1
/* pdp1_drm.c: PDP-1 drum simulator
3
Copyright (c) 1993-2004, 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
23
be 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
08-Dec-03 RMS Added parallel drum support
30
Fixed bug in DBL/DCN decoding
31
26-Oct-03 RMS Cleaned up buffer copy code
32
23-Jul-03 RMS Fixed incorrect logical, missing activate
33
05-Dec-02 RMS Cloned from pdp18b_drm.c
36
#include "pdp1_defs.h"
39
/* Serial drum constants */
41
#define DRM_NUMWDS 256 /* words/sector */
42
#define DRM_NUMSC 2 /* sectors/track */
43
#define DRM_NUMTR 256 /* tracks/drum */
44
#define DRM_NUMWDT (DRM_NUMWDS * DRM_NUMSC) /* words/track */
45
#define DRM_SIZE (DRM_NUMTR * DRM_NUMWDT) /* words/drum */
46
#define DRM_SMASK ((DRM_NUMTR * DRM_NUMSC) - 1) /* sector mask */
48
/* Parallel drum constants */
50
#define DRP_NUMWDT 4096 /* words/track */
51
#define DRP_NUMTK 32 /* tracks/drum */
52
#define DRP_SIZE (DRP_NUMWDT * DRP_NUMTK) /* words/drum */
53
#define DRP_V_RWE 17 /* read/write enable */
54
#define DRP_V_FLD 12 /* drum field */
56
#define DRP_TAMASK 07777 /* track address */
57
#define DRP_WCMASK 07777 /* word count */
58
#define DRP_MAINCM 07777 /* mem addr incr */
59
#define DRP_GETRWE(x) (((x) >> DRP_V_RWE) & 1)
60
#define DRP_GETRWF(x) (((x) >> DRP_V_FLD) & DRP_M_FLD)
62
/* Parameters in the unit descriptor */
64
#define FUNC u4 /* function */
65
#define DRM_READ 000 /* read */
66
#define DRM_WRITE 010 /* write */
67
#define DRP_RW 000 /* read/write */
68
#define DRP_BRK 001 /* break on address */
70
#define GET_POS(x) ((int) fmod (sim_gtime() / ((double) (x)), \
71
((double) DRM_NUMWDT)))
74
extern int32 iosta, sbs;
75
extern int32 stop_inst;
78
/* Serial drum variables */
80
uint32 drm_da = 0; /* track address */
81
uint32 drm_ma = 0; /* memory address */
82
uint32 drm_err = 0; /* error flag */
83
uint32 drm_wlk = 0; /* write lock */
84
int32 drm_time = 4; /* inter-word time */
85
int32 drm_stopioe = 1; /* stop on error */
87
/* Parallel drum variables */
89
uint32 drp_rde = 0; /* read enable */
90
uint32 drp_wre = 0; /* write enable */
91
uint32 drp_rdf = 0; /* read field */
92
uint32 drp_wrf = 0; /* write field */
93
uint32 drp_ta = 0; /* track address */
94
uint32 drp_wc = 0; /* word count */
95
uint32 drp_ma = 0; /* memory address */
96
uint32 drp_err = 0; /* error */
97
int32 drp_time = 2; /* inter-word time */
98
int32 drp_stopioe = 1; /* stop on error */
100
/* Forward declarations */
102
t_stat drm_svc (UNIT *uptr);
103
t_stat drm_reset (DEVICE *dptr);
104
t_stat drp_svc (UNIT *uptr);
105
t_stat drp_reset (DEVICE *dptr);
107
/* DRM data structures
109
drm_dev DRM device descriptor
110
drm_unit DRM unit descriptor
111
drm_reg DRM register list
115
{ UDATA (&drm_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF,
119
{ ORDATA (DA, drm_da, 9) },
120
{ ORDATA (MA, drm_ma, 16) },
121
{ FLDATA (DONE, iosta, IOS_V_DRM) },
122
{ FLDATA (ERR, drm_err, 0) },
123
{ ORDATA (WLK, drm_wlk, 32) },
124
{ DRDATA (TIME, drm_time, 24), REG_NZ + PV_LEFT },
125
{ FLDATA (STOP_IOE, drm_stopioe, 0) },
129
"DRM", &drm_unit, drm_reg, NULL,
131
NULL, NULL, &drm_reset,
135
/* DRP data structures
137
drp_dev DRP device descriptor
138
drp_unit DRP unit descriptor
139
drp_reg DRP register list
143
{ UDATA (&drp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF,
147
{ ORDATA (TA, drp_ta, 12) },
148
{ ORDATA (RDF, drp_rdf, 5) },
149
{ FLDATA (RDE, drp_rde, 0) },
150
{ FLDATA (WRF, drp_wrf, 5) },
151
{ FLDATA (WRE, drp_wre, 0) },
152
{ ORDATA (MA, drp_ma, 16) },
153
{ ORDATA (WC, drp_wc, 12) },
154
{ FLDATA (BUSY, iosta, IOS_V_DRP) },
155
{ FLDATA (ERR, drp_err, 0) },
156
{ DRDATA (TIME, drp_time, 24), REG_NZ + PV_LEFT },
157
{ FLDATA (STOP_IOE, drp_stopioe, 0) },
161
"DRP", &drp_unit, drp_reg, NULL,
163
NULL, NULL, &drp_reset,
165
NULL, DEV_DISABLE | DEV_DIS };
169
int32 drm (int32 IR, int32 dev, int32 dat)
172
int32 pulse = (IR >> 6) & 037;
174
if ((drm_dev.flags & DEV_DIS) == 0) { /* serial enabled? */
175
if ((pulse != 001) && (pulse != 011)) /* invalid pulse? */
176
return (stop_inst << IOT_V_REASON) | dat; /* stop if requested */
177
switch (dev) { /* switch on device */
178
case 061: /* DWR, DRD */
179
drm_ma = dat & AMASK; /* load mem addr */
180
drm_unit.FUNC = pulse & DRM_WRITE; /* save function */
182
case 062: /* DBL, DCN */
183
if ((pulse & 010) == 0) /* DBL? */
184
drm_da = dat & DRM_SMASK; /* load sector # */
185
iosta = iosta & ~IOS_DRM; /* clear flags */
187
t = ((drm_da % DRM_NUMSC) * DRM_NUMWDS) - GET_POS (drm_time);
188
if (t <= 0) t = t + DRM_NUMWDT; /* wrap around? */
189
sim_activate (&drm_unit, t); /* start operation */
192
if (pulse == 011) return (stop_inst << IOT_V_REASON) | dat;
193
if (iosta & IOS_DRM) return (dat | IOT_SKP); /* skip if done */
195
case 064: /* DSE, DSP */
196
if ((drm_err == 0) || (pulse & 010)) /* no error, par test? */
197
return (dat | IOT_SKP);
199
return dat; } /* end if serial */
201
if ((drp_dev.flags & DEV_DIS) == 0) { /* parallel enabled? */
202
switch (dev) { /* switch on device */
203
case 061: /* DIA, DBA */
204
drp_err = 0; /* clear error */
205
iosta = iosta & ~IOS_DRP; /* not busy */
206
drp_rde = DRP_GETRWE (dat); /* set read enable */
207
drp_rdf = DRP_GETRWF (dat); /* set read field */
208
drp_ta = dat & DRP_TAMASK; /* set track addr */
209
if (IR & 02000) { /* DBA? */
210
t = drp_ta - GET_POS (drp_time); /* delta words */
211
if (t <= 0) t = t + DRP_NUMWDT; /* wrap around? */
212
sim_activate (&drp_unit, t); /* start operation */
213
drp_unit.FUNC = DRP_BRK; } /* mark as break */
214
else drp_unit.FUNC = DRP_RW; /* no, read/write */
216
case 062: /* DWC, DRA */
217
if (IR & 02000) dat = GET_POS (drp_time) | /* DRA, get position */
218
(drp_err? 0400000: 0);
220
drp_wre = DRP_GETRWE (dat); /* set write enable */
221
drp_wrf = DRP_GETRWF (dat); /* set write field */
222
drp_wc = dat & DRP_WCMASK; } /* set word count */
225
drp_ma = dat & AMASK; /* set mem address */
226
t = drp_ta - GET_POS (drp_time); /* delta words */
227
if (t <= 0) t = t + DRP_NUMWDT; /* wrap around? */
228
sim_activate (&drp_unit, t); /* start operation */
229
iosta = iosta | IOS_DRP; /* set busy */
231
case 064: /* not assigned */
232
return (stop_inst << IOT_V_REASON) | dat; /* stop if requested */
234
return dat; } /* end if parallel */
236
return (stop_inst << IOT_V_REASON) | dat; /* stop if requested */
239
/* Serial unit service - this code assumes the entire drum is buffered */
241
t_stat drm_svc (UNIT *uptr)
244
uint32 *fbuf = uptr->filebuf;
246
if ((uptr->flags & UNIT_BUF) == 0) { /* not buf? abort */
247
drm_err = 1; /* set error */
248
iosta = iosta | IOS_DRM; /* set done */
249
sbs = sbs | SB_RQ; /* req intr */
250
return IORETURN (drm_stopioe, SCPE_UNATT); }
252
da = drm_da * DRM_NUMWDS; /* compute dev addr */
253
for (i = 0; i < DRM_NUMWDS; i++, da++) { /* do transfer */
254
if (uptr->FUNC == DRM_READ) { /* read? */
255
if (MEM_ADDR_OK (drm_ma)) /* if !nxm */
256
M[drm_ma] = fbuf[da]; } /* read word */
258
if ((drm_wlk >> (drm_da >> 4)) & 1) drm_err = 1;
259
else { /* not locked */
260
fbuf[da] = M[drm_ma]; /* write word */
261
if (da >= uptr->hwmark) uptr->hwmark = da + 1; } }
262
drm_ma = (drm_ma + 1) & AMASK; } /* incr mem addr */
263
drm_da = (drm_da + 1) & DRM_SMASK; /* incr dev addr */
264
iosta = iosta | IOS_DRM; /* set done */
265
sbs = sbs | SB_RQ; /* req intr */
271
t_stat drm_reset (DEVICE *dptr)
273
if ((drm_dev.flags & DEV_DIS) == 0)
274
drp_dev.flags = drp_dev.flags | DEV_DIS;
275
drm_da = drm_ma = drm_err = 0;
276
iosta = iosta & ~IOS_DRM;
277
sim_cancel (&drm_unit);
282
/* Parallel unit service - this code assumes the entire drum is buffered */
284
t_stat drp_svc (UNIT *uptr)
287
uint32 *fbuf = uptr->filebuf;
289
if ((uptr->flags & UNIT_BUF) == 0) { /* not buf? abort */
290
drp_err = 1; /* set error */
291
iosta = iosta & ~IOS_DRP; /* clear busy */
292
if (uptr->FUNC) sbs = sbs | SB_RQ; /* req intr */
293
return IORETURN (drp_stopioe, SCPE_UNATT); }
295
if (uptr->FUNC == DRP_RW) { /* read/write? */
296
lim = drp_wc? drp_wc: DRP_TAMASK + 1; /* eff word count */
297
for (i = 0; i < lim; i++) { /* do transfer */
298
if (drp_wre) /* write enabled? */
299
fbuf[(drp_wrf << DRP_V_FLD) | drp_ta] = M[drp_ma];
300
if (drp_rde && MEM_ADDR_OK (drp_ma)) /* read enabled? */
301
M[drp_ma] = fbuf[(drp_rdf << DRP_V_FLD) | drp_ta];
302
drp_ta = (drp_ta + 1) & DRP_TAMASK; /* incr track addr */
303
drp_ma = ((drp_ma & ~DRP_MAINCM) | ((drp_ma + 1) & DRP_MAINCM));
306
iosta = iosta & ~IOS_DRP; /* clear busy */
307
if (uptr->FUNC) sbs = sbs | SB_RQ; /* req intr */
313
t_stat drp_reset (DEVICE *dptr)
315
if ((drp_dev.flags & DEV_DIS) == 0)
316
drm_dev.flags = drm_dev.flags | DEV_DIS;
318
drp_rde = drp_rdf = drp_wre = drp_wrf = 0;
322
iosta = iosta & ~IOS_DRP;
323
sim_cancel (&drp_unit);