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

  1. /* nova_dsk.c: 4019 fixed head disk simulator
  2.  
  3.    Copyright (c) 1993, 1994, 1995, 1996,
  4.    Robert M Supnik, Digital Equipment Corporation
  5.    Commercial use prohibited
  6.  
  7.    The 4019 is a head-per-track disk.  To minimize overhead, the entire disk
  8.    is buffered in memory.
  9. */
  10.  
  11. #include "nova_defs.h"
  12. #include <math.h>
  13.  
  14. /* Constants */
  15.  
  16. #define DSK_NUMWD    256                /* words/sector */
  17. #define DSK_NUMSC    8                /* sectors/track */
  18. #define DSK_NUMTR    128                /* tracks/disk */
  19. #define DSK_NUMDK    8                /* disks/controller */
  20. #define DSK_SCSIZE     (DSK_NUMDK*DSK_NUMTR*DSK_NUMSC) /* sectors/drive */
  21. #define DSK_AMASK    (DSK_SCSIZE - 1)        /* address mask */
  22. #define DSK_SIZE    (DSK_SCSIZE * DSK_NUMWD)    /* words/drive */
  23. #define GET_DISK(x)    (((x) / (DSK_NUMSC * DSK_NUMTR)) & (DSK_NUMDK - 1))
  24.  
  25. /* Parameters in the unit descriptor */
  26.  
  27. #define FUNC        u4                /* function */
  28.  
  29. /* Status register */
  30.  
  31. #define DSKS_WLS    020                /* write lock status */
  32. #define DSKS_DLT    010                /* data late error */
  33. #define DSKS_NSD    004                /* non-existent disk */
  34. #define DSKS_CRC    002                /* parity error */
  35. #define DSKS_ERR    001                /* error summary */
  36. #define DSKS_ALLERR    (DSKS_WLS | DSKS_DLT | DSKS_NSD | DSKS_CRC | DSKS_ERR)
  37.  
  38. /* Map logical sector numbers to physical sector numbers
  39.    (indexed by track<2:0>'sector)
  40. */
  41.  
  42. static const int sector_map[] = {
  43.     0, 2, 4, 6, 1, 3, 5, 7, 1, 3, 5, 7, 2, 4, 6, 0,
  44.     2, 4, 6, 0, 3, 5, 7, 1, 3, 5, 7, 1, 4, 6, 0, 2,
  45.     4, 6, 0, 2, 5, 7, 1, 3, 5, 7, 1, 3, 6, 0, 2, 4,
  46.     6, 0, 2, 4, 7, 1, 3, 5, 7, 1, 3, 5, 0, 2, 4, 6  };
  47.  
  48. #define DSK_MMASK    077
  49. #define GET_SECTOR(x)    ((int) fmod (sim_gtime() / ((double) (x)), \
  50.             ((double) DSK_NUMSC)))
  51.  
  52. extern unsigned short M[];
  53. extern UNIT cpu_unit;
  54. extern int int_req, dev_busy, dev_done, dev_disable;
  55. int dsk_stat = 0;                    /* status register */
  56. int dsk_da = 0;                        /* disk address */
  57. int dsk_ma = 0;                        /* memory address */
  58. int dsk_wlk = 0;                    /* wrt lock switches */
  59. int dsk_stopioe = 1;                    /* stop on error */
  60. int dsk_time = 100;                    /* time per sector */
  61. int dsk_svc (UNIT *uptr);
  62. int dsk_reset (DEVICE *dptr);
  63. int dsk_boot (int unitno);
  64. extern int sim_activate (UNIT *uptr, int interval);
  65. extern int sim_cancel (UNIT *uptr);
  66. extern int sim_is_active (UNIT *uptr);
  67. extern double sim_gtime (void);
  68.  
  69. /* DSK data structures
  70.  
  71.    dsk_dev    device descriptor
  72.    dsk_unit    unit descriptor
  73.    dsk_reg    register list
  74. */
  75.  
  76. UNIT dsk_unit =
  77.     { UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF,
  78.         DSK_SIZE) };
  79.  
  80. REG dsk_reg[] = {
  81.     { ORDATA (STAT, dsk_stat, 16) },
  82.     { ORDATA (DA, dsk_da, 16) },
  83.     { ORDATA (MA, dsk_ma, 16) },
  84.     { FLDATA (BUSY, dev_busy, INT_V_DSK) },
  85.     { FLDATA (DONE, dev_done, INT_V_DSK) },
  86.     { FLDATA (DISABLE, dev_disable, INT_V_DSK) },
  87.     { FLDATA (INT, int_req, INT_V_DSK) },
  88.     { ORDATA (WLK, dsk_wlk, 8) },
  89.     { DRDATA (TIME, dsk_time, 24), REG_NZ + PV_LEFT },
  90.     { FLDATA (STOP_IOE, dsk_stopioe, 0) },
  91.     { NULL }  };
  92.  
  93. DEVICE dsk_dev = {
  94.     "DK", &dsk_unit, dsk_reg, NULL,
  95.     1, 8, 21, 1, 8, 16,
  96.     NULL, NULL, &dsk_reset,
  97.     &dsk_boot, NULL, NULL };
  98.  
  99. /* IOT routine */
  100.  
  101. int dsk (int pulse, int code, int AC)
  102. {
  103. int t, rval;
  104.  
  105. rval = 0;
  106. switch (code) {                        /* decode IR<5:7> */
  107. case ioDIA:                        /* DIA */
  108.     rval = dsk_stat & DSKS_ALLERR;            /* read status */
  109.     break;
  110. case ioDOA:                        /* DOA */
  111.     dsk_da = AC & DSK_AMASK;            /* save disk addr */
  112.     break;
  113. case ioDIB:                        /* DIB */
  114.     rval = dsk_ma & ADDRMASK;            /* read mem addr */
  115.     break;
  116. case ioDOB:                        /* DOB */
  117.     dsk_ma = AC & ADDRMASK;                /* save mem addr */
  118.     break;  }                    /* end switch code */
  119.  
  120. if (pulse) {                        /* any pulse? */
  121.     dev_busy = dev_busy & ~INT_DSK;            /* clear busy */
  122.     dev_done = dev_done & ~INT_DSK;            /* clear done */
  123.     int_req = int_req & ~INT_DSK;            /* clear int */
  124.     dsk_stat = 0;                    /* clear status */
  125.     sim_cancel (&dsk_unit);  }            /* stop I/O */
  126.  
  127. if ((pulse == iopP) && ((dsk_wlk >> GET_DISK (dsk_da)) & 1)) {    /* wrt lock? */
  128.     dev_done = dev_done | INT_DSK;            /* set done */
  129.     int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable);
  130.     dsk_stat = DSKS_ERR + DSKS_WLS;            /* set status */
  131.     return rval;  }
  132.  
  133. if (pulse & 1) {                    /* read or write? */
  134.     if ((dsk_da * DSK_NUMWD) >= dsk_unit.capac) {    /* invalid sector? */
  135.         dev_done = dev_done | INT_DSK;        /* set done */
  136.         int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable);
  137.         dsk_stat = DSKS_ERR + DSKS_NSD;        /* set status */
  138.         return rval;  }                /* done */
  139.     dsk_unit.FUNC = pulse;                /* save command */
  140.     dev_busy = dev_busy | INT_DSK;            /* set busy */
  141.     t = sector_map[dsk_da & DSK_MMASK] - GET_SECTOR (dsk_time);
  142.     if (t < 0) t = t + DSK_NUMSC;
  143.     sim_activate (&dsk_unit, t * dsk_time);  }    /* activate */
  144. return rval;
  145. }
  146.  
  147. /* Unit service */
  148.  
  149. int dsk_svc (UNIT *uptr)
  150. {
  151. int i, j, da;
  152.  
  153. dev_busy = dev_busy & ~INT_DSK;                /* clear busy */
  154. dev_done = dev_done | INT_DSK;                /* set done */
  155. int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable);
  156.  
  157. if ((uptr -> flags & UNIT_BUF) == 0) {            /* not buf? abort */
  158.     dsk_stat = DSKS_ERR + DSKS_NSD;            /* set status */
  159.     return IORETURN (dsk_stopioe, SCPE_UNATT);  }
  160.  
  161. da = dsk_da * DSK_NUMWD;                /* calc disk addr */
  162. if (uptr -> FUNC == iopS) {                /* read? */
  163.     for (i = 0; i < DSK_NUMWD; i++) {        /* copy sector */
  164.         j = (dsk_ma + i) & ADDRMASK;
  165.         if (MEM_ADDR_OK (j))
  166.             M[j] = *(((short *) uptr -> filebuf) + da + i);  }
  167.     dsk_ma = (dsk_ma + DSK_NUMWD) & ADDRMASK;  }
  168. if (uptr -> FUNC == iopP) {                /* write? */
  169.     for (i = 0; i < DSK_NUMWD; i++) {        /* copy sector */
  170.         *(((short *) uptr -> filebuf) + da + i) =
  171.             M[(dsk_ma + i) & ADDRMASK];  }
  172.     dsk_ma = (dsk_ma + DSK_NUMWD + 3) & ADDRMASK;  }
  173.  
  174. dsk_stat = 0;                        /* set status */
  175. return SCPE_OK;
  176. }
  177.  
  178. /* Reset routine */
  179.  
  180. int dsk_reset (DEVICE *dptr)
  181. {
  182. dsk_stat = dsk_da = dsk_ma = 0;
  183. dev_busy = dev_busy & ~INT_DSK;                /* clear busy */
  184. dev_done = dev_done & ~INT_DSK;                /* clear done */
  185. int_req = int_req & ~INT_DSK;                /* clear int */
  186. sim_cancel (&dsk_unit);
  187. return SCPE_OK;
  188. }
  189.  
  190. /* Bootstrap routine */
  191.  
  192. #define BOOT_START 2000
  193. #define BOOT_LEN (sizeof (boot_rom) / sizeof (int))
  194.  
  195. static const int boot_rom[] = {
  196.     060220,            /* NIOC DSK        ; clear disk */
  197.     0102400,        /* SUB 0,0        ; addr = 0 */
  198.     061020,            /* DOA 0,DSK        ; set disk addr */
  199.     062120,            /* DOBS 0,DSK        ; set mem addr, rd */
  200.     063620,            /* SKPDN DSK        ; done? */
  201.     000776,            /* JMP .-2 */
  202.     000377,            /* JMP 377 */
  203. };
  204.  
  205. int dsk_boot (int unitno)
  206. {
  207. int i;
  208. extern int saved_PC;
  209.  
  210. for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i];
  211. saved_PC = BOOT_START;
  212. return SCPE_OK;
  213. }
  214.