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_dkp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-01-29  |  18.5 KB  |  546 lines

  1. /* NOVA moving head disk simulator
  2.  
  3.    Copyright (c) 1993, 1994, 1995, 1996,
  4.    Robert M Supnik, Digital Equipment Corporation
  5.    Commercial use prohibited
  6.  
  7.    dkp        moving head disk
  8. */
  9.  
  10. #include "nova_defs.h"
  11.  
  12. #define DKP_NUMDR    4                /* #drives */
  13. #define DKP_NUMWD    256                /* words/sector */
  14. #define UNIT_V_ONLINE    (UNIT_V_UF + 0)            /* present */
  15. #define UNIT_V_WLK    (UNIT_V_UF + 1)            /* write locked */
  16. #define UNIT_V_DTYPE    (UNIT_V_UF + 2)            /* disk type */
  17. #define UNIT_M_DTYPE    7
  18. #define UNIT_V_AUTO    (UNIT_V_UF + 5)            /* autosize */
  19. #define UNIT_W_UF    6                /* saved flag width */
  20. #define UNIT_ONLINE    (1 << UNIT_V_ONLINE)
  21. #define UNIT_WLK    (1 << UNIT_V_WLK)
  22. #define UNIT_DTYPE    (UNIT_M_DTYPE << UNIT_V_DTYPE)
  23. #define UNIT_AUTO    (1 << UNIT_V_AUTO)
  24. #define GET_DTYPE(x)    (((x) >> UNIT_V_DTYPE) & UNIT_M_DTYPE)
  25. #define FUNC        u3                /* function */
  26. #define CYL        u4                /* on cylinder */
  27.  
  28. /* Unit, surface, sector, count register */
  29.  
  30. #define    USSC_V_COUNT    0                /* count */
  31. #define USSC_M_COUNT    017
  32. #define USSC_V_SECTOR    4                /* sector */
  33. #define USSC_M_SECTOR    017
  34. #define USSC_V_SURFACE    8                /* surface */
  35. #define USSC_M_SURFACE    077
  36. #define USSC_V_UNIT    14                /* unit */
  37. #define USSC_M_UNIT    03
  38. #define USSC_UNIT    (USSC_M_UNIT << USSC_V_UNIT)
  39. #define GET_COUNT(x)    (((x) >> USSC_V_COUNT) & USSC_M_COUNT)
  40. #define GET_SECT(x)    (((x) >> USSC_V_SECTOR) & USSC_M_SECTOR)
  41. #define GET_SURF(x)    (((x) >> USSC_V_SURFACE) & USSC_M_SURFACE)
  42. #define GET_UNIT(x)    (((x) >> USSC_V_UNIT) & USSC_M_UNIT)
  43.  
  44. /* Flags, command, cylinder register */
  45.  
  46. #define FCCY_V_CYL    0                /* cylinder */
  47. #define FCCY_M_CYL    0377
  48. #define FCCY_V_CMD    8                /* command */
  49. #define FCCY_M_CMD    3
  50. #define  FCCY_READ    0
  51. #define  FCCY_WRITE    1
  52. #define  FCCY_SEEK    2
  53. #define  FCCY_RECAL    3
  54. #define FCCY_V_CEX    10                /* cyl extension */
  55. #define FCCY_CEX    (1 << FCCY_V_CEX)
  56. #define FCCY_FLAGS    0174000                /* flags */
  57. #define GET_CMD(x)    (((x) >> FCCY_V_CMD) & FCCY_M_CMD)
  58. #define GET_CYL(x)    ((((x) >> FCCY_V_CYL) & FCCY_M_CYL) | \
  59.             (((x) & FCCY_CEX) >> (FCCY_V_CEX - FCCY_V_CMD)))
  60. /* Status */
  61.  
  62. #define STA_ERR        0000001                /* error */
  63. #define STA_DLT        0000002                /* data late */
  64. #define STA_CRC        0000004                /* crc error */
  65. #define STA_UNS        0000010                /* unsafe */
  66. #define STA_XCY        0000020                /* cross cylinder */
  67. #define STA_CYL        0000040                /* nx cylinder */
  68. #define STA_DRDY    0000100                /* drive ready */
  69. #define STA_SEEK3    0000200                /* seeking unit 3 */
  70. #define STA_SEEK2    0000400                /* seeking unit 2 */
  71. #define STA_SEEK1    0001000                /* seeking unit 1 */
  72. #define STA_SEEK0    0002000                /* seeking unit 0 */
  73. #define STA_SKDN3    0004000                /* seek done unit 3 */
  74. #define STA_SKDN2    0010000                /* seek done unit 2 */
  75. #define STA_SKDN1    0020000                /* seek done unit 1 */
  76. #define STA_SKDN0    0040000                /* seek done unit 0 */
  77. #define STA_DONE    0100000                /* operation done */
  78.  
  79. #define STA_DYN        (STA_DRDY | STA_CYL)        /* set from unit */
  80. #define STA_EFLGS    (STA_ERR | STA_DLT | STA_CRC | STA_UNS | \
  81.              STA_XCY | STA_CYL)        /* error flags */
  82. #define STA_DFLGS    (STA_DONE | STA_SKDN0 | STA_SKDN1 | \
  83.              STA_SKDN2 | STA_SKDN3)        /* done flags */
  84.  
  85. #define GET_SA(cy,sf,sc,t) (((((cy)*drv_tab[t].surf)+(sf))* \
  86.     drv_tab[t].sect)+(sc))
  87.  
  88. /* This controller supports many different disk drive types:
  89.  
  90.    type        #sectors/    #surfaces/    #cylinders/
  91.          surface     cylinder     drive
  92.  
  93.    floppy    8        1        77
  94.    Diablo 31    12        2        203
  95.    Century 111    6        10        203
  96.    Diablo 44    12        4        408
  97.    Century 114    12        20        203
  98.  
  99.    In theory, each drive can be a different type.  The size field in
  100.    each unit selects the drive capacity for each drive and thus the
  101.    drive type.  DISKS MUST BE DECLARED IN ASCENDING SIZE.
  102. */
  103.  
  104. #define FLP_DTYPE    0
  105. #define FLP_SECT    8
  106. #define FLP_SURF    1
  107. #define FLP_CYL        77
  108. #define FLP_SIZE    (FLP_SECT * FLP_SURF * FLP_CYL * DKP_NUMWD)
  109.  
  110. #define D31_DTYPE    1
  111. #define D31_SECT    12
  112. #define D31_SURF    2
  113. #define D31_CYL        203
  114. #define D31_SIZE    (D31_SECT * D31_SURF * D31_CYL * DKP_NUMWD)
  115.  
  116. #define C111_DTYPE    2
  117. #define C111_SECT    6
  118. #define C111_SURF    10
  119. #define C111_CYL    203
  120. #define C111_SIZE    (C111_SECT * C111_SURF * C111_CYL * DKP_NUMWD)
  121.  
  122. #define D44_DTYPE    3
  123. #define D44_SECT    12
  124. #define D44_SURF    4
  125. #define D44_CYL        408
  126. #define D44_SIZE    (D44_SECT * D44_SURF * D44_CYL * DKP_NUMWD)
  127.  
  128. #define C114_DTYPE    4
  129. #define C114_SECT    12
  130. #define C114_SURF    20
  131. #define C114_CYL    203
  132. #define C114_SIZE    (C114_SECT * C114_SURF * C114_CYL * DKP_NUMWD)
  133.  
  134. struct drvtyp {
  135.     int    sect;                    /* sectors */
  136.     int    surf;                    /* surfaces */
  137.     int    cyl;                    /* cylinders */
  138.     int    size;                    /* #blocks */
  139. };
  140.  
  141. struct drvtyp drv_tab[] = {
  142.     { FLP_SECT, FLP_SURF, FLP_CYL, FLP_SIZE },
  143.     { D31_SECT, D31_SURF, D31_CYL, D31_SIZE },
  144.     { C111_SECT, C111_SURF, C111_CYL, C111_SIZE },
  145.     { D44_SECT, D44_SURF, D44_CYL, D44_SIZE },
  146.     { C114_SECT, C114_SURF, C114_CYL, C114_SIZE },
  147.     { 0 }  };
  148.  
  149. extern unsigned short M[];
  150. extern UNIT cpu_unit;
  151. extern int int_req, dev_busy, dev_done, dev_disable;
  152. int dkp_ma = 0;                        /* memory address */
  153. int dkp_ussc = 0;                    /* unit/sf/sc/cnt */
  154. int dkp_fccy = 0;                    /* flags/cylinder */
  155. int dkp_sta = 0;                    /* status register */
  156. int dkp_swait = 100;                    /* seek latency */
  157. int dkp_rwait = 100;                    /* rotate latency */
  158. int dkp_svc (UNIT *uptr);
  159. int dkp_reset (DEVICE *dptr);
  160. int dkp_boot (int unitno);
  161. int dkp_attach (UNIT *uptr, char *cptr);
  162. int dkp_go (void);
  163. int dkp_set_size (UNIT *uptr, int value);
  164. extern int sim_activate (UNIT *uptr, int interval);
  165. extern int sim_cancel (UNIT *uptr);
  166. extern int sim_is_active (UNIT *uptr);
  167. extern int attach_unit (UNIT *uptr, char *cptr);
  168.  
  169. /* DKP data structures
  170.  
  171.    dkp_dev    DKP device descriptor
  172.    dkp_unit    DKP unit list
  173.    dkp_reg    DKP register list
  174.    dkp_mod    DKP modifier list
  175. */
  176.  
  177. UNIT dkp_unit[] = {
  178.     { UDATA (&dkp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_ONLINE+
  179.         (D31_DTYPE << UNIT_V_DTYPE), D31_SIZE) },
  180.     { UDATA (&dkp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_ONLINE+
  181.         (D31_DTYPE << UNIT_V_DTYPE), D31_SIZE) },
  182.     { UDATA (&dkp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_ONLINE+
  183.         (D31_DTYPE << UNIT_V_DTYPE), D31_SIZE) },
  184.     { UDATA (&dkp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_ONLINE+
  185.         (D31_DTYPE << UNIT_V_DTYPE), D31_SIZE) }  };
  186.  
  187. REG dkp_reg[] = {
  188.     { ORDATA (FCCY, dkp_fccy, 16) },
  189.     { ORDATA (USSC, dkp_ussc, 16) },
  190.     { ORDATA (STA, dkp_sta, 16) },
  191.     { ORDATA (MA, dkp_ma, 16) },
  192.     { FLDATA (INT, int_req, INT_V_DKP) },
  193.     { FLDATA (BUSY, dev_busy, INT_V_DKP) },
  194.     { FLDATA (DONE, dev_done, INT_V_DKP) },
  195.     { FLDATA (DISABLE, dev_disable, INT_V_DKP) },
  196.     { DRDATA (STIME, dkp_swait, 24), PV_LEFT },
  197.     { DRDATA (RTIME, dkp_rwait, 24), PV_LEFT },
  198.     { GRDATA (FLG0, dkp_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF), REG_HRO },
  199.     { GRDATA (FLG1, dkp_unit[1].flags, 8, UNIT_W_UF, UNIT_V_UF), REG_HRO },
  200.     { GRDATA (FLG2, dkp_unit[2].flags, 8, UNIT_W_UF, UNIT_V_UF), REG_HRO },
  201.     { GRDATA (FLG3, dkp_unit[3].flags, 8, UNIT_W_UF, UNIT_V_UF), REG_HRO },
  202.     { DRDATA (CAPAC0, dkp_unit[0].capac, 32), PV_LEFT + REG_HRO },
  203.     { DRDATA (CAPAC1, dkp_unit[1].capac, 32), PV_LEFT + REG_HRO },
  204.     { DRDATA (CAPAC2, dkp_unit[2].capac, 32), PV_LEFT + REG_HRO },
  205.     { DRDATA (CAPAC3, dkp_unit[3].capac, 32), PV_LEFT + REG_HRO },
  206.     { NULL }  };
  207.  
  208. MTAB dkp_mod[] = {
  209.     { UNIT_ONLINE, 0, "offline", "OFFLINE", NULL },
  210.     { UNIT_ONLINE, UNIT_ONLINE, "online", "ONLINE", NULL },
  211.     { UNIT_WLK, 0, "write enabled", "ENABLED", NULL },
  212.     { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL },
  213.     { (UNIT_DTYPE+UNIT_ATT), (FLP_DTYPE << UNIT_V_DTYPE) + UNIT_ATT,
  214.         "floppy", NULL, NULL },
  215.     { (UNIT_DTYPE+UNIT_ATT), (D31_DTYPE << UNIT_V_DTYPE) + UNIT_ATT,
  216.         "Diablo 31", NULL, NULL },
  217.     { (UNIT_DTYPE+UNIT_ATT), (D44_DTYPE << UNIT_V_DTYPE) + UNIT_ATT,
  218.         "Diablo 44", NULL, NULL },
  219.     { (UNIT_DTYPE+UNIT_ATT), (C111_DTYPE << UNIT_V_DTYPE) + UNIT_ATT,
  220.         "Century 111", NULL, NULL },
  221.     { (UNIT_DTYPE+UNIT_ATT), (C114_DTYPE << UNIT_V_DTYPE) + UNIT_ATT,
  222.         "Century 114", NULL, NULL },
  223.     { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (FLP_DTYPE << UNIT_V_DTYPE),
  224.         "floppy", NULL, NULL },
  225.     { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (D31_DTYPE << UNIT_V_DTYPE),
  226.         "Diablo 31", NULL, NULL },
  227.     { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (D44_DTYPE << UNIT_V_DTYPE),
  228.         "Diablo 44", NULL, NULL },
  229.     { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (C111_DTYPE << UNIT_V_DTYPE),
  230.         "Century 111", NULL, NULL },
  231.     { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (C114_DTYPE << UNIT_V_DTYPE),
  232.         "Century 114", NULL, NULL },
  233.     { (UNIT_AUTO+UNIT_ATT), UNIT_AUTO, "autosize", NULL, NULL },
  234.     { UNIT_AUTO, UNIT_AUTO, NULL, "AUTOSIZE", NULL },
  235.      { (UNIT_AUTO+UNIT_DTYPE), (FLP_DTYPE << UNIT_V_DTYPE),
  236.         NULL, "FLOPPY", &dkp_set_size },
  237.     { (UNIT_AUTO+UNIT_DTYPE), (D31_DTYPE << UNIT_V_DTYPE),
  238.         NULL, "D31", &dkp_set_size }, 
  239.      { (UNIT_AUTO+UNIT_DTYPE), (D44_DTYPE << UNIT_V_DTYPE),
  240.         NULL, "D44", &dkp_set_size },
  241.      { (UNIT_AUTO+UNIT_DTYPE), (C111_DTYPE << UNIT_V_DTYPE),
  242.         NULL, "C111", &dkp_set_size },
  243.      { (UNIT_AUTO+UNIT_DTYPE), (C114_DTYPE << UNIT_V_DTYPE),
  244.         NULL, "C114", &dkp_set_size },
  245.     { 0 }  };
  246.  
  247. DEVICE dkp_dev = {
  248.     "DP", dkp_unit, dkp_reg, dkp_mod,
  249.     DKP_NUMDR, 8, 30, 1, 8, 16,
  250.     NULL, NULL, &dkp_reset,
  251.     &dkp_boot, &dkp_attach, NULL };
  252.  
  253. /* IOT routine */
  254.  
  255. int dkp (int pulse, int code, int AC)
  256. {
  257. UNIT *uptr;
  258. int u, rval;
  259.  
  260. rval = 0;
  261. switch (code) {                        /* decode IR<5:7> */
  262. case ioDIA:                        /* DIA */
  263.     dkp_sta = dkp_sta & ~STA_DYN;            /* clear dynamic */
  264.     uptr = dkp_dev.units + GET_UNIT (dkp_ussc);    /* select unit */
  265.     if ((uptr -> flags & UNIT_ATT) && (uptr -> flags & UNIT_ONLINE))
  266.         dkp_sta = dkp_sta | STA_DRDY;        /* online? */
  267.     if (uptr -> CYL >= drv_tab[GET_DTYPE (uptr -> flags)].cyl)
  268.         dkp_sta = dkp_sta | STA_CYL;        /* bad cylinder? */
  269.     if (dkp_sta & STA_EFLGS) dkp_sta = dkp_sta | STA_ERR;
  270.     rval = dkp_sta;
  271.     break;
  272. case ioDOA:                        /* DOA */
  273.     if ((dev_busy & INT_DKP) == 0) {
  274.         dkp_fccy = AC;                /* save cmd, cyl */
  275.         dkp_sta = dkp_sta & ~(AC & FCCY_FLAGS);  }
  276.     break;
  277. case ioDIB:                        /* DIB */
  278.     rval = dkp_ma & ADDRMASK;            /* return buf addr */
  279.     break;
  280. case ioDOB:                        /* DOB */
  281.     if ((dev_busy & INT_DKP) == 0) dkp_ma = AC & ADDRMASK; /* save ma */
  282.     break;
  283. case ioDIC:                        /* DIC */
  284.     rval = dkp_ussc;                /* return unit, sect */
  285.     break;
  286. case ioDOC:                        /* DOC */
  287.     if ((dev_busy & INT_DKP) == 0) dkp_ussc = AC;    /* save unit, sect */
  288.     break;  }                    /* end switch code */
  289.  
  290. /* IOT, continued */
  291.  
  292. u = GET_UNIT(dkp_ussc);                    /* select unit */
  293. switch (pulse) {                    /* decode IR<8:9> */
  294. case iopS:                        /* start */
  295.     dev_busy = dev_busy | INT_DKP;            /* set busy */
  296.     dev_done = dev_done & ~INT_DKP;            /* clear done */
  297.     int_req = int_req & ~INT_DKP;            /* clear int */
  298.     if (dkp_go ()) break;                /* new cmd, error? */
  299.     dev_busy = dev_busy & ~INT_DKP;            /* clear busy */
  300.     dev_done = dev_done | INT_DKP;            /* set done */
  301.     int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable);
  302.     dkp_sta = dkp_sta | STA_DONE;
  303.     break;
  304. case iopC:                        /* clear */
  305.     dev_busy = dev_busy & ~INT_DKP;            /* clear busy */
  306.     dev_done = dev_done & ~INT_DKP;            /* clear done */
  307.     int_req = int_req & ~INT_DKP;            /* clear int */
  308.     dkp_sta = dkp_sta & ~(STA_DFLGS + STA_EFLGS);
  309.     if (dkp_unit[u].FUNC != FCCY_SEEK) sim_cancel (&dkp_unit[u]);
  310.     break;
  311. case iopP:                        /* pulse */
  312.     dev_done = dev_done & ~INT_DKP;            /* clear done */
  313.     if (dkp_go ()) break;                /* new seek command */
  314.     dev_done = dev_done | INT_DKP;            /* set done */
  315.     int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable);
  316.     dkp_sta = dkp_sta | (STA_SKDN0 >> u);        /* set seek done */
  317.     break;  }                    /* end case pulse */
  318. return rval;
  319. }
  320.  
  321. /* New command, start vs pulse handled externally
  322.    Returns true if command ok, false if error
  323. */
  324.  
  325. int dkp_go (void)
  326. {
  327. UNIT *uptr;
  328. int newcyl, func, u;
  329.  
  330. dkp_sta = dkp_sta & ~STA_EFLGS;                /* clear errors */
  331. u = GET_UNIT (dkp_ussc);                /* get unit number */
  332. uptr = dkp_dev.units + u;                /* get unit */
  333. if (((uptr -> flags & UNIT_ONLINE) == 0) ||         /* drive offline */
  334.     ((uptr -> flags & UNIT_ATT) == 0) ||        /* or not attached */
  335.       sim_is_active (uptr)) {                /* or active? */
  336.     dkp_sta = dkp_sta | STA_ERR;            /* yes, error */
  337.     return FALSE;  }
  338. func = GET_CMD (dkp_fccy);                /* get function */
  339. newcyl = GET_CYL (dkp_fccy);                /* get cylinder */
  340. switch (func) {                        /* decode command */
  341. case FCCY_READ: case FCCY_WRITE:
  342.     sim_activate (uptr, dkp_rwait);            /* schedule */
  343.     break;
  344. case FCCY_RECAL:                    /* recalibrate */
  345.     newcyl = 0;
  346.     func = FCCY_SEEK;
  347. case FCCY_SEEK:                     /* seek */
  348.     sim_activate (uptr, dkp_swait * abs (newcyl - uptr -> CYL));
  349.     dkp_sta = dkp_sta | (STA_SEEK0 >> u);    /* set seeking */
  350.     uptr -> CYL = newcyl;                /* on cylinder */
  351.     break;  }                    /* end case command */
  352. uptr -> FUNC = func;                    /* save command */
  353. return TRUE;                        /* no error */
  354. }
  355.  
  356. /* Unit service
  357.  
  358.    If seek done, put on cylinder;
  359.    else, do read or write
  360.    If controller was busy, clear busy, set done, interrupt
  361.  
  362.    NXM calculation: this takes advantage of the 4KW granularity of
  363.    memory, versus the 4KW maximum transfer size.  The end address
  364.    is calculated as an absolute value; thus it may be ok, non-
  365.    existant, or greater than 32KW (wraps to first bank).
  366.  
  367.    start addr    end addr    wc            wc1
  368.     ok    ok        unchanged        0
  369.     ok    nxm        MEMSIZE-dkp_ma        < 0
  370.     ok    wrapped        MEMSIZE-dkp_ma        dkp_ma+wc mod 32K
  371.     nxm    ok        impossible
  372.     nxm    nxm        < 0            < 0
  373.     nxm    wrapped        < 0            dkp-ma+wc mod 32K
  374. */
  375.  
  376. int dkp_svc (uptr)
  377. UNIT *uptr;
  378. {
  379. int sc, sa, xcsa, wc, wc1, awc, fc, bda;
  380. int dtype, u, err, rval, newsect, newsurf;
  381.  
  382. rval = SCPE_OK;
  383. dtype = GET_DTYPE (uptr -> flags);            /* get drive type */
  384. if (uptr -> FUNC == FCCY_SEEK) {            /* seek? */
  385.     if (uptr -> CYL >= drv_tab[dtype].cyl)        /* bad cylinder? */
  386.         dkp_sta = dkp_sta | STA_ERR | STA_CYL;
  387.     dev_done = dev_done | INT_DKP;            /* set done */
  388.     int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable);
  389.     u = uptr - dkp_dev.units;            /* get unit number */
  390.     dkp_sta = (dkp_sta | (STA_SKDN0 >> u))        /* set seek done */
  391.         & ~(STA_SEEK0 >> u);            /* clear seeking */
  392.     return SCPE_OK;  }
  393.  
  394. if (((uptr -> flags & UNIT_ONLINE) == 0) ||         /* drive offline */
  395.     ((uptr -> flags & UNIT_ATT) == 0) ||        /* or not attached? */
  396.     ((uptr -> flags & UNIT_WLK) && (uptr -> FUNC == FCCY_WRITE)))
  397.     dkp_sta = dkp_sta | STA_DONE | STA_ERR;        /* error */
  398.  
  399. else if ((uptr -> CYL >= drv_tab[dtype].cyl) ||        /* bad cylinder */
  400.      (GET_SURF (dkp_ussc) >= drv_tab[dtype].surf) || /* bad surface */
  401.          (GET_SECT (dkp_ussc) >= drv_tab[dtype].sect))    /* or bad sector? */
  402.     dkp_sta = dkp_sta | STA_DONE | STA_ERR | STA_UNS;
  403.  
  404. else {    sc = 16 - GET_COUNT (dkp_ussc);            /* get sector count */
  405.     sa = GET_SA (uptr -> CYL, GET_SURF (dkp_ussc),
  406.         GET_SECT (dkp_ussc), dtype);        /* get disk block */
  407.     xcsa = GET_SA (uptr -> CYL + 1, 0, 0, dtype);    /* get next cyl addr */
  408.     if ((sa + sc) > xcsa ) {            /* across cylinder? */
  409.         sc = xcsa - sa;                /* limit transfer */
  410.         dkp_sta = dkp_sta | STA_XCY;  }        /* xcyl error */
  411.     wc = sc * DKP_NUMWD;                /* convert blocks */
  412.     bda = sa * DKP_NUMWD * sizeof (short);        /* to words, bytes */
  413.     if ((dkp_ma + wc) <= MEMSIZE) wc1 = 0;        /* xfer fit? */
  414.     else {    wc = MEMSIZE - dkp_ma;            /* calculate xfer */
  415.         wc1 = (dkp_ma + wc) - MAXMEMSIZE;  }    /* calculate wrap */
  416.  
  417.     err = fseek (uptr -> fileref, bda, SEEK_SET);    /* position drive */
  418.  
  419.     if (uptr -> FUNC == FCCY_READ) {        /* read? */
  420.         if ((wc > 0) && (err == 0)) {        /* start in memory? */
  421.         awc = fread (&M[dkp_ma], sizeof (short), wc, uptr -> fileref);
  422.         for ( ; awc < wc; awc++) M[(dkp_ma + awc) & ADDRMASK] = 0;
  423.         err = ferror (uptr -> fileref);
  424.         dkp_ma = (dkp_ma + wc) & ADDRMASK;  }
  425.         if ((wc1 > 0) && (err == 0)) {        /* memory wrap? */
  426.         awc = fread (&M[0], sizeof (short), wc1, uptr -> fileref);
  427.         for ( ; awc < wc1; awc++) M[0 + awc] = 0;
  428.         err = ferror (uptr -> fileref);  
  429.         dkp_ma = (dkp_ma + wc1) & ADDRMASK;  }  }
  430.  
  431.     if (uptr -> FUNC == FCCY_WRITE) {        /* write? */
  432.         if ((wc > 0) && (err == 0)) {        /* start in memory? */
  433.         fwrite (&M[dkp_ma], sizeof (short), wc, uptr -> fileref);
  434.         err = ferror (uptr -> fileref);
  435.         dkp_ma = (dkp_ma + wc + 2) & ADDRMASK;  }
  436.         if ((wc1 > 0) && (err == 0)) {        /* memory wrap? */
  437.         fwrite (&M[0], sizeof (short), wc1, uptr -> fileref);
  438.         err = ferror (uptr -> fileref);
  439.         dkp_ma = (dkp_ma + wc1) & ADDRMASK;  }  }
  440.  
  441.     if (err != 0) {
  442.         perror ("DKP I/O error");
  443.         rval = SCPE_IOERR;  }
  444.     clearerr (uptr -> fileref);
  445.  
  446.     sa = sa + sc;                    /* update sector addr */
  447.     newsect = sa % drv_tab[dtype].sect;
  448.     newsurf = (sa / drv_tab[dtype].sect) % drv_tab[dtype].surf;
  449.     dkp_ussc = (dkp_ussc & USSC_UNIT) | (newsurf << USSC_V_SURFACE) |
  450.         (newsect << USSC_V_SECTOR) | ((dkp_ussc + sc) & USSC_M_COUNT);
  451.     dkp_sta = dkp_sta | STA_DONE;  }        /* set status */
  452.  
  453. dev_busy = dev_busy & ~INT_DKP;                /* clear busy */
  454. dev_done = dev_done | INT_DKP;                /* set done */
  455. int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable);
  456. return rval;
  457. }
  458.  
  459. /* Reset routine */
  460.  
  461. int dkp_reset (dptr)
  462. DEVICE *dptr;
  463. {
  464. int i, u;
  465. UNIT *uptr;
  466.  
  467. dev_busy = dev_busy & ~INT_DKP;                /* clear busy */
  468. dev_done = dev_done & ~INT_DKP;                /* clear done, int */
  469. int_req = int_req & ~INT_DKP;
  470. dkp_fccy = dkp_ussc = dkp_ma = dkp_sta = 0;        /* clear registers */
  471. for (u = 0; u < DKP_NUMDR; u++) {            /* loop thru units */
  472.     uptr = dkp_dev.units + u;
  473.     sim_cancel (uptr);                /* cancel activity */
  474.     uptr -> CYL = uptr -> FUNC = 0;  }
  475. return SCPE_OK;
  476. }
  477.  
  478. /* Attach routine (with optional autosizing) */
  479.  
  480. int dkp_attach (UNIT *uptr, char *cptr)
  481. {
  482. int i, p, r;
  483.  
  484. uptr -> capac = drv_tab[GET_DTYPE (uptr -> flags)].size;
  485. r = attach_unit (uptr, cptr);
  486. if ((r != SCPE_OK) || ((uptr -> flags & UNIT_AUTO) == 0)) return r;
  487. if (fseek (uptr -> fileref, 0, SEEK_END)) return SCPE_OK;
  488. if ((p = ftell (uptr -> fileref)) == 0) return SCPE_OK;
  489. for (i = 0; drv_tab[i].sect != 0; i++) {
  490.     if (p <= (drv_tab[i].size * sizeof (short))) {
  491.     uptr -> flags = (uptr -> flags & ~UNIT_DTYPE) | (i << UNIT_V_DTYPE);
  492.     uptr -> capac = drv_tab[i].size;
  493.     return SCPE_OK;  }  }
  494. return SCPE_OK;
  495. }
  496.  
  497. /* Set size command validation routine */
  498.  
  499. int dkp_set_size (UNIT *uptr, int value)
  500. {
  501. if (uptr -> flags & UNIT_ATT) return SCPE_ALATT;
  502. uptr -> capac = drv_tab[GET_DTYPE (value)].size;
  503. return SCPE_OK;
  504. }
  505.  
  506. /* Bootstrap routine */
  507.  
  508. #define BOOT_START 02000
  509. #define BOOT_UNIT 02021
  510. #define BOOT_LEN (sizeof (boot_rom) / sizeof (int))
  511.  
  512. static const int boot_rom[] = {
  513.     060233,            /* NIOC 0,DKP        ; clear disk */
  514.     020420,            /* LDA 0,USSC         ; unit, sfc, sec, cnt */
  515.     063033,            /* DOC 0,DKP        ; select disk */
  516.     020417,            /* LDA 0,SEKCMD        ; command, cylinder */
  517.     061333,            /* DOAP 0,DKP        ; start seek */
  518.     024415,            /* LDA 1,SEKDN */
  519.     060433,            /* DIA 0,DKP        ; get status */
  520.     0123415,        /* AND# 1,0,SZR        ; skip if done */
  521.     000776,            /* JMP .-2 */
  522.     0102400,        /* SUB 0,0         ; mem addr = 0 */
  523.     062033,            /* DOB 0,DKP */
  524.     020411,            /* LDA 0,REDCMD        ; command, cylinder */
  525.     061133,            /* DOAS 0,DKP        ; start read */
  526.     060433,            /* DIA 0, DKP        ; get status */
  527.     0101113,        /* MOVL# 0,0,SNC    ; skip if done */
  528.     000776,            /* JMP .-2 */
  529.     000377,            /* JMP 377 */
  530.     000016,            /* USSC: 0.B1+0.B7+0.B11+16 */
  531.     0175000,        /* SEKCMD: 175000 */
  532.     074000,            /* SEKDN: 074000 */
  533.     0174000            /* REDCMD: 174000 */
  534. };
  535.  
  536. int dkp_boot (int unitno)
  537. {
  538. int i;
  539. extern int saved_PC;
  540.  
  541. for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i];
  542. M[BOOT_UNIT] = M[BOOT_UNIT] | ((unitno & USSC_M_UNIT) << USSC_V_UNIT);
  543. saved_PC = BOOT_START;
  544. return SCPE_OK;
  545. }
  546.