| /* dc4.c: SWTP DC-4 FDC Simulator | |
| Copyright (c) 2005-2011, 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. | |
| 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 <stdio.h> | |
| #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<NUM_DISK; i++) { | |
| dsk_unit[i].u3 = 0; /* clear current flags */ | |
| dsk_unit[i].u4 = 0; /* clear current cylinder # */ | |
| dsk_unit[i].u5 = 0; /* clear current sector # */ | |
| dsk_unit[i].pos = 0; /* clear current byte ptr */ | |
| if (dsk_unit[i].filebuf == NULL) { | |
| dsk_unit[i].filebuf = malloc(256); /* allocate buffer */ | |
| if (dsk_unit[i].filebuf == NULL) { | |
| printf("dc-4_reset: Malloc error\n"); | |
| return SCPE_MEM; | |
| } | |
| } | |
| } | |
| spt = 0; | |
| trksiz = 0; | |
| heds = 0; | |
| cpd = 0; | |
| dsksiz = 0; | |
| return SCPE_OK; | |
| } | |
| /* I/O instruction handlers, called from the MP-B2 module when a | |
| read or write occur to addresses 0x8004-0x8007. */ | |
| /* DC-4 drive select register routine - this register is not part of the 1797 | |
| */ | |
| int32 fdcdrv(int32 io, int32 data) | |
| { | |
| static long pos; | |
| if (io) { /* write to DC-4 drive register */ | |
| if (dsk_dev.dctrl & DEBUG_write) | |
| printf("\nfdcdrv: Drive selected %d cur_dsk=%d", data & 0x03, cur_dsk); | |
| if (cur_dsk == (data & 0x03)) | |
| return 0; /* already selected */ | |
| cur_dsk = data & 0x03; /* only 2 drive select bits */ | |
| if (dsk_dev.dctrl & DEBUG_write) | |
| printf("\nfdcdrv: Drive set to %d", cur_dsk); | |
| if ((dsk_unit[cur_dsk].flags & UNIT_ENABLE) == 0) { | |
| dsk_unit[cur_dsk].u3 |= WRPROT; /* set 1797 WPROT */ | |
| if (dsk_dev.dctrl & DEBUG_write) | |
| printf("\nfdcdrv: Drive write protected"); | |
| } else { | |
| dsk_unit[cur_dsk].u3 &= ~WRPROT; /* set 1797 not WPROT */ | |
| if (dsk_dev.dctrl & DEBUG_write) | |
| printf("\nfdcdrv: Drive NOT write protected"); | |
| } | |
| pos = 0x200; /* Read in SIR */ | |
| if (dsk_dev.dctrl & DEBUG_read) | |
| printf("\nfdcdrv: Read pos = %ld ($%04X)", pos, (unsigned int) pos); | |
| sim_fseek(dsk_unit[cur_dsk].fileref, pos, 0); /* seek to offset */ | |
| sim_fread(dsk_unit[cur_dsk].filebuf, SECSIZ, 1, dsk_unit[cur_dsk].fileref); /* read in buffer */ | |
| dsk_unit[cur_dsk].u3 |= BUSY | DRQ; /* set DRQ & BUSY */ | |
| dsk_unit[cur_dsk].pos = 0; /* clear counter */ | |
| spt = *((uint8 *)(dsk_unit[cur_dsk].filebuf) + MAXSEC) & 0xFF; | |
| heds = 0; | |
| cpd = *((uint8 *)(dsk_unit[cur_dsk].filebuf) + MAXCYL) & 0xFF; | |
| trksiz = spt * SECSIZ; | |
| dsksiz = trksiz * cpd; | |
| if (dsk_dev.dctrl & DEBUG_read) | |
| printf("\nfdcdrv: spt=%d heds=%d cpd=%d trksiz=%d dsksiz=%d flags=%08X u3=%08X", | |
| spt, heds, cpd, trksiz, dsksiz, dsk_unit[cur_dsk].flags, dsk_unit[cur_dsk].u3); | |
| return 0; | |
| } else { /* read from DC-4 drive register */ | |
| if (dsk_dev.dctrl & DEBUG_read) | |
| printf("\nfdcdrv: Drive read as %02X", intrq); | |
| return intrq; | |
| } | |
| } | |
| /* WD 1797 FDC command register routine */ | |
| int32 fdccmd(int32 io, int32 data) | |
| { | |
| static int32 val = 0, val1 = NOTRDY; | |
| static long pos; | |
| if ((dsk_unit[cur_dsk].flags & UNIT_ATT) == 0) { /* not attached */ | |
| dsk_unit[cur_dsk].u3 |= NOTRDY; /* set not ready flag */ | |
| if (dsk_dev.dctrl & DEBUG_flow) | |
| printf("\nfdccmd: Drive %d is not attached", cur_dsk); | |
| return 0; | |
| } else { | |
| dsk_unit[cur_dsk].u3 &= ~NOTRDY; /* clear not ready flag */ | |
| } | |
| if (io) { /* write command to fdc */ | |
| switch(data) { | |
| case 0x8C: /* read command */ | |
| case 0x9C: | |
| if (dsk_dev.dctrl & DEBUG_read) | |
| printf("\nfdccmd: Read of disk %d, track %d, sector %d", | |
| cur_dsk, dsk_unit[cur_dsk].u4, dsk_unit[cur_dsk].u5); | |
| pos = trksiz * dsk_unit[cur_dsk].u4; /* calculate file offset */ | |
| pos += SECSIZ * (dsk_unit[cur_dsk].u5 - 1); | |
| if (dsk_dev.dctrl & DEBUG_read) | |
| printf("\nfdccmd: Read pos = %ld ($%08X)", pos, (unsigned int) pos); | |
| sim_fseek(dsk_unit[cur_dsk].fileref, pos, 0); /* seek to offset */ | |
| sim_fread(dsk_unit[cur_dsk].filebuf, SECSIZ, 1, dsk_unit[cur_dsk].fileref); /* read in buffer */ | |
| dsk_unit[cur_dsk].u3 |= BUSY | DRQ; /* set DRQ & BUSY */ | |
| dsk_unit[cur_dsk].pos = 0; /* clear counter */ | |
| break; | |
| case 0xAC: /* write command */ | |
| if (dsk_dev.dctrl & DEBUG_write) | |
| printf("\nfdccmd: Write of disk %d, track %d, sector %d", | |
| cur_dsk, dsk_unit[cur_dsk].u4, dsk_unit[cur_dsk].u5); | |
| if (dsk_unit[cur_dsk].u3 & WRPROT) { | |
| printf("\nfdccmd: Drive %d is write-protected", cur_dsk); | |
| } else { | |
| pos = trksiz * dsk_unit[cur_dsk].u4; /* calculate file offset */ | |
| pos += SECSIZ * (dsk_unit[cur_dsk].u5 - 1); | |
| if (dsk_dev.dctrl & DEBUG_write) | |
| printf("\nfdccmd: Write pos = %ld ($%08X)", pos, (unsigned int) pos); | |
| sim_fseek(dsk_unit[cur_dsk].fileref, pos, 0); /* seek to offset */ | |
| wrt_flag = 1; /* set write flag */ | |
| dsk_unit[cur_dsk].u3 |= BUSY | DRQ;/* set DRQ & BUSY */ | |
| dsk_unit[cur_dsk].pos = 0; /* clear counter */ | |
| } | |
| break; | |
| case 0x18: /* seek command */ | |
| case 0x1B: | |
| dsk_unit[cur_dsk].u4 = fdcbyte; /* set track */ | |
| dsk_unit[cur_dsk].u3 &= ~(BUSY | DRQ); /* clear flags */ | |
| if (dsk_dev.dctrl & DEBUG_flow) | |
| printf("\nfdccmd: Seek of disk %d, track %d", cur_dsk, fdcbyte); | |
| break; | |
| case 0x0B: /* restore command */ | |
| dsk_unit[cur_dsk].u4 = 0; /* home the drive */ | |
| dsk_unit[cur_dsk].u3 &= ~(BUSY | DRQ); /* clear flags */ | |
| if (dsk_dev.dctrl & DEBUG_flow) | |
| printf("\nfdccmd: Drive %d homed", cur_dsk); | |
| break; | |
| case 0xF0: /* write track command */ | |
| if (dsk_dev.dctrl & DEBUG_write) | |
| printf("\nfdccmd: Write track command for drive %d", cur_dsk); | |
| break; | |
| default: | |
| printf("Unknown FDC command %02XH\n\r", data); | |
| } | |
| } else { /* read status from fdc */ | |
| val = dsk_unit[cur_dsk].u3; /* set return value */ | |
| /* either print below will force the val to 0x43 forever. timing problem in | |
| the 6800 disk driver software? */ | |
| // if (dsk_dev.dctrl & DEBUG_flow) | |
| // printf("\nfdccmd: Exit Drive %d status=%02X", cur_dsk, val); | |
| // printf("\n%02X", val); //even this short fails it! | |
| if (val1 == 0 && ((val & (BUSY + DRQ)) == (BUSY + DRQ))) /* delay BUSY going high */ | |
| val &= ~BUSY; | |
| if (val != val1) /* now allow BUSY after one read */ | |
| val1 = val; | |
| if (dsk_dev.dctrl & DEBUG_flow) | |
| printf("\nfdccmd: Exit Drive %d status=%02X", cur_dsk, val); | |
| } | |
| return val; | |
| } | |
| /* WD 1797 FDC track register routine */ | |
| int32 fdctrk(int32 io, int32 data) | |
| { | |
| if (io) { | |
| dsk_unit[cur_dsk].u4 = data & 0xFF; | |
| if (dsk_dev.dctrl & DEBUG_read) | |
| printf("\nfdctrk: Drive %d track set to %d", cur_dsk, dsk_unit[cur_dsk].u4); | |
| } else | |
| ; | |
| if (dsk_dev.dctrl & DEBUG_write) | |
| printf("\nfdctrk: Drive %d track read as %d", cur_dsk, dsk_unit[cur_dsk].u4); | |
| return dsk_unit[cur_dsk].u4; | |
| } | |
| /* WD 1797 FDC sector register routine */ | |
| int32 fdcsec(int32 io, int32 data) | |
| { | |
| if (io) { | |
| dsk_unit[cur_dsk].u5 = data & 0xFF; | |
| if (dsk_unit[cur_dsk].u5 == 0) /* fix for swtp boot! */ | |
| dsk_unit[cur_dsk].u5 = 1; | |
| if (dsk_dev.dctrl & DEBUG_write) | |
| printf("\nfdcsec: Drive %d sector set to %d", cur_dsk, dsk_unit[cur_dsk].u5); | |
| } else | |
| ; | |
| if (dsk_dev.dctrl & DEBUG_read) | |
| printf("\nfdcsec: Drive %d sector read as %d", cur_dsk, dsk_unit[cur_dsk].u5); | |
| return dsk_unit[cur_dsk].u5; | |
| } | |
| /* WD 1797 FDC data register routine */ | |
| int32 fdcdata(int32 io, int32 data) | |
| { | |
| int32 val; | |
| if (io) { /* write byte to fdc */ | |
| fdcbyte = data; /* save for seek */ | |
| if (dsk_unit[cur_dsk].pos < SECSIZ) { /* copy bytes to buffer */ | |
| if (dsk_dev.dctrl & DEBUG_write) | |
| printf("\nfdcdata: Writing byte %d of %02X", dsk_unit[cur_dsk].pos, data); | |
| *((uint8 *)(dsk_unit[cur_dsk].filebuf) + dsk_unit[cur_dsk].pos) = data; /* byte into buffer */ | |
| dsk_unit[cur_dsk].pos++; /* step counter */ | |
| if (dsk_unit[cur_dsk].pos == SECSIZ) { | |
| dsk_unit[cur_dsk].u3 &= ~(BUSY | DRQ); | |
| if (wrt_flag) { /* if initiated by FDC write command */ | |
| sim_fwrite(dsk_unit[cur_dsk].filebuf, SECSIZ, 1, dsk_unit[cur_dsk].fileref); /* write it */ | |
| wrt_flag = 0; /* clear write flag */ | |
| } | |
| if (dsk_dev.dctrl & DEBUG_write) | |
| printf("\nfdcdata: Sector write complete"); | |
| } | |
| } | |
| return 0; | |
| } else { /* read byte from fdc */ | |
| if (dsk_unit[cur_dsk].pos < SECSIZ) { /* copy bytes from buffer */ | |
| if (dsk_dev.dctrl & DEBUG_read) | |
| printf("\nfdcdata: Reading byte %d u3=%02X", dsk_unit[cur_dsk].pos, dsk_unit[cur_dsk].u3); | |
| val = *((uint8 *)(dsk_unit[cur_dsk].filebuf) + dsk_unit[cur_dsk].pos) & 0xFF; | |
| dsk_unit[cur_dsk].pos++; /* step counter */ | |
| if (dsk_unit[cur_dsk].pos == SECSIZ) { /* done? */ | |
| dsk_unit[cur_dsk].u3 &= ~(BUSY | DRQ); /* clear flags */ | |
| if (dsk_dev.dctrl & DEBUG_write) | |
| printf("\nfdcdata: Sector read complete"); | |
| } | |
| return val; | |
| } else | |
| return 0; | |
| } | |
| } | |
| /* end of dc-4.c */ |