home *** CD-ROM | disk | FTP | other *** search
- /* 18b PDP magnetic tape simulator
-
- Copyright (c) 1995, 1996, Robert M Supnik, Digital Equipment Corporation
- Commercial use prohibited
-
- mt TC59 magnetic tape for PDP-9
- TC59D magnetic tape for PDP-15
-
- Magnetic tapes are represented as a series of variable 16b records
- of the form:
-
- byte count
- byte 0'byte 1
- :
- byte n-2'byte n-1
-
- If the byte count is odd, the record is padded with an extra byte
- of junk. File marks are represented by a byte count of 0.
- */
-
- #include "pdp18b_defs.h"
-
- #define MT_NUMDR 8 /* #drives */
- #define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */
- #define UNIT_WLK 1 << UNIT_V_WLK
- #define USTAT u3 /* unit status */
- #define UNUM u4 /* unit number */
- #define SBSIZE (1 << 18) /* max space cmd */
- #define SBMASK (SBSIZE - 1)
- #define MT_WC 032 /* in core reg */
- #define MT_MA 033
-
- /* Command/unit - mt_cu */
-
- #define CU_V_UNIT 15 /* unit */
- #define CU_M_UNIT 07
- #define CU_PARITY 0040000 /* parity select */
- #define CU_DUMP 0020000 /* dump mode */
- #define CU_ERASE 0010000 /* ext rec gap */
- #define CU_V_CMD 9 /* command */
- #define CU_M_CMD 07
- #define FN_NOP 00
- #define FN_REWIND 01
- #define FN_READ 02
- #define FN_CMPARE 03
- #define FN_WRITE 04
- #define FN_WREOF 05
- #define FN_SPACEF 06
- #define FN_SPACER 07
- #define CU_IE 0000400 /* interrupt enable */
- #define CU_V_TYPE 6 /* drive type */
- #define CU_M_TYPE 03
- #define TY_9TK 3
- #define GET_UNIT(x) (((x) >> CU_V_UNIT) & CU_M_UNIT)
- #define GET_CMD(x) (((x) >> CU_V_CMD) & CU_M_CMD)
- #define GET_TYPE(x) (((x) >> CU_V_TYPE) & CU_M_TYPE)
- #define PACKED(x) (((x) & CU_DUMP) || (GET_TYPE (x) != TY_9TK))
-
- /* Status - stored in mt_sta or (*) uptr -> USTAT */
-
- #define STA_ERR 0400000 /* error */
- #define STA_REW 0200000 /* *rewinding */
- #define STA_BOT 0100000 /* *start of tape */
- #define STA_ILL 0040000 /* illegal cmd */
- #define STA_PAR 0020000 /* parity error */
- #define STA_EOF 0010000 /* *end of file */
- #define STA_EOT 0004000 /* *end of tape */
- #define STA_CPE 0002000 /* compare error */
- #define STA_RLE 0001000 /* rec lnt error */
- #define STA_DLT 0000400 /* data late */
- #define STA_BAD 0000200 /* bad tape */
- #define STA_DON 0000100 /* done */
-
- #define STA_CLR 0000077 /* always clear */
- #define STA_DYN (STA_REW | STA_BOT | STA_EOF | STA_EOT)
- /* kept in USTAT */
- #define STA_EFLGS (STA_BOT | STA_ILL | STA_PAR | STA_EOF | \
- STA_EOT | STA_CPE | STA_RLE | STA_DLT | STA_BAD)
- /* error flags */
-
- extern unsigned int M[];
- extern int int_req;
- extern UNIT cpu_unit;
- int mt_cu = 0; /* command/unit */
- int mt_sta = 0; /* status register */
- int mt_time = 10; /* record latency */
- int mt_stopioe = 1; /* stop on error */
- int mt_svc (UNIT *uptr);
- int mt_reset (DEVICE *dptr);
- int mt_attach (UNIT *uptr, char *cptr);
- int mt_detach (UNIT *uptr);
- int mt_updcsta (UNIT *uptr, int val);
- UNIT *mt_busy (void);
- extern int sim_activate (UNIT *uptr, int interval);
- extern int sim_cancel (UNIT *uptr);
- extern int sim_is_active (UNIT *uptr);
- extern int attach_unit (UNIT *uptr, char *cptr);
- extern int detach_unit (UNIT *uptr);
-
- /* MT data structures
-
- mt_dev MT device descriptor
- mt_unit MT unit list
- mt_reg MT register list
- mt_mod MT modifier list
- */
-
- UNIT mt_unit[] = {
- { UDATA (&mt_svc, UNIT_ATTABLE, 0) },
- { UDATA (&mt_svc, UNIT_ATTABLE, 0) },
- { UDATA (&mt_svc, UNIT_ATTABLE, 0) },
- { UDATA (&mt_svc, UNIT_ATTABLE, 0) },
- { UDATA (&mt_svc, UNIT_ATTABLE, 0) },
- { UDATA (&mt_svc, UNIT_ATTABLE, 0) },
- { UDATA (&mt_svc, UNIT_ATTABLE, 0) },
- { UDATA (&mt_svc, UNIT_ATTABLE, 0) } };
-
- REG mt_reg[] = {
- { ORDATA (STA, mt_sta, 18) },
- { ORDATA (CMD, mt_cu, 18) },
- { ORDATA (MA, M[MT_MA], 18) },
- { ORDATA (WC, M[MT_WC], 18) },
- { FLDATA (INT, int_req, INT_V_MTA) },
- { FLDATA (STOP_IOE, mt_stopioe, 0) },
- { DRDATA (TIME, mt_time, 24), PV_LEFT },
- { ORDATA (UST0, mt_unit[0].USTAT, 18) },
- { ORDATA (UST1, mt_unit[1].USTAT, 18) },
- { ORDATA (UST2, mt_unit[2].USTAT, 18) },
- { ORDATA (UST3, mt_unit[3].USTAT, 18) },
- { ORDATA (UST4, mt_unit[4].USTAT, 18) },
- { ORDATA (UST5, mt_unit[5].USTAT, 18) },
- { ORDATA (UST6, mt_unit[6].USTAT, 18) },
- { ORDATA (UST7, mt_unit[7].USTAT, 18) },
- { GRDATA (POS0, mt_unit[0].pos, 10, 31, 1), PV_LEFT + REG_RO },
- { GRDATA (POS1, mt_unit[1].pos, 10, 31, 1), PV_LEFT + REG_RO },
- { GRDATA (POS2, mt_unit[2].pos, 10, 31, 1), PV_LEFT + REG_RO },
- { GRDATA (POS3, mt_unit[3].pos, 10, 31, 1), PV_LEFT + REG_RO },
- { GRDATA (POS4, mt_unit[4].pos, 10, 31, 1), PV_LEFT + REG_RO },
- { GRDATA (POS5, mt_unit[5].pos, 10, 31, 1), PV_LEFT + REG_RO },
- { GRDATA (POS6, mt_unit[6].pos, 10, 31, 1), PV_LEFT + REG_RO },
- { GRDATA (POS7, mt_unit[7].pos, 10, 31, 1), PV_LEFT + REG_RO },
- { FLDATA (WLK0, mt_unit[0].flags, UNIT_V_WLK), REG_HRO },
- { FLDATA (WLK1, mt_unit[1].flags, UNIT_V_WLK), REG_HRO },
- { FLDATA (WLK2, mt_unit[2].flags, UNIT_V_WLK), REG_HRO },
- { FLDATA (WLK3, mt_unit[3].flags, UNIT_V_WLK), REG_HRO },
- { FLDATA (WLK4, mt_unit[4].flags, UNIT_V_WLK), REG_HRO },
- { FLDATA (WLK5, mt_unit[5].flags, UNIT_V_WLK), REG_HRO },
- { FLDATA (WLK6, mt_unit[6].flags, UNIT_V_WLK), REG_HRO },
- { FLDATA (WLK7, mt_unit[7].flags, UNIT_V_WLK), REG_HRO },
- { NULL } };
-
- MTAB mt_mod[] = {
- { UNIT_WLK, 0, "write enabled", "ENABLED", NULL },
- { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL },
- { 0 } };
-
- DEVICE mt_dev = {
- "MT", mt_unit, mt_reg, mt_mod,
- MT_NUMDR, 10, 32, 1, 8, 16,
- NULL, NULL, &mt_reset,
- NULL, &mt_attach, &mt_detach };
-
- /* IOT routine */
-
- int mt (int pulse, int AC)
- {
- int f;
- UNIT *uptr;
-
- uptr = mt_dev.units + GET_UNIT (mt_cu); /* get unit */
- mt_updcsta (uptr, 0); /* update status */
- if (pulse == 001) /* MTTR */
- return (!sim_is_active (uptr))? IOT_SKP + AC: AC;
- if (pulse == 021) /* MTCR */
- return (!mt_busy ())? IOT_SKP + AC: AC;
- if (pulse == 041) /* MTSF */
- return (mt_sta & (STA_ERR | STA_DON))? IOT_SKP + AC: AC;
- if (pulse == 002) return (mt_cu & 0777700); /* MTRC */
- if (pulse == 042) return mt_sta; /* MTRS */
- if ((pulse & 062) == 022) { /* MTAF, MTLC */
- if (!mt_busy ()) mt_cu = mt_sta = 0; /* if not busy, clr */
- mt_sta = mt_sta & ~(STA_ERR | STA_DON); } /* clear flags */
- if ((pulse & 064) == 024) /* MTCM, MTLC */
- mt_cu = (mt_cu & 0770700) | (AC & 0777700); /* load status */
- if (pulse == 004) { /* MTGO */
- f = GET_CMD (mt_cu); /* get function */
- if (mt_busy () || (sim_is_active (uptr)) ||
- (((f == FN_SPACER) || (f == FN_REWIND)) & (uptr -> pos == 0)) ||
- (((f == FN_WRITE) || (f == FN_WREOF)) && (uptr -> flags & UNIT_WLK))
- || ((uptr -> flags & UNIT_ATT) == 0) || (f == FN_NOP))
- mt_sta = mt_sta | STA_ILL; /* illegal op flag */
- else { if (f == FN_REWIND) uptr -> USTAT = STA_REW; /* rewind? */
- else mt_sta = uptr -> USTAT = 0; /* no, clear status */
- sim_activate (uptr, mt_time); } } /* start io */
- mt_updcsta (mt_dev.units + GET_UNIT (mt_cu), 0); /* update status */
- return AC;
- }
-
- /* Unit service
-
- If rewind done, reposition to start of tape, set status
- else, do operation, set done, interrupt
- */
-
- int mt_svc (UNIT *uptr)
- {
- int rval, c, f, i, p, u, err;
- int awc, wc, xma;
- unsigned short bc, sbuf[((SBSIZE * 3) / 2) + 1];
- static const unsigned short bceof = 0;
-
- u = uptr -> UNUM; /* get unit number */
- if (uptr -> USTAT & STA_REW) { /* rewind? */
- uptr -> pos = 0; /* update position */
- if (uptr -> flags & UNIT_ATT) uptr -> USTAT = STA_BOT;
- else uptr -> USTAT = 0;
- if (u == GET_UNIT (mt_cu)) mt_updcsta (uptr, STA_DON);
- return SCPE_OK; }
-
- f = GET_CMD (mt_cu); /* get command */
- if ((uptr -> flags & UNIT_ATT) == 0) { /* if not attached */
- mt_updcsta (uptr, STA_ILL); /* illegal operation */
- return IORETURN (mt_stopioe, SCPE_UNATT); }
-
- if ((f == FN_WRITE) || (f == FN_WREOF)) { /* write? */
- if (uptr -> flags & UNIT_WLK) { /* write locked? */
- mt_updcsta (uptr, STA_ILL); /* illegal operation */
- return SCPE_OK; }
- mt_cu = mt_cu & ~CU_ERASE; } /* clear erase flag */
-
- err = 0;
- rval = SCPE_OK;
- wc = 01000000 - M[MT_WC]; /* get word count */
- switch (f) { /* case on function */
-
- /* Unit service, continued */
-
- case FN_READ: /* read */
- case FN_CMPARE: /* read/compare */
- fseek (uptr -> fileref, uptr -> pos, SEEK_SET);
- fread (&bc, sizeof (short), 1, uptr -> fileref); /* read byte count */
- if ((err = ferror (uptr -> fileref)) || /* error or eof? */
- (feof (uptr -> fileref))) {
- uptr -> USTAT = STA_EOT;
- mt_updcsta (uptr, STA_RLE);
- break; }
- if (bc == 0) { /* tape mark? */
- uptr -> USTAT = STA_EOF;
- mt_updcsta (uptr, STA_RLE);
- uptr -> pos = uptr -> pos + sizeof (short);
- break; }
- awc = PACKED (mt_cu)? ((int) bc + 2) / 3: ((int) bc + 1) / 2;
- if (awc != wc) mt_sta = mt_sta | STA_RLE; /* wrong size? */
- if (awc < wc) wc = awc; /* use smaller */
- awc = PACKED (mt_cu)? (((wc * 3) + 1)/ 2): wc;
- i = fread (sbuf, sizeof (short), awc, uptr -> fileref);
- for ( ; i < awc; i++) sbuf[i] = 0; /* fill with 0's */
- err = ferror (uptr -> fileref);
- for (i = p = 0; i < wc; i++) { /* copy buffer */
- M[MT_MA] = (M[MT_MA] + 1) & 0777777;
- xma = M[MT_MA] & ADDRMASK;
- if (!PACKED (mt_cu)) c = sbuf[p++] & 0177777;
- else { if (i & 1) {
- c = (sbuf[p++] << 12) & 0770000;
- c = c | ((sbuf[p] >> 2) & 07700);
- c = c | (sbuf[p++] & 077); }
- else { c = (sbuf[p] << 4) & 0770000;
- c = c | ((sbuf[p++] << 6) & 07700);
- c = c | ((sbuf[p] >> 8) & 077); } }
- if ((f == FN_READ) && MEM_ADDR_OK (xma)) M[xma] = c;
- else if ((f == FN_CMPARE) && (c != (M[xma] &
- (PACKED (mt_cu)? 0777777: 0177777)))) {
- mt_updcsta (uptr, STA_CPE);
- break; }
- M[MT_WC] = (M[MT_WC] + 1) & 0777777; }
- uptr -> pos = uptr -> pos + (((int) bc + 1) & ~1) + sizeof (short);
- break;
- case FN_WRITE: /* write */
- fseek (uptr -> fileref, uptr -> pos, SEEK_SET);
- sbuf[0] = bc = PACKED (mt_cu)? wc * 3: wc * 2;
- for (i = 0, p = 1; i < wc; i++) { /* copy buf to tape */
- M[MT_MA] = (M[MT_MA] + 1) & 0777777;
- xma = M[MT_MA] & ADDRMASK;
- if (!PACKED (mt_cu)) sbuf[p++] = M[xma] & 0177777;
- else if (i & 1) {
- sbuf[p++] = c | ((M[xma] & 0770000) >> 12);
- sbuf[p++] = ((M[xma] & 07700) << 2) | (M[xma] & 077); }
- else { sbuf[p++] = ((M[xma] & 0770000) >> 4) |
- ((M[xma] & 07700) >> 6);
- sbuf[p] = c = (M[xma] & 077) << 8; }
- M[MT_WC] = (M[MT_WC] + 1) & 0777777; }
- fwrite (sbuf, sizeof (short), p + 1, uptr -> fileref);
- err = ferror (uptr -> fileref);
- uptr -> pos = uptr -> pos + (((int) bc + 1) & ~1) + sizeof (short);
- break;
-
- /* Unit service, continued */
-
- case FN_WREOF:
- fseek (uptr -> fileref, uptr -> pos, SEEK_SET);
- fwrite (&bceof, sizeof (short), 1, uptr -> fileref); /* write eof */
- err = ferror (uptr -> fileref);
- uptr -> pos = uptr -> pos + sizeof (short); /* update position */
- uptr -> USTAT = STA_EOF;
- break;
- case FN_SPACEF: /* space forward */
- do { fseek (uptr -> fileref, uptr -> pos, SEEK_SET);
- fread (&bc, sizeof (short), 1, uptr -> fileref); /* read bc */
- if ((err = ferror (uptr -> fileref)) || /* error or eof? */
- feof (uptr -> fileref)) {
- uptr -> USTAT = STA_EOT;
- break; }
- uptr -> pos = uptr -> pos + sizeof (short);
- if (bc == 0) { /* zero bc? */
- uptr -> USTAT = STA_EOF;
- break; }
- uptr -> pos = uptr -> pos + (((int) bc + 1) & ~1); }
- while ((M[MT_WC] = (M[MT_WC] + 1) & 0777777) != 0);
- break;
- case FN_SPACER: /* space reverse */
- for (i = 0; i < SBSIZE; i++) sbuf[i] = 0; /* clear table */
- for (i = 0, p = 0; p < uptr -> pos; ) { /* build table */
- fseek (uptr -> fileref, p, SEEK_SET);
- fread (&sbuf[i], sizeof (short), 1, uptr -> fileref);
- if ((err = ferror (uptr -> fileref)) ||
- (feof (uptr -> fileref))) {
- uptr -> pos = p;
- break; }
- p = p + sizeof (short) + (((int) sbuf[i] + 1) & ~1);
- i = (i + 1) & SBMASK; }
- if (uptr -> pos == 0) { /* at BOT? */
- uptr -> USTAT = STA_BOT;
- break; }
- do { i = (i - 1) & SBMASK;
- uptr -> pos = uptr -> pos - sizeof (short) -
- (((int) sbuf[i] + 1) & ~1);
- if (uptr -> pos == 0) uptr -> USTAT = STA_BOT;
- if (sbuf[i] == 0) uptr -> USTAT = STA_EOF;
- if (uptr -> USTAT & (STA_BOT | STA_EOF)) break; }
- while ((M[MT_WC] = (M[MT_WC] + 1) & 0777777) != 0);
- break; } /* end case */
-
- /* Unit service, continued */
-
- if (err != 0) { /* I/O error */
- mt_updcsta (uptr, STA_PAR); /* flag error */
- perror ("MT I/O error");
- rval = SCPE_IOERR;
- clearerr (uptr -> fileref); }
- mt_updcsta (uptr, STA_DON); /* set done */
- return IORETURN (mt_stopioe, rval);
- }
-
- /* Update controller status */
-
- int mt_updcsta (UNIT *uptr, int new)
- {
- mt_sta = (mt_sta & ~(STA_DYN | STA_ERR | STA_CLR)) |
- (uptr -> USTAT & STA_DYN) | new;
- if (mt_sta & STA_EFLGS) mt_sta = mt_sta | STA_ERR; /* error flag */
- if ((mt_sta & (STA_ERR | STA_DON)) && ((mt_cu & CU_IE) == 0))
- int_req = int_req | INT_MTA;
- else int_req = int_req & ~INT_MTA; /* int request */
- return mt_sta;
- }
-
- /* Test if controller busy */
-
- UNIT *mt_busy (void)
- {
- int u;
- UNIT *uptr;
-
- for (u = 0; u < MT_NUMDR; u++) { /* loop thru units */
- uptr = mt_dev.units + u;
- if (sim_is_active (uptr) && ((uptr -> USTAT & STA_REW) == 0))
- return uptr; }
- return NULL;
- }
-
- /* Reset routine */
-
- int mt_reset (DEVICE *dptr)
- {
- int i, u;
- UNIT *uptr;
-
- mt_cu = mt_sta = 0;
- for (u = 0; u < MT_NUMDR; u++) { /* loop thru units */
- uptr = mt_dev.units + u;
- uptr -> UNUM = u; /* init drive number */
- sim_cancel (uptr); /* cancel activity */
- if (uptr -> flags & UNIT_ATT) uptr -> USTAT = STA_BOT;
- else uptr -> USTAT = 0; }
- mt_updcsta (&mt_unit[0], 0); /* update status */
- return SCPE_OK;
- }
-
- /* IORS routine */
-
- int mt_iors (void)
- {
- return (mt_sta & (STA_ERR | STA_DON))? IOS_MTA: 0;
- }
-
- /* Attach routine */
-
- int mt_attach (UNIT *uptr, char *cptr)
- {
- int r;
-
- r = attach_unit (uptr, cptr);
- if (r != SCPE_OK) return r;
- uptr -> USTAT = STA_BOT;
- mt_updcsta (mt_dev.units + GET_UNIT (mt_cu), 0); /* update status */
- return r;
- }
-
- /* Detach routine */
-
- int mt_detach (UNIT* uptr)
- {
- if (!sim_is_active (uptr)) uptr -> USTAT = 0;
- mt_updcsta (mt_dev.units + GET_UNIT (mt_cu), 0); /* update status */
- return detach_unit (uptr);
- }
-