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