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