246957d6d2df67ed53f52759528711183ce58ec4
1 /* pdp11_rf.c: RF11 fixed head disk simulator
3 Copyright (c) 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 rf RF11 fixed head disk
28 25-Dec-06 RMS Fixed bug in unit mask (found by John Dundas)
29 26-Jun-06 RMS Cloned from RF08 simulator
31 The RF11 is a head-per-track disk. To minimize overhead, the entire RF11
32 is buffered in memory.
34 Two timing parameters are provided:
36 rf_time Interword timing, must be non-zero
37 rf_burst Burst mode, if 0, DMA occurs cycle by cycle; otherwise,
41 #include "pdp11_defs.h"
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)
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 */
59 /* Parameters in the unit descriptor */
61 #define FUNC u4 /* function */
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 */
77 #define RFCS_MEX (RFCS_M_MEX << RFCS_V_MEX)
78 #define RFCS_MAINT 0000010 /* maint */
79 #define RFCS_M_FUNC 0000003 /* function */
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)
90 /* Current memory address */
92 #define RFCMA_RW 0177776
94 /* Address extension */
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
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)))
111 extern int32 int_req
[IPL_HLVL
];
112 extern FILE *sim_deb
;
114 uint32 rf_cs
= 0; /* status register */
117 uint32 rf_da
= 0; /* disk address */
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 */
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
);
137 /* RF11 data structures
139 rf_dev RF device descriptor
140 rf_unit RF unit descriptor
141 rf_reg RF register list
145 IOBA_RF
, IOLN_RF
, &rf_rd
, &rf_wr
,
146 1, IVCL (RF
), VEC_RF
, NULL
151 UDATA (&rf_svc
, UNIT_FIX
+UNIT_ATTABLE
+
152 UNIT_BUFABLE
+UNIT_MUSTBUF
, RF_DKSIZE
)
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
},
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
},
194 "RF", &rf_unit
, rf_reg
, rf_mod
,
196 NULL
, NULL
, &rf_reset
,
197 &rf_boot
, &rf_attach
, NULL
,
198 &rf_dib
, DEV_DISABLE
| DEV_DIS
| DEV_UBUS
| DEV_DEBUG
201 /* I/O dispatch routine, I/O addresses 17777460 - 17777476 */
203 t_stat
rf_rd (int32
*data
, int32 PA
, int32 access
)
205 switch ((PA
>> 1) & 07) { /* decode PA<3:1> */
208 *data
= update_rfcs (0, 0); /* update RFCS */
216 *data
= rf_cma
& RFCMA_RW
;
224 *data
= rf_dae
& RFDAE_R
;
236 *data
= GET_POS (rf_time
);
242 t_stat
rf_wr (int32 data
, int32 PA
, int32 access
)
246 switch ((PA
>> 1) & 07) { /* decode PA<3:1> */
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
);
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
);
272 if (access
== WRITEB
) data
= (PA
& 1)?
273 (rf_wc
& 0377) | (data
<< 8): (rf_wc
& ~0377) | data
;
278 if (access
== WRITEB
) data
= (PA
& 1)?
279 (rf_cma
& 0377) | (data
<< 8): (rf_cma
& ~0377) | data
;
280 rf_cma
= data
& RFCMA_RW
;
284 if (access
== WRITEB
) data
= (PA
& 1)?
285 (rf_da
& 0377) | (data
<< 8): (rf_da
& ~0377) | data
;
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
);
304 break; /* read only */
313 Note that for reads and writes, memory addresses wrap around in the
314 current field. This code assumes the entire disk is buffered.
317 t_stat
rf_svc (UNIT
*uptr
)
321 uint16
*fbuf
= uptr
->filebuf
;
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
);
328 ma
= GET_MEX (rf_cs
) | rf_cma
; /* 18b mem addr */
329 da
= GET_DEX (rf_dae
) | rf_da
; /* 22b disk addr */
331 if (da
>= rf_unit
.capac
) { /* disk overflow? */
332 update_rfcs (RFCS_NED
, 0);
335 if (uptr
->FUNC
== RFNC_READ
) { /* read? */
336 dat
= fbuf
[da
]; /* get disk data */
338 if (Map_WriteW (ma
, 2, &dat
)) { /* store mem, nxm? */
339 update_rfcs (0, RFDAE_NXM
);
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
);
349 if (rf_dbr
!= dat
) { /* miscompare? */
350 update_rfcs (RFCS_WCHK
, 0);
355 t
= (da
>> 15) & 037;
356 if ((rf_wlk
>> t
) & 1) { /* write locked? */
357 update_rfcs (RFCS_WLK
, 0);
360 else { /* not locked */
361 if (Map_ReadW (ma
, 2, &dat
)) { /* read mem, nxm? */
362 update_rfcs (0, RFDAE_NXM
);
365 fbuf
[da
] = dat
; /* write word */
367 if (da
>= uptr
->hwmark
) uptr
->hwmark
= da
+ 1;
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 */
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 */
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
);
391 /* Update CS register */
393 uint32
update_rfcs (uint32 newcs
, uint32 newdae
)
395 uint32 oldcs
= rf_cs
;
396 uint32 da
= GET_DEX (rf_dae
) | rf_da
;
398 rf_dae
|= newdae
; /* update DAE */
399 rf_cs
|= newcs
; /* update CS */
400 if (da
>= rf_unit
.capac
) /* update CS<ned> */
402 else rf_cs
&= ~RFCS_NED
;
403 if (rf_dae
& RFDAE_ALLERR
) /* update CS<frz> */
405 else rf_cs
&= ~RFCS_FRZ
;
406 if (rf_cs
& RFCS_ALLERR
) /* update CS<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? */
417 t_stat
rf_reset (DEVICE
*dptr
)
426 sim_cancel (&rf_unit
);
430 /* Bootstrap routine */
432 /* Device bootstrap */
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))
439 static const uint16 boot_rom
[] = {
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) */
458 t_stat
rf_boot (int32 unitno
, DEVICE
*dptr
)
461 extern int32 saved_PC
;
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
;
471 t_stat
rf_attach (UNIT
*uptr
, char *cptr
)
474 uint32 ds_bytes
= RF_DKSIZE
* sizeof (int16
);
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
) |
482 uptr
->capac
= UNIT_GETP (uptr
->flags
) * RF_DKSIZE
;
483 return attach_unit (uptr
, cptr
);
486 /* Change disk size */
488 t_stat
rf_set_size (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
)
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
;