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  switch (address & 0x3FFF) {
41  case 0x3FB8:
42  return controller.getStatusReg(time);
43  case 0x3FB9:
44  return controller.getTrackReg(time);
45  case 0x3FBA:
46  return controller.getSectorReg(time);
47  case 0x3FBB:
48  return controller.getDataReg(time);
49  case 0x3FBC: {
50  byte value = 0;
51  if ( controller.getIRQ (time)) value |= 0x80;
52  if (!controller.getDTRQ(time)) value |= 0x40;
53  return value;
54  }
55  case 0x3FBE: // Software switch to turn on CP/M,
56  // boot ROM and turn off MSX DOS ROM.
57  cpmRomEnabled = true;
58  return 0xFF;
59  case 0x3FBF: // Software switch to turn off CP/M,
60  // boot ROM and turn on MSX DOS ROM.
61  cpmRomEnabled = false;
62  return 0xFF;
63  default:
64  return SpectravideoFDC::peekMem(address, time);
65  }
66 }
67 
68 byte SpectravideoFDC::peekMem(word address, EmuTime::param time) const
69 {
70  switch (address & 0x3FFF) {
71  case 0x3FB8:
72  return controller.peekStatusReg(time);
73  case 0x3FB9:
74  return controller.peekTrackReg(time);
75  case 0x3FBA:
76  return controller.peekSectorReg(time);
77  case 0x3FBB:
78  return controller.peekDataReg(time);
79  case 0x3FBC: {
80  // Drive control IRQ and DRQ lines are not connected to Z80 interrupt request
81  // bit 7: interrupt of 1793 (1 for interrupt)
82  // bit 6: data request of 1793 (0 for request)
83  // TODO: other bits read 0?
84  byte value = 0;
85  if ( controller.peekIRQ (time)) value |= 0x80;
86  if (!controller.peekDTRQ(time)) value |= 0x40;
87  return value;
88  }
89  default:
90  if ((0x4000 <= address) && (address < 0x8000) && !cpmRomEnabled) {
91  // MSX-DOS ROM only visible in 0x4000-0x7FFF
92  return MSXFDC::peekMem(address, time);
93  } else if ((0x4000 <= address) && (address < 0x5000) && cpmRomEnabled) {
94  // CP/M ROM only visible in 0x4000-0x4FFF
95  return cpmRom[address & 0x0FFF];
96  } else {
97  return 0xFF;
98  }
99  }
100 }
101 
102 const byte* SpectravideoFDC::getReadCacheLine(word start) const
103 {
104  if ((start & 0x3FFF & CacheLine::HIGH) == (0x3FB8 & CacheLine::HIGH)) {
105  // FDC at 0x7FB8-0x7FBF, and mirrored in other pages
106  return nullptr;
107  } else if ((0x4000 <= start) && (start < 0x8000) && !cpmRomEnabled) {
108  // MSX-DOS ROM at 0x4000-0x7FFF
109  return MSXFDC::getReadCacheLine(start);
110  } else if ((0x4000 <= start) && (start < 0x5000) && cpmRomEnabled) {
111  // CP/M ROM at 0x4000-0x4FFF
112  return &cpmRom[start & 0x0FFF];
113  } else {
114  return unmappedRead;
115  }
116 }
117 
118 void SpectravideoFDC::writeMem(word address, byte value, EmuTime::param time)
119 {
120  switch (address & 0x3FFF) {
121  case 0x3FB8:
122  controller.setCommandReg(value, time);
123  break;
124  case 0x3FB9:
125  controller.setTrackReg(value, time);
126  break;
127  case 0x3FBA:
128  controller.setSectorReg(value, time);
129  break;
130  case 0x3FBB:
131  controller.setDataReg(value, time);
132  break;
133  case 0x3FBC:
134  // bit 0 -> enable drive (1 for ENABLE)
135  // bit 2 -> side select (0 for side 0)
136  // bit 3 -> motor on (1 for ON)
138  multiplexer.setSide ((value & 0x04) != 0);
139  multiplexer.setMotor ((value & 0x08) != 0, time);
140  break;
141  case 0x3FBE: // Software switch to turn on CP/M,
142  // boot ROM and turn off MSX DOS ROM.
143  cpmRomEnabled = true;
144  break;
145  case 0x3FBF: // Software switch to turn off CP/M,
146  // boot ROM and turn on MSX DOS ROM.
147  cpmRomEnabled = false;
148  break;
149  }
150 }
151 
153 {
154  if ((address & 0x3FFF & CacheLine::HIGH) == (0x3FB8 & CacheLine::HIGH)) {
155  // FDC at 0x7FB8-0x7FBF - mirrored
156  return nullptr;
157  } else {
158  return unmappedWrite;
159  }
160 }
161 
162 template<typename Archive>
163 void SpectravideoFDC::serialize(Archive& ar, unsigned /*version*/)
164 {
165  ar.template serializeBase<WD2793BasedFDC>(*this);
166  ar.serialize("cpmRomEnabled", cpmRomEnabled);
167 }
170 
171 } // namespace openmsx
void setMotor(bool status, EmuTime::param time) override
Set motor on/off.
void selectDrive(DriveNum num, EmuTime::param time)
void setSide(bool side) override
Side select.
static byte unmappedRead[0x10000]
Definition: MSXDevice.hh:301
EmuTime::param getCurrentTime() const
Definition: MSXDevice.cc:131
static byte unmappedWrite[0x10000]
Definition: MSXDevice.hh:302
byte peekMem(word address, EmuTime::param time) const override
Read a byte from a given memory location.
Definition: MSXFDC.cc:57
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:62
unsigned getSize() const
Definition: Rom.hh:34
byte * getWriteCacheLine(word address) const override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for writing.
void reset(EmuTime::param time) override
This method is called on reset.
const byte * getReadCacheLine(word start) const override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for reading.
void serialize(Archive &ar, unsigned version)
SpectravideoFDC(const DeviceConfig &config)
byte peekMem(word address, EmuTime::param time) const override
Read a byte from a given memory location.
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.
byte readMem(word address, EmuTime::param time) override
Read a byte from a location at a certain time from this device.
DriveMultiplexer multiplexer
bool peekIRQ(EmuTime::param time) const
Definition: WD2793.cc:110
byte peekStatusReg(EmuTime::param time) const
Definition: WD2793.cc:210
byte getTrackReg(EmuTime::param time) const
Definition: WD2793.cc:221
byte getDataReg(EmuTime::param time)
Definition: WD2793.cc:260
byte getSectorReg(EmuTime::param time) const
Definition: WD2793.cc:236
bool peekDTRQ(EmuTime::param time) const
Definition: WD2793.cc:95
bool getDTRQ(EmuTime::param time) const
Definition: WD2793.cc:90
byte getStatusReg(EmuTime::param time)
Definition: WD2793.cc:170
byte peekTrackReg(EmuTime::param time) const
Definition: WD2793.cc:226
void setTrackReg(byte value, EmuTime::param time)
Definition: WD2793.cc:216
void setDataReg(byte value, EmuTime::param time)
Definition: WD2793.cc:246
byte peekDataReg(EmuTime::param time) const
Definition: WD2793.cc:325
void setCommandReg(byte value, EmuTime::param time)
Definition: WD2793.cc:122
bool getIRQ(EmuTime::param time) const
Definition: WD2793.cc:105
void setSectorReg(byte value, EmuTime::param time)
Definition: WD2793.cc:231
byte peekSectorReg(EmuTime::param time) const
Definition: WD2793.cc:241
constexpr unsigned HIGH
Definition: CacheLine.hh:10
string getName(KeyCode keyCode)
Translate key code to key name.
Definition: Keys.cc:742
This file implemented 3 utility functions:
Definition: Autofire.cc:9
REGISTER_MSXDEVICE(ChakkariCopy, "ChakkariCopy")
uint16_t word
16 bit unsigned integer
Definition: openmsx.hh:29
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:983