beffa0a488b73bd6247ee0f4fc60f1727d41cd53
1 /* pdp1_drm.c: PDP-1 drum simulator
3 Copyright (c) 1993-2006, Robert M Supnik
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:
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
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.
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.
26 drp Type 23 parallel drum
27 drm Type 24 serial drum
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
37 #include "pdp1_defs.h"
40 /* Serial drum constants */
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 */
49 /* Parallel drum constants */
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 */
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)
63 /* Parameters in the unit descriptor */
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 */
71 #define GET_POS(x) ((int) fmod (sim_gtime() / ((double) (x)), \
72 ((double) DRM_NUMWDT)))
76 extern int32 stop_inst
;
79 /* Serial drum variables */
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 */
89 /* Parallel drum variables */
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 */
102 /* Forward declarations */
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
);
109 /* DRM data structures
111 drm_dev DRM device descriptor
112 drm_unit DRM unit descriptor
113 drm_reg DRM register list
117 UDATA (&drm_svc
, UNIT_FIX
+UNIT_ATTABLE
+UNIT_BUFABLE
+UNIT_MUSTBUF
,
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) },
134 { MTAB_XTD
|MTAB_VDV
, 0, "APILVL", "APILVL",
135 &dev_set_sbs
, &dev_show_sbs
, (void *) &drm_sbs
},
140 "DRM", &drm_unit
, drm_reg
, drm_mod
,
142 NULL
, NULL
, &drm_reset
,
147 /* DRP data structures
149 drp_dev DRP device descriptor
150 drp_unit DRP unit descriptor
151 drp_reg DRP register list
155 UDATA (&drp_svc
, UNIT_FIX
+UNIT_ATTABLE
+UNIT_BUFABLE
+UNIT_MUSTBUF
,
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
},
176 "DRP", &drp_unit
, drp_reg
, NULL
,
178 NULL
, NULL
, &drp_reset
,
180 NULL
, DEV_DISABLE
| DEV_DIS
185 int32
drm (int32 IR
, int32 dev
, int32 dat
)
188 int32 pulse
= (IR
>> 6) & 037;
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 */
195 case 061: /* DWR, DRD */
196 drm_ma
= dat
& AMASK
; /* load mem addr */
197 drm_unit
.FUNC
= pulse
& DRM_WRITE
; /* save function */
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 */
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 */
211 if (pulse
== 011) return (stop_inst
<< IOT_V_REASON
) | dat
;
212 if (iosta
& IOS_DRM
) return (dat
| IOT_SKP
); /* skip if done */
215 case 064: /* DSE, DSP */
216 if ((drm_err
== 0) || (pulse
& 010)) /* no error, par test? */
217 return (dat
| IOT_SKP
);
221 } /* end if serial */
223 if ((drp_dev
.flags
& DEV_DIS
) == 0) { /* parallel enabled? */
224 switch (dev
) { /* switch on device */
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 */
238 else drp_unit
.FUNC
= DRP_RW
; /* no, read/write */
241 case 062: /* DWC, DRA */
242 if (IR
& 02000) dat
= GET_POS (drp_time
) | /* DRA, get position */
243 (drp_err
? 0400000: 0);
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 */
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 */
259 case 064: /* not assigned */
260 return (stop_inst
<< IOT_V_REASON
) | dat
; /* stop if requested */
264 } /* end if parallel */
266 return (stop_inst
<< IOT_V_REASON
) | dat
; /* stop if requested */
269 /* Serial unit service - this code assumes the entire drum is buffered */
271 t_stat
drm_svc (UNIT
*uptr
)
274 uint32
*fbuf
= uptr
->filebuf
;
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
);
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 */
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;
296 drm_ma
= (drm_ma
+ 1) & AMASK
; /* incr mem addr */
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 */
306 t_stat
drm_reset (DEVICE
*dptr
)
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
);
317 /* Parallel unit service - this code assumes the entire drum is buffered */
319 t_stat
drp_svc (UNIT
*uptr
)
322 uint32
*fbuf
= uptr
->filebuf
;
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
);
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
));
342 iosta
= iosta
& ~IOS_DRP
; /* clear busy */
343 if (uptr
->FUNC
) dev_req_int (drm_sbs
); /* req intr */
349 t_stat
drp_reset (DEVICE
*dptr
)
351 if ((drp_dev
.flags
& DEV_DIS
) == 0)
352 drm_dev
.flags
= drm_dev
.flags
| DEV_DIS
;
354 drp_rde
= drp_rdf
= drp_wre
= drp_wrf
= 0;
358 iosta
= iosta
& ~IOS_DRP
;
359 sim_cancel (&drp_unit
);