First Commit of my working state
[simh.git] / PDP11 / pdp11_ry.c
1 /* pdp11_ry.c: RX211/RXV21/RX02 floppy disk simulator
2
3 Copyright (c) 1993-2006, Robert M Supnik
4
5 Permission is hereby granted, free of charge, to any person obtaining a
6 copy of this software and associated documentation files (the "Software"),
7 to deal in the Software without restriction, including without limitation
8 the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 and/or sell copies of the Software, and to permit persons to whom the
10 Software is furnished to do so, subject to the following conditions:
11
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
14
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22 Except as contained in this notice, the name of Robert M Supnik shall not be
23 used in advertising or otherwise to promote the sale, use or other dealings
24 in this Software without prior written authorization from Robert M Supnik.
25
26 ry RX211/RXV21/RX02 floppy disk
27
28 15-May-06 RMS Fixed bug in autosize attach (reported by David Gesswein)
29 07-Jul-05 RMS Removed extraneous externs
30 18-Feb-05 RMS Fixed bug in boot code (reported by Graham Toal)
31 30-Sep-04 RMS Revised Unibus interface
32 21-Mar-04 RMS Added VAX support
33 29-Dec-03 RMS Added RXV21 support
34 19-May-03 RMS Revised for new conditional compilation scheme
35 25-Apr-03 RMS Revised for extended file support
36 14-Mar-03 RMS Fixed variable size interaction with save/restore
37 03-Mar-03 RMS Fixed autosizing
38 12-Oct-02 RMS Added autoconfigure support
39
40 An RX02 diskette consists of 77 tracks, each with 26 sectors of 256B.
41 Tracks are numbered 0-76, sectors 1-26.
42 */
43
44 #if defined (VM_PDP10) /* PDP10 version */
45 #include "pdp10_defs.h"
46 extern int32 int_req;
47 #define DEV_DISI DEV_DIS
48
49 #elif defined (VM_VAX) /* VAX version */
50 #include "vax_defs.h"
51 extern int32 int_req[IPL_HLVL];
52 #define DEV_DISI 0
53
54 #else /* PDP-11 version */
55 #include "pdp11_defs.h"
56 extern int32 int_req[IPL_HLVL];
57 #define DEV_DISI DEV_DIS
58 #endif
59
60 #define RX_NUMTR 77 /* tracks/disk */
61 #define RX_M_TRACK 0377
62 #define RX_NUMSC 26 /* sectors/track */
63 #define RX_M_SECTOR 0177
64 #define RX_NUMBY 128
65 #define RX_SIZE (RX_NUMTR * RX_NUMSC * RX_NUMBY)
66 #define RY_NUMBY 256 /* bytes/sector */
67 #define RY_SIZE (RX_NUMTR * RX_NUMSC * RY_NUMBY)
68 #define RX_NUMDR 2 /* drives/controller */
69 #define RX_M_NUMDR 01
70 #define UNIT_V_WLK (UNIT_V_UF) /* write locked */
71 #define UNIT_V_DEN (UNIT_V_UF + 1) /* double density */
72 #define UNIT_V_AUTO (UNIT_V_UF + 2) /* autosize */
73 #define UNIT_WLK (1u << UNIT_V_WLK)
74 #define UNIT_DEN (1u << UNIT_V_DEN)
75 #define UNIT_AUTO (1u << UNIT_V_AUTO)
76 #define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */
77
78 #define IDLE 0 /* idle state */
79 #define RWDS 1 /* rw, sect next */
80 #define RWDT 2 /* rw, track next */
81 #define RWXFR 3 /* rw, transfer */
82 #define FEWC 4 /* fill empty, wc next */
83 #define FEBA 5 /* fill empty, ba next */
84 #define FEXFR 6 /* fill empty, transfer */
85 #define SDCNF 7 /* set dens, conf next */
86 #define SDXFR 8 /* set dens, transfer */
87 #define ESBA 9 /* ext sta, ba next */
88 #define ESXFR 10 /* ext sta, transfer */
89 #define CMD_COMPLETE 11 /* set done next */
90 #define INIT_COMPLETE 12 /* init compl next */
91
92 #define RYCS_V_FUNC 1 /* function */
93 #define RYCS_M_FUNC 7
94 #define RYCS_FILL 0 /* fill buffer */
95 #define RYCS_EMPTY 1 /* empty buffer */
96 #define RYCS_WRITE 2 /* write sector */
97 #define RYCS_READ 3 /* read sector */
98 #define RYCS_SDEN 4 /* set density */
99 #define RYCS_RYES 5 /* read status */
100 #define RYCS_WRDEL 6 /* write del data */
101 #define RYCS_ESTAT 7 /* read ext status */
102 #define RYCS_V_DRV 4 /* drive select */
103 #define RYCS_V_DONE 5 /* done */
104 #define RYCS_V_IE 6 /* int enable */
105 #define RYCS_V_TR 7 /* xfer request */
106 #define RYCS_V_DEN 8 /* density select */
107 #define RYCS_V_RY 11 /* RX02 flag */
108 #define RYCS_V_UAE 12 /* addr ext */
109 #define RYCS_M_UAE 03
110 #define RYCS_V_INIT 14 /* init */
111 #define RYCS_V_ERR 15 /* error */
112 #define RYCS_FUNC (RYCS_M_FUNC << RYCS_V_FUNC)
113 #define RYCS_DRV (1u << RYCS_V_DRV)
114 #define RYCS_DONE (1u << RYCS_V_DONE)
115 #define RYCS_IE (1u << RYCS_V_IE)
116 #define RYCS_TR (1u << RYCS_V_TR)
117 #define RYCS_DEN (1u << RYCS_V_DEN)
118 #define RYCS_RY (1u << RYCS_V_RY)
119 #define RYCS_UAE (RYCS_M_UAE << RYCS_V_UAE)
120 #define RYCS_INIT (1u << RYCS_V_INIT)
121 #define RYCS_ERR (1u << RYCS_V_ERR)
122 #define RYCS_IMP (RYCS_ERR+RYCS_UAE+RYCS_DEN+RYCS_TR+RYCS_IE+\
123 RYCS_DONE+RYCS_DRV+RYCS_FUNC)
124 #define RYCS_RW (RYCS_UAE+RYCS_DEN+RYCS_IE+RYCS_DRV+RYCS_FUNC)
125 #define RYCS_GETFNC(x) (((x) >> RYCS_V_FUNC) & RYCS_M_FUNC)
126 #define RYCS_GETUAE(x) (((x) >> RYCS_V_UAE) & RYCS_M_UAE)
127
128 #define RYES_CRC 00001 /* CRC error NI */
129 #define RYES_ID 00004 /* init done */
130 #define RYES_ACLO 00010 /* ACLO NI */
131 #define RYES_DERR 00020 /* density err */
132 #define RYES_DDEN 00040 /* drive density */
133 #define RYES_DD 00100 /* deleted data */
134 #define RYES_DRDY 00200 /* drive ready */
135 #define RYES_USEL 00400 /* unit selected */
136 #define RYES_WCO 02000 /* wc overflow */
137 #define RYES_NXM 04000 /* nxm */
138 #define RYES_ERR (RYES_NXM|RYES_WCO|RYES_DERR|RYES_ACLO|RYES_CRC)
139
140 #define TRACK u3 /* current track */
141 #define CALC_DA(t,s,b) (((t) * RX_NUMSC) + ((s) - 1)) * b
142
143 int32 ry_csr = 0; /* control/status */
144 int32 ry_dbr = 0; /* data buffer */
145 int32 ry_esr = 0; /* error status */
146 int32 ry_ecode = 0; /* error code */
147 int32 ry_track = 0; /* desired track */
148 int32 ry_sector = 0; /* desired sector */
149 int32 ry_ba = 0; /* bus addr */
150 int32 ry_wc = 0; /* word count */
151 int32 ry_state = IDLE; /* controller state */
152 int32 ry_stopioe = 1; /* stop on error */
153 int32 ry_cwait = 100; /* command time */
154 int32 ry_swait = 10; /* seek, per track */
155 int32 ry_xwait = 1; /* tr set time */
156 uint8 rx2xb[RY_NUMBY] = { 0 }; /* sector buffer */
157
158 DEVICE ry_dev;
159 t_stat ry_rd (int32 *data, int32 PA, int32 access);
160 t_stat ry_wr (int32 data, int32 PA, int32 access);
161 t_stat ry_svc (UNIT *uptr);
162 t_stat ry_reset (DEVICE *dptr);
163 t_stat ry_boot (int32 unitno, DEVICE *dptr);
164 void ry_done (int esr_flags, int new_ecode);
165 t_stat ry_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
166 t_stat ry_attach (UNIT *uptr, char *cptr);
167
168 /* RY11 data structures
169
170 ry_dev RY device descriptor
171 ry_unit RY unit list
172 ry_reg RY register list
173 ry_mod RY modifier list
174 */
175
176 DIB ry_dib = {
177 IOBA_RY, IOLN_RY, &ry_rd, &ry_wr,
178 1, IVCL (RY), VEC_RY, { NULL }
179 };
180
181 UNIT ry_unit[] = {
182 { UDATA (&ry_svc, UNIT_DEN+UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF,
183 RY_SIZE) },
184 { UDATA (&ry_svc, UNIT_DEN+UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF,
185 RY_SIZE) }
186 };
187
188 REG ry_reg[] = {
189 { GRDATA (RYCS, ry_csr, DEV_RDX, 16, 0) },
190 { GRDATA (RYBA, ry_ba, DEV_RDX, 16, 0) },
191 { GRDATA (RYWC, ry_wc, DEV_RDX, 8, 0) },
192 { GRDATA (RYDB, ry_dbr, DEV_RDX, 16, 0) },
193 { GRDATA (RYES, ry_esr, DEV_RDX, 12, 0) },
194 { GRDATA (RYERR, ry_ecode, DEV_RDX, 8, 0) },
195 { GRDATA (RYTA, ry_track, DEV_RDX, 8, 0) },
196 { GRDATA (RYSA, ry_sector, DEV_RDX, 8, 0) },
197 { DRDATA (STAPTR, ry_state, 4), REG_RO },
198 { FLDATA (INT, IREQ (RY), INT_V_RY) },
199 { FLDATA (ERR, ry_csr, RYCS_V_ERR) },
200 { FLDATA (TR, ry_csr, RYCS_V_TR) },
201 { FLDATA (IE, ry_csr, RYCS_V_IE) },
202 { FLDATA (DONE, ry_csr, RYCS_V_DONE) },
203 { DRDATA (CTIME, ry_cwait, 24), PV_LEFT },
204 { DRDATA (STIME, ry_swait, 24), PV_LEFT },
205 { DRDATA (XTIME, ry_xwait, 24), PV_LEFT },
206 { BRDATA (SBUF, rx2xb, 8, 8, RY_NUMBY) },
207 { FLDATA (STOP_IOE, ry_stopioe, 0) },
208 { URDATA (CAPAC, ry_unit[0].capac, 10, T_ADDR_W, 0,
209 RX_NUMDR, REG_HRO | PV_LEFT) },
210 { GRDATA (DEVADDR, ry_dib.ba, DEV_RDX, 32, 0), REG_HRO },
211 { GRDATA (DEVVEC, ry_dib.vec, DEV_RDX, 16, 0), REG_HRO },
212 { NULL }
213 };
214
215 MTAB ry_mod[] = {
216 { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL },
217 { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL },
218 { (UNIT_DEN+UNIT_ATT), UNIT_ATT, "single density", NULL, NULL },
219 { (UNIT_DEN+UNIT_ATT), (UNIT_DEN+UNIT_ATT), "double density", NULL, NULL },
220 { (UNIT_AUTO+UNIT_DEN+UNIT_ATT), 0, "single density", NULL, NULL },
221 { (UNIT_AUTO+UNIT_DEN+UNIT_ATT), UNIT_DEN, "double density", NULL, NULL },
222 { (UNIT_AUTO+UNIT_ATT), UNIT_AUTO, "autosize", NULL, NULL },
223 { UNIT_AUTO, UNIT_AUTO, NULL, "AUTOSIZE", NULL },
224 { (UNIT_AUTO+UNIT_DEN), 0, NULL, "SINGLE", &ry_set_size },
225 { (UNIT_AUTO+UNIT_DEN), UNIT_DEN, NULL, "DOUBLE", &ry_set_size },
226 { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", "ADDRESS",
227 &set_addr, &show_addr, NULL },
228 { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR",
229 &set_vec, &show_vec, NULL },
230 #if defined (VM_PDP11)
231 { MTAB_XTD | MTAB_VDV, 0, NULL, "AUTOCONFIGURE",
232 &set_addr_flt, NULL, NULL },
233 #endif
234 { 0 }
235 };
236
237 DEVICE ry_dev = {
238 "RY", ry_unit, ry_reg, ry_mod,
239 RX_NUMDR, DEV_RDX, 20, 1, DEV_RDX, 8,
240 NULL, NULL, &ry_reset,
241 &ry_boot, &ry_attach, NULL,
242 &ry_dib, DEV_FLTA | DEV_DISABLE | DEV_DISI | DEV_UBUS | DEV_Q18
243 };
244
245 /* I/O dispatch routine, I/O addresses 17777170 - 17777172
246
247 17777170 floppy CSR
248 17777172 floppy data register
249 */
250
251 t_stat ry_rd (int32 *data, int32 PA, int32 access)
252 {
253 switch ((PA >> 1) & 1) { /* decode PA<1> */
254
255 case 0: /* RYCS */
256 ry_csr = (ry_csr & RYCS_IMP) | RYCS_RY; /* clear junk */
257 *data = ry_csr;
258 break;
259
260 case 1: /* RYDB */
261 *data = ry_dbr; /* return data */
262 break;
263 } /* end switch PA */
264
265 return SCPE_OK;
266 }
267
268 t_stat ry_wr (int32 data, int32 PA, int32 access)
269 {
270 int32 drv;
271
272 switch ((PA >> 1) & 1) { /* decode PA<1> */
273
274 /* Writing RYCS, three cases:
275 1. Writing INIT, reset device
276 2. Idle and writing new function
277 - clear error, done, transfer ready, int req
278 - save int enable, function, drive
279 - start new function
280 3. Otherwise, write IE and update interrupts
281 */
282
283 case 0: /* RYCS */
284 ry_csr = (ry_csr & RYCS_IMP) | RYCS_RY; /* clear junk */
285 if (access == WRITEB) data = (PA & 1)? /* write byte? */
286 (ry_csr & 0377) | (data << 8): (ry_csr & ~0377) | data;
287 if (data & RYCS_INIT) { /* initialize? */
288 ry_reset (&ry_dev); /* reset device */
289 return SCPE_OK; /* end if init */
290 }
291 if ((data & CSR_GO) && (ry_state == IDLE)) { /* new function? */
292 ry_csr = (data & RYCS_RW) | RYCS_RY;
293 drv = ((ry_csr & RYCS_DRV)? 1: 0); /* reselect drv */
294 switch (RYCS_GETFNC (data)) {
295
296 case RYCS_FILL: case RYCS_EMPTY:
297 ry_state = FEWC; /* state = get wc */
298 ry_csr = ry_csr | RYCS_TR; /* xfer is ready */
299 break;
300
301 case RYCS_SDEN:
302 ry_state = SDCNF; /* state = get conf */
303 ry_csr = ry_csr | RYCS_TR; /* xfer is ready */
304 break;
305
306 case RYCS_ESTAT:
307 ry_state = ESBA; /* state = get ba */
308 ry_csr = ry_csr | RYCS_TR; /* xfer is ready */
309 break;
310
311 case RYCS_READ: case RYCS_WRITE: case RYCS_WRDEL:
312 ry_state = RWDS; /* state = get sector */
313 ry_csr = ry_csr | RYCS_TR; /* xfer is ready */
314 ry_esr = ry_esr & RYES_ID; /* clear errors */
315 ry_ecode = 0;
316 break;
317
318 default:
319 ry_state = CMD_COMPLETE; /* state = cmd compl */
320 sim_activate (&ry_unit[drv], ry_cwait);
321 break;
322 } /* end switch func */
323 return SCPE_OK;
324 } /* end if GO */
325 if ((data & RYCS_IE) == 0) CLR_INT (RY);
326 else if ((ry_csr & (RYCS_DONE + RYCS_IE)) == RYCS_DONE)
327 SET_INT (RY);
328 ry_csr = (ry_csr & ~RYCS_RW) | (data & RYCS_RW);
329 break; /* end case RYCS */
330
331 /* Accessing RYDB, two cases:
332 1. Write idle, write
333 2. Write not idle and TR set, state dependent
334 */
335
336 case 1: /* RYDB */
337 if ((PA & 1) || ((ry_state != IDLE) && ((ry_csr & RYCS_TR) == 0)))
338 return SCPE_OK; /* if ~IDLE, need tr */
339 ry_dbr = data; /* save data */
340 if (ry_state != IDLE) {
341 drv = ((ry_csr & RYCS_DRV)? 1: 0); /* select drv */
342 sim_activate (&ry_unit[drv], ry_xwait); /* sched event */
343 ry_csr = ry_csr & ~RYCS_TR; /* clear xfer */
344 }
345 break; /* end case RYDB */
346 } /* end switch PA */
347
348 return SCPE_OK;
349 }
350
351 /* Unit service; the action to be taken depends on the transfer state:
352
353 IDLE Should never get here
354 FEWC Save word count, set TR, set FEBA
355 FEBA Save bus address, set FEXFR
356 FEXFR Fill/empty buffer
357 RWDS Save sector, set TR, set RWDT
358 RWDT Save track, set RWXFR
359 RWXFR Read/write buffer
360 SDCNF Check confirmation, set SDXFR
361 SDXFR Erase disk
362 CMD_COMPLETE copy requested data to ir, finish command
363 INIT_COMPLETE read drive 0, track 1, sector 1 to buffer, finish command
364 */
365
366 t_stat ry_svc (UNIT *uptr)
367 {
368 int32 i, t, func, bps;
369 static uint8 estat[8];
370 uint32 ba, da;
371 int8 *fbuf = uptr->filebuf;
372
373 func = RYCS_GETFNC (ry_csr); /* get function */
374 bps = (ry_csr & RYCS_DEN)? RY_NUMBY: RX_NUMBY; /* get sector size */
375 ba = (RYCS_GETUAE (ry_csr) << 16) | ry_ba; /* get mem addr */
376 switch (ry_state) { /* case on state */
377
378 case IDLE: /* idle */
379 return SCPE_IERR;
380
381 case FEWC: /* word count */
382 ry_wc = ry_dbr & 0377; /* save WC */
383 ry_csr = ry_csr | RYCS_TR; /* set TR */
384 ry_state = FEBA; /* next state */
385 return SCPE_OK;
386
387 case FEBA: /* buffer address */
388 ry_ba = ry_dbr; /* save buf addr */
389 ry_state = FEXFR; /* next state */
390 sim_activate (uptr, ry_cwait); /* schedule xfer */
391 return SCPE_OK;
392
393 case FEXFR: /* transfer */
394 if ((ry_wc << 1) > bps) { /* wc too big? */
395 ry_done (RYES_WCO, 0230); /* error */
396 break;
397 }
398 if (func == RYCS_FILL) { /* fill? read */
399 for (i = 0; i < RY_NUMBY; i++) rx2xb[i] = 0;
400 t = Map_ReadB (ba, ry_wc << 1, rx2xb);
401 }
402 else t = Map_WriteB (ba, ry_wc << 1, rx2xb);
403 ry_wc = t >> 1; /* adjust wc */
404 ry_done (t? RYES_NXM: 0, 0); /* done */
405 break;
406
407 case RWDS: /* wait for sector */
408 ry_sector = ry_dbr & RX_M_SECTOR; /* save sector */
409 ry_csr = ry_csr | RYCS_TR; /* set xfer */
410 ry_state = RWDT; /* advance state */
411 return SCPE_OK;
412
413 case RWDT: /* wait for track */
414 ry_track = ry_dbr & RX_M_TRACK; /* save track */
415 ry_state = RWXFR; /* next state */
416 sim_activate (uptr, /* sched xfer */
417 ry_swait * abs (ry_track - uptr->TRACK));
418 return SCPE_OK;
419
420 case RWXFR: /* read/write */
421 if ((uptr->flags & UNIT_BUF) == 0) { /* not buffered? */
422 ry_done (0, 0110); /* done, error */
423 return IORETURN (ry_stopioe, SCPE_UNATT);
424 }
425 if (ry_track >= RX_NUMTR) { /* bad track? */
426 ry_done (0, 0040); /* done, error */
427 break;
428 }
429 uptr->TRACK = ry_track; /* now on track */
430 if ((ry_sector == 0) || (ry_sector > RX_NUMSC)) { /* bad sect? */
431 ry_done (0, 0070); /* done, error */
432 break;
433 }
434 if (((uptr->flags & UNIT_DEN) != 0) ^
435 ((ry_csr & RYCS_DEN) != 0)) { /* densities agree? */
436 ry_done (RYES_DERR, 0240); /* no, error */
437 break;
438 }
439 da = CALC_DA (ry_track, ry_sector, bps); /* get disk address */
440 if (func == RYCS_WRDEL) ry_esr = ry_esr | RYES_DD; /* del data? */
441 if (func == RYCS_READ) { /* read? */
442 for (i = 0; i < bps; i++)
443 rx2xb[i] = fbuf[da + i];
444 }
445 else {
446 if (uptr->flags & UNIT_WPRT) { /* write and locked? */
447 ry_done (0, 0100); /* done, error */
448 break;
449 }
450 for (i = 0; i < bps; i++) /* write */
451 fbuf[da + i] = rx2xb[i];
452 da = da + bps;
453 if (da > uptr->hwmark) uptr->hwmark = da;
454 }
455 ry_done (0, 0); /* done */
456 break;
457
458 case SDCNF: /* confirm set density */
459 if ((ry_dbr & 0377) != 0111) { /* confirmed? */
460 ry_done (0, 0250); /* no, error */
461 break;
462 }
463 ry_state = SDXFR; /* next state */
464 sim_activate (uptr, ry_cwait * 100); /* schedule operation */
465 break;
466
467 case SDXFR: /* erase disk */
468 for (i = 0; i < (int32) uptr->capac; i++) fbuf[i] = 0;
469 uptr->hwmark = (uint32) uptr->capac;
470 if (ry_csr & RYCS_DEN) uptr->flags = uptr->flags | UNIT_DEN;
471 else uptr->flags = uptr->flags & ~UNIT_DEN;
472 ry_done (0, 0);
473 break;
474
475
476 case ESBA:
477 ry_ba = ry_dbr; /* save WC */
478 ry_state = ESXFR; /* next state */
479 sim_activate (uptr, ry_cwait); /* schedule xfer */
480 return SCPE_OK;
481
482 case ESXFR:
483 estat[0] = ry_ecode; /* fill 8B status */
484 estat[1] = ry_wc;
485 estat[2] = ry_unit[0].TRACK;
486 estat[3] = ry_unit[1].TRACK;
487 estat[4] = ry_track;
488 estat[5] = ry_sector;
489 estat[6] = ((ry_csr & RYCS_DRV)? 0200: 0) |
490 ((ry_unit[1].flags & UNIT_DEN)? 0100: 0) |
491 ((uptr->flags & UNIT_ATT)? 0040: 0) |
492 ((ry_unit[0].flags & UNIT_DEN)? 0020: 0) |
493 ((ry_csr & RYCS_DEN)? 0001: 0);
494 estat[7] = uptr->TRACK;
495 t = Map_WriteB (ba, 8, estat); /* DMA to memory */
496 ry_done (t? RYES_NXM: 0, 0); /* done */
497 break;
498
499 case CMD_COMPLETE: /* command complete */
500 ry_done (0, 0);
501 break;
502
503 case INIT_COMPLETE: /* init complete */
504 ry_unit[0].TRACK = 1; /* drive 0 to trk 1 */
505 ry_unit[1].TRACK = 0; /* drive 1 to trk 0 */
506 if ((uptr->flags & UNIT_BUF) == 0) { /* not buffered? */
507 ry_done (RYES_ID, 0010); /* init done, error */
508 break;
509 }
510 da = CALC_DA (1, 1, bps); /* track 1, sector 1 */
511 for (i = 0; i < bps; i++) /* read sector */
512 rx2xb[i] = fbuf[da + i];
513 ry_done (RYES_ID, 0); /* set done */
514 if ((ry_unit[1].flags & UNIT_ATT) == 0) ry_ecode = 0020;
515 break;
516 } /* end case state */
517
518 return SCPE_OK;
519 }
520
521 /* Command complete. Set done and put final value in interface register,
522 request interrupt if needed, return to IDLE state.
523 */
524
525 void ry_done (int32 esr_flags, int32 new_ecode)
526 {
527 int32 drv = (ry_csr & RYCS_DRV)? 1: 0;
528
529 ry_state = IDLE; /* now idle */
530 ry_csr = ry_csr | RYCS_DONE; /* set done */
531 if (ry_csr & CSR_IE) SET_INT (RY); /* if ie, intr */
532 ry_esr = (ry_esr | esr_flags) & ~(RYES_USEL|RYES_DDEN|RYES_DRDY);
533 if (drv) ry_esr = ry_esr | RYES_USEL; /* updates RYES */
534 if (ry_unit[drv].flags & UNIT_ATT) {
535 ry_esr = ry_esr | RYES_DRDY;
536 if (ry_unit[drv].flags & UNIT_DEN)
537 ry_esr = ry_esr | RYES_DDEN;
538 }
539 if ((new_ecode > 0) || (ry_esr & RYES_ERR)) /* test for error */
540 ry_csr = ry_csr | RYCS_ERR;
541 ry_ecode = new_ecode; /* update ecode */
542 ry_dbr = ry_esr; /* update RYDB */
543 return;
544 }
545
546 /* Device initialization. The RY is one of the few devices that schedules
547 an I/O transfer as part of its initialization.
548 */
549
550 t_stat ry_reset (DEVICE *dptr)
551 {
552 ry_csr = ry_dbr = 0; /* clear registers */
553 ry_esr = ry_ecode = 0; /* clear error */
554 ry_ba = ry_wc = 0; /* clear wc, ba */
555 ry_track = ry_sector = 0; /* clear trk, sector */
556 ry_state = IDLE; /* ctrl idle */
557 CLR_INT (RY); /* clear int req */
558 sim_cancel (&ry_unit[1]); /* cancel drive 1 */
559 if (dptr->flags & UNIT_DIS) sim_cancel (&ry_unit[0]); /* disabled? */
560 else if (ry_unit[0].flags & UNIT_BUF) { /* attached? */
561 ry_state = INIT_COMPLETE; /* yes, sched init */
562 sim_activate (&ry_unit[0], ry_swait * abs (1 - ry_unit[0].TRACK));
563 }
564 else ry_done (RYES_ID, 0010); /* no, error */
565 return auto_config (0, 0); /* run autoconfig */
566 }
567
568 /* Attach routine */
569
570 t_stat ry_attach (UNIT *uptr, char *cptr)
571 {
572 uint32 sz;
573
574 if ((uptr->flags & UNIT_AUTO) && (sz = sim_fsize_name (cptr))) {
575 if (sz > RX_SIZE) uptr->flags = uptr->flags | UNIT_DEN;
576 else uptr->flags = uptr->flags & ~UNIT_DEN;
577 }
578 uptr->capac = (uptr->flags & UNIT_DEN)? RY_SIZE: RX_SIZE;
579 return attach_unit (uptr, cptr);
580 }
581
582 /* Set size routine */
583
584 t_stat ry_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)
585 {
586 if (uptr->flags & UNIT_ATT) return SCPE_ALATT;
587 uptr->capac = val? RY_SIZE: RX_SIZE;
588 return SCPE_OK;
589 }
590
591 /* Device bootstrap */
592
593 #if defined (VM_PDP11)
594
595 #define BOOT_START 02000 /* start */
596 #define BOOT_ENTRY (BOOT_START + 002) /* entry */
597 #define BOOT_UNIT (BOOT_START + 010) /* unit number */
598 #define BOOT_CSR (BOOT_START + 026) /* CSR */
599 #define BOOT_LEN (sizeof (boot_rom) / sizeof (int16))
600
601 static const uint16 boot_rom[] = {
602 042131, /* "YD" */
603 0012706, BOOT_START, /* MOV #boot_start, SP */
604 0012700, 0000000, /* MOV #unit, R0 ; unit number */
605 0010003, /* MOV R0, R3 */
606 0006303, /* ASL R3 */
607 0006303, /* ASL R3 */
608 0006303, /* ASL R3 */
609 0006303, /* ASL R3 */
610 0012701, 0177170, /* MOV #RYCS, R1 ; csr */
611 0005002, /* CLR R2 ; ba */
612 0005004, /* CLR R4 ; density */
613 0012705, 0000001, /* MOV #1, R5 ; sector */
614 0005104, /* DN: COM R4 ; compl dens */
615 0042704, 0177377, /* BIC #177377, R4 ; clr rest */
616 0032711, 0000040, /* RD: BIT #40, (R1) ; ready? */
617 0001775, /* BEQ .-4 */
618 0012746, 0000007, /* MOV #READ+GO, -(SP) */
619 0050316, /* BIS R3, (SP) ; or unit */
620 0050416, /* BIS R4, (SP) ; or density */
621 0012611, /* MOV (SP)+, (R1) ; read & go */
622 0105711, /* TSTB (R1) ; xfr ready? */
623 0100376, /* BPL .-2 */
624 0010561, 0000002, /* MOV R5, 2(R1) ; sector */
625 0105711, /* TSTB (R1) ; xfr ready? */
626 0100376, /* BPL .-2 */
627 0012761, 0000001, 0000002, /* MOV #1, 2(R1) ; track */
628 0032711, 0000040, /* BIT #40, (R1) ; ready? */
629 0001775, /* BEQ .-4 */
630 0005711, /* TST (R1) ; error? */
631 0100003, /* BEQ OK */
632 0005704, /* TST R4 ; single? */
633 0001345, /* BNE DN ; no, try again */
634 0000000, /* HALT ; dead */
635 0012746, 0000003, /* OK: MOV #EMPTY+GO, -(SP); empty & go */
636 0050416, /* BIS R4, (SP) ; or density */
637 0012611, /* MOV (SP)+, (R1) ; read & go */
638 0105711, /* TSTB (R1) ; xfr, done? */
639 0001776, /* BPL .-2 */
640 0012746, 0000100, /* MOV #100, -(SP) ; assume sd */
641 0005704, /* TST R4 ; test dd */
642 0001401, /* BEQ .+4 */
643 0006316, /* ASL (SP) ; dd, double */
644 0011661, 0000002, /* MOV (SP), 2(R1) ; wc */
645 0105711, /* TSTB (R1) ; xfr, done? */
646 0001776, /* BPL .-2 */
647 0010261, 0000002, /* MOV R2, 2(R1) ; ba */
648 0032711, 0000040, /* BIT #40, (R1) ; ready? */
649 0001775, /* BEQ .-4 */
650 0061602, /* ADD (SP), R2 ; cvt wd to byte */
651 0062602, /* ADD (SP)+, R2 ; adv buf addr */
652 0122525, /* CMPB (R5)+, (R5)+ ; sect += 2 */
653 0020527, 0000007, /* CMP R5, #7 ; end? */
654 0101715, /* BLOS RD ; read next */
655 0005002, /* CLR R2 */
656 0005003, /* CLR R3 */
657 0012704, BOOT_START+020, /* MOV #START+20, R4 */
658 0005005, /* CLR R5 */
659 0005007 /* CLR R7 */
660 };
661
662 t_stat ry_boot (int32 unitno, DEVICE *dptr)
663 {
664 int32 i;
665 extern int32 saved_PC;
666 extern uint16 *M;
667
668 if ((ry_unit[unitno & RX_M_NUMDR].flags & UNIT_DEN) == 0)
669 return SCPE_NOFNC;
670 for (i = 0; i < BOOT_LEN; i++) M[(BOOT_START >> 1) + i] = boot_rom[i];
671 M[BOOT_UNIT >> 1] = unitno & RX_M_NUMDR;
672 M[BOOT_CSR >> 1] = ry_dib.ba & DMASK;
673 saved_PC = BOOT_ENTRY;
674 return SCPE_OK;
675 }
676
677 #else
678
679 t_stat ry_boot (int32 unitno, DEVICE *dptr)
680 {
681 return SCPE_NOFNC;
682 }
683
684 #endif