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