openMSX
SpectravideoFDC.cc
Go to the documentation of this file.
1 #include "SpectravideoFDC.hh"
2 #include "CacheLine.hh"
3 #include "DriveMultiplexer.hh"
4 #include "WD2793.hh"
5 #include "MSXException.hh"
6 #include "serialize.hh"
7 
8 // Note: although this implementation seems to work, it has not been checked on
9 // real hardware how the FDC registers are mirrored across the slot, nor how
10 // the ROM is visible in the slot. Currently FDC registers are implemented to
11 // be mirrored all over the slot (as it seems that the MSX-DOS that came with
12 // the SVI-707 needs that), and ROMs are implemented to be visible in page 1.
13 //
14 // This implementation is solely based on the MSX SVI-728 Service and Technical
15 // Manual [Vol.1], page 3-7 (memory mapping of registers) and page 3-1 (ROM).
16 // Thanks to Leonard Oliveira for interpreting some of the hardware schematics
17 // in that same manual.
18 // Thanks to Benoit Delvaux for providing some extra info and software to test
19 // with.
20 
21 namespace openmsx {
22 
24  : WD2793BasedFDC(config, "msxdos")
25  , cpmRom(getName() + " CP/M ROM", "rom", config, "cpm")
26 {
27  if (cpmRom.getSize() != 0x1000) {
28  throw MSXException("CP/M ROM must be exactly 4kB in size.");
29  }
31 }
32 
33 void SpectravideoFDC::reset(EmuTime::param /*time*/)
34 {
35  cpmRomEnabled = true;
36 }
37 
38 byte SpectravideoFDC::readMem(word address, EmuTime::param time)
39 {
40  byte value;
41  switch (address & 0x3FFF) {
42  case 0x3FB8:
43  value = controller.getStatusReg(time);
44  break;
45  case 0x3FB9:
46  value = controller.getTrackReg(time);
47  break;
48  case 0x3FBA:
49  value = controller.getSectorReg(time);
50  break;
51  case 0x3FBB:
52  value = controller.getDataReg(time);
53  break;
54  case 0x3FBC:
55  value = 0;
56  if ( controller.getIRQ(time)) value |= 0x80;
57  if (!controller.getDTRQ(time)) value |= 0x40;
58  break;
59  case 0x3FBE: // Software switch to turn on CP/M,
60  // boot ROM and turn off MSX DOS ROM.
61  cpmRomEnabled = true;
62  value = 0xFF;
63  break;
64  case 0x3FBF: // Software switch to turn off CP/M,
65  // boot ROM and turn on MSX DOS ROM.
66  cpmRomEnabled = false;
67  value = 0xFF;
68  break;
69  default:
70  value = SpectravideoFDC::peekMem(address, time);
71  break;
72  }
73  return value;
74 }
75 
76 byte SpectravideoFDC::peekMem(word address, EmuTime::param time) const
77 {
78  byte value;
79  switch (address & 0x3FFF) {
80  case 0x3FB8:
81  value = controller.peekStatusReg(time);
82  break;
83  case 0x3FB9:
84  value = controller.peekTrackReg(time);
85  break;
86  case 0x3FBA:
87  value = controller.peekSectorReg(time);
88  break;
89  case 0x3FBB:
90  value = controller.peekDataReg(time);
91  break;
92  case 0x3FBC:
93  // Drive control IRQ and DRQ lines are not connected to Z80 interrupt request
94  // bit 7: interrupt of 1793 (1 for interrupt)
95  // bit 6: data request of 1793 (0 for request)
96  // TODO: other bits read 0?
97  value = 0;
98  if ( controller.peekIRQ(time)) value |= 0x80;
99  if (!controller.peekDTRQ(time)) value |= 0x40;
100  break;
101  default:
102  if ((0x4000 <= address) && (address < 0x8000) && !cpmRomEnabled) {
103  // MSX-DOS ROM only visible in 0x4000-0x7FFF
104  value = MSXFDC::peekMem(address, time);
105  } else if ((0x4000 <= address) && (address < 0x5000) && cpmRomEnabled) {
106  // CP/M ROM only visible in 0x4000-0x4FFF
107  value = cpmRom[address & 0x0FFF];
108  } else {
109  value = 0xFF;
110  }
111  break;
112  }
113  return value;
114 }
115 
116 const byte* SpectravideoFDC::getReadCacheLine(word start) const
117 {
118  if ((start & 0x3FFF & CacheLine::HIGH) == (0x3FB8 & CacheLine::HIGH)) {
119  // FDC at 0x7FB8-0x7FBF, and mirrored in other pages
120  return nullptr;
121  } else if ((0x4000 <= start) && (start < 0x8000) && !cpmRomEnabled) {
122  // MSX-DOS ROM at 0x4000-0x7FFF
123  return MSXFDC::getReadCacheLine(start);
124  } else if ((0x4000 <= start) && (start < 0x5000) && cpmRomEnabled) {
125  // CP/M ROM at 0x4000-0x4FFF
126  return &cpmRom[start & 0x0FFF];
127  } else {
128  return unmappedRead;
129  }
130 }
131 
132 void SpectravideoFDC::writeMem(word address, byte value, EmuTime::param time)
133 {
134  switch (address & 0x3FFF) {
135  case 0x3FB8:
136  controller.setCommandReg(value, time);
137  break;
138  case 0x3FB9:
139  controller.setTrackReg(value, time);
140  break;
141  case 0x3FBA:
142  controller.setSectorReg(value, time);
143  break;
144  case 0x3FBB:
145  controller.setDataReg(value, time);
146  break;
147  case 0x3FBC:
148  // bit 0 -> enable drive (1 for ENABLE)
149  // bit 2 -> side select (0 for side 0)
150  // bit 3 -> motor on (1 for ON)
152  multiplexer.setSide( (value & 0x04) != 0);
153  multiplexer.setMotor( (value & 0x08) != 0, time);
154  break;
155  case 0x3FBE: // Software switch to turn on CP/M,
156  // boot ROM and turn off MSX DOS ROM.
157  cpmRomEnabled = true;
158  break;
159  case 0x3FBF: // Software switch to turn off CP/M,
160  // boot ROM and turn on MSX DOS ROM.
161  cpmRomEnabled = false;
162  break;
163  }
164 }
165 
167 {
168  if ((address & 0x3FFF & CacheLine::HIGH) == (0x3FB8 & CacheLine::HIGH)) {
169  // FDC at 0x7FB8-0x7FBF - mirrored
170  return nullptr;
171  } else {
172  return unmappedWrite;
173  }
174 }
175 
176 template<typename Archive>
177 void SpectravideoFDC::serialize(Archive& ar, unsigned /*version*/)
178 {
179  ar.template serializeBase<WD2793BasedFDC>(*this);
180  ar.serialize("cpmRomEnabled", cpmRomEnabled);
181 }
184 
185 } // namespace openmsx
openmsx::MSXFDC::peekMem
byte peekMem(word address, EmuTime::param time) const override
Read a byte from a given memory location.
Definition: MSXFDC.cc:56
openmsx::WD2793BasedFDC::multiplexer
DriveMultiplexer multiplexer
Definition: WD2793BasedFDC.hh:25
serialize.hh
openmsx::WD2793BasedFDC::controller
WD2793 controller
Definition: WD2793BasedFDC.hh:26
openmsx::DeviceConfig
Definition: DeviceConfig.hh:20
openmsx::MSXDevice::unmappedWrite
static byte unmappedWrite[0x10000]
Definition: MSXDevice.hh:301
openmsx::SpectravideoFDC::reset
void reset(EmuTime::param time) override
This method is called on reset.
Definition: SpectravideoFDC.cc:33
openmsx::WD2793::getIRQ
bool getIRQ(EmuTime::param time)
Definition: WD2793.cc:105
openmsx::SpectravideoFDC::readMem
byte readMem(word address, EmuTime::param time) override
Read a byte from a location at a certain time from this device.
Definition: SpectravideoFDC.cc:38
openmsx::WD2793::getDataReg
byte getDataReg(EmuTime::param time)
Definition: WD2793.cc:260
openmsx::WD2793::peekStatusReg
byte peekStatusReg(EmuTime::param time) const
Definition: WD2793.cc:210
SpectravideoFDC.hh
openmsx::WD2793::peekIRQ
bool peekIRQ(EmuTime::param time) const
Definition: WD2793.cc:110
MSXException.hh
openmsx::MSXException
Definition: MSXException.hh:10
openmsx::WD2793::getStatusReg
byte getStatusReg(EmuTime::param time)
Definition: WD2793.cc:170
openmsx::SpectravideoFDC::writeMem
void writeMem(word address, byte value, EmuTime::param time) override
Write a given byte to a given location at a certain time to this device.
Definition: SpectravideoFDC.cc:132
openmsx::SpectravideoFDC::getReadCacheLine
const byte * getReadCacheLine(word start) const override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for reading.
Definition: SpectravideoFDC.cc:116
openmsx::CacheLine::HIGH
constexpr unsigned HIGH
Definition: CacheLine.hh:10
openmsx::WD2793BasedFDC
Definition: WD2793BasedFDC.hh:12
openmsx::DriveMultiplexer::setMotor
void setMotor(bool status, EmuTime::param time) override
Set motor on/off.
Definition: DriveMultiplexer.cc:69
openmsx::DriveMultiplexer::NO_DRIVE
@ NO_DRIVE
Definition: DriveMultiplexer.hh:20
openmsx::REGISTER_MSXDEVICE
REGISTER_MSXDEVICE(ChakkariCopy, "ChakkariCopy")
openmsx::WD2793::getTrackReg
byte getTrackReg(EmuTime::param time)
Definition: WD2793.cc:221
openmsx::DriveMultiplexer::setSide
void setSide(bool side) override
Side select.
Definition: DriveMultiplexer.cc:48
openmsx::Keys::getName
string getName(KeyCode keyCode)
Translate key code to key name.
Definition: Keys.cc:740
openmsx::WD2793::getSectorReg
byte getSectorReg(EmuTime::param time)
Definition: WD2793.cc:236
openmsx::MSXDevice::getCurrentTime
EmuTime::param getCurrentTime() const
Definition: MSXDevice.cc:131
openmsx::SpectravideoFDC::SpectravideoFDC
SpectravideoFDC(const DeviceConfig &config)
Definition: SpectravideoFDC.cc:23
INSTANTIATE_SERIALIZE_METHODS
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:981
openmsx::DriveMultiplexer::DRIVE_A
@ DRIVE_A
Definition: DriveMultiplexer.hh:16
openmsx::WD2793::setDataReg
void setDataReg(byte value, EmuTime::param time)
Definition: WD2793.cc:246
CacheLine.hh
openmsx::SpectravideoFDC::peekMem
byte peekMem(word address, EmuTime::param time) const override
Read a byte from a given memory location.
Definition: SpectravideoFDC.cc:76
DriveMultiplexer.hh
WD2793.hh
openmsx::MSXDevice::unmappedRead
static byte unmappedRead[0x10000]
Definition: MSXDevice.hh:300
openmsx::word
uint16_t word
16 bit unsigned integer
Definition: openmsx.hh:29
openmsx::WD2793::peekSectorReg
byte peekSectorReg(EmuTime::param time) const
Definition: WD2793.cc:241
openmsx::SpectravideoFDC::getWriteCacheLine
byte * getWriteCacheLine(word address) const override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for writing.
Definition: SpectravideoFDC.cc:166
openmsx::DriveMultiplexer::selectDrive
void selectDrive(DriveNum num, EmuTime::param time)
Definition: DriveMultiplexer.cc:18
openmsx::SpectravideoFDC::serialize
void serialize(Archive &ar, unsigned version)
Definition: SpectravideoFDC.cc:177
openmsx::WD2793::setCommandReg
void setCommandReg(byte value, EmuTime::param time)
Definition: WD2793.cc:122
openmsx::WD2793::peekDataReg
byte peekDataReg(EmuTime::param time) const
Definition: WD2793.cc:325
openmsx::MSXFDC::getReadCacheLine
const byte * getReadCacheLine(word start) const override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for reading.
Definition: MSXFDC.cc:61
openmsx::WD2793::peekDTRQ
bool peekDTRQ(EmuTime::param time) const
Definition: WD2793.cc:95
openmsx::WD2793::peekTrackReg
byte peekTrackReg(EmuTime::param time) const
Definition: WD2793.cc:226
openmsx::WD2793::setSectorReg
void setSectorReg(byte value, EmuTime::param time)
Definition: WD2793.cc:231
openmsx::WD2793::getDTRQ
bool getDTRQ(EmuTime::param time)
Definition: WD2793.cc:90
openmsx::WD2793::setTrackReg
void setTrackReg(byte value, EmuTime::param time)
Definition: WD2793.cc:216
openmsx::Rom::getSize
unsigned getSize() const
Definition: Rom.hh:32
openmsx
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:5
openmsx::SpectravideoFDC
Definition: SpectravideoFDC.hh:10