1 /* pdp1_drm.c: PDP-1 drum simulator
2
3 Copyright (c) 1993-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 drp Type 23 parallel drum
27 drm Type 24 serial drum
28
29 21-Dec-06 RMS Added 16-chan SBS support
30 08-Dec-03 RMS Added parallel drum support
31 Fixed bug in DBL/DCN decoding
32 26-Oct-03 RMS Cleaned up buffer copy code
33 23-Jul-03 RMS Fixed incorrect logical, missing activate
34 05-Dec-02 RMS Cloned from pdp18b_drm.c
35 */
36
37 #include "pdp1_defs.h"
38 #include <math.h>
39
40 /* Serial drum constants */
41
42 #define DRM_NUMWDS 256 /* words/sector */
43 #define DRM_NUMSC 2 /* sectors/track */
44 #define DRM_NUMTR 256 /* tracks/drum */
45 #define DRM_NUMWDT (DRM_NUMWDS * DRM_NUMSC) /* words/track */
46 #define DRM_SIZE (DRM_NUMTR * DRM_NUMWDT) /* words/drum */
47 #define DRM_SMASK ((DRM_NUMTR * DRM_NUMSC) - 1) /* sector mask */
48
49 /* Parallel drum constants */
50
51 #define DRP_NUMWDT 4096 /* words/track */
52 #define DRP_NUMTK 32 /* tracks/drum */
53 #define DRP_SIZE (DRP_NUMWDT * DRP_NUMTK) /* words/drum */
54 #define DRP_V_RWE 17 /* read/write enable */
55 #define DRP_V_FLD 12 /* drum field */
56 #define DRP_M_FLD 037
57 #define DRP_TAMASK 07777 /* track address */
58 #define DRP_WCMASK 07777 /* word count */
59 #define DRP_MAINCM 07777 /* mem addr incr */
60 #define DRP_GETRWE(x) (((x) >> DRP_V_RWE) & 1)
61 #define DRP_GETRWF(x) (((x) >> DRP_V_FLD) & DRP_M_FLD)
62
63 /* Parameters in the unit descriptor */
64
65 #define FUNC u4 /* function */
66 #define DRM_READ 000 /* read */
67 #define DRM_WRITE 010 /* write */
68 #define DRP_RW 000 /* read/write */
69 #define DRP_BRK 001 /* break on address */
70
71 #define GET_POS(x) ((int) fmod (sim_gtime() / ((double) (x)), \
72 ((double) DRM_NUMWDT)))
73
74 extern int32 M[];
75 extern int32 iosta;
76 extern int32 stop_inst;
77 extern UNIT cpu_unit;
78
79 /* Serial drum variables */
80
81 uint32 drm_da = 0; /* track address */
82 uint32 drm_ma = 0; /* memory address */
83 uint32 drm_err = 0; /* error flag */
84 uint32 drm_wlk = 0; /* write lock */
85 int32 drm_time = 4; /* inter-word time */
86 int32 drm_sbs = 0; /* SBS level */
87 int32 drm_stopioe = 1; /* stop on error */
88
89 /* Parallel drum variables */
90
91 uint32 drp_rde = 0; /* read enable */
92 uint32 drp_wre = 0; /* write enable */
93 uint32 drp_rdf = 0; /* read field */
94 uint32 drp_wrf = 0; /* write field */
95 uint32 drp_ta = 0; /* track address */
96 uint32 drp_wc = 0; /* word count */
97 uint32 drp_ma = 0; /* memory address */
98 uint32 drp_err = 0; /* error */
99 int32 drp_time = 2; /* inter-word time */
100 int32 drp_stopioe = 1; /* stop on error */
101
102 /* Forward declarations */
103
104 t_stat drm_svc (UNIT *uptr);
105 t_stat drm_reset (DEVICE *dptr);
106 t_stat drp_svc (UNIT *uptr);
107 t_stat drp_reset (DEVICE *dptr);
108
109 /* DRM data structures
110
111 drm_dev DRM device descriptor
112 drm_unit DRM unit descriptor
113 drm_reg DRM register list
114 */
115
116 UNIT drm_unit = {
117 UDATA (&drm_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF,
118 DRM_SIZE)
119 };
120
121 REG drm_reg[] = {
122 { ORDATA (DA, drm_da, 9) },
123 { ORDATA (MA, drm_ma, 16) },
124 { FLDATA (DONE, iosta, IOS_V_DRM) },
125 { FLDATA (ERR, drm_err, 0) },
126 { ORDATA (WLK, drm_wlk, 32) },
127 { DRDATA (TIME, drm_time, 24), REG_NZ + PV_LEFT },
128 { DRDATA (SBSLVL, drm_sbs, 4), REG_HRO },
129 { FLDATA (STOP_IOE, drm_stopioe, 0) },
130 { NULL }
131 };
132
133 MTAB drm_mod[] = {
134 { MTAB_XTD|MTAB_VDV, 0, "APILVL", "APILVL",
135 &dev_set_sbs, &dev_show_sbs, (void *) &drm_sbs },
136 { 0 }
137 };
138
139 DEVICE drm_dev = {
140 "DRM", &drm_unit, drm_reg, drm_mod,
141 1, 8, 20, 1, 8, 18,
142 NULL, NULL, &drm_reset,
143 NULL, NULL, NULL,
144 NULL, DEV_DISABLE
145 };
146
147 /* DRP data structures
148
149 drp_dev DRP device descriptor
150 drp_unit DRP unit descriptor
151 drp_reg DRP register list
152 */
153
154 UNIT drp_unit = {
155 UDATA (&drp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF,
156 DRM_SIZE)
157 };
158
159 REG drp_reg[] = {
160 { ORDATA (TA, drp_ta, 12) },
161 { ORDATA (RDF, drp_rdf, 5) },
162 { FLDATA (RDE, drp_rde, 0) },
163 { FLDATA (WRF, drp_wrf, 5) },
164 { FLDATA (WRE, drp_wre, 0) },
165 { ORDATA (MA, drp_ma, 16) },
166 { ORDATA (WC, drp_wc, 12) },
167 { FLDATA (BUSY, iosta, IOS_V_DRP) },
168 { FLDATA (ERR, drp_err, 0) },
169 { DRDATA (TIME, drp_time, 24), REG_NZ + PV_LEFT },
170 { FLDATA (STOP_IOE, drp_stopioe, 0) },
171 { DRDATA (SBSLVL, drm_sbs, 4), REG_HRO },
172 { NULL }
173 };
174
175 DEVICE drp_dev = {
176 "DRP", &drp_unit, drp_reg, NULL,
177 1, 8, 20, 1, 8, 18,
178 NULL, NULL, &drp_reset,
179 NULL, NULL, NULL,
180 NULL, DEV_DISABLE | DEV_DIS
181 };
182
183 /* IOT routines */
184
drm(int32 IR,int32 dev,int32 dat)185 int32 drm (int32 IR, int32 dev, int32 dat)
186 {
187 int32 t;
188 int32 pulse = (IR >> 6) & 037;
189
190 if ((drm_dev.flags & DEV_DIS) == 0) { /* serial enabled? */
191 if ((pulse != 001) && (pulse != 011)) /* invalid pulse? */
192 return (stop_inst << IOT_V_REASON) | dat; /* stop if requested */
193 switch (dev) { /* switch on device */
194
195 case 061: /* DWR, DRD */
196 drm_ma = dat & AMASK; /* load mem addr */
197 drm_unit.FUNC = pulse & DRM_WRITE; /* save function */
198 break;
199
200 case 062: /* DBL, DCN */
201 if ((pulse & 010) == 0) /* DBL? */
202 drm_da = dat & DRM_SMASK; /* load sector # */
203 iosta = iosta & ~IOS_DRM; /* clear flags */
204 drm_err = 0;
205 t = ((drm_da % DRM_NUMSC) * DRM_NUMWDS) - GET_POS (drm_time);
206 if (t <= 0) /* wrap around? */
207 t = t + DRM_NUMWDT;
208 sim_activate (&drm_unit, t); /* start operation */
209 break;
210
211 case 063: /* DTD */
212 if (pulse == 011)
213 return (stop_inst << IOT_V_REASON) | dat;
214 if (iosta & IOS_DRM) /* skip if done */
215 return (dat | IOT_SKP);
216 break;
217
218 case 064: /* DSE, DSP */
219 if ((drm_err == 0) || (pulse & 010)) /* no error, par test? */
220 return (dat | IOT_SKP);
221 } /* end case */
222
223 return dat;
224 } /* end if serial */
225
226 if ((drp_dev.flags & DEV_DIS) == 0) { /* parallel enabled? */
227 switch (dev) { /* switch on device */
228
229 case 061: /* DIA, DBA */
230 drp_err = 0; /* clear error */
231 iosta = iosta & ~IOS_DRP; /* not busy */
232 drp_rde = DRP_GETRWE (dat); /* set read enable */
233 drp_rdf = DRP_GETRWF (dat); /* set read field */
234 drp_ta = dat & DRP_TAMASK; /* set track addr */
235 if (IR & 02000) { /* DBA? */
236 t = drp_ta - GET_POS (drp_time); /* delta words */
237 if (t <= 0) /* wrap around? */
238 t = t + DRP_NUMWDT;
239 sim_activate (&drp_unit, t); /* start operation */
240 drp_unit.FUNC = DRP_BRK; /* mark as break */
241 }
242 else drp_unit.FUNC = DRP_RW; /* no, read/write */
243 break;
244
245 case 062: /* DWC, DRA */
246 if (IR & 02000) dat = GET_POS (drp_time) | /* DRA, get position */
247 (drp_err? 0400000: 0);
248 else { /* DWC */
249 drp_wre = DRP_GETRWE (dat); /* set write enable */
250 drp_wrf = DRP_GETRWF (dat); /* set write field */
251 drp_wc = dat & DRP_WCMASK; /* set word count */
252 }
253 break;
254
255 case 063: /* DCL */
256 drp_ma = dat & AMASK; /* set mem address */
257 t = drp_ta - GET_POS (drp_time); /* delta words */
258 if (t <= 0) /* wrap around? */
259 t = t + DRP_NUMWDT;
260 sim_activate (&drp_unit, t); /* start operation */
261 iosta = iosta | IOS_DRP; /* set busy */
262 break;
263
264 case 064: /* not assigned */
265 return (stop_inst << IOT_V_REASON) | dat; /* stop if requested */
266 } /* end case */
267
268 return dat;
269 } /* end if parallel */
270
271 return (stop_inst << IOT_V_REASON) | dat; /* stop if requested */
272 }
273
274 /* Serial unit service - this code assumes the entire drum is buffered */
275
drm_svc(UNIT * uptr)276 t_stat drm_svc (UNIT *uptr)
277 {
278 uint32 i, da;
279 uint32 *fbuf = uptr->filebuf;
280
281 if ((uptr->flags & UNIT_BUF) == 0) { /* not buf? abort */
282 drm_err = 1; /* set error */
283 iosta = iosta | IOS_DRM; /* set done */
284 dev_req_int (drm_sbs); /* req intr */
285 return IORETURN (drm_stopioe, SCPE_UNATT);
286 }
287
288 da = drm_da * DRM_NUMWDS; /* compute dev addr */
289 for (i = 0; i < DRM_NUMWDS; i++, da++) { /* do transfer */
290 if (uptr->FUNC == DRM_READ) { /* read? */
291 if (MEM_ADDR_OK (drm_ma)) /* if !nxm */
292 M[drm_ma] = fbuf[da]; /* read word */
293 }
294 else { /* write */
295 if ((drm_wlk >> (drm_da >> 4)) & 1)
296 drm_err = 1;
297 else { /* not locked */
298 fbuf[da] = M[drm_ma]; /* write word */
299 if (da >= uptr->hwmark)
300 uptr->hwmark = da + 1;
301 }
302 }
303 drm_ma = (drm_ma + 1) & AMASK; /* incr mem addr */
304 }
305 drm_da = (drm_da + 1) & DRM_SMASK; /* incr dev addr */
306 iosta = iosta | IOS_DRM; /* set done */
307 dev_req_int (drm_sbs); /* req intr */
308 return SCPE_OK;
309 }
310
311 /* Reset routine */
312
drm_reset(DEVICE * dptr)313 t_stat drm_reset (DEVICE *dptr)
314 {
315 if ((drm_dev.flags & DEV_DIS) == 0)
316 drp_dev.flags = drp_dev.flags | DEV_DIS;
317 drm_da = drm_ma = drm_err = 0;
318 iosta = iosta & ~IOS_DRM;
319 sim_cancel (&drm_unit);
320 drm_unit.FUNC = 0;
321 return SCPE_OK;
322 }
323
324 /* Parallel unit service - this code assumes the entire drum is buffered */
325
drp_svc(UNIT * uptr)326 t_stat drp_svc (UNIT *uptr)
327 {
328 uint32 i, lim;
329 uint32 *fbuf = uptr->filebuf;
330
331 if ((uptr->flags & UNIT_BUF) == 0) { /* not buf? abort */
332 drp_err = 1; /* set error */
333 iosta = iosta & ~IOS_DRP; /* clear busy */
334 if (uptr->FUNC) /* req intr */
335 dev_req_int (drm_sbs);
336 return IORETURN (drp_stopioe, SCPE_UNATT);
337 }
338
339 if (uptr->FUNC == DRP_RW) { /* read/write? */
340 lim = drp_wc? drp_wc: DRP_TAMASK + 1; /* eff word count */
341 for (i = 0; i < lim; i++) { /* do transfer */
342 if (drp_wre) /* write enabled? */
343 fbuf[(drp_wrf << DRP_V_FLD) | drp_ta] = M[drp_ma];
344 if (drp_rde && MEM_ADDR_OK (drp_ma)) /* read enabled? */
345 M[drp_ma] = fbuf[(drp_rdf << DRP_V_FLD) | drp_ta];
346 drp_ta = (drp_ta + 1) & DRP_TAMASK; /* incr track addr */
347 drp_ma = ((drp_ma & ~DRP_MAINCM) | ((drp_ma + 1) & DRP_MAINCM));
348 } /* end for */
349 } /* end if */
350 iosta = iosta & ~IOS_DRP; /* clear busy */
351 if (uptr->FUNC) /* req intr */
352 dev_req_int (drm_sbs);
353 return SCPE_OK;
354 }
355
356 /* Reset routine */
357
drp_reset(DEVICE * dptr)358 t_stat drp_reset (DEVICE *dptr)
359 {
360 if ((drp_dev.flags & DEV_DIS) == 0)
361 drm_dev.flags = drm_dev.flags | DEV_DIS;
362 drp_ta = 0;
363 drp_rde = drp_rdf = drp_wre = drp_wrf = 0;
364 drp_err = 0;
365 drp_ma = 0;
366 drp_wc = 0;
367 iosta = iosta & ~IOS_DRP;
368 sim_cancel (&drp_unit);
369 drp_unit.FUNC = 0;
370 return SCPE_OK;
371 }
372