Index: iodev/floppy.cc =================================================================== RCS file: /cvsroot/bochs/bochs/iodev/floppy.cc,v retrieving revision 1.103 diff -u -r1.103 floppy.cc --- iodev/floppy.cc 10 Sep 2006 17:18:44 -0000 1.103 +++ iodev/floppy.cc 20 Nov 2006 23:07:14 -0000 @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////// -// $Id: floppy.cc,v 1.103 2006/09/10 17:18:44 vruppert Exp $ +// $Id: floppy.cc,v 1.24 2006/11/20 23:04:10 jcomeau Exp $ ///////////////////////////////////////////////////////////////////////// // // Copyright (C) 2002 MandrakeSoft S.A. @@ -41,7 +41,6 @@ // is used to know when we are exporting symbols and when we are importing. #define BX_PLUGGABLE - extern "C" { #include } @@ -63,15 +62,30 @@ bx_floppy_ctrl_c *theFloppyController; -/* for main status register */ +/* for main status register (s.main_status_reg) */ #define FD_MS_MRQ 0x80 #define FD_MS_DIO 0x40 +#define FD_MS_DATA_READY FD_MS_MRQ|FD_MS_DIO #define FD_MS_NDMA 0x20 +/* note: when NDMA is set, controller interrupts for every byte available +/* at data register */ #define FD_MS_BUSY 0x10 +#define FD_MS_STATUSBITS FD_MS_MRQ|FD_MS_DIO|FD_MS_NDMA|FD_MS_BUSY #define FD_MS_ACTD 0x08 #define FD_MS_ACTC 0x04 #define FD_MS_ACTB 0x02 #define FD_MS_ACTA 0x01 +#define FD_MS_ACTIVEBITS FD_MS_ACTD|FD_MS_ACTC|FD_MS_ACTB|FD_MS_ACTA + +#define FD_RESET 0 // useful for most registers in reset state + +// define bits of status register ST0 +#define FD_ST0_IC1 0x80 // interrupt code bit 1 +#define FD_ST0_IC0 0x40 // interrupt code bit 0 +#define FD_ST0_NORMAL_TERMINATION 0 // command terminated without errors +#define FD_ST0_ABNORMAL_TERMINATION FD_ST0_IC0 // could not finish processing +#define FD_ST0_INVALID_COMMAND FD_ST0_IC1 // could not start processing +#define FD_ST0_POLLING_FAILED FD_ST0_IC1|FD_ST0_IC0 // drive not ready #define FROM_FLOPPY 10 #define TO_FLOPPY 11 @@ -139,9 +153,10 @@ { Bit8u i; - BX_DEBUG(("Init $Id: floppy.cc,v 1.103 2006/09/10 17:18:44 vruppert Exp $")); + BX_DEBUG(("Init $Id: floppy.cc,v 1.24 2006/11/20 23:04:10 jcomeau Exp $")); DEV_dma_register_8bit_channel(2, dma_read, dma_write, "Floppy Drive"); DEV_register_irq(6, "Floppy Drive"); + // here is where we register ourself to handle reads and writes to these ports for (unsigned addr=0x03F2; addr<=0x03F7; addr++) { DEV_register_ioread_handler(this, read_handler, addr, "Floppy Drive", 1); DEV_register_iowrite_handler(this, write_handler, addr, "Floppy Drive", 1); @@ -330,7 +345,7 @@ BX_FD_THIS s.SRT = 0; BX_FD_THIS s.HUT = 0; BX_FD_THIS s.HLT = 0; - BX_FD_THIS s.non_dma = 0; + BX_FD_THIS s.main_status_reg &= ~FD_MS_NDMA; // enable DMA from start } void bx_floppy_ctrl_c::reset(unsigned type) @@ -340,11 +355,12 @@ BX_FD_THIS s.pending_irq = 0; BX_FD_THIS s.reset_sensei = 0; /* no reset result present */ - BX_FD_THIS s.main_status_reg = 0; - BX_FD_THIS s.status_reg0 = 0; - BX_FD_THIS s.status_reg1 = 0; - BX_FD_THIS s.status_reg2 = 0; - BX_FD_THIS s.status_reg3 = 0; + BX_FD_THIS s.main_status_reg = FD_RESET; + // status regs 0-3 are accessed through the data register via command 0x04 + BX_FD_THIS s.status_reg0 = FD_RESET; + BX_FD_THIS s.status_reg1 = FD_RESET; + BX_FD_THIS s.status_reg2 = FD_RESET; + BX_FD_THIS s.status_reg3 = FD_RESET; // software reset (via DOR port 0x3f2 bit 2) does not change DOR if (type == BX_RESET_HARDWARE) { @@ -377,7 +393,9 @@ } DEV_pic_lower_irq(6); - DEV_dma_set_drq(FLOPPY_DMA_CHAN, 0); + if (!(non_dma())) { + DEV_dma_set_drq(FLOPPY_DMA_CHAN, 0); + } enter_idle_phase(); } @@ -420,7 +438,6 @@ new bx_shadow_num_c(list, "status_reg2", &BX_FD_THIS s.status_reg2, BASE_HEX); new bx_shadow_num_c(list, "status_reg3", &BX_FD_THIS s.status_reg3, BASE_HEX); new bx_shadow_num_c(list, "floppy_buffer_index", &BX_FD_THIS s.floppy_buffer_index); - new bx_shadow_bool_c(list, "non_dma", &BX_FD_THIS s.non_dma); new bx_shadow_bool_c(list, "lock", &BX_FD_THIS s.lock); new bx_shadow_num_c(list, "SRT", &BX_FD_THIS s.SRT, BASE_HEX); new bx_shadow_num_c(list, "HUT", &BX_FD_THIS s.HUT, BASE_HEX); @@ -463,7 +480,7 @@ switch (address) { #if BX_DMA_FLOPPY_IO - case 0x3F2: // diskette controller digital output register + case 0x3F2: // diskette controller digital output register (DOR) value = BX_FD_THIS s.DOR; break; @@ -472,16 +489,23 @@ break; case 0x3F5: /* diskette controller data */ - if (BX_FD_THIS s.result_size == 0) { - BX_ERROR(("port 0x3f5: no results to read")); - BX_FD_THIS s.main_status_reg = 0; - value = BX_FD_THIS s.result[0]; + if (non_dma() && + (BX_FD_THIS s.pending_command & 0x4f) == 0x46) { + // don't enter idle phase until we've given CPU last data byte + if (FD_MS_DATA_READY) dma_write(&value); + if (BX_FD_THIS s.TC) enter_idle_phase(); } else { - value = BX_FD_THIS s.result[BX_FD_THIS s.result_index++]; - BX_FD_THIS s.main_status_reg &= 0xF0; - BX_FD_THIS lower_interrupt(); - if (BX_FD_THIS s.result_index >= BX_FD_THIS s.result_size) { - enter_idle_phase(); + if (BX_FD_THIS s.result_size == 0) { + BX_ERROR(("read(): port 0x3f5: no results to read")); + reset_status(); + value = BX_FD_THIS s.result[0]; + } else { + value = BX_FD_THIS s.result[BX_FD_THIS s.result_index++]; + BX_FD_THIS s.main_status_reg &= FD_MS_STATUSBITS; + BX_FD_THIS lower_interrupt(); + if (BX_FD_THIS s.result_index >= BX_FD_THIS s.result_size) { + enter_idle_phase(); + } } } break; @@ -535,11 +559,12 @@ break; default: - BX_ERROR(("io_read: unsupported address 0x%04x", (unsigned) address)); + BX_ERROR(("read(): unsupported address 0x%04x", (unsigned) address)); return(0); break; } - BX_DEBUG(("read access to port %04x returns 0x%02x", address, value)); + BX_DEBUG(("read(): during command 0x%02x, port %04x returns 0x%02x", + BX_FD_THIS s.pending_command, address, value)); return (value); } @@ -564,7 +589,7 @@ Bit8u drive_select; Bit8u motor_on_drive0, motor_on_drive1; - BX_DEBUG(("write access to port %04x, value=%02x", address, value)); + BX_DEBUG(("write(): to port %04x, value=%02x", address, value)); switch (address) { #if BX_DMA_FLOPPY_IO @@ -592,9 +617,10 @@ if (prev_normal_operation==0 && normal_operation) { // transition from RESET to NORMAL bx_pc_system.activate_timer(BX_FD_THIS s.floppy_timer_index, 250, 0); + BX_DEBUG(("write(): timer activated for floppy transition to normal")); } else if (prev_normal_operation && normal_operation==0) { // transition from NORMAL to RESET - BX_FD_THIS s.main_status_reg = 0; + reset_status(); BX_FD_THIS s.pending_command = 0xfe; // RESET pending } BX_DEBUG(("io_write: digital output register")); @@ -614,9 +640,10 @@ case 0x3f4: /* diskette controller data rate select register */ BX_FD_THIS s.data_rate = value & 0x03; if (value & 0x80) { - BX_FD_THIS s.main_status_reg = 0; + reset_all_status(); BX_FD_THIS s.pending_command = 0xfe; // RESET pending bx_pc_system.activate_timer(BX_FD_THIS s.floppy_timer_index, 250, 0); + BX_DEBUG(("write(): timer activated for floppy reset")); } if ((value & 0x7c) > 0) { BX_ERROR(("write to data rate select register: unsupported bits set")); @@ -627,13 +654,12 @@ BX_DEBUG(("command = %02x", (unsigned) value)); if (BX_FD_THIS s.command_complete) { if (BX_FD_THIS s.pending_command != 0) - BX_PANIC(("write 0x03f5: receiving new command 0x%02x, old one (0x%02x) pending", + BX_PANIC(("write(): port 0x03f5 receiving new command 0x%02x, old one (0x%02x) pending", value, BX_FD_THIS s.pending_command)); BX_FD_THIS s.command[0] = value; BX_FD_THIS s.command_complete = 0; BX_FD_THIS s.command_index = 1; - /* read/write command in progress */ - BX_FD_THIS s.main_status_reg &= 0x0f; // leave drive status untouched + reset_status(); // clear drive status BX_FD_THIS s.main_status_reg |= FD_MS_MRQ | FD_MS_BUSY; switch (value) { case 0x03: /* specify */ @@ -690,7 +716,7 @@ BX_DEBUG(("io_write: 0x3f5: unsupported floppy command 0x%02x", (unsigned) value)); BX_FD_THIS s.command_size = 0; // make sure we don't try to process this command - BX_FD_THIS s.status_reg0 = 0x80; // status: invalid command + BX_FD_THIS s.status_reg0 = FD_ST0_INVALID_COMMAND; enter_result_phase(); break; @@ -698,7 +724,7 @@ BX_ERROR(("io_write: 0x3f5: invalid floppy command 0x%02x", (unsigned) value)); BX_FD_THIS s.command_size = 0; // make sure we don't try to process this command - BX_FD_THIS s.status_reg0 = 0x80; // status: invalid command + BX_FD_THIS s.status_reg0 = FD_ST0_INVALID_COMMAND; enter_result_phase(); break; } @@ -745,6 +771,7 @@ void bx_floppy_ctrl_c::floppy_command(void) { + BX_DEBUG(("floppy_command() starting")); #if BX_PROVIDE_CPU_MEMORY==0 BX_PANIC(("floppy_command(): uses DMA: not supported for" " external environment")); @@ -771,9 +798,12 @@ BX_FD_THIS s.SRT = BX_FD_THIS s.command[1] >> 4; BX_FD_THIS s.HUT = BX_FD_THIS s.command[1] & 0x0f; BX_FD_THIS s.HLT = BX_FD_THIS s.command[2] >> 1; - BX_FD_THIS s.non_dma = BX_FD_THIS s.command[2] & 0x01; - if (BX_FD_THIS s.non_dma) - BX_ERROR(("non DMA mode not implemented yet")); + if (BX_FD_THIS s.command[2] & 0x01) BX_FD_THIS s.main_status_reg |= FD_MS_NDMA; + if (non_dma()) { + BX_DEBUG(("floppy_command(): controller in non DMA mode")); + /* other bugs must be fixed before we can unregister */ + //DEV_dma_unregister_channel(FLOPPY_DMA_CHAN); + } enter_idle_phase(); return; @@ -794,6 +824,7 @@ (unsigned) drive)); step_delay = calculate_step_delay(drive, 0); bx_pc_system.activate_timer(BX_FD_THIS s.floppy_timer_index, step_delay, 0); + BX_DEBUG(("floppy_command(): timer activated for floppy recalibrate")); /* command head to track 0 * controller set to non-busy * error condition noted in Status reg 0's equipment check bit @@ -801,7 +832,8 @@ * The last two are taken care of in timer(). */ BX_FD_THIS s.cylinder[drive] = 0; - BX_FD_THIS s.main_status_reg = (1 << drive); + BX_FD_THIS s.main_status_reg &= ~FD_MS_BUSY; + BX_FD_THIS s.main_status_reg |= (1 << drive); return; case 0x08: /* sense interrupt status */ @@ -841,10 +873,11 @@ BX_FD_THIS s.head[drive] = (BX_FD_THIS s.command[1] >> 2) & 0x01; step_delay = calculate_step_delay(drive, BX_FD_THIS s.command[2]); bx_pc_system.activate_timer(BX_FD_THIS s.floppy_timer_index, step_delay, 0); + BX_DEBUG(("floppy_command(): timer activated for floppy seek")); /* ??? should also check cylinder validity */ BX_FD_THIS s.cylinder[drive] = BX_FD_THIS s.command[2]; /* data reg not ready, drive busy */ - BX_FD_THIS s.main_status_reg = (1 << drive); + BX_FD_THIS s.main_status_reg |= (1 << drive); return; case 0x13: // Configure @@ -867,25 +900,26 @@ motor_on = (BX_FD_THIS s.DOR>>(drive+4)) & 0x01; if (motor_on == 0) { BX_ERROR(("floppy_command(): read ID: motor not on")); - BX_FD_THIS s.main_status_reg = FD_MS_BUSY; + BX_FD_THIS s.main_status_reg |= FD_MS_BUSY; return; // Hang controller } if (BX_FD_THIS s.device_type[drive] == FDRIVE_NONE) { BX_ERROR(("floppy_command(): read ID: bad drive #%d", drive)); - BX_FD_THIS s.main_status_reg = FD_MS_BUSY; + BX_FD_THIS s.main_status_reg |= FD_MS_BUSY; return; // Hang controller } if (BX_FD_THIS s.media_present[drive] == 0) { BX_INFO(("attempt to read sector ID with media not present")); - BX_FD_THIS s.main_status_reg = FD_MS_BUSY; + BX_FD_THIS s.main_status_reg |= FD_MS_BUSY; return; // Hang controller } BX_FD_THIS s.status_reg0 = (BX_FD_THIS s.head[drive]<<2) | drive; // time to read one sector at 300 rpm sector_time = 200000 / BX_FD_THIS s.media[drive].sectors_per_track; bx_pc_system.activate_timer(BX_FD_THIS s.floppy_timer_index, sector_time, 0); + BX_DEBUG(("floppy_command(): timer activated for floppy read ID")); /* data reg not ready, controller busy */ - BX_FD_THIS s.main_status_reg = FD_MS_BUSY; + BX_FD_THIS s.main_status_reg |= FD_MS_BUSY; return; case 0x4d: // format track @@ -926,11 +960,13 @@ /* 4 header bytes per sector are required */ BX_FD_THIS s.format_count <<= 2; - - DEV_dma_set_drq(FLOPPY_DMA_CHAN, 1); - + if (non_dma()) { + BX_DEBUG(("floppy_command(): implement non-DMA floppy format"));; + } else { + DEV_dma_set_drq(FLOPPY_DMA_CHAN, 1); + } /* data reg not ready, controller busy */ - BX_FD_THIS s.main_status_reg = FD_MS_BUSY; + BX_FD_THIS s.main_status_reg |= FD_MS_BUSY; BX_DEBUG(("format track")); return; @@ -1014,7 +1050,6 @@ BX_DEBUG(("io: cylinder request != current cylinder")); reset_changeline(); } - logical_sector = (cylinder * BX_FD_THIS s.media[drive].heads * BX_FD_THIS s.media[drive].sectors_per_track) + (head * BX_FD_THIS s.media[drive].sectors_per_track) + (sector - 1); @@ -1031,19 +1066,24 @@ BX_FD_THIS s.sector[drive] = sector; BX_FD_THIS s.eot[drive] = eot; - if ((BX_FD_THIS s.command[0] & 0x4f) == 0x46) { // read + if ((BX_FD_THIS s.pending_command & 0x4f) == 0x46) { // read floppy_xfer(drive, logical_sector*512, BX_FD_THIS s.floppy_buffer, 512, FROM_FLOPPY); /* data reg not ready, controller busy */ - BX_FD_THIS s.main_status_reg = FD_MS_BUSY; + BX_FD_THIS s.main_status_reg |= FD_MS_BUSY; // time to read one sector at 300 rpm sector_time = 200000 / BX_FD_THIS s.media[drive].sectors_per_track; bx_pc_system.activate_timer(BX_FD_THIS s.floppy_timer_index, sector_time , 0); + BX_DEBUG(("floppy_command(): timer activated for floppy read")); } else if ((BX_FD_THIS s.command[0] & 0x7f) == 0x45) { // write - /* data reg not ready, controller busy */ - BX_FD_THIS s.main_status_reg = FD_MS_BUSY; - DEV_dma_set_drq(FLOPPY_DMA_CHAN, 1); + BX_FD_THIS s.main_status_reg |= FD_MS_BUSY; + if (non_dma()) { + BX_DEBUG(("floppy_command(): implement non-DMA floppy write"));; + } else { + /* data reg not ready, controller busy */ + DEV_dma_set_drq(FLOPPY_DMA_CHAN, 1); + } } else { BX_PANIC(("floppy_command(): unknown read/write command")); return; @@ -1066,6 +1106,7 @@ void bx_floppy_ctrl_c::floppy_xfer(Bit8u drive, Bit32u offset, Bit8u *buffer, Bit32u bytes, Bit8u direction) { + BX_DEBUG(("floppy_xfer() starting")); int ret = 0; if (BX_FD_THIS s.device_type[drive] == FDRIVE_NONE) @@ -1182,7 +1223,7 @@ void bx_floppy_ctrl_c::timer() { Bit8u drive, motor_on; - + BX_DEBUG(("timer() starting")); drive = BX_FD_THIS s.DOR & 0x03; switch (BX_FD_THIS s.pending_command) { case 0x07: // recal @@ -1224,7 +1265,11 @@ enter_result_phase(); } else { // transfer next sector - DEV_dma_set_drq(FLOPPY_DMA_CHAN, 1); + if (non_dma()) { + BX_DEBUG(("timer(): implement non-DMA floppy write"));; + } else { + DEV_dma_set_drq(FLOPPY_DMA_CHAN, 1); + } } break; @@ -1233,7 +1278,13 @@ case 0xc6: case 0xe6: // transfer next sector - DEV_dma_set_drq(FLOPPY_DMA_CHAN, 1); + if (non_dma()) { + BX_DEBUG(("timer(): implement non-DMA floppy read"));; + BX_FD_THIS s.main_status_reg &= ~FD_MS_BUSY; + BX_FD_THIS s.main_status_reg |= FD_MS_MRQ | FD_MS_DIO; + } else { + DEV_dma_set_drq(FLOPPY_DMA_CHAN, 1); + } break; case 0x4d: /* format track */ @@ -1242,8 +1293,12 @@ BX_FD_THIS s.status_reg0 = (BX_FD_THIS s.head[drive] << 2) | drive; enter_result_phase(); } else { - // transfer next sector - DEV_dma_set_drq(FLOPPY_DMA_CHAN, 1); + if (non_dma()) { + BX_DEBUG(("timer(): implement non-DMA floppy format"));; + } else { + // transfer next sector + DEV_dma_set_drq(FLOPPY_DMA_CHAN, 1); + } } break; @@ -1267,21 +1322,26 @@ void bx_floppy_ctrl_c::dma_write(Bit8u *data_byte) { // A DMA write is from I/O to Memory - // We need to return then next data byte from the floppy buffer + // We need to return the next data byte from the floppy buffer // to be transfered via the DMA to memory. (read block from floppy) + Bit8u drive; + drive = BX_FD_THIS s.DOR & 0x03; + /* + BX_DEBUG(("dma_write() starting, D %d, S %d, H %d B %d", + drive, BX_FD_THIS s.sector[drive], + BX_FD_THIS s.head[drive], BX_FD_THIS s.floppy_buffer_index)); + */ *data_byte = BX_FD_THIS s.floppy_buffer[BX_FD_THIS s.floppy_buffer_index++]; - BX_FD_THIS s.TC = DEV_dma_get_tc(); + BX_FD_THIS s.TC = get_tc(); if ((BX_FD_THIS s.floppy_buffer_index >= 512) || (BX_FD_THIS s.TC)) { - Bit8u drive; - - drive = BX_FD_THIS s.DOR & 0x03; if (BX_FD_THIS s.floppy_buffer_index >= 512) { increment_sector(); // increment to next sector before retrieving next one BX_FD_THIS s.floppy_buffer_index = 0; } if (BX_FD_THIS s.TC) { // Terminal Count line, done + BX_DEBUG(("dma_write(): end of data transfer")); BX_FD_THIS s.status_reg0 = (BX_FD_THIS s.head[drive] << 2) | drive; BX_FD_THIS s.status_reg1 = 0; BX_FD_THIS s.status_reg2 = 0; @@ -1295,12 +1355,15 @@ BX_INFO((" sector = %u", (unsigned) BX_FD_THIS s.sector[drive])); } - DEV_dma_set_drq(FLOPPY_DMA_CHAN, 0); + if (!(non_dma())) { + } else { + DEV_dma_set_drq(FLOPPY_DMA_CHAN, 0); + } enter_result_phase(); } else { // more data to transfer Bit32u logical_sector, sector_time; - // original assumed all floppies had two sides...now it does not *delete this comment line* + // do not assume that all floppies have two sides logical_sector = (BX_FD_THIS s.cylinder[drive] * BX_FD_THIS s.media[drive].heads * BX_FD_THIS s.media[drive].sectors_per_track) + (BX_FD_THIS s.head[drive] * @@ -1309,11 +1372,14 @@ floppy_xfer(drive, logical_sector*512, BX_FD_THIS s.floppy_buffer, 512, FROM_FLOPPY); - DEV_dma_set_drq(FLOPPY_DMA_CHAN, 0); + if (!(non_dma())) { + DEV_dma_set_drq(FLOPPY_DMA_CHAN, 0); + } // time to read one sector at 300 rpm sector_time = 200000 / BX_FD_THIS s.media[drive].sectors_per_track; bx_pc_system.activate_timer(BX_FD_THIS s.floppy_timer_index, sector_time , 0); + BX_DEBUG(("dma_write(): timer activated for floppy read")); } } } @@ -1327,8 +1393,8 @@ Bit8u drive; Bit32u logical_sector, sector_time; - BX_FD_THIS s.TC = DEV_dma_get_tc(); drive = BX_FD_THIS s.DOR & 0x03; + BX_FD_THIS s.TC = get_tc(); if (BX_FD_THIS s.pending_command == 0x4d) { // format track in progress BX_FD_THIS s.format_count--; switch (3 - (BX_FD_THIS s.format_count & 0x03)) { @@ -1355,11 +1421,14 @@ (BX_FD_THIS s.sector[drive] - 1); floppy_xfer(drive, logical_sector*512, BX_FD_THIS s.floppy_buffer, 512, TO_FLOPPY); - DEV_dma_set_drq(FLOPPY_DMA_CHAN, 0); + if (!(non_dma())) { + DEV_dma_set_drq(FLOPPY_DMA_CHAN, 0); + } // time to write one sector at 300 rpm sector_time = 200000 / BX_FD_THIS s.media[drive].sectors_per_track; bx_pc_system.activate_timer(BX_FD_THIS s.floppy_timer_index, sector_time , 0); + BX_DEBUG(("dma_read(): timer activated for sector format")); break; } } else { // write normal data @@ -1385,11 +1454,14 @@ 512, TO_FLOPPY); increment_sector(); // increment to next sector after writing current one BX_FD_THIS s.floppy_buffer_index = 0; - DEV_dma_set_drq(FLOPPY_DMA_CHAN, 0); + if (!(non_dma())) { + DEV_dma_set_drq(FLOPPY_DMA_CHAN, 0); + } // time to write one sector at 300 rpm sector_time = 200000 / BX_FD_THIS s.media[drive].sectors_per_track; bx_pc_system.activate_timer(BX_FD_THIS s.floppy_timer_index, sector_time , 0); + BX_DEBUG(("dma_read(): timer activated for sector write")); } } } @@ -1778,6 +1850,7 @@ void bx_floppy_ctrl_c::enter_result_phase(void) { + BX_DEBUG(("enter_result_phase() starting")); Bit8u drive; unsigned i; @@ -1785,7 +1858,7 @@ /* these are always the same */ BX_FD_THIS s.result_index = 0; - BX_FD_THIS s.main_status_reg &= 0x0f; // leave drive status untouched + reset_status(); BX_FD_THIS s.main_status_reg |= FD_MS_MRQ | FD_MS_DIO | FD_MS_BUSY; /* invalid command */ @@ -1811,7 +1884,7 @@ BX_FD_THIS s.result[i] = BX_FD_THIS s.cylinder[i]; } BX_FD_THIS s.result[4] = (BX_FD_THIS s.SRT << 4) | BX_FD_THIS s.HUT; - BX_FD_THIS s.result[5] = (BX_FD_THIS s.HLT << 1) | BX_FD_THIS s.non_dma; + BX_FD_THIS s.result[5] = (BX_FD_THIS s.HLT << 1) | non_dma(); BX_FD_THIS s.result[6] = BX_FD_THIS s.eot[drive]; BX_FD_THIS s.result[7] = (BX_FD_THIS s.lock << 7) | (BX_FD_THIS s.perp_mode & 0x7f); BX_FD_THIS s.result[8] = BX_FD_THIS s.config; @@ -1858,8 +1931,9 @@ void bx_floppy_ctrl_c::enter_idle_phase(void) { - BX_FD_THIS s.main_status_reg &= 0x0f; // leave drive status untouched - BX_FD_THIS s.main_status_reg |= FD_MS_MRQ; // data register ready + BX_DEBUG(("enter_idle_phase() starting")); + reset_status(); + BX_FD_THIS s.main_status_reg |= FD_MS_MRQ; // ready to receive BX_FD_THIS s.command_complete = 1; /* waiting for new command */ BX_FD_THIS s.command_index = 0; @@ -1890,3 +1964,52 @@ if (BX_FD_THIS s.media_present[drive]) BX_FD_THIS s.DIR[drive] &= ~0x80; } + +bx_bool bx_floppy_ctrl_c::non_dma(void) +{ + return ((BX_FD_THIS s.main_status_reg & FD_MS_NDMA) > 0); +} + +void bx_floppy_ctrl_c::reset_status(void) +{ + int not_using_dma = BX_FD_THIS s.main_status_reg & FD_MS_NDMA; + BX_FD_THIS s.main_status_reg &= FD_MS_ACTIVEBITS | not_using_dma; +} + +void bx_floppy_ctrl_c::reset_all_status(void) +{ + int not_using_dma = BX_FD_THIS s.main_status_reg & FD_MS_NDMA; + BX_FD_THIS s.main_status_reg = not_using_dma; +} + +bx_bool bx_floppy_ctrl_c::get_tc(void) +{ + Bit8u drive; + bool terminal_count; + if (non_dma()) { + drive = BX_FD_THIS s.DOR & 0x03; + /* figure out if we've sent all the data, in non-DMA mode + /* the drive stays on the same cylinder for a read or write, so that's + /* not going to be an issue. EOT stands for the last sector to be I/Od. + /* it does all the head 0 sectors first, then the second if any. + /* now, regarding reaching the end of the sector... + /* == 512 would make it more precise, allowing one to spot bugs... + /* >= 512 makes it more robust, but allows for sloppy code... + /* pick your poison? + /* note: byte and head are 0-based; eot, sector, and heads are 1-based. /* + // comment out the verbose debugging when it works + /* + BX_DEBUG(("get_tc(): eot=%d, sector=%d, byte=%d head=%d, heads=%d", + BX_FD_THIS s.eot[drive], BX_FD_THIS s.sector[drive], + BX_FD_THIS s.floppy_buffer_index, BX_FD_THIS s.head[drive], + BX_FD_THIS s.media[drive].heads)); + */ + terminal_count = (BX_FD_THIS s.floppy_buffer_index == 512 && + BX_FD_THIS s.sector[drive] == BX_FD_THIS s.eot[drive]) && + BX_FD_THIS s.head[drive] == BX_FD_THIS s.media[drive].heads - 1; + } else { + terminal_count = DEV_dma_get_tc(); + } + //if (terminal_count) BX_DEBUG(("get_tc(): terminal count reached")); + return terminal_count; +} Index: iodev/floppy.h =================================================================== RCS file: /cvsroot/bochs/bochs/iodev/floppy.h,v retrieving revision 1.29 diff -u -r1.29 floppy.h --- iodev/floppy.h 27 May 2006 15:54:48 -0000 1.29 +++ iodev/floppy.h 20 Nov 2006 23:07:14 -0000 @@ -151,6 +151,10 @@ BX_FD_SMF void enter_result_phase(void); BX_FD_SMF Bit32u calculate_step_delay(Bit8u drive, Bit8u new_cylinder); BX_FD_SMF void reset_changeline(void); + BX_FD_SMF bx_bool non_dma(void); + BX_FD_SMF void reset_status(void); + BX_FD_SMF void reset_all_status(void); + BX_FD_SMF bx_bool get_tc(void); static void timer_handler(void *); public: