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

  1. /* RL11 (RLV12) cartridge disk simulator
  2.  
  3.    Copyright (c) 1994, 1995, Robert M Supnik, Digital Equipment Corporation
  4.    Commercial use prohibited
  5.  
  6.    The RL11 is a four drive cartridge disk subsystem.  An RL01 drive
  7.    consists of 256 cylinders, each with 2 surfaces containing 40 sectors
  8.    of 256 bytes.  An RL02 drive has 512 cylinders.  The RLV12 is a
  9.    controller variant which supports 22b direct addressing.
  10.  
  11.    The most complicated part of the RL11 controller is the way it does
  12.    seeks.  Seeking is relative to the current disk address; this requires
  13.    keeping accurate track of the current cylinder.  The RL01 will not
  14.    switch heads or cross cylinders during transfers.
  15. */
  16.  
  17. #include "pdp11_defs.h"
  18.  
  19. /* Constants */
  20.  
  21. #define RL_NUMWD    128                /* words/sector */
  22. #define RL_NUMSC    40                /* sectors/surface */
  23. #define RL_NUMSF    2                /* surfaces/cylinder */
  24. #define RL_NUMCY    256                /* cylinders/drive */
  25. #define RL_NUMDR    4                /* drives/controller */
  26. #define RL01_SIZE (RL_NUMCY * RL_NUMSF * RL_NUMSC * RL_NUMWD)  /* words/drive */
  27. #define RL02_SIZE    (RL01_SIZE * 2)            /* words/drive */
  28. #define RL_MAXMEM    (MEMSIZE / sizeof (short))    /* words/memory */
  29.  
  30. /* Flags in the unit flags word */
  31.  
  32. #define UNIT_V_HWLK    (UNIT_V_UF)            /* hwre write lock */
  33. #define UNIT_V_RL02    (UNIT_V_UF+1)            /* RL01 vs RL02 */
  34. #define UNIT_V_AUTO    (UNIT_V_UF+2)            /* autosize enable */
  35. #define UNIT_W_UF    3                /* saved flags width */
  36. #define UNIT_HWLK    (1u << UNIT_V_HWLK)
  37. #define UNIT_RL02    (1u << UNIT_V_RL02)
  38. #define UNIT_AUTO    (1u << UNIT_V_AUTO)
  39.  
  40. /* Parameters in the unit descriptor */
  41.  
  42. #define TRK        u3                /* current track */
  43. #define STAT        u4                /* status */
  44.  
  45. /* RLDS */
  46.  
  47. #define RLDS_LOAD    0                /* no cartridge */
  48. #define RLDS_LOCK    5                /* lock on */
  49. #define RLDS_BHO    0000010                /* brushes home */
  50. #define RLDS_HDO    0000020                /* heads out */
  51. #define RLDS_CVO    0000040                /* cover open */
  52. #define RLDS_HD        0000100                /* head select */
  53. #define RLDS_DSE    0000400                /* drive select err */
  54. #define RLDS_RL02    0000200                /* RL02 */
  55. #define RLDS_VCK    0001000                /* volume check */
  56. #define RLDS_WGE    0002000                /* write gate err */
  57. #define RLDS_SPE    0004000                /* spin err */
  58. #define RLDS_STO    0010000                /* seek time out */
  59. #define RLDS_WLK    0020000                /* write locked */
  60. #define RLDS_HCE    0040000                /* head current err */
  61. #define RLDS_WDE    0100000                /* write data err */
  62. #define RLDS_ATT    (RLDS_HDO+RLDS_BHO+RLDS_LOCK)    /* attached status */
  63. #define RLDS_UNATT    (RLDS_CVO+RLDS_LOAD)        /* unattached status */
  64. #define RLDS_ERR     (RLDS_WDE+RLDS_HCE+RLDS_STO+RLDS_SPE+RLDS_WGE+ \
  65.             RLDS_VCK+RLDS_DSE)        /* errors bits */
  66.  
  67. /* RLCS */
  68.  
  69. #define RLCS_DRDY    0000001                /* drive ready */
  70. #define RLCS_M_FUNC    0000007                /* function */
  71. #define  RLCS_NOP    0
  72. #define  RLCS_WCHK    1
  73. #define  RLCS_GSTA    2
  74. #define  RLCS_SEEK    3
  75. #define  RLCS_RHDR    4
  76. #define  RLCS_WRITE    5
  77. #define  RLCS_READ    6
  78. #define  RLCS_RNOHDR    7
  79. #define RLCS_V_FUNC    1
  80. #define RLCS_M_MEX    03                /* memory extension */
  81. #define RLCS_V_MEX    4
  82. #define RLCS_MEX    (RLCS_M_MEX << RLCS_V_MEX)
  83. #define RLCS_M_DRIVE    03
  84. #define RLCS_V_DRIVE    8
  85. #define RLCS_INCMP    0002000                /* incomplete */
  86. #define RLCS_CRC    0004000                /* CRC error */
  87. #define RLCS_HDE    0010000                /* header error */
  88. #define RLCS_NXM    0020000                /* non-exist memory */
  89. #define RLCS_DRE    0040000                /* drive error */
  90. #define RLCS_ERR    0100000                /* error summary */
  91. #define RLCS_ALLERR (RLCS_ERR+RLCS_DRE+RLCS_NXM+RLCS_HDE+RLCS_CRC+RLCS_INCMP)
  92. #define RLCS_RW        0001776                /* read/write */
  93. #define GET_FUNC(x)    (((x) >> RLCS_V_FUNC) & RLCS_M_FUNC)
  94. #define GET_DRIVE(x)    (((x) >> RLCS_V_DRIVE) & RLCS_M_DRIVE)
  95.  
  96. /* RLDA */
  97.  
  98. #define RLDA_SK_DIR    0000004                /* direction */
  99. #define RLDA_GS_CLR    0000010                /* clear errors */
  100. #define RLDA_SK_HD    0000020                /* head select */
  101.  
  102. #define RLDA_V_SECT    0                /* sector */
  103. #define RLDA_M_SECT    077
  104. #define RLDA_V_TRACK    6                /* track */
  105. #define RLDA_M_TRACK    01777
  106. #define RLDA_HD0    (0 << RLDA_V_TRACK)
  107. #define RLDA_HD1    (1u << RLDA_V_TRACK)
  108. #define RLDA_V_CYL    7                /* cylinder */
  109. #define RLDA_M_CYL    0777
  110. #define RLDA_TRACK    (RLDA_M_TRACK << RLDA_V_TRACK)
  111. #define RLDA_CYL    (RLDA_M_CYL << RLDA_V_CYL)
  112. #define GET_SECT(x)    (((x) >> RLDA_V_SECT) & RLDA_M_SECT)
  113. #define GET_CYL(x)    (((x) >> RLDA_V_CYL) & RLDA_M_CYL)
  114. #define GET_TRACK(x)    (((x) >> RLDA_V_TRACK) & RLDA_M_TRACK)
  115. #define GET_DA(x)    ((GET_TRACK (x) * RL_NUMSC) + GET_SECT (x))
  116.  
  117. /* RLBA */
  118.  
  119. #define RLBA_IMP    0177776                /* implemented */
  120.  
  121. /* RLBAE */
  122.  
  123. #define RLBAE_IMP    0000077                /* implemented */
  124.  
  125. extern int int_req;
  126. extern unsigned short M[];                /* memory */
  127. int rlcs = 0;                        /* control/status */
  128. int rlba = 0;                        /* memory address */
  129. int rlbae = 0;                        /* mem addr extension */
  130. int rlda = 0;                        /* disk addr */
  131. int rlmp = 0, rlmp1 = 0, rlmp2 = 0;            /* mp register queue */
  132. int rl_swait = 10;                    /* seek wait */
  133. int rl_rwait = 10;                    /* rotate wait */
  134. int rl_stopioe = 1;                    /* stop on error */
  135. int rl_svc (UNIT *uptr);
  136. int rl_reset (DEVICE *dptr);
  137. void rl_set_done (int error);
  138. int rl_boot (int unitno);
  139. int rl_attach (UNIT *uptr, char *cptr);
  140. int rl_set_size (UNIT *uptr, int value);
  141. extern int sim_activate (UNIT *uptr, int interval);
  142. extern int sim_cancel (UNIT *uptr);
  143. extern int sim_is_active (UNIT *uptr);
  144. extern int attach_unit (UNIT *uptr, char *cptr);
  145.  
  146. /* RL11 data structures
  147.  
  148.    rl_dev    RL device descriptor
  149.    rl_unit    RL unit list
  150.    rl_reg    RL register list
  151.    rl_mod    RL modifier list
  152. */
  153.  
  154. UNIT rl_unit[] = {
  155.     { UDATA (&rl_svc, UNIT_FIX+UNIT_ATTABLE, RL01_SIZE) },
  156.     { UDATA (&rl_svc, UNIT_FIX+UNIT_ATTABLE, RL01_SIZE) },
  157.     { UDATA (&rl_svc, UNIT_FIX+UNIT_ATTABLE, RL01_SIZE) },
  158.     { UDATA (&rl_svc, UNIT_FIX+UNIT_ATTABLE, RL01_SIZE) } };
  159.  
  160. REG rl_reg[] = {
  161.     { ORDATA (RLCS, rlcs, 16) },
  162.     { ORDATA (RLDA, rlda, 16) },
  163.     { ORDATA (RLBA, rlba, 16) },
  164.     { ORDATA (RLBAE, rlbae, 6) },
  165.     { ORDATA (RLMP, rlmp, 16) },
  166.     { ORDATA (RLMP1, rlmp1, 16) },
  167.     { ORDATA (RLMP2, rlmp2, 16) },
  168.     { FLDATA (INT, int_req, INT_V_RL) },
  169.     { FLDATA (ERR, rlcs, CSR_V_ERR) },
  170.     { FLDATA (DONE, rlcs, CSR_V_DONE) },
  171.     { FLDATA (IE, rlcs, CSR_V_IE) },
  172.     { DRDATA (STIME, rl_swait, 24), PV_LEFT },
  173.     { DRDATA (RTIME, rl_rwait, 24), PV_LEFT },
  174.     { GRDATA (FLG0, rl_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF), REG_HRO },
  175.     { GRDATA (FLG1, rl_unit[1].flags, 8, UNIT_W_UF, UNIT_V_UF), REG_HRO },
  176.     { GRDATA (FLG2, rl_unit[2].flags, 8, UNIT_W_UF, UNIT_V_UF), REG_HRO },
  177.     { GRDATA (FLG3, rl_unit[3].flags, 8, UNIT_W_UF, UNIT_V_UF), REG_HRO },
  178.     { DRDATA (CAPAC0, rl_unit[0].capac, 32), PV_LEFT + REG_HRO },
  179.     { DRDATA (CAPAC1, rl_unit[1].capac, 32), PV_LEFT + REG_HRO },
  180.     { DRDATA (CAPAC2, rl_unit[2].capac, 32), PV_LEFT + REG_HRO },
  181.     { DRDATA (CAPAC3, rl_unit[3].capac, 32), PV_LEFT + REG_HRO },
  182.     { FLDATA (STOP_IOE, rl_stopioe, 0) },
  183.     { NULL }  };
  184.  
  185. MTAB rl_mod[] = {
  186.     { UNIT_HWLK, 0, "write enabled", "ENABLED", NULL },
  187.     { UNIT_HWLK, UNIT_HWLK, "write locked", "LOCKED", NULL },
  188.     { (UNIT_RL02+UNIT_ATT), UNIT_ATT, "RL01", NULL, NULL },
  189.     { (UNIT_RL02+UNIT_ATT), (UNIT_RL02+UNIT_ATT), "RL02", NULL, NULL },
  190.     { (UNIT_AUTO+UNIT_RL02+UNIT_ATT), 0, "RL01", NULL, NULL },
  191.     { (UNIT_AUTO+UNIT_RL02+UNIT_ATT), UNIT_RL02, "RL02", NULL, NULL },
  192.     { (UNIT_AUTO+UNIT_ATT), UNIT_AUTO, "autosize", NULL, NULL },
  193.     { UNIT_AUTO, UNIT_AUTO, NULL, "AUTOSIZE", NULL },
  194.     { (UNIT_AUTO+UNIT_RL02), 0, NULL, "RL01", &rl_set_size },
  195.     { (UNIT_AUTO+UNIT_RL02), UNIT_RL02, NULL, "RL02", &rl_set_size },
  196.     { 0 }  };
  197.  
  198. DEVICE rl_dev = {
  199.     "RL", rl_unit, rl_reg, rl_mod,
  200.     RL_NUMDR, 8, 24, 1, 8, 16,
  201.     NULL, NULL, &rl_reset,
  202.     &rl_boot, &rl_attach, NULL };
  203.  
  204. /* I/O dispatch routine, I/O addresses 17774400 - 17774407
  205.  
  206.    17774400    RLCS    read/write
  207.    17774402    RLBA    read/write
  208.    17774404    RLDA    read/write
  209.    17774406    RLMP    read/write
  210.    17774410    RLBAE    read/write
  211. */
  212.  
  213. int rl_rd (int *data, int PA, int access)
  214. {
  215. UNIT *uptr;
  216.  
  217. switch ((PA >> 1) & 07) {                /* decode PA<2:1> */
  218. case 0:                            /* RLCS */
  219.     rlcs = (rlcs & ~RLCS_MEX) | ((rlbae & RLCS_M_MEX) << RLCS_V_MEX);
  220.     if (rlcs & RLCS_ALLERR) rlcs = rlcs | RLCS_ERR;
  221.     uptr = rl_dev.units + GET_DRIVE (rlcs);
  222.     if (sim_is_active (uptr)) rlcs = rlcs & ~RLCS_DRDY;
  223.     else rlcs = rlcs | RLCS_DRDY;            /* see if ready */
  224.     *data = rlcs;
  225.     return SCPE_OK;
  226. case 1:                            /* RLBA */
  227.     *data = rlba & RLBA_IMP;
  228.     return SCPE_OK;
  229. case 2:                            /* RLDA */
  230.     *data = rlda;
  231.     return SCPE_OK;
  232. case 3:                            /* RLMP */
  233.     *data = rlmp;
  234.     rlmp = rlmp1;                    /* ripple data */
  235.     rlmp1 = rlmp2;
  236.     return SCPE_OK;
  237. case 4:                            /* RLBAE */
  238.     *data = rlbae & RLBAE_IMP;
  239.     return SCPE_OK;  }                /* end switch */
  240. }                            /* end rl_rd */
  241.  
  242. int rl_wr (int data, int PA, int access)
  243. {
  244. int curr, offs, newc, maxc;
  245. UNIT *uptr;
  246.  
  247. switch ((PA >> 1) & 07) {                /* decode PA<2:1> */
  248. case 0:                            /* RLCS */
  249.     rlcs = (rlcs & ~RLCS_MEX) | ((rlbae & RLCS_M_MEX) << RLCS_V_MEX);
  250.     if (rlcs & RLCS_ALLERR) rlcs = rlcs | RLCS_ERR;
  251.     uptr = rl_dev.units + GET_DRIVE (data);        /* get new drive */
  252.     if (sim_is_active (uptr)) rlcs = rlcs & ~RLCS_DRDY;
  253.     else rlcs = rlcs | RLCS_DRDY;            /* see if ready */
  254.  
  255.     if (access == WRITEB) data = (PA & 1)?
  256.         (rlcs & 0377) | (data << 8): (rlcs & ~0377) | data;
  257.     rlcs = (rlcs & ~RLCS_RW) | (data & RLCS_RW);
  258.     rlbae = (rlbae & ~RLCS_M_MEX) | ((rlcs >> RLCS_V_MEX) & RLCS_M_MEX);
  259.     if (data & CSR_DONE) {                /* ready set? */
  260.         if ((data & CSR_IE) == 0) int_req = int_req & ~INT_RL;
  261.         else if ((rlcs & (CSR_DONE + CSR_IE)) == CSR_DONE)
  262.             int_req = int_req | INT_RL;    
  263.         return SCPE_OK;  }
  264.  
  265.     int_req = int_req & ~INT_RL;            /* clear interrupt */
  266.     rlcs = rlcs & ~RLCS_ALLERR;            /* clear errors */
  267.     switch (GET_FUNC (rlcs)) {            /* case on RLCS<3:1> */
  268.     case RLCS_NOP:                    /* nop */
  269.         rl_set_done (0);
  270.         return SCPE_OK;
  271.     case RLCS_SEEK:                    /* seek */
  272.         curr = GET_CYL (uptr -> TRK);        /* current cylinder */
  273.         offs = GET_CYL (rlda);            /* offset */
  274.         if (rlda & RLDA_SK_DIR) {        /* in or out? */
  275.             newc = curr + offs;        /* out */
  276.             maxc = (uptr -> flags & UNIT_RL02)?
  277.                 RL_NUMCY * 2: RL_NUMCY;
  278.             if (newc >= maxc) newc = maxc - 1;  }
  279.         else {    newc = curr - offs;        /* in */
  280.             if (newc < 0) newc = 0;  }
  281.         uptr -> TRK = (newc << RLDA_V_CYL) |    /* put on track */
  282.             ((rlda & RLDA_SK_HD)? RLDA_HD1: RLDA_HD0);
  283.         sim_activate (uptr, rl_swait * abs (newc - curr));
  284.         return SCPE_OK;
  285.     default:                    /* data transfer */
  286.         sim_activate (uptr, rl_swait);        /* activate unit */
  287.         return SCPE_OK;  }            /* end switch func */
  288.     return SCPE_OK;                    /* end case RLCS */
  289.  
  290. case 1:                            /* RLBA */
  291.     if (access == WRITEB) data = (PA & 1)?
  292.         (rlba & 0377) | (data << 8): (rlba & ~0377) | data;
  293.     rlba = data & RLBA_IMP;
  294.     return SCPE_OK;
  295. case 2:                            /* RLDA */
  296.     if (access == WRITEB) data = (PA & 1)?
  297.         (rlda & 0377) | (data << 8): (rlda & ~0377) | data;
  298.     rlda = data;
  299.     return SCPE_OK;
  300. case 3:                            /* RLMP */
  301.     if (access == WRITEB) data = (PA & 1)?
  302.         (rlmp & 0377) | (data << 8): (rlmp & ~0377) | data;
  303.     rlmp = rlmp1 = rlmp2 = data;
  304.     return SCPE_OK;
  305. case 4:                            /* RLBAE */
  306.     if (PA & 1) return;
  307.     rlbae = data & RLBAE_IMP;
  308.     rlcs = (rlcs & ~RLCS_MEX) | ((rlbae & RLCS_M_MEX) << RLCS_V_MEX);
  309.     return SCPE_OK;  }                /* end switch */
  310. }                            /* end rl_wr */
  311.  
  312. /* Service unit timeout
  313.  
  314.    If seek in progress, complete seek command
  315.    Else complete data transfer command
  316.  
  317.    The unit control block contains the function and cylinder for
  318.    the current command.
  319. */
  320.  
  321. static unsigned short fill[RL_NUMWD] = { 0 };
  322. int rl_svc (UNIT *uptr)
  323. {
  324. int comp, err, awc, wc, maxwc;
  325. int func, pa, da, fillc;
  326.  
  327. func = GET_FUNC (rlcs);                    /* get function */
  328. if (func == RLCS_GSTA) {                /* get status */
  329.     rlmp = uptr -> STAT | (uptr -> TRK & RLDS_HD) |
  330.         ((uptr -> flags & UNIT_ATT)? RLDS_ATT: RLDS_UNATT);
  331.     if (rlda & RLDA_GS_CLR) rlmp = rlmp & ~RLDS_ERR;
  332.     if (uptr -> flags & UNIT_RL02) rlmp = rlmp | RLDS_RL02;
  333.     if (uptr -> flags & UNIT_HWLK) rlmp = rlmp | RLDS_WLK;
  334.     uptr -> STAT = rlmp2 = rlmp1 = rlmp;
  335.     rl_set_done (0);                /* done */
  336.     return SCPE_OK;  }
  337.  
  338. if ((uptr -> flags & UNIT_ATT) == 0) {            /* attached? */
  339.     rlcs = rlcs & ~RLCS_DRDY;            /* clear drive ready */
  340.     rl_set_done (RLCS_ERR | RLCS_INCMP);        /* flag error */
  341.     return IORETURN (rl_stopioe, SCPE_UNATT);  }
  342.  
  343. if ((func == RLCS_WRITE) && (uptr -> flags & UNIT_HWLK)) {
  344.     uptr -> STAT = uptr -> STAT | RLDS_WGE;        /* write and locked */
  345.     rl_set_done (RLCS_ERR | RLCS_DRE);
  346.     return SCPE_OK;  }
  347.  
  348. if (func == RLCS_SEEK) {                /* seek? */
  349.     rl_set_done (0);                /* done */
  350.     return SCPE_OK;  }
  351.  
  352. if (func == RLCS_RHDR) {                /* read header? */
  353.     rlmp = (uptr -> TRK & RLDA_TRACK) | GET_SECT (rlda);
  354.     rlmp1 = 0;
  355.     rl_set_done (0);                /* done */
  356.     return SCPE_OK;  }
  357.  
  358. if (((func != RLCS_RNOHDR) && ((uptr -> TRK & RLDA_CYL) != (rlda & RLDA_CYL)))
  359.    || (GET_SECT (rlda) >= RL_NUMSC)) {            /* bad cyl or sector? */
  360.     rl_set_done (RLCS_ERR | RLCS_HDE | RLCS_INCMP);    /* wrong cylinder? */
  361.     return SCPE_OK;  }
  362.     
  363. pa = ((rlbae << 16) | rlba) >> 1;            /* form phys addr */
  364. da = GET_DA (rlda) * RL_NUMWD;                /* get disk addr */
  365. wc = 0200000 - rlmp;                    /* get true wc */
  366.  
  367. maxwc = (RL_NUMSC - GET_SECT (rlda)) * RL_NUMWD;    /* max transfer */
  368. if (wc > maxwc) wc = maxwc;                /* track overrun? */
  369. if ((pa + wc) > RL_MAXMEM) {                /* mem overrun? */
  370.     rlcs = rlcs | RLCS_ERR | RLCS_NXM;
  371.     wc = (RL_MAXMEM - pa);  }
  372. if (wc < 0) {                        /* abort transfer? */
  373.     rl_set_done (RLCS_INCMP);
  374.     return SCPE_OK;  }
  375.  
  376. err = fseek (uptr -> fileref, da * sizeof (short), SEEK_SET);
  377. if ((func >= RLCS_READ) && (err == 0)) {        /* read (no hdr)? */
  378.     awc = fread (&M[pa], sizeof (short), wc, uptr -> fileref);
  379.     for ( ; awc < wc; awc++) M[pa + awc] = 0;
  380.     err = ferror (uptr -> fileref);  }
  381.  
  382. if ((func == RLCS_WRITE) && (err == 0)) {        /* write? */
  383.     fwrite (&M[pa], sizeof (short), wc, uptr -> fileref);
  384.     err = ferror (uptr -> fileref);
  385.     if ((err == 0) && (fillc = (wc & (RL_NUMWD - 1)))) {
  386.         fwrite (fill, sizeof (short), fillc, uptr -> fileref);
  387.         err = ferror (uptr -> fileref);  }  }
  388.  
  389. if ((func == RLCS_WCHK) && (err == 0)) {        /* write check? */
  390.     fillc = wc;                    /* xfer length */
  391.     for (wc = 0; (err == 0) && (wc < fillc); wc++)  {
  392.         awc = fread (&comp, sizeof (short), 1, uptr -> fileref);
  393.         if (awc == 0) comp = 0;
  394.         if (comp != M[pa + wc]) rlcs = rlcs | RLCS_ERR | RLCS_CRC;  }
  395.     err = ferror (uptr -> fileref);  }
  396.  
  397. rlmp = (rlmp + wc) & 0177777;                /* final word count */
  398. if (rlmp != 0) rlcs = rlcs | RLCS_ERR | RLCS_INCMP;    /* completed? */
  399. pa = (pa + wc) << 1;                    /* final byte addr */
  400. rlbae = (pa >> 16) & RLBAE_IMP;                /* upper 6b */
  401. rlba = pa & RLBA_IMP;                    /* lower 16b */
  402. rlcs = (rlcs & ~RLCS_MEX) | ((rlbae & RLCS_M_MEX) << RLCS_V_MEX);
  403. rlda = rlda + ((wc + (RL_NUMWD - 1)) / RL_NUMWD);
  404. rl_set_done (0);
  405.  
  406. if (err != 0) {                        /* error? */
  407.     perror ("RL I/O error");
  408.     clearerr (uptr -> fileref);
  409.     return SCPE_IOERR;  }
  410. return SCPE_OK;
  411. }
  412.  
  413. /* Set done and possibly errors */
  414.  
  415. void rl_set_done (int status)
  416. {
  417.     rlcs = rlcs | status | CSR_DONE;        /* set done */
  418.     if (rlcs & CSR_IE) int_req = int_req | INT_RL;
  419.     else int_req = int_req & ~INT_RL;
  420.     return;
  421. }
  422.  
  423. /* Device reset
  424.  
  425.    Note that the RL11 does NOT recalibrate its drives on RESET
  426. */
  427.  
  428. int rl_reset (DEVICE *dptr)
  429. {
  430. int i;
  431. UNIT *uptr;
  432.  
  433. rlcs = CSR_DONE;
  434. rlda = rlba = rlbae = rlmp = rlmp1 = rlmp2 = 0;
  435. int_req = int_req & ~INT_RL;
  436. for (i = 0; i < RL_NUMDR; i++) {
  437.     uptr = rl_dev.units + i;
  438.     sim_cancel (uptr);
  439.     uptr -> STAT = 0;  }
  440. return SCPE_OK;
  441. }
  442.  
  443. /* Attach routine */
  444.  
  445. int rl_attach (UNIT *uptr, char *cptr)
  446. {
  447. int p, r;
  448.  
  449. uptr -> capac = (uptr -> flags & UNIT_RL02)? RL02_SIZE: RL01_SIZE;
  450. r = attach_unit (uptr, cptr);
  451. if ((r != SCPE_OK) || ((uptr -> flags & UNIT_AUTO) == 0)) return r;
  452. if (fseek (uptr -> fileref, 0, SEEK_END)) return SCPE_OK;
  453. if ((p = ftell (uptr -> fileref)) == 0) return SCPE_OK;
  454. if (p > (RL01_SIZE * sizeof (short))) {
  455.     uptr -> flags = uptr -> flags | UNIT_RL02;
  456.     uptr -> capac = RL02_SIZE;  }
  457. else {    uptr -> flags = uptr -> flags & ~UNIT_RL02;
  458.     uptr -> capac = RL01_SIZE;  }
  459. return SCPE_OK;
  460. }
  461.  
  462. /* Set size routine */
  463.  
  464. int rl_set_size (UNIT *uptr, int value)
  465. {
  466. if (uptr -> flags & UNIT_ATT) return SCPE_ALATT;
  467. uptr -> capac = (value & UNIT_RL02)? RL02_SIZE: RL01_SIZE;
  468. return SCPE_OK;
  469. }
  470.  
  471. /* Device bootstrap */
  472.  
  473. #define BOOT_START 02000        /* start */
  474. #define BOOT_UNIT 02006            /* where to store unit number */
  475. #define BOOT_LEN (sizeof (boot_rom) / sizeof (int))
  476.  
  477. static const int boot_rom[] = {
  478.     0012706, 0002000,        /* MOV #2000, SP */
  479.     0012700, 0000000,        /* MOV #UNIT, R0 */
  480.     0010003,            /* MOV R0, R3 */
  481.     0000303,            /* SWAB R3 */
  482.     0012701, 0174400,        /* MOV #RLCS, R1     ; csr */
  483.     0012761, 0000013, 0000004,    /* MOV #13, 4(R1)    ; clr err */
  484.     0052703, 0000004,        /* BIS #4, R3        ; unit+gstat */
  485.     0010311,            /* MOV R3, (R1)        ; issue cmd */
  486.     0105711,            /* TSTB (R1)        ; wait */
  487.     0100376,            /* BPL .-2 */
  488.     0105003,            /* CLRB R3 */
  489.     0052703, 0000010,        /* BIS #10, R3        ; unit+rdhdr */
  490.     0010311,            /* MOV R3, (R1)        ; issue cmd */
  491.     0105711,            /* TSTB (R1)        ; wait */
  492.     0100376,            /* BPL .-2 */
  493.     0016102, 0000006,        /* MOV 6(R1), R2    ; get hdr */
  494.     0042702, 0000077,        /* BIC #77, R2        ; clr sector */
  495.     0005202,            /* INC R2        ; magic bit */
  496.     0010261, 0000004,        /* MOV R2, 4(R1)    ; seek to 0 */
  497.     0105003,            /* CLRB R3 */
  498.     0052703, 0000006,        /* BIS #6, R3        ; unit+seek */
  499.     0010311,            /* MOV R3, (R1)        ; issue cmd */
  500.     0105711,            /* TSTB (R1)        ; wait */
  501.     0100376,            /* BPL .-2 */
  502.     0005061, 0000002,        /* CLR 2(R1)        ; clr ba */
  503.     0005061, 0000004,        /* CLR 4(R1)        ; clr da */
  504.     0012761, 0177000, 0000006,    /* MOV #-512., 6(R1)    ; set wc */
  505.     0105003,            /* CLRB R3 */
  506.     0052703, 0000014,        /* BIS #14, R3        ; unit+read */
  507.     0010311,            /* MOV R3, (R1)        ; issue cmd */
  508.     0105711,            /* TSTB (R1)        ; wait */
  509.     0100376,            /* BPL .-2 */
  510.     0042711, 0000377,        /* BIC #377, (R1) */
  511.     0005002,            /* CLR R2 */
  512.     0005003,            /* CLR R3 */
  513.     0005004,            /* CLR R4 */
  514.     0012705, 0062154,        /* MOV "DL, R5 */
  515.     0005007                /* CLR PC */
  516. };
  517.  
  518. int rl_boot (int unitno)
  519. {
  520. int i;
  521. extern int saved_PC;
  522.  
  523. for (i = 0; i < BOOT_LEN; i++) M[(BOOT_START >> 1) + i] = boot_rom[i];
  524. M[BOOT_UNIT >> 1] = unitno & RLCS_M_DRIVE;
  525. saved_PC = BOOT_START;
  526. return SCPE_OK;
  527. }
  528.