1 /* pdp11_ry.c: RX211/RXV21/RX02 floppy disk simulator
3 Copyright (c) 1993-2006, Robert M Supnik
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:
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
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.
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.
26 ry RX211/RXV21/RX02 floppy disk
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
40 An RX02 diskette consists of 77 tracks, each with 26 sectors of 256B.
41 Tracks are numbered 0-76, sectors 1-26.
44 #if defined (VM_PDP10) /* PDP10 version */
45 #include "pdp10_defs.h"
47 #define DEV_DISI DEV_DIS
49 #elif defined (VM_VAX) /* VAX version */
51 extern int32 int_req
[IPL_HLVL
];
54 #else /* PDP-11 version */
55 #include "pdp11_defs.h"
56 extern int32 int_req
[IPL_HLVL
];
57 #define DEV_DISI DEV_DIS
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
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 */
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 */
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 */
92 #define RYCS_V_FUNC 1 /* function */
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)
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)
140 #define TRACK u3 /* current track */
141 #define CALC_DA(t,s,b) (((t) * RX_NUMSC) + ((s) - 1)) * b
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 */
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
);
168 /* RY11 data structures
170 ry_dev RY device descriptor
172 ry_reg RY register list
173 ry_mod RY modifier list
177 IOBA_RY
, IOLN_RY
, &ry_rd
, &ry_wr
,
178 1, IVCL (RY
), VEC_RY
, { NULL
}
182 { UDATA (&ry_svc
, UNIT_DEN
+UNIT_FIX
+UNIT_ATTABLE
+UNIT_BUFABLE
+UNIT_MUSTBUF
,
184 { UDATA (&ry_svc
, UNIT_DEN
+UNIT_FIX
+UNIT_ATTABLE
+UNIT_BUFABLE
+UNIT_MUSTBUF
,
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
},
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
},
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
245 /* I/O dispatch routine, I/O addresses 17777170 - 17777172
248 17777172 floppy data register
251 t_stat
ry_rd (int32
*data
, int32 PA
, int32 access
)
253 switch ((PA
>> 1) & 1) { /* decode PA<1> */
256 ry_csr
= (ry_csr
& RYCS_IMP
) | RYCS_RY
; /* clear junk */
261 *data
= ry_dbr
; /* return data */
263 } /* end switch PA */
268 t_stat
ry_wr (int32 data
, int32 PA
, int32 access
)
272 switch ((PA
>> 1) & 1) { /* decode PA<1> */
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
280 3. Otherwise, write IE and update interrupts
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 */
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
)) {
296 case RYCS_FILL
: case RYCS_EMPTY
:
297 ry_state
= FEWC
; /* state = get wc */
298 ry_csr
= ry_csr
| RYCS_TR
; /* xfer is ready */
302 ry_state
= SDCNF
; /* state = get conf */
303 ry_csr
= ry_csr
| RYCS_TR
; /* xfer is ready */
307 ry_state
= ESBA
; /* state = get ba */
308 ry_csr
= ry_csr
| RYCS_TR
; /* xfer is ready */
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 */
319 ry_state
= CMD_COMPLETE
; /* state = cmd compl */
320 sim_activate (&ry_unit
[drv
], ry_cwait
);
322 } /* end switch func */
325 if ((data
& RYCS_IE
) == 0) CLR_INT (RY
);
326 else if ((ry_csr
& (RYCS_DONE
+ RYCS_IE
)) == RYCS_DONE
)
328 ry_csr
= (ry_csr
& ~RYCS_RW
) | (data
& RYCS_RW
);
329 break; /* end case RYCS */
331 /* Accessing RYDB, two cases:
333 2. Write not idle and TR set, state dependent
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 */
345 break; /* end case RYDB */
346 } /* end switch PA */
351 /* Unit service; the action to be taken depends on the transfer state:
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
362 CMD_COMPLETE copy requested data to ir, finish command
363 INIT_COMPLETE read drive 0, track 1, sector 1 to buffer, finish command
366 t_stat
ry_svc (UNIT
*uptr
)
368 int32 i
, t
, func
, bps
;
369 static uint8 estat
[8];
371 int8
*fbuf
= uptr
->filebuf
;
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 */
378 case IDLE
: /* idle */
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 */
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 */
393 case FEXFR
: /* transfer */
394 if ((ry_wc
<< 1) > bps
) { /* wc too big? */
395 ry_done (RYES_WCO
, 0230); /* error */
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
);
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 */
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 */
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
));
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
);
425 if (ry_track
>= RX_NUMTR
) { /* bad track? */
426 ry_done (0, 0040); /* done, error */
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 */
434 if (((uptr
->flags
& UNIT_DEN
) != 0) ^
435 ((ry_csr
& RYCS_DEN
) != 0)) { /* densities agree? */
436 ry_done (RYES_DERR
, 0240); /* no, error */
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
];
446 if (uptr
->flags
& UNIT_WPRT
) { /* write and locked? */
447 ry_done (0, 0100); /* done, error */
450 for (i
= 0; i
< bps
; i
++) /* write */
451 fbuf
[da
+ i
] = rx2xb
[i
];
453 if (da
> uptr
->hwmark
) uptr
->hwmark
= da
;
455 ry_done (0, 0); /* done */
458 case SDCNF
: /* confirm set density */
459 if ((ry_dbr
& 0377) != 0111) { /* confirmed? */
460 ry_done (0, 0250); /* no, error */
463 ry_state
= SDXFR
; /* next state */
464 sim_activate (uptr
, ry_cwait
* 100); /* schedule operation */
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
;
477 ry_ba
= ry_dbr
; /* save WC */
478 ry_state
= ESXFR
; /* next state */
479 sim_activate (uptr
, ry_cwait
); /* schedule xfer */
483 estat
[0] = ry_ecode
; /* fill 8B status */
485 estat
[2] = ry_unit
[0].TRACK
;
486 estat
[3] = ry_unit
[1].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 */
499 case CMD_COMPLETE
: /* command complete */
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 */
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;
516 } /* end case state */
521 /* Command complete. Set done and put final value in interface register,
522 request interrupt if needed, return to IDLE state.
525 void ry_done (int32 esr_flags
, int32 new_ecode
)
527 int32 drv
= (ry_csr
& RYCS_DRV
)? 1: 0;
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
;
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 */
546 /* Device initialization. The RY is one of the few devices that schedules
547 an I/O transfer as part of its initialization.
550 t_stat
ry_reset (DEVICE
*dptr
)
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
));
564 else ry_done (RYES_ID
, 0010); /* no, error */
565 return auto_config (0, 0); /* run autoconfig */
570 t_stat
ry_attach (UNIT
*uptr
, char *cptr
)
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
;
578 uptr
->capac
= (uptr
->flags
& UNIT_DEN
)? RY_SIZE
: RX_SIZE
;
579 return attach_unit (uptr
, cptr
);
582 /* Set size routine */
584 t_stat
ry_set_size (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
)
586 if (uptr
->flags
& UNIT_ATT
) return SCPE_ALATT
;
587 uptr
->capac
= val
? RY_SIZE
: RX_SIZE
;
591 /* Device bootstrap */
593 #if defined (VM_PDP11)
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))
601 static const uint16 boot_rom
[] = {
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 */
662 t_stat
ry_boot (int32 unitno
, DEVICE
*dptr
)
665 extern int32 saved_PC
;
668 if ((ry_unit
[unitno
& RX_M_NUMDR
].flags
& UNIT_DEN
) == 0)
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
;
679 t_stat
ry_boot (int32 unitno
, DEVICE
*dptr
)