1 /* sds_drm.c: SDS 940 Project Genie drum simulator
2
3 Copyright (c) 2002-2008, 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 drm drum
27
28 The drum is buffered in memory.
29
30 Note: the Project Genie documentation and the actual monitor sources disagree
31 on the I/O instruction definitions for the drum. The simulator follows the
32 monitor sources, as follows:
33
34 DCC OP 00230404B RESET DRUM CHANNEL
35 DSC OP 00230204B START DRUM CHANNEL (NO CHAIN)
36 DRA OP 00230504B READ DRUM TIMING COUNTER INTO 21B
37 DSR OP 04030204B SKIP IF DRUM NOT BUSY
38 DSE OP 04037404B SKIP IF NO DRUM ERROR
39 */
40
41 #include "sds_defs.h"
42 #include <math.h>
43
44 /* Constants */
45
46 #define DRM_N_WD 11 /* word addr width */
47 #define DRM_V_WD 0 /* position */
48 #define DRM_M_WD ((1 << DRM_N_WD) - 1) /* word mask */
49 #define DRM_NUMWD (1 << DRM_N_WD) /* words/sector */
50 #define DRM_NUMGP 236 /* gap/sector */
51 #define DRM_PHYWD (DRM_NUMWD + DRM_NUMGP) /* phys wds/sector */
52 #define DRM_N_SC 3 /* sect addr width */
53 #define DRM_V_SC (DRM_N_WD) /* position */
54 #define DRM_M_SC ((1 << DRM_N_SC) - 1) /* sector mask */
55 #define DRM_NUMSC (1 << DRM_N_SC) /* sectors/track */
56 #define DRM_N_TR 7 /* track addr width */
57 #define DRM_V_TR (DRM_N_WD+DRM_N_SC) /* position */
58 #define DRM_M_TR ((1 << DRM_N_TR) - 1) /* track mask */
59 #define DRM_NUMTR 84 /* tracks/drum */
60 #define DRM_N_ADDR (DRM_N_WD+DRM_N_SC+DRM_N_TR) /* drum addr width */
61 #define DRM_SWMASK ((1 << (DRM_N_WD+DRM_N_SC)) - 1)/* sector+word mask */
62 #define DRM_DAMASK ((1 << DRM_N_ADDR) - 1) /* drum addr mask */
63 #define DRM_SIZE (DRM_NUMTR*DRM_NUMSC*DRM_NUMWD) /* words/disk */
64 #define DRM_WCMASK 037777 /* wc mask */
65 #define DRM_GETSC(x) (((x) >> DRM_V_SC) & DRM_M_SC)
66
67 #define DRM_PC 020
68 #define DRM_AD 021
69 #define DRM_ADAT (1 << (DRM_N_WD + DRM_N_SC)) /* data flag */
70
71 #define DRM_SFET 0 /* fetch state */
72 #define DRM_SFCA 1 /* fetch CA */
73 #define DRM_SFDA 2 /* fetch DA */
74 #define DRM_SXFR 3 /* xfer */
75
76 #define DRM_V_OP 21 /* drum op */
77 #define DRM_M_OP 07
78 #define DRM_V_RW 20
79 #define DRM_GETOP(x) (((x) >> DRM_V_OP) & DRM_M_OP)
80 #define DRM_GETRW(x) (((x) >> DRM_V_RW) & 1)
81 #define DRM_OXF 0 /* xfer */
82 #define DRM_OCX 1 /* cond xfer */
83 #define DRM_OBR 2 /* branch */
84 #define DRM_ORS 3 /* reset error */
85 #define DRM_END 4 /* end prog */
86 #define DRM_EIE 5 /* end int if err */
87 #define DRM_EIU 7 /* end int uncond */
88
89 #define GET_TWORD(x) ((int32) fmod (sim_gtime() / ((double) (x)), \
90 ((double) (DRM_NUMSC * DRM_PHYWD))))
91
92 extern uint32 M[]; /* memory */
93 extern uint32 alert, int_req;
94 extern int32 stop_invins, stop_invdev, stop_inviop;
95 uint32 drm_da = 0; /* disk address */
96 uint32 drm_ca = 0; /* core address */
97 uint32 drm_wc = 0; /* word count */
98 int32 drm_par = 0; /* cumulative par */
99 int32 drm_err = 0; /* error */
100 int32 drm_rw = 0; /* read/write */
101 int32 drm_sta = 0; /* drum state */
102 int32 drm_ftime = 3; /* time to fetch */
103 int32 drm_xtime = 1; /* time to xfr */
104 int32 drm_stopioe = 1; /* stop on error */
105
106 DEVICE drm_dev;
107 t_stat drm (uint32 fnc, uint32 inst, uint32 *dat);
108 t_stat drm_svc (UNIT *uptr);
109 t_stat drm_reset (DEVICE *dptr);
110
111 /* DRM data structures
112
113 drm_dev device descriptor
114 drm_unit unit descriptor
115 drm_reg register list
116 */
117
118 DIB drm_dib = { -1, DEV3_GDRM, 0, NULL, &drm };
119
120 UNIT drm_unit = {
121 UDATA (&drm_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF,
122 DRM_SIZE)
123 };
124
125 REG drm_reg[] = {
126 { ORDATA (DA, drm_da, DRM_N_ADDR) },
127 { ORDATA (CA, drm_ca, 16) },
128 { ORDATA (WC, drm_wc, 14) },
129 { ORDATA (PAR, drm_par, 12) },
130 { FLDATA (RW, drm_rw, 0) },
131 { FLDATA (ERR, drm_err, 0) },
132 { ORDATA (STA, drm_sta, 2) },
133 { DRDATA (FTIME, drm_ftime, 24), REG_NZ + PV_LEFT },
134 { DRDATA (XTIME, drm_xtime, 24), REG_NZ + PV_LEFT },
135 { FLDATA (STOP_IOE, drm_stopioe, 0) },
136 { NULL }
137 };
138
139 DEVICE drm_dev = {
140 "DRM", &drm_unit, drm_reg, NULL,
141 1, 8, DRM_N_ADDR, 1, 8, 24,
142 NULL, NULL, &drm_reset,
143 NULL, NULL, NULL,
144 &drm_dib, DEV_DISABLE | DEV_DIS
145 };
146
147 /* Drum routine - EOM/SKS 3xx04 */
148
drm(uint32 fnc,uint32 inst,uint32 * dat)149 t_stat drm (uint32 fnc, uint32 inst, uint32 *dat)
150 {
151 int32 t, op = inst & 07700;
152
153 switch (fnc) {
154
155 case IO_CONN: /* connect */
156 if (op == 00400) /* EOM 404 = reset */
157 return drm_reset (&drm_dev);
158 if (op == 00500) { /* EOM 504 = read DA */
159 if (sim_is_active (&drm_unit))
160 return SCPE_OK; /* must be idle */
161 t = GET_TWORD (drm_xtime); /* get position */
162 if (t < DRM_NUMGP) /* in gap? */
163 M[DRM_AD] = DRM_NUMWD - t;
164 else M[DRM_AD] = (t - DRM_NUMGP) | DRM_ADAT;/* in data */
165 }
166 else if (op == 00200) { /* EOM 204 = start */
167 if (sim_is_active (&drm_unit)) /* must be idle */
168 return SCPE_OK;
169 drm_sta = DRM_SFET; /* state = fetch */
170 sim_activate (&drm_unit, drm_ftime); /* activate */
171 }
172 else CRETINS;
173 break;
174
175 case IO_SKS: /* SKS */
176 if (((op == 07400) && !drm_err) || /* 37404: no err */
177 ((op == 00200) && !sim_is_active (&drm_unit))) /* 30204: idle */
178 *dat = 1;
179 break;
180
181 default:
182 return SCPE_IERR;
183 }
184
185 return SCPE_OK;
186 }
187
188 /* Unit service */
189
drm_svc(UNIT * uptr)190 t_stat drm_svc (UNIT *uptr)
191 {
192 int32 t, rda;
193 uint32 dpc, dwd;
194 uint32 *fbuf = uptr->filebuf;
195
196 if (drm_sta != DRM_SXFR) { /* fetch drum prog? */
197 dpc = M[DRM_PC]; /* get drum PC */
198 dwd = M[dpc & PAMASK]; /* get drum inst */
199 M[DRM_PC] = (dpc + 1) & PAMASK; /* update drum PC */
200 if (drm_sta == DRM_SFCA) { /* fetch core addr? */
201 drm_rw = DRM_GETRW (dwd); /* set op */
202 drm_ca = dwd & PAMASK; /* set core addr */
203 drm_sta = DRM_SFDA; /* next is disk addr */
204 }
205 else if (drm_sta == DRM_SFDA) { /* fetch disk addr? */
206 drm_da = dwd & DRM_DAMASK; /* set disk addr */
207 drm_sta = DRM_SXFR; /* next is xfer */
208 drm_par = 0; /* init parity */
209 rda = (drm_da & DRM_SWMASK) + (DRM_GETSC (drm_da) * DRM_NUMGP);
210 t = rda - GET_TWORD (drm_xtime); /* difference */
211 if (t <= 0) /* add trk lnt */
212 t = t + (DRM_NUMSC * DRM_PHYWD);
213 sim_activate (&drm_unit, t * drm_xtime); /* activate */
214 }
215 else {
216 switch (DRM_GETOP (dwd)) {
217
218 case DRM_OCX: /* cond xfr */
219 if (drm_err) { /* error? */
220 int_req = int_req | INT_DRM; /* req int */
221 return SCPE_OK; /* done */
222 }
223 case DRM_OXF: /* transfer */
224 drm_wc = dwd & DRM_WCMASK; /* save wc */
225 drm_sta = DRM_SFCA; /* next state */
226 break;
227
228 case DRM_OBR: /* branch */
229 M[DRM_PC] = dwd & PAMASK; /* new drum PC */
230 break;
231
232 case DRM_END: /* end */
233 return SCPE_OK;
234
235 case DRM_EIE: /* end, int if err */
236 if (!drm_err)
237 return SCPE_OK;
238
239 case DRM_EIU: /* end, int uncond */
240 int_req = int_req | INT_DRM;
241 return SCPE_OK;
242 } /* end switch */
243 } /* end else sta */
244 sim_activate (uptr, drm_ftime); /* fetch next word */
245 } /* end if !xfr */
246 else { /* transfer word */
247 if ((uptr->flags & UNIT_BUF) == 0) { /* not buffered? */
248 drm_err = 1; /* error */
249 CRETIOE (drm_stopioe, SCPE_UNATT);
250 }
251 if (drm_rw) { /* write? */
252 dwd = M[drm_ca]; /* get mem word */
253 fbuf[drm_da] = dwd; /* write to drum */
254 if (drm_da >= uptr->hwmark)
255 uptr->hwmark = drm_da + 1;
256 }
257 else { /* read */
258 dwd = fbuf[drm_da]; /* get drum word */
259 M[drm_ca] = dwd; /* write to mem */
260 }
261 drm_da = drm_da + 1; /* inc drum addr */
262 if (drm_da >= DRM_SIZE) /* wrap */
263 drm_da = 0;
264 drm_ca = (drm_ca + 1) & PAMASK; /* inc core addr */
265 drm_wc = (drm_wc - 1) & DRM_WCMASK; /* dec word cnt */
266 drm_par = drm_par ^ (dwd >> 12); /* parity */
267 drm_par = ((drm_par << 1) | (drm_par >> 11)) & 07777;
268 drm_par = drm_par ^ (dwd & 07777);
269 if (drm_wc) { /* more to do */
270 if (drm_da & DRM_M_WD)
271 sim_activate (uptr, drm_xtime);
272 else sim_activate (uptr, drm_xtime * DRM_NUMGP);
273 }
274 else { /* end xfr */
275 #if defined (DRM_PAR)
276 if ((drm_da & DRM_M_WD) && drm_rw) { /* wr end mid sector? */
277 M[drm_da] = drm_par << 12; /* clobber data */
278 if (drm_da >= uptr->hwmark)
279 uptr->hwmark = drm_da + 1;
280 }
281 #endif
282 drm_sta = DRM_SFET; /* back to fetch */
283 sim_activate (uptr, drm_ftime); /* schedule */
284 } /* end else end xfr */
285 } /* end else xfr */
286 return SCPE_OK;
287 }
288
289 /* Reset routine */
290
drm_reset(DEVICE * dptr)291 t_stat drm_reset (DEVICE *dptr)
292 {
293 drm_da = 0; /* clear state */
294 drm_ca = 0;
295 drm_wc = 0;
296 drm_par = 0;
297 drm_sta = 0;
298 drm_err = 0;
299 drm_rw = 0;
300 int_req = int_req & ~INT_DRM; /* clear intr */
301 sim_cancel (&drm_unit); /* deactivate */
302 return SCPE_OK;
303 }
304