/* dc4.c: SWTP DC-4 FDC Simulator Copyright (c) 2005-2012, William A. Beech Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL WILLIAM A BEECH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Except as contained in this notice, the name of William A. Beech shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from William A. Beech. MODIFICATIONS: 23 Apr 15 -- Modified to use simh_debug NOTES: The DC-4 is a 5-inch floppy controller which can control up to 4 daisy-chained 5-inch floppy drives. The controller is based on the Western Digital 1797 Floppy Disk Controller (FDC) chip. This file only emulates the minimum DC-4 functionality to interface with the virtual disk file. The floppy controller is interfaced to the CPU by use of 5 memory addreses. These are SS-30 slot numbers 5 and 6 (0x8014-0x801B). Address Mode Function ------- ---- -------- 0x8014 Read Returns FDC interrupt status 0x8014 Write Selects the drive/head/motor control 0x8018 Read Returns status of FDC 0x8018 Write FDC command register 0x8019 Read Returns FDC track register 0x8019 Write Set FDC track register 0x801A Read Returns FDC sector register 0x801A Write Set FDC sector register 0x801B Read Read data 0x801B Write Write data Drive Select Read (0x8014): +---+---+---+---+---+---+---+---+ | I | D | X | X | X | X | X | X | +---+---+---+---+---+---+---+---+ I = Set indicates an interrupt request from the FDC pending. D = DRQ pending - same as bit 1 of FDC status register. Drive Select Write (0x8014): +---+---+---+---+---+---+---+---+ | M | S | X | X | X | X | Device| +---+---+---+---+---+---+---+---+ M = If this bit is 1, the one-shot is triggered/retriggered to start/keep the motors on. S = Side select. If set, side one is selected otherwise side zero is selected. X = not used Device = value 0 thru 3, selects drive 0-3 to be controlled. Drive Status Read (0x8018): +---+---+---+---+---+---+---+---+ | R | P | H | S | C | L | D | B | +---+---+---+---+---+---+---+---+ B - When 1, the controller is busy. D - When 1, index mark detected (type I) or data request - read data ready/write data empty (type II or III). H - When 1, track 0 (type I) or lost data (type II or III). C - When 1, crc error detected. S - When 1, seek (type I) or RNF (type II or III) error. H - When 1, head is currently loaded (type I) or record type/ write fault (type II or III). P - When 1, indicates that diskette is write-protected. R - When 1, drive is not ready. Drive Control Write (0x8018) for type I commands: +---+---+---+---+---+---+---+---+ | 0 | S2| S1| S0| H | V | R1| R0| +---+---+---+---+---+---+---+---+ R0/R1 - Selects the step rate. V - When 1, verify on destination track. H - When 1, loads head to drive surface. S0/S1/S2 = 000 - home. 001 - seek track in data register. 010 - step without updating track register. 011 - step and update track register. 100 - step in without updating track register. 101 - step in and update track register. 110 - step out without updating track register. 111 - step out and update track register. Drive Control Write (0x8018) for type II commands: +---+---+---+---+---+---+---+---+ | 1 | 0 | T | M | S | E | B | A | +---+---+---+---+---+---+---+---+ A - Zero for read, 1 on write deleted data mark else data mark. B - When 1, shifts sector length field definitions one place. E - When, delay operation 15 ms, 0 no delay. S - When 1, select side 1, 0 select side 0. M - When 1, multiple records, 0 for single record. T - When 1, write command, 0 for read. Drive Control Write (0x8018) for type III commands: +---+---+---+---+---+---+---+---+ | 1 | 1 | T0| T1| 0 | E | 0 | 0 | +---+---+---+---+---+---+---+---+ E - When, delay operation 15 ms, 0 no delay. T0/T1 - 00 - read address command. 10 - read track command. 11 - write track command. Tracks are numbered from 0 up to one minus the last track in the 1797! Track Register Read (0x8019): +---+---+---+---+---+---+---+---+ | Track Number | +---+---+---+---+---+---+---+---+ Reads the current 8-bit value from the track position. Track Register Write (0x8019): +---+---+---+---+---+---+---+---+ | Track Number | +---+---+---+---+---+---+---+---+ Writes the 8-bit value to the track register. Sectors are numbers from 1 up to the last sector in the 1797! Sector Register Read (0x801A): +---+---+---+---+---+---+---+---+ | Sector Number | +---+---+---+---+---+---+---+---+ Reads the current 8-bit value from the sector position. Sector Register Write (0x801A): +---+---+---+---+---+---+---+---+ | Sector Number | +---+---+---+---+---+---+---+---+ Writes the 8-bit value to the sector register. Data Register Read (0x801B): +---+---+---+---+---+---+---+---+ | Data | +---+---+---+---+---+---+---+---+ Reads the current 8-bit value from the data register. Data Register Write (0x801B): +---+---+---+---+---+---+---+---+ | Data | +---+---+---+---+---+---+---+---+ Writes the 8-bit value to the data register. A FLEX disk is defined as follows: Track Sector Use 0 1 Boot sector 0 2 Boot sector (cont) 0 3 Unused 0 4 System Identity Record (explained below) 0 5 Unused 0 6-last Directory - 10 entries/sector (explained below) 1 1 First available data sector last-1 last Last available data sector System Identity Record Byte Use 0x00 Two bytes of zeroes (Clears forward link) 0x10 Volume name in ASCII(11 bytes) 0x1B Volume number in binary (2 bytes) 0x1D Address of first free data sector (Track-Sector) (2 bytes) 0x1F Address of last free data sector (Track-Sector) (2 bytes) 0x21 Total number of data sectors in binary (2 bytes) 0x23 Current date (Month-Day-Year) in binary 0x26 Highest track number on disk in binary (byte) 0x27 Highest sector number on a track in binary (byte) The following unit registers are used by this controller emulation: dsk_unit[cur_drv].u3 unit current flags dsk_unit[cur_drv].u4 unit current track dsk_unit[cur_drv].u5 unit current sector dsk_unit[cur_drv].pos unit current sector byte index into buffer dsk_unit[cur_drv].filebuf unit current sector buffer dsk_unit[cur_drv].fileref unit current attached file reference */ #include #include "swtp_defs.h" #define DEBUG 0 #define UNIT_V_ENABLE (UNIT_V_UF + 0) /* Write Enable */ #define UNIT_ENABLE (1 << UNIT_V_ENABLE) /* emulate a SS FLEX disk with 72 sectors and 80 tracks */ #define NUM_DISK 4 /* standard 1797 maximum */ #define SECT_SIZE 256 /* standard FLEX sector */ #define NUM_SECT 72 /* sectors/track */ #define TRAK_SIZE (SECT_SIZE * NUM_SECT) /* trk size (bytes) */ #define HEADS 1 /* handle as SS with twice the sectors */ #define NUM_CYL 80 /* maximum tracks */ #define DSK_SIZE (NUM_SECT * HEADS * NUM_CYL * SECT_SIZE) /* dsk size (bytes) */ #define SECSIZ 256 /* standard FLEX sector */ /* SIR offsets */ #define MAXCYL 0x26 /* last cylinder # */ #define MAXSEC 0x27 /* last sector # */ /* 1797 status bits */ #define BUSY 0x01 #define DRQ 0x02 #define WRPROT 0x40 #define NOTRDY 0x80 /* function prototypes */ t_stat dsk_reset (DEVICE *dptr); /* SS-50 I/O address space functions */ int32 fdcdrv(int32 io, int32 data); int32 fdccmd(int32 io, int32 data); int32 fdctrk(int32 io, int32 data); int32 fdcsec(int32 io, int32 data); int32 fdcdata(int32 io, int32 data); /* Local Variables */ int32 fdcbyte; int32 intrq = 0; /* interrupt request flag */ int32 cur_dsk; /* Currently selected drive */ int32 wrt_flag = 0; /* FDC write flag */ int32 spt; /* sectors/track */ int32 trksiz; /* trk size (bytes) */ int32 heds; /* number of heads */ int32 cpd; /* cylinders/disk */ int32 dsksiz; /* dsk size (bytes) */ /* Floppy Disk Controller data structures dsk_dev Mother Board device descriptor dsk_unit Mother Board unit descriptor dsk_reg Mother Board register list dsk_mod Mother Board modifiers list */ UNIT dsk_unit[] = { { UDATA (NULL, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, 0) }, { UDATA (NULL, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, 0) }, { UDATA (NULL, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, 0) }, { UDATA (NULL, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, 0) } }; REG dsk_reg[] = { { HRDATA (DISK, cur_dsk, 4) }, { NULL } }; MTAB dsk_mod[] = { { UNIT_ENABLE, UNIT_ENABLE, "RW", "RW", NULL }, { UNIT_ENABLE, 0, "RO", "RO", NULL }, { 0 } }; DEBTAB dsk_debug[] = { { "ALL", DEBUG_all }, { "FLOW", DEBUG_flow }, { "READ", DEBUG_read }, { "WRITE", DEBUG_write }, { "LEV1", DEBUG_level1 }, { "LEV2", DEBUG_level2 }, { NULL } }; DEVICE dsk_dev = { "DC-4", //name dsk_unit, //units dsk_reg, //registers dsk_mod, //modifiers 4, //numunits 16, //aradix 16, //awidth 1, //aincr 16, //dradix 8, //dwidth NULL, //examine NULL, //deposit &dsk_reset, //reset NULL, //boot NULL, //attach NULL, //detach NULL, //ctxt DEV_DEBUG, //flags 0, //dctrl dsk_debug, /* debflags */ NULL, //msize NULL //lname }; /* Reset routine */ t_stat dsk_reset (DEVICE *dptr) { int i; cur_dsk = 5; /* force initial SIR read */ for (i=0; i