1
/* sds_rad.c: SDS 940 fixed head disk simulator
3
Copyright (c) 2001-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 fixed head disk is a head-per-track disk, with up to four disks. Each
29
disk is divided into two logical units. Reads and writes cannot cross logical
30
unit boundaries. The fixed head disk transfers 12b characters, rather than 6b
31
characters. To minimize overhead, the disk is buffered in memory.
39
#define RAD_NUMWD 64 /* words/sector */
40
#define RAD_NUMSC 64 /* sectors/track */
41
#define RAD_NUMTR 64 /* tracks/log unit */
42
#define RAD_NUMLU 8 /* log units/ctrl */
43
#define RAD_SCSIZE (RAD_NUMLU*RAD_NUMTR*RAD_NUMSC) /* sectors/disk */
44
#define RAD_AMASK (RAD_SCSIZE - 1) /* sec addr mask */
45
#define RAD_SIZE (RAD_SCSIZE * RAD_NUMWD) /* words/disk */
46
#define RAD_GETLUN(x) ((x) / (RAD_NUMTR * RAD_NUMSC))
47
#define RAD_SCMASK (RAD_NUMSC - 1) /* sector mask */
48
#define RAD_TRSCMASK ((RAD_NUMSC * RAD_NUMTR) - 1) /* track/sec mask */
50
#define GET_SECTOR(x) ((int) fmod (sim_gtime() / ((double) (x)), \
51
((double) RAD_NUMSC)))
53
extern uint32 xfr_req;
55
extern int32 stop_invins, stop_invdev, stop_inviop;
56
int32 rad_err = 0; /* error */
57
int32 rad_nobi = 0; /* !incr x track */
58
int32 rad_da = 0; /* disk address */
59
int32 rad_sba = 0; /* sec byte addr */
60
int32 rad_wrp = 0; /* write prot */
61
int32 rad_time = 2; /* time per 12b */
62
int32 rad_stopioe = 1; /* stop on error */
63
DSPT rad_tplt[] = { /* template */
64
{ 1, 0 }, { 1, DEV_OUT }, { 0, 0 } };
67
t_stat rad_svc (UNIT *uptr);
68
t_stat rad_reset (DEVICE *dptr);
69
t_stat rad_fill (int32 sba);
70
void rad_end_op (int32 fl);
71
int32 rad_adjda (int32 sba, int32 inc);
72
t_stat rad (uint32 fnc, uint32 inst, uint32 *dat);
74
/* RAD data structures
76
rad_dev device descriptor
77
rad_unit unit descriptor
81
DIB rad_dib = { CHAN_E, DEV_RAD, XFR_RAD, rad_tplt, &rad };
84
{ UDATA (&rad_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF,
88
{ ORDATA (DA, rad_da, 15) },
89
{ GRDATA (SA, rad_sba, 8, 6, 1) },
90
{ FLDATA (BP, rad_sba, 0) },
91
{ FLDATA (XFR, xfr_req, XFR_V_RAD) },
92
{ FLDATA (NOBD, rad_nobi, 0) },
93
{ FLDATA (ERR, rad_err, 0) },
94
{ ORDATA (PROT, rad_wrp, 8) },
95
{ DRDATA (TIME, rad_time, 24), REG_NZ + PV_LEFT },
96
{ FLDATA (STOP_IOE, rad_stopioe, 0) },
100
{ MTAB_XTD|MTAB_VDV, 0, "CHANNEL", "CHANNEL",
101
&set_chan, &show_chan, NULL },
105
"RAD", &rad_unit, rad_reg, rad_mod,
107
NULL, NULL, &rad_reset,
109
&rad_dib, DEV_DISABLE };
111
/* Fixed head disk routine
113
conn - inst = EOM0, dat = NULL
114
eom1 - inst = EOM1, dat = NULL
115
sks - inst = SKS, dat = ptr to result
116
disc - inst = device number, dat = NULL
117
wreor - inst = device number, dat = NULL
118
read - inst = device number, dat = ptr to data
119
write - inst = device number, dat = ptr to result
122
t_stat rad (uint32 fnc, uint32 inst, uint32 *dat)
124
int32 t, lun, new_ch;
126
uint32 *fbuf = rad_unit.filebuf;
128
switch (fnc) { /* case function */
129
case IO_CONN: /* connect */
130
new_ch = I_GETEOCH (inst); /* get new chan */
131
if (new_ch != rad_dib.chan) return SCPE_IERR; /* wrong chan? */
132
if (CHC_GETCPW (inst) > 1) return STOP_INVIOP; /* 1-2 char/word? */
133
if (sim_is_active (&rad_unit) || (alert == POT_RADA)) /* protocol viol? */
135
rad_err = 0; /* clr error */
136
rad_sba = 0; /* clr sec bptr */
137
chan_set_flag (rad_dib.chan, CHF_12B); /* 12B mode */
138
t = (rad_da & RAD_SCMASK) - GET_SECTOR (rad_time * RAD_NUMWD);
139
if (t <= 0) t = t + RAD_NUMSC; /* seek */
140
sim_activate (&rad_unit, t * rad_time * (RAD_NUMWD / 2));
141
xfr_req = xfr_req & ~XFR_RAD; /* clr xfr flg */
144
case IO_EOM1: /* EOM mode 1 */
145
new_ch = I_GETEOCH (inst); /* get new chan */
146
if (new_ch != rad_dib.chan) return SCPE_IERR; /* wrong chan? */
147
if ((inst & 00600) == 00200) alert = POT_RADS; /* alert for sec */
148
else if ((inst & 06600) == 0) { /* alert for addr */
149
if (sim_is_active (&rad_unit)) rad_err = 1; /* busy? */
151
rad_nobi = (inst & 01000)? 1: 0; /* save inc type */
152
alert = POT_RADA; } } /* set alert */
155
case IO_DISC: /* disconnect */
156
rad_end_op (0); /* normal term */
157
if (inst & DEV_OUT) return rad_fill (rad_sba); /* fill write */
160
case IO_WREOR: /* write eor */
161
rad_end_op (CHF_EOR); /* eor term */
162
return rad_fill (rad_sba); /* fill write */
164
case IO_SKS: /* SKS */
165
new_ch = I_GETSKCH (inst); /* sks chan */
166
if (new_ch != rad_dib.chan) return SCPE_IERR; /* wrong chan? */
167
t = I_GETSKCND (inst); /* sks cond */
168
lun = RAD_GETLUN (rad_da);
169
if (((t == 000) && !sim_is_active (&rad_unit)) || /* 10026: ready */
170
((t == 004) && !rad_err) || /* 11026: !err */
171
((t == 014) && !(rad_wrp & (1 << lun)))) /* 13026: !wrprot */
175
case IO_READ: /* read */
176
p = (rad_da * RAD_NUMWD) + (rad_sba >> 1); /* buf wd addr */
177
xfr_req = xfr_req & ~XFR_RAD; /* clr xfr req */
178
if ((rad_unit.flags & UNIT_BUF) == 0) { /* not buffered? */
179
rad_end_op (CHF_ERR | CHF_EOR); /* set rad err */
180
CRETIOE (rad_stopioe, SCPE_UNATT); }
181
if (p >= rad_unit.capac) { /* end of disk? */
182
rad_end_op (CHF_ERR | CHF_EOR); /* set rad err */
184
if (rad_sba & 1) *dat = fbuf[p] & 07777; /* odd byte? */
185
else *dat = (fbuf[p] >> 12) & 07777; /* even */
186
rad_sba = rad_adjda (rad_sba, 1); /* next byte */
190
p = (rad_da * RAD_NUMWD) + (rad_sba >> 1);
191
xfr_req = xfr_req & ~XFR_RAD; /* clr xfr req */
192
if ((rad_unit.flags & UNIT_BUF) == 0) { /* not buffered? */
193
rad_end_op (CHF_ERR | CHF_EOR); /* set rad err */
194
CRETIOE (rad_stopioe, SCPE_UNATT); }
195
if ((p >= rad_unit.capac) || /* end of disk? */
196
(rad_wrp & (1 << RAD_GETLUN (rad_da)))) { /* write prot? */
197
rad_end_op (CHF_ERR | CHF_EOR); /* set rad err */
199
if (rad_sba & 1) fbuf[p] = fbuf[p] | (*dat & 07777); /* odd byte? */
200
else fbuf[p] = (*dat & 07777) << 12; /* even */
201
if (p >= rad_unit.hwmark) rad_unit.hwmark = p + 1; /* mark hiwater */
202
rad_sba = rad_adjda (rad_sba, 1); /* next byte */
212
t_stat pin_rads (uint32 num, uint32 *dat)
214
*dat = GET_SECTOR (rad_time * RAD_NUMWD); /* ret curr sec */
220
t_stat pot_rada (uint32 num, uint32 *dat)
222
rad_da = (*dat) & RAD_AMASK; /* save dsk addr */
226
/* Unit service and read/write */
228
t_stat rad_svc (UNIT *uptr)
230
xfr_req = xfr_req | XFR_RAD; /* set xfr req */
231
sim_activate (&rad_unit, rad_time); /* activate */
235
/* Fill incomplete sector */
237
t_stat rad_fill (int32 sba)
239
uint32 p = rad_da * RAD_NUMWD;
240
uint32 *fbuf = rad_unit.filebuf;
241
int32 wa = (sba + 1) >> 1; /* whole words */
243
if (sba && (p < rad_unit.capac)) { /* fill needed? */
244
for ( ; wa < RAD_NUMWD; wa++) fbuf[p + wa] = 0;
245
if ((p + wa) >= rad_unit.hwmark) rad_unit.hwmark = p + wa + 1;
246
rad_adjda (sba, RAD_NUMWD - 1); } /* inc da */
250
/* Adjust disk address */
252
int32 rad_adjda (int32 sba, int32 inc)
255
if (rad_sba >= (RAD_NUMWD * 2)) { /* next sector? */
256
if (rad_nobi) rad_da = (rad_da & ~RAD_SCMASK) + /* within band? */
257
((rad_da + 1) & RAD_SCMASK);
258
else rad_da = (rad_da & ~RAD_TRSCMASK) + /* cross band */
259
((rad_da + 1) & RAD_TRSCMASK);
260
sba = 0; } /* start new sec */
264
/* Terminate disk operation */
266
void rad_end_op (int32 fl)
268
if (fl) chan_set_flag (rad_dib.chan, fl); /* set flags */
269
xfr_req = xfr_req & ~XFR_RAD; /* clear xfr */
270
sim_cancel (&rad_unit); /* stop */
271
if (fl & CHF_ERR) { /* error? */
272
chan_disc (rad_dib.chan); /* disconnect */
273
rad_err = 1; } /* set rad err */
279
t_stat rad_reset (DEVICE *dptr)
281
chan_disc (rad_dib.chan); /* disconnect */
282
rad_nobi = 0; /* clear state */
285
xfr_req = xfr_req & ~XFR_RAD; /* clr xfr req */
286
sim_cancel (&rad_unit); /* deactivate */