First Commit of my working state
[simh.git] / PDP11 / pdp11_rx.c
CommitLineData
196ba1fc
PH
1/* pdp11_rx.c: RX11/RX01 floppy disk simulator\r
2\r
3 Copyright (c) 1993-2005, Robert M Supnik\r
4\r
5 Permission is hereby granted, free of charge, to any person obtaining a\r
6 copy of this software and associated documentation files (the "Software"),\r
7 to deal in the Software without restriction, including without limitation\r
8 the rights to use, copy, modify, merge, publish, distribute, sublicense,\r
9 and/or sell copies of the Software, and to permit persons to whom the\r
10 Software is furnished to do so, subject to the following conditions:\r
11\r
12 The above copyright notice and this permission notice shall be included in\r
13 all copies or substantial portions of the Software.\r
14\r
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\r
18 ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
19 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
21\r
22 Except as contained in this notice, the name of Robert M Supnik shall not be\r
23 used in advertising or otherwise to promote the sale, use or other dealings\r
24 in this Software without prior written authorization from Robert M Supnik.\r
25\r
26 rx RX11/RX01 floppy disk\r
27\r
28 07-Jul-05 RMS Removed extraneous externs\r
29 12-Oct-02 RMS Added autoconfigure support\r
30 08-Oct-02 RMS Added variable address support to bootstrap\r
31 Added vector change/display support\r
32 Revised state machine based on RX211\r
33 New data structures\r
34 Fixed reset of disabled device\r
35 26-Jan-02 RMS Revised bootstrap to conform to M9312\r
36 06-Jan-02 RMS Revised enable/disable support\r
37 30-Nov-01 RMS Added read only unit, extended SET/SHOW support\r
38 24-Nov-01 RMS Converted FLG to array\r
39 07-Sep-01 RMS Revised device disable and interrupt mechanisms\r
40 17-Jul-01 RMS Fixed warning from VC++ 6.0\r
41 26-Apr-01 RMS Added device enable/disable support\r
42 13-Apr-01 RMS Revised for register arrays\r
43 15-Feb-01 RMS Corrected bootstrap string\r
44 14-Apr-99 RMS Changed t_addr to unsigned\r
45\r
46 An RX01 diskette consists of 77 tracks, each with 26 sectors of 128B.\r
47 Tracks are numbered 0-76, sectors 1-26.\r
48*/\r
49\r
50#include "pdp11_defs.h"\r
51\r
52#define RX_NUMTR 77 /* tracks/disk */\r
53#define RX_M_TRACK 0377\r
54#define RX_NUMSC 26 /* sectors/track */\r
55#define RX_M_SECTOR 0177\r
56#define RX_NUMBY 128 /* bytes/sector */\r
57#define RX_SIZE (RX_NUMTR * RX_NUMSC * RX_NUMBY) /* bytes/disk */\r
58#define RX_NUMDR 2 /* drives/controller */\r
59#define RX_M_NUMDR 01\r
60#define UNIT_V_WLK (UNIT_V_UF) /* write locked */\r
61#define UNIT_WLK (1u << UNIT_V_UF)\r
62#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */\r
63\r
64#define IDLE 0 /* idle state */\r
65#define RWDS 1 /* rw, sect next */\r
66#define RWDT 2 /* rw, track next */\r
67#define RWXFR 3 /* rw, transfer */\r
68#define FILL 4 /* fill buffer */\r
69#define EMPTY 5 /* empty buffer */\r
70#define CMD_COMPLETE 6 /* set done next */\r
71#define INIT_COMPLETE 7 /* init compl next */\r
72\r
73#define RXCS_V_FUNC 1 /* function */\r
74#define RXCS_M_FUNC 7\r
75#define RXCS_FILL 0 /* fill buffer */\r
76#define RXCS_EMPTY 1 /* empty buffer */\r
77#define RXCS_WRITE 2 /* write sector */\r
78#define RXCS_READ 3 /* read sector */\r
79#define RXCS_RXES 5 /* read status */\r
80#define RXCS_WRDEL 6 /* write del data */\r
81#define RXCS_ECODE 7 /* read error code */\r
82#define RXCS_V_DRV 4 /* drive select */\r
83#define RXCS_V_DONE 5 /* done */\r
84#define RXCS_V_IE 6 /* intr enable */\r
85#define RXCS_V_TR 7 /* xfer request */\r
86#define RXCS_V_INIT 14 /* init */\r
87#define RXCS_V_ERR 15 /* error */\r
88#define RXCS_FUNC (RXCS_M_FUNC << RXCS_V_FUNC)\r
89#define RXCS_DRV (1u << RXCS_V_DRV)\r
90#define RXCS_DONE (1u << RXCS_V_DONE)\r
91#define RXCS_IE (1u << RXCS_V_IE)\r
92#define RXCS_TR (1u << RXCS_V_TR)\r
93#define RXCS_INIT (1u << RXCS_V_INIT)\r
94#define RXCS_ERR (1u << RXCS_V_ERR)\r
95#define RXCS_ROUT (RXCS_ERR+RXCS_TR+RXCS_IE+RXCS_DONE)\r
96#define RXCS_IMP (RXCS_ROUT+RXCS_DRV+RXCS_FUNC)\r
97#define RXCS_RW (RXCS_IE) /* read/write */\r
98#define RXCS_GETFNC(x) (((x) >> RXCS_V_FUNC) & RXCS_M_FUNC)\r
99\r
100#define RXES_CRC 0001 /* CRC error */\r
101#define RXES_PAR 0002 /* parity error */\r
102#define RXES_ID 0004 /* init done */\r
103#define RXES_WLK 0010 /* write protect */\r
104#define RXES_DD 0100 /* deleted data */\r
105#define RXES_DRDY 0200 /* drive ready */\r
106\r
107#define TRACK u3 /* current track */\r
108#define CALC_DA(t,s) (((t) * RX_NUMSC) + ((s) - 1)) * RX_NUMBY\r
109\r
110extern int32 int_req[IPL_HLVL];\r
111\r
112int32 rx_csr = 0; /* control/status */\r
113int32 rx_dbr = 0; /* data buffer */\r
114int32 rx_esr = 0; /* error status */\r
115int32 rx_ecode = 0; /* error code */\r
116int32 rx_track = 0; /* desired track */\r
117int32 rx_sector = 0; /* desired sector */\r
118int32 rx_state = IDLE; /* controller state */\r
119int32 rx_stopioe = 1; /* stop on error */\r
120int32 rx_cwait = 100; /* command time */\r
121int32 rx_swait = 10; /* seek, per track */\r
122int32 rx_xwait = 1; /* tr set time */\r
123uint8 rx_buf[RX_NUMBY] = { 0 }; /* sector buffer */\r
124int32 rx_bptr = 0; /* buffer pointer */\r
125int32 rx_enb = 1; /* device enable */\r
126\r
127DEVICE rx_dev;\r
128t_stat rx_rd (int32 *data, int32 PA, int32 access);\r
129t_stat rx_wr (int32 data, int32 PA, int32 access);\r
130t_stat rx_svc (UNIT *uptr);\r
131t_stat rx_reset (DEVICE *dptr);\r
132t_stat rx_boot (int32 unitno, DEVICE *dptr);\r
133void rx_done (int esr_flags, int new_ecode);\r
134\r
135/* RX11 data structures\r
136\r
137 rx_dev RX device descriptor\r
138 rx_unit RX unit list\r
139 rx_reg RX register list\r
140 rx_mod RX modifier list\r
141*/\r
142\r
143DIB rx_dib = {\r
144 IOBA_RX, IOLN_RX, &rx_rd, &rx_wr,\r
145 1, IVCL (RX), VEC_RX, { NULL }\r
146 };\r
147\r
148UNIT rx_unit[] = {\r
149 { UDATA (&rx_svc,\r
150 UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF, RX_SIZE) },\r
151 { UDATA (&rx_svc,\r
152 UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF, RX_SIZE) }\r
153 };\r
154\r
155REG rx_reg[] = {\r
156 { ORDATA (RXCS, rx_csr, 16) },\r
157 { ORDATA (RXDB, rx_dbr, 8) },\r
158 { ORDATA (RXES, rx_esr, 8) },\r
159 { ORDATA (RXERR, rx_ecode, 8) },\r
160 { ORDATA (RXTA, rx_track, 8) },\r
161 { ORDATA (RXSA, rx_sector, 8) },\r
162 { DRDATA (STAPTR, rx_state, 3), REG_RO },\r
163 { DRDATA (BUFPTR, rx_bptr, 7) },\r
164 { FLDATA (INT, IREQ (RX), INT_V_RX) },\r
165 { FLDATA (ERR, rx_csr, RXCS_V_ERR) },\r
166 { FLDATA (TR, rx_csr, RXCS_V_TR) },\r
167 { FLDATA (IE, rx_csr, RXCS_V_IE) },\r
168 { FLDATA (DONE, rx_csr, RXCS_V_DONE) },\r
169 { DRDATA (CTIME, rx_cwait, 24), PV_LEFT },\r
170 { DRDATA (STIME, rx_swait, 24), PV_LEFT },\r
171 { DRDATA (XTIME, rx_xwait, 24), PV_LEFT },\r
172 { FLDATA (STOP_IOE, rx_stopioe, 0) },\r
173 { BRDATA (SBUF, rx_buf, 8, 8, RX_NUMBY) },\r
174 { ORDATA (DEVADDR, rx_dib.ba, 32), REG_HRO },\r
175 { ORDATA (DEVVEC, rx_dib.vec, 16), REG_HRO },\r
176 { NULL }\r
177 };\r
178\r
179MTAB rx_mod[] = {\r
180 { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL },\r
181 { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL },\r
182 { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", "ADDRESS",\r
183 &set_addr, &show_addr, NULL },\r
184 { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR",\r
185 &set_vec, &show_vec, NULL },\r
186 { MTAB_XTD | MTAB_VDV, 0, NULL, "AUTOCONFIGURE",\r
187 &set_addr_flt, NULL, NULL },\r
188 { 0 }\r
189 };\r
190\r
191DEVICE rx_dev = {\r
192 "RX", rx_unit, rx_reg, rx_mod,\r
193 RX_NUMDR, 8, 20, 1, 8, 8,\r
194 NULL, NULL, &rx_reset,\r
195 &rx_boot, NULL, NULL,\r
196 &rx_dib, DEV_FLTA | DEV_DISABLE | DEV_UBUS | DEV_QBUS\r
197 };\r
198\r
199/* I/O dispatch routine, I/O addresses 17777170 - 17777172\r
200\r
201 17777170 floppy CSR\r
202 17777172 floppy data register\r
203*/\r
204\r
205t_stat rx_rd (int32 *data, int32 PA, int32 access)\r
206{\r
207switch ((PA >> 1) & 1) { /* decode PA<1> */\r
208\r
209 case 0: /* RXCS */\r
210 rx_csr = rx_csr & RXCS_IMP; /* clear junk */\r
211 *data = rx_csr & RXCS_ROUT;\r
212 break;\r
213\r
214 case 1: /* RXDB */\r
215 if ((rx_state == EMPTY) && (rx_csr & RXCS_TR)) {/* empty? */\r
216 sim_activate (&rx_unit[0], rx_xwait);\r
217 rx_csr = rx_csr & ~RXCS_TR; /* clear xfer */\r
218 }\r
219 *data = rx_dbr; /* return data */\r
220 break;\r
221 } /* end switch PA */\r
222\r
223return SCPE_OK;\r
224}\r
225\r
226t_stat rx_wr (int32 data, int32 PA, int32 access)\r
227{\r
228int32 drv;\r
229\r
230switch ((PA >> 1) & 1) { /* decode PA<1> */\r
231\r
232/* Writing RXCS, three cases:\r
233 1. Writing INIT, reset device\r
234 2. Idle and writing new function\r
235 - clear error, done, transfer ready, int req\r
236 - save int enable, function, drive\r
237 - start new function\r
238 3. Otherwise, write IE and update interrupts\r
239*/\r
240\r
241 case 0: /* RXCS */\r
242 rx_csr = rx_csr & RXCS_IMP; /* clear junk */\r
243 if (access == WRITEB) data = (PA & 1)? /* write byte? */\r
244 (rx_csr & 0377) | (data << 8): (rx_csr & ~0377) | data;\r
245 if (data & RXCS_INIT) { /* initialize? */\r
246 rx_reset (&rx_dev); /* reset device */\r
247 return SCPE_OK; /* end if init */\r
248 }\r
249 if ((data & CSR_GO) && (rx_state == IDLE)) { /* new function? */\r
250 rx_csr = data & (RXCS_IE + RXCS_DRV + RXCS_FUNC);\r
251 drv = ((rx_csr & RXCS_DRV)? 1: 0); /* reselect drive */\r
252 rx_bptr = 0; /* clear buf pointer */\r
253 switch (RXCS_GETFNC (data)) { /* case on func */\r
254\r
255 case RXCS_FILL:\r
256 rx_state = FILL; /* state = fill */\r
257 rx_csr = rx_csr | RXCS_TR; /* xfer is ready */\r
258 break;\r
259\r
260 case RXCS_EMPTY:\r
261 rx_state = EMPTY; /* state = empty */\r
262 sim_activate (&rx_unit[drv], rx_xwait);\r
263 break;\r
264\r
265 case RXCS_READ: case RXCS_WRITE: case RXCS_WRDEL:\r
266 rx_state = RWDS; /* state = get sector */\r
267 rx_csr = rx_csr | RXCS_TR; /* xfer is ready */\r
268 rx_esr = rx_esr & RXES_ID; /* clear errors */\r
269 break;\r
270\r
271 default:\r
272 rx_state = CMD_COMPLETE; /* state = cmd compl */\r
273 sim_activate (&rx_unit[drv], rx_cwait);\r
274 break;\r
275 } /* end switch func */\r
276 return SCPE_OK;\r
277 } /* end if GO */\r
278 if ((data & RXCS_IE) == 0) CLR_INT (RX);\r
279 else if ((rx_csr & (RXCS_DONE + RXCS_IE)) == RXCS_DONE)\r
280 SET_INT (RX);\r
281 rx_csr = (rx_csr & ~RXCS_RW) | (data & RXCS_RW);\r
282 break; /* end case RXCS */\r
283\r
284/* Accessing RXDB, two cases:\r
285 1. Write idle, write\r
286 2. Write not idle and TR set, state dependent\r
287*/\r
288\r
289 case 1: /* RXDB */\r
290 if ((PA & 1) || ((rx_state != IDLE) && ((rx_csr & RXCS_TR) == 0)))\r
291 return SCPE_OK; /* if ~IDLE, need tr */\r
292 rx_dbr = data & 0377; /* save data */\r
293 if ((rx_state != IDLE) && (rx_state != EMPTY)) {\r
294 drv = ((rx_csr & RXCS_DRV)? 1: 0); /* select drive */\r
295 sim_activate (&rx_unit[drv], rx_xwait); /* sched event */\r
296 rx_csr = rx_csr & ~RXCS_TR; /* clear xfer */\r
297 }\r
298 break; /* end case RXDB */\r
299 } /* end switch PA */\r
300\r
301return SCPE_OK;\r
302}\r
303\r
304/* Unit service; the action to be taken depends on the transfer state:\r
305\r
306 IDLE Should never get here\r
307 RWDS Save sector, set TR, set RWDT\r
308 RWDT Save track, set RWXFR\r
309 RWXFR Read/write buffer\r
310 FILL copy ir to rx_buf[rx_bptr], advance ptr\r
311 if rx_bptr > max, finish command, else set tr\r
312 EMPTY if rx_bptr > max, finish command, else\r
313 copy rx_buf[rx_bptr] to ir, advance ptr, set tr\r
314 CMD_COMPLETE copy requested data to ir, finish command\r
315 INIT_COMPLETE read drive 0, track 1, sector 1 to buffer, finish command\r
316\r
317 For RWDT and CMD_COMPLETE, the input argument is the selected drive;\r
318 otherwise, it is drive 0.\r
319*/\r
320\r
321t_stat rx_svc (UNIT *uptr)\r
322{\r
323int32 i, func;\r
324uint32 da;\r
325int8 *fbuf = uptr->filebuf;\r
326\r
327func = RXCS_GETFNC (rx_csr); /* get function */\r
328switch (rx_state) { /* case on state */\r
329\r
330 case IDLE: /* idle */\r
331 return SCPE_IERR; /* done */\r
332\r
333 case EMPTY: /* empty buffer */\r
334 if (rx_bptr >= RX_NUMBY) rx_done (0, 0); /* done all? */\r
335 else {\r
336 rx_dbr = rx_buf[rx_bptr]; /* get next */\r
337 rx_bptr = rx_bptr + 1;\r
338 rx_csr = rx_csr | RXCS_TR; /* set xfer */\r
339 }\r
340 break;\r
341\r
342 case FILL: /* fill buffer */\r
343 rx_buf[rx_bptr] = rx_dbr; /* write next */\r
344 rx_bptr = rx_bptr + 1;\r
345 if (rx_bptr < RX_NUMBY) rx_csr = rx_csr | RXCS_TR; /* more? set xfer */\r
346 else rx_done (0, 0); /* else done */\r
347 break;\r
348\r
349 case RWDS: /* wait for sector */\r
350 rx_sector = rx_dbr & RX_M_SECTOR; /* save sector */\r
351 rx_csr = rx_csr | RXCS_TR; /* set xfer */\r
352 rx_state = RWDT; /* advance state */\r
353 return SCPE_OK;\r
354\r
355 case RWDT: /* wait for track */\r
356 rx_track = rx_dbr & RX_M_TRACK; /* save track */\r
357 rx_state = RWXFR;\r
358 sim_activate (uptr, /* sched done */\r
359 rx_swait * abs (rx_track - uptr->TRACK));\r
360 return SCPE_OK;\r
361\r
362 case RWXFR:\r
363 if ((uptr->flags & UNIT_BUF) == 0) { /* not buffered? */\r
364 rx_done (0, 0110); /* done, error */\r
365 return IORETURN (rx_stopioe, SCPE_UNATT);\r
366 }\r
367 if (rx_track >= RX_NUMTR) { /* bad track? */\r
368 rx_done (0, 0040); /* done, error */\r
369 break;\r
370 }\r
371 uptr->TRACK = rx_track; /* now on track */\r
372 if ((rx_sector == 0) || (rx_sector > RX_NUMSC)) { /* bad sect? */\r
373 rx_done (0, 0070); /* done, error */\r
374 break;\r
375 }\r
376 da = CALC_DA (rx_track, rx_sector); /* get disk address */\r
377 if (func == RXCS_WRDEL) rx_esr = rx_esr | RXES_DD; /* del data? */\r
378 if (func == RXCS_READ) { /* read? */\r
379 for (i = 0; i < RX_NUMBY; i++)\r
380 rx_buf[i] = fbuf[da + i];\r
381 }\r
382 else {\r
383 if (uptr->flags & UNIT_WPRT) { /* write and locked? */\r
384 rx_done (RXES_WLK, 0100); /* done, error */\r
385 break;\r
386 }\r
387 for (i = 0; i < RX_NUMBY; i++) /* write */\r
388 fbuf[da + i] = rx_buf[i];\r
389 da = da + RX_NUMBY;\r
390 if (da > uptr->hwmark) uptr->hwmark = da;\r
391 }\r
392 rx_done (0, 0); /* done */\r
393 break;\r
394\r
395 case CMD_COMPLETE: /* command complete */\r
396 if (func == RXCS_ECODE) { /* read ecode? */\r
397 rx_dbr = rx_ecode; /* set dbr */\r
398 rx_done (0, -1); /* don't update */\r
399 }\r
400 else rx_done (0, 0);\r
401 break;\r
402\r
403 case INIT_COMPLETE: /* init complete */\r
404 rx_unit[0].TRACK = 1; /* drive 0 to trk 1 */\r
405 rx_unit[1].TRACK = 0; /* drive 1 to trk 0 */\r
406 if ((rx_unit[0].flags & UNIT_BUF) == 0) { /* not buffered? */\r
407 rx_done (RXES_ID, 0010); /* init done, error */\r
408 break;\r
409 }\r
410 da = CALC_DA (1, 1); /* track 1, sector 1 */\r
411 for (i = 0; i < RX_NUMBY; i++) /* read sector */\r
412 rx_buf[i] = fbuf[da + i];\r
413 rx_done (RXES_ID, 0); /* set done */\r
414 if ((rx_unit[1].flags & UNIT_ATT) == 0) rx_ecode = 0020;\r
415 break;\r
416 } /* end case state */\r
417\r
418return SCPE_OK;\r
419}\r
420\r
421/* Command complete. Set done and put final value in interface register,\r
422 request interrupt if needed, return to IDLE state.\r
423*/\r
424\r
425void rx_done (int32 esr_flags, int32 new_ecode)\r
426{\r
427int32 drv = (rx_csr & RXCS_DRV)? 1: 0;\r
428\r
429rx_state = IDLE; /* now idle */\r
430rx_csr = rx_csr | RXCS_DONE; /* set done */\r
431if (rx_csr & RXCS_IE) SET_INT (RX); /* if ie, intr */\r
432rx_esr = (rx_esr | esr_flags) & ~RXES_DRDY;\r
433if (rx_unit[drv].flags & UNIT_ATT)\r
434 rx_esr = rx_esr | RXES_DRDY;\r
435if (new_ecode > 0) rx_csr = rx_csr | RXCS_ERR; /* test for error */\r
436if (new_ecode < 0) return; /* don't update? */\r
437rx_ecode = new_ecode; /* update ecode */\r
438rx_dbr = rx_esr; /* update RXDB */\r
439return;\r
440}\r
441\r
442/* Device initialization. The RX is one of the few devices that schedules\r
443 an I/O transfer as part of its initialization.\r
444*/\r
445\r
446t_stat rx_reset (DEVICE *dptr)\r
447{\r
448rx_csr = rx_dbr = 0; /* clear regs */\r
449rx_esr = rx_ecode = 0; /* clear error */\r
450rx_track = rx_sector = 0; /* clear addr */\r
451rx_state = IDLE; /* ctrl idle */\r
452CLR_INT (RX); /* clear int req */\r
453sim_cancel (&rx_unit[1]); /* cancel drive 1 */\r
454if (dptr->flags & DEV_DIS) sim_cancel (&rx_unit[0]); /* disabled? */\r
455else if (rx_unit[0].flags & UNIT_BUF) { /* attached? */\r
456 rx_state = INIT_COMPLETE; /* yes, sched init */\r
457 sim_activate (&rx_unit[0], rx_swait * abs (1 - rx_unit[0].TRACK));\r
458 }\r
459else rx_done (0, 0010); /* no, error */\r
460return auto_config (0, 0); /* run autoconfig */\r
461}\r
462\r
463/* Device bootstrap */\r
464\r
465#define BOOT_START 02000 /* start */\r
466#define BOOT_ENTRY (BOOT_START + 002) /* entry */\r
467#define BOOT_UNIT (BOOT_START + 010) /* unit number */\r
468#define BOOT_CSR (BOOT_START + 026) /* CSR */\r
469#define BOOT_LEN (sizeof (boot_rom) / sizeof (int16))\r
470\r
471static const uint16 boot_rom[] = {\r
472 042130, /* "XD" */\r
473 0012706, BOOT_START, /* MOV #boot_start, SP */\r
474 0012700, 0000000, /* MOV #unit, R0 ; unit number */\r
475 0010003, /* MOV R0, R3 */\r
476 0006303, /* ASL R3 */\r
477 0006303, /* ASL R3 */\r
478 0006303, /* ASL R3 */\r
479 0006303, /* ASL R3 */\r
480 0012701, 0177170, /* MOV #RXCS, R1 ; csr */\r
481 0032711, 0000040, /* BITB #40, (R1) ; ready? */\r
482 0001775, /* BEQ .-4 */\r
483 0052703, 0000007, /* BIS #READ+GO, R3 */\r
484 0010311, /* MOV R3, (R1) ; read & go */\r
485 0105711, /* TSTB (R1) ; xfr ready? */\r
486 0100376, /* BPL .-2 */\r
487 0012761, 0000001, 0000002, /* MOV #1, 2(R1) ; sector */\r
488 0105711, /* TSTB (R1) ; xfr ready? */\r
489 0100376, /* BPL .-2 */\r
490 0012761, 0000001, 0000002, /* MOV #1, 2(R1) ; track */\r
491 0005003, /* CLR R3 */\r
492 0032711, 0000040, /* BITB #40, (R1) ; ready? */\r
493 0001775, /* BEQ .-4 */\r
494 0012711, 0000003, /* MOV #EMPTY+GO, (R1) ; empty & go */\r
495 0105711, /* TSTB (R1) ; xfr, done? */\r
496 0001776, /* BEQ .-2 */\r
497 0100003, /* BPL .+010 */\r
498 0116123, 0000002, /* MOVB 2(R1), (R3)+ ; move byte */\r
499 0000772, /* BR .-012 */\r
500 0005002, /* CLR R2 */\r
501 0005003, /* CLR R3 */\r
502 0012704, BOOT_START+020, /* MOV #START+20, R4 */\r
503 0005005, /* CLR R5 */\r
504 0005007 /* CLR R7 */\r
505 };\r
506\r
507t_stat rx_boot (int32 unitno, DEVICE *dptr)\r
508{\r
509int32 i;\r
510extern int32 saved_PC;\r
511extern uint16 *M;\r
512\r
513for (i = 0; i < BOOT_LEN; i++) M[(BOOT_START >> 1) + i] = boot_rom[i];\r
514M[BOOT_UNIT >> 1] = unitno & RX_M_NUMDR;\r
515M[BOOT_CSR >> 1] = rx_dib.ba & DMASK;\r
516saved_PC = BOOT_ENTRY;\r
517return SCPE_OK;\r
518}\r