First Commit of my working state
[simh.git] / PDP1 / pdp1_drm.c
CommitLineData
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
74extern int32 M[];\r
75extern int32 iosta;\r
76extern int32 stop_inst;\r
77extern UNIT cpu_unit;\r
78\r
79/* Serial drum variables */\r
80\r
81uint32 drm_da = 0; /* track address */\r
82uint32 drm_ma = 0; /* memory address */\r
83uint32 drm_err = 0; /* error flag */\r
84uint32 drm_wlk = 0; /* write lock */\r
85int32 drm_time = 4; /* inter-word time */\r
86int32 drm_sbs = 0; /* SBS level */\r
87int32 drm_stopioe = 1; /* stop on error */\r
88\r
89/* Parallel drum variables */\r
90\r
91uint32 drp_rde = 0; /* read enable */\r
92uint32 drp_wre = 0; /* write enable */\r
93uint32 drp_rdf = 0; /* read field */\r
94uint32 drp_wrf = 0; /* write field */\r
95uint32 drp_ta = 0; /* track address */\r
96uint32 drp_wc = 0; /* word count */\r
97uint32 drp_ma = 0; /* memory address */\r
98uint32 drp_err = 0; /* error */\r
99int32 drp_time = 2; /* inter-word time */\r
100int32 drp_stopioe = 1; /* stop on error */\r
101\r
102/* Forward declarations */\r
103\r
104t_stat drm_svc (UNIT *uptr);\r
105t_stat drm_reset (DEVICE *dptr);\r
106t_stat drp_svc (UNIT *uptr);\r
107t_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
116UNIT drm_unit = {\r
117 UDATA (&drm_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF,\r
118 DRM_SIZE)\r
119 };\r
120\r
121REG 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
133MTAB 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
139DEVICE 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
154UNIT drp_unit = {\r
155 UDATA (&drp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF,\r
156 DRM_SIZE)\r
157 };\r
158\r
159REG 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
175DEVICE 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
185int32 drm (int32 IR, int32 dev, int32 dat)\r
186{\r
187int32 t;\r
188int32 pulse = (IR >> 6) & 037;\r
189\r
190if ((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
223if ((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
266return (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
271t_stat drm_svc (UNIT *uptr)\r
272{\r
273uint32 i, da;\r
274uint32 *fbuf = uptr->filebuf;\r
275\r
276if ((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
283da = drm_da * DRM_NUMWDS; /* compute dev addr */\r
284for (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
298drm_da = (drm_da + 1) & DRM_SMASK; /* incr dev addr */\r
299iosta = iosta | IOS_DRM; /* set done */\r
300dev_req_int (drm_sbs); /* req intr */\r
301return SCPE_OK;\r
302}\r
303\r
304/* Reset routine */\r
305\r
306t_stat drm_reset (DEVICE *dptr)\r
307{\r
308if ((drm_dev.flags & DEV_DIS) == 0)\r
309 drp_dev.flags = drp_dev.flags | DEV_DIS;\r
310drm_da = drm_ma = drm_err = 0;\r
311iosta = iosta & ~IOS_DRM;\r
312sim_cancel (&drm_unit);\r
313drm_unit.FUNC = 0;\r
314return SCPE_OK;\r
315}\r
316\r
317/* Parallel unit service - this code assumes the entire drum is buffered */\r
318\r
319t_stat drp_svc (UNIT *uptr)\r
320{\r
321uint32 i, lim;\r
322uint32 *fbuf = uptr->filebuf;\r
323\r
324if ((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
331if (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
342iosta = iosta & ~IOS_DRP; /* clear busy */\r
343if (uptr->FUNC) dev_req_int (drm_sbs); /* req intr */\r
344return SCPE_OK;\r
345}\r
346\r
347/* Reset routine */\r
348\r
349t_stat drp_reset (DEVICE *dptr)\r
350{\r
351if ((drp_dev.flags & DEV_DIS) == 0)\r
352 drm_dev.flags = drm_dev.flags | DEV_DIS;\r
353drp_ta = 0;\r
354drp_rde = drp_rdf = drp_wre = drp_wrf = 0;\r
355drp_err = 0;\r
356drp_ma = 0;\r
357drp_wc = 0;\r
358iosta = iosta & ~IOS_DRP;\r
359sim_cancel (&drp_unit);\r
360drp_unit.FUNC = 0;\r
361return SCPE_OK;\r
362}\r