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

  1. /* pdp8_rf.c: RF08 fixed head disk simulator
  2.  
  3.    Copyright (c) 1993, 1994, 1996,
  4.    Robert M Supnik, Digital Equipment Corporation
  5.    Commercial use prohibited
  6.  
  7.    The RF08 is a head-per-track disk.  It uses the three cycle data break
  8.    facility.  To minimize overhead, the entire RF08 is buffered in memory.
  9.  
  10.    Two timing parameters are provided:
  11.  
  12.    rf_time    Interword timing, must be non-zero
  13.    rf_burst    Burst mode, if 0, DMA occurs cycle by cycle; otherwise,
  14.         DMA occurs in a burst
  15. */
  16.  
  17. #include "pdp8_defs.h"
  18. #include <math.h>
  19.  
  20. /* Constants */
  21.  
  22. #define RF_NUMWD    2048                /* words/track */
  23. #define RF_NUMTR    128                /* tracks/disk */
  24. #define RF_NUMDK    4                /* disks/controller */
  25. #define RF_SIZE        (RF_NUMDK * RF_NUMTR * RF_NUMWD) /* words/drive */
  26. #define RF_WC        07750                /* word count */
  27. #define RF_MA        07751                /* mem address */
  28. #define RF_WMASK    (RF_NUMWD - 1)            /* word mask */
  29.  
  30. /* Parameters in the unit descriptor */
  31.  
  32. #define FUNC        u4                /* function */
  33. #define RF_READ        3                /* read */
  34. #define RF_WRITE    5                /* write */
  35.  
  36. /* Status register */
  37.  
  38. #define RFS_PCA        04000                /* photocell status */
  39. #define RFS_DRE        02000                /* data req enable */
  40. #define RFS_WLS        01000                /* write lock status */
  41. #define RFS_EIE        00400                /* error int enable */
  42. #define RFS_PIE        00200                /* photocell int enb */
  43. #define RFS_CIE        00100                /* done int enable */
  44. #define RFS_MEX        00070                /* memory extension */
  45. #define RFS_DRL        00004                /* data late error */
  46. #define RFS_NXD        00002                /* non-existent disk */
  47. #define RFS_PER        00001                /* parity error */
  48. #define RFS_ERR        (RFS_WLS + RFS_DRL + RFS_NXD + RFS_PER)
  49. #define RFS_V_MEX    3
  50.  
  51. #define GET_MEX(x)    (((x) & RFS_MEX) << (12 - RFS_V_MEX))
  52. #define GET_POS(x)    ((int) fmod (sim_gtime() / ((double) (x)), \
  53.             ((double) RF_NUMWD)))
  54. #define UPDATE_PCELL    if (GET_POS(rf_time) < 6) rf_sta = rf_sta | RFS_PCA; \
  55.             else rf_sta = rf_sta & ~RFS_PCA
  56. #define RF_INT_UPDATE    if ((rf_done && (rf_sta & RFS_CIE)) || \
  57.                 ((rf_sta & RFS_ERR) && (rf_sta & RFS_EIE)) || \
  58.                 ((rf_sta & RFS_PCA) && (rf_sta & RFS_PIE))) \
  59.                 int_req = int_req | INT_RF; \
  60.             else int_req = int_req & ~INT_RF
  61.  
  62. extern int int_req, stop_inst;
  63. extern unsigned short M[];
  64. extern UNIT cpu_unit;
  65. int rf_sta = 0;                        /* status register */
  66. int rf_da = 0;                        /* disk address */
  67. int rf_done = 0;                    /* done flag */
  68. int rf_wlk = 0;                        /* write lock */
  69. int rf_time = 10;                    /* inter-word time */
  70. int rf_burst = 1;                    /* burst mode flag */
  71. int rf_stopioe = 1;                    /* stop on error */
  72. int rf_svc (UNIT *uptr);
  73. int pcell_svc (UNIT *uptr);
  74. int rf_reset (DEVICE *dptr);
  75. int rf_boot (int unitno);
  76. extern int sim_activate (UNIT *uptr, int interval);
  77. extern int sim_cancel (UNIT *uptr);
  78. extern int sim_is_active (UNIT *uptr);
  79. extern double sim_gtime(void);
  80.  
  81. /* RF08 data structures
  82.  
  83.    rf_dev    RF device descriptor
  84.    rf_unit    RF unit descriptor
  85.    pcell_unit    photocell timing unit (orphan)
  86.    rf_reg    RF register list
  87. */
  88.  
  89. UNIT rf_unit =
  90.     { UDATA (&rf_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF,
  91.     RF_SIZE) };
  92.  
  93. UNIT pcell_unit = { UDATA (&pcell_svc, 0, 0) };
  94.  
  95. REG rf_reg[] = {
  96.     { ORDATA (STA, rf_sta, 12) },
  97.     { ORDATA (DA, rf_da, 20) },
  98.     { ORDATA (MA, M[RF_MA], 12) },
  99.     { ORDATA (WC, M[RF_WC], 12) },
  100.     { FLDATA (DONE, rf_done, 0) },
  101.     { FLDATA (INT, int_req, INT_V_RF) },
  102.     { ORDATA (WLK, rf_wlk, 32) },
  103.     { DRDATA (TIME, rf_time, 24), REG_NZ + PV_LEFT },
  104.     { FLDATA (BURST, rf_burst, 0) },
  105.     { FLDATA (STOP_IOE, rf_stopioe, 0) },
  106.     { NULL }  };
  107.  
  108. DEVICE rf_dev = {
  109.     "RF", &rf_unit, rf_reg, NULL,
  110.     1, 8, 20, 1, 8, 12,
  111.     NULL, NULL, &rf_reset,
  112.     &rf_boot, NULL, NULL };
  113.  
  114. /* IOT routines */
  115.  
  116. int rf60 (int pulse, int AC)
  117. {
  118. int t;
  119.  
  120. UPDATE_PCELL;                        /* update photocell */
  121. switch (pulse) {                    /* decode IR<9:11> */
  122. case 1:                            /* DCMA */
  123.     rf_da = rf_da & ~07777;                /* clear DAR<11:0> */
  124.     return AC;
  125. case 3:case 5:                        /* DMAR, DMAW */
  126.     rf_da = (rf_da & ~07777) | AC;            /* DAR<11:0> <- AC */
  127.     rf_done = 0;                    /* clear done */
  128.     rf_sta = rf_sta & ~RFS_ERR;            /* clear errors */
  129.     RF_INT_UPDATE;                    /* update int req */
  130.     rf_unit.FUNC = pulse;                /* save function */
  131.     t = (rf_da & RF_WMASK) - GET_POS (rf_time);    /* delta to new loc */
  132.     if (t < 0) t = t + RF_NUMWD;            /* wrap around? */
  133.     sim_activate (&rf_unit, t * rf_time);        /* schedule op */
  134.     return 0;                    /* clear AC */
  135. default:
  136.     return (stop_inst << IOT_V_REASON) + AC;  }    /* end switch */
  137. }
  138.  
  139. int rf61 (int pulse, int AC)
  140. {
  141. UPDATE_PCELL;                        /* update photocell */
  142. switch (pulse) {                    /* decode IR<9:11> */
  143. case 1:                            /* DCIM */
  144.     rf_sta = rf_sta & 07007;            /* clear STA<8:3> */
  145.     int_req = int_req & ~INT_RF;            /* clear int req */
  146.     sim_cancel (&pcell_unit);            /* cancel photocell */
  147.     return AC;
  148. case 2:                            /* DSAC */
  149.     return ((rf_da & RF_WMASK) == GET_POS (rf_time))? IOT_SKP + AC: AC;
  150. case 5:                            /* DIML */
  151.     rf_sta = (rf_sta & 07007) | (AC & 0770);    /* STA<8:3> <- AC */
  152.     if (rf_sta & RFS_PIE)                /* photocell int? */
  153.         sim_activate (&pcell_unit, (RF_NUMWD - GET_POS (rf_time)) *
  154.             rf_time);
  155.     else sim_cancel (&pcell_unit);
  156.     RF_INT_UPDATE;                    /* update int req */
  157.     return 0;                    /* clear AC */
  158. case 6:                            /* DIMA */
  159.     return rf_sta;                    /* AC <- STA<11:0> */
  160. default:
  161.     return (stop_inst << IOT_V_REASON) + AC;  }    /* end switch */
  162. }
  163.  
  164. /* IOT's, continued */
  165.  
  166. int rf62 (int pulse, int AC)
  167. {
  168. UPDATE_PCELL;                        /* update photocell */
  169. switch (pulse) {                    /* decode IR<9:11> */
  170. case 1:                            /* DFSE */
  171.     return (rf_sta & RFS_ERR)? IOT_SKP + AC: AC;
  172. case 2:                            /* DFSC */
  173.     return (rf_done)? IOT_SKP + AC: AC;
  174. case 3:                            /* DISK */
  175.     return (rf_done || (rf_sta & RFS_ERR))? IOT_SKP + AC: AC;
  176. case 6:                            /* DMAC */
  177.     return rf_da & 07777;                /* AC <- DAR<11:0> */
  178. default:
  179.     return (stop_inst << IOT_V_REASON) + AC;  }    /* end switch */
  180. }
  181.  
  182. int rf64 (int pulse, int AC)
  183. {
  184. UPDATE_PCELL;                        /* update photocell */
  185. switch (pulse) {                    /* decode IR<9:11> */
  186. case 1:                            /* DCXA */
  187.     rf_da = rf_da & 07777;                /* clear DAR<19:12> */
  188.     return AC;
  189. case 3:                            /* DXAL */
  190.     rf_da = (rf_da & 07777) | ((AC & 0377) << 12);    /* DAR<19:12> <- AC */
  191.     return 0;                    /* clear AC */
  192. case 5:                            /* DXAC */
  193.     return ((rf_da >> 12) & 0377);            /* AC <- DAR<19:12> */
  194. default:
  195.     return (stop_inst << IOT_V_REASON) + AC;  }    /* end switch */
  196. }
  197.  
  198. /* Unit service
  199.  
  200.    Note that for reads and writes, memory addresses wrap around in the
  201.    current field.  This code assumes the entire disk is buffered.
  202. */
  203.  
  204. int rf_svc (UNIT *uptr)
  205. {
  206. int t, mex, pa;
  207.  
  208. UPDATE_PCELL;                        /* update photocell */
  209. if ((uptr -> flags & UNIT_BUF) == 0) {            /* not buf? abort */
  210.     rf_sta = rf_sta | RFS_NXD;
  211.     rf_done = 1;
  212.     RF_INT_UPDATE;                    /* update int req */
  213.     return IORETURN (rf_stopioe, SCPE_UNATT);  }
  214.  
  215. mex = GET_MEX (rf_sta);
  216. do {     M[RF_MA] = (M[RF_MA] + 1) & 07777;        /* incr mem addr */
  217.     pa = mex | M[RF_MA];                 /* add extension */
  218.     if (uptr -> FUNC == RF_READ) {
  219.         if (MEM_ADDR_OK (pa))            /* read, check nxm */
  220.             M[pa] = *(((short *) uptr -> filebuf) + rf_da);  }
  221.     else {    t = ((rf_da >> 15) & 030) | ((rf_da >> 14) & 07);
  222.         if ((rf_wlk >> t) & 1) rf_sta = rf_sta | RFS_WLS;
  223.         else {    *(((short *) uptr -> filebuf) + rf_da) = M[pa];
  224.             if (rf_da >= uptr -> hwmark)
  225.                 uptr -> hwmark = rf_da + 1;  }  }
  226.     rf_da = (rf_da + 1) & 03777777;            /* incr disk addr */
  227.     M[RF_WC] = (M[RF_WC] + 1) & 07777;  }        /* incr word count */
  228. while ((M[RF_WC] != 0) && (rf_burst != 0));        /* brk if wc, no brst */
  229.  
  230. if (M[RF_WC] != 0)                    /* more to do? */
  231.     sim_activate (&rf_unit, rf_time);        /* sched next */
  232. else {    rf_done = 1;                    /* done */
  233.     RF_INT_UPDATE;  }                /* update int req */
  234. return SCPE_OK;
  235. }
  236.  
  237. /* Photocell unit service */
  238.  
  239. int pcell_svc (UNIT *uptr)
  240. {
  241. rf_sta = rf_sta | RFS_PCA;                /* set photocell */
  242. if (rf_sta & RFS_PIE) {                    /* int enable? */
  243.     sim_activate (&pcell_unit, RF_NUMWD * rf_time);
  244.     int_req = int_req | INT_RF;  }
  245. return SCPE_OK;
  246. }
  247.  
  248. /* Reset routine */
  249.  
  250. int rf_reset (DEVICE *dptr)
  251. {
  252. rf_sta = rf_da = 0;
  253. rf_done = 1;
  254. int_req = int_req & ~INT_RF;                /* clear interrupt */
  255. sim_cancel (&rf_unit);
  256. sim_cancel (&pcell_unit);
  257. return SCPE_OK;
  258. }
  259.  
  260. /* Bootstrap routine */
  261.  
  262. #define BOOT_START 7750
  263. #define BOOT_LEN (sizeof (boot_rom) / sizeof (int))
  264.  
  265. static const int boot_rom[] = {
  266.     07600,            /* 7750, CLA CLL    ; also word count */
  267.     06603,            /* 7751, DMAR        ; also address */
  268.     06622,            /* 7752, DFSC        ; done? */
  269.     05352,            /* 7753, JMP .-1    ; no */
  270.     05752            /* 7754, JMP @.-2    ; enter boot */
  271. };
  272.  
  273. int rf_boot (int unitno)
  274. {
  275. int i;
  276. extern int saved_PC;
  277.  
  278. for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i];
  279. saved_PC = BOOT_START;
  280. return SCPE_OK;
  281. }
  282.