home *** CD-ROM | disk | FTP | other *** search
/ minnie.tuhs.org / unixen.tar / unixen / PDP-11 / Boot_Images / 2.11_on_rl02 / pdpsim.tz / pdpsim / pdp18b_mt.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-01-29  |  13.8 KB  |  427 lines

  1. /* 18b PDP magnetic tape simulator
  2.  
  3.    Copyright (c) 1995, 1996, Robert M Supnik, Digital Equipment Corporation
  4.    Commercial use prohibited
  5.  
  6.    mt        TC59 magnetic tape for PDP-9
  7.         TC59D magnetic tape for PDP-15
  8.  
  9.    Magnetic tapes are represented as a series of variable 16b records
  10.    of the form:
  11.  
  12.     byte count
  13.     byte 0'byte 1
  14.     :
  15.     byte n-2'byte n-1
  16.  
  17.    If the byte count is odd, the record is padded with an extra byte
  18.    of junk.  File marks are represented by a byte count of 0.
  19. */
  20.  
  21. #include "pdp18b_defs.h"
  22.  
  23. #define MT_NUMDR    8                /* #drives */
  24. #define UNIT_V_WLK    (UNIT_V_UF + 0)            /* write locked */
  25. #define UNIT_WLK    1 << UNIT_V_WLK
  26. #define USTAT        u3                /* unit status */
  27. #define UNUM        u4                /* unit number */
  28. #define SBSIZE        (1 << 18)            /* max space cmd */
  29. #define SBMASK        (SBSIZE - 1)
  30. #define MT_WC        032                /* in core reg */
  31. #define MT_MA        033
  32.  
  33. /* Command/unit - mt_cu */
  34.  
  35. #define CU_V_UNIT    15                /* unit */
  36. #define CU_M_UNIT    07
  37. #define CU_PARITY    0040000                /* parity select */
  38. #define CU_DUMP        0020000                /* dump mode */
  39. #define CU_ERASE    0010000                /* ext rec gap */
  40. #define CU_V_CMD    9                /* command */
  41. #define CU_M_CMD    07
  42. #define  FN_NOP         00
  43. #define  FN_REWIND     01
  44. #define  FN_READ     02
  45. #define  FN_CMPARE     03
  46. #define  FN_WRITE     04
  47. #define  FN_WREOF     05
  48. #define  FN_SPACEF     06
  49. #define  FN_SPACER     07
  50. #define CU_IE        0000400                /* interrupt enable */
  51. #define CU_V_TYPE    6                /* drive type */
  52. #define CU_M_TYPE    03
  53. #define  TY_9TK        3
  54. #define GET_UNIT(x)    (((x) >> CU_V_UNIT) & CU_M_UNIT)
  55. #define GET_CMD(x)    (((x) >> CU_V_CMD) & CU_M_CMD)
  56. #define GET_TYPE(x)    (((x) >> CU_V_TYPE) & CU_M_TYPE)
  57. #define PACKED(x)    (((x) & CU_DUMP) || (GET_TYPE (x) != TY_9TK))
  58.  
  59. /* Status - stored in mt_sta or (*) uptr -> USTAT */
  60.  
  61. #define STA_ERR        0400000                /* error */
  62. #define STA_REW        0200000                /* *rewinding */
  63. #define STA_BOT        0100000                /* *start of tape */
  64. #define STA_ILL        0040000                /* illegal cmd */
  65. #define STA_PAR        0020000                /* parity error */
  66. #define STA_EOF        0010000                /* *end of file */
  67. #define STA_EOT        0004000                /* *end of tape */
  68. #define STA_CPE        0002000                /* compare error */
  69. #define STA_RLE        0001000                /* rec lnt error */
  70. #define STA_DLT        0000400                /* data late */
  71. #define STA_BAD        0000200                /* bad tape */
  72. #define STA_DON        0000100                /* done */
  73.  
  74. #define STA_CLR        0000077                /* always clear */
  75. #define STA_DYN        (STA_REW | STA_BOT | STA_EOF | STA_EOT)
  76.                             /* kept in USTAT */
  77. #define STA_EFLGS    (STA_BOT | STA_ILL | STA_PAR | STA_EOF | \
  78.              STA_EOT | STA_CPE | STA_RLE | STA_DLT | STA_BAD)
  79.                             /* error flags */
  80.  
  81. extern unsigned int M[];
  82. extern int int_req;
  83. extern UNIT cpu_unit;
  84. int mt_cu = 0;                        /* command/unit */
  85. int mt_sta = 0;                        /* status register */
  86. int mt_time = 10;                    /* record latency */
  87. int mt_stopioe = 1;                    /* stop on error */
  88. int mt_svc (UNIT *uptr);
  89. int mt_reset (DEVICE *dptr);
  90. int mt_attach (UNIT *uptr, char *cptr);
  91. int mt_detach (UNIT *uptr);
  92. int mt_updcsta (UNIT *uptr, int val);
  93. UNIT *mt_busy (void);
  94. extern int sim_activate (UNIT *uptr, int interval);
  95. extern int sim_cancel (UNIT *uptr);
  96. extern int sim_is_active (UNIT *uptr);
  97. extern int attach_unit (UNIT *uptr, char *cptr);
  98. extern int detach_unit (UNIT *uptr);
  99.  
  100. /* MT data structures
  101.  
  102.    mt_dev    MT device descriptor
  103.    mt_unit    MT unit list
  104.    mt_reg    MT register list
  105.    mt_mod    MT modifier list
  106. */
  107.  
  108. UNIT mt_unit[] = {
  109.     { UDATA (&mt_svc, UNIT_ATTABLE, 0) },
  110.     { UDATA (&mt_svc, UNIT_ATTABLE, 0) },
  111.     { UDATA (&mt_svc, UNIT_ATTABLE, 0) },
  112.     { UDATA (&mt_svc, UNIT_ATTABLE, 0) },
  113.     { UDATA (&mt_svc, UNIT_ATTABLE, 0) },
  114.     { UDATA (&mt_svc, UNIT_ATTABLE, 0) },
  115.     { UDATA (&mt_svc, UNIT_ATTABLE, 0) },
  116.     { UDATA (&mt_svc, UNIT_ATTABLE, 0) }  };
  117.  
  118. REG mt_reg[] = {
  119.     { ORDATA (STA, mt_sta, 18) },
  120.     { ORDATA (CMD, mt_cu, 18) },
  121.     { ORDATA (MA, M[MT_MA], 18) },
  122.     { ORDATA (WC, M[MT_WC], 18) },
  123.     { FLDATA (INT, int_req, INT_V_MTA) },
  124.     { FLDATA (STOP_IOE, mt_stopioe, 0) },
  125.     { DRDATA (TIME, mt_time, 24), PV_LEFT },
  126.     { ORDATA (UST0, mt_unit[0].USTAT, 18) },
  127.     { ORDATA (UST1, mt_unit[1].USTAT, 18) },
  128.     { ORDATA (UST2, mt_unit[2].USTAT, 18) },
  129.     { ORDATA (UST3, mt_unit[3].USTAT, 18) },
  130.     { ORDATA (UST4, mt_unit[4].USTAT, 18) },
  131.     { ORDATA (UST5, mt_unit[5].USTAT, 18) },
  132.     { ORDATA (UST6, mt_unit[6].USTAT, 18) },
  133.     { ORDATA (UST7, mt_unit[7].USTAT, 18) },
  134.     { GRDATA (POS0, mt_unit[0].pos, 10, 31, 1), PV_LEFT + REG_RO },
  135.     { GRDATA (POS1, mt_unit[1].pos, 10, 31, 1), PV_LEFT + REG_RO },
  136.     { GRDATA (POS2, mt_unit[2].pos, 10, 31, 1), PV_LEFT + REG_RO },
  137.     { GRDATA (POS3, mt_unit[3].pos, 10, 31, 1), PV_LEFT + REG_RO },
  138.     { GRDATA (POS4, mt_unit[4].pos, 10, 31, 1), PV_LEFT + REG_RO },
  139.     { GRDATA (POS5, mt_unit[5].pos, 10, 31, 1), PV_LEFT + REG_RO },
  140.     { GRDATA (POS6, mt_unit[6].pos, 10, 31, 1), PV_LEFT + REG_RO },
  141.     { GRDATA (POS7, mt_unit[7].pos, 10, 31, 1), PV_LEFT + REG_RO },
  142.     { FLDATA (WLK0, mt_unit[0].flags, UNIT_V_WLK), REG_HRO },
  143.     { FLDATA (WLK1, mt_unit[1].flags, UNIT_V_WLK), REG_HRO },
  144.     { FLDATA (WLK2, mt_unit[2].flags, UNIT_V_WLK), REG_HRO },
  145.     { FLDATA (WLK3, mt_unit[3].flags, UNIT_V_WLK), REG_HRO },
  146.     { FLDATA (WLK4, mt_unit[4].flags, UNIT_V_WLK), REG_HRO },
  147.     { FLDATA (WLK5, mt_unit[5].flags, UNIT_V_WLK), REG_HRO },
  148.     { FLDATA (WLK6, mt_unit[6].flags, UNIT_V_WLK), REG_HRO },
  149.     { FLDATA (WLK7, mt_unit[7].flags, UNIT_V_WLK), REG_HRO },
  150.     { NULL }  };
  151.  
  152. MTAB mt_mod[] = {
  153.     { UNIT_WLK, 0, "write enabled", "ENABLED", NULL },
  154.     { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, 
  155.     { 0 }  };
  156.  
  157. DEVICE mt_dev = {
  158.     "MT", mt_unit, mt_reg, mt_mod,
  159.     MT_NUMDR, 10, 32, 1, 8, 16,
  160.     NULL, NULL, &mt_reset,
  161.     NULL, &mt_attach, &mt_detach };
  162.  
  163. /* IOT routine */
  164.  
  165. int mt (int pulse, int AC)
  166. {
  167. int f;
  168. UNIT *uptr;
  169.  
  170. uptr = mt_dev.units + GET_UNIT (mt_cu);            /* get unit */
  171. mt_updcsta (uptr, 0);                    /* update status */
  172. if (pulse == 001)                    /* MTTR */
  173.     return (!sim_is_active (uptr))? IOT_SKP + AC: AC;
  174. if (pulse == 021)                    /* MTCR */
  175.     return (!mt_busy ())? IOT_SKP + AC: AC;
  176. if (pulse == 041)                    /* MTSF */
  177.     return (mt_sta & (STA_ERR | STA_DON))? IOT_SKP + AC: AC;
  178. if (pulse == 002) return (mt_cu & 0777700);        /* MTRC */
  179. if (pulse == 042) return mt_sta;            /* MTRS */
  180. if ((pulse & 062) == 022) {                /* MTAF, MTLC */
  181.     if (!mt_busy ()) mt_cu = mt_sta = 0;        /* if not busy, clr */
  182.     mt_sta = mt_sta & ~(STA_ERR | STA_DON);  }    /* clear flags */
  183. if ((pulse & 064) == 024)                /* MTCM, MTLC  */
  184.     mt_cu = (mt_cu & 0770700) | (AC & 0777700);    /* load status */
  185. if (pulse == 004) {                    /* MTGO */
  186.     f = GET_CMD (mt_cu);                /* get function */
  187.     if (mt_busy () || (sim_is_active (uptr)) ||
  188.        (((f == FN_SPACER) || (f == FN_REWIND)) & (uptr -> pos == 0)) ||
  189.        (((f == FN_WRITE) || (f == FN_WREOF)) && (uptr -> flags & UNIT_WLK))
  190.        || ((uptr -> flags & UNIT_ATT) == 0) || (f == FN_NOP))
  191.         mt_sta = mt_sta | STA_ILL;        /* illegal op flag */
  192.     else {    if (f == FN_REWIND) uptr -> USTAT = STA_REW;    /* rewind? */
  193.         else mt_sta = uptr -> USTAT = 0;    /* no, clear status */
  194.         sim_activate (uptr, mt_time);  }  }    /* start io */
  195. mt_updcsta (mt_dev.units + GET_UNIT (mt_cu), 0);    /* update status */
  196. return AC;
  197. }
  198.  
  199. /* Unit service
  200.  
  201.    If rewind done, reposition to start of tape, set status
  202.    else, do operation, set done, interrupt
  203. */
  204.  
  205. int mt_svc (UNIT *uptr)
  206. {
  207. int rval, c, f, i, p, u, err;
  208. int awc, wc, xma;
  209. unsigned short bc, sbuf[((SBSIZE * 3) / 2) + 1];
  210. static const unsigned short bceof = 0;
  211.  
  212. u = uptr -> UNUM;                    /* get unit number */
  213. if (uptr -> USTAT & STA_REW) {                /* rewind? */
  214.     uptr -> pos = 0;                /* update position */
  215.     if (uptr -> flags & UNIT_ATT) uptr -> USTAT = STA_BOT;
  216.     else uptr -> USTAT = 0;
  217.     if (u == GET_UNIT (mt_cu)) mt_updcsta (uptr, STA_DON);
  218.     return SCPE_OK;  }
  219.  
  220. f = GET_CMD (mt_cu);                    /* get command */
  221. if ((uptr -> flags & UNIT_ATT) == 0) {            /* if not attached */
  222.     mt_updcsta (uptr, STA_ILL);            /* illegal operation */
  223.     return IORETURN (mt_stopioe, SCPE_UNATT);  }
  224.  
  225. if ((f == FN_WRITE) || (f == FN_WREOF)) {        /* write? */
  226.     if (uptr -> flags & UNIT_WLK) {            /* write locked? */
  227.         mt_updcsta (uptr, STA_ILL);        /* illegal operation */
  228.         return SCPE_OK;  }
  229.     mt_cu = mt_cu & ~CU_ERASE;  }            /* clear erase flag */
  230.  
  231. err = 0;
  232. rval = SCPE_OK;
  233. wc = 01000000 - M[MT_WC];                /* get word count */
  234. switch (f) {                        /* case on function */
  235.  
  236. /* Unit service, continued */
  237.  
  238. case FN_READ:                        /* read */
  239. case FN_CMPARE:                        /* read/compare */
  240.     fseek (uptr -> fileref, uptr -> pos, SEEK_SET);
  241.     fread (&bc, sizeof (short), 1, uptr -> fileref); /* read byte count */
  242.     if ((err = ferror (uptr -> fileref)) ||        /* error or eof? */
  243.         (feof (uptr -> fileref))) {
  244.         uptr -> USTAT = STA_EOT;
  245.         mt_updcsta (uptr, STA_RLE);
  246.         break;  }
  247.     if (bc == 0) {                    /* tape mark? */
  248.         uptr -> USTAT = STA_EOF;
  249.         mt_updcsta (uptr, STA_RLE);
  250.         uptr -> pos = uptr -> pos + sizeof (short);
  251.         break;  }
  252.     awc = PACKED (mt_cu)? ((int) bc + 2) / 3: ((int) bc + 1) / 2;
  253.     if (awc != wc) mt_sta = mt_sta | STA_RLE;    /* wrong size? */
  254.     if (awc < wc) wc = awc;                /* use smaller */
  255.     awc = PACKED (mt_cu)? (((wc * 3) + 1)/ 2): wc;
  256.     i = fread (sbuf, sizeof (short), awc, uptr -> fileref);
  257.     for ( ; i < awc; i++) sbuf[i] = 0;        /* fill with 0's */
  258.     err = ferror (uptr -> fileref);
  259.     for (i = p = 0; i < wc; i++) {            /* copy buffer */
  260.         M[MT_MA] = (M[MT_MA] + 1) & 0777777;
  261.         xma = M[MT_MA] & ADDRMASK;
  262.         if (!PACKED (mt_cu)) c = sbuf[p++] & 0177777;
  263.             else {    if (i & 1) {
  264.                 c = (sbuf[p++] << 12) & 0770000;
  265.                 c = c | ((sbuf[p] >> 2) & 07700);
  266.                 c = c | (sbuf[p++] & 077);  }
  267.             else {    c = (sbuf[p] << 4) & 0770000;
  268.                     c = c | ((sbuf[p++] << 6) & 07700);
  269.                 c = c | ((sbuf[p] >> 8) & 077);  }  }
  270.         if ((f == FN_READ) && MEM_ADDR_OK (xma)) M[xma] = c;
  271.         else if ((f == FN_CMPARE) && (c != (M[xma] &
  272.             (PACKED (mt_cu)? 0777777: 0177777)))) {
  273.             mt_updcsta (uptr, STA_CPE);
  274.             break;  }
  275.         M[MT_WC] = (M[MT_WC] + 1) & 0777777;  }
  276.     uptr -> pos = uptr -> pos + (((int) bc + 1) & ~1) + sizeof (short);
  277.     break;
  278. case FN_WRITE:                        /* write */
  279.     fseek (uptr -> fileref, uptr -> pos, SEEK_SET);
  280.     sbuf[0] = bc = PACKED (mt_cu)? wc * 3: wc * 2;
  281.     for (i = 0, p = 1; i < wc; i++) {        /* copy buf to tape */
  282.         M[MT_MA] = (M[MT_MA] + 1) & 0777777;
  283.         xma = M[MT_MA] & ADDRMASK;
  284.         if (!PACKED (mt_cu)) sbuf[p++] = M[xma] & 0177777;
  285.         else if (i & 1) {
  286.             sbuf[p++] = c | ((M[xma] & 0770000) >> 12);
  287.             sbuf[p++] = ((M[xma] & 07700) << 2) | (M[xma] & 077); }
  288.         else {    sbuf[p++] = ((M[xma] & 0770000) >> 4) |
  289.                     ((M[xma] & 07700) >> 6);
  290.             sbuf[p] = c = (M[xma] & 077) << 8;  }
  291.         M[MT_WC] = (M[MT_WC] + 1) & 0777777;  }
  292.     fwrite (sbuf, sizeof (short), p + 1, uptr -> fileref);
  293.     err = ferror (uptr -> fileref);
  294.     uptr -> pos = uptr -> pos + (((int) bc + 1) & ~1) + sizeof (short);
  295.     break;
  296.  
  297. /* Unit service, continued */
  298.  
  299. case FN_WREOF:
  300.     fseek (uptr -> fileref, uptr -> pos, SEEK_SET);
  301.     fwrite (&bceof, sizeof (short), 1, uptr -> fileref); /* write eof */
  302.     err = ferror (uptr -> fileref);
  303.     uptr -> pos = uptr -> pos + sizeof (short);    /* update position */
  304.     uptr -> USTAT = STA_EOF;
  305.     break;
  306. case FN_SPACEF:                        /* space forward */
  307.     do {    fseek (uptr -> fileref, uptr -> pos, SEEK_SET);
  308.         fread (&bc, sizeof (short), 1, uptr -> fileref); /* read bc */
  309.         if ((err = ferror (uptr -> fileref)) ||    /* error or eof? */
  310.              feof (uptr -> fileref)) {
  311.             uptr -> USTAT = STA_EOT;
  312.             break;  }
  313.         uptr -> pos = uptr -> pos + sizeof (short);
  314.         if (bc == 0) {                /* zero bc? */
  315.             uptr -> USTAT = STA_EOF;
  316.             break;  }
  317.         uptr -> pos = uptr -> pos + (((int) bc + 1) & ~1);  }
  318.     while ((M[MT_WC] = (M[MT_WC] + 1) & 0777777) != 0);
  319.     break;
  320. case FN_SPACER:                        /* space reverse */
  321.     for (i = 0; i < SBSIZE; i++) sbuf[i] = 0;    /* clear table */
  322.     for (i = 0, p = 0; p < uptr -> pos; ) {        /* build table */
  323.         fseek (uptr -> fileref, p, SEEK_SET);
  324.         fread (&sbuf[i], sizeof (short), 1, uptr -> fileref);
  325.         if ((err = ferror (uptr -> fileref)) ||
  326.             (feof (uptr -> fileref))) {
  327.             uptr -> pos = p;
  328.             break;  }
  329.         p = p + sizeof (short) + (((int) sbuf[i] + 1) & ~1);
  330.         i = (i + 1) & SBMASK;  }
  331.     if (uptr -> pos == 0) {                /* at BOT? */
  332.         uptr -> USTAT = STA_BOT;
  333.         break;  }
  334.     do {    i = (i - 1) & SBMASK;
  335.         uptr -> pos = uptr -> pos - sizeof (short) -
  336.             (((int) sbuf[i] + 1) & ~1);
  337.         if (uptr -> pos == 0) uptr -> USTAT = STA_BOT;
  338.         if (sbuf[i] == 0) uptr -> USTAT = STA_EOF;
  339.         if (uptr -> USTAT & (STA_BOT | STA_EOF)) break;  }
  340.     while ((M[MT_WC] = (M[MT_WC] + 1) & 0777777) != 0);
  341.     break;  }                    /* end case */
  342.  
  343. /* Unit service, continued */
  344.  
  345. if (err != 0) {                        /* I/O error */
  346.     mt_updcsta (uptr, STA_PAR);            /* flag error */
  347.     perror ("MT I/O error");
  348.     rval = SCPE_IOERR;
  349.     clearerr (uptr -> fileref);  }
  350. mt_updcsta (uptr, STA_DON);                /* set done */
  351. return IORETURN (mt_stopioe, rval);
  352. }
  353.  
  354. /* Update controller status */
  355.  
  356. int mt_updcsta (UNIT *uptr, int new)
  357. {
  358. mt_sta = (mt_sta & ~(STA_DYN | STA_ERR | STA_CLR)) |
  359.     (uptr -> USTAT & STA_DYN) | new;
  360. if (mt_sta & STA_EFLGS) mt_sta = mt_sta | STA_ERR;    /* error flag */
  361. if ((mt_sta & (STA_ERR | STA_DON)) && ((mt_cu & CU_IE) == 0))
  362.     int_req = int_req | INT_MTA;
  363. else int_req = int_req & ~INT_MTA;            /* int request */
  364. return mt_sta;
  365. }
  366.  
  367. /* Test if controller busy */
  368.  
  369. UNIT *mt_busy (void)
  370. {
  371. int u;
  372. UNIT *uptr;
  373.  
  374. for (u = 0; u < MT_NUMDR; u++) {            /* loop thru units */
  375.     uptr = mt_dev.units + u;
  376.     if (sim_is_active (uptr) && ((uptr -> USTAT & STA_REW) == 0))
  377.         return uptr;  }
  378. return NULL;
  379. }
  380.  
  381. /* Reset routine */
  382.  
  383. int mt_reset (DEVICE *dptr)
  384. {
  385. int i, u;
  386. UNIT *uptr;
  387.  
  388. mt_cu = mt_sta = 0;
  389. for (u = 0; u < MT_NUMDR; u++) {            /* loop thru units */
  390.     uptr = mt_dev.units + u;
  391.     uptr -> UNUM = u;                /* init drive number */
  392.     sim_cancel (uptr);                /* cancel activity */
  393.     if (uptr -> flags & UNIT_ATT) uptr -> USTAT = STA_BOT;
  394.     else uptr -> USTAT = 0;  }
  395. mt_updcsta (&mt_unit[0], 0);                /* update status */
  396. return SCPE_OK;
  397. }
  398.  
  399. /* IORS routine */
  400.  
  401. int mt_iors (void)
  402. {
  403. return (mt_sta & (STA_ERR | STA_DON))? IOS_MTA: 0;
  404. }
  405.  
  406. /* Attach routine */
  407.  
  408. int mt_attach (UNIT *uptr, char *cptr)
  409. {
  410. int r;
  411.  
  412. r = attach_unit (uptr, cptr);
  413. if (r != SCPE_OK) return r;
  414. uptr -> USTAT = STA_BOT;
  415. mt_updcsta (mt_dev.units + GET_UNIT (mt_cu), 0);    /* update status */
  416. return r;
  417. }
  418.  
  419. /* Detach routine */
  420.  
  421. int mt_detach (UNIT* uptr)
  422. {
  423. if (!sim_is_active (uptr)) uptr -> USTAT = 0;
  424. mt_updcsta (mt_dev.units + GET_UNIT (mt_cu), 0);    /* update status */
  425. return detach_unit (uptr);
  426. }
  427.