~ubuntu-branches/ubuntu/utopic/simh/utopic

« back to all changes in this revision

Viewing changes to pdp11_rk.c

  • Committer: Bazaar Package Importer
  • Author(s): Vince Mulhollon
  • Date: 2004-04-20 20:01:26 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20040420200126-ehsuleda8xcgi51h
Tags: 3.2.0-1
New upstream 3.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* RK11 cartridge disk simulator
2
 
 
3
 
   Copyright (c) 1993-1997,
4
 
   Robert M Supnik, Digital Equipment Corporation
5
 
   Commercial use prohibited
6
 
 
7
 
   29-Jun-96    RMS     Added unit disable support.
8
 
 
9
 
   The RK11 is an eight drive cartridge disk subsystem.  An RK05 drive
10
 
   consists of 203 cylinders, each with 2 surfaces containing 12 sectors
11
 
   of 512 bytes.
12
 
 
13
 
   The most complicated part of the RK11 controller is the concept of
14
 
   interrupt "polling".  While only one read or write can occur at a
15
 
   time, the controller supports multiple seeks.  When a seek completes,
16
 
   if done is set the drive attempts to interrupt.  If an interrupt is
17
 
   already pending, the interrupt is "queued" until it can be processed.
18
 
   When an interrupt occurs, RKDS<15:13> is loaded with the number of the
19
 
   interrupting drive.
20
 
 
21
 
   To implement this structure, and to assure that read/write interrupts
22
 
   take priority over seek interrupts, the controller contains an
23
 
   interrupt queue, rkintq, with a bit for a controller interrupt and
24
 
   then one for each drive.  In addition, the drive number of the last
25
 
   non-seeking drive is recorded in last_drv.
26
 
*/
27
 
 
28
 
#include "pdp11_defs.h"
29
 
 
30
 
/* Constants */
31
 
 
32
 
#define RK_NUMWD        256                             /* words/sector */
33
 
#define RK_NUMSC        12                              /* sectors/surface */
34
 
#define RK_NUMSF        2                               /* surfaces/cylinder */
35
 
#define RK_NUMCY        203                             /* cylinders/drive */
36
 
#define RK_NUMTR        (RK_NUMCY * RK_NUMSF)           /* tracks/drive */
37
 
#define RK_NUMDR        8                               /* drives/controller */
38
 
#define RK_M_NUMDR      07
39
 
#define RK_SIZE (RK_NUMCY * RK_NUMSF * RK_NUMSC * RK_NUMWD)  /* words/drive */
40
 
#define RK_MAXMEM       ((int) (MEMSIZE / sizeof (int16)))      /* words/memory */
41
 
#define RK_CTLI         1                               /* controller int */
42
 
#define RK_SCPI(x)      (2u << (x))                     /* drive int */
43
 
 
44
 
/* Flags in the unit flags word */
45
 
 
46
 
#define UNIT_V_HWLK     (UNIT_V_UF + 0)                 /* hwre write lock */
47
 
#define UNIT_V_SWLK     (UNIT_V_UF + 1)                 /* swre write lock */
48
 
#define UNIT_W_UF       3                               /* user flags width */
49
 
#define UNIT_HWLK       (1u << UNIT_V_HWLK)
50
 
#define UNIT_SWLK       (1u << UNIT_V_SWLK)
51
 
 
52
 
/* Parameters in the unit descriptor */
53
 
 
54
 
#define CYL             u3                              /* current cylinder */
55
 
#define FUNC            u4                              /* function */
56
 
 
57
 
/* RKDS */
58
 
 
59
 
#define RKDS_SC         0000017                         /* sector counter */
60
 
#define RKDS_ON_SC      0000020                         /* on sector */
61
 
#define RKDS_WLK        0000040                         /* write locked */
62
 
#define RKDS_RWS        0000100                         /* rd/wr/seek ready */
63
 
#define RKDS_RDY        0000200                         /* drive ready */
64
 
#define RKDS_SC_OK      0000400                         /* SC valid */
65
 
#define RKDS_INC        0001000                         /* seek incomplete */
66
 
#define RKDS_UNSAFE     0002000                         /* unsafe */
67
 
#define RKDS_RK05       0004000                         /* RK05 */
68
 
#define RKDS_PWR        0010000                         /* power low */
69
 
#define RKDS_ID         0160000                         /* drive ID */
70
 
#define RKDS_V_ID       13
71
 
 
72
 
/* RKER */
73
 
 
74
 
#define RKER_WCE        0000001                         /* write check */
75
 
#define RKER_CSE        0000002                         /* checksum */
76
 
#define RKER_NXS        0000040                         /* nx sector */
77
 
#define RKER_NXC        0000100                         /* nx cylinder */
78
 
#define RKER_NXD        0000200                         /* nx drive */
79
 
#define RKER_TE         0000400                         /* timing error */
80
 
#define RKER_DLT        0001000                         /* data late */
81
 
#define RKER_NXM        0002000                         /* nx memory */
82
 
#define RKER_PGE        0004000                         /* programming error */
83
 
#define RKER_SKE        0010000                         /* seek error */
84
 
#define RKER_WLK        0020000                         /* write lock */
85
 
#define RKER_OVR        0040000                         /* overrun */
86
 
#define RKER_DRE        0100000                         /* drive error */
87
 
#define RKER_IMP        0177743                         /* implemented */
88
 
#define RKER_SOFT       (RKER_WCE+RKER_CSE)             /* soft errors */
89
 
#define RKER_HARD       0177740                         /* hard errors */
90
 
 
91
 
/* RKCS */
92
 
 
93
 
#define RKCS_M_FUNC     0000007                         /* function */
94
 
#define  RKCS_CTLRESET  0
95
 
#define  RKCS_WRITE     1
96
 
#define  RKCS_READ      2
97
 
#define  RKCS_WCHK      3
98
 
#define  RKCS_SEEK      4
99
 
#define  RKCS_RCHK      5
100
 
#define  RKCS_DRVRESET  6
101
 
#define  RKCS_WLK       7
102
 
#define RKCS_V_FUNC     1
103
 
#define RKCS_MEX        0000060                         /* memory extension */
104
 
#define RKCS_V_MEX      4
105
 
#define RKCS_SSE        0000400                         /* stop on soft err */
106
 
#define RKCS_FMT        0002000                         /* format */
107
 
#define RKCS_INH        0004000                         /* inhibit increment */
108
 
#define RKCS_SCP        0020000                         /* search complete */
109
 
#define RKCS_HERR       0040000                         /* hard error */
110
 
#define RKCS_ERR        0100000                         /* error */
111
 
#define RKCS_REAL       0026776                         /* kept here */
112
 
#define RKCS_RW         0006576                         /* read/write */
113
 
#define GET_FUNC(x)     (((x) >> RKCS_V_FUNC) & RKCS_M_FUNC)
114
 
 
115
 
/* RKDA */
116
 
 
117
 
#define RKDA_V_SECT     0                               /* sector */
118
 
#define RKDA_M_SECT     017
119
 
#define RKDA_V_TRACK    4                               /* track */
120
 
#define RKDA_M_TRACK    0777
121
 
#define RKDA_V_CYL      5                               /* cylinder */
122
 
#define RKDA_M_CYL      0377
123
 
#define RKDA_V_DRIVE    13                              /* drive */
124
 
#define RKDA_M_DRIVE    07
125
 
#define RKDA_DRIVE      (RKDA_M_DRIVE << RKDA_V_DRIVE)
126
 
#define GET_SECT(x)     (((x) >> RKDA_V_SECT) & RKDA_M_SECT)
127
 
#define GET_CYL(x)      (((x) >> RKDA_V_CYL) & RKDA_M_CYL)
128
 
#define GET_TRACK(x)    (((x) >> RKDA_V_TRACK) & RKDA_M_TRACK)
129
 
#define GET_DRIVE(x)    (((x) >> RKDA_V_DRIVE) & RKDA_M_DRIVE)
130
 
#define GET_DA(x)       ((GET_TRACK (x) * RK_NUMSC) + GET_SECT (x))
131
 
 
132
 
/* RKBA */
133
 
 
134
 
#define RKBA_IMP        0177776                         /* implemented */
135
 
 
136
 
#define RK_MIN 10
137
 
#define MAX(x,y) (((x) > (y))? (x): (y))
138
 
 
139
 
extern int32 int_req;
140
 
extern unsigned int16 *M;                               /* memory */
141
 
extern UNIT cpu_unit;
142
 
int32 rkcs = 0;                                         /* control/status */
143
 
int32 rkds = 0;                                         /* drive status */
144
 
int32 rkba = 0;                                         /* memory address */
145
 
int32 rkda = 0;                                         /* disk address */
146
 
int32 rker = 0;                                         /* error status */
147
 
int32 rkwc = 0;                                         /* word count */
148
 
int32 rkintq = 0;                                       /* interrupt queue */
149
 
int32 last_drv = 0;                                     /* last r/w drive */
150
 
int32 rk_stopioe = 1;                                   /* stop on error */
151
 
int32 rk_swait = 10;                                    /* seek time */
152
 
int32 rk_rwait = 10;                                    /* rotate time */
153
 
t_stat rk_svc (UNIT *uptr);
154
 
t_stat rk_reset (DEVICE *dptr);
155
 
void rk_go (void);
156
 
void rk_set_done (int32 error);
157
 
void rk_clr_done (void);
158
 
t_stat rk_boot (int32 unitno);
159
 
extern t_stat sim_activate (UNIT *uptr, int32 delay);
160
 
extern t_stat sim_cancel (UNIT *uptr);
161
 
extern int32 sim_is_active (UNIT *uptr);
162
 
extern size_t fxread (void *bptr, size_t size, size_t count, FILE *fptr);
163
 
extern size_t fxwrite (void *bptr, size_t size, size_t count, FILE *fptr);
164
 
 
165
 
/* RK11 data structures
166
 
 
167
 
   rk_dev       RK device descriptor
168
 
   rk_unit      RK unit list
169
 
   rk_reg       RK register list
170
 
   rk_mod       RK modifier list
171
 
*/
172
 
 
173
 
UNIT rk_unit[] = {
174
 
        { UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, RK_SIZE) },
175
 
        { UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, RK_SIZE) },
176
 
        { UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, RK_SIZE) },
177
 
        { UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, RK_SIZE) },
178
 
        { UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, RK_SIZE) },
179
 
        { UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, RK_SIZE) },
180
 
        { UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, RK_SIZE) },
181
 
        { UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, RK_SIZE) } };
182
 
 
183
 
REG rk_reg[] = {
184
 
        { ORDATA (RKCS, rkcs, 16) },
185
 
        { ORDATA (RKDA, rkda, 16) },
186
 
        { ORDATA (RKBA, rkba, 16) },
187
 
        { ORDATA (RKWC, rkwc, 16) },
188
 
        { ORDATA (RKDS, rkds, 16) },
189
 
        { ORDATA (RKER, rker, 16) },
190
 
        { ORDATA (INTQ, rkintq, 9) },
191
 
        { ORDATA (DRVN, last_drv, 3) },
192
 
        { FLDATA (INT, int_req, INT_V_RK) },
193
 
        { FLDATA (ERR, rkcs, CSR_V_ERR) },
194
 
        { FLDATA (DONE, rkcs, CSR_V_DONE) },
195
 
        { FLDATA (IE, rkcs, CSR_V_IE) },
196
 
        { DRDATA (STIME, rk_swait, 24), PV_LEFT },
197
 
        { DRDATA (RTIME, rk_rwait, 24), PV_LEFT },
198
 
        { GRDATA (FLG0, rk_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
199
 
                  REG_HRO },
200
 
        { GRDATA (FLG1, rk_unit[1].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
201
 
                  REG_HRO },
202
 
        { GRDATA (FLG2, rk_unit[2].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
203
 
                  REG_HRO },
204
 
        { GRDATA (FLG3, rk_unit[3].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
205
 
                  REG_HRO },
206
 
        { GRDATA (FLG4, rk_unit[4].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
207
 
                  REG_HRO },
208
 
        { GRDATA (FLG5, rk_unit[5].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
209
 
                  REG_HRO },
210
 
        { GRDATA (FLG6, rk_unit[6].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
211
 
                  REG_HRO },
212
 
        { GRDATA (FLG7, rk_unit[7].flags, 8, UNIT_W_UF, UNIT_V_UF - 1),
213
 
                  REG_HRO },
214
 
        { FLDATA (STOP_IOE, rk_stopioe, 0) },
215
 
        { NULL }  };
216
 
 
217
 
MTAB rk_mod[] = {
218
 
        { (UNIT_HWLK+UNIT_SWLK), 0, "write enabled", "ENABLED", NULL },
219
 
        { (UNIT_HWLK+UNIT_SWLK), UNIT_HWLK, "write locked", "LOCKED", NULL },
220
 
        { (UNIT_HWLK+UNIT_SWLK), UNIT_SWLK, "write locked", NULL, NULL },
221
 
        { (UNIT_HWLK+UNIT_SWLK), (UNIT_HWLK+UNIT_SWLK), "write locked",
222
 
                NULL, NULL }, 
223
 
        { 0 }  };
224
 
 
225
 
DEVICE rk_dev = {
226
 
        "RK", rk_unit, rk_reg, rk_mod,
227
 
        RK_NUMDR, 8, 24, 1, 8, 16,
228
 
        NULL, NULL, &rk_reset,
229
 
        &rk_boot, NULL, NULL };
230
 
 
231
 
/* I/O dispatch routine, I/O addresses 17777400 - 17777416
232
 
 
233
 
   17777400     RKDS    read only, constructed from "id'd drive"
234
 
                        plus current drive status flags
235
 
   17777402     RKER    read only, set as operations progress,
236
 
                        cleared by INIT or CONTROL RESET
237
 
   17777404     RKCS    read/write
238
 
   17777406     RKWC    read/write
239
 
   17777410     RKBA    read/write
240
 
   17777412     RKDA    read/write
241
 
   17777414     RKMR    read/write, unimplemented
242
 
   17777416     RKDB    read only, unimplemented
243
 
*/
244
 
 
245
 
t_stat rk_rd (int32 *data, int32 PA, int32 access)
246
 
{
247
 
UNIT *uptr;
248
 
 
249
 
switch ((PA >> 1) & 07) {                               /* decode PA<3:1> */
250
 
case 0:                                                 /* RKDS: read only */
251
 
        rkds = (rkds & RKDS_ID) | RKDS_RK05 | RKDS_SC_OK |
252
 
                (rand () % RK_NUMSC);                   /* random sector */
253
 
        uptr = rk_dev.units + GET_DRIVE (rkda);         /* selected unit */
254
 
        if (uptr -> flags & UNIT_ATT) rkds = rkds | RKDS_RDY;   /* attached? */
255
 
        if (!sim_is_active (uptr)) rkds = rkds | RKDS_RWS;      /* idle? */
256
 
        if (uptr -> flags & (UNIT_HWLK + UNIT_SWLK)) rkds = rkds | RKDS_WLK;
257
 
        if (GET_SECT (rkda) == (rkds & RKDS_SC)) rkds = rkds | RKDS_ON_SC;
258
 
        *data = rkds;
259
 
        return SCPE_OK;
260
 
case 1:                                                 /* RKER: read only */
261
 
        *data = rker & RKER_IMP;
262
 
        return SCPE_OK;
263
 
case 2:                                                 /* RKCS */
264
 
        rkcs = rkcs & RKCS_REAL;
265
 
        if (rker) rkcs = rkcs | RKCS_ERR;               /* update err flags */
266
 
        if (rker & RKER_HARD) rkcs = rkcs | RKCS_HERR;
267
 
        *data = rkcs;
268
 
        return SCPE_OK;
269
 
case 3:                                                 /* RKWC */
270
 
        *data = rkwc;
271
 
        return SCPE_OK;
272
 
case 4:                                                 /* RKBA */
273
 
        *data = rkba & RKBA_IMP;
274
 
        return SCPE_OK;
275
 
case 5:                                                 /* RKDA */
276
 
        *data = rkda;
277
 
        return SCPE_OK;
278
 
default:
279
 
        *data = 0;
280
 
        return SCPE_OK;  }                              /* end switch */
281
 
}
282
 
 
283
 
t_stat rk_wr (int32 data, int32 PA, int32 access)
284
 
{
285
 
switch ((PA >> 1) & 07) {                               /* decode PA<3:1> */
286
 
case 0:                                                 /* RKDS: read only */
287
 
        return SCPE_OK;
288
 
case 1:                                                 /* RKER: read only */
289
 
        return SCPE_OK;
290
 
case 2:                                                 /* RKCS */
291
 
        rkcs = rkcs & RKCS_REAL;
292
 
        if (access == WRITEB) data = (PA & 1)?
293
 
                (rkcs & 0377) | (data << 8): (rkcs & ~0377) | data;
294
 
        if ((data & CSR_IE) == 0) {                     /* int disable? */
295
 
                rkintq = 0;                             /* clr int queue */
296
 
                int_req = int_req & ~INT_RK;  }         /* clr int request */
297
 
        else if ((rkcs & (CSR_DONE + CSR_IE)) == CSR_DONE) {
298
 
                rkintq = rkintq | RK_CTLI;              /* queue ctrl int */
299
 
                int_req = int_req | INT_RK;  }          /* set int request */
300
 
        rkcs = (rkcs & ~RKCS_RW) | (data & RKCS_RW);
301
 
        if ((rkcs & CSR_DONE) && (data & CSR_GO)) rk_go (); /* new function? */
302
 
        return SCPE_OK;
303
 
case 3:                                                 /* RKWC */
304
 
        if (access == WRITEB) data = (PA & 1)?
305
 
                (rkwc & 0377) | (data << 8): (rkwc & ~0377) | data;
306
 
        rkwc = data;
307
 
        return SCPE_OK;
308
 
case 4:                                                 /* RKBA */
309
 
        if (access == WRITEB) data = (PA & 1)?
310
 
                (rkba & 0377) | (data << 8): (rkba & ~0377) | data;
311
 
        rkba = data & RKBA_IMP;
312
 
        return SCPE_OK;
313
 
case 5:                                                 /* RKDA */
314
 
        if ((rkcs & CSR_DONE) == 0) return SCPE_OK;
315
 
        if (access == WRITEB) data = (PA & 1)?
316
 
                (rkda & 0377) | (data << 8): (rkda & ~0377) | data;
317
 
        rkda = data;
318
 
        return SCPE_OK;
319
 
default:
320
 
        return SCPE_OK;  }                              /* end switch */
321
 
}
322
 
 
323
 
/* Initiate new function */
324
 
 
325
 
void rk_go (void)
326
 
{
327
 
int32 i, sect, cyl, func;
328
 
UNIT *uptr;
329
 
 
330
 
func = GET_FUNC (rkcs);                                 /* get function */
331
 
if (func == RKCS_CTLRESET) {                            /* control reset? */
332
 
        rker = 0;                                       /* clear errors */
333
 
        rkda = 0;
334
 
        rkba = 0;
335
 
        rkcs = CSR_DONE;
336
 
        rkintq = 0;                                     /* clr int queue */
337
 
        int_req = int_req & ~INT_RK;                    /* clr int request */
338
 
        return;  }
339
 
rker = rker & ~RKER_SOFT;                               /* clear soft errors */
340
 
if (rker == 0) rkcs = rkcs & ~RKCS_ERR;                 /* redo summary */
341
 
rkcs = rkcs & ~RKCS_SCP;                                /* clear sch compl*/
342
 
rk_clr_done ();                                         /* clear done */
343
 
last_drv = GET_DRIVE (rkda);                            /* get drive no */
344
 
uptr = rk_dev.units + last_drv;                         /* select unit */
345
 
if (uptr -> flags & UNIT_DIS) {                         /* not present? */
346
 
        rk_set_done (RKER_NXD);
347
 
        return;  }
348
 
if (((uptr -> flags & UNIT_ATT) == 0) || sim_is_active (uptr)) {
349
 
        rk_set_done (RKER_DRE);                         /* not att or busy */
350
 
        return;  }
351
 
if (rkcs & (RKCS_INH + RKCS_FMT)) {                     /* format? */
352
 
        rk_set_done (RKER_PGE);
353
 
        return;  }
354
 
if ((func == RKCS_WRITE) && (uptr -> flags & (UNIT_HWLK + UNIT_SWLK))) {
355
 
        rk_set_done (RKER_WLK);                         /* write and locked? */
356
 
        return;  }
357
 
if (func == RKCS_WLK) {                                 /* write lock? */
358
 
        uptr -> flags = uptr -> flags | UNIT_SWLK;
359
 
        rk_set_done (0);
360
 
        return;  }
361
 
if (func == RKCS_DRVRESET) {                            /* drive reset? */
362
 
        uptr -> flags = uptr -> flags & ~UNIT_SWLK;
363
 
        cyl = sect = 0;
364
 
        func = RKCS_SEEK;  }
365
 
else {  sect = GET_SECT (rkda);
366
 
        cyl = GET_CYL (rkda);  }
367
 
if (sect >= RK_NUMSC) {                                 /* bad sector? */
368
 
        rk_set_done (RKER_NXS);
369
 
        return;  }
370
 
if (cyl >= RK_NUMCY) {                                  /* bad cyl? */
371
 
        rk_set_done (RKER_NXC);
372
 
        return;  }
373
 
i = abs (cyl - uptr -> CYL) * rk_swait;                 /* seek time */
374
 
if (func == RKCS_SEEK) {                                /* seek? */
375
 
        rk_set_done (0);                                /* set done */
376
 
        sim_activate (uptr, MAX (RK_MIN, i));  }        /* schedule */
377
 
else sim_activate (uptr, i + rk_rwait);
378
 
uptr -> FUNC = func;                                    /* save func */
379
 
uptr -> CYL = cyl;                                      /* put on cylinder */
380
 
return;
381
 
}
382
 
 
383
 
/* Service unit timeout
384
 
 
385
 
   If seek in progress, complete seek command
386
 
   Else complete data transfer command
387
 
 
388
 
   The unit control block contains the function and disk address for
389
 
   the current command.
390
 
*/
391
 
 
392
 
static unsigned int16 fill[RK_NUMWD] = { 0 };
393
 
t_stat rk_svc (UNIT *uptr)
394
 
{
395
 
int32 comp, drv, err, awc, twc, wc;
396
 
int32 pa, da, fillc, track, sect;
397
 
 
398
 
drv = uptr - rk_dev.units;                              /* get drv number */
399
 
if (uptr -> FUNC == RKCS_SEEK) {                        /* seek */
400
 
        rkcs = rkcs | RKCS_SCP;                         /* set seek done */
401
 
        if (rkcs & CSR_IE) {                            /* ints enabled? */
402
 
                rkintq = rkintq | RK_SCPI (drv);        /* queue request */
403
 
                if (rkcs & CSR_DONE) int_req = int_req | INT_RK;  }
404
 
        else {  rkintq = 0;                             /* clear queue */
405
 
                int_req = int_req & ~INT_RK;  }         /* clear interrupt */
406
 
        return SCPE_OK;  }
407
 
 
408
 
if ((uptr -> flags & UNIT_ATT) == 0) {                  /* attached? */
409
 
        rk_set_done (RKER_DRE);
410
 
        return IORETURN (rk_stopioe, SCPE_UNATT);  }
411
 
pa = (((rkcs & RKCS_MEX) << (16 - RKCS_V_MEX)) | rkba) >> 1;
412
 
da = GET_DA (rkda) * RK_NUMWD;                          /* get disk addr */
413
 
twc = 0200000 - rkwc;                                   /* get true wc */
414
 
if ((pa + twc) > RK_MAXMEM) {                           /* mem overrun? */
415
 
        rker = rker | RKER_NXM;
416
 
        wc = (RK_MAXMEM - pa);  }
417
 
else wc = twc;
418
 
if (wc < 0) {                                           /* abort transfer? */
419
 
        rk_set_done (0);
420
 
        return SCPE_OK;  }
421
 
if ((da + twc) > RK_SIZE) {                             /* disk overrun? */
422
 
        rker = rker | RKER_OVR;
423
 
        if (wc > (RK_SIZE - da)) wc = RK_SIZE - da;  }
424
 
 
425
 
err = fseek (uptr -> fileref, da * sizeof (int16), SEEK_SET);
426
 
 
427
 
if ((uptr -> FUNC == RKCS_READ) && (err == 0)) {        /* read? */
428
 
        awc = fxread (&M[pa], sizeof (int16), wc, uptr -> fileref);
429
 
        for ( ; awc < wc; awc++) M[pa + awc] = 0;
430
 
        err = ferror (uptr -> fileref);  }
431
 
 
432
 
if ((uptr -> FUNC == RKCS_WRITE) && (err == 0)) {       /* write? */
433
 
        fxwrite (&M[pa], sizeof (int16), wc, uptr -> fileref);
434
 
        err = ferror (uptr -> fileref);
435
 
        if ((err == 0) && (fillc = (wc & (RK_NUMWD - 1)))) {
436
 
                fxwrite (fill, sizeof (int16), fillc, uptr -> fileref);
437
 
                err = ferror (uptr -> fileref);  }  }
438
 
 
439
 
if ((uptr -> FUNC == RKCS_WCHK) && (err == 0)) {        /* write check? */
440
 
        twc = wc;                                       /* xfer length */
441
 
        for (wc = 0; (err == 0) && (wc < twc); wc++)  {
442
 
                awc = fxread (&comp, sizeof (int16), 1, uptr -> fileref);
443
 
                if (awc == 0) comp = 0;
444
 
                if (comp != M[pa + wc])  {
445
 
                        rker = rker | RKER_WCE;
446
 
                        if (rkcs & RKCS_SSE) break;  }  }
447
 
        err = ferror (uptr -> fileref);  }
448
 
 
449
 
rkwc = (rkwc + wc) & 0177777;                           /* final word count */
450
 
pa = (pa + wc) << 1;                                    /* final byte addr */
451
 
rkba = pa & RKBA_IMP;                                   /* lower 16b */
452
 
rkcs = (rkcs & ~RKCS_MEX) | ((pa >> (16 - RKCS_V_MEX)) & RKCS_MEX);
453
 
da = da + wc + (RK_NUMWD - 1);
454
 
track = (da / RK_NUMWD) / RK_NUMSC;
455
 
sect = (da / RK_NUMWD) % RK_NUMSC;
456
 
rkda = (rkda & RKDA_DRIVE) | (track << RKDA_V_TRACK) | (sect << RKDA_V_SECT);
457
 
rk_set_done (0);
458
 
 
459
 
if (err != 0) {                                         /* error? */
460
 
        perror ("RK I/O error");
461
 
        clearerr (uptr -> fileref);
462
 
        return SCPE_IOERR;  }
463
 
return SCPE_OK;
464
 
}
465
 
 
466
 
/* Interrupt state change routines
467
 
 
468
 
   rk_set_done          set done and possibly errors
469
 
   rk_clr_done          clear done
470
 
   rk_inta              acknowledge intererupt
471
 
*/
472
 
 
473
 
void rk_set_done (int32 error)
474
 
{
475
 
        rkcs = rkcs | CSR_DONE;                         /* set done */
476
 
        if (error != 0) {
477
 
                rker = rker | error;                    /* update error */
478
 
                if (rker) rkcs = rkcs | RKCS_ERR;       /* update err flags */
479
 
                if (rker & RKER_HARD) rkcs = rkcs | RKCS_HERR;  }
480
 
        if (rkcs & CSR_IE) {                            /* int enable? */
481
 
                rkintq = rkintq | RK_CTLI;              /* set ctrl int */
482
 
                int_req = int_req | INT_RK;  }          /* request int */
483
 
        else {  rkintq = 0;                             /* clear queue */
484
 
                int_req = int_req & ~INT_RK;  }
485
 
        return;
486
 
}
487
 
 
488
 
void rk_clr_done (void)
489
 
{
490
 
        rkcs = rkcs & ~CSR_DONE;                        /* clear done */
491
 
        rkintq = rkintq & ~RK_CTLI;                     /* clear ctl int */
492
 
        int_req = int_req & ~INT_RK;                    /* clear int req */
493
 
        return;
494
 
}
495
 
 
496
 
int32 rk_inta (void)
497
 
{
498
 
int32 i;
499
 
 
500
 
for (i = 0; i <= RK_NUMDR; i++) {                       /* loop thru intq */
501
 
        if (rkintq & (1u << i)) {                       /* bit i set? */
502
 
                rkintq = rkintq & ~(1u << i);           /* clear bit i */
503
 
                if (rkintq) int_req = int_req | INT_RK; /* queue next */
504
 
                rkds = (rkds & ~RKDS_ID) |              /* id drive */
505
 
                        (((i == 0)? last_drv: i - 1) << RKDS_V_ID);
506
 
                return VEC_RK;  }  }                    /* return vector */
507
 
rkintq = 0;                                             /* clear queue */
508
 
return 0;                                               /* passive release */
509
 
}
510
 
 
511
 
/* Device reset */
512
 
 
513
 
t_stat rk_reset (DEVICE *dptr)
514
 
{
515
 
int32 i;
516
 
UNIT *uptr;
517
 
 
518
 
rkcs = CSR_DONE;
519
 
rkda = rkba = rker = rkds = 0;
520
 
rkintq = last_drv = 0;
521
 
int_req = int_req & ~INT_RK;
522
 
for (i = 0; i < RK_NUMDR; i++) {
523
 
        uptr = rk_dev.units + i;
524
 
        sim_cancel (uptr);
525
 
        uptr -> CYL = uptr -> FUNC = 0;
526
 
        uptr -> flags = uptr -> flags & ~UNIT_SWLK;  }
527
 
return SCPE_OK;
528
 
}
529
 
 
530
 
/* Device bootstrap */
531
 
 
532
 
#define BOOT_START 02000                /* start */
533
 
#define BOOT_UNIT 02006                 /* where to store unit number */
534
 
#define BOOT_LEN (sizeof (boot_rom) / sizeof (int))
535
 
 
536
 
static const int32 boot_rom[] = {
537
 
        0012706, 0002000,               /* MOV #2000, SP */
538
 
        0012700, 0000000,               /* MOV #unit, R0        ; unit number */
539
 
        0010003,                        /* MOV R0, R3 */
540
 
        0000303,                        /* SWAB R3 */
541
 
        0006303,                        /* ASL R3 */
542
 
        0006303,                        /* ASL R3 */
543
 
        0006303,                        /* ASL R3 */
544
 
        0006303,                        /* ASL R3 */
545
 
        0006303,                        /* ASL R3 */
546
 
        0012701, 0177412,               /* MOV #RKDA, R1        ; csr */
547
 
        0010311,                        /* MOV R3, (R1)         ; load da */
548
 
        0005041,                        /* CLR -(R1)            ; clear ba */
549
 
        0012741, 0177000,               /* MOV #-256.*2, -(R1)  ; load wc */
550
 
        0012741, 0000005,               /* MOV #READ+GO, -(R1)  ; read & go */
551
 
        0005002,                        /* CLR R2 */
552
 
        0005003,                        /* CLR R3 */
553
 
        0005004,                        /* CLR R4 */
554
 
        0012705, 0062153,               /* MOV #"DK, R5 */
555
 
        0105711,                        /* TSTB (R1) */
556
 
        0100376,                        /* BPL .-2 */
557
 
        0105011,                        /* CLRB (R1) */
558
 
        0005007                         /* CLR PC */
559
 
};
560
 
 
561
 
t_stat rk_boot (int32 unitno)
562
 
{
563
 
int32 i;
564
 
extern int32 saved_PC;
565
 
 
566
 
for (i = 0; i < BOOT_LEN; i++) M[(BOOT_START >> 1) + i] = boot_rom[i];
567
 
M[BOOT_UNIT >> 1] = unitno & RK_M_NUMDR;
568
 
saved_PC = BOOT_START;
569
 
return SCPE_OK;
570
 
}