First Commit of my working state
[simh.git] / PDP11 / pdp11_rf.c
1 /* pdp11_rf.c: RF11 fixed head disk simulator
2
3 Copyright (c) 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 rf RF11 fixed head disk
27
28 25-Dec-06 RMS Fixed bug in unit mask (found by John Dundas)
29 26-Jun-06 RMS Cloned from RF08 simulator
30
31 The RF11 is a head-per-track disk. To minimize overhead, the entire RF11
32 is buffered in memory.
33
34 Two timing parameters are provided:
35
36 rf_time Interword timing, must be non-zero
37 rf_burst Burst mode, if 0, DMA occurs cycle by cycle; otherwise,
38 DMA occurs in a burst
39 */
40
41 #include "pdp11_defs.h"
42 #include <math.h>
43
44 #define UNIT_V_AUTO (UNIT_V_UF + 0) /* autosize */
45 #define UNIT_V_PLAT (UNIT_V_UF + 1) /* #platters - 1 */
46 #define UNIT_M_PLAT (RF_NUMDK - 1)
47 #define UNIT_GETP(x) ((((x) >> UNIT_V_PLAT) & UNIT_M_PLAT) + 1)
48 #define UNIT_AUTO (1 << UNIT_V_AUTO)
49 #define UNIT_PLAT (UNIT_M_PLAT << UNIT_V_PLAT)
50
51 /* Constants */
52
53 #define RF_NUMWD 2048 /* words/track */
54 #define RF_NUMTR 128 /* tracks/disk */
55 #define RF_DKSIZE (RF_NUMTR * RF_NUMWD) /* words/disk */
56 #define RF_NUMDK 8 /* disks/controller */
57 #define RF_WMASK (RF_NUMWD - 1) /* word mask */
58
59 /* Parameters in the unit descriptor */
60
61 #define FUNC u4 /* function */
62
63 /* Status register */
64
65 #define RFCS_ERR (CSR_ERR) /* error */
66 #define RFCS_FRZ 0040000 /* error freeze */
67 #define RFCS_WCHK 0020000 /* write check */
68 #define RFCS_DPAR 0010000 /* data parity (ni) */
69 #define RFCS_NED 0004000 /* nx disk */
70 #define RFCS_WLK 0002000 /* write lock */
71 #define RFCS_MXFR 0001000 /* missed xfer (ni) */
72 #define RFCS_CLR 0000400 /* clear */
73 #define RFCS_DONE (CSR_DONE)
74 #define RFCS_IE (CSR_IE)
75 #define RFCS_M_MEX 0000003 /* memory extension */
76 #define RFCS_V_MEX 4
77 #define RFCS_MEX (RFCS_M_MEX << RFCS_V_MEX)
78 #define RFCS_MAINT 0000010 /* maint */
79 #define RFCS_M_FUNC 0000003 /* function */
80 #define RFNC_NOP 0
81 #define RFNC_WRITE 1
82 #define RFNC_READ 2
83 #define RFNC_WCHK 3
84 #define RFCS_V_FUNC 1
85 #define RFCS_FUNC (RFCS_M_FUNC << RFCS_V_FUNC)
86 #define RFCS_GO 0000001
87 #define RFCS_ALLERR (RFCS_FRZ|RFCS_WCHK|RFCS_DPAR|RFCS_NED|RFCS_WLK|RFCS_MXFR)
88 #define RFCS_W (RFCS_IE|RFCS_MEX|RFCS_FUNC)
89
90 /* Current memory address */
91
92 #define RFCMA_RW 0177776
93
94 /* Address extension */
95
96 #define RFDAE_ALLERR 0176000
97 #define RFDAE_NXM 0002000
98 #define RFDAE_INH 0000400 /* addr inhibit */
99 #define RFDAE_RLAT 0000200 /* req late */
100 #define RFDAE_DAE 0000077 /* extension */
101 #define RFDAE_R 0176677
102 #define RFDAE_W 0000677
103
104 #define GET_FUNC(x) (((x) >> RFCS_V_FUNC) & RFCS_M_FUNC)
105 #define GET_MEX(x) (((x) & RFCS_MEX) << (16 - RFCS_V_MEX))
106 #define GET_DEX(x) (((x) & RFDAE_DAE) << 16)
107 #define GET_POS(x) ((int) fmod (sim_gtime() / ((double) (x)), \
108 ((double) RF_NUMWD)))
109
110 extern uint16 *M;
111 extern int32 int_req[IPL_HLVL];
112 extern FILE *sim_deb;
113
114 uint32 rf_cs = 0; /* status register */
115 uint32 rf_cma = 0;
116 uint32 rf_wc = 0;
117 uint32 rf_da = 0; /* disk address */
118 uint32 rf_dae = 0;
119 uint32 rf_dbr = 0;
120 uint32 rf_maint = 0;
121 uint32 rf_wlk = 0; /* write lock */
122 uint32 rf_time = 10; /* inter-word time */
123 uint32 rf_burst = 1; /* burst mode flag */
124 uint32 rf_stopioe = 1; /* stop on error */
125
126 DEVICE rf_dev;
127 t_stat rf_rd (int32 *data, int32 PA, int32 access);
128 t_stat rf_wr (int32 data, int32 PA, int32 access);
129 int32 rf_inta (void);
130 t_stat rf_svc (UNIT *uptr);
131 t_stat rf_reset (DEVICE *dptr);
132 t_stat rf_boot (int32 unitno, DEVICE *dptr);
133 t_stat rf_attach (UNIT *uptr, char *cptr);
134 t_stat rf_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
135 uint32 update_rfcs (uint32 newcs, uint32 newdae);
136
137 /* RF11 data structures
138
139 rf_dev RF device descriptor
140 rf_unit RF unit descriptor
141 rf_reg RF register list
142 */
143
144 DIB rf_dib = {
145 IOBA_RF, IOLN_RF, &rf_rd, &rf_wr,
146 1, IVCL (RF), VEC_RF, NULL
147 };
148
149
150 UNIT rf_unit = {
151 UDATA (&rf_svc, UNIT_FIX+UNIT_ATTABLE+
152 UNIT_BUFABLE+UNIT_MUSTBUF, RF_DKSIZE)
153 };
154
155 REG rf_reg[] = {
156 { ORDATA (RFCS, rf_cs, 16) },
157 { ORDATA (RFWC, rf_wc, 16) },
158 { ORDATA (RFCMA, rf_cma, 16) },
159 { ORDATA (RFDA, rf_da, 16) },
160 { ORDATA (RFDAE, rf_dae, 16) },
161 { ORDATA (RFDBR, rf_dbr, 16) },
162 { ORDATA (RFMR, rf_maint, 16) },
163 { ORDATA (RFWLK, rf_wlk, 32) },
164 { FLDATA (INT, IREQ (RF), INT_V_RF) },
165 { FLDATA (ERR, rf_cs, CSR_V_ERR) },
166 { FLDATA (DONE, rf_cs, CSR_V_DONE) },
167 { FLDATA (IE, rf_cs, CSR_V_IE) },
168 { DRDATA (TIME, rf_time, 24), REG_NZ + PV_LEFT },
169 { FLDATA (BURST, rf_burst, 0) },
170 { FLDATA (STOP_IOE, rf_stopioe, 0) },
171 { ORDATA (DEVADDR, rf_dib.ba, 32), REG_HRO },
172 { ORDATA (DEVVEC, rf_dib.vec, 16), REG_HRO },
173 { NULL }
174 };
175
176 MTAB rf_mod[] = {
177 { UNIT_PLAT, (0 << UNIT_V_PLAT), NULL, "1P", &rf_set_size },
178 { UNIT_PLAT, (1 << UNIT_V_PLAT), NULL, "2P", &rf_set_size },
179 { UNIT_PLAT, (2 << UNIT_V_PLAT), NULL, "3P", &rf_set_size },
180 { UNIT_PLAT, (3 << UNIT_V_PLAT), NULL, "4P", &rf_set_size },
181 { UNIT_PLAT, (4 << UNIT_V_PLAT), NULL, "5P", &rf_set_size },
182 { UNIT_PLAT, (5 << UNIT_V_PLAT), NULL, "6P", &rf_set_size },
183 { UNIT_PLAT, (6 << UNIT_V_PLAT), NULL, "7P", &rf_set_size },
184 { UNIT_PLAT, (7 << UNIT_V_PLAT), NULL, "8P", &rf_set_size },
185 { UNIT_AUTO, UNIT_AUTO, "autosize", "AUTOSIZE", NULL },
186 { MTAB_XTD|MTAB_VDV, 020, "ADDRESS", "ADDRESS",
187 &set_addr, &show_addr, NULL },
188 { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR",
189 &set_vec, &show_vec, NULL },
190 { 0 }
191 };
192
193 DEVICE rf_dev = {
194 "RF", &rf_unit, rf_reg, rf_mod,
195 1, 8, 21, 1, 8, 16,
196 NULL, NULL, &rf_reset,
197 &rf_boot, &rf_attach, NULL,
198 &rf_dib, DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_DEBUG
199 };
200
201 /* I/O dispatch routine, I/O addresses 17777460 - 17777476 */
202
203 t_stat rf_rd (int32 *data, int32 PA, int32 access)
204 {
205 switch ((PA >> 1) & 07) { /* decode PA<3:1> */
206
207 case 0: /* RFCS */
208 *data = update_rfcs (0, 0); /* update RFCS */
209 break;
210
211 case 1: /* RFWC */
212 *data = rf_wc;
213 break;
214
215 case 2: /* RFCMA */
216 *data = rf_cma & RFCMA_RW;
217 break;
218
219 case 3: /* RFDA */
220 *data = rf_da;
221 break;
222
223 case 4: /* RFDAE */
224 *data = rf_dae & RFDAE_R;
225 break;
226
227 case 5: /* RFDBR */
228 *data = rf_dbr;
229 break;
230
231 case 6: /* RFMR */
232 *data = rf_maint;
233 break;
234
235 case 7: /* RFADS */
236 *data = GET_POS (rf_time);
237 break;
238 } /* end switch */
239 return SCPE_OK;
240 }
241
242 t_stat rf_wr (int32 data, int32 PA, int32 access)
243 {
244 int32 t, fnc;
245
246 switch ((PA >> 1) & 07) { /* decode PA<3:1> */
247
248 case 0: /* RFCS */
249 if (access == WRITEB) data = (PA & 1)?
250 (rf_cs & 0377) | (data << 8): (rf_cs & ~0377) | data;
251 if (data & RFCS_CLR) rf_reset (&rf_dev); /* clear? */
252 if ((data & RFCS_IE) == 0) /* int disable? */
253 CLR_INT (RF); /* clr int request */
254 else if ((rf_cs & (RFCS_DONE + RFCS_IE)) == RFCS_DONE)
255 SET_INT (RF); /* set int request */
256 rf_cs = (rf_cs & ~RFCS_W) | (data & RFCS_W); /* merge */
257 if ((rf_cs & RFCS_DONE) && (data & RFCS_GO) && /* new function? */
258 ((fnc = GET_FUNC (rf_cs)) != RFNC_NOP)) {
259 rf_unit.FUNC = fnc; /* save function */
260 t = (rf_da & RF_WMASK) - GET_POS (rf_time); /* delta to new loc */
261 if (t < 0) t = t + RF_NUMWD; /* wrap around? */
262 sim_activate (&rf_unit, t * rf_time); /* schedule op */
263 rf_cs &= ~(RFCS_WCHK|RFCS_DPAR|RFCS_NED|RFCS_WLK|RFCS_MXFR|RFCS_DONE);
264 CLR_INT (RF);
265 if (DEBUG_PRS (rf_dev))
266 fprintf (sim_deb, ">>RF start: cs = %o, da = %o, ma = %o\n",
267 update_rfcs (0, 0), GET_DEX (rf_dae) | rf_da, GET_MEX (rf_cs) | rf_cma);
268 }
269 break;
270
271 case 1: /* RFWC */
272 if (access == WRITEB) data = (PA & 1)?
273 (rf_wc & 0377) | (data << 8): (rf_wc & ~0377) | data;
274 rf_wc = data;
275 break;
276
277 case 2: /* RFCMA */
278 if (access == WRITEB) data = (PA & 1)?
279 (rf_cma & 0377) | (data << 8): (rf_cma & ~0377) | data;
280 rf_cma = data & RFCMA_RW;
281 break;
282
283 case 3: /* RFDA */
284 if (access == WRITEB) data = (PA & 1)?
285 (rf_da & 0377) | (data << 8): (rf_da & ~0377) | data;
286 rf_da = data;
287 break;
288
289 case 4: /* RFDAE */
290 if (access == WRITEB) data = (PA & 1)?
291 (rf_dae & 0377) | (data << 8): (rf_dae & ~0377) | data;
292 rf_dae = (rf_dae & ~RFDAE_W) | (data & RFDAE_W);
293 break;
294
295 case 5: /* RFDBR */
296 rf_dbr = data;
297 break;
298
299 case 6: /* RFMR */
300 rf_maint = data;
301 break;
302
303 case 7: /* RFADS */
304 break; /* read only */
305 } /* end switch */
306
307 update_rfcs (0, 0);
308 return SCPE_OK;
309 }
310
311 /* Unit service
312
313 Note that for reads and writes, memory addresses wrap around in the
314 current field. This code assumes the entire disk is buffered.
315 */
316
317 t_stat rf_svc (UNIT *uptr)
318 {
319 uint32 ma, da, t;
320 uint16 dat;
321 uint16 *fbuf = uptr->filebuf;
322
323 if ((uptr->flags & UNIT_BUF) == 0) { /* not buf? abort */
324 update_rfcs (RFCS_NED|RFCS_DONE, 0); /* nx disk */
325 return IORETURN (rf_stopioe, SCPE_UNATT);
326 }
327
328 ma = GET_MEX (rf_cs) | rf_cma; /* 18b mem addr */
329 da = GET_DEX (rf_dae) | rf_da; /* 22b disk addr */
330 do {
331 if (da >= rf_unit.capac) { /* disk overflow? */
332 update_rfcs (RFCS_NED, 0);
333 break;
334 }
335 if (uptr->FUNC == RFNC_READ) { /* read? */
336 dat = fbuf[da]; /* get disk data */
337 rf_dbr = dat;
338 if (Map_WriteW (ma, 2, &dat)) { /* store mem, nxm? */
339 update_rfcs (0, RFDAE_NXM);
340 break;
341 }
342 }
343 else if (uptr->FUNC == RFNC_WCHK) { /* write check? */
344 rf_dbr = fbuf[da]; /* get disk data */
345 if (Map_ReadW (ma, 2, &dat)) { /* read mem, nxm? */
346 update_rfcs (0, RFDAE_NXM);
347 break;
348 }
349 if (rf_dbr != dat) { /* miscompare? */
350 update_rfcs (RFCS_WCHK, 0);
351 break;
352 }
353 }
354 else { /* write */
355 t = (da >> 15) & 037;
356 if ((rf_wlk >> t) & 1) { /* write locked? */
357 update_rfcs (RFCS_WLK, 0);
358 break;
359 }
360 else { /* not locked */
361 if (Map_ReadW (ma, 2, &dat)) { /* read mem, nxm? */
362 update_rfcs (0, RFDAE_NXM);
363 break;
364 }
365 fbuf[da] = dat; /* write word */
366 rf_dbr = dat;
367 if (da >= uptr->hwmark) uptr->hwmark = da + 1;
368 }
369 }
370 da = (da + 1) & 017777777; /* incr disk addr */
371 if ((rf_dae & RFDAE_INH) == 0) /* inhibit clear? */
372 ma = (ma + 2) & UNIMASK; /* incr mem addr */
373 rf_wc = (rf_wc + 1) & DMASK; /* incr word count */
374 } while ((rf_wc != 0) && (rf_burst != 0)); /* brk if wc, no brst */
375
376 rf_da = da & DMASK; /* split da */
377 rf_dae = (rf_dae & ~RFDAE_DAE) | ((rf_da >> 16) && RFDAE_DAE);
378 rf_cma = ma & DMASK; /* split ma */
379 rf_cs = (rf_cs & ~RFCS_MEX) | ((ma >> (16 - RFCS_V_MEX)) & RFCS_MEX);
380 if ((rf_wc != 0) && ((rf_cs & RFCS_ERR) == 0)) /* more to do? */
381 sim_activate (&rf_unit, rf_time); /* sched next */
382 else {
383 update_rfcs (RFCS_DONE, 0);
384 if (DEBUG_PRS (rf_dev))
385 fprintf (sim_deb, ">>RF done: cs = %o, dae = %o, da = %o, ma = %o, wc = %o\n",
386 rf_cs, rf_dae, rf_da, rf_cma, rf_wc);
387 }
388 return SCPE_OK;
389 }
390
391 /* Update CS register */
392
393 uint32 update_rfcs (uint32 newcs, uint32 newdae)
394 {
395 uint32 oldcs = rf_cs;
396 uint32 da = GET_DEX (rf_dae) | rf_da;
397
398 rf_dae |= newdae; /* update DAE */
399 rf_cs |= newcs; /* update CS */
400 if (da >= rf_unit.capac) /* update CS<ned> */
401 rf_cs |= RFCS_NED;
402 else rf_cs &= ~RFCS_NED;
403 if (rf_dae & RFDAE_ALLERR) /* update CS<frz> */
404 rf_cs |= RFCS_FRZ;
405 else rf_cs &= ~RFCS_FRZ;
406 if (rf_cs & RFCS_ALLERR) /* update CS<err> */
407 rf_cs |= RFCS_ERR;
408 else rf_cs &= ~RFCS_ERR;
409 if ((rf_cs & RFCS_IE) && /* IE and */
410 (rf_cs & RFCS_DONE) &&!(oldcs & RFCS_DONE)) /* done 0->1? */
411 SET_INT (RF);
412 return rf_cs;
413 }
414
415 /* Reset routine */
416
417 t_stat rf_reset (DEVICE *dptr)
418 {
419 rf_cs = RFCS_DONE;
420 rf_da = rf_dae = 0;
421 rf_dbr = 0;
422 rf_cma = 0;
423 rf_wc = 0;
424 rf_maint = 0;
425 CLR_INT (RF);
426 sim_cancel (&rf_unit);
427 return SCPE_OK;
428 }
429
430 /* Bootstrap routine */
431
432 /* Device bootstrap */
433
434 #define BOOT_START 02000 /* start */
435 #define BOOT_ENTRY (BOOT_START + 002) /* entry */
436 #define BOOT_CSR (BOOT_START + 032) /* CSR */
437 #define BOOT_LEN (sizeof (boot_rom) / sizeof (uint16))
438
439 static const uint16 boot_rom[] = {
440 0043113, /* "FD" */
441 0012706, BOOT_START, /* MOV #boot_start, SP */
442 0012701, 0177472, /* MOV #RFDAE+2, R1 ; csr block */
443 0005041, /* CLR -(R1) ; clear dae */
444 0005041, /* CLR -(R1), ; clear da */
445 0005041, /* CLR -(R1), ; clear cma */
446 0012741, 0177000, /* MOV #-256.*2, -(R1) ; load wc */
447 0012741, 0000005, /* MOV #READ+GO, -(R1) ; read & go */
448 0005002, /* CLR R2 */
449 0005003, /* CLR R3 */
450 0012704, BOOT_START+020, /* MOV #START+20, R4 */
451 0005005, /* CLR R5 */
452 0105711, /* TSTB (R1) */
453 0100376, /* BPL .-2 */
454 0105011, /* CLRB (R1) */
455 0005007 /* CLR PC */
456 };
457
458 t_stat rf_boot (int32 unitno, DEVICE *dptr)
459 {
460 int32 i;
461 extern int32 saved_PC;
462
463 for (i = 0; i < BOOT_LEN; i++) M[(BOOT_START >> 1) + i] = boot_rom[i];
464 M[BOOT_CSR >> 1] = (rf_dib.ba & DMASK) + 012;
465 saved_PC = BOOT_ENTRY;
466 return SCPE_OK;
467 }
468
469 /* Attach routine */
470
471 t_stat rf_attach (UNIT *uptr, char *cptr)
472 {
473 uint32 sz, p;
474 uint32 ds_bytes = RF_DKSIZE * sizeof (int16);
475
476 if ((uptr->flags & UNIT_AUTO) && (sz = sim_fsize_name (cptr))) {
477 p = (sz + ds_bytes - 1) / ds_bytes;
478 if (p >= RF_NUMDK) p = RF_NUMDK - 1;
479 uptr->flags = (uptr->flags & ~UNIT_PLAT) |
480 (p << UNIT_V_PLAT);
481 }
482 uptr->capac = UNIT_GETP (uptr->flags) * RF_DKSIZE;
483 return attach_unit (uptr, cptr);
484 }
485
486 /* Change disk size */
487
488 t_stat rf_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)
489 {
490 if (val < 0) return SCPE_IERR;
491 if (uptr->flags & UNIT_ATT) return SCPE_ALATT;
492 uptr->capac = UNIT_GETP (val) * RF_DKSIZE;
493 uptr->flags = uptr->flags & ~UNIT_AUTO;
494 return SCPE_OK;
495 }