1
/* sds_drm.c: SDS 940 Project Genie drum simulator
3
Copyright (c) 2002-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.
28
The drum is buffered in memory.
30
Note: the Project Genie documentation and the actual monitor sources disagree
31
on the I/O instruction definitions for the drum. The simulator follows the
32
monitor sources, as follows:
34
DCC OP 00230404B RESET DRUM CHANNEL
35
DSC OP 00230204B START DRUM CHANNEL (NO CHAIN)
36
DRA OP 00230504B READ DRUM TIMING COUNTER INTO 21B
37
DSR OP 04030204B SKIP IF DRUM NOT BUSY
38
DSE OP 04037404B SKIP IF NO DRUM ERROR
46
#define DRM_N_WD 11 /* word addr width */
47
#define DRM_V_WD 0 /* position */
48
#define DRM_M_WD ((1 << DRM_N_WD) - 1) /* word mask */
49
#define DRM_NUMWD (1 << DRM_N_WD) /* words/sector */
50
#define DRM_NUMGP 236 /* gap/sector */
51
#define DRM_PHYWD (DRM_NUMWD + DRM_NUMGP) /* phys wds/sector */
52
#define DRM_N_SC 3 /* sect addr width */
53
#define DRM_V_SC (DRM_N_WD) /* position */
54
#define DRM_M_SC ((1 << DRM_N_SC) - 1) /* sector mask */
55
#define DRM_NUMSC (1 << DRM_N_SC) /* sectors/track */
56
#define DRM_N_TR 7 /* track addr width */
57
#define DRM_V_TR (DRM_N_WD+DRM_N_SC) /* position */
58
#define DRM_M_TR ((1 << DRM_N_TR) - 1) /* track mask */
59
#define DRM_NUMTR 84 /* tracks/drum */
60
#define DRM_N_ADDR (DRM_N_WD+DRM_N_SC+DRM_N_TR) /* drum addr width */
61
#define DRM_SWMASK ((1 << (DRM_N_WD+DRM_N_SC)) - 1)/* sector+word mask */
62
#define DRM_DAMASK ((1 << DRM_N_ADDR) - 1) /* drum addr mask */
63
#define DRM_SIZE (DRM_NUMTR*DRM_NUMSC*DRM_NUMWD) /* words/disk */
64
#define DRM_WCMASK 037777 /* wc mask */
65
#define DRM_GETSC(x) (((x) >> DRM_V_SC) & DRM_M_SC)
69
#define DRM_ADAT (1 << (DRM_N_WD + DRM_N_SC)) /* data flag */
71
#define DRM_SFET 0 /* fetch state */
72
#define DRM_SFCA 1 /* fetch CA */
73
#define DRM_SFDA 2 /* fetch DA */
74
#define DRM_SXFR 3 /* xfer */
76
#define DRM_V_OP 21 /* drum op */
79
#define DRM_GETOP(x) (((x) >> DRM_V_OP) & DRM_M_OP)
80
#define DRM_GETRW(x) (((x) >> DRM_V_RW) & 1)
81
#define DRM_OXF 0 /* xfer */
82
#define DRM_OCX 1 /* cond xfer */
83
#define DRM_OBR 2 /* branch */
84
#define DRM_ORS 3 /* reset error */
85
#define DRM_END 4 /* end prog */
86
#define DRM_EIE 5 /* end int if err */
87
#define DRM_EIU 7 /* end int uncond */
89
#define GET_TWORD(x) ((int32) fmod (sim_gtime() / ((double) (x)), \
90
((double) (DRM_NUMSC * DRM_PHYWD))))
92
extern uint32 M[]; /* memory */
93
extern uint32 alert, int_req;
94
extern int32 stop_invins, stop_invdev, stop_inviop;
95
uint32 drm_da = 0; /* disk address */
96
uint32 drm_ca = 0; /* core address */
97
uint32 drm_wc = 0; /* word count */
98
int32 drm_par = 0; /* cumulative par */
99
int32 drm_err = 0; /* error */
100
int32 drm_rw = 0; /* read/write */
101
int32 drm_sta = 0; /* drum state */
102
int32 drm_ftime = 3; /* time to fetch */
103
int32 drm_xtime = 1; /* time to xfr */
104
int32 drm_stopioe = 1; /* stop on error */
107
t_stat drm (uint32 fnc, uint32 inst, uint32 *dat);
108
t_stat drm_svc (UNIT *uptr);
109
t_stat drm_reset (DEVICE *dptr);
111
/* DRM data structures
113
drm_dev device descriptor
114
drm_unit unit descriptor
115
drm_reg register list
118
DIB drm_dib = { -1, DEV3_GDRM, 0, NULL, &drm };
121
{ UDATA (&drm_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF,
125
{ ORDATA (DA, drm_da, DRM_N_ADDR) },
126
{ ORDATA (CA, drm_ca, 16) },
127
{ ORDATA (WC, drm_wc, 14) },
128
{ ORDATA (PAR, drm_par, 12) },
129
{ FLDATA (RW, drm_rw, 0) },
130
{ FLDATA (ERR, drm_err, 0) },
131
{ ORDATA (STA, drm_sta, 2) },
132
{ DRDATA (FTIME, drm_ftime, 24), REG_NZ + PV_LEFT },
133
{ DRDATA (XTIME, drm_xtime, 24), REG_NZ + PV_LEFT },
134
{ FLDATA (STOP_IOE, drm_stopioe, 0) },
138
"DRM", &drm_unit, drm_reg, NULL,
139
1, 8, DRM_N_ADDR, 1, 8, 24,
140
NULL, NULL, &drm_reset,
142
&drm_dib, DEV_DISABLE | DEV_DIS };
144
/* Drum routine - EOM/SKS 3xx04 */
146
t_stat drm (uint32 fnc, uint32 inst, uint32 *dat)
148
int32 t, op = inst & 07700;
151
case IO_CONN: /* connect */
152
if (op == 00400) return drm_reset (&drm_dev); /* EOM 404 = reset */
153
if (op == 00500) { /* EOM 504 = read DA */
154
if (sim_is_active (&drm_unit)) return SCPE_OK; /* must be idle */
155
t = GET_TWORD (drm_xtime); /* get position */
156
if (t < DRM_NUMGP) M[DRM_AD] = DRM_NUMWD - t; /* in gap? */
157
else M[DRM_AD] = (t - DRM_NUMGP) | DRM_ADAT; } /* in data */
158
else if (op == 00200) { /* EOM 204 = start */
159
if (sim_is_active (&drm_unit)) return SCPE_OK; /* must be idle */
160
drm_sta = DRM_SFET; /* state = fetch */
161
sim_activate (&drm_unit, drm_ftime); } /* activate */
165
case IO_SKS: /* SKS */
166
if (((op == 07400) && !drm_err) || /* 37404: no err */
167
((op == 00200) && !sim_is_active (&drm_unit))) /* 30204: idle */
172
return SCPE_IERR; } /* can't get here */
178
t_stat drm_svc (UNIT *uptr)
182
uint32 *fbuf = uptr->filebuf;
184
if (drm_sta != DRM_SXFR) { /* fetch drum prog? */
185
dpc = M[DRM_PC]; /* get drum PC */
186
dwd = M[dpc & PAMASK]; /* get drum inst */
187
M[DRM_PC] = (dpc + 1) & PAMASK; /* update drum PC */
188
if (drm_sta == DRM_SFCA) { /* fetch core addr? */
189
drm_rw = DRM_GETRW (dwd); /* set op */
190
drm_ca = dwd & PAMASK; /* set core addr */
191
drm_sta = DRM_SFDA; } /* next is disk addr */
192
else if (drm_sta == DRM_SFDA) { /* fetch disk addr? */
193
drm_da = dwd & DRM_DAMASK; /* set disk addr */
194
drm_sta = DRM_SXFR; /* next is xfer */
195
drm_par = 0; /* init parity */
196
rda = (drm_da & DRM_SWMASK) + (DRM_GETSC (drm_da) * DRM_NUMGP);
197
t = rda - GET_TWORD (drm_xtime); /* difference */
198
if (t <= 0) t = t + (DRM_NUMSC * DRM_PHYWD); /* add trk lnt */
199
sim_activate (&drm_unit, t * drm_xtime); } /* activate */
201
switch (DRM_GETOP (dwd)) {
202
case DRM_OCX: /* cond xfr */
203
if (drm_err) { /* error? */
204
int_req = int_req | INT_DRM; /* req int */
205
return SCPE_OK; } /* done */
206
case DRM_OXF: /* transfer */
207
drm_wc = dwd & DRM_WCMASK; /* save wc */
208
drm_sta = DRM_SFCA; /* next state */
210
case DRM_OBR: /* branch */
211
M[DRM_PC] = dwd & PAMASK; /* new drum PC */
213
case DRM_END: /* end */
215
case DRM_EIE: /* end, int if err */
216
if (!drm_err) return SCPE_OK;
217
case DRM_EIU: /* end, int uncond */
218
int_req = int_req | INT_DRM;
219
return SCPE_OK; } /* end switch */
221
sim_activate (uptr, drm_ftime); /* fetch next word */
223
else { /* transfer word */
224
if ((uptr->flags & UNIT_BUF) == 0) { /* not buffered? */
225
drm_err = 1; /* error */
226
CRETIOE (drm_stopioe, SCPE_UNATT); }
227
if (drm_rw) { /* write? */
228
dwd = M[drm_ca]; /* get mem word */
229
fbuf[drm_da] = dwd; /* write to drum */
230
if (drm_da >= uptr->hwmark) uptr->hwmark = drm_da + 1; }
232
dwd = fbuf[drm_da]; /* get drum word */
233
M[drm_ca] = dwd; } /* write to mem */
234
drm_da = drm_da + 1; /* inc drum addr */
235
if (drm_da >= DRM_SIZE) drm_da = 0; /* wrap */
236
drm_ca = (drm_ca + 1) & PAMASK; /* inc core addr */
237
drm_wc = (drm_wc - 1) & DRM_WCMASK; /* dec word cnt */
238
drm_par = drm_par ^ (dwd >> 12); /* parity */
239
drm_par = ((drm_par << 1) | (drm_par >> 11)) & 07777;
240
drm_par = drm_par ^ (dwd & 07777);
241
if (drm_wc) { /* more to do */
242
if (drm_da & DRM_M_WD) sim_activate (uptr, drm_xtime);
243
else sim_activate (uptr, drm_xtime * DRM_NUMGP); }
245
#if defined (DRM_PAR)
246
if ((drm_da & DRM_M_WD) && drm_rw) { /* wr end mid sector? */
247
M[drm_da] = drm_par << 12; /* clobber data */
248
if (drm_da >= uptr->hwmark) uptr->hwmark = drm_da + 1; }
250
drm_sta = DRM_SFET; /* back to fetch */
251
sim_activate (uptr, drm_ftime); /* schedule */
252
} /* end else end xfr */
259
t_stat drm_reset (DEVICE *dptr)
261
drm_da = 0; /* clear state */
268
int_req = int_req & ~INT_DRM; /* clear intr */
269
sim_cancel (&drm_unit); /* deactivate */