First Commit of my working state
[simh.git] / PDP8 / pdp8_rl.c
1 /* pdp8_rl.c: RL8A cartridge disk simulator
2
3 Copyright (c) 1993-2005, 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 (found by 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
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) AC = IOT_SKP; /* skip if done */
272 else AC = 0;
273 rl_done = 0; /* clear done */
274 int_req = int_req & ~INT_RL; /* clear intr */
275 return AC;
276
277 case 2: /* RLMA */
278 rlma = AC;
279 break;
280
281 case 3: /* RLCA */
282 rlcsa = AC;
283 break;
284
285 case 4: /* RLCB */
286 rlcsb = AC;
287 rl_done = 0; /* clear done */
288 rler = rl_erf = 0; /* clear errors */
289 int_req = int_req & ~INT_RL; /* clear intr */
290 rl_lft = 0; /* clear silo ptr */
291 uptr = rl_dev.units + GET_DRIVE (rlcsb); /* select unit */
292 switch (GET_FUNC (rlcsb)) { /* case on func */
293
294 case RLCSB_CLRD: /* clear drive */
295 uptr->STAT = uptr->STAT & ~RLDS_ERR; /* clear errors */
296 case RLCSB_MNT: /* mnt */
297 rl_set_done (0);
298 break;
299
300 case RLCSB_SEEK: /* seek */
301 curr = GET_CYL (uptr->TRK); /* current cylinder */
302 offs = GET_CYL (rlcsa); /* offset */
303 if (rlcsa & RLCSA_DIR) { /* in or out? */
304 newc = curr + offs; /* out */
305 maxc = (uptr->flags & UNIT_RL02)?
306 RL_NUMCY * 2: RL_NUMCY;
307 if (newc >= maxc) newc = maxc - 1;
308 }
309 else {
310 newc = curr - offs; /* in */
311 if (newc < 0) newc = 0;
312 }
313 uptr->TRK = newc | (rlcsa & RLCSA_HD);
314 sim_activate (uptr, rl_swait * abs (newc - curr));
315 break;
316
317 default: /* data transfer */
318 sim_activate (uptr, rl_swait); /* activate unit */
319 break;
320 } /* end switch func */
321 break;
322
323 case 5: /* RLSA */
324 rlsa = GET_SECT (AC);
325 break;
326
327 case 6: /* spare */
328 return 0;
329
330 case 7: /* RLWC */
331 rlwc = AC;
332 break;
333 } /* end switch pulse */
334
335 return 0; /* clear AC */
336 }
337
338 int32 rl61 (int32 IR, int32 AC)
339 {
340 int32 dat;
341 UNIT *uptr;
342
343 switch (IR & 07) { /* case IR<9:11> */
344
345 case 0: /* RRER */
346 uptr = rl_dev.units + GET_DRIVE (rlcsb); /* select unit */
347 if (!sim_is_active (uptr) && /* update drdy */
348 (uptr->flags & UNIT_ATT))
349 rler = rler | RLER_DRDY;
350 else rler = rler & ~RLER_DRDY;
351 dat = rler & RLER_MASK;
352 break;
353
354 case 1: /* RRWC */
355 dat = rlwc;
356 break;
357
358 case 2: /* RRCA */
359 dat = rlcsa;
360 break;
361
362 case 3: /* RRCB */
363 dat = rlcsb;
364 break;
365
366 case 4: /* RRSA */
367 dat = (rlsa << RLSA_V_SECT) & 07777;
368 break;
369
370 case 5: /* RRSI */
371 if (rl_lft) { /* silo left? */
372 dat = (rlsi >> 8) & 0377; /* get left 8b */
373 rlsi = rlsi1; /* ripple */
374 rlsi1 = rlsi2;
375 }
376 else dat = rlsi & 0377; /* get right 8b */
377 rl_lft = rl_lft ^ 1; /* change side */
378 break;
379
380 case 6: /* spare */
381 return AC;
382
383 case 7: /* RLSE */
384 if (rl_erf) dat = IOT_SKP | AC; /* skip if err */
385 else dat = AC;
386 rl_erf = 0;
387 break;
388 } /* end switch pulse */
389
390 return dat;
391 }
392
393 /* Service unit timeout
394
395 If seek in progress, complete seek command
396 Else complete data transfer command
397
398 The unit control block contains the function and cylinder for
399 the current command.
400 */
401
402 t_stat rl_svc (UNIT *uptr)
403 {
404 int32 err, wc, maxc;
405 int32 i, j, func, da, bc, wbc;
406 uint32 ma;
407
408 func = GET_FUNC (rlcsb); /* get function */
409 if (func == RLCSB_GSTA) { /* get status? */
410 rlsi = uptr->STAT |
411 ((uptr->TRK & RLCSA_HD)? RLDS_HD: 0) |
412 ((uptr->flags & UNIT_ATT)? RLDS_ATT: RLDS_UNATT);
413 if (uptr->flags & UNIT_RL02) rlsi = rlsi | RLDS_RL02;
414 if (uptr->flags & UNIT_WPRT) rlsi = rlsi | RLDS_WLK;
415 rlsi2 = rlsi1 = rlsi;
416 rl_set_done (0); /* done */
417 return SCPE_OK;
418 }
419
420 if ((uptr->flags & UNIT_ATT) == 0) { /* attached? */
421 uptr->STAT = uptr->STAT | RLDS_SPE; /* spin error */
422 rl_set_done (RLER_INCMP); /* flag error */
423 return IORETURN (rl_stopioe, SCPE_UNATT);
424 }
425
426 if ((func == RLCSB_WRITE) && (uptr->flags & UNIT_WPRT)) {
427 uptr->STAT = uptr->STAT | RLDS_WGE; /* write and locked */
428 rl_set_done (RLER_DRE); /* flag error */
429 return SCPE_OK;
430 }
431
432 if (func == RLCSB_SEEK) { /* seek? */
433 rl_set_done (0); /* done */
434 return SCPE_OK;
435 }
436
437 if (func == RLCSB_RHDR) { /* read header? */
438 rlsi = (GET_TRK (uptr->TRK) << RLSI_V_TRK) | rlsa;
439 rlsi1 = rlsi2 = 0;
440 rl_set_done (0); /* done */
441 return SCPE_OK;
442 }
443
444 if (((func != RLCSB_RNOHDR) && (GET_CYL (uptr->TRK) != GET_CYL (rlcsa)))
445 || (rlsa >= RL_NUMSC)) { /* bad cyl or sector? */
446 rl_set_done (RLER_HDE | RLER_INCMP); /* flag error */
447 return SCPE_OK;
448 }
449
450 ma = (GET_MEX (rlcsb) << 12) | rlma; /* get mem addr */
451 da = GET_DA (rlcsa) * RL_NUMBY; /* get disk addr */
452 wc = 010000 - rlwc; /* get true wc */
453 if (rlcsb & RLCSB_8B) { /* 8b mode? */
454 bc = wc; /* bytes to xfr */
455 maxc = (RL_NUMSC - rlsa) * RL_NUMBY; /* max transfer */
456 if (bc > maxc) wc = bc = maxc; /* trk ovrun? limit */
457 }
458 else {
459 bc = ((wc * 3) + 1) / 2; /* 12b mode */
460 if (bc > RL_NUMBY) { /* > 1 sector */
461 bc = RL_NUMBY; /* cap xfer */
462 wc = (RL_NUMBY * 2) / 3;
463 }
464 }
465
466 err = fseek (uptr->fileref, da, SEEK_SET);
467
468 if ((func >= RLCSB_READ) && (err == 0) && /* read (no hdr)? */
469 MEM_ADDR_OK (ma)) { /* valid bank? */
470 i = fxread (rlxb, sizeof (int8), bc, uptr->fileref);
471 err = ferror (uptr->fileref);
472 for ( ; i < bc; i++) rlxb[i] = 0; /* fill buffer */
473 for (i = j = 0; i < wc; i++) { /* store buffer */
474 if (rlcsb & RLCSB_8B) /* 8b mode? */
475 M[ma] = rlxb[i] & 0377; /* store */
476 else if (i & 1) { /* odd wd 12b? */
477 M[ma] = ((rlxb[j + 1] >> 4) & 017) |
478 (((uint16) rlxb[j + 2]) << 4);
479 j = j + 3;
480 }
481 else M[ma] = rlxb[j] | /* even wd 12b */
482 ((((uint16) rlxb[j + 1]) & 017) << 8);
483 ma = (ma & 070000) + ((ma + 1) & 07777);
484 } /* end for */
485 } /* end if wr */
486
487 if ((func == RLCSB_WRITE) && (err == 0)) { /* write? */
488 for (i = j = 0; i < wc; i++) { /* fetch buffer */
489 if (rlcsb & RLCSB_8B) /* 8b mode? */
490 rlxb[i] = M[ma] & 0377; /* fetch */
491 else if (i & 1) { /* odd wd 12b? */
492 rlxb[j + 1] = rlxb[j + 1] | ((M[ma] & 017) << 4);
493 rlxb[j + 2] = ((M[ma] >> 4) & 0377);
494 j = j + 3;
495 }
496 else { /* even wd 12b */
497 rlxb[j] = M[ma] & 0377;
498 rlxb[j + 1] = (M[ma] >> 8) & 017;
499 }
500 ma = (ma & 070000) + ((ma + 1) & 07777);
501 } /* end for */
502 wbc = (bc + (RL_NUMBY - 1)) & ~(RL_NUMBY - 1); /* clr to */
503 for (i = bc; i < wbc; i++) rlxb[i] = 0; /* end of blk */
504 fxwrite (rlxb, sizeof (int8), wbc, uptr->fileref);
505 err = ferror (uptr->fileref);
506 } /* end write */
507
508 rlwc = (rlwc + wc) & 07777; /* final word count */
509 if (rlwc != 0) rler = rler | RLER_INCMP; /* completed? */
510 rlma = (rlma + wc) & 07777; /* final word addr */
511 rlsa = rlsa + ((bc + (RL_NUMBY - 1)) / RL_NUMBY);
512 rl_set_done (0);
513
514 if (err != 0) { /* error? */
515 perror ("RL I/O error");
516 clearerr (uptr->fileref);
517 return SCPE_IOERR;
518 }
519 return SCPE_OK;
520 }
521
522 /* Set done and possibly errors */
523
524 void rl_set_done (int32 status)
525 {
526 rl_done = 1;
527 rler = rler | status;
528 if (rler) rl_erf = 1;
529 if (rlcsb & RLCSB_IE) int_req = int_req | INT_RL;
530 else int_req = int_req & ~INT_RL;
531 return;
532 }
533
534 /* Device reset
535
536 Note that the RL8A does NOT recalibrate its drives on RESET
537 */
538
539 t_stat rl_reset (DEVICE *dptr)
540 {
541 int32 i;
542 UNIT *uptr;
543
544 rlcsa = rlcsb = rlsa = rler = 0;
545 rlma = rlwc = 0;
546 rlsi = rlsi1 = rlsi2 = 0;
547 rl_lft = 0;
548 rl_done = 0;
549 rl_erf = 0;
550 int_req = int_req & ~INT_RL;
551 for (i = 0; i < RL_NUMDR; i++) {
552 uptr = rl_dev.units + i;
553 sim_cancel (uptr);
554 uptr->STAT = 0;
555 }
556 if (rlxb == NULL) rlxb = (uint8 *) calloc (RL_MAXFR, sizeof (uint8));
557 if (rlxb == NULL) return SCPE_MEM;
558 return SCPE_OK;
559 }
560
561 /* Attach routine */
562
563 t_stat rl_attach (UNIT *uptr, char *cptr)
564 {
565 uint32 p;
566 t_stat r;
567
568 uptr->capac = (uptr->flags & UNIT_RL02)? RL02_SIZE: RL01_SIZE;
569 r = attach_unit (uptr, cptr); /* attach unit */
570 if (r != SCPE_OK) return r; /* error? */
571 uptr->TRK = 0; /* cyl 0 */
572 uptr->STAT = RLDS_VCK; /* new volume */
573 if ((p = sim_fsize (uptr->fileref)) == 0) { /* new disk image? */
574 if (uptr->flags & UNIT_RO) return SCPE_OK;
575 return rl_set_bad (uptr, 0, NULL, NULL);
576 }
577 if ((uptr->flags & UNIT_AUTO) == 0) return r; /* autosize? */
578 if (p > (RL01_SIZE * sizeof (int16))) {
579 uptr->flags = uptr->flags | UNIT_RL02;
580 uptr->capac = RL02_SIZE;
581 }
582 else {
583 uptr->flags = uptr->flags & ~UNIT_RL02;
584 uptr->capac = RL01_SIZE;
585 }
586 return SCPE_OK;
587 }
588
589 /* Set size routine */
590
591 t_stat rl_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)
592 {
593 if (uptr->flags & UNIT_ATT) return SCPE_ALATT;
594 uptr->capac = (val & UNIT_RL02)? RL02_SIZE: RL01_SIZE;
595 return SCPE_OK;
596 }
597
598 /* Factory bad block table creation routine
599
600 This routine writes the OS/8 specific bad block map in track 0, sector 014 (RL_BBMAP):
601
602 words 0 magic number = 0123 (RL_BBID)
603 words 1-n block numbers
604 :
605 words n+1 end of table = 0
606
607 Inputs:
608 uptr = pointer to unit
609 val = ignored
610 Outputs:
611 sta = status code
612 */
613
614 t_stat rl_set_bad (UNIT *uptr, int32 val, char *cptr, void *desc)
615 {
616 int32 i, da = RL_BBMAP * RL_NUMBY;
617
618 if ((uptr->flags & UNIT_ATT) == 0) return SCPE_UNATT;
619 if (uptr->flags & UNIT_RO) return SCPE_RO;
620 if (!get_yn ("Create bad block table? [N]", FALSE)) return SCPE_OK;
621 if (fseek (uptr->fileref, da, SEEK_SET)) return SCPE_IOERR;
622 rlxb[0] = RL_BBID;
623 for (i = 1; i < RL_NUMBY; i++) rlxb[i] = 0;
624 fxwrite (rlxb, sizeof (uint8), RL_NUMBY, uptr->fileref);
625 if (ferror (uptr->fileref)) return SCPE_IOERR;
626 return SCPE_OK;
627 }
628
629 /* Bootstrap */
630
631 #define BOOT_START 1 /* start */
632 #define BOOT_UNIT 02006 /* unit number */
633 #define BOOT_LEN (sizeof (boot_rom) / sizeof (int16))
634
635 static const uint16 boot_rom[] = {
636 06600, /* BT, RLDC ; reset */
637 07201, /* 02, CLA IAC ; clr drv = 1 */
638 04027, /* 03, JMS GO ; do io */
639 01004, /* 04, TAD 4 ; rd hdr fnc */
640 04027, /* 05, JMS GO ; do io */
641 06615, /* 06, RRSI ; rd hdr lo */
642 07002, /* 07, BSW ; swap */
643 07012, /* 10, RTR ; lo cyl to L */
644 06615, /* 11, RRSI ; rd hdr hi */
645 00025, /* 12, AND 25 ; mask = 377 */
646 07004, /* 13, RTL ; get cyl */
647 06603, /* 14, RLCA ; set addr */
648 07325, /* 15, CLA STL IAC RAL ; seek = 3 */
649 04027, /* 16, JMS GO ; do io */
650 07332, /* 17, CLA STL RTR ; dir in = 2000 */
651 06605, /* 20, RLSA ; sector */
652 01026, /* 21, TAD (-200) ; one sector */
653 06607, /* 22, RLWC ; word cnt */
654 07327, /* 23, CLA STL IAC RTL ; read = 6*/
655 04027, /* 24, JMS GO ; do io */
656 00377, /* 25, JMP 377 ; start */
657 07600, /* 26, -200 ; word cnt */
658 00000, /* GO, 0 ; subr */
659 06604, /* 30, RLCB ; load fnc */
660 06601, /* 31, RLSD ; wait */
661 05031, /* 32, JMP .-1 ; */
662 06617, /* 33, RLSE ; error? */
663 05427, /* 34, JMP I GO ; no, ok */
664 05001 /* 35, JMP BT ; restart */
665 };
666
667
668 t_stat rl_boot (int32 unitno, DEVICE *dptr)
669 {
670 int32 i;
671 extern int32 saved_PC;
672
673 if (unitno) return SCPE_ARG; /* only unit 0 */
674 if (rl_dib.dev != DEV_RL) return STOP_NOTSTD; /* only std devno */
675 rl_unit[unitno].TRK = 0;
676 for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i];
677 saved_PC = BOOT_START;
678 return SCPE_OK;
679 }