From: Wouter V. <m97...@us...> - 2002-10-31 19:28:19
|
Update of /cvsroot/openmsx/openMSX/src/fdc In directory usw-pr-cvs1:/tmp/cvs-serv5407/src/fdc Modified Files: MSXFDC.cc MSXFDC.hh Makefile.am Added Files: BrazilFDC.cc BrazilFDC.hh FDCFactory.cc FDCFactory.hh NationalFDC.cc NationalFDC.hh PhilipsFDC.cc PhilipsFDC.hh WD2793.cc WD2793.hh Removed Files: FDC.hh FDC2793.cc FDC2793.hh Log Message: rewrite of FDC infrastructure --- NEW FILE: BrazilFDC.cc --- // $Id: BrazilFDC.cc,v 1.1 2002/10/31 19:28:15 m9710797 Exp $ #include "BrazilFDC.hh" #include "WD2793.hh" #include "MSXCPUInterface.hh" BrazilFDC::BrazilFDC(MSXConfig::Device *config, const EmuTime &time) : MSXFDC(config, time), MSXDevice(config, time), MSXIODevice(config, time) { controller = new WD2793(config); if (deviceConfig->hasParameter("brokenFDCread")) { brokenFDCread = deviceConfig->getParameterAsBool("brokenFDCread"); } else { brokenFDCread = false; } MSXCPUInterface::instance()->register_IO_In (0xD0,this); MSXCPUInterface::instance()->register_IO_In (0xD1,this); MSXCPUInterface::instance()->register_IO_In (0xD2,this); MSXCPUInterface::instance()->register_IO_In (0xD3,this); MSXCPUInterface::instance()->register_IO_In (0xD4,this); } BrazilFDC::~BrazilFDC() { delete controller; } void BrazilFDC::reset(const EmuTime &time) { controller->reset(); } byte BrazilFDC::readIO(byte port, const EmuTime &time) { byte value = 255; switch (port) { case 0xD0: value = controller->getStatusReg(time); break; case 0xD1: value = brokenFDCread ? 255 : controller->getTrackReg(time); break; case 0xD2: value = brokenFDCread ? 255 : controller->getSectorReg(time); break; case 0xD3: value = controller->getDataReg(time); break; case 0xD4: value = driveD4; break; } return value; } void BrazilFDC::writeIO(byte port, byte value, const EmuTime &time) { switch (port) { case 0xD0: controller->setCommandReg(value, time); break; case 0xD1: controller->setTrackReg(value, time); break; case 0xD2: controller->setSectorReg(value, time); break; case 0xD3: controller->setDataReg(value, time); break; case 0xD4: // From Ricardo Bittencourt // bit 0: drive select A // bit 1: drive select B // bit 2: drive select C // bit 3: drive select D // bit 4: side select // bit 5: turn on motor // bit 6: enable waitstates // bit 7: density: 0=single 1=double // // When you enable a drive select bit, the led on the // disk-drive turns on. Since this was used as user feedback, // in things such as "replace disk 1 when the led turns off" // we need to connect this to the OSD later on. driveD4 = value; // Set correct drive byte drivenr; switch (value & 15) { case 1: drivenr = 0; break; case 2: drivenr = 1; break; case 4: drivenr = 2; break; case 8: drivenr = 3; break; default: // No drive selected or two drives at same time // The motor is enabled for all drives at the same time, so // in a real machine you must take care to do not select more // than one drive at the same time (you could get data // collision). drivenr = 255; //no drive selected } controller->setDriveSelect(drivenr, time); controller->setSideSelect((value & 16) ? 1 : 0, time); controller->setMotor((value & 32) ? 1 : 0, time); break; } } --- NEW FILE: BrazilFDC.hh --- // $Id: BrazilFDC.hh,v 1.1 2002/10/31 19:28:15 m9710797 Exp $ #ifndef __BRAZILFDC_HH__ #define __BRAZILFDC_HH__ #include "MSXFDC.hh" #include "MSXIODevice.hh" class WD2793; class BrazilFDC : public MSXFDC, public MSXIODevice { public: BrazilFDC(MSXConfig::Device *config, const EmuTime &time); virtual ~BrazilFDC(); virtual void reset(const EmuTime &time); virtual byte readIO(byte port, const EmuTime &time); virtual void writeIO(byte port, byte value, const EmuTime &time); private: WD2793* controller; bool brokenFDCread; byte driveD4; }; #endif --- NEW FILE: FDCFactory.cc --- // $Id: FDCFactory.cc,v 1.1 2002/10/31 19:28:15 m9710797 Exp $ #include "FDCFactory.hh" #include "PhilipsFDC.hh" #include "BrazilFDC.hh" #include "NationalFDC.hh" MSXDevice* FDCFactory::create(MSXConfig::Device *config, const EmuTime &time) { const std::string &type = config->getParameter("type"); if (type == "Philips") { return new PhilipsFDC(config, time); } if (type == "Brazil") { return new BrazilFDC(config, time); } if (type == "National") { return new NationalFDC(config, time); } PRT_ERROR("Unknown FDC type"); return NULL; } --- NEW FILE: FDCFactory.hh --- // $Id: FDCFactory.hh,v 1.1 2002/10/31 19:28:15 m9710797 Exp $ #ifndef __FDCFACTORY_HH__ #define __FDCFACTORY_HH__ #include "MSXConfig.hh" class EmuTime; class MSXDevice; class FDCFactory { public: static MSXDevice* create(MSXConfig::Device *config, const EmuTime &time); }; #endif --- NEW FILE: NationalFDC.cc --- // $Id: NationalFDC.cc,v 1.1 2002/10/31 19:28:16 m9710797 Exp $ #include "NationalFDC.hh" #include "WD2793.hh" #include "CPU.hh" NationalFDC::NationalFDC(MSXConfig::Device *config, const EmuTime &time) : MSXFDC(config, time), MSXDevice(config, time) { emptyRom = new byte[CPU::CACHE_LINE_SIZE]; memset(emptyRom, 255, CPU::CACHE_LINE_SIZE); // real thing uses MB8877A, but it is compatible with WD2793 // TODO check completely compatible controller = new WD2793(config); } NationalFDC::~NationalFDC() { delete controller; delete[] emptyRom; } void NationalFDC::reset(const EmuTime &time) { controller->reset(); } byte NationalFDC::readMem(word address, const EmuTime &time) { byte value = 255; switch (address & 0x3FFF) { case 0x3FB8: value = controller->getStatusReg(time); break; case 0x3FB9: value = controller->getTrackReg(time); break; case 0x3FBA: value = controller->getSectorReg(time); break; case 0x3FBB: value = controller->getDataReg(time); break; case 0x3FBC: // Drive control IRQ and DRQ lines are not connected to Z80 interrupt request // bit 7: !intrq // bit 6: !dtrq value = 0xC0; if (controller->getIRQ(time)) value &= ~0x80; if (controller->getDTRQ(time)) value &= ~0x40; break; default: if (address < 0x8000) { // ROM only visible in 0x0000-0x7FFF value = NationalFDC::readMem(address, time); } break; } //PRT_DEBUG("NationalFDC::readMem(0x" << std::hex << (int)address << std::dec << ")."); return value; } void NationalFDC::writeMem(word address, byte value, const EmuTime &time) { //PRT_DEBUG("NationalFDC::writeMem(0x" << std::hex << (int)address << std::dec << ", value "<<(int)value<<")."); switch (address & 0x3FFF) { case 0x3FB8: controller->setCommandReg(value, time); break; case 0x3FB9: controller->setTrackReg(value, time); break; case 0x3FBA: controller->setSectorReg(value, time); break; case 0x3FBB: controller->setDataReg(value, time); break; case 0x3FBC: //bit 1,0 -> drive number (00 or 10: drive A, 01: drive B, 11: nothing) //bit 2 -> side select //bit 3 -> motor on byte drivenr; switch (value & 3) { case 0: case 2: drivenr = 0; break; case 1: drivenr = 1; break; case 3: default: drivenr = 255; //no drive selected } controller->setDriveSelect(drivenr, time); controller->setSideSelect((value & 0x04) ? 1 : 0, time); controller->setMotor((value & 0x08) ? 1 : 0, time); break; } } byte* NationalFDC::getReadCacheLine(word start) { if ((start & 0x3FB8 & CPU::CACHE_LINE_HIGH) == (0x3FB8 & CPU::CACHE_LINE_HIGH)) // FDC at 0x7FB8-0x7FBC (also mirrored) return NULL; if (start < 0x8000) { // ROM at 0x0000-0x7FFF return MSXFDC::getReadCacheLine(start); } else { return emptyRom; } } --- NEW FILE: NationalFDC.hh --- // $Id: NationalFDC.hh,v 1.1 2002/10/31 19:28:16 m9710797 Exp $ #ifndef __NATIONALFDC_HH__ #define __NATIONALFDC_HH__ #include "MSXFDC.hh" class WD2793; class NationalFDC : public MSXFDC { public: NationalFDC(MSXConfig::Device *config, const EmuTime &time); virtual ~NationalFDC(); virtual void reset(const EmuTime &time); virtual byte readMem(word address, const EmuTime &time); virtual void writeMem(word address, byte value, const EmuTime &time); virtual byte* getReadCacheLine(word start); private: byte* emptyRom; WD2793* controller; bool brokenFDCread; byte driveReg; }; #endif --- NEW FILE: PhilipsFDC.cc --- // $Id: PhilipsFDC.cc,v 1.1 2002/10/31 19:28:16 m9710797 Exp $ #include "PhilipsFDC.hh" #include "WD2793.hh" #include "CPU.hh" PhilipsFDC::PhilipsFDC(MSXConfig::Device *config, const EmuTime &time) : MSXFDC(config, time), MSXDevice(config, time) { emptyRom = new byte[CPU::CACHE_LINE_SIZE]; memset(emptyRom, 255, CPU::CACHE_LINE_SIZE); controller = new WD2793(config); if (deviceConfig->hasParameter("brokenFDCread")) { brokenFDCread = deviceConfig->getParameterAsBool("brokenFDCread"); } else { brokenFDCread = false; } } PhilipsFDC::~PhilipsFDC() { delete controller; delete[] emptyRom; } void PhilipsFDC::reset(const EmuTime &time) { controller->reset(); } byte PhilipsFDC::readMem(word address, const EmuTime &time) { byte value = 255; switch (address & 0x3FFF) { case 0x3FF8: value = controller->getStatusReg(time); break; case 0x3FF9: value = brokenFDCread ? 255 : controller->getTrackReg(time); //TODO: check if such broken interfaces indeed return 255 or something else // example of such machines : Sony 700 series break; case 0x3FFA: value = brokenFDCread ? 255 : controller->getSectorReg(time); //TODO: check if such broken interfaces indeed return 255 or something else break; case 0x3FFB: value = controller->getDataReg(time); //PRT_DEBUG("Got byte from disk : "<<(int)value); break; case 0x3FFC: //bit 0 = side select //TODO check other bits !! value = controller->getSideSelect(time); break; case 0x3FFD: //bit 1,0 -> drive number (00 or 10: drive A, 01: drive B, 11: nothing) //bit 7 -> motor on //TODO check other bits !! value = driveReg; //controller->getDriveSelect(time); break; case 0x3FFE: //not used value = 255; break; case 0x3FFF: // Drive control IRQ and DRQ lines are not connected to Z80 interrupt request // bit 6: !intrq // bit 7: !dtrq //TODO check other bits !! value = 0xC0; if (controller->getIRQ(time)) value &= 0xBF ; if (controller->getDTRQ(time)) value &= 0x7F ; break; default: if (address < 0x8000) { // ROM only visible in 0x0000-0x7FFF value = PhilipsFDC::readMem(address, time); } break; } //PRT_DEBUG("PhilipsFDC::readMem(0x" << std::hex << (int)address << std::dec << ")."); return value; } void PhilipsFDC::writeMem(word address, byte value, const EmuTime &time) { //PRT_DEBUG("PhilipsFDC::writeMem(0x" << std::hex << (int)address << std::dec << ", value "<<(int)value<<")."); switch (address & 0x3FFF) { case 0x3FF8: controller->setCommandReg(value, time); break; case 0x3FF9: controller->setTrackReg(value, time); break; case 0x3FFA: controller->setSectorReg(value, time); break; case 0x3FFB: controller->setDataReg(value, time); break; case 0x3FFC: //bit 0 = side select //TODO check other bits !! controller->setSideSelect(value&1, time); break; case 0x3FFD: //bit 1,0 -> drive number (00 or 10: drive A, 01: drive B, 11: nothing) //bit 7 -> motor on //TODO check other bits !! driveReg = value; byte drivenr; switch (value & 3) { case 0: case 2: drivenr = 0; break; case 1: drivenr = 1; break; case 3: default: drivenr = 255; //no drive selected } controller->setDriveSelect(drivenr, time); controller->setMotor((value & 128) ? 1 : 0, time); // set motor for current drive break; } } byte* PhilipsFDC::getReadCacheLine(word start) { //if address overlap 0x7ff8-0x7ffb then return NULL, else normal ROM behaviour if ((start & 0x3FF8 & CPU::CACHE_LINE_HIGH) == (0x3FF8 & CPU::CACHE_LINE_HIGH)) return NULL; if (start < 0x8000) { // ROM visible in 0x0000-0x7FFF return MSXFDC::getReadCacheLine(start); } else { return emptyRom; } } --- NEW FILE: PhilipsFDC.hh --- // $Id: PhilipsFDC.hh,v 1.1 2002/10/31 19:28:16 m9710797 Exp $ #ifndef __PHILIPSFDC_HH__ #define __PHILIPSFDC_HH__ #include "MSXFDC.hh" class WD2793; class PhilipsFDC : public MSXFDC { public: PhilipsFDC(MSXConfig::Device *config, const EmuTime &time); virtual ~PhilipsFDC(); virtual void reset(const EmuTime &time); virtual byte readMem(word address, const EmuTime &time); virtual void writeMem(word address, byte value, const EmuTime &time); virtual byte* getReadCacheLine(word start); private: byte* emptyRom; WD2793* controller; bool brokenFDCread; byte driveReg; }; #endif --- NEW FILE: WD2793.cc --- // $Id: WD2793.cc,v 1.1 2002/10/31 19:28:16 m9710797 Exp $ #include "WD2793.hh" #include "DiskImageManager.hh" #include "FDCBackEnd.hh" WD2793::WD2793(MSXConfig::Device *config) { PRT_DEBUG("instantiating an WD2793 object.."); driveName[0] = config->getParameter("drivename1"); DiskImageManager::instance()->registerDrive(driveName[0]); try { driveName[1] = config->getParameter("drivename2"); DiskImageManager::instance()->registerDrive(driveName[1]); numDrives = 2; } catch (MSXException &e) { numDrives = 1; } reset(); timePerStep[0]=6; // in MSX a 1MHz clock is used! timePerStep[1]=12; timePerStep[2]=20; timePerStep[3]=30; } WD2793::~WD2793() { PRT_DEBUG("Destructing an WD2793 object.."); for (int i=0; i<numDrives; i++) { DiskImageManager::instance()->unregisterDrive(driveName[i]); } } void WD2793::reset() { PRT_DEBUG("WD2793::reset()"); statusReg=0; trackReg=0; dataReg=0; current_track=0; current_sector=0; current_side=0; stepSpeed=0; directionIn=true; current_drive=0; motor_drive[0]=0; motor_drive[1]=0; //motorStartTime[0]=0; //motorStartTime[1]=0; // According to the specs it nows issues a RestoreCommando (0x03) Afterwards // the stepping rate can still be changed so that the remaining steps of the // restorecommand can go faster. On an MSX this time can be ignored since the // bootstrap of the MSX takes MUCH longer then an ,even failing, // Restorecommand. commandReg=0x03; sectorReg=0x01; DRQ=false; INTRQ=false; //statusReg bit 7 (Not Ready status) is already reset } void WD2793::setDriveSelect(byte value,const EmuTime &time) { switch (value & 3){ case 0: case 2: current_drive=0; break; case 1: current_drive=1; break; case 3: current_drive=255; //no drive selected }; //PRT_DEBUG("motor is "<<(int)motor_drive<<" drive "<<(int)current_drive); } void WD2793::setMotor(byte value,const EmuTime &time) { if (current_drive != 255 ){ if (motor_drive[current_drive] != value){ //if already in current state this is skipped motorStartTime[current_drive]=time; } motor_drive[current_drive]=value; }; } //actually not used, maybe for GUI ? byte WD2793::getDriveSelect(const EmuTime &time) { return current_drive; } //actually not used ,maybe for GUI ? byte WD2793::getMotor(const EmuTime &time) { return (current_drive<4)?motor_drive[current_drive]:0; } byte WD2793::getDTRQ(const EmuTime &time) { return dataAvailable?1:0 ; } byte WD2793::getIRQ(const EmuTime &time) { return INTRQ?1:0; if (INTRQ){ INTRQ=false; return 1; } else { return 0; } } void WD2793::setSideSelect(byte value,const EmuTime &time) { current_side=value&1; } byte WD2793::getSideSelect(const EmuTime &time) { return current_side; } FDCBackEnd* WD2793::getBackEnd() { if (current_drive < numDrives) { return DiskImageManager::instance()-> getBackEnd(driveName[current_drive]); } else { throw MSXException("No such drive"); } } void WD2793::setCommandReg(byte value,const EmuTime &time) { commandReg = value; statusReg |= 1 ;// set status on Busy INTRQ=false; DRQ=false; // commandEnd = commandStart = time; commandEnd = time; //First we set some flags from the lower four bits of the command Cflag = value & 2 ; stepSpeed = value & 3 ; Eflag = Vflag = value & 4 ; hflag = Sflag = value & 8 ; mflag = Tflag = value & 16; // above code could by executed always with no if's // what-so-ever. Since the flags are always written during // a new command and only applicable // for the current command // some confusion about Eflag/Vflag see below // flags for the Force Interrupt are ignored for now. switch (value & 0xF0){ case 0x00: //restore PRT_DEBUG("FDC command: restore"); commandEnd += (current_track * timePerStep[stepSpeed]); if (Vflag) commandEnd += 15; //Head setting time // according to page 1-100 last alinea, however not sure so ommited // if (Eflag) commandEnd += 15; current_track = 0; trackReg=0; directionIn = false; // TODO Ask ricardo about his "timeout" for a restore driveb ? statusReg &= 254 ;// reset status on Busy break; case 0x10: //seek PRT_DEBUG("FDC command: seek"); //PRT_DEBUG("before: track "<<(int)trackReg<<",data "<<(int)dataReg<<",cur "<<(int)current_track); if ( trackReg != dataReg ){ // It could be that the current track isn't the one indicated by the dataReg-sectorReg // so we calculated the steps the FDC will send to get the two regs the same // and add/distract this from the real current track byte steps; if (trackReg<dataReg){ steps = dataReg-trackReg ; current_track += steps; directionIn=true; } else { steps = trackReg-dataReg; current_track -= steps; directionIn=false; } trackReg = dataReg; commandEnd += (steps * timePerStep[stepSpeed]); if (Vflag) commandEnd += 15; //Head setting time //TODO actually verify //PRT_DEBUG("after : track "<<(int)trackReg<<",data "<<(int)dataReg<<",cur "<<(int)current_track); statusReg &= 254 ;// reset status on Busy }; break; case 0x20: //step case 0x30: //step (Update trackRegister) PRT_DEBUG("FDC command: step (Tflag "<<(int)Tflag<<")"); if (directionIn){ current_track++; if (Tflag) trackReg++; } else { current_track--; if (Tflag) trackReg--; }; commandEnd += timePerStep[stepSpeed]; if (Vflag) commandEnd += 15; //Head setting time statusReg &= 254 ;// reset status on Busy break; case 0x40: //step-in case 0x50: //step-in (Update trackRegister) PRT_DEBUG("FDC command: step in (Tflag "<<(int)Tflag<<")"); current_track++; directionIn = true; if (Tflag) trackReg++; commandEnd += timePerStep[stepSpeed]; if (Vflag) commandEnd += 15; //Head setting time statusReg &= 254 ;// reset status on Busy break; case 0x60: //step-out case 0x70: //step-out (Update trackRegister) PRT_DEBUG("FDC command: step out (Tflag "<<(int)Tflag<<")"); current_track--; // TODO Specs don't say what happens if track was already 0 !! directionIn = false; if (Tflag) trackReg++; commandEnd += timePerStep[stepSpeed]; if (Vflag) commandEnd += 15; //Head setting time statusReg &= 254 ;// reset status on Busy break; case 0x80: //read sector case 0x90: //read sector (multi) PRT_DEBUG("FDC command: read sector"); INTRQ=false; DRQ=false; statusReg &= 0x01 ;// reset lost data,record not found & status bits 5 & 6 //statusReg &= 0x // fake ready, fake CRC error, fake record t1=copy DRQ Type :-) dataCurrent=0; dataAvailable=512; // TODO should come from sector header !!! try { getBackEnd()->read(current_track, trackReg, sectorReg, current_side, 512, dataBuffer); statusReg |= 2; DRQ=true; // data ready to be read } catch (MSXException &e) { statusReg |= 2; DRQ=true; // TODO data not ready because read error } break; case 0xA0: // write sector case 0xB0: // write sector (multi) PRT_DEBUG("FDC command: write sector"); INTRQ=false; DRQ=false; statusReg &= 0x01 ;// reset lost data,record not found & status bits 5 & 6 dataCurrent=0; dataAvailable=512; // TODO should come from sector header !!! statusReg |= 2; DRQ=true; // data ready to be written break; case 0xC0: //Read Address PRT_DEBUG("FDC command: read address"); PRT_INFO("FDC command not yet implemented "); break; case 0xD0: //Force interrupt PRT_DEBUG("FDC command: Force interrupt statusregister "<<(int)statusReg); statusReg &= 254 ;// reset status on Busy break; case 0xE0: //read track PRT_DEBUG("FDC command: read track"); PRT_INFO("FDC command not yet implemented "); break; case 0xF0: //write track PRT_DEBUG("FDC command: write track"); statusReg &= 0x01 ;// reset lost data,record not found & status bits 5 & 6 statusReg |= 2; DRQ=true; //PRT_INFO("FDC command not yet implemented "); break; } } byte WD2793::getStatusReg(const EmuTime &time) { if ( (commandReg & 0x80) == 0){ //Type I command so bit 1 should be the index pulse if ( current_drive < 2 ){ int ticks = motorStartTime[current_drive].getTicksTill(time); if ( ticks >= 200) ticks -= 200 * ( int (ticks/200) ); //TODO: check on a real MSX how long this indexmark is visible // According to Ricardo it is simply a sensor that is mapped // onto this bit that sees if the index mark is passing by // or not. (The little gap in the metal plate of te disk) if (ticks < 20) statusReg |= 2; } }; //statusReg &= 254 ;// reset status on Busy //TODO this hould be time dependend !!! // like in : if (time>=endTime) statusReg &= 254; if (time>=commandEnd) statusReg &= 254; PRT_DEBUG("statusReg is "<<(int)statusReg); return statusReg; } void WD2793::setTrackReg(byte value,const EmuTime &time) { trackReg=value; }; byte WD2793::getTrackReg(const EmuTime &time) { return trackReg; }; void WD2793::setSectorReg(byte value,const EmuTime &time) { sectorReg=value; }; byte WD2793::getSectorReg(const EmuTime &time) { return sectorReg; }; void WD2793::setDataReg(byte value, const EmuTime &time) { dataReg=value; // TODO is this also true in case of sector write ? Not so according to ASM of brMSX if ((commandReg&0xE0)==0xA0){ // WRITE SECTOR dataBuffer[dataCurrent]=value; dataCurrent++; dataAvailable--; if ( dataAvailable == 0 ){ PRT_DEBUG("Now we call the backend to write a sector"); try { getBackEnd()->write(current_track, trackReg, sectorReg, current_side, 512, dataBuffer); // If we wait too long we should also write a partialy filled sector // ofcourse and set the correct status bits !! statusReg &= 0x7D ;// reset status on Busy(=bit7) reset DRQ bit(=bit1) DRQ=false; if (mflag==0) { //TODO verify this ! INTRQ=true; } dataCurrent=0; dataAvailable=512; // TODO should come from sector header !!! } catch (MSXException &e) { // Backend couldn't write data } } } else if ((commandReg&0xF0)==0xF0){ // WRITE TRACK PRT_DEBUG("WD2793 WRITE TRACK value "<<(int)value); switch ( value ){ case 0xFE: case 0xFD: case 0xFC: case 0xFB: case 0xFA: case 0xF9: case 0xF8: PRT_DEBUG("CRC generator initializing"); break; case 0xF6: PRT_DEBUG("write C2 ?"); break; case 0xF5: PRT_DEBUG("CRC generator initializing in MFM,write A1 ?"); break; case 0xF7: PRT_DEBUG("two CRC characters"); break; default: //Normal write to track break; } //shouldn't been done here !! statusReg &= 0x7D ;// reset status on Busy(=bit7) reset DRQ bit(=bit1) /* if (indexmark){ statusReg &= 0x7D ;// reset status on Busy(=bit7) reset DRQ bit(=bit1) INTRQ=true; DRQ=false; } */ } } byte WD2793::getDataReg(const EmuTime &time) { if ((commandReg&0xE0)==0x80){ // READ SECTOR dataReg=dataBuffer[dataCurrent]; dataCurrent++; dataAvailable--; if ( dataAvailable == 0 ){ statusReg &= 0x7D ;// reset status on Busy(=bit7) reset DRQ bit(=bit1) DRQ=false; if (mflag==0) INTRQ=true; PRT_DEBUG("Now we terminate the read sector command or skip to next sector if multi set"); } } return dataReg; } --- NEW FILE: WD2793.hh --- // $Id: WD2793.hh,v 1.1 2002/10/31 19:28:16 m9710797 Exp $ #ifndef __WD2793_HH__ #define __WD2793_HH__ #include "MSXConfig.hh" // forward declarations class FDCBackEnd; class WD2793 { public: virtual ~WD2793(); virtual void reset(); virtual byte getStatusReg(const EmuTime &time); virtual byte getTrackReg(const EmuTime &time); virtual byte getSectorReg(const EmuTime &time); virtual byte getDataReg(const EmuTime &time); virtual void setCommandReg(byte value,const EmuTime &time); virtual void setTrackReg(byte value,const EmuTime &time); virtual void setSectorReg(byte value,const EmuTime &time); virtual void setDataReg(byte value,const EmuTime &time); virtual byte getSideSelect(const EmuTime &time); virtual byte getDriveSelect(const EmuTime &time); virtual byte getMotor(const EmuTime &time); virtual byte getIRQ(const EmuTime &time); virtual byte getDTRQ(const EmuTime &time); virtual void setSideSelect(byte value,const EmuTime &time); virtual void setDriveSelect(byte value,const EmuTime &time); virtual void setMotor(byte value,const EmuTime &time); WD2793(MSXConfig::Device *config); private: FDCBackEnd* getBackEnd(); byte timePerStep[4]; // {3,6,10,15} in ms case of of 2 MHz clock, double this if a 1MHz clock is used! (MSX=1MHz clock :-) std::string driveName[2]; int numDrives; // number of connected drives (1 or 2) /* EmuTime commandStart; EmuTime commandEnd; */ EmuTimeFreq<1000> commandEnd; EmuTimeFreq<1000> motorStartTime[2]; byte statusReg; byte commandReg; byte sectorReg; byte trackReg; byte dataReg; byte current_drive; byte motor_drive[4]; //Brazilian based machines support up to 4 drives per FDC byte current_track; byte current_sector; byte current_side; byte stepSpeed; //flags could have been bools ofcourse //Names taken from Table 2 in the WD279X-02 specs pdf byte Vflag; //Track Number Verify Flag byte hflag; //Head Load Flag byte Tflag; //Track Update Flag byte Dflag; //Data Address Mark Flag byte Cflag; //Side Compare Flag byte mflag; //Multi Record Flag byte Eflag; //15 MS delay byte Sflag; //Side Compare Flag2 bool directionIn; bool INTRQ; bool DRQ; byte dataBuffer[1024]; // max sector size possible int dataCurrent; // which byte in dataBuffer is next to be read/write int dataAvailable; // how many bytes left in sector }; #endif Index: MSXFDC.cc =================================================================== RCS file: /cvsroot/openmsx/openMSX/src/fdc/MSXFDC.cc,v retrieving revision 1.13 retrieving revision 1.14 diff -u -d -r1.13 -r1.14 --- MSXFDC.cc 13 Oct 2002 10:02:13 -0000 1.13 +++ MSXFDC.cc 31 Oct 2002 19:28:15 -0000 1.14 @@ -1,275 +1,25 @@ // $Id$ #include "MSXFDC.hh" -#include "FDC2793.hh" #include "CPU.hh" -#include "MSXCPUInterface.hh" MSXFDC::MSXFDC(MSXConfig::Device *config, const EmuTime &time) : MSXDevice(config, time), MSXMemDevice(config, time), - MSXRomDevice(config, time), MSXIODevice(config, time) + MSXRomDevice(config, time) { - // The loading of the diskrom and the mapping in the slot layout - // has been done by the MSXRom - - emptyRom = new byte[CPU::CACHE_LINE_SIZE]; - memset(emptyRom, 255, CPU::CACHE_LINE_SIZE); - - std::string fdcChip = deviceConfig->getParameter("chip"); - PRT_DEBUG("FDC of chiptype " << fdcChip); - if (fdcChip == "2793") - controller = new FDC2793(config); - else - PRT_ERROR("Unknown FDC chiptype"); - - try { - brokenFDCread = deviceConfig->getParameterAsBool("brokenFDCread"); - PRT_DEBUG("brokenFDCread " << brokenFDCread); - } catch(MSXConfig::Exception& e) { - brokenFDCread = false; - } - - try { - std::string interfaceType= deviceConfig->getParameter("interface"); - PRT_DEBUG("interfaceType " << interfaceType); - if (interfaceType == "memory") - interface = 0; - else if (interfaceType == "port") - interface = 1; - else if (interfaceType == "hybrid") - interface = 2; - else - assert(false); - } catch(MSXConfig::Exception& e) { - interface = 2; - } - - if (interface) { - //register extra IO ports for brazilian based interfaces - MSXCPUInterface::instance()->register_IO_In (0xD0,this); - MSXCPUInterface::instance()->register_IO_In (0xD1,this); - MSXCPUInterface::instance()->register_IO_In (0xD2,this); - MSXCPUInterface::instance()->register_IO_In (0xD3,this); - } } MSXFDC::~MSXFDC() { - PRT_DEBUG("Destructing an MSXFDC object"); - delete controller; - delete[] emptyRom; -} - -void MSXFDC::reset(const EmuTime &time) -{ - controller->reset(); -} - -byte MSXFDC::readIO(byte port, const EmuTime &time) -{ - byte value = 255; - switch (port){ - case 0xD0: - value = controller->getStatusReg(time); - break; - case 0xD1: - value = brokenFDCread ? 255 : controller->getTrackReg(time); - break; - case 0xD2: - value = brokenFDCread ? 255 : controller->getSectorReg(time); - break; - case 0xD3: - value = controller->getDataReg(time); - break; - case 0xD4: - value = driveD4; - break; - }; - return value; } byte MSXFDC::readMem(word address, const EmuTime &time) { - byte value = 255; - //PRT_DEBUG("MSXFDC::readMem(0x" << std::hex << (int)address << std::dec << ")."); - if (interface != 1) { - // if hybrid or memory based - // if address overlap 0x7ff8-0x7ffb then return FDC, else normal ROM behaviour - switch (address & 0x3FFF) { - case 0x3FF8: - value = controller->getStatusReg(time); - break; - case 0x3FF9: - value = brokenFDCread ? 255 : controller->getTrackReg(time); - //TODO: check if such broken interfaces indeed return 255 or something else - // example of such machines : Sony 700 series - break; - case 0x3FFA: - value = brokenFDCread ? 255 : controller->getSectorReg(time); - //TODO: check if such broken interfaces indeed return 255 or something else - break; - case 0x3FFB: - value = controller->getDataReg(time); - //PRT_DEBUG("Got byte from disk : "<<(int)value); - break; - case 0x3FFC: - //bit 0 = side select - //TODO check other bits !! - value = controller->getSideSelect(time); - break; - case 0x3FFD: - //bit 1,0 -> drive number (00 or 10: drive A, 01: drive B, 11: nothing) - //bit 7 -> motor on - //TODO check other bits !! - value = driveReg; //controller->getDriveSelect(time); - break; - case 0x3FFE: - //not used - value = 255; - break; - case 0x3FFF: - // Drive control IRQ and DRQ lines are not connected to Z80 interrupt request - // bit 6: !intrq - // bit 7: !dtrq - //TODO check other bits !! - value = 0xC0; - if (controller->getIRQ(time)) value &= 0xBF ; - if (controller->getDTRQ(time)) value &= 0x7F ; - break; - - default: - if (address < 0x8000) - value = romBank[address & 0x3FFF]; - // quick hack to have FDC register in the correct ranges but not the rom - // (other wise calculus says to litle TPA memory :-) - // The rom needs to be visible in the 0x4000-0x7FFF range - // However in an NMS8250 the FDC registers are read - // from 0x4FF8-0x4FFF and 0xBFF8-0xBFFF - break; - } - return value; - } else { - return romBank[address & 0x3FFF]; - } -} - -void MSXFDC::writeIO(byte port, byte value, const EmuTime &time) -{ - switch (port) { - case 0xD0: - controller->setCommandReg(value, time); - break; - case 0xD1: - controller->setTrackReg(value, time); - break; - case 0xD2: - controller->setSectorReg(value, time); - break; - case 0xD3: - controller->setDataReg(value, time); - break; - case 0xD4: - // From Ricardo Bittencourt - // bit 0: drive select A - // bit 1: drive select B - // bit 2: drive select C - // bit 3: drive select D - // bit 4: side select - // bit 5: turn on motor - // bit 6: enable waitstates - // bit 7: density: 0=single 1=double - // - // When you enable a drive select bit, the led on the - // disk-drive turns on. Since this was used as user feedback, - // in things such as "replace disk 1 when the led turns off" - // we need to connect this to the OSD later on. - - driveD4 = value; - // Set correct drive - byte drivenr; - switch (value & 15) { - case 1: - drivenr = 0; - break; - case 2: - drivenr = 1; - break; - case 4: - drivenr = 2; - break; - case 8: - drivenr = 3; - break; - default: - // No drive selected or two drives at same time - // The motor is enabled for all drives at the same time, so - // in a real machine you must take care to do not select more - // than one drive at the same time (you could get data - // collision). - drivenr = 255; //no drive selected - } - controller->setDriveSelect(drivenr, time); - - controller->setSideSelect((value & 16) ? 1 : 0, time); - - controller->setMotor((value & 32) ? 1 : 0, time); - - break; - } -} - -void MSXFDC::writeMem(word address, byte value, const EmuTime &time) -{ - //PRT_DEBUG("MSXFDC::writeMem(0x" << std::hex << (int)address << std::dec << ", value "<<(int)value<<")."); - switch (address & 0x3FFF) { - case 0x3FF8: - controller->setCommandReg(value, time); - break; - case 0x3FF9: - controller->setTrackReg(value, time); - break; - case 0x3FFA: - controller->setSectorReg(value, time); - break; - case 0x3FFB: - controller->setDataReg(value, time); - break; - case 0x3FFC: - //bit 0 = side select - //TODO check other bits !! - controller->setSideSelect(value&1, time); - break; - case 0x3FFD: - //bit 1,0 -> drive number (00 or 10: drive A, 01: drive B, 11: nothing) - //bit 7 -> motor on - //TODO check other bits !! - driveReg = value; - byte drivenr; - switch (value & 3) { - case 0: - case 2: - drivenr = 0; - break; - case 1: - drivenr = 1; - break; - case 3: - default: - drivenr = 255; //no drive selected - }; - controller->setDriveSelect(drivenr, time); - controller->setMotor((value & 128) ? 1 : 0, time); // set motor for current drive - break; - } + return romBank[address & 0x3FFF]; } byte* MSXFDC::getReadCacheLine(word start) { - //if address overlap 0x7ff8-0x7ffb then return NULL, else normal ROM behaviour - if ((start & 0x3FF8 & CPU::CACHE_LINE_HIGH) == (0x3FF8 & CPU::CACHE_LINE_HIGH)) - return NULL; - if (start >= 0x8000) - return emptyRom; return &romBank[start & 0x3FFF]; } Index: MSXFDC.hh =================================================================== RCS file: /cvsroot/openmsx/openMSX/src/fdc/MSXFDC.hh,v retrieving revision 1.10 retrieving revision 1.11 diff -u -d -r1.10 -r1.11 --- MSXFDC.hh 13 Oct 2002 10:02:13 -0000 1.10 +++ MSXFDC.hh 31 Oct 2002 19:28:15 -0000 1.11 @@ -5,47 +5,15 @@ #include "MSXMemDevice.hh" #include "MSXRomDevice.hh" -#include "MSXIODevice.hh" - -// This is the interface for the emulated MSX towards the FDC -// in a first stage it will be only on memmorymappedFDC as in -// the Philips NMSxxxx MSX2 machines -// -// The actual FDC is implemented elsewhere and uses backends -// to talk to actual disk(image)s - -// forward declarations -class FDC; -class MSXFDC : public MSXMemDevice, MSXRomDevice, public MSXIODevice +class MSXFDC : public MSXMemDevice, private MSXRomDevice { public: - /** - * Constructor - */ MSXFDC(MSXConfig::Device *config, const EmuTime &time); - - /** - * Destructor - */ virtual ~MSXFDC(); - - virtual void reset(const EmuTime &time); - + virtual byte readMem(word address, const EmuTime &time); - virtual void writeMem(word address, byte value, const EmuTime &time); virtual byte* getReadCacheLine(word start); - - virtual byte readIO(byte port, const EmuTime &time); - virtual void writeIO(byte port, byte value, const EmuTime &time); - - private: - FDC* controller; - bool brokenFDCread; - byte* emptyRom; - byte interface; - byte driveD4; - byte driveReg; }; #endif Index: Makefile.am =================================================================== RCS file: /cvsroot/openmsx/openMSX/src/fdc/Makefile.am,v retrieving revision 1.6 retrieving revision 1.7 diff -u -d -r1.6 -r1.7 --- Makefile.am 27 Oct 2002 12:40:55 -0000 1.6 +++ Makefile.am 31 Oct 2002 19:28:16 -0000 1.7 @@ -13,13 +13,16 @@ noinst_LTLIBRARIES = libFdc.la libFdc_la_SOURCES = \ + FDCFactory.cc FDCFactory.hh \ MSXFDC.cc MSXFDC.hh \ - FDC.hh \ - FDC2793.cc FDC2793.hh \ + PhilipsFDC.cc PhilipsFDC.hh \ + BrazilFDC.cc BrazilFDC.hh \ + NationalFDC.cc NationalFDC.hh \ + WD2793.cc WD2793.hh \ + DiskImageManager.cc DiskImageManager.hh \ FDCBackEnd.cc FDCBackEnd.hh \ FDCDummyBackEnd.cc FDCDummyBackEnd.hh \ FDC_DSK.cc FDC_DSK.hh \ - DiskImageManager.cc DiskImageManager.hh \ FDC_XSA.cc FDC_XSA.hh nodebug: resetdebug all --- FDC.hh DELETED --- --- FDC2793.cc DELETED --- --- FDC2793.hh DELETED --- |