1 /* pdp8_rl.c: RL8A cartridge disk simulator
2
3 Copyright (c) 1993-2011, 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 rl RL8A cartridge disk
27
28 25-Oct-05 RMS Fixed IOT 61 decode bug (David Gesswein)
29 16-Aug-05 RMS Fixed C++ declaration and cast problems
30 04-Jan-04 RMS Changed attach routine to use sim_fsize
31 25-Apr-03 RMS Revised for extended file support
32 04-Oct-02 RMS Added DIB, device number support
33 06-Jan-02 RMS Changed enable/disable support
34 30-Nov-01 RMS Cloned from RL11
35
36 The RL8A is a four drive cartridge disk subsystem. An RL01 drive
37 consists of 256 cylinders, each with 2 surfaces containing 40 sectors
38 of 256 bytes. An RL02 drive has 512 cylinders.
39
40 The RL8A controller has several serious complications.
41 - Seeking is relative to the current disk address; this requires
42 keeping accurate track of the current cylinder.
43 - The RL8A will not switch heads or cross cylinders during transfers.
44 - The RL8A operates in 8b and 12b mode, like the RX8E; in 12b mode, it
45 packs 2 12b words into 3 bytes, creating a 170 "word" sector with
46 one wasted byte. Multi-sector transfers in 12b mode don't work.
47 */
48
49 #include "pdp8_defs.h"
50
51 /* Constants */
52
53 #define RL_NUMBY 256 /* 8b bytes/sector */
54 #define RL_NUMSC 40 /* sectors/surface */
55 #define RL_NUMSF 2 /* surfaces/cylinder */
56 #define RL_NUMCY 256 /* cylinders/drive */
57 #define RL_NUMDR 4 /* drives/controller */
58 #define RL_MAXFR (1 << 12) /* max transfer */
59 #define RL01_SIZE (RL_NUMCY*RL_NUMSF*RL_NUMSC*RL_NUMBY) /* words/drive */
60 #define RL02_SIZE (RL01_SIZE * 2) /* words/drive */
61 #define RL_BBMAP 014 /* sector for bblk map */
62 #define RL_BBID 0123 /* ID for bblk map */
63
64 /* Flags in the unit flags word */
65
66 #define UNIT_V_WLK (UNIT_V_UF + 0) /* write lock */
67 #define UNIT_V_RL02 (UNIT_V_UF + 1) /* RL01 vs RL02 */
68 #define UNIT_V_AUTO (UNIT_V_UF + 2) /* autosize enable */
69 #define UNIT_V_DUMMY (UNIT_V_UF + 3) /* dummy flag */
70 #define UNIT_DUMMY (1u << UNIT_V_DUMMY)
71 #define UNIT_WLK (1u << UNIT_V_WLK)
72 #define UNIT_RL02 (1u << UNIT_V_RL02)
73 #define UNIT_AUTO (1u << UNIT_V_AUTO)
74 #define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */
75
76 /* Parameters in the unit descriptor */
77
78 #define TRK u3 /* current cylinder */
79 #define STAT u4 /* status */
80
81 /* RLDS, NI = not implemented, * = kept in STAT, ^ = kept in TRK */
82
83 #define RLDS_LOAD 0 /* no cartridge */
84 #define RLDS_LOCK 5 /* lock on */
85 #define RLDS_BHO 0000010 /* brushes home NI */
86 #define RLDS_HDO 0000020 /* heads out NI */
87 #define RLDS_CVO 0000040 /* cover open NI */
88 #define RLDS_HD 0000100 /* head select ^ */
89 #define RLDS_RL02 0000200 /* RL02 */
90 #define RLDS_DSE 0000400 /* drv sel err NI */
91 #define RLDS_VCK 0001000 /* vol check * */
92 #define RLDS_WGE 0002000 /* wr gate err * */
93 #define RLDS_SPE 0004000 /* spin err * */
94 #define RLDS_STO 0010000 /* seek time out NI */
95 #define RLDS_WLK 0020000 /* wr locked */
96 #define RLDS_HCE 0040000 /* hd curr err NI */
97 #define RLDS_WDE 0100000 /* wr data err NI */
98 #define RLDS_ATT (RLDS_HDO+RLDS_BHO+RLDS_LOCK) /* att status */
99 #define RLDS_UNATT (RLDS_CVO+RLDS_LOAD) /* unatt status */
100 #define RLDS_ERR (RLDS_WDE+RLDS_HCE+RLDS_STO+RLDS_SPE+RLDS_WGE+ \
101 RLDS_VCK+RLDS_DSE) /* errors bits */
102
103 /* RLCSA, seek = offset/rw = address (also uptr->TRK) */
104
105 #define RLCSA_DIR 04000 /* direction */
106 #define RLCSA_HD 02000 /* head select */
107 #define RLCSA_CYL 00777 /* cyl offset */
108 #define GET_CYL(x) ((x) & RLCSA_CYL)
109 #define GET_TRK(x) ((((x) & RLCSA_CYL) * RL_NUMSF) + \
110 (((x) & RLCSA_HD)? 1: 0))
111 #define GET_DA(x) ((GET_TRK(x) * RL_NUMSC) + rlsa)
112
113 /* RLCSB, function/unit select */
114
115 #define RLCSB_V_FUNC 0 /* function */
116 #define RLCSB_M_FUNC 07
117 #define RLCSB_MNT 0
118 #define RLCSB_CLRD 1
119 #define RLCSB_GSTA 2
120 #define RLCSB_SEEK 3
121 #define RLCSB_RHDR 4
122 #define RLCSB_WRITE 5
123 #define RLCSB_READ 6
124 #define RLCSB_RNOHDR 7
125 #define RLCSB_V_MEX 3 /* memory extension */
126 #define RLCSB_M_MEX 07
127 #define RLCSB_V_DRIVE 6 /* drive */
128 #define RLCSB_M_DRIVE 03
129 #define RLCSB_V_IE 8 /* int enable */
130 #define RLCSB_IE (1u << RLCSB_V_IE)
131 #define RLCSB_8B 01000 /* 12b/8b */
132 #define RCLS_MNT 02000 /* maint NI */
133 #define RLCSB_RW 0001777 /* read/write */
134 #define GET_FUNC(x) (((x) >> RLCSB_V_FUNC) & RLCSB_M_FUNC)
135 #define GET_MEX(x) (((x) >> RLCSB_V_MEX) & RLCSB_M_MEX)
136 #define GET_DRIVE(x) (((x) >> RLCSB_V_DRIVE) & RLCSB_M_DRIVE)
137
138 /* RLSA, disk sector */
139
140 #define RLSA_V_SECT 6 /* sector */
141 #define RLSA_M_SECT 077
142 #define GET_SECT(x) (((x) >> RLSA_V_SECT) & RLSA_M_SECT)
143
144 /* RLER, error register */
145
146 #define RLER_DRDY 00001 /* drive ready */
147 #define RLER_DRE 00002 /* drive error */
148 #define RLER_HDE 01000 /* header error */
149 #define RLER_INCMP 02000 /* incomplete */
150 #define RLER_ICRC 04000 /* CRC error */
151 #define RLER_MASK 07003
152
153 /* RLSI, silo register, used only in read header */
154
155 #define RLSI_V_TRK 6 /* track */
156
157 extern uint16 M[];
158 extern int32 int_req;
159 extern UNIT cpu_unit;
160
161 uint8 *rlxb = NULL; /* xfer buffer */
162 int32 rlcsa = 0; /* control/status A */
163 int32 rlcsb = 0; /* control/status B */
164 int32 rlma = 0; /* memory address */
165 int32 rlwc = 0; /* word count */
166 int32 rlsa = 0; /* sector address */
167 int32 rler = 0; /* error register */
168 int32 rlsi = 0, rlsi1 = 0, rlsi2 = 0; /* silo queue */
169 int32 rl_lft = 0; /* silo left/right */
170 int32 rl_done = 0; /* done flag */
171 int32 rl_erf = 0; /* error flag */
172 int32 rl_swait = 10; /* seek wait */
173 int32 rl_rwait = 10; /* rotate wait */
174 int32 rl_stopioe = 1; /* stop on error */
175
176 DEVICE rl_dev;
177 int32 rl60 (int32 IR, int32 AC);
178 int32 rl61 (int32 IR, int32 AC);
179 t_stat rl_svc (UNIT *uptr);
180 t_stat rl_reset (DEVICE *dptr);
181 void rl_set_done (int32 error);
182 t_stat rl_boot (int32 unitno, DEVICE *dptr);
183 t_stat rl_attach (UNIT *uptr, char *cptr);
184 t_stat rl_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
185 t_stat rl_set_bad (UNIT *uptr, int32 val, char *cptr, void *desc);
186
187 /* RL8A data structures
188
189 rl_dev RL device descriptor
190 rl_unit RL unit list
191 rl_reg RL register list
192 rl_mod RL modifier list
193 */
194
195 DIB rl_dib = { DEV_RL, 2, { &rl60, &rl61 } };
196
197 UNIT rl_unit[] = {
198 { UDATA (&rl_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+
199 UNIT_ROABLE, RL01_SIZE) },
200 { UDATA (&rl_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+
201 UNIT_ROABLE, RL01_SIZE) },
202 { UDATA (&rl_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+
203 UNIT_ROABLE, RL01_SIZE) },
204 { UDATA (&rl_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+
205 UNIT_ROABLE, RL01_SIZE) }
206 };
207
208 REG rl_reg[] = {
209 { ORDATA (RLCSA, rlcsa, 12) },
210 { ORDATA (RLCSB, rlcsb, 12) },
211 { ORDATA (RLMA, rlma, 12) },
212 { ORDATA (RLWC, rlwc, 12) },
213 { ORDATA (RLSA, rlsa, 6) },
214 { ORDATA (RLER, rler, 12) },
215 { ORDATA (RLSI, rlsi, 16) },
216 { ORDATA (RLSI1, rlsi1, 16) },
217 { ORDATA (RLSI2, rlsi2, 16) },
218 { FLDATA (RLSIL, rl_lft, 0) },
219 { FLDATA (INT, int_req, INT_V_RL) },
220 { FLDATA (DONE, rl_done, INT_V_RL) },
221 { FLDATA (IE, rlcsb, RLCSB_V_IE) },
222 { FLDATA (ERR, rl_erf, 0) },
223 { DRDATA (STIME, rl_swait, 24), PV_LEFT },
224 { DRDATA (RTIME, rl_rwait, 24), PV_LEFT },
225 { URDATA (CAPAC, rl_unit[0].capac, 10, T_ADDR_W, 0,
226 RL_NUMDR, PV_LEFT + REG_HRO) },
227 { FLDATA (STOP_IOE, rl_stopioe, 0) },
228 { ORDATA (DEVNUM, rl_dib.dev, 6), REG_HRO },
229 { NULL }
230 };
231
232 MTAB rl_mod[] = {
233 { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL },
234 { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL },
235 { UNIT_DUMMY, 0, NULL, "BADBLOCK", &rl_set_bad },
236 { (UNIT_RL02+UNIT_ATT), UNIT_ATT, "RL01", NULL, NULL },
237 { (UNIT_RL02+UNIT_ATT), (UNIT_RL02+UNIT_ATT), "RL02", NULL, NULL },
238 { (UNIT_AUTO+UNIT_RL02+UNIT_ATT), 0, "RL01", NULL, NULL },
239 { (UNIT_AUTO+UNIT_RL02+UNIT_ATT), UNIT_RL02, "RL02", NULL, NULL },
240 { (UNIT_AUTO+UNIT_ATT), UNIT_AUTO, "autosize", NULL, NULL },
241 { UNIT_AUTO, UNIT_AUTO, NULL, "AUTOSIZE", NULL },
242 { (UNIT_AUTO+UNIT_RL02), 0, NULL, "RL01", &rl_set_size },
243 { (UNIT_AUTO+UNIT_RL02), UNIT_RL02, NULL, "RL02", &rl_set_size },
244 { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",
245 &set_dev, &show_dev, NULL },
246 { 0 }
247 };
248
249 DEVICE rl_dev = {
250 "RL", rl_unit, rl_reg, rl_mod,
251 RL_NUMDR, 8, 24, 1, 8, 8,
252 NULL, NULL, &rl_reset,
253 &rl_boot, &rl_attach, NULL,
254 &rl_dib, DEV_DISABLE | DEV_DIS
255 };
256
257 /* IOT routines */
258
rl60(int32 IR,int32 AC)259 int32 rl60 (int32 IR, int32 AC)
260 {
261 int32 curr, offs, newc, maxc;
262 UNIT *uptr;
263
264 switch (IR & 07) { /* case IR<9:11> */
265
266 case 0: /* RLDC */
267 rl_reset (&rl_dev); /* reset device */
268 break;
269
270 case 1: /* RLSD */
271 if (rl_done) /* skip if done */
272 AC = IOT_SKP;
273 else AC = 0;
274 rl_done = 0; /* clear done */
275 int_req = int_req & ~INT_RL; /* clear intr */
276 return AC;
277
278 case 2: /* RLMA */
279 rlma = AC;
280 break;
281
282 case 3: /* RLCA */
283 rlcsa = AC;
284 break;
285
286 case 4: /* RLCB */
287 rlcsb = AC;
288 rl_done = 0; /* clear done */
289 rler = rl_erf = 0; /* clear errors */
290 int_req = int_req & ~INT_RL; /* clear intr */
291 rl_lft = 0; /* clear silo ptr */
292 uptr = rl_dev.units + GET_DRIVE (rlcsb); /* select unit */
293 switch (GET_FUNC (rlcsb)) { /* case on func */
294
295 case RLCSB_CLRD: /* clear drive */
296 uptr->STAT = uptr->STAT & ~RLDS_ERR; /* clear errors */
297 case RLCSB_MNT: /* mnt */
298 rl_set_done (0);
299 break;
300
301 case RLCSB_SEEK: /* seek */
302 curr = GET_CYL (uptr->TRK); /* current cylinder */
303 offs = GET_CYL (rlcsa); /* offset */
304 if (rlcsa & RLCSA_DIR) { /* in or out? */
305 newc = curr + offs; /* out */
306 maxc = (uptr->flags & UNIT_RL02)?
307 RL_NUMCY * 2: RL_NUMCY;
308 if (newc >= maxc) newc = maxc - 1;
309 }
310 else {
311 newc = curr - offs; /* in */
312 if (newc < 0) newc = 0;
313 }
314 uptr->TRK = newc | (rlcsa & RLCSA_HD);
315 sim_activate (uptr, rl_swait * abs (newc - curr));
316 break;
317
318 default: /* data transfer */
319 sim_activate (uptr, rl_swait); /* activate unit */
320 break;
321 } /* end switch func */
322 break;
323
324 case 5: /* RLSA */
325 rlsa = GET_SECT (AC);
326 break;
327
328 case 6: /* spare */
329 return 0;
330
331 case 7: /* RLWC */
332 rlwc = AC;
333 break;
334 } /* end switch pulse */
335
336 return 0; /* clear AC */
337 }
338
rl61(int32 IR,int32 AC)339 int32 rl61 (int32 IR, int32 AC)
340 {
341 int32 dat;
342 UNIT *uptr;
343
344 switch (IR & 07) { /* case IR<9:11> */
345
346 case 0: /* RRER */
347 uptr = rl_dev.units + GET_DRIVE (rlcsb); /* select unit */
348 if (!sim_is_active (uptr) && /* update drdy */
349 (uptr->flags & UNIT_ATT))
350 rler = rler | RLER_DRDY;
351 else rler = rler & ~RLER_DRDY;
352 dat = rler & RLER_MASK;
353 break;
354
355 case 1: /* RRWC */
356 dat = rlwc;
357 break;
358
359 case 2: /* RRCA */
360 dat = rlcsa;
361 break;
362
363 case 3: /* RRCB */
364 dat = rlcsb;
365 break;
366
367 case 4: /* RRSA */
368 dat = (rlsa << RLSA_V_SECT) & 07777;
369 break;
370
371 case 5: /* RRSI */
372 if (rl_lft) { /* silo left? */
373 dat = (rlsi >> 8) & 0377; /* get left 8b */
374 rlsi = rlsi1; /* ripple */
375 rlsi1 = rlsi2;
376 }
377 else dat = rlsi & 0377; /* get right 8b */
378 rl_lft = rl_lft ^ 1; /* change side */
379 break;
380
381 case 6: /* spare */
382 return AC;
383
384 case 7: /* RLSE */
385 if (rl_erf) /* skip if err */
386 dat = IOT_SKP | AC;
387 else dat = AC;
388 rl_erf = 0;
389 break;
390 } /* end switch pulse */
391
392 return dat;
393 }
394
395 /* Service unit timeout
396
397 If seek in progress, complete seek command
398 Else complete data transfer command
399
400 The unit control block contains the function and cylinder for
401 the current command.
402 */
403
rl_svc(UNIT * uptr)404 t_stat rl_svc (UNIT *uptr)
405 {
406 int32 err, wc, maxc;
407 int32 i, j, func, da, bc, wbc;
408 uint32 ma;
409
410 func = GET_FUNC (rlcsb); /* get function */
411 if (func == RLCSB_GSTA) { /* get status? */
412 rlsi = uptr->STAT |
413 ((uptr->TRK & RLCSA_HD)? RLDS_HD: 0) |
414 ((uptr->flags & UNIT_ATT)? RLDS_ATT: RLDS_UNATT);
415 if (uptr->flags & UNIT_RL02)
416 rlsi = rlsi | RLDS_RL02;
417 if (uptr->flags & UNIT_WPRT)
418 rlsi = rlsi | RLDS_WLK;
419 rlsi2 = rlsi1 = rlsi;
420 rl_set_done (0); /* done */
421 return SCPE_OK;
422 }
423
424 if ((uptr->flags & UNIT_ATT) == 0) { /* attached? */
425 uptr->STAT = uptr->STAT | RLDS_SPE; /* spin error */
426 rl_set_done (RLER_INCMP); /* flag error */
427 return IORETURN (rl_stopioe, SCPE_UNATT);
428 }
429
430 if ((func == RLCSB_WRITE) && (uptr->flags & UNIT_WPRT)) {
431 uptr->STAT = uptr->STAT | RLDS_WGE; /* write and locked */
432 rl_set_done (RLER_DRE); /* flag error */
433 return SCPE_OK;
434 }
435
436 if (func == RLCSB_SEEK) { /* seek? */
437 rl_set_done (0); /* done */
438 return SCPE_OK;
439 }
440
441 if (func == RLCSB_RHDR) { /* read header? */
442 rlsi = (GET_TRK (uptr->TRK) << RLSI_V_TRK) | rlsa;
443 rlsi1 = rlsi2 = 0;
444 rl_set_done (0); /* done */
445 return SCPE_OK;
446 }
447
448 if (((func != RLCSB_RNOHDR) && (GET_CYL (uptr->TRK) != GET_CYL (rlcsa)))
449 || (rlsa >= RL_NUMSC)) { /* bad cyl or sector? */
450 rl_set_done (RLER_HDE | RLER_INCMP); /* flag error */
451 return SCPE_OK;
452 }
453
454 ma = (GET_MEX (rlcsb) << 12) | rlma; /* get mem addr */
455 da = GET_DA (rlcsa) * RL_NUMBY; /* get disk addr */
456 wc = 010000 - rlwc; /* get true wc */
457 if (rlcsb & RLCSB_8B) { /* 8b mode? */
458 bc = wc; /* bytes to xfr */
459 maxc = (RL_NUMSC - rlsa) * RL_NUMBY; /* max transfer */
460 if (bc > maxc) /* trk ovrun? limit */
461 wc = bc = maxc;
462 }
463 else {
464 bc = ((wc * 3) + 1) / 2; /* 12b mode */
465 if (bc > RL_NUMBY) { /* > 1 sector */
466 bc = RL_NUMBY; /* cap xfer */
467 wc = (RL_NUMBY * 2) / 3;
468 }
469 }
470
471 err = fseek (uptr->fileref, da, SEEK_SET);
472
473 if ((func >= RLCSB_READ) && (err == 0) && /* read (no hdr)? */
474 MEM_ADDR_OK (ma)) { /* valid bank? */
475 i = fxread (rlxb, sizeof (int8), bc, uptr->fileref);
476 err = ferror (uptr->fileref);
477 for ( ; i < bc; i++) /* fill buffer */
478 rlxb[i] = 0;
479 for (i = j = 0; i < wc; i++) { /* store buffer */
480 if (rlcsb & RLCSB_8B) /* 8b mode? */
481 M[ma] = rlxb[i] & 0377; /* store */
482 else if (i & 1) { /* odd wd 12b? */
483 M[ma] = ((rlxb[j + 1] >> 4) & 017) |
484 (((uint16) rlxb[j + 2]) << 4);
485 j = j + 3;
486 }
487 else M[ma] = rlxb[j] | /* even wd 12b */
488 ((((uint16) rlxb[j + 1]) & 017) << 8);
489 ma = (ma & 070000) + ((ma + 1) & 07777);
490 } /* end for */
491 } /* end if wr */
492
493 if ((func == RLCSB_WRITE) && (err == 0)) { /* write? */
494 for (i = j = 0; i < wc; i++) { /* fetch buffer */
495 if (rlcsb & RLCSB_8B) /* 8b mode? */
496 rlxb[i] = M[ma] & 0377; /* fetch */
497 else if (i & 1) { /* odd wd 12b? */
498 rlxb[j + 1] = rlxb[j + 1] | ((M[ma] & 017) << 4);
499 rlxb[j + 2] = ((M[ma] >> 4) & 0377);
500 j = j + 3;
501 }
502 else { /* even wd 12b */
503 rlxb[j] = M[ma] & 0377;
504 rlxb[j + 1] = (M[ma] >> 8) & 017;
505 }
506 ma = (ma & 070000) + ((ma + 1) & 07777);
507 } /* end for */
508 wbc = (bc + (RL_NUMBY - 1)) & ~(RL_NUMBY - 1); /* clr to */
509 for (i = bc; i < wbc; i++) /* end of blk */
510 rlxb[i] = 0;
511 fxwrite (rlxb, sizeof (int8), wbc, uptr->fileref);
512 err = ferror (uptr->fileref);
513 } /* end write */
514
515 rlwc = (rlwc + wc) & 07777; /* final word count */
516 if (rlwc != 0) /* completed? */
517 rler = rler | RLER_INCMP;
518 rlma = (rlma + wc) & 07777; /* final word addr */
519 rlsa = rlsa + ((bc + (RL_NUMBY - 1)) / RL_NUMBY);
520 rl_set_done (0);
521
522 if (err != 0) { /* error? */
523 perror ("RL I/O error");
524 clearerr (uptr->fileref);
525 return SCPE_IOERR;
526 }
527 return SCPE_OK;
528 }
529
530 /* Set done and possibly errors */
531
rl_set_done(int32 status)532 void rl_set_done (int32 status)
533 {
534 rl_done = 1;
535 rler = rler | status;
536 if (rler)
537 rl_erf = 1;
538 if (rlcsb & RLCSB_IE)
539 int_req = int_req | INT_RL;
540 else int_req = int_req & ~INT_RL;
541 return;
542 }
543
544 /* Device reset
545
546 Note that the RL8A does NOT recalibrate its drives on RESET
547 */
548
rl_reset(DEVICE * dptr)549 t_stat rl_reset (DEVICE *dptr)
550 {
551 int32 i;
552 UNIT *uptr;
553
554 rlcsa = rlcsb = rlsa = rler = 0;
555 rlma = rlwc = 0;
556 rlsi = rlsi1 = rlsi2 = 0;
557 rl_lft = 0;
558 rl_done = 0;
559 rl_erf = 0;
560 int_req = int_req & ~INT_RL;
561 for (i = 0; i < RL_NUMDR; i++) {
562 uptr = rl_dev.units + i;
563 sim_cancel (uptr);
564 uptr->STAT = 0;
565 }
566 if (rlxb == NULL)
567 rlxb = (uint8 *) calloc (RL_MAXFR, sizeof (uint8));
568 if (rlxb == NULL)
569 return SCPE_MEM;
570 return SCPE_OK;
571 }
572
573 /* Attach routine */
574
rl_attach(UNIT * uptr,char * cptr)575 t_stat rl_attach (UNIT *uptr, char *cptr)
576 {
577 uint32 p;
578 t_stat r;
579
580 uptr->capac = (uptr->flags & UNIT_RL02)? RL02_SIZE: RL01_SIZE;
581 r = attach_unit (uptr, cptr); /* attach unit */
582 if (r != SCPE_OK) /* error? */
583 return r;
584 uptr->TRK = 0; /* cyl 0 */
585 uptr->STAT = RLDS_VCK; /* new volume */
586 if ((p = sim_fsize (uptr->fileref)) == 0) { /* new disk image? */
587 if (uptr->flags & UNIT_RO)
588 return SCPE_OK;
589 return rl_set_bad (uptr, 0, NULL, NULL);
590 }
591 if ((uptr->flags & UNIT_AUTO) == 0) /* autosize? */
592 return r;
593 if (p > (RL01_SIZE * sizeof (int16))) {
594 uptr->flags = uptr->flags | UNIT_RL02;
595 uptr->capac = RL02_SIZE;
596 }
597 else {
598 uptr->flags = uptr->flags & ~UNIT_RL02;
599 uptr->capac = RL01_SIZE;
600 }
601 return SCPE_OK;
602 }
603
604 /* Set size routine */
605
rl_set_size(UNIT * uptr,int32 val,char * cptr,void * desc)606 t_stat rl_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)
607 {
608 if (uptr->flags & UNIT_ATT)
609 return SCPE_ALATT;
610 uptr->capac = (val & UNIT_RL02)? RL02_SIZE: RL01_SIZE;
611 return SCPE_OK;
612 }
613
614 /* Factory bad block table creation routine
615
616 This routine writes the OS/8 specific bad block map in track 0, sector 014 (RL_BBMAP):
617
618 words 0 magic number = 0123 (RL_BBID)
619 words 1-n block numbers
620 :
621 words n+1 end of table = 0
622
623 Inputs:
624 uptr = pointer to unit
625 val = ignored
626 Outputs:
627 sta = status code
628 */
629
rl_set_bad(UNIT * uptr,int32 val,char * cptr,void * desc)630 t_stat rl_set_bad (UNIT *uptr, int32 val, char *cptr, void *desc)
631 {
632 int32 i, da = RL_BBMAP * RL_NUMBY;
633
634 if ((uptr->flags & UNIT_ATT) == 0)
635 return SCPE_UNATT;
636 if (uptr->flags & UNIT_RO)
637 return SCPE_RO;
638 if (!get_yn ("Create bad block table? [N]", FALSE))
639 return SCPE_OK;
640 if (fseek (uptr->fileref, da, SEEK_SET))
641 return SCPE_IOERR;
642 rlxb[0] = RL_BBID;
643 for (i = 1; i < RL_NUMBY; i++)
644 rlxb[i] = 0;
645 fxwrite (rlxb, sizeof (uint8), RL_NUMBY, uptr->fileref);
646 if (ferror (uptr->fileref))
647 return SCPE_IOERR;
648 return SCPE_OK;
649 }
650
651 /* Bootstrap */
652
653 #define BOOT_START 1 /* start */
654 #define BOOT_UNIT 02006 /* unit number */
655 #define BOOT_LEN (sizeof (boot_rom) / sizeof (int16))
656
657 static const uint16 boot_rom[] = {
658 06600, /* BT, RLDC ; reset */
659 07201, /* 02, CLA IAC ; clr drv = 1 */
660 04027, /* 03, JMS GO ; do io */
661 01004, /* 04, TAD 4 ; rd hdr fnc */
662 04027, /* 05, JMS GO ; do io */
663 06615, /* 06, RRSI ; rd hdr lo */
664 07002, /* 07, BSW ; swap */
665 07012, /* 10, RTR ; lo cyl to L */
666 06615, /* 11, RRSI ; rd hdr hi */
667 00025, /* 12, AND 25 ; mask = 377 */
668 07004, /* 13, RTL ; get cyl */
669 06603, /* 14, RLCA ; set addr */
670 07325, /* 15, CLA STL IAC RAL ; seek = 3 */
671 04027, /* 16, JMS GO ; do io */
672 07332, /* 17, CLA STL RTR ; dir in = 2000 */
673 06605, /* 20, RLSA ; sector */
674 01026, /* 21, TAD (-200) ; one sector */
675 06607, /* 22, RLWC ; word cnt */
676 07327, /* 23, CLA STL IAC RTL ; read = 6*/
677 04027, /* 24, JMS GO ; do io */
678 00377, /* 25, JMP 377 ; start */
679 07600, /* 26, -200 ; word cnt */
680 00000, /* GO, 0 ; subr */
681 06604, /* 30, RLCB ; load fnc */
682 06601, /* 31, RLSD ; wait */
683 05031, /* 32, JMP .-1 ; */
684 06617, /* 33, RLSE ; error? */
685 05427, /* 34, JMP I GO ; no, ok */
686 05001 /* 35, JMP BT ; restart */
687 };
688
689
rl_boot(int32 unitno,DEVICE * dptr)690 t_stat rl_boot (int32 unitno, DEVICE *dptr)
691 {
692 int32 i;
693 extern int32 saved_PC;
694
695 if (unitno) /* only unit 0 */
696 return SCPE_ARG;
697 if (rl_dib.dev != DEV_RL) /* only std devno */
698 return STOP_NOTSTD;
699 rl_unit[unitno].TRK = 0;
700 for (i = 0; i < BOOT_LEN; i++)
701 M[BOOT_START + i] = boot_rom[i];
702 saved_PC = BOOT_START;
703 return SCPE_OK;
704 }
705