home *** CD-ROM | disk | FTP | other *** search
- /* nova_dsk.c: 4019 fixed head disk simulator
-
- Copyright (c) 1993, 1994, 1995, 1996,
- Robert M Supnik, Digital Equipment Corporation
- Commercial use prohibited
-
- The 4019 is a head-per-track disk. To minimize overhead, the entire disk
- is buffered in memory.
- */
-
- #include "nova_defs.h"
- #include <math.h>
-
- /* Constants */
-
- #define DSK_NUMWD 256 /* words/sector */
- #define DSK_NUMSC 8 /* sectors/track */
- #define DSK_NUMTR 128 /* tracks/disk */
- #define DSK_NUMDK 8 /* disks/controller */
- #define DSK_SCSIZE (DSK_NUMDK*DSK_NUMTR*DSK_NUMSC) /* sectors/drive */
- #define DSK_AMASK (DSK_SCSIZE - 1) /* address mask */
- #define DSK_SIZE (DSK_SCSIZE * DSK_NUMWD) /* words/drive */
- #define GET_DISK(x) (((x) / (DSK_NUMSC * DSK_NUMTR)) & (DSK_NUMDK - 1))
-
- /* Parameters in the unit descriptor */
-
- #define FUNC u4 /* function */
-
- /* Status register */
-
- #define DSKS_WLS 020 /* write lock status */
- #define DSKS_DLT 010 /* data late error */
- #define DSKS_NSD 004 /* non-existent disk */
- #define DSKS_CRC 002 /* parity error */
- #define DSKS_ERR 001 /* error summary */
- #define DSKS_ALLERR (DSKS_WLS | DSKS_DLT | DSKS_NSD | DSKS_CRC | DSKS_ERR)
-
- /* Map logical sector numbers to physical sector numbers
- (indexed by track<2:0>'sector)
- */
-
- static const int sector_map[] = {
- 0, 2, 4, 6, 1, 3, 5, 7, 1, 3, 5, 7, 2, 4, 6, 0,
- 2, 4, 6, 0, 3, 5, 7, 1, 3, 5, 7, 1, 4, 6, 0, 2,
- 4, 6, 0, 2, 5, 7, 1, 3, 5, 7, 1, 3, 6, 0, 2, 4,
- 6, 0, 2, 4, 7, 1, 3, 5, 7, 1, 3, 5, 0, 2, 4, 6 };
-
- #define DSK_MMASK 077
- #define GET_SECTOR(x) ((int) fmod (sim_gtime() / ((double) (x)), \
- ((double) DSK_NUMSC)))
-
- extern unsigned short M[];
- extern UNIT cpu_unit;
- extern int int_req, dev_busy, dev_done, dev_disable;
- int dsk_stat = 0; /* status register */
- int dsk_da = 0; /* disk address */
- int dsk_ma = 0; /* memory address */
- int dsk_wlk = 0; /* wrt lock switches */
- int dsk_stopioe = 1; /* stop on error */
- int dsk_time = 100; /* time per sector */
- int dsk_svc (UNIT *uptr);
- int dsk_reset (DEVICE *dptr);
- int dsk_boot (int unitno);
- 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);
-
- /* DSK data structures
-
- dsk_dev device descriptor
- dsk_unit unit descriptor
- dsk_reg register list
- */
-
- UNIT dsk_unit =
- { UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF,
- DSK_SIZE) };
-
- REG dsk_reg[] = {
- { ORDATA (STAT, dsk_stat, 16) },
- { ORDATA (DA, dsk_da, 16) },
- { ORDATA (MA, dsk_ma, 16) },
- { FLDATA (BUSY, dev_busy, INT_V_DSK) },
- { FLDATA (DONE, dev_done, INT_V_DSK) },
- { FLDATA (DISABLE, dev_disable, INT_V_DSK) },
- { FLDATA (INT, int_req, INT_V_DSK) },
- { ORDATA (WLK, dsk_wlk, 8) },
- { DRDATA (TIME, dsk_time, 24), REG_NZ + PV_LEFT },
- { FLDATA (STOP_IOE, dsk_stopioe, 0) },
- { NULL } };
-
- DEVICE dsk_dev = {
- "DK", &dsk_unit, dsk_reg, NULL,
- 1, 8, 21, 1, 8, 16,
- NULL, NULL, &dsk_reset,
- &dsk_boot, NULL, NULL };
-
- /* IOT routine */
-
- int dsk (int pulse, int code, int AC)
- {
- int t, rval;
-
- rval = 0;
- switch (code) { /* decode IR<5:7> */
- case ioDIA: /* DIA */
- rval = dsk_stat & DSKS_ALLERR; /* read status */
- break;
- case ioDOA: /* DOA */
- dsk_da = AC & DSK_AMASK; /* save disk addr */
- break;
- case ioDIB: /* DIB */
- rval = dsk_ma & ADDRMASK; /* read mem addr */
- break;
- case ioDOB: /* DOB */
- dsk_ma = AC & ADDRMASK; /* save mem addr */
- break; } /* end switch code */
-
- if (pulse) { /* any pulse? */
- dev_busy = dev_busy & ~INT_DSK; /* clear busy */
- dev_done = dev_done & ~INT_DSK; /* clear done */
- int_req = int_req & ~INT_DSK; /* clear int */
- dsk_stat = 0; /* clear status */
- sim_cancel (&dsk_unit); } /* stop I/O */
-
- if ((pulse == iopP) && ((dsk_wlk >> GET_DISK (dsk_da)) & 1)) { /* wrt lock? */
- dev_done = dev_done | INT_DSK; /* set done */
- int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable);
- dsk_stat = DSKS_ERR + DSKS_WLS; /* set status */
- return rval; }
-
- if (pulse & 1) { /* read or write? */
- if ((dsk_da * DSK_NUMWD) >= dsk_unit.capac) { /* invalid sector? */
- dev_done = dev_done | INT_DSK; /* set done */
- int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable);
- dsk_stat = DSKS_ERR + DSKS_NSD; /* set status */
- return rval; } /* done */
- dsk_unit.FUNC = pulse; /* save command */
- dev_busy = dev_busy | INT_DSK; /* set busy */
- t = sector_map[dsk_da & DSK_MMASK] - GET_SECTOR (dsk_time);
- if (t < 0) t = t + DSK_NUMSC;
- sim_activate (&dsk_unit, t * dsk_time); } /* activate */
- return rval;
- }
-
- /* Unit service */
-
- int dsk_svc (UNIT *uptr)
- {
- int i, j, da;
-
- dev_busy = dev_busy & ~INT_DSK; /* clear busy */
- dev_done = dev_done | INT_DSK; /* set done */
- int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable);
-
- if ((uptr -> flags & UNIT_BUF) == 0) { /* not buf? abort */
- dsk_stat = DSKS_ERR + DSKS_NSD; /* set status */
- return IORETURN (dsk_stopioe, SCPE_UNATT); }
-
- da = dsk_da * DSK_NUMWD; /* calc disk addr */
- if (uptr -> FUNC == iopS) { /* read? */
- for (i = 0; i < DSK_NUMWD; i++) { /* copy sector */
- j = (dsk_ma + i) & ADDRMASK;
- if (MEM_ADDR_OK (j))
- M[j] = *(((short *) uptr -> filebuf) + da + i); }
- dsk_ma = (dsk_ma + DSK_NUMWD) & ADDRMASK; }
- if (uptr -> FUNC == iopP) { /* write? */
- for (i = 0; i < DSK_NUMWD; i++) { /* copy sector */
- *(((short *) uptr -> filebuf) + da + i) =
- M[(dsk_ma + i) & ADDRMASK]; }
- dsk_ma = (dsk_ma + DSK_NUMWD + 3) & ADDRMASK; }
-
- dsk_stat = 0; /* set status */
- return SCPE_OK;
- }
-
- /* Reset routine */
-
- int dsk_reset (DEVICE *dptr)
- {
- dsk_stat = dsk_da = dsk_ma = 0;
- dev_busy = dev_busy & ~INT_DSK; /* clear busy */
- dev_done = dev_done & ~INT_DSK; /* clear done */
- int_req = int_req & ~INT_DSK; /* clear int */
- sim_cancel (&dsk_unit);
- return SCPE_OK;
- }
-
- /* Bootstrap routine */
-
- #define BOOT_START 2000
- #define BOOT_LEN (sizeof (boot_rom) / sizeof (int))
-
- static const int boot_rom[] = {
- 060220, /* NIOC DSK ; clear disk */
- 0102400, /* SUB 0,0 ; addr = 0 */
- 061020, /* DOA 0,DSK ; set disk addr */
- 062120, /* DOBS 0,DSK ; set mem addr, rd */
- 063620, /* SKPDN DSK ; done? */
- 000776, /* JMP .-2 */
- 000377, /* JMP 377 */
- };
-
- int dsk_boot (int unitno)
- {
- int i;
- extern int saved_PC;
-
- for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i];
- saved_PC = BOOT_START;
- return SCPE_OK;
- }
-