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

  1. /* RP15/RP02 disk pack simulator
  2.  
  3.    Copyright (c) 1996, Robert M Supnik, Digital Equipment Corporation
  4.    Commercial use prohibited
  5.  
  6.    rp        RP15/RP02 disk pack
  7. */
  8.  
  9. #ifndef PDP15
  10. #define PDP15 0
  11. #endif
  12.  
  13. #include "pdp18b_defs.h"
  14.  
  15. /* Constants */
  16.  
  17. #define RP_NUMWD    256                /* words/sector */
  18. #define RP_NUMSC    10                /* sectors/surface */
  19. #define RP_NUMSF    20                /* surfaces/cylinder */
  20. #define RP_NUMCY    203                /* cylinders/drive */
  21. #define RP_NUMDR    8                /* drives/controller */
  22. #define RP_SIZE (RP_NUMCY * RP_NUMSF * RP_NUMSC * RP_NUMWD)  /* words/drive */
  23.  
  24. /* Unit specific flags */
  25.  
  26. #define UNIT_V_HWLK    (UNIT_V_UF + 0)            /* hwre write lock */
  27. #define UNIT_W_UF    1                /* user flags width */
  28. #define UNIT_HWLK    (1u << UNIT_V_HWLK)
  29.  
  30. /* Parameters in the unit descriptor */
  31.  
  32. #define CYL        u3                /* current cylinder */
  33. #define FUNC        u4                /* function */
  34.  
  35. /* Status register A */
  36.  
  37. #define STA_V_UNIT    15                /* unit select */
  38. #define STA_M_UNIT    07
  39. #define STA_V_FUNC    12                /* function */
  40. #define STA_M_FUNC    07
  41. #define  FN_IDLE    0
  42. #define  FN_READ    1
  43. #define  FN_WRITE    2
  44. #define  FN_RECAL    3
  45. #define  FN_SEEK    4
  46. #define  FN_RDALL    5
  47. #define  FN_WRALL    6
  48. #define  FN_WRCHK    7
  49. #define  FN_2ND        010                /* second state flag */
  50. #define STA_IED        0004000                /* int enable done */
  51. #define STA_IEA        0002000                /* int enable attn */
  52. #define STA_GO        0001000                /* go */
  53. #define STA_WPE        0000400                /* write lock error */
  54. #define STA_NXC        0000200                /* nx cyl error */
  55. #define STA_NXF        0000100                /* nx surface error */
  56. #define STA_NXS        0000040                /* nx sector error */
  57. #define STA_HNF        0000020                /* hdr not found */
  58. #define STA_SUWP    0000010                /* sel unit wrt lock */
  59. #define STA_SUSI    0000004                /* sel unit seek inc */
  60. #define STA_DON        0000002                /* done */
  61. #define STA_ERR        0000001                /* error */
  62.  
  63. #define STA_RW        0777000                /* read/write */
  64. #define STA_EFLGS    (STA_WPE | STA_NXC | STA_NXF | STA_NXS | \
  65.              STA_HNF | STA_SUSI)        /* error flags */
  66. #define STA_DYN        (STA_SUWP | STA_SUSI)        /* per unit status */
  67. #define GET_UNIT(x)    (((x) >> STA_V_UNIT) & STA_M_UNIT)
  68. #define GET_FUNC(x)    (((x) >> STA_V_FUNC) & STA_M_FUNC)
  69.  
  70. /* Status register B */
  71.  
  72. #define STB_V_ATT0    17                /* unit 0 attention */
  73. #define STB_ATTN    0776000                /* attention flags */
  74. #define STB_SUFU    0001000                /* sel unit unsafe */
  75. #define STB_PGE        0000400                /* programming error */
  76. #define STB_EOP        0000200                /* end of pack */
  77. #define STB_TME        0000100                /* timing error */
  78. #define STB_FME        0000040                /* format error */
  79. #define STB_WCE        0000020                /* write check error */
  80. #define STB_WPE        0000010                /* word parity error */
  81. #define STB_LON        0000004                /* long parity error */
  82. #define STB_SUSU    0000002                /* sel unit seeking */
  83. #define STB_SUNR    0000001                /* sel unit not rdy */
  84.  
  85. #define STB_EFLGS    (STB_SUFU | STB_PGE | STB_EOP | STB_TME | STB_FME | \
  86.              STB_WCE | STB_WPE | STB_LON )    /* error flags */
  87. #define STB_DYN        (STB_SUFU | STB_SUSU | STB_SUNR)    /* per unit */
  88.  
  89. /* Disk address */
  90.  
  91. #define DA_V_SECT    0                /* sector */
  92. #define DA_M_SECT    017
  93. #define DA_V_SURF    5
  94. #define DA_M_SURF    037
  95. #define DA_V_CYL    10                /* cylinder */
  96. #define DA_M_CYL    0377
  97. #define GET_SECT(x)    (((x) >> DA_V_SECT) & DA_M_SECT)
  98. #define GET_SURF(x)    (((x) >> DA_V_SURF) & DA_M_SURF)
  99. #define GET_CYL(x)    (((x) >> DA_V_CYL) & DA_M_CYL)
  100. #define GET_DA(x)    ((((GET_CYL (x) * RP_NUMSF) + GET_SURF (x)) * \
  101.             RP_NUMSC) + GET_SECT (x))
  102.  
  103. #define RP_MIN 2
  104. #define MAX(x,y) (((x) > (y))? (x): (y))
  105.  
  106. extern unsigned int M[];                /* memory */
  107. extern int int_req, nexm;
  108. extern UNIT cpu_unit;
  109. int rp_sta = 0;                        /* status A */
  110. int rp_stb = 0;                        /* status B */
  111. int rp_ma = 0;                        /* memory address */
  112. int rp_da = 0;                        /* disk address */
  113. int rp_wc = 0;                        /* word count */
  114. int rp_busy = 0;                    /* busy */
  115. int rp_stopioe = 1;                    /* stop on error */
  116. int rp_swait = 10;                    /* seek time */
  117. int rp_rwait = 10;                    /* rotate time */
  118. int rp_svc (UNIT *uptr);
  119. void rp_updsta (int newa, int newb);
  120. int rp_reset (DEVICE *dptr);
  121. int rp_attach (UNIT *uptr, char *cptr);
  122. int rp_detach (UNIT *uptr);
  123. extern int sim_activate (UNIT *uptr, int interval);
  124. extern int sim_cancel (UNIT *uptr);
  125. extern int sim_is_active (UNIT *uptr);
  126. extern int attach_unit (UNIT *uptr, char *cptr);
  127. extern int detach_unit (UNIT *uptr);
  128.  
  129. /* RP15 data structures
  130.  
  131.    rp_dev    RP device descriptor
  132.    rp_unit    RP unit list
  133.    rp_reg    RP register list
  134.    rp_mod    RP modifier list
  135. */
  136.  
  137. UNIT rp_unit[] = {
  138.     { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE, RP_SIZE) },
  139.     { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE, RP_SIZE) },
  140.     { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE, RP_SIZE) },
  141.     { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE, RP_SIZE) },
  142.     { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE, RP_SIZE) },
  143.     { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE, RP_SIZE) },
  144.     { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE, RP_SIZE) },
  145.     { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE, RP_SIZE) } };
  146.  
  147. REG rp_reg[] = {
  148.     { ORDATA (STA, rp_sta, 18) },
  149.     { ORDATA (STB, rp_stb, 18) },
  150.     { ORDATA (DA, rp_da, 18) },
  151.     { ORDATA (MA, rp_ma, 18) },
  152.     { ORDATA (WC, rp_wc, 18) },
  153.     { FLDATA (INT, int_req, INT_V_RP) },
  154.     { FLDATA (BUSY, rp_busy, 0) },
  155.     { DRDATA (STIME, rp_swait, 24), PV_LEFT },
  156.     { DRDATA (RTIME, rp_rwait, 24), PV_LEFT },
  157.     { GRDATA (FLG0, rp_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF), REG_HRO },
  158.     { GRDATA (FLG1, rp_unit[1].flags, 8, UNIT_W_UF, UNIT_V_UF), REG_HRO },
  159.     { GRDATA (FLG2, rp_unit[2].flags, 8, UNIT_W_UF, UNIT_V_UF), REG_HRO },
  160.     { GRDATA (FLG3, rp_unit[3].flags, 8, UNIT_W_UF, UNIT_V_UF), REG_HRO },
  161.     { GRDATA (FLG4, rp_unit[4].flags, 8, UNIT_W_UF, UNIT_V_UF), REG_HRO },
  162.     { GRDATA (FLG5, rp_unit[5].flags, 8, UNIT_W_UF, UNIT_V_UF), REG_HRO },
  163.     { GRDATA (FLG6, rp_unit[6].flags, 8, UNIT_W_UF, UNIT_V_UF), REG_HRO },
  164.     { GRDATA (FLG7, rp_unit[7].flags, 8, UNIT_W_UF, UNIT_V_UF), REG_HRO },
  165.     { FLDATA (STOP_IOE, rp_stopioe, 0) },
  166.     { NULL }  };
  167.  
  168. MTAB rp_mod[] = {
  169.     { UNIT_HWLK, 0, "write enabled", "ENABLED", NULL },
  170.     { UNIT_HWLK, UNIT_HWLK, "write locked", "LOCKED", NULL },
  171.     { 0 }  };
  172.  
  173. DEVICE rp_dev = {
  174.     "RP", rp_unit, rp_reg, rp_mod,
  175.     RP_NUMDR, 8, 24, 1, 8, 18,
  176.     NULL, NULL, &rp_reset,
  177.     NULL, &rp_attach, &rp_detach };
  178.  
  179. /* IOT routines */
  180.  
  181. int rp63 (int pulse, int AC)
  182. {
  183. rp_updsta (0, 0);
  184. if (pulse == 001)                    /* DPSF */
  185.     return ((rp_sta & (STA_DON | STA_ERR)) || (rp_stb & STB_ATTN))?
  186.         IOT_SKP + AC: AC;
  187. if (pulse == 021)                    /* DPSA */
  188.     return (rp_stb & STB_ATTN)? IOT_SKP + AC: AC;
  189. if (pulse == 041)                    /* DPSJ */
  190.     return (rp_sta & STA_DON)? IOT_SKP + AC: AC;
  191. if (pulse == 061)                    /* DPSE */
  192.     return (rp_sta & STA_ERR)? IOT_SKP + AC: AC;
  193. if (pulse == 002) return rp_sta;            /* DPOSA */
  194. if (pulse == 022) return rp_stb;            /* DPOSB */
  195. if (((pulse & 007) == 004) && rp_busy) {        /* busy? */
  196.     rp_updsta (0, STB_PGE);
  197.     return AC;  }
  198. if (pulse == 004) {                    /* DPLA */
  199.     rp_da = AC;
  200.     if (GET_SECT (rp_da) >= RP_NUMSC) rp_updsta (STA_NXS, 0);
  201.     if (GET_SURF (rp_da) >= RP_NUMSF) rp_updsta (STA_NXF, 0);
  202.     if (GET_CYL (rp_da) >= RP_NUMCY) rp_updsta (STA_NXC, 0);  }
  203. if (pulse == 024) {                    /* DPCS */
  204.     rp_sta = rp_sta & ~(STA_HNF | STA_DON);
  205.     rp_stb = rp_stb & ~(STB_FME | STB_WPE | STB_LON | STB_WCE |
  206.         STB_TME | STB_PGE | STB_EOP);
  207.     rp_updsta (0, 0);  }
  208. if (pulse == 044) rp_ma = AC;                /* DPCA */
  209. if (pulse == 064) rp_wc = AC;                /* DPWC */
  210. return AC;
  211. }
  212.  
  213. /* IOT 64 */
  214.  
  215. int rp64 (int pulse, int AC)
  216. {
  217. int u, f, c;
  218. UNIT *uptr;
  219.  
  220. if (pulse == 021) return IOT_SKP + AC;            /* DPSN */
  221. if (pulse == 002) return rp_unit[GET_UNIT (rp_sta)].CYL; /* DPOU */
  222. if (pulse == 022) return rp_da;                /* DPOA */
  223. if (pulse == 042) return rp_ma;                /* DPOC */
  224. if (pulse == 062) return rp_wc;                /* DPOW */
  225. if ((pulse & 007) != 004) return AC;
  226. if (rp_busy) {                        /* busy? */
  227.     rp_updsta (0, STB_PGE);
  228.     return AC;  }
  229. if (pulse == 004) rp_sta = rp_sta & ~STA_RW;        /* DPCF */
  230. if (pulse == 024) rp_sta = rp_sta & (AC | ~STA_RW);    /* DPLZ */
  231. if (pulse == 044) rp_sta = rp_sta | (AC & STA_RW);    /* DPLO */
  232. if (pulse == 064) rp_sta = (rp_sta & ~STA_RW) | (AC & STA_RW); /* DPLF */
  233. if (rp_sta & STA_GO) {
  234.     u = GET_UNIT (rp_sta);                /* get unit num */
  235.     uptr = rp_dev.units + u;            /* select unit */
  236.     if (sim_is_active (uptr)) return AC;        /* can't if busy */
  237.     f = uptr -> FUNC = GET_FUNC (rp_sta);        /* get function */
  238.     rp_busy = 1;                    /* set ctrl busy */
  239.     rp_sta = rp_sta & ~(STA_HNF | STA_DON);        /* clear flags */
  240.     rp_stb = rp_stb & ~(STB_FME | STB_WPE | STB_LON | STB_WCE |
  241.         STB_TME | STB_PGE | STB_EOP | (1 << (STB_V_ATT0 - u)));
  242.     if (((uptr -> flags & UNIT_ATT) == 0) || (f == FN_IDLE) ||
  243.          (f == FN_SEEK) || (f == FN_RECAL))
  244.         sim_activate (uptr, RP_MIN);        /* short delay */
  245.     else {    c = GET_CYL (rp_da);
  246.         c = abs (c - uptr -> CYL) * rp_swait;    /* seek time */
  247.         sim_activate (uptr, MAX (RP_MIN, c + rp_rwait));  }  }
  248. rp_updsta (0, 0);
  249. return AC;
  250. }
  251.  
  252. /* Unit service
  253.  
  254.    If function = idle, clear busy
  255.    If seek or recal initial state, clear attention line, compute seek time,
  256.     put on cylinder, set second state
  257.    If unit not attached, give error
  258.    If seek or recal second state, set attention line, compute errors
  259.    Else complete data transfer command
  260.  
  261.    The unit control block contains the function and cylinder for
  262.    the current command.
  263. */
  264.  
  265. static const unsigned int fill[RP_NUMWD] = { 0 };
  266. int rp_svc (UNIT *uptr)
  267. {
  268. int f, u, comp, cyl, sect, surf;
  269. int err, pa, da, wc, awc, i;
  270.  
  271. u = uptr - rp_dev.units;                /* get drv number */
  272. f = uptr -> FUNC;                    /* get function */
  273. if (f == FN_IDLE) {                    /* idle? */
  274.     rp_busy = 0;                    /* clear busy */
  275.     return SCPE_OK;  }
  276.  
  277. if ((f == FN_SEEK) || (f == FN_RECAL)) {        /* seek or recal? */
  278.     rp_busy = 0;                    /* not busy */
  279.     cyl = (f == FN_SEEK)? GET_CYL (rp_da): 0;    /* get cylinder */
  280.     sim_activate (uptr, MAX (RP_MIN, abs (cyl - uptr -> CYL) * rp_swait));
  281.     uptr -> CYL = cyl;                /* on cylinder */
  282.     uptr -> FUNC = FN_SEEK | FN_2ND;        /* set second state */
  283.     rp_updsta (0, 0);                /* update status */
  284.     return SCPE_OK;  }
  285.  
  286. if (f == (FN_SEEK | FN_2ND)) {                /* seek done? */
  287.     rp_updsta (0, rp_stb | (1 << (STB_V_ATT0 - u))); /* set attention */
  288.     return SCPE_OK;  }
  289.  
  290. if ((uptr -> flags & UNIT_ATT) == 0) {            /* not attached? */
  291.     rp_updsta (STA_DON, STB_SUFU);            /* done, unsafe */
  292.     return IORETURN (rp_stopioe, SCPE_UNATT);  }
  293.  
  294. if (GET_SECT (rp_da) >= RP_NUMSC) rp_updsta (STA_NXS, 0);
  295. if (GET_SURF (rp_da) >= RP_NUMSF) rp_updsta (STA_NXF, 0);
  296. if (GET_CYL (rp_da) >= RP_NUMCY) rp_updsta (STA_NXC, 0);
  297. if (rp_sta & (STA_NXS | STA_NXF | STA_NXC)) {        /* or bad disk addr? */
  298.     rp_updsta (STA_DON, STB_SUFU);            /* done, unsafe */
  299.     return SCPE_OK;  }
  300.  
  301. pa = rp_ma & ADDRMASK;                    /* get mem addr */
  302. da = GET_DA (rp_da) * RP_NUMWD;                /* get disk addr */
  303. wc = 01000000 - rp_wc;                    /* get true wc */
  304. if ((pa + wc) > MEMSIZE) {                /* memory overrun? */
  305.     nexm = 1;                    /* set nexm flag */
  306.     wc = MEMSIZE - pa;  }                /* limit xfer */
  307. if ((da + wc) > RP_SIZE) {                /* disk overrun? */
  308.     rp_updsta (0, STB_EOP);                /* error */
  309.     wc = RP_SIZE - da;  }                /* limit xfer */
  310.  
  311. err = fseek (uptr -> fileref, da * sizeof (int), SEEK_SET);
  312.  
  313. if ((f == FN_READ) && (err == 0)) {            /* read? */
  314.     awc = fread (&M[pa], sizeof (int), wc, uptr -> fileref);
  315.     for ( ; awc < wc; awc++) M[pa + awc] = 0;
  316.     err = ferror (uptr -> fileref);  }
  317.  
  318. if ((f == FN_WRITE) && (err == 0)) {            /* write? */
  319.     fwrite (&M[pa], sizeof (int), wc, uptr -> fileref);
  320.     err = ferror (uptr -> fileref);
  321.     if ((err == 0) && (i = (wc & (RP_NUMWD - 1)))) {
  322.         fwrite (fill, sizeof (int), i, uptr -> fileref);
  323.         err = ferror (uptr -> fileref);  }  }
  324.  
  325. if ((f == FN_WRCHK) && (err == 0)) {            /* write check? */
  326.     for (i = 0; (err == 0) && (i < wc); i++)  {
  327.         awc = fread (&comp, sizeof (int), 1, uptr -> fileref);
  328.         if (awc == 0) comp = 0;
  329.         if (comp != M[pa + i]) rp_updsta (0, STB_WCE);  }
  330.     err = ferror (uptr -> fileref);  }
  331.  
  332. rp_wc = (rp_wc + wc) & 0777777;                /* final word count */
  333. rp_ma = (rp_ma + wc) & 0777777;                /* final mem addr */
  334. da = (da + wc + (RP_NUMWD - 1)) / RP_NUMWD;        /* final sector num */
  335. cyl = da / (RP_NUMSC * RP_NUMSF);            /* get cyl */
  336. if (cyl >= RP_NUMCY) cyl = RP_NUMCY - 1;
  337. surf = (da % (RP_NUMSC * RP_NUMSF)) / RP_NUMSC;        /* get surface */
  338. sect = (da % (RP_NUMSC * RP_NUMSF)) % RP_NUMSC;        /* get sector */
  339. rp_da = (cyl << DA_V_CYL) | (surf << DA_V_SURF) | (sect << DA_V_SECT);
  340. rp_busy = 0;                        /* clear busy */
  341. rp_updsta (STA_DON, 0);                    /* set done */
  342.  
  343. if (err != 0) {                        /* error? */
  344.     perror ("RP I/O error");
  345.     clearerr (uptr -> fileref);
  346.     return IORETURN (rp_stopioe, SCPE_IOERR);  }
  347. return SCPE_OK;
  348. }
  349.  
  350. /* Update status */
  351.  
  352. void rp_updsta (int newa, int newb)
  353. {
  354. int f;
  355. UNIT *uptr;
  356.  
  357. uptr = rp_dev.units + GET_UNIT (rp_sta);
  358. rp_sta = (rp_sta & ~(STA_DYN | STA_ERR)) | newa;
  359. rp_stb = (rp_stb & ~STB_DYN) | newb;
  360. if (uptr -> flags & UNIT_HWLK) rp_sta = rp_sta | STA_SUWP;
  361. if ((uptr -> flags & UNIT_ATT) == 0) rp_stb = rp_stb | STB_SUFU | STB_SUNR;
  362. else if (sim_is_active (uptr)) {
  363.     f = (uptr -> FUNC) & STA_M_FUNC;
  364.     if ((f == FN_SEEK) || (f == FN_RECAL))
  365.         rp_stb = rp_stb | STB_SUSU | STB_SUNR;  }
  366. else if (uptr -> CYL >= RP_NUMCY) rp_sta = rp_sta | STA_SUSI;
  367. if ((rp_sta & STA_EFLGS) || (rp_stb & STB_EFLGS)) rp_sta = rp_sta | STA_ERR;
  368. if (((rp_sta & (STA_ERR | STA_DON)) && (rp_sta & STA_IED)) ||
  369.     ((rp_stb & STB_ATTN) && (rp_sta & STA_IEA))) int_req = int_req | INT_RP;
  370. else int_req = int_req & ~INT_RP;
  371. return;
  372. }
  373.  
  374. /* Reset routine */
  375.  
  376. int rp_reset (DEVICE *dptr)
  377. {
  378. int i;
  379. UNIT *uptr;
  380.  
  381. rp_sta = rp_stb = rp_da = rp_wc = rp_ma = rp_busy = 0;
  382. int_req = int_req & ~INT_RP;
  383. for (i = 0; i < RP_NUMDR; i++) {
  384.     uptr = rp_dev.units + i;
  385.     sim_cancel (uptr);
  386.     uptr -> CYL = uptr -> FUNC = 0;  }
  387. return SCPE_OK;
  388. }
  389.  
  390. /* IORS routine */
  391.  
  392. int rp_iors (void)
  393. {
  394. return ((rp_sta & (STA_ERR | STA_DON)) ||  (rp_stb & STB_ATTN))? IOS_RP: 0;
  395. }
  396.  
  397. /* Attach unit */
  398.  
  399. int rp_attach (UNIT *uptr, char *cptr)
  400. {
  401. int reason;
  402.  
  403. reason = attach_unit (uptr, cptr);
  404. rp_updsta (0, 0);
  405. return reason;
  406. }
  407.  
  408. /* Detach unit */
  409.  
  410. int rp_detach (UNIT *uptr)
  411. {
  412. int reason;
  413.  
  414. reason = detach_unit (uptr);
  415. rp_updsta (0, 0);
  416. return reason;
  417. }
  418.