First Commit of my working state
[simh.git] / PDP1 / pdp1_drm.c
1 /* pdp1_drm.c: PDP-1 drum simulator
2
3 Copyright (c) 1993-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 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
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) t = t + DRM_NUMWDT; /* wrap around? */
207 sim_activate (&drm_unit, t); /* start operation */
208 break;
209
210 case 063: /* DTD */
211 if (pulse == 011) return (stop_inst << IOT_V_REASON) | dat;
212 if (iosta & IOS_DRM) return (dat | IOT_SKP); /* skip if done */
213 break;
214
215 case 064: /* DSE, DSP */
216 if ((drm_err == 0) || (pulse & 010)) /* no error, par test? */
217 return (dat | IOT_SKP);
218 } /* end case */
219
220 return dat;
221 } /* end if serial */
222
223 if ((drp_dev.flags & DEV_DIS) == 0) { /* parallel enabled? */
224 switch (dev) { /* switch on device */
225
226 case 061: /* DIA, DBA */
227 drp_err = 0; /* clear error */
228 iosta = iosta & ~IOS_DRP; /* not busy */
229 drp_rde = DRP_GETRWE (dat); /* set read enable */
230 drp_rdf = DRP_GETRWF (dat); /* set read field */
231 drp_ta = dat & DRP_TAMASK; /* set track addr */
232 if (IR & 02000) { /* DBA? */
233 t = drp_ta - GET_POS (drp_time); /* delta words */
234 if (t <= 0) t = t + DRP_NUMWDT; /* wrap around? */
235 sim_activate (&drp_unit, t); /* start operation */
236 drp_unit.FUNC = DRP_BRK; /* mark as break */
237 }
238 else drp_unit.FUNC = DRP_RW; /* no, read/write */
239 break;
240
241 case 062: /* DWC, DRA */
242 if (IR & 02000) dat = GET_POS (drp_time) | /* DRA, get position */
243 (drp_err? 0400000: 0);
244 else { /* DWC */
245 drp_wre = DRP_GETRWE (dat); /* set write enable */
246 drp_wrf = DRP_GETRWF (dat); /* set write field */
247 drp_wc = dat & DRP_WCMASK; /* set word count */
248 }
249 break;
250
251 case 063: /* DCL */
252 drp_ma = dat & AMASK; /* set mem address */
253 t = drp_ta - GET_POS (drp_time); /* delta words */
254 if (t <= 0) t = t + DRP_NUMWDT; /* wrap around? */
255 sim_activate (&drp_unit, t); /* start operation */
256 iosta = iosta | IOS_DRP; /* set busy */
257 break;
258
259 case 064: /* not assigned */
260 return (stop_inst << IOT_V_REASON) | dat; /* stop if requested */
261 } /* end case */
262
263 return dat;
264 } /* end if parallel */
265
266 return (stop_inst << IOT_V_REASON) | dat; /* stop if requested */
267 }
268
269 /* Serial unit service - this code assumes the entire drum is buffered */
270
271 t_stat drm_svc (UNIT *uptr)
272 {
273 uint32 i, da;
274 uint32 *fbuf = uptr->filebuf;
275
276 if ((uptr->flags & UNIT_BUF) == 0) { /* not buf? abort */
277 drm_err = 1; /* set error */
278 iosta = iosta | IOS_DRM; /* set done */
279 dev_req_int (drm_sbs); /* req intr */
280 return IORETURN (drm_stopioe, SCPE_UNATT);
281 }
282
283 da = drm_da * DRM_NUMWDS; /* compute dev addr */
284 for (i = 0; i < DRM_NUMWDS; i++, da++) { /* do transfer */
285 if (uptr->FUNC == DRM_READ) { /* read? */
286 if (MEM_ADDR_OK (drm_ma)) /* if !nxm */
287 M[drm_ma] = fbuf[da]; /* read word */
288 }
289 else { /* write */
290 if ((drm_wlk >> (drm_da >> 4)) & 1) drm_err = 1;
291 else { /* not locked */
292 fbuf[da] = M[drm_ma]; /* write word */
293 if (da >= uptr->hwmark) uptr->hwmark = da + 1;
294 }
295 }
296 drm_ma = (drm_ma + 1) & AMASK; /* incr mem addr */
297 }
298 drm_da = (drm_da + 1) & DRM_SMASK; /* incr dev addr */
299 iosta = iosta | IOS_DRM; /* set done */
300 dev_req_int (drm_sbs); /* req intr */
301 return SCPE_OK;
302 }
303
304 /* Reset routine */
305
306 t_stat drm_reset (DEVICE *dptr)
307 {
308 if ((drm_dev.flags & DEV_DIS) == 0)
309 drp_dev.flags = drp_dev.flags | DEV_DIS;
310 drm_da = drm_ma = drm_err = 0;
311 iosta = iosta & ~IOS_DRM;
312 sim_cancel (&drm_unit);
313 drm_unit.FUNC = 0;
314 return SCPE_OK;
315 }
316
317 /* Parallel unit service - this code assumes the entire drum is buffered */
318
319 t_stat drp_svc (UNIT *uptr)
320 {
321 uint32 i, lim;
322 uint32 *fbuf = uptr->filebuf;
323
324 if ((uptr->flags & UNIT_BUF) == 0) { /* not buf? abort */
325 drp_err = 1; /* set error */
326 iosta = iosta & ~IOS_DRP; /* clear busy */
327 if (uptr->FUNC) dev_req_int (drm_sbs); /* req intr */
328 return IORETURN (drp_stopioe, SCPE_UNATT);
329 }
330
331 if (uptr->FUNC == DRP_RW) { /* read/write? */
332 lim = drp_wc? drp_wc: DRP_TAMASK + 1; /* eff word count */
333 for (i = 0; i < lim; i++) { /* do transfer */
334 if (drp_wre) /* write enabled? */
335 fbuf[(drp_wrf << DRP_V_FLD) | drp_ta] = M[drp_ma];
336 if (drp_rde && MEM_ADDR_OK (drp_ma)) /* read enabled? */
337 M[drp_ma] = fbuf[(drp_rdf << DRP_V_FLD) | drp_ta];
338 drp_ta = (drp_ta + 1) & DRP_TAMASK; /* incr track addr */
339 drp_ma = ((drp_ma & ~DRP_MAINCM) | ((drp_ma + 1) & DRP_MAINCM));
340 } /* end for */
341 } /* end if */
342 iosta = iosta & ~IOS_DRP; /* clear busy */
343 if (uptr->FUNC) dev_req_int (drm_sbs); /* req intr */
344 return SCPE_OK;
345 }
346
347 /* Reset routine */
348
349 t_stat drp_reset (DEVICE *dptr)
350 {
351 if ((drp_dev.flags & DEV_DIS) == 0)
352 drm_dev.flags = drm_dev.flags | DEV_DIS;
353 drp_ta = 0;
354 drp_rde = drp_rdf = drp_wre = drp_wrf = 0;
355 drp_err = 0;
356 drp_ma = 0;
357 drp_wc = 0;
358 iosta = iosta & ~IOS_DRP;
359 sim_cancel (&drp_unit);
360 drp_unit.FUNC = 0;
361 return SCPE_OK;
362 }