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

  1. /* NOVA magnetic tape simulator
  2.  
  3.    Copyright (c) 1995, 1996, Robert M Supnik, Digital Equipment Corporation
  4.    Commercial use prohibited
  5.  
  6.    mta        magnetic tape
  7.  
  8.    Magnetic tapes are represented as a series of variable 16b records
  9.    of the form:
  10.  
  11.     byte count
  12.     byte 0'byte 1
  13.     :
  14.     byte n-2'byte n-1
  15.  
  16.    If the byte count is odd, the record is padded with an extra byte
  17.    of junk.  File marks are represented by a byte count of 0; end of
  18.    tape by end of file.
  19. */
  20.  
  21. #include "nova_defs.h"
  22.  
  23. #define MTA_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 << 16)            /* max space cmd */
  29. #define SBMASK        (SBSIZE - 1)
  30. #define DTSIZE        (1 << 14)            /* max data xfer */
  31. #define DTMASK        (DTSIZE - 1)
  32.  
  33. /* Command/unit */
  34.  
  35. #define    CU_CI        0100000                /* clear interrupt */
  36. #define CU_EP        0002000                /* poll enable */
  37. #define CU_DE        0001000                /* disable erase */
  38. #define CU_DA        0000400                /* disable autoretry */
  39. #define CU_PE        0000400                /* PE mode */
  40. #define CU_V_CMD    3                /* command */
  41. #define CU_M_CMD    027
  42. #define  CU_READ     000
  43. #define  CU_REWIND     001
  44. #define  CU_CMODE     002
  45. #define  CU_SPACEF     003
  46. #define  CU_SPACER     004
  47. #define  CU_WRITE     005
  48. #define  CU_WREOF     006
  49. #define  CU_ERASE     007
  50. #define  CU_READNS     020
  51. #define  CU_UNLOAD     021
  52. #define  CU_DMODE     022
  53. #define CU_V_UNIT    0                /* unit */
  54. #define CU_M_UNIT    07
  55. #define GET_CMD(x)    (((x) >> CU_V_CMD) & CU_M_CMD)
  56. #define GET_UNIT(x)    (((x) >> CU_V_UNIT) & CU_M_UNIT)
  57.  
  58. /* Status 1 - stored in mta_sta<31:16> or (*) uptr -> USTAT<31:16> */
  59.  
  60. #define STA_ERR1    (0100000u << 16)        /* error */
  61. #define STA_DLT        (0040000 << 16)            /* data late */
  62. #define STA_REW        (0020000 << 16)            /* *rewinding */
  63. #define STA_ILL        (0010000 << 16)            /* illegal */
  64. #define STA_HDN        (0004000 << 16)            /* high density */
  65. #define STA_DAE        (0002000 << 16)            /* data error */
  66. #define STA_EOT        (0001000 << 16)            /* *end of tape */
  67. #define STA_EOF        (0000400 << 16)            /* *end of file */
  68. #define STA_BOT        (0000200 << 16)            /* *start of tape */
  69. #define STA_9TK        (0000100 << 16)            /* nine track */
  70. #define STA_BAT        (0000040 << 16)            /* bad tape */
  71. #define STA_CHG        (0000010 << 16)            /* status change */
  72. #define STA_WLK        (0000004 << 16)            /* *write lock */
  73. #define STA_ODD        (0000002 << 16)            /* odd character */
  74. #define STA_RDY        (0000001 << 16)            /* *drive ready */
  75.  
  76. /* Status 2 - stored in mta_sta<15:0> or (*) uptr -> USTAT<15:0> */
  77.  
  78. #define STA_ERR2    0100000                /* error */
  79. #define STA_RWY        0040000                /* runaway tape */
  80. #define STA_FGP        0020000                /* false gap */
  81. #define STA_CDL        0004000                /* corrected dlt */
  82. #define STA_V_UNIT    8
  83. #define STA_M_UNIT    07                /* unit */
  84. #define STA_WCO        0000200                /* word count ovflo */
  85. #define STA_BDS        0000100                /* bad signal */
  86. #define STA_OVS        0000040                /* overskew */
  87. #define STA_CRC        0000020                /* check error */
  88. #define STA_STE        0000010                /* single trk error */
  89. #define STA_FPR        0000004                /* false preamble */
  90. #define STA_FMT        0000002                /* format error */
  91. #define STA_PEM        0000001                /* *PE mode */
  92.  
  93. #define STA_EFLGS1     (STA_DLT | STA_ILL | STA_DAE | STA_EOT | \
  94.              STA_EOF | STA_BOT | STA_BAT | STA_ODD)
  95. #define STA_EFLGS2    (STA_FGP | STA_CDL | STA_BDS | STA_OVS | \
  96.              STA_CRC | STA_FPR | STA_FPR)    /* set error 2 */
  97. #define STA_CLR        ((020 << 16) | 0010000)        /* always clear */
  98. #define STA_SET        (STA_HDN | STA_9TK)        /* always set */
  99. #define STA_DYN        (STA_REW | STA_EOT | STA_EOF | STA_BOT | \
  100.              STA_WLK | STA_RDY | STA_PEM)    /* kept in USTAT */
  101. #define STA_MON        (STA_REW | STA_BOT | STA_WLK | STA_RDY | \
  102.              STA_PEM)            /* set status chg */
  103.  
  104. extern unsigned short M[];
  105. extern UNIT cpu_unit;
  106. extern int int_req, dev_busy, dev_done, dev_disable;
  107. int mta_ma = 0;                        /* memory address */
  108. int mta_wc = 0;                        /* word count */
  109. int mta_cu = 0;                        /* command/unit */
  110. int mta_sta = 0;                    /* status register */
  111. int mta_ep = 0;                        /* enable polling */
  112. int mta_cwait = 100;                    /* command latency */
  113. int mta_rwait = 100;                    /* record latency */
  114. int mta_svc (UNIT *uptr);
  115. int mta_reset (DEVICE *dptr);
  116. int mta_boot (int unitno);
  117. int mta_attach (UNIT *uptr, char *cptr);
  118. int mta_detach (UNIT *uptr);
  119. int mta_updcsta (UNIT *uptr);
  120. void mta_upddsta (UNIT *uptr, int newsta);
  121. int mta_vlock (UNIT *uptr, int val);
  122. extern int sim_activate (UNIT *uptr, int interval);
  123. extern int sim_cancel (UNIT *uptr);
  124. extern int sim_is_active (UNIT *uptr);
  125. extern int attach_unit (UNIT *uptr, char *cptr);
  126. extern int detach_unit (UNIT *uptr);
  127. static const int ctype[32] = {                /* c vs r timing */
  128.  0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
  129.  0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1  };
  130.  
  131. /* MTA data structures
  132.  
  133.    mta_dev    MTA device descriptor
  134.    mta_unit    MTA unit list
  135.    mta_reg    MTA register list
  136.    mta_mod    MTA modifier list
  137. */
  138.  
  139. UNIT mta_unit[] = {
  140.     { UDATA (&mta_svc, UNIT_ATTABLE, 0) },
  141.     { UDATA (&mta_svc, UNIT_ATTABLE, 0) },
  142.     { UDATA (&mta_svc, UNIT_ATTABLE, 0) },
  143.     { UDATA (&mta_svc, UNIT_ATTABLE, 0) },
  144.     { UDATA (&mta_svc, UNIT_ATTABLE, 0) },
  145.     { UDATA (&mta_svc, UNIT_ATTABLE, 0) },
  146.     { UDATA (&mta_svc, UNIT_ATTABLE, 0) },
  147.     { UDATA (&mta_svc, UNIT_ATTABLE, 0) }  };
  148.  
  149. REG mta_reg[] = {
  150.     { ORDATA (CU, mta_cu, 16) },
  151.     { ORDATA (MA, mta_ma, 16) },
  152.     { ORDATA (WC, mta_wc, 16) },
  153.     { GRDATA (STA1, mta_sta, 8, 16, 16) },
  154.     { ORDATA (STA2, mta_sta, 16) },
  155.     { FLDATA (EP, mta_ep, 0) },
  156.     { FLDATA (BUSY, dev_busy, INT_V_MTA) },
  157.     { FLDATA (DONE, dev_done, INT_V_MTA) },
  158.     { FLDATA (DISABLE, dev_disable, INT_V_MTA) },
  159.     { FLDATA (INT, int_req, INT_V_MTA) },
  160.     { DRDATA (CTIME, mta_cwait, 24), PV_LEFT },
  161.     { DRDATA (RTIME, mta_rwait, 24), PV_LEFT },
  162.     { ORDATA (UST0, mta_unit[0].USTAT, 32) },
  163.     { ORDATA (UST1, mta_unit[1].USTAT, 32) },
  164.     { ORDATA (UST2, mta_unit[2].USTAT, 32) },
  165.     { ORDATA (UST3, mta_unit[3].USTAT, 32) },
  166.     { ORDATA (UST4, mta_unit[4].USTAT, 32) },
  167.     { ORDATA (UST5, mta_unit[5].USTAT, 32) },
  168.     { ORDATA (UST6, mta_unit[6].USTAT, 32) },
  169.     { ORDATA (UST7, mta_unit[7].USTAT, 32) },
  170.     { GRDATA (POS0, mta_unit[0].pos, 10, 31, 1), REG_RO + PV_LEFT },
  171.     { GRDATA (POS1, mta_unit[1].pos, 10, 31, 1), REG_RO + PV_LEFT },
  172.     { GRDATA (POS2, mta_unit[2].pos, 10, 31, 1), REG_RO + PV_LEFT },
  173.     { GRDATA (POS3, mta_unit[3].pos, 10, 31, 1), REG_RO + PV_LEFT },
  174.     { GRDATA (POS4, mta_unit[4].pos, 10, 31, 1), REG_RO + PV_LEFT },
  175.     { GRDATA (POS5, mta_unit[5].pos, 10, 31, 1), REG_RO + PV_LEFT },
  176.     { GRDATA (POS6, mta_unit[6].pos, 10, 31, 1), REG_RO + PV_LEFT },
  177.     { GRDATA (POS7, mta_unit[7].pos, 10, 31, 1), REG_RO + PV_LEFT },
  178.     { FLDATA (WLK0, mta_unit[0].flags, UNIT_V_WLK), REG_HRO },
  179.     { FLDATA (WLK1, mta_unit[1].flags, UNIT_V_WLK), REG_HRO },
  180.     { FLDATA (WLK2, mta_unit[2].flags, UNIT_V_WLK), REG_HRO },
  181.     { FLDATA (WLK3, mta_unit[3].flags, UNIT_V_WLK), REG_HRO },
  182.     { FLDATA (WLK4, mta_unit[4].flags, UNIT_V_WLK), REG_HRO },
  183.     { FLDATA (WLK5, mta_unit[5].flags, UNIT_V_WLK), REG_HRO },
  184.     { FLDATA (WLK6, mta_unit[6].flags, UNIT_V_WLK), REG_HRO },
  185.     { FLDATA (WLK7, mta_unit[7].flags, UNIT_V_WLK), REG_HRO },
  186.     { NULL }  };
  187.  
  188. MTAB mta_mod[] = {
  189.     { UNIT_WLK, 0, "write enabled", "ENABLED", &mta_vlock },
  190.     { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", &mta_vlock },
  191.     { 0 }  };
  192.  
  193. DEVICE mta_dev = {
  194.     "MT", mta_unit, mta_reg, mta_mod,
  195.     MTA_NUMDR, 10, 32, 1, 8, 16,
  196.     NULL, NULL, &mta_reset,
  197.     &mta_boot, &mta_attach, &mta_detach };
  198.  
  199. /* IOT routine */
  200.  
  201. int mta (int pulse, int code, int AC)
  202. {
  203. UNIT *uptr;
  204. int u, c, rval;
  205.  
  206. rval = 0;
  207. uptr = mta_dev.units + GET_UNIT(mta_cu);        /* get unit */
  208. switch (code) {                        /* decode IR<5:7> */
  209. case ioDIA:                        /* DIA */
  210.     rval = (mta_updcsta (uptr) >> 16) & 0177777;    /* return status 1 */
  211.     break;
  212. case ioDOA:                        /* DOA */
  213. /*    if (AC & CU_CI) ... clear ep int            */
  214.     mta_cu = AC;                    /* save cmd/unit */
  215.     uptr = mta_dev.units + GET_UNIT(mta_cu);    /* get unit */
  216.     mta_updcsta (uptr);                /* update status */
  217.     break;
  218. case ioDIB:                        /* DIB */
  219.     rval = mta_ma & ADDRMASK;            /* return ma */
  220.     break;
  221. case ioDOB:                        /* DOB */
  222.     mta_ma = AC & ADDRMASK;                /* save ma */
  223.     break;
  224. case ioDIC:                        /* DIC */
  225.     rval = mta_updcsta (uptr) & 0177777;        /* return status 2 */
  226.     break;
  227. case ioDOC:                        /* DOC */
  228.     mta_wc = ((AC & 040000) << 1) | (AC & 077777);    /* save wc */
  229.     break;  }                    /* end switch code */
  230.  
  231. /* IOT, continued */
  232.  
  233. switch (pulse) {                    /* decode IR<8:9> */
  234. case iopS:                        /* start */
  235.     c = GET_CMD (mta_cu);                /* get command */
  236.     if (dev_busy & INT_MTA) break;            /* ignore if busy */
  237.     if ((uptr -> USTAT & STA_RDY) == 0) {        /* drive not ready? */
  238.         mta_sta = mta_sta | STA_ILL;        /* illegal op */
  239.         dev_busy = dev_busy & ~INT_MTA;        /* clear busy */
  240.         dev_done = dev_done | INT_MTA;        /* set done */
  241.         int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable);  }
  242.     else if ((c == CU_REWIND) || (c == CU_UNLOAD)) { /* rewind, unload? */
  243.         mta_upddsta (uptr, (uptr -> USTAT &    /* update status */
  244.             ~(STA_BOT | STA_EOF | STA_EOT | STA_RDY)) | STA_REW);
  245.         sim_activate (uptr, mta_rwait);        /* start IO */
  246.         if (c == CU_UNLOAD) detach_unit (uptr);  }
  247.     else {    mta_sta = 0;                /* clear errors */
  248.         dev_busy = dev_busy | INT_MTA;        /* set busy */
  249.         dev_done = dev_done & ~INT_MTA;        /* clear done */
  250.         int_req = int_req & ~INT_MTA;        /* clear int */
  251.         if (ctype[c]) sim_activate (uptr, mta_cwait);
  252.         else {    mta_upddsta (uptr, uptr -> USTAT &
  253.                ~(STA_BOT | STA_EOF | STA_EOT | STA_RDY));
  254.             sim_activate (uptr, mta_rwait);  }  }
  255.     mta_updcsta (uptr);                /* update status */
  256.     break;
  257. case iopC:                        /* clear */
  258.     for (u = 0; u < MTA_NUMDR; u++) {        /* loop thru units */
  259.         uptr = mta_dev.units + u;        /* cancel IO */
  260.         if (sim_is_active (uptr) && !(uptr -> USTAT & STA_REW)) {
  261.             mta_upddsta (uptr, uptr -> USTAT | STA_RDY);
  262.             sim_cancel (uptr);  }  }
  263.     dev_busy = dev_busy & ~INT_MTA;            /* clear busy */
  264.     dev_done = dev_done & ~INT_MTA;            /* clear done */
  265.     int_req = int_req & ~INT_MTA;            /* clear int */
  266.     mta_sta = mta_cu = mta_ma = 0;            /* clear registers */
  267.     mta_updcsta (&mta_unit[0]);            /* update status */
  268.     break;  }                    /* end case pulse */
  269. return rval;
  270. }
  271.  
  272. /* Unit service
  273.  
  274.    If rewind done, reposition to start of tape, set status
  275.    else, do operation, clear busy, set done, interrupt
  276. */
  277.  
  278. int mta_svc (UNIT *uptr)
  279. {
  280. int c, i, p, rval, u, err;
  281. int awc, wc;
  282. unsigned short bc, sbuf[SBSIZE + 1];
  283. const static unsigned short bceof = 0;
  284.  
  285. rval = SCPE_OK;
  286. u = uptr -> UNUM;                    /* get unit number */
  287. if (uptr -> USTAT & STA_REW) {                /* rewind? */
  288.     uptr -> pos = 0;                /* update position */
  289.     mta_upddsta (uptr, (uptr -> USTAT & ~STA_REW) | STA_BOT | STA_RDY);
  290.     if (u == GET_UNIT (mta_cu)) mta_updcsta (uptr);
  291.     return rval;  }
  292.  
  293. err = 0;
  294. c = GET_CMD (mta_cu);                    /* command */
  295. wc = DTSIZE - (mta_wc & DTMASK);            /* io wc */
  296.  
  297. if ((uptr -> flags & UNIT_ATT) == 0) {            /* not attached? */
  298.     mta_upddsta (uptr, 0);                /* unit off line */
  299.     mta_sta = mta_sta | STA_ILL;  }            /* illegal operation */
  300.  
  301. else if ((uptr -> flags & UNIT_WLK) &&            /* write locked? */
  302.     ((c == CU_WRITE) || (c == CU_WREOF) || (c == CU_ERASE))) {
  303.     mta_upddsta (uptr, uptr -> USTAT | STA_WLK | STA_RDY);
  304.     mta_sta = mta_sta | STA_ILL;  }            /* illegal operation */
  305.     
  306. else switch (c) {                    /* case on command */
  307. case CU_CMODE:                        /* controller mode */
  308.     mta_ep = mta_cu & CU_EP;
  309.     break;
  310. case CU_DMODE:                        /* drive mode */
  311.     if (uptr -> pos) mta_sta = mta_sta | STA_ILL;    /* must be BOT */
  312.     else mta_upddsta (uptr, (mta_cu & CU_PE)?    /* update drv status */
  313.         uptr -> USTAT | STA_PEM: uptr -> USTAT & ~ STA_PEM);
  314.     break;
  315.  
  316. /* Unit service, continued */
  317.  
  318. case CU_READ:                        /* read */
  319. case CU_READNS:                        /* read non-stop */
  320.     fseek (uptr -> fileref, uptr -> pos, SEEK_SET);
  321.     fread (&bc, sizeof (short), 1, uptr -> fileref); /* read byte count */
  322.     if ((err = ferror (uptr -> fileref)) ||        /* error or eof? */
  323.         (feof (uptr -> fileref))) {
  324.         mta_upddsta (uptr, uptr -> USTAT | STA_RDY | STA_EOT);
  325.         break;  }
  326.     if (bc == 0) {                    /* tape mark? */
  327.         mta_upddsta (uptr, uptr -> USTAT | STA_RDY | STA_EOF);
  328.         uptr -> pos = uptr -> pos + sizeof (short);
  329.         break;  }
  330.     awc = ((int) bc + 1) >> 1;            /* actual word count */
  331.     if (bc & 1) mta_sta = mta_sta | STA_ODD;    /* odd byte count? */
  332.     if (awc > wc) mta_sta = mta_sta | STA_WCO;    /* too big? */
  333.     else wc = awc;                    /* no, use it */
  334.     i = fread (sbuf, sizeof (short), wc, uptr -> fileref);
  335.     for ( ; i < wc; i++) sbuf[i] = 0;
  336.     err = ferror (uptr -> fileref);
  337.     for (i = 0; i < wc; i++) {            /* copy buf to mem */
  338.         if (MEM_ADDR_OK (mta_ma)) M[mta_ma] = sbuf[i];
  339.         mta_ma = (mta_ma + 1) & ADDRMASK;  }
  340.     mta_wc = (mta_wc + wc) & 0177777;
  341.     uptr -> pos = uptr -> pos + ((awc + 1) * sizeof (short));
  342.     mta_upddsta (uptr, uptr -> USTAT | STA_RDY);
  343.     break;
  344. case CU_WRITE:                        /* write */
  345.     fseek (uptr -> fileref, uptr -> pos, SEEK_SET);
  346.     sbuf[0] = wc << 1;                /* io byte count */
  347.     for (i = 0; i < wc; i++) {            /* copy to buffer */
  348.         sbuf[i + 1] = M[mta_ma];
  349.         mta_ma = (mta_ma + 1) & ADDRMASK;  }
  350.     fwrite (sbuf, sizeof (short), wc + 1, uptr -> fileref);
  351.     err = ferror (uptr -> fileref);
  352.     mta_wc = 0;
  353.     uptr -> pos = uptr -> pos + ((wc + 1) * sizeof (short));
  354.     mta_upddsta (uptr, uptr -> USTAT | STA_RDY);
  355.     break;
  356. case CU_WREOF:                        /* write eof */
  357.     fseek (uptr -> fileref, uptr -> pos, SEEK_SET);
  358.     fwrite (&bceof, sizeof (short), 1, uptr -> fileref);
  359.     err = ferror (uptr -> fileref);
  360.     uptr -> pos = uptr -> pos + sizeof (short);
  361.     mta_upddsta (uptr, uptr -> USTAT | STA_EOF | STA_RDY);
  362.     break;
  363. case CU_ERASE:                        /* erase */
  364.     mta_upddsta (uptr, uptr -> USTAT | STA_RDY);
  365.     break;
  366.  
  367. /* Unit service, continued */
  368.  
  369. case CU_SPACEF:                        /* space forward */
  370.     do {    mta_wc = (mta_wc + 1) & 0177777;    /* incr wc */
  371.         fseek (uptr -> fileref, uptr -> pos, SEEK_SET);
  372.         fread (&bc, sizeof (short), 1, uptr -> fileref); /* read bc */
  373.         if ((err = ferror (uptr -> fileref)) ||    /* error or eof? */
  374.             (feof (uptr -> fileref))) {
  375.             mta_upddsta (uptr, uptr -> USTAT | STA_RDY | STA_EOT);
  376.             break;  }
  377.         uptr -> pos = uptr -> pos + sizeof (short);
  378.         if (bc == 0) {                /* zero bc? */
  379.             mta_upddsta (uptr, uptr -> USTAT | STA_RDY | STA_EOF);
  380.             break;  }
  381.         uptr -> pos = uptr -> pos + (((int) bc + 1) & ~1);  }
  382.     while (mta_wc != 0);
  383.     mta_upddsta (uptr, uptr -> USTAT | STA_RDY);
  384.     break;
  385. case CU_SPACER:                        /* space reverse */
  386.     for (i = 0; i < SBSIZE; i++) sbuf[i] = 0;    /* set table = EOF */
  387.     for (i = 0, p = 0; p < uptr -> pos; ) {        /* build spc table */
  388.         fseek (uptr -> fileref, p, SEEK_SET);
  389.         fread (&sbuf[i], sizeof (short), 1, uptr -> fileref);
  390.         if ((err = ferror (uptr -> fileref)) ||
  391.             (feof (uptr -> fileref))) {        /* error or eof? */
  392.             uptr -> pos = p;        /* tape ends */
  393.             break;  }
  394.         p = p + sizeof (short) + (((int) sbuf[i] + 1) & ~1);
  395.         i = (i + 1) & SBMASK;  }
  396.     if (uptr -> pos == 0) {                /* at BOT? */
  397.         mta_upddsta (uptr, uptr -> USTAT | STA_RDY | STA_BOT);
  398.         break;  }
  399.     do {    mta_wc = (mta_wc + 1) & 0177777;    /* incr wc */
  400.         i = (i - 1) & SBMASK;
  401.         uptr -> pos = uptr -> pos - sizeof (short) -
  402.             (((int) sbuf[i] + 1) & ~1);
  403.         if (uptr -> pos == 0)            /* start of tape? */
  404.             mta_upddsta (uptr, uptr -> USTAT | STA_RDY | STA_BOT);
  405.         if (sbuf[i] == 0)            /* start of prv file? */
  406.             mta_upddsta (uptr, uptr -> USTAT | STA_RDY | STA_EOF);
  407.         if (uptr -> USTAT & (STA_BOT | STA_EOF)) break;  }
  408.     while (mta_wc != 0);
  409.     mta_upddsta (uptr, uptr -> USTAT | STA_RDY);
  410.     break;
  411. default:                        /* reserved */
  412.     mta_sta = mta_sta | STA_ILL;
  413.     break;  }                    /* end case */
  414.  
  415. /* Unit service, continued */
  416.  
  417. if (err != 0) {                        /* I/O error */
  418.     mta_sta = mta_sta | STA_DAE;            /* flag error */
  419.     perror ("MTA I/O error");
  420.     rval = SCPE_IOERR;
  421.     clearerr (uptr -> fileref);  }
  422. mta_updcsta (uptr);                    /* update status */
  423. dev_busy = dev_busy & ~INT_MTA;                /* clear busy */
  424. dev_done = dev_done | INT_MTA;                /* set done */
  425. int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable);
  426. return rval;
  427. }
  428.  
  429. /* Update controller status */
  430.  
  431. int mta_updcsta (UNIT *uptr)                /* update ctrl */
  432. {
  433. mta_sta = (mta_sta & ~(STA_DYN | STA_CLR | STA_ERR1 | STA_ERR2)) |
  434.     (uptr -> USTAT & STA_DYN) | STA_SET;
  435. if (mta_sta & STA_EFLGS1) mta_sta = mta_sta | STA_ERR1;
  436. if (mta_sta & STA_EFLGS2) mta_sta = mta_sta | STA_ERR2;
  437. return mta_sta;
  438. }
  439.  
  440. /* Update drive status */
  441.  
  442. void mta_upddsta (UNIT *uptr, int newsta)        /* drive status */
  443. {
  444. int change, u;
  445.  
  446. if ((uptr -> flags & UNIT_ATT) == 0) newsta = 0;    /* offline? */
  447. change = (uptr -> USTAT ^ newsta) & STA_MON;        /* changes? */
  448. uptr -> USTAT = newsta & STA_DYN;            /* update status */
  449. if (change) {
  450. /*    if (mta_ep) {                    /* if polling */
  451. /*        u = uptr -> UNUM;            /* unit num */
  452. /*        mta_sta = (mta_sta & ~STA_UNIT) | (u << STA_V_UNIT);
  453. /*        set polling interupt...  }        */
  454.     mta_sta = mta_sta | STA_CHG;  }            /* flag change */
  455. return;
  456. }
  457.  
  458. /* Reset routine */
  459.  
  460. int mta_reset (DEVICE *dptr)
  461. {
  462. int i, u;
  463. UNIT *uptr;
  464.  
  465. dev_busy = dev_busy & ~INT_MTA;                /* clear busy */
  466. dev_done = dev_done & ~INT_MTA;                /* clear done, int */
  467. int_req = int_req & ~INT_MTA;
  468. mta_cu = mta_wc = mta_ma = mta_sta = 0;            /* clear registers */
  469. mta_ep = 0;
  470. for (u = 0; u < MTA_NUMDR; u++) {            /* loop thru units */
  471.     uptr = mta_dev.units + u;
  472.     sim_cancel (uptr);                /* cancel activity */
  473.     uptr -> UNUM = u;
  474.     if (uptr -> flags & UNIT_ATT) uptr -> USTAT = STA_RDY |
  475.             (uptr -> USTAT & STA_PEM) |
  476.             ((uptr -> flags & UNIT_WLK)? STA_WLK: 0) |
  477.             ((uptr -> pos)? 0: STA_BOT);
  478.     else uptr -> USTAT = 0;  }
  479. mta_updcsta (&mta_unit[0]);                /* update status */
  480. return SCPE_OK;
  481. }
  482.  
  483. /* Attach routine */
  484.  
  485. int mta_attach (UNIT *uptr, char *cptr)
  486. {
  487. int r;
  488. r = attach_unit (uptr, cptr);
  489. if (r != SCPE_OK) return r;
  490. if (!sim_is_active (uptr)) mta_upddsta (uptr, STA_RDY | STA_BOT | STA_PEM |
  491.     ((uptr -> flags & UNIT_WLK)? STA_WLK: 0));
  492. return r;
  493. }
  494.  
  495. /* Detach routine */
  496.  
  497. int mta_detach (UNIT* uptr)
  498. {
  499. if (!sim_is_active (uptr)) mta_upddsta (uptr, 0);
  500. return detach_unit (uptr);
  501. }
  502.  
  503. /* Write lock/unlock validate routine */
  504.  
  505. int mta_vlock (UNIT *uptr, int val)
  506. {
  507. if ((uptr -> flags & UNIT_ATT) && val)
  508.     mta_upddsta (uptr, uptr -> USTAT | STA_WLK);
  509. else mta_upddsta (uptr, uptr -> USTAT & ~STA_WLK);
  510. return SCPE_OK;
  511. }
  512.  
  513. /* Bootstrap routine */
  514.  
  515. #define BOOT_START 02000
  516. #define BOOT_UNIT 02020
  517. #define BOOT_LEN (sizeof (boot_rom) / sizeof (int))
  518.  
  519. static const int boot_rom[] = {
  520.     060222,            /* NIOC 0,MTA        ; clear disk */
  521.     020417,            /* LDA 0,UNIT        ; unit */
  522.     024417,            /* LDA 1,REWIND        ; cmd */
  523.     0107000,        /* ADD 0,1        ; cmd + unit */
  524.     065122,            /* DOAS 1,MTA        ; start rewind */
  525.     070422,            /* DIA 2,MTA        ; get status */
  526.     0151213,        /* MOVR# 2,2,SNC    ; skip if done */
  527.     000776,            /* JMP .-2 */
  528.     0126400,        /* SUB 1,1         ; ma, wc = 0 */
  529.     066022,            /* DOB 1,MTA */
  530.     067022,            /* DOC 1,MTA */
  531.     061122,            /* DOAS 0,MTA        ; start read */
  532.     070422,            /* DIA 2,MTA        ; get status */
  533.     0151213,        /* MOVR# 2,2,SNC    ; skip if done */
  534.     000776,            /* JMP .-2 */
  535.     000377,            /* JMP 377 */
  536.     000000,            /* UNIT: */
  537.     000010            /* REWIND: 10 */
  538. };
  539.  
  540. int mta_boot (int unitno)
  541. {
  542. int i;
  543. extern int saved_PC;
  544.  
  545. for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i];
  546. M[BOOT_UNIT] = (unitno & CU_M_UNIT) << CU_V_UNIT;
  547. saved_PC = BOOT_START;
  548. return SCPE_OK;
  549. }
  550.