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

« back to all changes in this revision

Viewing changes to HP2100/hp2100_ms.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
/* hp2100_ms.c: HP 2100 13181A/13183A magnetic tape 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
   ms           13181A 7970B 800bpi nine track magnetic tape
 
27
                13183A 7970E 1600bpi nine track magnetic tape
 
28
 
 
29
   25-Apr-03    RMS     Revised for extended file support
 
30
   28-Mar-03    RMS     Added multiformat support
 
31
   28-Feb-03    RMS     Revised for magtape library
 
32
   18-Oct-02    RMS     Added BOOT command, added 13183A support
 
33
   30-Sep-02    RMS     Revamped error handling
 
34
   29-Aug-02    RMS     Added end of medium support
 
35
   30-May-02    RMS     Widened POS to 32b
 
36
   22-Apr-02    RMS     Added maximum record length test
 
37
 
 
38
   Magnetic tapes are represented as a series of variable records
 
39
   of the form:
 
40
 
 
41
        32b byte count
 
42
        byte 0
 
43
        byte 1
 
44
        :
 
45
        byte n-2
 
46
        byte n-1
 
47
        32b byte count
 
48
 
 
49
   If the byte count is odd, the record is padded with an extra byte
 
50
   of junk.  File marks are represented by a byte count of 0.
 
51
 
 
52
   Unusually among HP peripherals, the 12559 does not have a command flop,
 
53
   and its flag and flag buffer power up as clear rather than set.
 
54
*/
 
55
 
 
56
#include "hp2100_defs.h"
 
57
#include "sim_tape.h"
 
58
 
 
59
#define MS_NUMDR        4                               /* number of drives */
 
60
#define DB_N_SIZE       16                              /* max data buf */
 
61
#define DBSIZE          (1 << DB_N_SIZE)                /* max data cmd */
 
62
#define FNC             u3                              /* function */
 
63
#define UST             u4                              /* unit status */
 
64
 
 
65
/* Command - msc_fnc */
 
66
 
 
67
#define FNC_CLR         00110                           /* clear */
 
68
#define FNC_GAP         00015                           /* write gap */
 
69
#define FNC_GFM         00215                           /* gap+file mark */
 
70
#define FNC_RC          00023                           /* read */
 
71
#define FNC_WC          00031                           /* write */
 
72
#define FNC_FSR         00003                           /* forward space */
 
73
#define FNC_BSR         00041                           /* backward space */
 
74
#define FNC_FSF         00203                           /* forward file */
 
75
#define FNC_BSF         00241                           /* backward file */
 
76
#define FNC_REW         00101                           /* rewind */
 
77
#define FNC_RWS         00105                           /* rewind and offline */
 
78
#define FNC_WFM         00211                           /* write file mark */
 
79
#define FNC_RFF         00223                           /* "read file fwd" */
 
80
#define FNC_V_SEL       9                               /* select */
 
81
#define FNC_M_SEL       017
 
82
#define FNC_GETSEL(x)   (((x) >> FNC_V_SEL) & FNC_M_SEL)
 
83
 
 
84
#define FNF_MOT         00001                           /* motion */
 
85
#define FNF_OFL         00004
 
86
#define FNF_WRT         00010                           /* write */
 
87
#define FNF_REV         00040                           /* reverse */
 
88
#define FNF_RWD         00100                           /* rewind */
 
89
#define FNF_CHS         00400                           /* change select */
 
90
 
 
91
/* Status - stored in msc_sta, unit.UST (u), or dynamic (d) */
 
92
 
 
93
#define STA_PE          0100000                         /* 1600 bpi (d) */
 
94
#define STA_V_SEL       13                              /* unit sel (d) */
 
95
#define STA_M_SEL       03
 
96
#define STA_SEL         (STA_M_SEL << STA_V_SEL)
 
97
#define STA_ODD         0004000                         /* odd bytes */
 
98
#define STA_REW         0002000                         /* rewinding (u) */
 
99
#define STA_TBSY        0001000                         /* transport busy (d) */
 
100
#define STA_BUSY        0000400                         /* ctrl busy */
 
101
#define STA_EOF         0000200                         /* end of file */
 
102
#define STA_BOT         0000100                         /* beg of tape (u) */
 
103
#define STA_EOT         0000040                         /* end of tape (u) */
 
104
#define STA_TIM         0000020                         /* timing error */
 
105
#define STA_REJ         0000010                         /* programming error */
 
106
#define STA_WLK         0000004                         /* write locked (d) */
 
107
#define STA_PAR         0000002                         /* parity error */
 
108
#define STA_LOCAL       0000001                         /* local (d) */
 
109
#define STA_DYN         (STA_PE|STA_SEL|STA_TBSY|STA_WLK|STA_LOCAL)
 
110
 
 
111
extern uint16 *M;
 
112
extern uint32 PC, SR;
 
113
extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2];
 
114
extern int32 sim_switches;
 
115
extern UNIT cpu_unit;
 
116
 
 
117
int32 ms_ctype = 0;                                     /* ctrl type */
 
118
int32 msc_sta = 0;                                      /* status */
 
119
int32 msc_buf = 0;                                      /* buffer */
 
120
int32 msc_usl = 0;                                      /* unit select */
 
121
int32 msc_1st = 0;
 
122
int32 msc_ctime = 1000;                                 /* command wait */
 
123
int32 msc_gtime = 1000;                                 /* gap stop time */
 
124
int32 msc_rtime = 1000;                                 /* rewind wait */
 
125
int32 msc_xtime = 15;                                   /* data xfer time */
 
126
int32 msc_stopioe = 1;                                  /* stop on error */
 
127
int32 msd_buf = 0;                                      /* data buffer */
 
128
uint8 msxb[DBSIZE] = { 0 };                             /* data buffer */
 
129
t_mtrlnt ms_ptr = 0, ms_max = 0;                        /* buffer ptrs */
 
130
 
 
131
DEVICE msd_dev, msc_dev;
 
132
int32 msdio (int32 inst, int32 IR, int32 dat);
 
133
int32 mscio (int32 inst, int32 IR, int32 dat);
 
134
t_stat msc_svc (UNIT *uptr);
 
135
t_stat msc_reset (DEVICE *dptr);
 
136
t_stat msc_attach (UNIT *uptr, char *cptr);
 
137
t_stat msc_detach (UNIT *uptr);
 
138
t_stat msc_boot (int32 unitno, DEVICE *dptr);
 
139
t_stat ms_map_err (UNIT *uptr, t_stat st);
 
140
t_stat ms_settype (UNIT *uptr, int32 val, char *cptr, void *desc);
 
141
t_stat ms_showtype (FILE *st, UNIT *uptr, int32 val, void *desc);
 
142
 
 
143
/* MSD data structures
 
144
 
 
145
   msd_dev      MSD device descriptor
 
146
   msd_unit     MSD unit list
 
147
   msd_reg      MSD register list
 
148
*/
 
149
 
 
150
DIB ms_dib[] = {
 
151
        { MSD, 0, 0, 0, 0, &msdio },
 
152
        { MSC, 0, 0, 0, 0, &mscio }  };
 
153
 
 
154
#define msd_dib ms_dib[0]
 
155
#define msc_dib ms_dib[1]
 
156
 
 
157
UNIT msd_unit = { UDATA (NULL, 0, 0) };
 
158
 
 
159
REG msd_reg[] = {
 
160
        { ORDATA (BUF, msd_buf, 16) },
 
161
        { FLDATA (CMD, msd_dib.cmd, 0), REG_HRO },
 
162
        { FLDATA (CTL, msd_dib.ctl, 0) },
 
163
        { FLDATA (FLG, msd_dib.flg, 0) },
 
164
        { FLDATA (FBF, msd_dib.fbf, 0) },
 
165
        { BRDATA (DBUF, msxb, 8, 8, DBSIZE) },
 
166
        { DRDATA (BPTR, ms_ptr, DB_N_SIZE + 1) },
 
167
        { DRDATA (BMAX, ms_max, DB_N_SIZE + 1) },
 
168
        { ORDATA (DEVNO, msd_dib.devno, 6), REG_HRO },
 
169
        { NULL }  };
 
170
 
 
171
MTAB msd_mod[] = {
 
172
        { MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO",
 
173
                &hp_setdev, &hp_showdev, &msd_dev },
 
174
        { 0 }  };
 
175
 
 
176
DEVICE msd_dev = {
 
177
        "MSD", &msd_unit, msd_reg, msd_mod,
 
178
        1, 10, DB_N_SIZE, 1, 8, 8,
 
179
        NULL, NULL, &msc_reset,
 
180
        NULL, NULL, NULL,
 
181
        &msd_dib, 0 };
 
182
 
 
183
/* MSC data structures
 
184
 
 
185
   msc_dev      MSC device descriptor
 
186
   msc_unit     MSC unit list
 
187
   msc_reg      MSC register list
 
188
   msc_mod      MSC modifier list
 
189
*/
 
190
 
 
191
UNIT msc_unit[] = {
 
192
        { UDATA (&msc_svc, UNIT_ATTABLE + UNIT_ROABLE + UNIT_DISABLE, 0) },
 
193
        { UDATA (&msc_svc, UNIT_ATTABLE + UNIT_ROABLE + UNIT_DISABLE, 0) },
 
194
        { UDATA (&msc_svc, UNIT_ATTABLE + UNIT_ROABLE + UNIT_DISABLE, 0) },
 
195
        { UDATA (&msc_svc, UNIT_ATTABLE + UNIT_ROABLE + UNIT_DISABLE, 0) }  };
 
196
 
 
197
REG msc_reg[] = {
 
198
        { ORDATA (STA, msc_sta, 12) },
 
199
        { ORDATA (BUF, msc_buf, 16) },
 
200
        { ORDATA (USEL, msc_usl, 2) },
 
201
        { FLDATA (FSVC, msc_1st, 0) },
 
202
        { FLDATA (CMD, msc_dib.cmd, 0), REG_HRO },
 
203
        { FLDATA (CTL, msc_dib.ctl, 0) },
 
204
        { FLDATA (FLG, msc_dib.flg, 0) },
 
205
        { FLDATA (FBF, msc_dib.fbf, 0) },
 
206
        { URDATA (POS, msc_unit[0].pos, 10, T_ADDR_W, 0, MS_NUMDR, PV_LEFT) },
 
207
        { URDATA (FNC, msc_unit[0].FNC, 8, 8, 0, MS_NUMDR, REG_HRO) },
 
208
        { URDATA (UST, msc_unit[0].UST, 8, 12, 0, MS_NUMDR, REG_HRO) },
 
209
        { DRDATA (CTIME, msc_ctime, 24), REG_NZ + PV_LEFT },
 
210
        { DRDATA (GTIME, msc_gtime, 24), REG_NZ + PV_LEFT },
 
211
        { DRDATA (RTIME, msc_rtime, 24), REG_NZ + PV_LEFT },
 
212
        { DRDATA (XTIME, msc_xtime, 24), REG_NZ + PV_LEFT },
 
213
        { FLDATA (STOP_IOE, msc_stopioe, 0) },
 
214
        { FLDATA (CTYPE, ms_ctype, 0), REG_HRO },
 
215
        { ORDATA (DEVNO, msc_dib.devno, 6), REG_HRO },
 
216
        { NULL }  };
 
217
 
 
218
MTAB msc_mod[] = {
 
219
        { MTUF_WLK, 0, "write enabled", "WRITEENABLED", NULL },
 
220
        { MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL }, 
 
221
        { MTAB_XTD|MTAB_VUN, 0, "FORMAT", "FORMAT",
 
222
                &sim_tape_set_fmt, &sim_tape_show_fmt, NULL },
 
223
        { MTAB_XTD | MTAB_VDV, 0, NULL, "13181A",
 
224
                &ms_settype, NULL, NULL },
 
225
        { MTAB_XTD | MTAB_VDV, 1, NULL, "13183A",
 
226
                &ms_settype, NULL, NULL },
 
227
        { MTAB_XTD | MTAB_VDV, 0, "TYPE", NULL,
 
228
                NULL, &ms_showtype, NULL },
 
229
        { MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO",
 
230
                &hp_setdev, &hp_showdev, &msd_dev },
 
231
        { 0 }  };
 
232
 
 
233
DEVICE msc_dev = {
 
234
        "MSC", msc_unit, msc_reg, msc_mod,
 
235
        MS_NUMDR, 10, 31, 1, 8, 8,
 
236
        NULL, NULL, &msc_reset,
 
237
        &msc_boot, &msc_attach, &msc_detach,
 
238
        &msc_dib, DEV_DISABLE };
 
239
 
 
240
/* IOT routines */
 
241
 
 
242
int32 msdio (int32 inst, int32 IR, int32 dat)
 
243
{
 
244
int32 devd;
 
245
 
 
246
devd = IR & I_DEVMASK;                                  /* get device no */
 
247
switch (inst) {                                         /* case on opcode */
 
248
case ioFLG:                                             /* flag clear/set */
 
249
        if ((IR & I_HC) == 0) { setFLG (devd); }        /* STF */
 
250
        break;
 
251
case ioSFC:                                             /* skip flag clear */
 
252
        if (FLG (devd) == 0) PC = (PC + 1) & VAMASK;
 
253
        return dat;
 
254
case ioSFS:                                             /* skip flag set */
 
255
        if (FLG (devd) != 0) PC = (PC + 1) & VAMASK;
 
256
        return dat;
 
257
case ioOTX:                                             /* output */
 
258
        msd_buf = dat;                                  /* store data */
 
259
        break;
 
260
case ioMIX:                                             /* merge */
 
261
        dat = dat | msd_buf;
 
262
        break;
 
263
case ioLIX:                                             /* load */
 
264
        dat = msd_buf;
 
265
        break;
 
266
case ioCTL:                                             /* control clear/set */
 
267
        if (IR & I_CTL) {                               /* CLC */
 
268
            clrCTL (devd);                              /* clr ctl, cmd */
 
269
            clrCMD (devd);  }
 
270
        else {                                          /* STC */
 
271
            setCTL (devd);                              /* set ctl, cmd */
 
272
            setCMD (devd);  }
 
273
        break;
 
274
default:
 
275
        break;  }
 
276
if (IR & I_HC) { clrFLG (devd); }                       /* H/C option */
 
277
return dat;
 
278
}
 
279
 
 
280
int32 mscio (int32 inst, int32 IR, int32 dat)
 
281
{
 
282
int32 i, devc, devd;
 
283
t_stat st;
 
284
UNIT *uptr = msc_dev.units + msc_usl;
 
285
static const uint8 map_sel[16] = {
 
286
        0, 0, 1, 1, 2, 2, 2, 2,
 
287
        3, 3, 3, 3, 3, 3, 3, 3 };
 
288
 
 
289
devc = IR & I_DEVMASK;                                  /* get device no */
 
290
devd = devc - 1;
 
291
switch (inst) {                                         /* case on opcode */
 
292
case ioFLG:                                             /* flag clear/set */
 
293
        if ((IR & I_HC) == 0) { setFLG (devc); }        /* STF */
 
294
        break;
 
295
case ioSFC:                                             /* skip flag clear */
 
296
        if (FLG (devc) == 0) PC = (PC + 1) & VAMASK;
 
297
        return dat;
 
298
case ioSFS:                                             /* skip flag set */
 
299
        if (FLG (devc) != 0) PC = (PC + 1) & VAMASK;
 
300
        return dat;
 
301
case ioOTX:                                             /* output */
 
302
        msc_buf = dat;
 
303
        msc_sta = msc_sta & ~STA_REJ;                   /* clear reject */
 
304
        if ((dat & 0377) == FNC_CLR) break;             /* clear always ok */
 
305
        if (msc_sta & STA_BUSY) {                       /* busy? reject */
 
306
            msc_sta = msc_sta | STA_REJ;                /* dont chg select */
 
307
            break;  }
 
308
        if (dat & FNF_CHS) {                            /* select change */
 
309
            msc_usl = map_sel[FNC_GETSEL (dat)];        /* is immediate */
 
310
            uptr = msc_dev.units + msc_usl;  }
 
311
        if (((dat & FNF_MOT) && sim_is_active (uptr)) ||
 
312
            ((dat & FNF_REV) && (uptr->UST & STA_BOT)) ||
 
313
            ((dat & FNF_WRT) && sim_tape_wrp (uptr)))
 
314
            msc_sta = msc_sta | STA_REJ;                /* reject? */
 
315
        break;
 
316
case ioLIX:                                             /* load */
 
317
        dat = 0;
 
318
case ioMIX:                                             /* merge */
 
319
        dat = dat | ((msc_sta | uptr->UST) & ~STA_DYN);
 
320
        if (uptr->flags & UNIT_ATT) {                   /* online? */
 
321
            if (sim_is_active (uptr))                   /* busy */
 
322
                dat = dat | STA_TBSY;
 
323
            if (sim_tape_wrp (uptr))                    /* write prot? */
 
324
                dat = dat | STA_WLK;  }
 
325
        else dat = dat | STA_TBSY | STA_LOCAL;
 
326
        if (ms_ctype) dat = dat | STA_PE |              /* 13183A? */
 
327
            (msc_usl << STA_V_SEL);     
 
328
        break;
 
329
case ioCTL:                                             /* control clear/set */
 
330
        if (IR & I_CTL) { clrCTL (devc); }              /* CLC */
 
331
        else {                                          /* STC */
 
332
            if ((msc_buf & 0377) == FNC_CLR) {          /* clear? */
 
333
                for (i = 0; i < MS_NUMDR; i++) {        /* loop thru units */
 
334
                    if (sim_is_active (&msc_unit[i]) && /* write in prog? */
 
335
                        (msc_unit[i].FNC == FNC_WC) && (ms_ptr > 0)) {
 
336
                        if (st = sim_tape_wrrecf (uptr, msxb, ms_ptr | MTR_ERF))
 
337
                            ms_map_err (uptr, st);  }
 
338
                    if ((msc_unit[i].UST & STA_REW) == 0)
 
339
                        sim_cancel (&msc_unit[i]);  }   /* stop if now rew */
 
340
                clrCTL (devc);                          /* init device */
 
341
                setFLG (devc);
 
342
                clrCTL (devd);
 
343
                setFLG (devd);
 
344
                msc_sta = msd_buf = msc_buf = msc_1st = 0;
 
345
                return SCPE_OK;  }
 
346
            uptr->FNC = msc_buf & 0377;                 /* save function */
 
347
            if (uptr->FNC & FNF_RWD)                    /* rewind? */
 
348
                sim_activate (uptr, msc_rtime);         /* fast response */
 
349
            else sim_activate (uptr, msc_ctime);        /* schedule op */
 
350
            uptr->UST = 0;                              /* clear status */
 
351
            msc_sta = STA_BUSY;                         /* ctrl is busy */
 
352
            msc_1st = 1;
 
353
            setCTL (devc);  }                           /* go */
 
354
        break;
 
355
default:
 
356
        break;  }
 
357
if (IR & I_HC) { clrFLG (devc); }                       /* H/C option */
 
358
return dat;
 
359
}
 
360
 
 
361
/* Unit service
 
362
 
 
363
   If rewind done, reposition to start of tape, set status
 
364
   else, do operation, set done, interrupt
 
365
 
 
366
   Can't be write locked, can only write lock detached unit
 
367
*/
 
368
 
 
369
t_stat msc_svc (UNIT *uptr)
 
370
{
 
371
int32 devc, devd;
 
372
t_mtrlnt tbc;
 
373
t_stat st, r = SCPE_OK;
 
374
 
 
375
devc = msc_dib.devno;                                   /* get device nos */
 
376
devd = msd_dib.devno;
 
377
 
 
378
if ((uptr->flags & UNIT_ATT) == 0) {                    /* offline? */
 
379
        msc_sta = (msc_sta | STA_REJ) & ~STA_BUSY;      /* reject */
 
380
        setFLG (devc);                                  /* set cch flg */
 
381
        return IORETURN (msc_stopioe, SCPE_UNATT);  }
 
382
 
 
383
switch (uptr->FNC) {                                    /* case on function */
 
384
case FNC_REW:                                           /* rewind */
 
385
case FNC_RWS:                                           /* rewind offline */
 
386
        if (uptr->UST & STA_REW) {                      /* rewind in prog? */
 
387
            sim_tape_rewind (uptr);                     /* done */
 
388
            uptr->UST = STA_BOT;                        /* set BOT status */
 
389
            if (uptr->FNC & FNF_OFL) detach_unit (uptr);
 
390
            return SCPE_OK;  }
 
391
        uptr->UST = STA_REW;                            /* set rewinding */
 
392
        sim_activate (uptr, msc_ctime);                 /* sched completion */
 
393
        break;                                          /* "done" */
 
394
 
 
395
case FNC_GFM:                                           /* gap file mark */
 
396
case FNC_WFM:                                           /* write file mark */
 
397
        if (st = sim_tape_wrtmk (uptr))                 /* write tmk, err? */
 
398
            r = ms_map_err (uptr, st);                  /* map error */
 
399
        msc_sta = STA_EOF;                              /* set EOF status */
 
400
        break;
 
401
 
 
402
case FNC_GAP:                                           /* erase gap */
 
403
        break;
 
404
 
 
405
case FNC_FSR:                                           /* space forward */
 
406
        if (st = sim_tape_sprecf (uptr, &tbc))          /* space rec fwd, err? */
 
407
            r = ms_map_err (uptr, st);                  /* map error */
 
408
        if (tbc & 1) msc_sta = msc_sta | STA_ODD;
 
409
        else msc_sta = msc_sta & ~STA_ODD;
 
410
        break;
 
411
 
 
412
case FNC_BSR:
 
413
        if (st = sim_tape_sprecr (uptr, &tbc))          /* space rec rev, err? */
 
414
            r = ms_map_err (uptr, st);                  /* map error */
 
415
        if (tbc & 1) msc_sta = msc_sta | STA_ODD;
 
416
        else msc_sta = msc_sta & ~STA_ODD;
 
417
        break;
 
418
 
 
419
case FNC_FSF:
 
420
        while ((st = sim_tape_sprecf (uptr, &tbc)) == MTSE_OK) ;
 
421
        if (st == MTSE_TMK)                             /* stopped by tmk? */
 
422
            msc_sta = msc_sta | STA_EOF | STA_ODD;      /* normal status */
 
423
        else r = ms_map_err (uptr, st);                 /* map error */
 
424
        break;
 
425
 
 
426
case FNC_BSF:
 
427
        while ((st = sim_tape_sprecr (uptr, &tbc)) == MTSE_OK) ;
 
428
        if (st == MTSE_TMK)                             /* stopped by tmk? */
 
429
            msc_sta = msc_sta | STA_EOF | STA_ODD;      /* normal status */
 
430
        else r = ms_map_err (uptr, st);                 /* map error */
 
431
        break;
 
432
 
 
433
/* Unit service, continued */
 
434
 
 
435
case FNC_RFF:                                           /* diagnostic read */
 
436
case FNC_RC:                                            /* read */
 
437
        if (msc_1st) {                                  /* first svc? */
 
438
            msc_1st = ms_ptr = 0;                       /* clr 1st flop */
 
439
            st = sim_tape_rdrecf (uptr, msxb, &ms_max, DBSIZE); /* read rec */
 
440
            if (st == MTSE_RECE) msc_sta = msc_sta | STA_PAR;   /* rec in err? */
 
441
            else if (st != MTSE_OK) {                   /* other error? */
 
442
                r = ms_map_err (uptr, st);              /* map error */
 
443
                if (r == SCPE_OK) {                     /* recoverable? */
 
444
                    sim_activate (uptr, msc_gtime);     /* sched IRG */
 
445
                    uptr->FNC = 0;                      /* NOP func */
 
446
                    return SCPE_OK;  }
 
447
                break;  }                               /* err, done */
 
448
            }
 
449
        if (ms_ptr < ms_max) {                          /* more chars? */
 
450
            if (FLG (devd)) msc_sta = msc_sta | STA_TIM | STA_PAR;
 
451
            msd_buf = ((uint16) msxb[ms_ptr] << 8) | msxb[ms_ptr + 1];
 
452
            ms_ptr = ms_ptr + 2;
 
453
            setFLG (devd);                              /* set dch flg */
 
454
            sim_activate (uptr, msc_xtime);             /* re-activate */
 
455
            return SCPE_OK;  }
 
456
        sim_activate (uptr, msc_gtime);                 /* sched IRG */
 
457
        if (uptr->FNC == FNC_RFF) msc_1st = 1;          /* diagnostic? */
 
458
        else uptr->FNC = 0;                             /* NOP func */
 
459
        return SCPE_OK;
 
460
 
 
461
case FNC_WC:                                            /* write */
 
462
        if (msc_1st) msc_1st = ms_ptr = 0;              /* no xfer on first */
 
463
        else {                                          /* not 1st, next char */
 
464
            if (ms_ptr < DBSIZE) {                      /* room in buffer? */
 
465
                msxb[ms_ptr] = msd_buf >> 8;            /* store 2 char */
 
466
                msxb[ms_ptr + 1] = msd_buf & 0377;
 
467
                ms_ptr = ms_ptr + 2;
 
468
                uptr->UST = 0;  }
 
469
            else msc_sta = msc_sta | STA_PAR;  }
 
470
        if (CTL (devd)) {                               /* xfer flop set? */
 
471
            setFLG (devd);                              /* set dch flag */
 
472
            sim_activate (uptr, msc_xtime);             /* re-activate */
 
473
            return SCPE_OK;  }
 
474
        if (ms_ptr) {                                   /* any data? write */
 
475
            if (st = sim_tape_wrrecf (uptr, msxb, ms_ptr)) {    /* write, err? */
 
476
                r = ms_map_err (uptr, st);              /* map error */
 
477
                break;  }  }
 
478
        sim_activate (uptr, msc_gtime);                 /* sched IRG */
 
479
        uptr->FNC = 0;                                  /* NOP func */
 
480
        return SCPE_OK;
 
481
 
 
482
default:                                                /* unknown */
 
483
        break;  }
 
484
 
 
485
setFLG (devc);                                          /* set cch flg */
 
486
msc_sta = msc_sta & ~STA_BUSY;                          /* update status */
 
487
return SCPE_OK;
 
488
}
 
489
 
 
490
/* Map tape error status */
 
491
 
 
492
t_stat ms_map_err (UNIT *uptr, t_stat st)
 
493
{
 
494
switch (st) {
 
495
case MTSE_FMT:                                          /* illegal fmt */
 
496
case MTSE_UNATT:                                        /* unattached */
 
497
        msc_sta = msc_sta | STA_REJ;                    /* reject */
 
498
case MTSE_OK:                                           /* no error */
 
499
        return SCPE_IERR;                               /* never get here! */
 
500
case MTSE_TMK:                                          /* end of file */
 
501
        msc_sta = msc_sta | STA_EOF | STA_ODD;          /* eof (also sets odd) */
 
502
        break;
 
503
case MTSE_INVRL:                                        /* invalid rec lnt */
 
504
        msc_sta = msc_sta | STA_PAR;
 
505
        return SCPE_MTRLNT;
 
506
case MTSE_IOERR:                                        /* IO error */
 
507
        msc_sta = msc_sta | STA_PAR;                    /* error */
 
508
        if (msc_stopioe) return SCPE_IOERR;
 
509
        break;
 
510
case MTSE_RECE:                                         /* record in error */
 
511
case MTSE_EOM:                                          /* end of medium */
 
512
        msc_sta = msc_sta | STA_PAR;                    /* error */
 
513
        break;
 
514
case MTSE_BOT:                                          /* reverse into BOT */
 
515
        uptr->UST = STA_BOT;                            /* set status */
 
516
        break;
 
517
case MTSE_WRP:                                          /* write protect */
 
518
        msc_sta = msc_sta | STA_REJ;                    /* reject */
 
519
        break;  }
 
520
return SCPE_OK;
 
521
}
 
522
 
 
523
/* Reset routine */
 
524
 
 
525
t_stat msc_reset (DEVICE *dptr)
 
526
{
 
527
int32 i;
 
528
UNIT *uptr;
 
529
 
 
530
hp_enbdis_pair (&msc_dev, &msd_dev);                    /* make pair cons */
 
531
msc_buf = msd_buf = 0;
 
532
msc_sta = msc_usl = 0;
 
533
msc_1st = 0;
 
534
msc_dib.cmd = msd_dib.cmd = 0;                          /* clear cmd */
 
535
msc_dib.ctl = msd_dib.ctl = 0;                          /* clear ctl */
 
536
msc_dib.flg = msd_dib.flg = 1;                          /* set flg */
 
537
msc_dib.fbf = msd_dib.fbf = 1;                          /* set fbf */
 
538
for (i = 0; i < MS_NUMDR; i++) {
 
539
        uptr = msc_dev.units + i;
 
540
        sim_tape_reset (uptr);
 
541
        sim_cancel (uptr);
 
542
        uptr->UST = 0;  }
 
543
return SCPE_OK;
 
544
}
 
545
 
 
546
/* Attach routine */
 
547
 
 
548
t_stat msc_attach (UNIT *uptr, char *cptr)
 
549
{
 
550
t_stat r;
 
551
 
 
552
r = sim_tape_attach (uptr, cptr);                       /* attach unit */
 
553
if (r != SCPE_OK) return r;                             /* update status */
 
554
uptr->UST = STA_BOT;
 
555
return r;
 
556
}
 
557
 
 
558
/* Detach routine */
 
559
 
 
560
t_stat msc_detach (UNIT* uptr)
 
561
{
 
562
uptr->UST = 0;                                          /* update status */
 
563
return sim_tape_detach (uptr);                          /* detach unit */
 
564
}
 
565
 
 
566
/* Set controller type */
 
567
 
 
568
t_stat ms_settype (UNIT *uptr, int32 val, char *cptr, void *desc)
 
569
{
 
570
int32 i;
 
571
 
 
572
if ((val < 0) || (val > 1) || (cptr != NULL)) return SCPE_ARG;
 
573
for (i = 0; i < MS_NUMDR; i++) {
 
574
        if (msc_unit[i].flags & UNIT_ATT) return SCPE_ALATT;  }
 
575
ms_ctype = val;
 
576
return SCPE_OK;
 
577
}
 
578
 
 
579
/* Show controller type */
 
580
 
 
581
t_stat ms_showtype (FILE *st, UNIT *uptr, int32 val, void *desc)
 
582
{
 
583
if (ms_ctype) fprintf (st, "13183A");
 
584
else fprintf (st, "13181A");
 
585
return SCPE_OK;
 
586
}
 
587
 
 
588
/* 7970B/7970E bootstrap routine (HP 12992D ROM) */
 
589
 
 
590
#define CHANGE_DEV      (1 << 24)
 
591
 
 
592
static const int32 mboot[IBL_LNT] = {
 
593
        0106501,                /*ST LIB 1              ; read sw */
 
594
        0006011,                /*   SLB,RSS            ; bit 0 set? */
 
595
        0027714,                /*   JMP RD             ; no read */
 
596
        0003004,                /*   CMA,INA            ; A is ctr */
 
597
        0073775,                /*   STA WC             ; save */
 
598
        0067772,                /*   LDA SL0RW          ; sel 0, rew */
 
599
        0017762,                /*FF JSB CMD            ; do cmd */
 
600
        0102301+CHANGE_DEV,     /*   SFS CC             ; done? */
 
601
        0027707,                /*   JMP *-1            ; wait */
 
602
        0067774,                /*   LDB FFC            ; get file fwd */
 
603
        0037775,                /*   ISZ WC             ; done files? */
 
604
        0027706,                /*   JMP FF             ; no */
 
605
        0067773,                /*RD LDB RDCMD          ; read cmd */
 
606
        0017762,                /*   JSB CMD            ; do cmd */
 
607
        0103700+CHANGE_DEV,     /*   STC DC,C           ; start dch */
 
608
        0102201+CHANGE_DEV,     /*   SFC CC             ; read done? */
 
609
        0027752,                /*   JMP STAT           ; no, get stat */
 
610
        0102300+CHANGE_DEV,     /*   SFS DC             ; any data? */
 
611
        0027717,                /*   JMP *-3            ; wait */
 
612
        0107500+CHANGE_DEV,     /*   LIB DC,C           ; get rec cnt */
 
613
        0005727,                /*   BLF,BLF            ; move to lower */
 
614
        0007000,                /*   CMB                ; make neg */
 
615
        0077775,                /*   STA WC             ; save */
 
616
        0102201+CHANGE_DEV,     /*   SFC CC             ; read done? */
 
617
        0027752,                /*   JMP STAT           ; no, get stat */
 
618
        0102300+CHANGE_DEV,     /*   SFS DC             ; any data? */
 
619
        0027727,                /*   JMP *-3            ; wait */
 
620
        0107500+CHANGE_DEV,     /*   LIB DC,C           ; get load addr */
 
621
        0074000,                /*   STB 0              ; start csum */
 
622
        0077762,                /*   STA CMD            ; save address */
 
623
        0027742,                /*   JMP *+4 */
 
624
        0177762,                /*NW STB CMD,I          ; store data */
 
625
        0040001,                /*   ADA 1              ; add to csum */
 
626
        0037762,                /*   ISZ CMD            ; adv addr ptr */
 
627
        0102300+CHANGE_DEV,     /*   SFS DC             ; any data? */
 
628
        0027742,                /*   JMP *-1            ; wait */
 
629
        0107500+CHANGE_DEV,     /*   LIB DC,C           ; get word */
 
630
        0037775,                /*   ISZ WC             ; done? */
 
631
        0027737,                /*   JMP NW             ; no */
 
632
        0054000,                /*   CPB 0              ; csum ok? */
 
633
        0027717,                /*   JMP RD+3           ; yes, cont */
 
634
        0102011,                /*   HLT 11             ; no, halt */
 
635
        0102501+CHANGE_DEV,     /*ST LIA CC             ; get status */
 
636
        0001727,                /*   ALF,ALF            ; get eof bit */
 
637
        0002020,                /*   SSA                ; set? */
 
638
        0102077,                /*   HLT 77             ; done */
 
639
        0001727,                /*   ALF,ALF            ; put status back */
 
640
        0001310,                /*   RAR,SLA            ; read ok? */
 
641
        0102000,                /*   HLT 0              ; no */
 
642
        0027714,                /*   JMP RD             ; read next */
 
643
        0000000,                /*CMD 0 */
 
644
        0106601+CHANGE_DEV,     /*   OTB CC             ; output cmd */
 
645
        0102501+CHANGE_DEV,     /*   LIA CC             ; check for reject */
 
646
        0001323,                /*   RAR,RAR */
 
647
        0001310,                /*   RAR,SLA */
 
648
        0027763,                /*   JMP CMD+1          ; try again */
 
649
        0103701+CHANGE_DEV,     /*   STC CC,C           ; start command */
 
650
        0127762,                /*   JMP CMD,I          ; exit */
 
651
        0001501,                /*SL0RW 001501          ; select 0, rewind */
 
652
        0001423,                /*RDCMD 001423          ; read record */
 
653
        0000203,                /*FFC   000203          ; space forward file */
 
654
        0000000,                /*WC    000000 */
 
655
        0000000,
 
656
        0000000 };
 
657
 
 
658
t_stat msc_boot (int32 unitno, DEVICE *dptr)
 
659
{
 
660
int32 i, dev;
 
661
 
 
662
if (unitno != 0) return SCPE_NOFNC;                     /* only unit 0 */
 
663
dev = msd_dib.devno;                                    /* get data chan dev */
 
664
PC = ((MEMSIZE - 1) & ~IBL_MASK) & VAMASK;              /* start at mem top */
 
665
SR = IBL_MS + (dev << IBL_V_DEV);                       /* set SR */
 
666
if ((sim_switches & SWMASK ('S')) && AR) SR = SR | 1;   /* skip? */
 
667
for (i = 0; i < IBL_LNT; i++) {                         /* copy bootstrap */
 
668
        if (mboot[i] & CHANGE_DEV)                      /* IO instr? */
 
669
                M[PC + i] = (mboot[i] + dev) & DMASK;
 
670
        else M[PC + i] = mboot[i];  }   
 
671
return SCPE_OK;
 
672
}