/* This file is in the public domian. */ /* rk11 disk driver module */ /* #define MMAP /* define to use Sun-style mmap call for disk files */ /* without MMAP, changes to simulated disks will be lost at simulator exit */ #ifdef MMAP #include #include #else extern char *malloc(); #endif #include #include "pdp11.h" #include "driver.h" #define MAXDRIVES 8 static char *drivefiles[MAXDRIVES] = { "/home/lightning/mouse/pdp11/disk/rk11.0", 0, 0, 0, 0, 0, 0, 0, }; #define REGBITS (reg,field) (((reg)&field)>>field/**/_SHIFT) #define BASE 017777400 #define RKDS (BASE+000) static word rkds; #define RKDS_SC 0000017 /* sector counter */ #define RKDS_SC_SHIFT 0 #define RKDS_SA_EQ_SC 0000020 /* currently over sector SC */ #define RKDS_WRT_PROT 0000040 /* write protect indicator */ #define RKDS_RWS_RDY 0000100 /* ready for read/write/seek cmd */ #define RKDS_DRV_RDY 0000200 /* drive ready to operate */ #define RKDS_SC_OK 0000400 /* SC is valid */ #define RKDS_SEEK_INC 0001000 /* seek incomplete error */ #define RKDS_UNSAFE 0002000 /* drive-unsafe error */ #define RKDS_RK05 0004000 /* drive is an rk05 */ #define RKDS_POWERLOW 0010000 /* drive power is low */ #define RKDS_DRIVEID 0160000 /* drive responsible for RKDS_SEEK_INC or RKCS_SCP */ #define RKDS_DRIVEID_SHIFT 13 #define RKDS_MBZ 0000000 /* msut be zero (no such bits for RKDS) */ #define RKER (BASE+002) static word rker; #define RKER_WCE 0000001 /* write-check error */ #define RKER_CSE 0000002 /* checksum error */ #define RKER_NXS 0000040 /* nonexistent sector (> 013) */ #define RKER_NXC 0000100 /* nonexistent cylinder (> 0312) */ #define RKER_NXD 0000200 /* nonexistent drive */ #define RKER_TE 0000400 /* timing error (no timing pulses) */ #define RKER_DLT 0001000 /* DMA data late */ #define RKER_NXM 0002000 /* no memory response during DMA - may set DLT too */ #define RKER_PGE 0004000 /* programming error - RKCS_FMT set but operation not read or write */ #define RKER_SKE 0010000 /* seek error */ #define RKER_WLO 0020000 /* write lockout (write protect error) */ #define RKER_OVR 0040000 /* RKWC attempted to overflow past end of disk */ #define RKER_DRE 0100000 /* drive error - attempt to do sth on non-ready drive */ #define RKER_MBZ 0000034 /* must be zero */ #define RKER_HARD (0177740) /* DRE|OVR|WLO|SKE|PGE|NXM|DLT|TE|NXD|NXC|NXS */ #define RKCS (BASE+004) static word rkcs; #define RKCS_GO 0000001 #define RKCS_FXN 0000016 #define RKCS_FXN_CTLRESET 0000000 #define RKCS_FXN_WRITE 0000002 #define RKCS_FXN_READ 0000004 #define RKCS_FXN_WRITECHK 0000006 #define RKCS_FXN_SEEK 0000010 #define RKCS_FXN_READCHK 0000012 #define RKCS_FXN_DRVRESET 0000014 #define RKCS_FXN_WRITELCK 0000016 #define RKCS_MEX 0000060 /* memory extension - for 18-bit bus addressing */ #define RKCS_MEX_SHIFT 4 #define RKCS_IDE 0000100 /* interrupt-on-done enable */ #define RKCS_RDY 0000200 /* controller ready */ #define RKCS_SSE 0000400 /* stop on soft error */ #define RKCS_FMT 0002000 /* format mode: write w/o servo check, read heaaders */ #define RKCS_IBA 0004000 /* inhibit RKBA increment: all DMA from single word */ #define RKCS_SCP 0020000 /* search complete */ #define RKCS_HE 0040000 /* hard error */ #define RKCS_ERR 0100000 /* error */ #define RKCS_MBZ 0011000 /* must be zero */ #define RKCS_RO 0160200 /* read-only: ERR|HE|SCP|RDY */ #define RKWC (BASE+006) static word rkwc; #define RKBA (BASE+010) static word rkba; #define RKDA (BASE+012) static word rkda; #define RKDA_SECTOR 0000017 /* sector, 000..013 */ #define RKDA_SECTOR_SHIFT 0 #define RKDA_SURFACE 0000020 /* surface, 0 or 1 */ #define RKDA_SURFACE_SHIFT 4 #define RKDA_CYLINDER 0017740 /* cylinder, 0000..0312 */ #define RKDA_CYLINDER_SHIFT 5 #define RKDA_DRIVE 0160000 /* drive, 0..7 */ #define RKDA_DRIVE_SHIFT 13 #define NSECT 014 #define NHEAD 2 #define NCYL 0313 #define DRIVESECTS (NSECT*NHEAD*NCYL) #define SECTSIZE 01000 /* 0t512 */ #define DRIVESIZE (DRIVESECTS*SECTSIZE) static char drivepresent[MAXDRIVES]; static char drivereadonly[MAXDRIVES]; static int drivefd[MAXDRIVES]; static char *drivebuf[MAXDRIVES]; static int curcyl[MAXDRIVES]; extern DRIVER rk11_driver; static void rk11_busreset(); static void intr() { interrupt(&rk11_driver,0220,BR5); } static void select_drive() { int d; d = REGBITS(rkda,RKDA_DRIVE); rkds = RKDS_RK05 | RKDS_SC_OK; if (drivepresent[d]) rkds |= RKDS_DRV_RDY | RKDS_RWS_RDY; } static void ctlreset() { rker = 0; rkcs = RKCS_RDY; rkda = 0; select_drive(); } static void dowrite() { int pa; int drv; int cyl; int head; int sect; int off_s; int off_b; int n_ok; int err; drv = REGBITS(rkda,RKDA_DRIVE); if (! drivepresent[drv]) { rker |= RKER_NXD; rkcs |= RKCS_HE; if (rkcs & RKCS_IDE) intr(); return; } if (drivereadonly[drv]) { rker |= RKER_WLO; } if ((rkds & (RKDS_DRV_RDY|RKDS_RWS_RDY)) != (RKDS_DRV_RDY|RKDS_RWS_RDY)) { rker |= RKER_DRE; } pa = (REGBITS(rkcs,RKCS_MEX) << 16) | rkba; cyl = curcyl[drv]; head = REGBITS(rkda,RKDA_SURFACE); sect = REGBITS(rkda,RKDA_SECTOR); if (sect >= NSECT) { rker |= RKER_NXS; } if (rker & RKER_HARD) { rkcs |= RKCS_HE; if (rkcs & RKCS_IDE) intr(); return; } off_s = (((cyl * NHEAD) + head) * NSECT) + sect; off_b = off_s * SECTSIZE; n_ok = rkwc * 2; err = 0; if (off_b+n_ok > DRIVESIZE) { n_ok = DRIVESIZE - off_b; err = RKER_OVR; } if (pa+n_ok > CORESIZE) { n_ok = CORESIZE - pa; err = RKER_NXM; } if (n_ok > 0) bcopy(&core[pa],&drivebuf[drv][off_b],n_ok); if (err) { rker |= err; rkcs |= RKCS_HE; if (rkcs & RKCS_IDE) intr(); return; } if (rkcs & RKCS_IDE) intr(); } static void doread() { int pa; int drv; int cyl; int head; int sect; int off_s; int off_b; int n_ok; int err; drv = regbits(rkda,RKDA_DRIVE); if (! drivepresent[drv]) { rker |= RKER_NXD; rkcs |= RKCS_HE; if (rkcs & RKCS_IDE) intr(); return; } if ((rkds & (RKDS_DRV_RDY|RKDS_RWS_RDY)) != (RKDS_DRV_RDY|RKDS_RWS_RDY)) { rker |= RKER_DRE; } pa = (REGBITS(rkcs,RKCS_MEX) << 16) | rkba; cyl = curcyl[drv]; head = REGBITS(rkda,RKDA_SURFACE); sect = REGBITS(rkda,RKDA_SECTOR)); if (cyl >= NCYL) { rker |= RKER_NXC; } if (sect >= NSECT) { rker |= RKER_NXS; } if (rker & RKER_HARD) { rkcs |= RKCS_HE; if (rkcs & RKCS_IDE) intr(); return; } off_s = (((cyl * NHEAD) + head) * NSECT) + sect; off_b = off_s * SECTSIZE; n_ok = rkwc * 2; err = 0; if (off_b+n_ok > DRIVESIZE) { n_ok = DRIVESIZE - off_b; err = RKER_OVR; } if (pa+n_ok > CORESIZE) { n_ok = CORESIZE - pa; err = RKER_NXM; } if (n_ok > 0) bcopy(&drivebuf[drv][off_b],&core[pa],n_ok); if (err) { rker |= err; rkcs |= RKCS_HE; if (rkcs & RKCS_IDE) intr(); return; } if (rkcs & RKCS_IDE) intr(); } static void dowritechk() { dowrite(); } static void doseek() { int drv; int cyl; drv = regbits(rkda,RKDA_DRIVE); if (! drivepresent[drv]) { rker |= RKER_NXD; rkcs |= RKCS_HE; if (rkcs & RKCS_IDE) intr(); return; } if ((rkds & (RKDS_DRV_RDY|RKDS_RWS_RDY)) != (RKDS_DRV_RDY|RKDS_RWS_RDY)) { rker |= RKER_DRE; } cyl = REGBITS(rkda,RKDA_CYLINDER); if (cyl >= NCYL) { rker |= RKER_NXC; rkcs |= RKCS_HE; if (rkcs & RKCS_IDE) intr(); return; } curcyl[drv] = cyl; rkcs |= RKCS_SCP; if (rkcs & RKCS_IDE) intr(); } blah. several these intr() calls have to queue interrupts internally. static void doreadchk() { doread(); } static void dodrvreset() { } static void dowritelck() { } static void go() { rkcs &= ~RKCS_GO; switch (rkcs & RKCS_FXN) { case RKCS_FXN_CTLRESET: ctlreset(); break; case RKCS_FXN_WRITE: dowrite(); break; case RKCS_FXN_READ: doread(); break; case RKCS_FXN_WRITECHK: dowritechk(); break; case RKCS_FXN_SEEK: doseek(); break; case RKCS_FXN_READCHK: doreadchk(); break; case RKCS_FXN_DRVRESET: dodrvreset(); break; case RKCS_FXN_WRITELCK: dowritelck(); break; } } static void rk11_init(d,iomask) DRIVER *d; char *iomask; { int i; iomask[IOMASK(RKDS)] = 1; iomask[IOMASK(RKER)] = 1; iomask[IOMASK(RKCS)] = 1; iomask[IOMASK(RKWC)] = 1; iomask[IOMASK(RKBA)] = 1; iomask[IOMASK(RKDA)] = 1; for (i=0;i 32) { time = 0; rkds = (rkds & ~RKDS_SC) | (((REGBITS(rkds,RKDS_SC) + 1) % NSECT) << RKDS_SC_SHIFT); if (REGBITS(rkds,RKDS_SC) == REGBITS(rkda,RKDA_SECTOR)) { rkds |= RKDS_SA_EQ_SC; } else { rkds &= ~RKDS_SA_EQ_SC; } } } static int rk11_io(d,loc,op,data,fxn) DRIVER *d; int loc; int op; int data; void (*fxn)(); { switch (loc) { case IOMASK(RKDS): switch (op & IO_OP) { case IO_R: return(rkds); break; case IO_W: break; } break; case IOMASK(RKER): switch (op & IO_OP) { case IO_R: return(rker); break; case IO_W: break; } break; case IOMASK(RKCS): switch (op & IO_OP) { case IO_R: return(rkcs); break; case IO_W: data &= ~RKCS_MBZ; rkcs = (rkcs & RKCS_RO) | (data & ~RKCS_RO); if (rkcs & RKCS_GO) go(); break; } break; case IOMASK(RKWC): switch (op & IO_OP) { case IO_R: return(rkwc); break; case IO_W: rkwc = data; break; } break; case IOMASK(RKBA): switch (op & IO_OP) { case IO_R: return(rkba); break; case IO_W: rkba = data; break; } break; case IOMASK(RKDA): switch (op & IO_OP) { case IO_R: return(rkda); break; case IO_W: if (rkcs & RKCS_RDY) rkda = data; break; } break; } } static void rk11_busreset(d) DRIVER *d; { ctlreset(); } static void rk11_reset(d) DRIVER *d; { rk11_busreset(d); } static int rk11_intchk(irq) INTRQ *irq; { } static void rk11_intack(irq) INTRQ *irq; { } DRIVER rk11_driver = { DVR_NORMW, "RK11", rk11_init, rk11_tick, rk11_io, rk11_busreset, rk11_reset, rk11_intchk, rk11_intack };