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

« back to all changes in this revision

Viewing changes to PDP11/pdp11_rl.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
/* pdp11_rl.c: RL11 (RLV12) cartridge disk simulator
 
2
 
 
3
   Copyright (c) 1993-2004, Robert M Supnik
 
4
 
 
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:
 
11
 
 
12
   The above copyright notice and this permission notice shall be included in
 
13
   all copies or substantial portions of the Software.
 
14
 
 
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.
 
21
 
 
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.
 
25
 
 
26
   rl           RL11(RLV12)/RL01/RL02 cartridge disk
 
27
 
 
28
   04-Jan-04    RMS     Changed sim_fsize calling sequence
 
29
   19-May-03    RMS     Revised for new conditional compilation scheme
 
30
   25-Apr-03    RMS     Revised for extended file support
 
31
   29-Sep-02    RMS     Added variable address support to bootstrap
 
32
                        Added vector change/display support
 
33
                        Revised mapping nomenclature
 
34
                        New data structures
 
35
   26-Jan-02    RMS     Revised bootstrap to conform to M9312
 
36
   06-Jan-02    RMS     Revised enable/disable support
 
37
   30-Nov-01    RMS     Added read only, extended SET/SHOW support
 
38
   26-Nov-01    RMS     Fixed per-drive error handling
 
39
   24-Nov-01    RMS     Converted FLG, CAPAC to arrays
 
40
   19-Nov-01    RMS     Fixed signed/unsigned mismatch in write check
 
41
   09-Nov-01    RMS     Added bus map, VAX support
 
42
   07-Sep-01    RMS     Revised device disable and interrupt mechanisms
 
43
   20-Aug-01    RMS     Added bad block option in attach
 
44
   17-Jul-01    RMS     Fixed warning from VC++ 6.0
 
45
   26-Apr-01    RMS     Added device enable/disable support
 
46
   25-Mar-01    RMS     Fixed block fill calculation
 
47
   15-Feb-01    RMS     Corrected bootstrap string
 
48
   12-Nov-97    RMS     Added bad block table command
 
49
   25-Nov-96    RMS     Default units to autosize
 
50
   29-Jun-96    RMS     Added unit disable support
 
51
 
 
52
   The RL11 is a four drive cartridge disk subsystem.  An RL01 drive
 
53
   consists of 256 cylinders, each with 2 surfaces containing 40 sectors
 
54
   of 256 bytes.  An RL02 drive has 512 cylinders.  The RLV12 is a
 
55
   controller variant which supports 22b direct addressing.
 
56
 
 
57
   The most complicated part of the RL11 controller is the way it does
 
58
   seeks.  Seeking is relative to the current disk address; this requires
 
59
   keeping accurate track of the current cylinder.  The RL11 will not
 
60
   switch heads or cross cylinders during transfers.
 
61
 
 
62
   The RL11 functions in three environments:
 
63
 
 
64
   - PDP-11 Q22 systems - the I/O map is one for one, so it's safe to
 
65
     go through the I/O map
 
66
   - PDP-11 Unibus 22b systems - the RL11 behaves as an 18b Unibus
 
67
     peripheral and must go through the I/O map
 
68
   - VAX Q22 systems - the RL11 must go through the I/O map
 
69
*/
 
70
 
 
71
#if defined (VM_PDP10)                                  /* PDP10 version */
 
72
#error "RL11 is not supported on the PDP-10!"
 
73
 
 
74
#elif defined (VM_VAX)                                  /* VAX version */
 
75
#include "vax_defs.h"
 
76
extern int32 int_req[IPL_HLVL];
 
77
extern int32 int_vec[IPL_HLVL][32];
 
78
 
 
79
#else                                                   /* PDP-11 version */
 
80
#include "pdp11_defs.h"
 
81
extern int32 int_req[IPL_HLVL];
 
82
extern int32 int_vec[IPL_HLVL][32];
 
83
extern int32 cpu_18b, cpu_ubm;
 
84
#endif
 
85
 
 
86
/* Constants */
 
87
 
 
88
#define RL_NUMWD        128                             /* words/sector */
 
89
#define RL_NUMSC        40                              /* sectors/surface */
 
90
#define RL_NUMSF        2                               /* surfaces/cylinder */
 
91
#define RL_NUMCY        256                             /* cylinders/drive */
 
92
#define RL_NUMDR        4                               /* drives/controller */
 
93
#define RL_MAXFR        (1 << 16)                       /* max transfer */
 
94
#define RL01_SIZE (RL_NUMCY * RL_NUMSF * RL_NUMSC * RL_NUMWD)  /* words/drive */
 
95
#define RL02_SIZE       (RL01_SIZE * 2)                 /* words/drive */
 
96
 
 
97
/* Flags in the unit flags word */
 
98
 
 
99
#define UNIT_V_WLK      (UNIT_V_UF + 0)                 /* hwre write lock */
 
100
#define UNIT_V_RL02     (UNIT_V_UF + 1)                 /* RL01 vs RL02 */
 
101
#define UNIT_V_AUTO     (UNIT_V_UF + 2)                 /* autosize enable */
 
102
#define UNIT_V_DUMMY    (UNIT_V_UF + 3)                 /* dummy flag */
 
103
#define UNIT_DUMMY      (1 << UNIT_V_DUMMY)
 
104
#define UNIT_WLK        (1u << UNIT_V_WLK)
 
105
#define UNIT_RL02       (1u << UNIT_V_RL02)
 
106
#define UNIT_AUTO       (1u << UNIT_V_AUTO)
 
107
#define UNIT_WPRT       (UNIT_WLK | UNIT_RO)            /* write protected */
 
108
 
 
109
/* Parameters in the unit descriptor */
 
110
 
 
111
#define TRK             u3                              /* current track */
 
112
#define STAT            u4                              /* status */
 
113
 
 
114
/* RLDS, NI = not implemented, * = kept in STAT, ^ = kept in TRK */
 
115
 
 
116
#define RLDS_LOAD       0                               /* no cartridge */
 
117
#define RLDS_LOCK       5                               /* lock on */
 
118
#define RLDS_BHO        0000010                         /* brushes home NI */
 
119
#define RLDS_HDO        0000020                         /* heads out NI */
 
120
#define RLDS_CVO        0000040                         /* cover open NI */
 
121
#define RLDS_HD         0000100                         /* head select ^ */
 
122
#define RLDS_RL02       0000200                         /* RL02 */
 
123
#define RLDS_DSE        0000400                         /* drv sel err NI */
 
124
#define RLDS_VCK        0001000                         /* vol check * */
 
125
#define RLDS_WGE        0002000                         /* wr gate err * */
 
126
#define RLDS_SPE        0004000                         /* spin err * */
 
127
#define RLDS_STO        0010000                         /* seek time out NI */
 
128
#define RLDS_WLK        0020000                         /* wr locked */
 
129
#define RLDS_HCE        0040000                         /* hd curr err NI */
 
130
#define RLDS_WDE        0100000                         /* wr data err NI */
 
131
#define RLDS_ATT        (RLDS_HDO+RLDS_BHO+RLDS_LOCK)   /* att status */
 
132
#define RLDS_UNATT      (RLDS_CVO+RLDS_LOAD)            /* unatt status */
 
133
#define RLDS_ERR        (RLDS_WDE+RLDS_HCE+RLDS_STO+RLDS_SPE+RLDS_WGE+ \
 
134
                        RLDS_VCK+RLDS_DSE)              /* errors bits */
 
135
 
 
136
/* RLCS */
 
137
 
 
138
#define RLCS_DRDY       0000001                         /* drive ready */
 
139
#define RLCS_M_FUNC     0000007                         /* function */
 
140
#define  RLCS_NOP       0
 
141
#define  RLCS_WCHK      1
 
142
#define  RLCS_GSTA      2
 
143
#define  RLCS_SEEK      3
 
144
#define  RLCS_RHDR      4
 
145
#define  RLCS_WRITE     5
 
146
#define  RLCS_READ      6
 
147
#define  RLCS_RNOHDR    7
 
148
#define RLCS_V_FUNC     1
 
149
#define RLCS_M_MEX      03                              /* memory extension */
 
150
#define RLCS_V_MEX      4
 
151
#define RLCS_MEX        (RLCS_M_MEX << RLCS_V_MEX)
 
152
#define RLCS_M_DRIVE    03
 
153
#define RLCS_V_DRIVE    8
 
154
#define RLCS_INCMP      0002000                         /* incomplete */
 
155
#define RLCS_CRC        0004000                         /* CRC error */
 
156
#define RLCS_HDE        0010000                         /* header error */
 
157
#define RLCS_NXM        0020000                         /* non-exist memory */
 
158
#define RLCS_DRE        0040000                         /* drive error */
 
159
#define RLCS_ERR        0100000                         /* error summary */
 
160
#define RLCS_ALLERR (RLCS_ERR+RLCS_DRE+RLCS_NXM+RLCS_HDE+RLCS_CRC+RLCS_INCMP)
 
161
#define RLCS_RW         0001776                         /* read/write */
 
162
#define GET_FUNC(x)     (((x) >> RLCS_V_FUNC) & RLCS_M_FUNC)
 
163
#define GET_DRIVE(x)    (((x) >> RLCS_V_DRIVE) & RLCS_M_DRIVE)
 
164
 
 
165
/* RLDA */
 
166
 
 
167
#define RLDA_SK_DIR     0000004                         /* direction */
 
168
#define RLDA_GS_CLR     0000010                         /* clear errors */
 
169
#define RLDA_SK_HD      0000020                         /* head select */
 
170
 
 
171
#define RLDA_V_SECT     0                               /* sector */
 
172
#define RLDA_M_SECT     077
 
173
#define RLDA_V_TRACK    6                               /* track */
 
174
#define RLDA_M_TRACK    01777
 
175
#define RLDA_HD0        (0 << RLDA_V_TRACK)
 
176
#define RLDA_HD1        (1u << RLDA_V_TRACK)
 
177
#define RLDA_V_CYL      7                               /* cylinder */
 
178
#define RLDA_M_CYL      0777
 
179
#define RLDA_TRACK      (RLDA_M_TRACK << RLDA_V_TRACK)
 
180
#define RLDA_CYL        (RLDA_M_CYL << RLDA_V_CYL)
 
181
#define GET_SECT(x)     (((x) >> RLDA_V_SECT) & RLDA_M_SECT)
 
182
#define GET_CYL(x)      (((x) >> RLDA_V_CYL) & RLDA_M_CYL)
 
183
#define GET_TRACK(x)    (((x) >> RLDA_V_TRACK) & RLDA_M_TRACK)
 
184
#define GET_DA(x)       ((GET_TRACK (x) * RL_NUMSC) + GET_SECT (x))
 
185
 
 
186
/* RLBA */
 
187
 
 
188
#define RLBA_IMP        0177776                         /* implemented */
 
189
 
 
190
/* RLBAE */
 
191
 
 
192
#define RLBAE_IMP       0000077                         /* implemented */
 
193
 
 
194
extern uint16 *M;
 
195
extern int32 int_req[IPL_HLVL];
 
196
extern int32 int_vec[IPL_HLVL][32];
 
197
 
 
198
uint16 *rlxb = NULL;                                    /* xfer buffer */
 
199
int32 rlcs = 0;                                         /* control/status */
 
200
int32 rlba = 0;                                         /* memory address */
 
201
int32 rlbae = 0;                                        /* mem addr extension */
 
202
int32 rlda = 0;                                         /* disk addr */
 
203
int32 rlmp = 0, rlmp1 = 0, rlmp2 = 0;                   /* mp register queue */
 
204
int32 rl_swait = 10;                                    /* seek wait */
 
205
int32 rl_rwait = 10;                                    /* rotate wait */
 
206
int32 rl_stopioe = 1;                                   /* stop on error */
 
207
 
 
208
DEVICE rl_dev;
 
209
t_stat rl_rd (int32 *data, int32 PA, int32 access);
 
210
t_stat rl_wr (int32 data, int32 PA, int32 access);
 
211
t_stat rl_svc (UNIT *uptr);
 
212
t_stat rl_reset (DEVICE *dptr);
 
213
void rl_set_done (int32 error);
 
214
t_stat rl_boot (int32 unitno, DEVICE *dptr);
 
215
t_stat rl_attach (UNIT *uptr, char *cptr);
 
216
t_stat rl_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
 
217
t_stat rl_set_bad (UNIT *uptr, int32 val, char *cptr, void *desc);
 
218
extern t_stat pdp11_bad_block (UNIT *uptr, int32 sec, int32 wds);
 
219
 
 
220
/* RL11 data structures
 
221
 
 
222
   rl_dev       RL device descriptor
 
223
   rl_unit      RL unit list
 
224
   rl_reg       RL register list
 
225
   rl_mod       RL modifier list
 
226
*/
 
227
 
 
228
DIB rl_dib = { IOBA_RL, IOLN_RL, &rl_rd, &rl_wr,
 
229
                1, IVCL (RL), VEC_RL, { NULL } };
 
230
 
 
231
UNIT rl_unit[] = {
 
232
        { UDATA (&rl_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
 
233
                UNIT_ROABLE+UNIT_AUTO, RL01_SIZE) },
 
234
        { UDATA (&rl_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
 
235
                UNIT_ROABLE+UNIT_AUTO, RL01_SIZE) },
 
236
        { UDATA (&rl_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
 
237
                UNIT_ROABLE+UNIT_AUTO, RL01_SIZE) },
 
238
        { UDATA (&rl_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
 
239
                UNIT_ROABLE+UNIT_AUTO, RL01_SIZE) }  };
 
240
 
 
241
REG rl_reg[] = {
 
242
        { GRDATA (RLCS, rlcs, DEV_RDX, 16, 0) },
 
243
        { GRDATA (RLDA, rlda, DEV_RDX, 16, 0) },
 
244
        { GRDATA (RLBA, rlba, DEV_RDX, 16, 0) },
 
245
        { GRDATA (RLBAE, rlbae, DEV_RDX, 6, 0) },
 
246
        { GRDATA (RLMP, rlmp, DEV_RDX, 16, 0) },
 
247
        { GRDATA (RLMP1, rlmp1, DEV_RDX, 16, 0) },
 
248
        { GRDATA (RLMP2, rlmp2, DEV_RDX, 16, 0) },
 
249
        { FLDATA (INT, IREQ (RL), INT_V_RL) },
 
250
        { FLDATA (ERR, rlcs, CSR_V_ERR) },
 
251
        { FLDATA (DONE, rlcs, CSR_V_DONE) },
 
252
        { FLDATA (IE, rlcs, CSR_V_IE) },
 
253
        { DRDATA (STIME, rl_swait, 24), PV_LEFT },
 
254
        { DRDATA (RTIME, rl_rwait, 24), PV_LEFT },
 
255
        { URDATA (CAPAC, rl_unit[0].capac, 10, T_ADDR_W, 0,
 
256
                  RL_NUMDR, PV_LEFT + REG_HRO) },
 
257
        { FLDATA (STOP_IOE, rl_stopioe, 0) },
 
258
        { GRDATA (DEVADDR, rl_dib.ba, DEV_RDX, 32, 0), REG_HRO },
 
259
        { GRDATA (DEVVEC, rl_dib.vec, DEV_RDX, 16, 0), REG_HRO },
 
260
        { NULL }  };
 
261
 
 
262
MTAB rl_mod[] = {
 
263
        { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL },
 
264
        { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL },
 
265
        { UNIT_DUMMY, 0, NULL, "BADBLOCK", &rl_set_bad },
 
266
        { (UNIT_RL02+UNIT_ATT), UNIT_ATT, "RL01", NULL, NULL },
 
267
        { (UNIT_RL02+UNIT_ATT), (UNIT_RL02+UNIT_ATT), "RL02", NULL, NULL },
 
268
        { (UNIT_AUTO+UNIT_RL02+UNIT_ATT), 0, "RL01", NULL, NULL },
 
269
        { (UNIT_AUTO+UNIT_RL02+UNIT_ATT), UNIT_RL02, "RL02", NULL, NULL },
 
270
        { (UNIT_AUTO+UNIT_ATT), UNIT_AUTO, "autosize", NULL, NULL },
 
271
        { UNIT_AUTO, UNIT_AUTO, NULL, "AUTOSIZE", NULL },
 
272
        { (UNIT_AUTO+UNIT_RL02), 0, NULL, "RL01", &rl_set_size },
 
273
        { (UNIT_AUTO+UNIT_RL02), UNIT_RL02, NULL, "RL02", &rl_set_size },
 
274
        { MTAB_XTD|MTAB_VDV, 010, "ADDRESS", "ADDRESS",
 
275
                &set_addr, &show_addr, NULL },
 
276
        { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR",
 
277
                &set_vec, &show_vec, NULL },
 
278
        { 0 }  };
 
279
 
 
280
DEVICE rl_dev = {
 
281
        "RL", rl_unit, rl_reg, rl_mod,
 
282
        RL_NUMDR, DEV_RDX, 24, 1, DEV_RDX, 16,
 
283
        NULL, NULL, &rl_reset,
 
284
        &rl_boot, &rl_attach, NULL,
 
285
        &rl_dib, DEV_DISABLE | DEV_UBUS | DEV_QBUS };
 
286
 
 
287
/* I/O dispatch routine, I/O addresses 17774400 - 17774407
 
288
 
 
289
   17774400     RLCS    read/write
 
290
   17774402     RLBA    read/write
 
291
   17774404     RLDA    read/write
 
292
   17774406     RLMP    read/write
 
293
   17774410     RLBAE   read/write
 
294
*/
 
295
 
 
296
t_stat rl_rd (int32 *data, int32 PA, int32 access)
 
297
{
 
298
UNIT *uptr;
 
299
 
 
300
switch ((PA >> 1) & 07) {                               /* decode PA<2:1> */
 
301
case 0:                                                 /* RLCS */
 
302
        rlcs = (rlcs & ~RLCS_MEX) | ((rlbae & RLCS_M_MEX) << RLCS_V_MEX);
 
303
        if (rlcs & RLCS_ALLERR) rlcs = rlcs | RLCS_ERR;
 
304
        uptr = rl_dev.units + GET_DRIVE (rlcs);
 
305
        if (sim_is_active (uptr)) rlcs = rlcs & ~RLCS_DRDY;
 
306
        else rlcs = rlcs | RLCS_DRDY;                   /* see if ready */
 
307
        *data = rlcs;
 
308
        break;
 
309
case 1:                                                 /* RLBA */
 
310
        *data = rlba & RLBA_IMP;
 
311
        break;
 
312
case 2:                                                 /* RLDA */
 
313
        *data = rlda;
 
314
        break;
 
315
case 3:                                                 /* RLMP */
 
316
        *data = rlmp;
 
317
        rlmp = rlmp1;                                   /* ripple data */
 
318
        rlmp1 = rlmp2;
 
319
        break;
 
320
case 4:                                                 /* RLBAE */
 
321
        if (UNIBUS) return SCPE_NXM;                    /* not in RL11 */
 
322
        *data = rlbae & RLBAE_IMP;
 
323
        break;  }                                       /* end switch */
 
324
return SCPE_OK;
 
325
}
 
326
 
 
327
t_stat rl_wr (int32 data, int32 PA, int32 access)
 
328
{
 
329
int32 curr, offs, newc, maxc;
 
330
UNIT *uptr;
 
331
 
 
332
switch ((PA >> 1) & 07) {                               /* decode PA<2:1> */
 
333
case 0:                                                 /* RLCS */
 
334
        rlcs = (rlcs & ~RLCS_MEX) | ((rlbae & RLCS_M_MEX) << RLCS_V_MEX);
 
335
        if (rlcs & RLCS_ALLERR) rlcs = rlcs | RLCS_ERR;
 
336
        uptr = rl_dev.units + GET_DRIVE (data);         /* get new drive */
 
337
        if (sim_is_active (uptr)) rlcs = rlcs & ~RLCS_DRDY;
 
338
        else rlcs = rlcs | RLCS_DRDY;                   /* see if ready */
 
339
 
 
340
        if (access == WRITEB) data = (PA & 1)?
 
341
            (rlcs & 0377) | (data << 8): (rlcs & ~0377) | data;
 
342
        rlcs = (rlcs & ~RLCS_RW) | (data & RLCS_RW);
 
343
        rlbae = (rlbae & ~RLCS_M_MEX) | ((rlcs >> RLCS_V_MEX) & RLCS_M_MEX);
 
344
        if (data & CSR_DONE) {                          /* ready set? */
 
345
            if ((data & CSR_IE) == 0) CLR_INT (RL);
 
346
            else if ((rlcs & (CSR_DONE + CSR_IE)) == CSR_DONE)
 
347
                SET_INT (RL);   
 
348
            return SCPE_OK;  }
 
349
 
 
350
        CLR_INT (RL);                                   /* clear interrupt */
 
351
        rlcs = rlcs & ~RLCS_ALLERR;                     /* clear errors */
 
352
        switch (GET_FUNC (rlcs)) {                      /* case on RLCS<3:1> */
 
353
        case RLCS_NOP:                                  /* nop */
 
354
            rl_set_done (0);
 
355
            break;
 
356
        case RLCS_SEEK:                                 /* seek */
 
357
            curr = GET_CYL (uptr->TRK);                 /* current cylinder */
 
358
            offs = GET_CYL (rlda);                      /* offset */
 
359
            if (rlda & RLDA_SK_DIR) {                   /* in or out? */
 
360
                newc = curr + offs;                     /* out */
 
361
                maxc = (uptr->flags & UNIT_RL02)?
 
362
                    RL_NUMCY * 2: RL_NUMCY;
 
363
                if (newc >= maxc) newc = maxc - 1;  }
 
364
            else {
 
365
                newc = curr - offs;                     /* in */
 
366
                if (newc < 0) newc = 0;  }
 
367
            uptr->TRK = (newc << RLDA_V_CYL) |          /* put on track */
 
368
                ((rlda & RLDA_SK_HD)? RLDA_HD1: RLDA_HD0);
 
369
            sim_activate (uptr, rl_swait * abs (newc - curr));
 
370
            break;
 
371
        default:                                        /* data transfer */
 
372
            sim_activate (uptr, rl_swait);              /* activate unit */
 
373
            break;  }                                   /* end switch func */
 
374
        break;                                          /* end case RLCS */
 
375
 
 
376
case 1:                                                 /* RLBA */
 
377
        if (access == WRITEB) data = (PA & 1)?
 
378
            (rlba & 0377) | (data << 8): (rlba & ~0377) | data;
 
379
        rlba = data & RLBA_IMP;
 
380
        break;
 
381
case 2:                                                 /* RLDA */
 
382
        if (access == WRITEB) data = (PA & 1)?
 
383
            (rlda & 0377) | (data << 8): (rlda & ~0377) | data;
 
384
        rlda = data;
 
385
        break;
 
386
case 3:                                                 /* RLMP */
 
387
        if (access == WRITEB) data = (PA & 1)?
 
388
            (rlmp & 0377) | (data << 8): (rlmp & ~0377) | data;
 
389
        rlmp = rlmp1 = rlmp2 = data;
 
390
        break;
 
391
case 4:                                                 /* RLBAE */
 
392
        if (UNIBUS) return SCPE_NXM;                    /* not in RL11 */
 
393
        if (PA & 1) return SCPE_OK;
 
394
        rlbae = data & RLBAE_IMP;
 
395
        rlcs = (rlcs & ~RLCS_MEX) | ((rlbae & RLCS_M_MEX) << RLCS_V_MEX);
 
396
        break;  }                                       /* end switch */
 
397
return SCPE_OK;
 
398
}
 
399
 
 
400
/* Service unit timeout
 
401
 
 
402
   If seek in progress, complete seek command
 
403
   Else complete data transfer command
 
404
 
 
405
   The unit control block contains the function and cylinder for
 
406
   the current command.
 
407
*/
 
408
 
 
409
t_stat rl_svc (UNIT *uptr)
 
410
{
 
411
int32 err, wc, maxwc, t;
 
412
int32 i, func, da, awc;
 
413
uint32 ma;
 
414
uint16 comp;
 
415
 
 
416
func = GET_FUNC (rlcs);                                 /* get function */
 
417
if (func == RLCS_GSTA) {                                /* get status */
 
418
        if (rlda & RLDA_GS_CLR) uptr->STAT = uptr->STAT & ~RLDS_ERR;
 
419
        rlmp = uptr->STAT | (uptr->TRK & RLDS_HD) |
 
420
            ((uptr->flags & UNIT_ATT)? RLDS_ATT: RLDS_UNATT);
 
421
        if (uptr->flags & UNIT_RL02) rlmp = rlmp | RLDS_RL02;
 
422
        if (uptr->flags & UNIT_WPRT) rlmp = rlmp | RLDS_WLK;
 
423
        rlmp2 = rlmp1 = rlmp;
 
424
        rl_set_done (0);                                /* done */
 
425
        return SCPE_OK;  }
 
426
 
 
427
if ((uptr->flags & UNIT_ATT) == 0) {                    /* attached? */
 
428
        rlcs = rlcs & ~RLCS_DRDY;                       /* clear drive ready */
 
429
        uptr->STAT = uptr->STAT | RLDS_SPE;             /* spin error */
 
430
        rl_set_done (RLCS_ERR | RLCS_INCMP);            /* flag error */
 
431
        return IORETURN (rl_stopioe, SCPE_UNATT);  }
 
432
 
 
433
if ((func == RLCS_WRITE) && (uptr->flags & UNIT_WPRT)) {
 
434
        uptr->STAT = uptr->STAT | RLDS_WGE;             /* write and locked */
 
435
        rl_set_done (RLCS_ERR | RLCS_DRE);
 
436
        return SCPE_OK;  }
 
437
 
 
438
if (func == RLCS_SEEK) {                                /* seek? */
 
439
        rl_set_done (0);                                /* done */
 
440
        return SCPE_OK;  }
 
441
 
 
442
if (func == RLCS_RHDR) {                                /* read header? */
 
443
        rlmp = (uptr->TRK & RLDA_TRACK) | GET_SECT (rlda);
 
444
        rlmp1 = rlmp2 = 0;
 
445
        rl_set_done (0);                                /* done */
 
446
        return SCPE_OK;  }
 
447
 
 
448
if (((func != RLCS_RNOHDR) && ((uptr->TRK & RLDA_CYL) != (rlda & RLDA_CYL)))
 
449
   || (GET_SECT (rlda) >= RL_NUMSC)) {                  /* bad cyl or sector? */
 
450
        rl_set_done (RLCS_ERR | RLCS_HDE | RLCS_INCMP); /* wrong cylinder? */
 
451
        return SCPE_OK;  }
 
452
        
 
453
ma = (rlbae << 16) | rlba;                              /* get mem addr */
 
454
da = GET_DA (rlda) * RL_NUMWD;                          /* get disk addr */
 
455
wc = 0200000 - rlmp;                                    /* get true wc */
 
456
 
 
457
maxwc = (RL_NUMSC - GET_SECT (rlda)) * RL_NUMWD;        /* max transfer */
 
458
if (wc > maxwc) wc = maxwc;                             /* track overrun? */
 
459
err = fseek (uptr->fileref, da * sizeof (int16), SEEK_SET);
 
460
 
 
461
if ((func >= RLCS_READ) && (err == 0)) {                /* read (no hdr)? */
 
462
        i = fxread (rlxb, sizeof (int16), wc, uptr->fileref);
 
463
        err = ferror (uptr->fileref);
 
464
        for ( ; i < wc; i++) rlxb[i] = 0;               /* fill buffer */
 
465
        if (t = Map_WriteW (ma, wc << 1, rlxb, MAP)) {  /* store buffer */
 
466
            rlcs = rlcs | RLCS_ERR | RLCS_NXM;          /* nxm */
 
467
            wc = wc - t;  }                             /* adjust wc */
 
468
        }                                               /* end read */
 
469
 
 
470
if ((func == RLCS_WRITE) && (err == 0)) {               /* write? */
 
471
        if (t = Map_ReadW (ma, wc << 1, rlxb, MAP)) {   /* fetch buffer */
 
472
            rlcs = rlcs | RLCS_ERR | RLCS_NXM;          /* nxm */
 
473
            wc = wc - t;  }                             /* adj xfer lnt */
 
474
        if (wc) {                                       /* any xfer? */
 
475
            awc = (wc + (RL_NUMWD - 1)) & ~(RL_NUMWD - 1);      /* clr to */
 
476
            for (i = wc; i < awc; i++) rlxb[i] = 0;     /* end of blk */
 
477
            fxwrite (rlxb, sizeof (int16), awc, uptr->fileref);
 
478
            err = ferror (uptr->fileref);  }
 
479
        }                                               /* end write */
 
480
 
 
481
if ((func == RLCS_WCHK) && (err == 0)) {                /* write check? */
 
482
        i = fxread (rlxb, sizeof (int16), wc, uptr->fileref);
 
483
        err = ferror (uptr->fileref);
 
484
        for ( ; i < wc; i++) rlxb[i] = 0;               /* fill buffer */
 
485
        awc = wc;                                       /* save wc */
 
486
        for (wc = 0; (err == 0) && (wc < awc); wc++)  { /* loop thru buf */
 
487
            if (Map_ReadW (ma + (wc << 1), 2, &comp, MAP)) { /* mem wd */
 
488
                rlcs = rlcs | RLCS_ERR | RLCS_NXM;      /* nxm */
 
489
                break;  }
 
490
            if (comp != rlxb[wc])                       /* check to buf */
 
491
                rlcs = rlcs | RLCS_ERR | RLCS_CRC;
 
492
            }                                           /* end for */
 
493
        }                                               /* end wcheck */
 
494
 
 
495
rlmp = (rlmp + wc) & 0177777;                           /* final word count */
 
496
if (rlmp != 0) rlcs = rlcs | RLCS_ERR | RLCS_INCMP;     /* completed? */
 
497
ma = ma + (wc << 1);                                    /* final byte addr */
 
498
rlbae = (ma >> 16) & RLBAE_IMP;                         /* upper 6b */
 
499
rlba = ma & RLBA_IMP;                                   /* lower 16b */
 
500
rlcs = (rlcs & ~RLCS_MEX) | ((rlbae & RLCS_M_MEX) << RLCS_V_MEX);
 
501
rlda = rlda + ((wc + (RL_NUMWD - 1)) / RL_NUMWD);
 
502
rl_set_done (0);
 
503
 
 
504
if (err != 0) {                                         /* error? */
 
505
        perror ("RL I/O error");
 
506
        clearerr (uptr->fileref);
 
507
        return SCPE_IOERR;  }
 
508
return SCPE_OK;
 
509
}
 
510
 
 
511
/* Set done and possibly errors */
 
512
 
 
513
void rl_set_done (int32 status)
 
514
{
 
515
        rlcs = rlcs | status | CSR_DONE;                /* set done */
 
516
        if (rlcs & CSR_IE) SET_INT (RL);
 
517
        else CLR_INT (RL);
 
518
        return;
 
519
}
 
520
 
 
521
/* Device reset
 
522
 
 
523
   Note that the RL11 does NOT recalibrate its drives on RESET
 
524
*/
 
525
 
 
526
t_stat rl_reset (DEVICE *dptr)
 
527
{
 
528
int32 i;
 
529
UNIT *uptr;
 
530
 
 
531
rlcs = CSR_DONE;
 
532
rlda = rlba = rlbae = rlmp = rlmp1 = rlmp2 = 0;
 
533
CLR_INT (RL);
 
534
for (i = 0; i < RL_NUMDR; i++) {
 
535
        uptr = rl_dev.units + i;
 
536
        sim_cancel (uptr);
 
537
        uptr->STAT = 0;  }
 
538
if (rlxb == NULL) rlxb = calloc (RL_MAXFR, sizeof (unsigned int16));
 
539
if (rlxb == NULL) return SCPE_MEM;
 
540
return SCPE_OK;
 
541
}
 
542
 
 
543
/* Attach routine */
 
544
 
 
545
t_stat rl_attach (UNIT *uptr, char *cptr)
 
546
{
 
547
uint32 p;
 
548
t_stat r;
 
549
 
 
550
uptr->capac = (uptr->flags & UNIT_RL02)? RL02_SIZE: RL01_SIZE;
 
551
r = attach_unit (uptr, cptr);                           /* attach unit */
 
552
if (r != SCPE_OK) return r;                             /* error? */
 
553
uptr->TRK = 0;                                          /* cylinder 0 */
 
554
uptr->STAT = RLDS_VCK;                                  /* new volume */
 
555
if ((p = sim_fsize (uptr->fileref)) == 0) {             /* new disk image? */
 
556
        if (uptr->flags & UNIT_RO) return SCPE_OK;      /* if ro, done */
 
557
        return pdp11_bad_block (uptr, RL_NUMSC, RL_NUMWD);  }
 
558
if ((uptr->flags & UNIT_AUTO) == 0) return SCPE_OK;     /* autosize? */
 
559
if (p > (RL01_SIZE * sizeof (int16))) {
 
560
        uptr->flags = uptr->flags | UNIT_RL02;
 
561
        uptr->capac = RL02_SIZE;  }
 
562
else {  uptr->flags = uptr->flags & ~UNIT_RL02;
 
563
        uptr->capac = RL01_SIZE;  }
 
564
return SCPE_OK;
 
565
}
 
566
 
 
567
/* Set size routine */
 
568
 
 
569
t_stat rl_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)
 
570
{
 
571
if (uptr->flags & UNIT_ATT) return SCPE_ALATT;
 
572
uptr->capac = (val & UNIT_RL02)? RL02_SIZE: RL01_SIZE;
 
573
return SCPE_OK;
 
574
}
 
575
 
 
576
/* Set bad block routine */
 
577
 
 
578
t_stat rl_set_bad (UNIT *uptr, int32 val, char *cptr, void *desc)
 
579
{
 
580
return pdp11_bad_block (uptr, RL_NUMSC, RL_NUMWD);
 
581
}
 
582
 
 
583
/* Device bootstrap */
 
584
 
 
585
#if defined (VM_PDP11)
 
586
 
 
587
#define BOOT_START      02000                           /* start */
 
588
#define BOOT_ENTRY      (BOOT_START + 002)              /* entry */
 
589
#define BOOT_UNIT       (BOOT_START + 010)              /* unit number */
 
590
#define BOOT_CSR        (BOOT_START + 020)              /* CSR */
 
591
#define BOOT_LEN        (sizeof (boot_rom) / sizeof (int16))
 
592
 
 
593
static const uint16 boot_rom[] = {
 
594
        0042114,                        /* "LD" */
 
595
        0012706, BOOT_START,            /* MOV #boot_start, SP */
 
596
        0012700, 0000000,               /* MOV #unit, R0 */
 
597
        0010003,                        /* MOV R0, R3 */
 
598
        0000303,                        /* SWAB R3 */
 
599
        0012701, 0174400,               /* MOV #RLCS, R1        ; csr */
 
600
        0012761, 0000013, 0000004,      /* MOV #13, 4(R1)       ; clr err */
 
601
        0052703, 0000004,               /* BIS #4, R3           ; unit+gstat */
 
602
        0010311,                        /* MOV R3, (R1)         ; issue cmd */
 
603
        0105711,                        /* TSTB (R1)            ; wait */
 
604
        0100376,                        /* BPL .-2 */
 
605
        0105003,                        /* CLRB R3 */
 
606
        0052703, 0000010,               /* BIS #10, R3          ; unit+rdhdr */
 
607
        0010311,                        /* MOV R3, (R1)         ; issue cmd */
 
608
        0105711,                        /* TSTB (R1)            ; wait */
 
609
        0100376,                        /* BPL .-2 */
 
610
        0016102, 0000006,               /* MOV 6(R1), R2        ; get hdr */
 
611
        0042702, 0000077,               /* BIC #77, R2          ; clr sector */
 
612
        0005202,                        /* INC R2               ; magic bit */
 
613
        0010261, 0000004,               /* MOV R2, 4(R1)        ; seek to 0 */
 
614
        0105003,                        /* CLRB R3 */
 
615
        0052703, 0000006,               /* BIS #6, R3           ; unit+seek */
 
616
        0010311,                        /* MOV R3, (R1)         ; issue cmd */
 
617
        0105711,                        /* TSTB (R1)            ; wait */
 
618
        0100376,                        /* BPL .-2 */
 
619
        0005061, 0000002,               /* CLR 2(R1)            ; clr ba */
 
620
        0005061, 0000004,               /* CLR 4(R1)            ; clr da */
 
621
        0012761, 0177000, 0000006,      /* MOV #-512., 6(R1)    ; set wc */
 
622
        0105003,                        /* CLRB R3 */
 
623
        0052703, 0000014,               /* BIS #14, R3          ; unit+read */
 
624
        0010311,                        /* MOV R3, (R1)         ; issue cmd */
 
625
        0105711,                        /* TSTB (R1)            ; wait */
 
626
        0100376,                        /* BPL .-2 */
 
627
        0042711, 0000377,               /* BIC #377, (R1) */
 
628
        0005002,                        /* CLR R2 */
 
629
        0005003,                        /* CLR R3 */
 
630
        0012704, BOOT_START+020,        /* MOV #START+20, R4 */
 
631
        0005005,                        /* CLR R5 */
 
632
        0005007                         /* CLR PC */
 
633
};
 
634
 
 
635
t_stat rl_boot (int32 unitno, DEVICE *dptr)
 
636
{
 
637
int32 i;
 
638
extern int32 saved_PC;
 
639
 
 
640
for (i = 0; i < BOOT_LEN; i++) M[(BOOT_START >> 1) + i] = boot_rom[i];
 
641
M[BOOT_UNIT >> 1] = unitno & RLCS_M_DRIVE;
 
642
M[BOOT_CSR >> 1] = rl_dib.ba & DMASK;
 
643
saved_PC = BOOT_ENTRY;
 
644
return SCPE_OK;
 
645
}
 
646
 
 
647
#else
 
648
 
 
649
t_stat rl_boot (int32 unitno, DEVICE *dptr)
 
650
{
 
651
return SCPE_NOFNC;
 
652
}
 
653
#endif