home *** CD-ROM | disk | FTP | other *** search
- /* pdp18b_rf.c: fixed head disk simulator
-
- Copyright (c) 1996, Robert M Supnik, Digital Equipment Corporation
- Commercial use prohibited
-
- rf RF09/RF09 for PDP-9
- RF15/RS09 for PDP-15
-
- The RFxx is a head-per-track disk. It uses the multicycle data break
- facility. To minimize overhead, the entire RFxx is buffered in memory.
-
- Two timing parameters are provided:
-
- rf_time Interword timing. If 0, treated as 1.
- rf_burst Burst mode. If 0, DMA occurs cycle by cycle; otherwise,
- DMA occurs in a burst.
- */
-
- #ifndef PDP9
- #define PDP9 0
- #endif
-
- #include "pdp18b_defs.h"
- #include <math.h>
-
- /* Constants */
-
- #define RF_NUMWD 2048 /* words/track */
- #define RF_NUMTR 128 /* tracks/disk */
- #define RF_NUMDK 8 /* disks/controller */
- #define RF_SIZE (RF_NUMDK * RF_NUMTR * RF_NUMWD) /* words/drive */
- #define RF_WMASK (RF_NUMWD - 1) /* word mask */
- #define RF_WC 036 /* word count */
- #define RF_MA 037 /* mem address */
-
- /* Function/status register */
-
- #define RFS_ERR 0400000 /* error */
- #define RFS_HDW 0200000 /* hardware error */
- #define RFS_APE 0100000 /* addr parity error */
- #define RFS_MXF 0040000 /* missed transfer */
- #define RFS_WCE 0020000 /* write check error */
- #define RFS_DPE 0010000 /* data parity error */
- #define RFS_WLO 0004000 /* write lock error */
- #define RFS_NED 0002000 /* non-existent disk */
- #define RFS_DCH 0001000 /* data chan timing */
- #define RFS_PGE 0000400 /* programming error */
- #define RFS_DON 0000200 /* transfer complete */
- #define RFS_V_FNC 1 /* function */
- #define RFS_M_FNC 03
- #define RFS_FNC (RFS_M_FNC << RFS_V_FNC)
- #define FN_NOP 0
- #define FN_READ 1
- #define FN_WRITE 2
- #define FN_WCHK 3
- #define RFS_IE 0000001 /* interrupt enable */
-
- #define RFS_CLR 0000170 /* always clear */
- #define RFS_EFLGS (RFS_HDW | RFS_APE | RFS_MXF | RFS_WCE | \
- RFS_DPE | RFS_WLO | RFS_NED ) /* error flags */
- #define MIN_TIME(x) ((x > 0)? (x): 1)
- #define GET_FNC(x) (((x) >> RFS_V_FNC) & RFS_M_FNC)
- #define GET_POS(x) ((int) fmod (sim_gtime() / ((double) (MIN_TIME(x))), \
- ((double) RF_NUMWD)))
- #define RF_BUSY (sim_is_active (&rf_unit))
-
- extern unsigned int M[];
- extern int int_req;
- extern UNIT cpu_unit;
- int rf_sta = 0; /* status register */
- int rf_da = 0; /* disk address */
- int rf_dbuf = 0; /* data buffer */
- int rf_wlk[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; /* write lock */
- int rf_time = 10; /* inter-word time */
- int rf_burst = 1; /* burst mode flag */
- int rf_stopioe = 1; /* stop on error */
- int rf_svc (UNIT *uptr);
- int rf_reset (DEVICE *dptr);
- int rf_updsta (int new);
- extern int sim_activate (UNIT *uptr, int interval);
- extern int sim_cancel (UNIT *uptr);
- extern int sim_is_active (UNIT *uptr);
- extern double sim_gtime(void);
-
- /* RF data structures
-
- rf_dev RF device descriptor
- rf_unit RF unit descriptor
- rf_reg RF register list
- */
-
- UNIT rf_unit =
- { UDATA (&rf_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF,
- RF_SIZE) };
-
- REG rf_reg[] = {
- { ORDATA (STA, rf_sta, 18) },
- { ORDATA (DA, rf_da, 21) },
- { ORDATA (MA, M[RF_MA], 18) },
- { ORDATA (WC, M[RF_WC], 18) },
- { ORDATA (BUF, rf_dbuf, 18) },
- { FLDATA (INT, int_req, INT_V_RF) },
- { ORDATA (WLK0, rf_wlk[0], 16) },
- { ORDATA (WLK1, rf_wlk[1], 16) },
- { ORDATA (WLK2, rf_wlk[2], 16) },
- { ORDATA (WLK3, rf_wlk[3], 16) },
- { ORDATA (WLK4, rf_wlk[4], 16) },
- { ORDATA (WLK5, rf_wlk[5], 16) },
- { ORDATA (WLK6, rf_wlk[6], 16) },
- { ORDATA (WLK7, rf_wlk[7], 16) },
- { DRDATA (TIME, rf_time, 24), PV_LEFT },
- { FLDATA (BURST, rf_burst, 0) },
- { FLDATA (STOP_IOE, rf_stopioe, 0) },
- { NULL } };
-
- DEVICE rf_dev = {
- "RF", &rf_unit, rf_reg, NULL,
- 1, 8, 21, 1, 8, 18,
- NULL, NULL, &rf_reset,
- NULL, NULL, NULL };
-
- /* IOT routines */
-
- int rf70 (int pulse, int AC)
- {
- int t;
-
- if (pulse == 001) /* DSSF */
- return (rf_sta & (RFS_ERR | RFS_DON))? IOT_SKP + AC: AC;
- if (pulse == 021) rf_reset (&rf_dev); /* DSCC */
- if ((pulse & 061) == 041) { /* DSCF */
- if (RF_BUSY) rf_sta = rf_sta | RFS_PGE; /* busy inhibits */
- else rf_sta = rf_sta & ~(RFS_FNC | RFS_IE); } /* clear func */
- if (pulse == 002) { /* DRBR */
- if (RF_BUSY) rf_sta = rf_sta | RFS_PGE; /* busy sets PGE */
- return AC | rf_dbuf; }
- if (pulse == 022) { /* DRAL */
- if (RF_BUSY) rf_sta = rf_sta | RFS_PGE; /* busy sets PGE */
- return rf_da & 0777777; }
- if (pulse == 062) { /* DRAH */
- if (RF_BUSY) rf_sta = rf_sta | RFS_PGE; /* busy sets PGE */
- return (rf_da >> 18) | ((rf_sta & RFS_NED)? 010: 0); }
- if ((pulse & 062) == 042) { /* DSFX */
- if (RF_BUSY) rf_sta = rf_sta | RFS_PGE; /* busy inhibits */
- else rf_sta = rf_sta ^ (AC & (RFS_FNC | RFS_IE)); } /* xor func */
- if (pulse == 004) { /* DLBR */
- if (RF_BUSY) rf_sta = rf_sta | RFS_PGE; /* busy inhibits */
- else rf_dbuf = AC; }
- if (pulse == 024) { /* DLAL */
- if (RF_BUSY) rf_sta = rf_sta | RFS_PGE; /* busy inhibits */
- else rf_da = (rf_da & ~0777777) | AC; }
- if (pulse == 064) { /* DLAH */
- if (RF_BUSY) rf_sta = rf_sta | RFS_PGE; /* busy inhibits */
- else rf_da = (rf_da & 0777777) | ((AC & 07) << 18); }
- if ((pulse & 064) == 044) { /* DSCN */
- if (RF_BUSY) rf_sta = rf_sta | RFS_PGE; /* busy inhibits */
- else if (GET_FNC (rf_sta) != FN_NOP) {
- t = (rf_da & RF_WMASK) - GET_POS (rf_time); /* delta to new */
- if (t < 0) t = t + RF_NUMWD; /* wrap around? */
- sim_activate (&rf_unit, t * rf_time); } } /* schedule op */
- rf_updsta (0); /* update status */
- return AC;
- }
-
- int rf72 (int pulse, int AC)
- {
- if (pulse == 002) return AC | GET_POS (rf_time) | /* DLOK */
- (sim_is_active (&rf_unit)? 0400000: 0);
- if (pulse == 042) { /* DSCD */
- if (RF_BUSY) rf_sta = rf_sta | RFS_PGE; /* busy inhibits */
- else rf_sta = 0;
- rf_updsta (0); }
- if (pulse == 0062) { /* DSRS */
- if (RF_BUSY) rf_sta = rf_sta | RFS_PGE; /* busy sets PGE */
- return rf_updsta (0); }
- return AC;
- }
-
- /* Unit service
-
- This code assumes the entire disk is buffered.
- */
-
- int rf_svc (UNIT *uptr)
- {
- int f, pa, d, t;
-
- if ((uptr -> flags & UNIT_BUF) == 0) { /* not buf? abort */
- rf_updsta (RFS_NED | RFS_DON); /* set nxd, done */
- return IORETURN (rf_stopioe, SCPE_UNATT); }
-
- f = GET_FNC (rf_sta); /* get function */
- do { pa = M[RF_MA] = (M[RF_MA] + 1) & ADDRMASK; /* incr mem addr */
- if ((f == FN_READ) && MEM_ADDR_OK (pa)) /* read? */
- M[pa] = *(((int *) uptr -> filebuf) + rf_da);
- if ((f == FN_WCHK) && /* write check? */
- (M[pa] != *(((int *) uptr -> filebuf) + rf_da))) {
- rf_updsta (RFS_WCE); /* flag error */
- break; }
- if (f == FN_WRITE) { /* write? */
- d = (rf_da >> 18) & 07; /* disk */
- t = (rf_da >> 14) & 017; /* track groups */
- if ((rf_wlk[d] >> t) & 1) { /* write locked? */
- rf_updsta (RFS_WLO);
- break; }
- else { *(((int *) uptr -> filebuf) + rf_da) = M[pa];
- if (rf_da >= uptr -> hwmark)
- uptr -> hwmark = rf_da + 1; } }
- rf_da = rf_da + 1; /* incr disk addr */
- if (rf_da > RF_SIZE) { /* disk overflow? */
- rf_da = 0;
- rf_updsta (RFS_NED); /* nx disk error */
- break; }
- M[RF_WC] = (M[RF_WC] + 1) & 0777777; } /* incr word count */
- while ((M[RF_WC] != 0) && (rf_burst != 0)); /* brk if wc, no brst */
-
- if ((M[RF_WC] != 0) && ((rf_sta & RFS_ERR) == 0)) /* more to do? */
- sim_activate (&rf_unit, MIN_TIME (rf_time)); /* sched next */
- else rf_updsta (RFS_DON);
- return SCPE_OK;
- }
-
- /* Update status */
-
- int rf_updsta (int new)
- {
- rf_sta = (rf_sta | new) & ~(RFS_ERR | RFS_CLR);
- if (rf_sta & RFS_EFLGS) rf_sta = rf_sta | RFS_ERR;
- if ((rf_sta & (RFS_ERR | RFS_DON)) && (rf_sta & RFS_IE))
- int_req = int_req | INT_RF;
- else int_req = int_req & ~INT_RF;
- return rf_sta;
- }
-
- /* Reset routine */
-
- int rf_reset (DEVICE *dptr)
- {
- rf_sta = rf_da = rf_dbuf = 0;
- rf_updsta (0);
- sim_cancel (&rf_unit);
- return SCPE_OK;
- }
-
- /* IORS routine */
-
- int rf_iors (void)
- {
- return ((rf_sta & (RFS_ERR | RFS_DON))? IOS_RF: 0);
- }
-