DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/hardware/floppy.cpp
00001 /*
00002  * Floppy controller emulation for DOSBox-X
00003  * (C) 2012 Jonathan Campbell
00004 
00005  * [insert open source license here]
00006  */
00007 
00008 #if defined(_MSC_VER)
00009 # pragma warning(disable:4244) /* const fmath::local::uint64_t to double possible loss of data */
00010 #endif
00011 
00012 // largest sector size supported here. Size code represents size as 2 << (7 + code) i.e. code == 2 is 2 << 9 = 512 bytes
00013 #define FLOPPY_MAX_SECTOR_SIZE              (2048u)
00014 #define FLOPPY_MAX_SECTOR_SIZE_SZCODE       (11u/*2^11=2048*/ - 7u)
00015 
00016 #include <math.h>
00017 #include <assert.h>
00018 #include "dosbox.h"
00019 #include "inout.h"
00020 #include "pic.h"
00021 #include "mem.h"
00022 #include "cpu.h"
00023 #include "dma.h"
00024 #include "ide.h"
00025 #include "mixer.h"
00026 #include "timer.h"
00027 #include "setup.h"
00028 #include "control.h"
00029 #include "callback.h"
00030 #include "bios_disk.h"
00031 
00032 #ifdef _MSC_VER
00033 # define MIN(a,b) ((a) < (b) ? (a) : (b))
00034 #else
00035 # define MIN(a,b) std::min(a,b)
00036 #endif
00037 
00038 #define MAX_FLOPPY_CONTROLLERS 1
00039 
00040 static unsigned char init_floppy = 0;
00041 
00042 class FloppyController;
00043 
00044 class FloppyDevice {
00045 public:
00046         FloppyController *controller = NULL;
00047 public:
00048         unsigned char current_track;
00049         bool select,motor;
00050         bool track0;
00051 public:
00052         int             int13_disk;
00053 public:
00054         FloppyDevice(FloppyController *c);
00055         void set_select(bool enable);   /* set selection on/off */
00056         void set_motor(bool enable);    /* set motor on/off */
00057         void motor_step(int dir);
00058         imageDisk *getImage();
00059         virtual ~FloppyDevice();
00060         double floppy_image_motor_position();
00061 };
00062 
00063 class FloppyController:public Module_base{
00064 public:
00065         int IRQ;
00066         int DMA;
00067         unsigned short base_io;
00068         unsigned char interface_index;
00069         IO_ReadHandleObject ReadHandler[8];
00070         IO_WriteHandleObject WriteHandler[8];
00071         uint8_t digital_output_register;
00072         bool int13fakev86io;            /* on certain INT 13h calls in virtual 8086 mode, trigger fake CPU I/O traps */
00073         bool instant_mode;              /* make floppy operations instantaneous if true */
00074         bool data_register_ready;       /* 0x3F4 bit 7 */
00075         bool data_read_expected;        /* 0x3F4 bit 6 (DIO) if set CPU is expected to read from the controller */
00076         bool non_dma_mode;              /* 0x3F4 bit 5 (NDMA) */
00077         bool busy_status;               /* 0x3F4 bit 4 (BUSY). By "busy" the floppy controller is in the middle of an instruction */
00078         bool positioning[4];            /* 0x3F4 bit 0-3 floppy A...D in positioning mode */
00079         bool irq_pending;
00080         bool register_pnp;
00081 /* FDC internal registers */
00082         uint8_t ST[4];                  /* ST0..ST3 */
00083     uint8_t current_cylinder[4] = {};
00084 /* buffers */
00085     uint8_t in_cmd[16] = {};
00086         uint8_t in_cmd_len;
00087         uint8_t in_cmd_pos;
00088     uint8_t out_res[16] = {};
00089         uint8_t out_res_len;
00090         uint8_t out_res_pos;
00091         unsigned int motor_steps;
00092         int motor_dir;
00093         float fdc_motor_step_delay;
00094         bool in_cmd_state;
00095         bool out_res_state;
00096 public:
00097     void register_isapnp();
00098         bool dma_enabled();
00099         bool irq_enabled();
00100     bool drive_motor_on(unsigned char index);
00101         int drive_selected();
00102         void reset_cmd();
00103         void reset_res();
00104         void reset_io();
00105         void update_ST3();
00106         uint8_t fdc_data_read();
00107         void fdc_data_write(uint8_t b);
00108         void prepare_res_phase(uint8_t len);
00109         void on_dor_change(unsigned char b);
00110         void invalid_command_code();
00111         void on_fdc_in_command();
00112         void on_reset();
00113 public:
00114         DmaChannel* dma;
00115         FloppyDevice* device[4];        /* Floppy devices */
00116 public:
00117         FloppyController(Section* configuration,unsigned char index);
00118         void install_io_port();
00119         void raise_irq();
00120         void lower_irq();
00121         ~FloppyController();
00122 };
00123 
00124 static FloppyController* floppycontroller[MAX_FLOPPY_CONTROLLERS]={NULL};
00125 
00126 bool FDC_AssignINT13Disk(unsigned char drv) {
00127         if (drv >= 2) return false;
00128         FloppyController *fdc = floppycontroller[0];
00129         if (fdc == NULL) return false;
00130         FloppyDevice *dev = fdc->device[drv];
00131 
00132         if (dev != NULL) {
00133                 /* sorry. move it aside */
00134                 delete dev;
00135                 fdc->device[drv] = NULL;
00136         }
00137 
00138         dev = fdc->device[drv] = new FloppyDevice(fdc);
00139         if (dev == NULL) return false;
00140         dev->int13_disk = drv;
00141         dev->set_select(fdc->drive_selected() == drv);
00142 
00143     if (IS_PC98_ARCH) {
00144         // HACK: Enable motor by default, until motor enable port 0xBE is implemented
00145         dev->set_motor(true);
00146     }
00147 
00148         LOG_MSG("FDC: Primary controller, drive %u assigned to INT 13h drive %u",drv,drv);
00149         return true;
00150 }
00151 
00152 bool FDC_UnassignINT13Disk(unsigned char drv) {
00153         if (drv >= 2) return false;
00154         FloppyController *fdc = floppycontroller[0];
00155         if (fdc == NULL) return false;
00156         FloppyDevice *dev = fdc->device[drv];
00157 
00158         if (dev != NULL) {
00159                 /* sorry. move it aside */
00160                 delete dev;
00161                 fdc->device[drv] = NULL;
00162         }
00163 
00164         LOG_MSG("FDC: Primary controller, drive %u unassigned from INT 13h drive %u",drv,drv);
00165         return true;
00166 }
00167 
00168 static void fdc_baseio98_w(Bitu port,Bitu val,Bitu iolen);
00169 static Bitu fdc_baseio98_r(Bitu port,Bitu iolen);
00170 static void fdc_baseio_w(Bitu port,Bitu val,Bitu iolen);
00171 static Bitu fdc_baseio_r(Bitu port,Bitu iolen);
00172 
00173 void FDC_MotorStep(Bitu idx/*which IDE controller*/) {
00174         FloppyController *fdc;
00175         FloppyDevice *dev;
00176         int devidx;
00177 
00178         if (idx >= MAX_FLOPPY_CONTROLLERS) return;
00179         fdc = floppycontroller[idx];
00180         if (fdc == NULL) return;
00181 
00182         devidx = fdc->drive_selected()&3;
00183         dev = fdc->device[devidx];
00184 
00185 #if 0
00186         LOG_MSG("FDC: motor step. if=%u dev=%u rem=%u dir=%d current=%u\n",
00187                 (int)idx,(int)devidx,(int)fdc->motor_steps,(int)fdc->motor_dir,(int)fdc->current_cylinder[devidx]);
00188 #endif
00189 
00190         if (dev != NULL && dev->track0 && fdc->motor_dir < 0) {
00191                 fdc->motor_steps = 0;
00192                 fdc->current_cylinder[devidx] = 0;
00193         }
00194 
00195     if (fdc->motor_steps > 0) {
00196         fdc->motor_steps--;
00197         if ((fdc->motor_dir < 0 && fdc->current_cylinder[devidx] != 0x00) ||
00198             (fdc->motor_dir > 0 && fdc->current_cylinder[devidx] != 0xFF)) {
00199             fdc->current_cylinder[devidx] += fdc->motor_dir;
00200         }
00201 
00202         if (dev != NULL) {
00203             dev->motor_step(fdc->motor_dir);
00204             if (dev->track0) {
00205                 fdc->motor_steps = 0;
00206                 fdc->current_cylinder[devidx] = 0;
00207             }
00208         }
00209     }
00210 
00211         fdc->update_ST3();
00212         if (fdc->motor_steps != 0) {
00213                 /* step again */
00214                 PIC_AddEvent(FDC_MotorStep,fdc->fdc_motor_step_delay,idx);
00215         }
00216         else {
00217                 /* done stepping */
00218                 fdc->data_register_ready = 1;
00219                 fdc->busy_status = 0;
00220                 fdc->ST[0] &= 0x1F;
00221                 fdc->ST[0] |= 0x20; /* seek completed (bit 5) */
00222                 /* fire IRQ */
00223                 fdc->raise_irq();
00224                 /* no result phase */
00225                 fdc->reset_io();
00226 
00227                 /* real FDC's don't have this insight, but for DOSBox-X debugging... */
00228                 if (dev != NULL && dev->current_track != fdc->current_cylinder[devidx])
00229                         LOG_MSG("FDC: warning, after motor step FDC and drive are out of sync (fdc=%u drive=%u). OS or App needs to recalibrate\n",
00230                                 fdc->current_cylinder[devidx],dev->current_track);
00231 
00232 //              LOG_MSG("FDC: motor step finished. current=%u\n",(int)(fdc->current_cylinder[devidx]));
00233         }
00234 }
00235 
00236 double FloppyDevice::floppy_image_motor_position() {
00237         const unsigned int motor_rpm = 300;
00238 
00239         if (!motor) return 0.0;
00240         return fmod((PIC_FullIndex() * motor_rpm/*rotations/minute*/) / 1000/*convert to seconds from milliseconds*/ / 60/*rotations/min to rotations/sec*/,1.0);
00241 }
00242 
00243 imageDisk *FloppyDevice::getImage() {
00244         if (int13_disk >= 0)
00245                 return GetINT13FloppyDrive((unsigned char)int13_disk);
00246 
00247         return NULL;
00248 }
00249 
00250 void FloppyController::on_reset() {
00251         /* TODO: cancel DOSBox events corresponding to read/seek/etc */
00252         PIC_RemoveSpecificEvents(FDC_MotorStep,interface_index);
00253         motor_dir = 0;
00254         motor_steps = 0;
00255         for (size_t i=0;i < 4;i++) current_cylinder[i] = 0;
00256         busy_status = 0;
00257         ST[0] &= 0x3F;
00258         reset_io();
00259         lower_irq();
00260 }
00261 
00262 FloppyDevice::~FloppyDevice() {
00263 }
00264 
00265 FloppyDevice::FloppyDevice(FloppyController *c) {
00266     (void)c;//UNUSED
00267         motor = select = false;
00268         current_track = 0;
00269         int13_disk = -1;
00270         track0 = false;
00271 }
00272 
00273 void FloppyDevice::set_select(bool enable) {
00274         select = enable;
00275 }
00276 
00277 void FloppyDevice::set_motor(bool enable) {
00278         motor = enable;
00279 }
00280 
00281 void FloppyDevice::motor_step(int dir) {
00282         current_track += dir;
00283 //      if (current_track < 0) current_track = 0;
00284         if (current_track > 84) current_track = 84;
00285         track0 = (current_track == 0);
00286 }
00287 
00288 bool FloppyController::drive_motor_on(unsigned char index) {
00289     if (index < 4) return !!((digital_output_register >> (4u + index)) & 1);
00290     return false;
00291 }
00292 
00293 int FloppyController::drive_selected() {
00294         return (digital_output_register & 3);
00295 }
00296 
00297 bool FloppyController::dma_enabled() {
00298         return (digital_output_register & 0x08); /* bit 3 of DOR controls DMA/IRQ enable */
00299 }
00300 
00301 bool FloppyController::irq_enabled() {
00302     /* IRQ seems to be enabled, always, on PC-98. There does not seem to be an enable bit. */
00303     if (IS_PC98_ARCH) return true;
00304 
00305         return (digital_output_register & 0x08); /* bit 3 of DOR controls DMA/IRQ enable */
00306 }
00307 
00308 static void FDC_Destroy(Section* sec) {
00309     (void)sec;//UNUSED
00310         for (unsigned int i=0;i < MAX_FLOPPY_CONTROLLERS;i++) {
00311                 if (floppycontroller[i] != NULL) {
00312                         delete floppycontroller[i];
00313                         floppycontroller[i] = NULL;
00314                 }
00315         }
00316 
00317         init_floppy = 0;
00318 }
00319 
00320 static void FDC_Init(Section* sec,unsigned char fdc_interface) {
00321         Section_prop *section=static_cast<Section_prop *>(sec);
00322 
00323         assert(fdc_interface < MAX_FLOPPY_CONTROLLERS);
00324 
00325         if (!section->Get_bool("enable"))
00326                 return;
00327 
00328         if (!init_floppy) {
00329                 AddExitFunction(AddExitFunctionFuncPair(FDC_Destroy));
00330                 init_floppy = 1;
00331         }
00332 
00333         LOG(LOG_MISC,LOG_DEBUG)("Initializing floppy controller interface %u",fdc_interface);
00334 
00335     {
00336         FloppyController *fdc = floppycontroller[fdc_interface] = new FloppyController(sec,fdc_interface);
00337         fdc->install_io_port();
00338 
00339                 PIC_SetIRQMask((unsigned int)(fdc->IRQ), false);
00340         }
00341 }
00342 
00343 void FDC_OnReset(Section *sec) {
00344     (void)sec;//UNUSED
00345         FDC_Init(control->GetSection("fdc, primary"),0);
00346 }
00347 
00348 void FDC_Primary_Init() {
00349         LOG(LOG_MISC,LOG_DEBUG)("Initializing floppy controller emulation");
00350 
00351         AddVMEventFunction(VM_EVENT_RESET,AddVMEventFunctionFuncPair(FDC_OnReset));
00352 }
00353 
00354 void FloppyController::update_ST3() {
00355         FloppyDevice *dev = device[drive_selected()&3];
00356 
00357         /* FIXME: Should assemble bits from FloppyDevice objects and their boolean "signal" variables */
00358         ST[3] =
00359                 0x20/*RDY*/ +
00360                 0x08/*DOUBLE-SIDED SIGNAL*/+
00361                 (drive_selected()&3);/*DRIVE SELECT*/
00362 
00363         if (dev != NULL)
00364                 ST[3] |= (dev->track0 ? 0x10 : 0)/*TRACK 0 signal from device*/;
00365 }
00366 
00367 void FloppyController::reset_io() {
00368         reset_cmd();
00369         reset_res();
00370         busy_status=0;
00371         data_read_expected=0;
00372 }
00373 
00374 void FloppyController::reset_cmd() {
00375         in_cmd_len=0;
00376         in_cmd_pos=0;
00377         in_cmd_state=false;
00378 }
00379 
00380 void FloppyController::reset_res() {
00381         out_res_len=0;
00382         out_res_pos=0;
00383         out_res_state=false;
00384 }
00385 
00386 void FloppyController::register_isapnp() {
00387         if (register_pnp && base_io > 0) {
00388                 unsigned char tmp[256];
00389                 unsigned int i;
00390 
00391                 const unsigned char h1[9] = {
00392                         ISAPNP_SYSDEV_HEADER(
00393                                 ISAPNP_ID('P','N','P',0x0,0x7,0x0,0x0), /* PNP0700 Generic floppy controller */
00394                                 ISAPNP_TYPE(0x01,0x02,0x00),            /* type: Mass Storage Device / Floppy / Generic */
00395                                 0x0001 | 0x0002)
00396                 };
00397 
00398                 i = 0;
00399                 memcpy(tmp+i,h1,9); i += 9;                     /* can't disable, can't configure */
00400                 /*----------allocated--------*/
00401                 tmp[i+0] = (8 << 3) | 7;                        /* IO resource */
00402                 tmp[i+1] = 0x01;                                /* 16-bit decode */
00403                 host_writew(tmp+i+2,base_io);                   /* min */
00404                 host_writew(tmp+i+4,base_io);                   /* max */
00405                 tmp[i+6] = 0x01;                                /* align */
00406                 tmp[i+7] = 0x06;                                /* length (FIXME: Emit as 7 unless we know IDE interface will not conflict) */
00407                 i += 7+1;
00408 
00409                 tmp[i+0] = (8 << 3) | 7;                        /* IO resource (FIXME: Don't emit this if we know IDE interface will take port 0x3F7) */
00410                 tmp[i+1] = 0x01;                                /* 16-bit decode */
00411                 host_writew(tmp+i+2,base_io+7);                 /* min */
00412                 host_writew(tmp+i+4,base_io+7);                 /* max */
00413                 tmp[i+6] = 0x01;                                /* align */
00414                 tmp[i+7] = 0x01;                                /* length */
00415                 i += 7+1;
00416 
00417                 if (IRQ > 0) {
00418                         tmp[i+0] = (4 << 3) | 3;                /* IRQ resource */
00419                         host_writew(tmp+i+1,1 << IRQ);
00420                         tmp[i+3] = 0x09;                        /* HTE=1 LTL=1 */
00421                         i += 3+1;
00422                 }
00423 
00424                 if (DMA >= 0) {
00425                         tmp[i+0] = (5 << 3) | 2;                /* IRQ resource */
00426                         tmp[i+1] = 1 << DMA;
00427                         tmp[i+2] = 0x00;                        /* 8-bit */
00428                         i += 2+1;
00429                 }
00430 
00431                 tmp[i+0] = 0x79;                                /* END TAG */
00432                 tmp[i+1] = 0x00;
00433                 i += 2;
00434                 /*-------------possible-----------*/
00435                 tmp[i+0] = 0x79;                                /* END TAG */
00436                 tmp[i+1] = 0x00;
00437                 i += 2;
00438                 /*-------------compatible---------*/
00439                 tmp[i+0] = 0x79;                                /* END TAG */
00440                 tmp[i+1] = 0x00;
00441                 i += 2;
00442 
00443                 if (!ISAPNP_RegisterSysDev(tmp,i))
00444                         LOG_MSG("ISAPNP register failed\n");
00445         }
00446 }
00447 
00448 FloppyController::FloppyController(Section* configuration,unsigned char index):Module_base(configuration){
00449         Section_prop * section=static_cast<Section_prop *>(configuration);
00450         int i;
00451 
00452         fdc_motor_step_delay = 400.0f / 80; /* FIXME: Based on 400ms seek time from track 0 to 80 */
00453         interface_index = index;
00454         data_register_ready = 1;
00455         data_read_expected = 0;
00456         non_dma_mode = 0;
00457         busy_status = 0;
00458         for (i=0;i < 4;i++) positioning[i] = false;
00459         for (i=0;i < 4;i++) ST[i] = 0x00;
00460     irq_pending = false;
00461     motor_steps = 0;
00462     motor_dir = 0;
00463         reset_io();
00464 
00465         digital_output_register = 0;
00466         device[0] = NULL;
00467         device[1] = NULL;
00468         device[2] = NULL;
00469         device[3] = NULL;
00470         base_io = 0;
00471         IRQ = -1;
00472         DMA = -1;
00473 
00474         update_ST3();
00475 
00476         int13fakev86io = section->Get_bool("int13fakev86io");
00477         instant_mode = section->Get_bool("instant mode");
00478         register_pnp = section->Get_bool("pnp");
00479 
00480         i = section->Get_int("irq");
00481         if (i > 0 && i <= 15) IRQ = i;
00482 
00483         i = section->Get_int("dma");
00484         if (i >= 0 && i <= 15) DMA = i;
00485 
00486         i = section->Get_hex("io");
00487         if (i >= 0x90 && i <= 0x3FF) base_io = i & ~7;
00488 
00489     if (IS_PC98_ARCH) {
00490         /* According to Neko Project II source code, and the Undocumented PC-98 reference:
00491          *
00492          * The primary controller at 0x90-0x94 is for 3.5" drives, uses IRQ 11 (INT42), and DMA channel 2.
00493          * The secondary controller at 0xC8-0xCC is for 5.25" drives, uses IRQ 10 (INT41), and DMA channel 3. */
00494         if (IRQ < 0) IRQ = (index == 1) ? 10/*INT41*/ : 11/*INT42*/;
00495         if (DMA < 0) DMA = (index == 1) ? 3 : 2;
00496 
00497         if (base_io == 0) {
00498             if (index == 0) base_io = 0x90;
00499             if (index == 1) base_io = 0xC8;
00500         }
00501     }
00502     else {
00503         if (IRQ < 0) IRQ = 6;
00504         if (DMA < 0) DMA = 2;
00505 
00506         if (base_io == 0) {
00507             if (index == 0) base_io = 0x3F0;
00508             if (index == 1) base_io = 0x370;
00509         }
00510     }
00511 
00512         dma = GetDMAChannel(DMA);
00513 }
00514 
00515 void FloppyController::install_io_port(){
00516         if (base_io != 0) {
00517                 LOG_MSG("FDC installing to io=%03xh IRQ=%d DMA=%d\n",base_io,IRQ,DMA);
00518         if (IS_PC98_ARCH) {
00519             WriteHandler[0].Install(base_io+0,fdc_baseio98_w,IO_MA);    // 0x90 / 0xC8
00520             ReadHandler[0].Install(base_io+0,fdc_baseio98_r,IO_MA);     // 0x90 / 0xC8
00521             WriteHandler[1].Install(base_io+2,fdc_baseio98_w,IO_MA);    // 0x92 / 0xCA
00522             ReadHandler[1].Install(base_io+2,fdc_baseio98_r,IO_MA);     // 0x92 / 0xCA
00523             WriteHandler[2].Install(base_io+4,fdc_baseio98_w,IO_MA);    // 0x94 / 0xCC
00524             ReadHandler[2].Install(base_io+4,fdc_baseio98_r,IO_MA);     // 0x94 / 0xCC
00525         }
00526         else {
00527             for (unsigned int i=0;i < 8;i++) {
00528                 if (i != 6) { /* does not use port 0x3F6 */
00529                     WriteHandler[i].Install(base_io+i,fdc_baseio_w,IO_MA);
00530                     ReadHandler[i].Install(base_io+i,fdc_baseio_r,IO_MA);
00531                 }
00532             }
00533         }
00534         }
00535 }
00536 
00537 FloppyController::~FloppyController() {
00538         unsigned int i;
00539 
00540         for (i=0;i < 4;i++) {
00541                 if (device[i] != NULL) {
00542                         delete device[i];
00543                         device[i] = NULL;
00544                 }
00545         }
00546 }
00547 
00548 FloppyController *match_fdc_controller(Bitu port) {
00549         unsigned int i;
00550 
00551         for (i=0;i < MAX_FLOPPY_CONTROLLERS;i++) {
00552                 FloppyController *fdc = floppycontroller[i];
00553                 if (fdc == NULL) continue;
00554                 if (fdc->base_io != 0U && fdc->base_io == (port&0xFFF8U)) return fdc;
00555         }
00556 
00557         return NULL;
00558 }
00559 
00560 /* when DOR port is written */
00561 void FloppyController::on_dor_change(unsigned char b) {
00562         unsigned char chg = b ^ digital_output_register;
00563 
00564         /* !RESET line */
00565         if (chg & 0x04) {
00566                 if (!(b&0x04)) { /* if bit 2 == 0 s/w is resetting the controller */
00567                         LOG_MSG("FDC: Reset\n");
00568                         on_reset();
00569                 }
00570                 else {
00571                         LOG_MSG("FDC: Reset complete\n");
00572                         /* resetting the FDC on real hardware apparently fires another IRQ */
00573                         raise_irq();
00574                 }
00575         }
00576 
00577         /* drive select */
00578         if (chg & 0x03) {
00579                 int o,n;
00580 
00581                 o = drive_selected();
00582                 n = b & 3;
00583                 if (o >= 0) {
00584                         LOG_MSG("FDC: Drive select from %c to %c\n",o+'A',n+'A');
00585                         if (device[o] != NULL) device[o]->set_select(false);
00586                         if (device[n] != NULL) device[n]->set_select(true);
00587                         update_ST3();
00588                 }
00589         }
00590 
00591         /* DMA/IRQ enable */
00592         if (chg & 0x08 && IRQ >= 0) {
00593                 if ((b&0x08) && irq_pending) PIC_ActivateIRQ((unsigned int)IRQ);
00594                 else PIC_DeActivateIRQ((unsigned int)IRQ);
00595         }
00596 
00597         /* drive motors */
00598         if (chg & 0xF0) {
00599                 LOG_MSG("FDC: Motor control {A,B,C,D} = {%u,%u,%u,%u}\n",
00600                         (b>>4)&1,(b>>5)&1,(b>>6)&1,(b>>7)&1);
00601 
00602                 for (unsigned int i=0;i < 4;i++) {
00603                         if (device[i] != NULL) device[i]->set_motor((b&(0x10<<i))?true:false);
00604                 }
00605         }
00606 
00607         digital_output_register = b;
00608 }
00609 
00610 /* IDE code needs to know if port 3F7 will be taken by FDC emulation */
00611 bool fdc_takes_port_3F7() {
00612         return (match_fdc_controller(0x3F7) != NULL);
00613 }
00614 
00615 void FloppyController::prepare_res_phase(uint8_t len) {
00616         data_read_expected = 1;
00617         out_res_pos = 0;
00618         out_res_len = len;
00619         out_res_state = true;
00620 }
00621 
00622 void FloppyController::invalid_command_code() {
00623         reset_res();
00624         prepare_res_phase(1);
00625         out_res[0] = ST[0] = 0x80;
00626 }
00627 
00628 uint8_t FloppyController::fdc_data_read() {
00629     // FIXME: It's unclear whether or not this is correct behavior.
00630     //        IBM compatible Pentium motherboards might have FDCs that
00631     //        leave the busy bit set until the response has been read, from my experience.
00632     //        On the other hand some PC-98 booter games seem to assume that busy will be
00633     //        cleared when read finishes and will not read response until busy bit clears
00634     //        (Arsys Star Cruiser).
00635     //
00636     //        This is a compromise until further study.
00637     if (busy_status || IS_PC98_ARCH) {
00638                 if (out_res_state) {
00639                         if (out_res_pos < out_res_len) {
00640                                 uint8_t b = out_res[out_res_pos++];
00641                                 if (out_res_pos >= out_res_len) reset_io();
00642                                 return b;
00643                         }
00644                         else {
00645                                 reset_io();
00646                         }
00647                 }
00648                 else {
00649                         reset_io();
00650                 }
00651         }
00652 
00653         return 0xFF;
00654 }
00655 
00656 void FloppyController::on_fdc_in_command() {
00657         imageDisk *image=NULL;
00658         FloppyDevice *dev;
00659         int devidx;
00660 
00661         in_cmd_state = false;
00662         devidx = drive_selected();
00663         dev = device[devidx];
00664         if (dev != NULL) image = dev->getImage();
00665 
00666         switch (in_cmd[0]&0x1F) {
00667                 case 0x0A:
00668                         break;
00669                 default:
00670                         LOG_MSG("FDC: Command len=%u %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
00671                                 in_cmd_len,
00672                                 in_cmd[0],in_cmd[1],in_cmd[2],in_cmd[3],in_cmd[4],
00673                                 in_cmd[5],in_cmd[6],in_cmd[7],in_cmd[8],in_cmd[9]);
00674                         break;
00675         }
00676 
00677         switch (in_cmd[0]&0x1F) {
00678                 case 0x03: /* Specify */
00679                         /*     |   7    6    5    4    3    2    1    0
00680                          * ----+------------------------------------------
00681                          *   0 |   0    0    0    0    0    0    1    1
00682                          *   1 |   <---- SRT ----->    <----- HUT ---->
00683                          *   2 |   <-------------- HLT ---------->   ND
00684                          * -----------------------------------------------
00685                          *   3     total
00686                          */
00687                         reset_res(); // TODO: Do something with this
00688                         reset_io();
00689                         break;
00690                 case 0x04: /* Check Drive Status */
00691                         /*     |   7    6    5    4    3    2    1    0
00692                          * ----+------------------------------------------
00693                          *   0 |               Register ST3
00694                          * -----------------------------------------------
00695                          *   1     total
00696                          */
00697                         reset_res();
00698                         prepare_res_phase(1);
00699                         out_res[0] = ST[3];
00700                         ST[0] = 0x00 | devidx;
00701                         break;
00702                 case 0x05: /* Write data (0101) */
00703                 case 0x09: /* Write deleted data (1001) */
00704                         /*     |   7    6    5    4    3    2    1    0
00705                          * ----+------------------------------------------
00706                          *   0 |               Register ST0
00707                          *   1 |               Register ST1
00708                          *   2 |               Register ST2
00709                          *   3 |             Logical cylinder
00710                          *   4 |               Logical head
00711                          *   5 |              Logical sector
00712                          *   6 |           Logical sector size
00713                          * -----------------------------------------------
00714                          *   7     total
00715                          */
00716                         /* must have a device present. must have an image. device motor and select must be enabled.
00717                          * current physical cylinder position must be within range of the image. request must have MFM bit set. */
00718                         dma = GetDMAChannel(DMA);
00719                         if (dev != NULL && dma != NULL && dev->motor && dev->select && image != NULL && (in_cmd[0]&0x40)/*MFM=1*/ &&
00720                                 current_cylinder[devidx] < image->cylinders && ((in_cmd[1]&4U)?1U:0U) <= image->heads &&
00721                                 ((in_cmd[1]&4U)?1U:0U) == in_cmd[3] && in_cmd[2] == current_cylinder[devidx] &&
00722                                 in_cmd[5] <= FLOPPY_MAX_SECTOR_SIZE_SZCODE && in_cmd[4] > 0U && in_cmd[4] <= image->sectors) {
00723                                 unsigned char sector[FLOPPY_MAX_SECTOR_SIZE];
00724                                 bool fail = false;
00725 
00726                 const unsigned int sector_size_bytes = (1u << (in_cmd[5]+7u));
00727                 assert(sector_size_bytes <= FLOPPY_MAX_SECTOR_SIZE);
00728 
00729                                 /* TODO: delay related to how long it takes for the disk to rotate around to the sector requested */
00730                                 reset_res();
00731                                 ST[0] = 0x00 | devidx;
00732 
00733                 // FIXME: Real IBM PC hardware (at least Pentium motherboard) behavior says that the FDC is too lazy
00734                 //        to clear/reset ST1/ST2 unless another error occurs.
00735                 //
00736                 //        PC-98 booter game Star Cruiser seems to expect these to zero out if no error.
00737                 //
00738                 //        Fix this compromise later when real behavior is determined.
00739                 if (IS_PC98_ARCH) {
00740                     ST[1] = 0;
00741                     ST[2] = 0;
00742                 }
00743 
00744                 out_res[3] = in_cmd[2];
00745                 out_res[4] = in_cmd[3];
00746                 out_res[5] = in_cmd[4];         /* the sector passing under the head at this time */
00747                 {
00748                     unsigned int sz = (unsigned int)image->sector_size;
00749                     out_res[6] = 0;                         /* 128 << 2 == 512 bytes/sector */
00750                     while (sz > 128u && out_res[6] < FLOPPY_MAX_SECTOR_SIZE_SZCODE) {
00751                         out_res[6]++;
00752                         sz >>= 1u;
00753                     }
00754                 }
00755 
00756                 if (dma->tcount) {
00757                     LOG(LOG_MISC,LOG_DEBUG)("FDC: DMA terminal count at write start. Resetting terminal count. Hope a new count was written!");
00758                     dma->tcount = false;
00759                 }
00760 
00761                                 while (!fail && !dma->tcount/*terminal count*/) {
00762                                         /* if we're reading past the track, fail */
00763                                         if (in_cmd[4] > image->sectors) {
00764                                                 fail = true;
00765                                                 break;
00766                                         }
00767 
00768                                         /* DMA transfer */
00769                                         dma->Register_Callback(0);
00770                                         if (dma->Read(sector_size_bytes,sector) != sector_size_bytes) {
00771                         LOG(LOG_MISC,LOG_DEBUG)("FDC: DMA read failed");
00772                         fail = true;
00773                         break;
00774                     }
00775 
00776                                         /* write sector */
00777                                         Bit8u err = image->Write_Sector(in_cmd[3]/*head*/,in_cmd[2]/*cylinder*/,in_cmd[4]/*sector*/,sector,sector_size_bytes);
00778                                         if (err != 0x00) {
00779                                                 fail = true;
00780                                                 break;
00781                                         }
00782 
00783                                         /* if we're at the last sector of the track according to program, then stop */
00784                                         if (in_cmd[4] == in_cmd[6]) break;
00785 
00786                     /* next sector (TODO "multi-track" mode) */
00787                     if (in_cmd[4] == image->sectors)
00788                         in_cmd[4] = 1;
00789                     else
00790                         in_cmd[4]++;
00791                                 }
00792 
00793                                 if (fail) {
00794                                         ST[0] = (ST[0] & 0x3F) | 0x80;
00795                                         ST[1] = (1 << 0)/*missing address mark*/ | (1 << 2)/*no data*/;
00796                                         ST[2] = (1 << 0)/*missing data address mark*/;
00797                                 }
00798                                 {
00799                                         prepare_res_phase(7);
00800                                         out_res[0] = ST[0];
00801                                         out_res[1] = ST[1];
00802                                         out_res[2] = ST[2];
00803                                 }
00804                         }
00805                         else {
00806                                 /* TODO: real floppy controllers will pause for up to 1/2 a second before erroring out */
00807                                 reset_res();
00808                                 ST[0] = (ST[0] & 0x1F) | 0x80;
00809                                 ST[1] = (1 << 0)/*missing address mark*/ | (1 << 2)/*no data*/;
00810                                 ST[2] = (1 << 0)/*missing data address mark*/;
00811 
00812                 prepare_res_phase(7);
00813                 out_res[0] = ST[0];
00814                 out_res[1] = ST[1];
00815                 out_res[2] = ST[2];
00816             }
00817                         raise_irq();
00818                         break;
00819                 case 0x06: /* Read data (0110) */
00820                         /*     |   7    6    5    4    3    2    1    0
00821                          * ----+------------------------------------------
00822                          *   0 |               Register ST0
00823                          *   1 |               Register ST1
00824                          *   2 |               Register ST2
00825                          *   3 |             Logical cylinder
00826                          *   4 |               Logical head
00827                          *   5 |              Logical sector
00828                          *   6 |           Logical sector size
00829                          * -----------------------------------------------
00830                          *   7     total
00831                          */
00832                         /* must have a device present. must have an image. device motor and select must be enabled.
00833                          * current physical cylinder position must be within range of the image. request must have MFM bit set.
00834              * In order to support copy-protected booter games (IBM PC or PC-98) the sector number is NOT range
00835              * limited in order to support games such as Star Cruiser that look for intentionally out of range
00836              * sector numbers. */
00837                         dma = GetDMAChannel(DMA);
00838                         if (dev != NULL && dma != NULL && dev->motor && dev->select && image != NULL && (in_cmd[0]&0x40)/*MFM=1*/ &&
00839                                 current_cylinder[devidx] < image->cylinders && ((in_cmd[1]&4U)?1U:0U) <= image->heads &&
00840                                 ((in_cmd[1]&4U)?1U:0U) == in_cmd[3] && in_cmd[2] == current_cylinder[devidx] &&
00841                                 in_cmd[5] <= FLOPPY_MAX_SECTOR_SIZE_SZCODE && in_cmd[4] > 0U) {
00842                                 unsigned char sector[FLOPPY_MAX_SECTOR_SIZE];
00843                                 bool fail = false;
00844 
00845                 const unsigned int sector_size_bytes = (1u << (in_cmd[5]+7u));
00846                 assert(sector_size_bytes <= FLOPPY_MAX_SECTOR_SIZE);
00847 
00848                                 /* TODO: delay related to how long it takes for the disk to rotate around to the sector requested */
00849                                 reset_res();
00850                                 ST[0] = 0x00 | devidx;
00851 
00852                 // FIXME: Real IBM PC hardware (at least Pentium motherboard) behavior says that the FDC is too lazy
00853                 //        to clear/reset ST1/ST2 unless another error occurs.
00854                 //
00855                 //        PC-98 booter game Star Cruiser seems to expect these to zero out if no error.
00856                 //
00857                 //        Fix this compromise later when real behavior is determined.
00858                 if (IS_PC98_ARCH) {
00859                     ST[1] = 0;
00860                     ST[2] = 0;
00861                 }
00862 
00863                 out_res[3] = in_cmd[2];
00864                 out_res[4] = in_cmd[3];
00865                 out_res[5] = in_cmd[4];         /* the sector passing under the head at this time */
00866                 {
00867                     unsigned int sz = (unsigned int)image->sector_size;
00868                     out_res[6] = 0;                         /* 128 << 2 == 512 bytes/sector */
00869                     while (sz > 128u && out_res[6] < FLOPPY_MAX_SECTOR_SIZE_SZCODE) {
00870                         out_res[6]++;
00871                         sz >>= 1u;
00872                     }
00873                 }
00874 
00875                 if (dma->tcount) {
00876                     LOG(LOG_MISC,LOG_DEBUG)("FDC: DMA terminal count at read start. Resetting terminal count. Hope a new count was written!");
00877                     dma->tcount = false;
00878                 }
00879 
00880                                 while (!fail && !dma->tcount/*terminal count*/) {
00881 //                  LOG_MSG("FDC: Read sector going to DMA 0x%x",(unsigned int)dma->pagebase + (unsigned int)dma->curraddr);
00882 
00883                                         /* read sector */
00884                                         Bit8u err = image->Read_Sector(in_cmd[3]/*head*/,in_cmd[2]/*cylinder*/,in_cmd[4]/*sector*/,sector,sector_size_bytes);
00885                                         if (err != 0x00) {
00886                                                 fail = true;
00887                                                 break;
00888                                         }
00889 
00890                                         /* DMA transfer */
00891                                         dma->Register_Callback(0);
00892                                         if (dma->Write(sector_size_bytes,sector) != sector_size_bytes) {
00893                         LOG(LOG_MISC,LOG_DEBUG)("FDC: DMA write failed during read");
00894                         fail = true;
00895                         break;
00896                     }
00897 
00898                                         /* if we're at the last sector of the track according to program, then stop */
00899                                         if (in_cmd[4] == in_cmd[6]) break;
00900 
00901                     /* next sector (TODO "multi-track" mode) */
00902                     if (in_cmd[4] == image->sectors)
00903                         in_cmd[4] = 1;
00904                     else
00905                         in_cmd[4]++;
00906                                 }
00907 
00908                                 if (fail) {
00909                                         ST[0] = (ST[0] & 0x3F) | 0x80;
00910                                         ST[1] = (1 << 0)/*missing address mark*/ | (1 << 2)/*no data*/;
00911                                         ST[2] = (1 << 0)/*missing data address mark*/;
00912                                 }
00913                                 {
00914                                         prepare_res_phase(7);
00915                                         out_res[0] = ST[0];
00916                                         out_res[1] = ST[1];
00917                                         out_res[2] = ST[2];
00918                                 }
00919                         }
00920                         else {
00921                                 /* TODO: real floppy controllers will pause for up to 1/2 a second before erroring out */
00922                                 reset_res();
00923                                 ST[0] = (ST[0] & 0x1F) | 0x80;
00924                                 ST[1] = (1 << 0)/*missing address mark*/ | (1 << 2)/*no data*/;
00925                                 ST[2] = (1 << 0)/*missing data address mark*/;
00926 
00927                 prepare_res_phase(7);
00928                 out_res[0] = ST[0];
00929                 out_res[1] = ST[1];
00930                 out_res[2] = ST[2];
00931             }
00932 
00933             // FIXME: It's unclear whether or not this is correct behavior.
00934             //        IBM compatible Pentium motherboards might have FDCs that
00935             //        leave the busy bit set until the response has been read, from my experience.
00936             //        On the other hand some PC-98 booter games seem to assume that busy will be
00937             //        cleared when read finishes and will not read response until busy bit clears
00938             //        (Arsys Star Cruiser).
00939             //
00940             //        This is a compromise until further study.
00941             if (IS_PC98_ARCH)
00942                 busy_status = 0;
00943 
00944                         raise_irq();
00945                         break;
00946                 case 0x07: /* Calibrate drive */
00947                         ST[0] = 0x20 | devidx;
00948                         if (instant_mode) {
00949                                 /* move head to track 0 */
00950                                 current_cylinder[devidx] = 0;
00951                                 /* fire IRQ */
00952                                 raise_irq();
00953                                 /* no result phase */
00954                                 reset_io();
00955                         }
00956                         else {
00957                                 /* delay due to stepping the head to the desired cylinder */
00958                                 motor_steps = 79; /* calibrate is said to max out at 79. motor step routine will STOP when drive sets track0 signal */
00959                                 motor_dir = -1; /* always step backwards */
00960 
00961                                 /* the command takes time to move the head */
00962                                 data_register_ready = 0;
00963                                 busy_status = 1;
00964 
00965                                 /* and make it happen */
00966                                 PIC_AddEvent(FDC_MotorStep,(motor_steps > 0 ? fdc_motor_step_delay : 0.1)/*ms*/,interface_index);
00967 
00968                                 /* return now */
00969                                 return;
00970                         }
00971                         break;
00972                 case 0x08: /* Check Interrupt Status */
00973                         /*     |   7    6    5    4    3    2    1    0
00974                          * ----+------------------------------------------
00975                          *   0 |               Register ST0
00976                          *   1 |              Current Cylinder
00977                          * -----------------------------------------------
00978                          *   2     total
00979                          */
00980                         if (irq_pending) {
00981                                 lower_irq(); /* doesn't cause IRQ, clears IRQ */
00982                                 reset_res();
00983                                 prepare_res_phase(2);
00984                                 out_res[0] = ST[0];
00985                                 out_res[1] = current_cylinder[devidx];
00986                         }
00987                         else {
00988                                 /* if no pending IRQ, signal error.
00989                                  * this is considered standard floppy controller behavior.
00990                                  * this also fixes an issue where Windows 3.1 QIC tape backup software like Norton Backup (Norton Desktop 3.0)
00991                                  * will "hang" Windows 3.1 polling the FDC in an endless loop if we don't return this error to say that no
00992                                  * more IRQs are pending. */
00993                                 reset_res();
00994                                 ST[0] = (ST[0] & 0x3F) | 0x80;
00995                                 out_res[0] = ST[0];
00996                                 prepare_res_phase(1);
00997                         }
00998                         break;
00999                 case 0x0A: /* Read ID */
01000                         /*     |   7    6    5    4    3    2    1    0
01001                          * ----+------------------------------------------
01002                          *   0 |               Register ST0
01003                          *   1 |               Register ST1
01004                          *   2 |               Register ST2
01005                          *   3 |             Logical cylinder
01006                          *   4 |               Logical head
01007                          *   5 |              Logical sector
01008                          *   6 |           Logical sector size
01009                          * -----------------------------------------------
01010                          *   7     total
01011                          */
01012                         /* must have a device present. must have an image. device motor and select must be enabled.
01013                          * current physical cylinder position must be within range of the image. request must have MFM bit set. */
01014             ST[0] &= ~0x20;
01015                         if (dev != NULL && dev->motor && dev->select && image != NULL && (in_cmd[0]&0x40)/*MFM=1*/ &&
01016                                 current_cylinder[devidx] < image->cylinders && ((in_cmd[1]&4U)?1U:0U) <= image->heads) {
01017                                 int ns = (int)floor(dev->floppy_image_motor_position() * image->sectors);
01018                                 /* TODO: minor delay to emulate time for one sector to pass under the head */
01019                                 reset_res();
01020                                 out_res[0] = ST[0];
01021                                 out_res[1] = ST[1];
01022                                 out_res[2] = ST[2];
01023                                 out_res[3] = current_cylinder[devidx];
01024                                 out_res[4] = ((in_cmd[1]&4)?1:0);
01025                                 out_res[5] = ns + 1;            /* the sector passing under the head at this time */
01026                 {
01027                     unsigned int sz = (unsigned int)image->sector_size;
01028                     out_res[6] = 0;                         /* 128 << 2 == 512 bytes/sector */
01029                     while (sz > 128u && out_res[6] < FLOPPY_MAX_SECTOR_SIZE_SZCODE) {
01030                         out_res[6]++;
01031                         sz >>= 1u;
01032                     }
01033                 }
01034                                 prepare_res_phase(7);
01035                         }
01036                         else {
01037                                 /* TODO: real floppy controllers will pause for up to 1/2 a second before erroring out */
01038                                 reset_res();
01039                                 ST[0] = (ST[0] & 0x3F) | 0x80;
01040                                 ST[1] = (1 << 0)/*missing address mark*/ | (1 << 2)/*no data*/;
01041                                 ST[2] = (1 << 0)/*missing data address mark*/;
01042                                 prepare_res_phase(1);
01043                                 out_res[0] = ST[0];
01044                         }
01045                         raise_irq();
01046                         break;
01047                 case 0x0C: /* Read deleted data (1100) */
01048                         /*     |   7    6    5    4    3    2    1    0
01049                          * ----+------------------------------------------
01050                          *   0 |               Register ST0
01051                          *   1 |               Register ST1
01052                          *   2 |               Register ST2
01053                          *   3 |             Logical cylinder
01054                          *   4 |               Logical head
01055                          *   5 |              Logical sector
01056                          *   6 |           Logical sector size
01057                          * -----------------------------------------------
01058                          *   7     total
01059                          */
01060                         /* the raw images used by DOSBox cannot represent "deleted sectors", so always fail */
01061                         reset_res();
01062                         ST[0] = (ST[0] & 0x1F) | 0x80;
01063                         ST[1] = (1 << 0)/*missing address mark*/ | (1 << 2)/*no data*/;
01064                         ST[2] = (1 << 0)/*missing data address mark*/;
01065                         prepare_res_phase(1);
01066                         break;
01067                 case 0x0E: /* Dump registers (response) */
01068                         /*     |   7    6    5    4    3    2    1    0
01069                          * ----+------------------------------------------
01070                          *   0 |                PCN-Drive 0
01071                          *   1 |                PCN-Drive 1
01072                          *   2 |                PCN-Drive 2
01073                          *   3 |                PCN-Drive 3
01074                          *   4 |   <----- SRT ---->    <----- HUT ---->
01075                          *   5 |   <------------ HLT ------------>   ND
01076                          *   6 |   <------------- SC/EOT ------------->
01077                          *   7 |  LOCK  0   D3   D2   D1   D0   GAP WGATE
01078                          *   8 |   0   EIS EFIFO POLL  <--- FIFOTHR -->
01079                          *   9 |                   PRETRK
01080                          * -----------------------------------------------
01081                          *  10     total
01082                          */
01083                         reset_res();
01084                         prepare_res_phase(10);
01085                         out_res[0] = current_cylinder[0];
01086                         out_res[1] = current_cylinder[1];
01087                         out_res[2] = current_cylinder[2];
01088                         out_res[3] = current_cylinder[3];
01089                         out_res[4] = 0x88;                      // FIXME
01090                         out_res[5] = 0x40;                      // FIXME
01091                         out_res[6] = 18;                        // FIXME
01092                         out_res[7] = 0;                         // FIXME
01093                         out_res[8] = 0x78;                      // FIXME
01094                         out_res[9] = 0x00;                      // FIXME
01095                         break;
01096                 case 0x0F: /* Seek Head */
01097                         ST[0] = 0x00 | drive_selected();
01098                         if (instant_mode) {
01099                                 /* move head to whatever track was wanted */
01100                                 current_cylinder[devidx] = in_cmd[2]; /* from 3rd byte of command */
01101                                 /* fire IRQ */
01102                                 raise_irq();
01103                                 /* no result phase */
01104                                 reset_io();
01105                         }
01106                         else {
01107                                 /* delay due to stepping the head to the desired cylinder */
01108                                 motor_steps = (unsigned int)abs((int)in_cmd[2] - (int)current_cylinder[devidx]);
01109                                 motor_dir = in_cmd[2] > current_cylinder[devidx] ? 1 : -1;
01110 
01111                                 /* the command takes time to move the head */
01112                                 data_register_ready = 0;
01113                                 busy_status = 1;
01114 
01115                                 /* and make it happen */
01116                                 PIC_AddEvent(FDC_MotorStep,(motor_steps > 0 ? fdc_motor_step_delay : 0.1)/*ms*/,interface_index);
01117 
01118                                 /* return now */
01119                                 return;
01120                         }
01121                         break;
01122                 case 0x13: /* Configure */
01123                         /*     |   7    6    5    4    3    2    1    0
01124                          * ----+------------------------------------------
01125                          *   0 |   0    0    0    1    0    0    1    1
01126                          *   1 |   0    0    0    0    0    0    0    0
01127                          *   2 |   0   EIS EFIFO POLL  <--- FIFOTHR -->
01128                          *   3 |                 PRETRK
01129                          * -----------------------------------------------
01130                          *   4     total
01131                          */
01132                         reset_res(); // TODO: Do something with this
01133                         reset_io();
01134                         break;
01135                 default:
01136                         LOG_MSG("FDC: Unknown command %02xh (somehow passed first check)\n",in_cmd[0]);
01137                         reset_io();
01138                         break;
01139         }
01140 
01141         switch (in_cmd[0]&0x1F) {
01142                 case 0x0A:
01143                         break;
01144                 default:
01145                         LOG_MSG("FDC: Response len=%u %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
01146                                 out_res_len,
01147                                 out_res[0],out_res[1],out_res[2],out_res[3],out_res[4],
01148                                 out_res[5],out_res[6],out_res[7],out_res[8],out_res[9]);
01149                         break;
01150         }
01151 }
01152 
01153 void FloppyController::fdc_data_write(uint8_t b) {
01154         if (!busy_status) {
01155                 /* we're starting another command */
01156                 reset_io();
01157                 in_cmd[0] = b;
01158                 in_cmd_len = 1;
01159                 in_cmd_pos = 1;
01160                 busy_status = true;
01161                 in_cmd_state = true;
01162 
01163                 /* right away.. how long is the command going to be? */
01164                 switch (in_cmd[0]&0x1F) {
01165                         case 0x03: /* Specify */
01166                                 /*     |   7    6    5    4    3    2    1    0
01167                                  * ----+------------------------------------------
01168                                  *   0 |   0    0    0    0    0    0    1    1
01169                                  *   1 |   <---- SRT ----->    <----- HUT ---->
01170                                  *   2 |   <-------------- HLT ---------->   ND
01171                                  * -----------------------------------------------
01172                                  *   3     total
01173                                  */
01174                                 in_cmd_len = 3;
01175                                 break;
01176                         case 0x04: /* Check Drive Status */
01177                                 /*     |   7    6    5    4    3    2    1    0
01178                                  * ----+------------------------------------------
01179                                  *   0 |   0    0    0    0    0    1    0    0
01180                                  *   1 |   x    x    x    x    x   HD  DR1  DR0
01181                                  * -----------------------------------------------
01182                                  *   2     total
01183                                  */
01184                                 in_cmd_len = 2;
01185                                 break;
01186                         case 0x05: /* Write data (0101) */
01187                         case 0x09: /* Write deleted data (1001) */
01188                                 /*     |   7    6    5    4    3    2    1    0
01189                                  * ----+------------------------------------------
01190                                  *   0 |  MT  MFM    0    0    0    1    0    1   
01191                                  *   1 |   0    0    0    0    0   HD  DR1  DR0
01192                                  *   2 |             Logical cylinder
01193                                  *   3 |               Logical head
01194                                  *   4 |          Logical sector (start)
01195                                  *   5 |           Logical sector size
01196                                  *   6 |               End of track               
01197                                  *   7 |               Gap 3 length
01198                                  *   8 |            Special sector size
01199                                  * -----------------------------------------------
01200                                  *   9     total
01201                                  */
01202                                 in_cmd_len = 9;
01203                                 break;
01204                         case 0x06: /* Read data (0110) */
01205                                 /*     |   7    6    5    4    3    2    1    0
01206                                  * ----+------------------------------------------
01207                                  *   0 |  MT  MFM   SK    0    0    1    1    0   
01208                                  *   1 |   0    0    0    0    0   HD  DR1  DR0
01209                                  *   2 |             Logical cylinder
01210                                  *   3 |               Logical head
01211                                  *   4 |          Logical sector (start)
01212                                  *   5 |           Logical sector size
01213                                  *   6 |               End of track               
01214                                  *   7 |               Gap 3 length
01215                                  *   8 |            Special sector size
01216                                  * -----------------------------------------------
01217                                  *   9     total
01218                                  */
01219                                 in_cmd_len = 9;
01220                                 break;
01221                         case 0x07: /* Calibrate drive (move head to track 0) */
01222                                 /*     |   7    6    5    4    3    2    1    0
01223                                  * ----+------------------------------------------
01224                                  *   0 |   0    0    0    0    0    1    1    1
01225                                  *   1 |   x    x    x    x    x    0  DR1  DR0
01226                                  * -----------------------------------------------
01227                                  *   2     total
01228                                  */
01229                                 in_cmd_len = 2;
01230                                 break;
01231                         case 0x08: /* Check Interrupt Status */
01232                                 /*     |   7    6    5    4    3    2    1    0
01233                                  * ----+------------------------------------------
01234                                  *   0 |   0    0    0    0    1    0    0    0
01235                                  * -----------------------------------------------
01236                                  *   1     total
01237                                  */
01238                                 break;
01239                         case 0x0A: /* Read ID */
01240                                 /*     |   7    6    5    4    3    2    1    0
01241                                  * ----+------------------------------------------
01242                                  *   0 |   0  MFM    0    0    1    0    1    0
01243                                  *   1 |   0    0    0    0    0   HD  DR1  DR0
01244                                  * -----------------------------------------------
01245                                  *   2     total
01246                                  */
01247                                 in_cmd_len = 2;
01248                                 break;
01249                         case 0x0C: /* Read deleted data (1100) */
01250                                 /*     |   7    6    5    4    3    2    1    0
01251                                  * ----+------------------------------------------
01252                                  *   0 |  MT  MFM   SK    0    0    1    1    0   
01253                                  *   1 |   0    0    0    0    0   HD  DR1  DR0
01254                                  *   2 |             Logical cylinder
01255                                  *   3 |               Logical head
01256                                  *   4 |          Logical sector (start)
01257                                  *   5 |           Logical sector size
01258                                  *   6 |               End of track               
01259                                  *   7 |               Gap 3 length
01260                                  *   8 |            Special sector size
01261                                  * -----------------------------------------------
01262                                  *   9     total
01263                                  */
01264                                 in_cmd_len = 9;
01265                                 break;
01266                         case 0x0E: /* Dump registers */
01267                                 /*     |   7    6    5    4    3    2    1    0
01268                                  * ----+------------------------------------------
01269                                  *   0 |   0    0    0    0    1    1    1    0
01270                                  * -----------------------------------------------
01271                                  *   1     total
01272                                  */
01273                                 in_cmd_len = 1;
01274                                 break;
01275                         case 0x0F: /* Seek Head */
01276                                 /*     |   7    6    5    4    3    2    1    0
01277                                  * ----+------------------------------------------
01278                                  *   0 |   0    0    0    0    1    1    1    1
01279                                  *   1 |   x    x    x    x    x   HD  DR1  DR0
01280                                  *   2 |                Cylinder
01281                                  * -----------------------------------------------
01282                                  *   3     total
01283                                  */
01284                                 if (in_cmd[0]&0x80) { /* Reject Seek Relative (1xfh) most FDC's I've tested don't support it */
01285                                         LOG_MSG("FDC: Seek Relative not supported\n");
01286                                         /* give Invalid Command Code 0x80 as response */
01287                                         invalid_command_code();
01288                                         reset_cmd();
01289                                 }
01290                                 else {
01291                                         in_cmd_len = 3;
01292                                 }
01293                                 break;
01294                         case 0x13: /* Configure */
01295                                 /*     |   7    6    5    4    3    2    1    0
01296                                  * ----+------------------------------------------
01297                                  *   0 |   0    0    0    1    0    0    1    1
01298                                  *   1 |   0    0    0    0    0    0    0    0
01299                                  *   2 |   0   EIS EFIFO POLL  <--- FIFOTHR -->
01300                                  *   3 |                 PRETRK
01301                                  * -----------------------------------------------
01302                                  *   4     total
01303                                  */
01304                                 in_cmd_len = 4;
01305                                 break;
01306                         default:
01307                                 LOG_MSG("FDC: Unknown command (first byte %02xh)\n",in_cmd[0]);
01308                                 /* give Invalid Command Code 0x80 as response */
01309                                 invalid_command_code();
01310                                 reset_cmd();
01311                                 break;
01312                 }
01313 
01314                 if (in_cmd_state && in_cmd_pos >= in_cmd_len)
01315                         on_fdc_in_command();
01316         }
01317         else if (in_cmd_state) {
01318                 if (in_cmd_pos < in_cmd_len)
01319                         in_cmd[in_cmd_pos++] = b;
01320 
01321                 if (in_cmd_pos >= in_cmd_len)
01322                         on_fdc_in_command();
01323         }
01324         else {
01325                 LOG_MSG("FDC: Unknown state!\n");
01326                 on_reset();
01327         }
01328 }
01329 
01330 static void fdc_baseio98_w(Bitu port,Bitu val,Bitu iolen) {
01331         FloppyController *fdc = match_fdc_controller(port);
01332         if (fdc == NULL) {
01333                 LOG_MSG("WARNING: port read from I/O port not registered to FDC, yet callback triggered\n");
01334                 return;
01335         }
01336 
01337 //      LOG_MSG("FDC: Write port 0x%03x data 0x%02x irq_at_time=%u\n",port,val,fdc->irq_pending);
01338 
01339         if (iolen > 1) {
01340                 LOG_MSG("WARNING: FDC unusual port write %03xh val=%02xh len=%u, port I/O should be 8-bit\n",(int)port,(int)val,(int)iolen);
01341         }
01342 
01343         switch (port&7) {
01344                 case 2: /* data */
01345                         if (!fdc->data_register_ready) {
01346                                 LOG_MSG("WARNING: FDC data write when data port not ready\n");
01347                         }
01348                         else if (fdc->data_read_expected) {
01349                                 LOG_MSG("WARNING: FDC data write when data port ready but expecting I/O read\n");
01350                         }
01351                         else {
01352                                 fdc->fdc_data_write(val&0xFF);
01353                         }
01354                         break;
01355                 default:
01356                         LOG_MSG("DEBUG: FDC write port %03xh val %02xh len=%u\n",(int)port,(int)val,(int)iolen);
01357                         break;
01358         }
01359 }
01360 
01361 static Bitu fdc_baseio98_r(Bitu port,Bitu iolen) {
01362         FloppyController *fdc = match_fdc_controller(port);
01363         unsigned char b;
01364 
01365         if (fdc == NULL) {
01366                 LOG_MSG("WARNING: port read from I/O port not registered to FDC, yet callback triggered\n");
01367                 return ~(0UL);
01368         }
01369 
01370 //      LOG_MSG("FDC: Read port 0x%03x irq_at_time=%u\n",port,fdc->irq_pending);
01371 
01372         if (iolen > 1) {
01373                 LOG_MSG("WARNING: FDC unusual port read %03xh len=%u, port I/O should be 8-bit\n",(int)port,(int)iolen);
01374         }
01375 
01376         switch (port&7) {
01377                 case 0: /* main status */
01378                         b =     (fdc->data_register_ready ? 0x80 : 0x00) +
01379                                 (fdc->data_read_expected ? 0x40 : 0x00) +
01380                                 (fdc->non_dma_mode ? 0x20 : 0x00) +
01381                                 (fdc->busy_status ? 0x10 : 0x00) +
01382                                 (fdc->positioning[3] ? 0x08 : 0x00) +
01383                                 (fdc->positioning[2] ? 0x04 : 0x00) +
01384                                 (fdc->positioning[1] ? 0x02 : 0x00) +
01385                                 (fdc->positioning[0] ? 0x01 : 0x00);
01386 //                      LOG_MSG("FDC: read status 0x%02x\n",b);
01387                         return b;
01388                 case 2: /* data */
01389                         if (!fdc->data_register_ready) {
01390                                 LOG_MSG("WARNING: FDC data read when data port not ready\n");
01391                                 return ~(0UL);
01392                         }
01393                         else if (!fdc->data_read_expected) {
01394                                 LOG_MSG("WARNING: FDC data read when data port ready but expecting I/O write\n");
01395                                 return ~(0UL);
01396                         }
01397 
01398                         b = fdc->fdc_data_read();
01399 //                      LOG_MSG("FDC: read data 0x%02x\n",b);
01400                         return b;
01401                 default:
01402                         LOG_MSG("DEBUG: FDC read port %03xh len=%u\n",(int)port,(int)iolen);
01403                         break;
01404         }
01405 
01406         return ~(0UL);
01407 }
01408 
01409 static void fdc_baseio_w(Bitu port,Bitu val,Bitu iolen) {
01410         FloppyController *fdc = match_fdc_controller(port);
01411         if (fdc == NULL) {
01412                 LOG_MSG("WARNING: port read from I/O port not registered to FDC, yet callback triggered\n");
01413                 return;
01414         }
01415 
01416 //      LOG_MSG("FDC: Write port 0x%03x data 0x%02x irq_at_time=%u\n",port,val,fdc->irq_pending);
01417 
01418         if (iolen > 1) {
01419                 LOG_MSG("WARNING: FDC unusual port write %03xh val=%02xh len=%u, port I/O should be 8-bit\n",(int)port,(int)val,(int)iolen);
01420         }
01421 
01422         switch (port&7) {
01423                 case 2: /* digital output port */
01424                         fdc->on_dor_change(val&0xFF);
01425                         break;
01426                 case 5: /* data */
01427                         if (!fdc->data_register_ready) {
01428                                 LOG_MSG("WARNING: FDC data write when data port not ready\n");
01429                         }
01430                         else if (fdc->data_read_expected) {
01431                                 LOG_MSG("WARNING: FDC data write when data port ready but expecting I/O read\n");
01432                         }
01433                         else {
01434                                 fdc->fdc_data_write(val&0xFF);
01435                         }
01436                         break;
01437                 default:
01438                         LOG_MSG("DEBUG: FDC write port %03xh val %02xh len=%u\n",(int)port,(int)val,(int)iolen);
01439                         break;
01440         }
01441 }
01442 
01443 static Bitu fdc_baseio_r(Bitu port,Bitu iolen) {
01444         FloppyController *fdc = match_fdc_controller(port);
01445         unsigned char b;
01446 
01447         if (fdc == NULL) {
01448                 LOG_MSG("WARNING: port read from I/O port not registered to FDC, yet callback triggered\n");
01449                 return ~(0UL);
01450         }
01451 
01452 //      LOG_MSG("FDC: Read port 0x%03x irq_at_time=%u\n",port,fdc->irq_pending);
01453 
01454         if (iolen > 1) {
01455                 LOG_MSG("WARNING: FDC unusual port read %03xh len=%u, port I/O should be 8-bit\n",(int)port,(int)iolen);
01456         }
01457 
01458         switch (port&7) {
01459                 case 4: /* main status */
01460                         b =     (fdc->data_register_ready ? 0x80 : 0x00) +
01461                                 (fdc->data_read_expected ? 0x40 : 0x00) +
01462                                 (fdc->non_dma_mode ? 0x20 : 0x00) +
01463                                 (fdc->busy_status ? 0x10 : 0x00) +
01464                                 (fdc->positioning[3] ? 0x08 : 0x00) +
01465                                 (fdc->positioning[2] ? 0x04 : 0x00) +
01466                                 (fdc->positioning[1] ? 0x02 : 0x00) +
01467                                 (fdc->positioning[0] ? 0x01 : 0x00);
01468 //                      LOG_MSG("FDC: read status 0x%02x\n",b);
01469                         return b;
01470                 case 5: /* data */
01471                         if (!fdc->data_register_ready) {
01472                                 LOG_MSG("WARNING: FDC data read when data port not ready\n");
01473                                 return ~(0UL);
01474                         }
01475                         else if (!fdc->data_read_expected) {
01476                                 LOG_MSG("WARNING: FDC data read when data port ready but expecting I/O write\n");
01477                                 return ~(0UL);
01478                         }
01479 
01480                         b = fdc->fdc_data_read();
01481 //                      LOG_MSG("FDC: read data 0x%02x\n",b);
01482                         return b;
01483                 default:
01484                         LOG_MSG("DEBUG: FDC read port %03xh len=%u\n",(int)port,(int)iolen);
01485                         break;
01486         }
01487 
01488         return ~(0UL);
01489 }
01490 
01491 void FloppyController::raise_irq() {
01492         irq_pending = true;
01493         if (irq_enabled() && IRQ >= 0) PIC_ActivateIRQ((unsigned int)IRQ);
01494 }
01495 
01496 void FloppyController::lower_irq() {
01497         irq_pending = false;
01498         if (IRQ >= 0) PIC_DeActivateIRQ((unsigned int)IRQ);
01499 }
01500 
01501 void BIOS_Post_register_FDC() {
01502         for (size_t i=0;i < MAX_FLOPPY_CONTROLLERS;i++) {
01503         if (floppycontroller[i] != NULL)
01504             floppycontroller[i]->register_isapnp();
01505     }
01506 }
01507