openMSX
ToshibaFDC.cc
Go to the documentation of this file.
1 #include "ToshibaFDC.hh"
2 #include "CacheLine.hh"
3 #include "DriveMultiplexer.hh"
4 #include "WD2793.hh"
5 #include "serialize.hh"
6 
7 // Based on studying the code in the Toshiba disk ROM.
8 // Thanks to Arjen Zeilemaker for an annotated disassembly:
9 // https://sourceforge.net/p/msxsyssrc/git/ci/master/tree/diskdrvs/hx-f101/driver.mac
10 // https://sourceforge.net/p/msxsyssrc/git/ci/master/tree/diskdrvs/hx-34/driver.mac
11 
12 namespace openmsx {
13 
15  : WD2793BasedFDC(config)
16 {
17 }
18 
19 byte ToshibaFDC::readMem(word address, EmuTime::param time)
20 {
21  byte value;
22  switch (address) {
23  case 0x7FF0:
24  value = controller.getStatusReg(time);
25  break;
26  case 0x7FF1:
27  value = controller.getTrackReg(time);
28  break;
29  case 0x7FF2:
30  value = controller.getSectorReg(time);
31  break;
32  case 0x7FF3:
33  value = controller.getDataReg(time);
34  break;
35  case 0x7FF6:
36  value = 0xFE | (multiplexer.diskChanged() ? 0 : 1);
37  break;
38  case 0x7FF7:
39  value = 0xFF;
40  if (controller.getIRQ(time)) value &= ~0x40;
41  if (controller.getDTRQ(time)) value &= ~0x80;
42  break;
43  default:
44  value = ToshibaFDC::peekMem(address, time);
45  break;
46  }
47  return value;
48 }
49 
50 byte ToshibaFDC::peekMem(word address, EmuTime::param time) const
51 {
52  byte value;
53  switch (address) { // checked on real HW: no mirroring
54  case 0x7FF0:
55  value = controller.peekStatusReg(time);
56  break;
57  case 0x7FF1:
58  value = controller.peekTrackReg(time);
59  break;
60  case 0x7FF2:
61  value = controller.peekSectorReg(time);
62  break;
63  case 0x7FF3:
64  value = controller.peekDataReg(time);
65  break;
66  case 0x7FF4:
67  // ToshibaFDC HX-F101 disk ROM doesn't read this, but HX-34
68  // does. No idea if this location is actually readable on
69  // HX-F101, but currently the emulation is the same for both.
70  value = 0xFC
71  | (multiplexer.getSide() ? 1 : 0)
72  | (multiplexer.getMotor() ? 2 : 0);
73  break;
74  case 0x7FF5:
75  value = 0xFE | ((multiplexer.getSelectedDrive() == DriveMultiplexer::DRIVE_B) ? 1 : 0);
76  break;
77  case 0x7FF6:
78  value = 0xFE | (multiplexer.peekDiskChanged() ? 0 : 1);
79  break;
80  case 0x7FF7:
81  value = 0xFF; // unused bits read as 1
82  if (controller.peekIRQ(time)) value &= ~0x40;
83  if (controller.peekDTRQ(time)) value &= ~0x80;
84  break;
85  default:
86  if (0x4000 <= address && address < 0x8000) {
87  // ROM only visible in 0x4000-0x7FFF.
88  value = MSXFDC::peekMem(address, time);
89  } else {
90  value = 0xFF;
91  }
92  break;
93  }
94  return value;
95 }
96 
97 const byte* ToshibaFDC::getReadCacheLine(word start) const
98 {
99  if ((start & CacheLine::HIGH) == (0x7FF0 & CacheLine::HIGH)) {
100  // FDC at 0x7FF0-0x7FF7
101  return nullptr;
102  } else if (0x4000 <= start && start < 0x8000) {
103  // ROM at 0x4000-0x7FFF
104  return MSXFDC::getReadCacheLine(start);
105  } else {
106  return unmappedRead;
107  }
108 }
109 
110 void ToshibaFDC::writeMem(word address, byte value, EmuTime::param time)
111 {
112  switch (address) {
113  case 0x7FF0:
114  controller.setCommandReg(value, time);
115  break;
116  case 0x7FF1:
117  controller.setTrackReg(value, time);
118  break;
119  case 0x7FF2:
120  controller.setSectorReg(value, time);
121  break;
122  case 0x7FF3:
123  controller.setDataReg(value, time);
124  break;
125  case 0x7FF4:
126  multiplexer.setSide((value & 0x01) != 0); // no effect on HX-F101 because it has single sided drive
127  multiplexer.setMotor((value & 0x02) != 0, time);
128  break;
129  case 0x7FF5:
130  // Disk ROM only writes the values 0 or 1.
133  time);
134  break;
135  case 0x7FF6:
136  // Disk ROM writes '1' (to drive A) and shortly after '0' (to drive B).
137  // TODO What does this do? Activate the 'disk is changed' state?
138  // And if so, does the written value matter?
139  break;
140  case 0x7FF7:
141  // Probably no function, disk ROM doesn't write to this address.
142  break;
143  }
144 }
145 
147 {
148  if ((address & CacheLine::HIGH) == (0x7FF0 & CacheLine::HIGH)) {
149  return nullptr;
150  } else {
151  return unmappedWrite;
152  }
153 }
154 
155 template<typename Archive>
156 void ToshibaFDC::serialize(Archive& ar, unsigned /*version*/)
157 {
158  ar.template serializeBase<WD2793BasedFDC>(*this);
159 }
162 
163 } // 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
ToshibaFDC.hh
serialize.hh
openmsx::DriveMultiplexer::peekDiskChanged
bool peekDiskChanged() const override
Definition: DriveMultiplexer.cc:125
openmsx::WD2793BasedFDC::controller
WD2793 controller
Definition: WD2793BasedFDC.hh:26
openmsx::DeviceConfig
Definition: DeviceConfig.hh:20
openmsx::DriveMultiplexer::getMotor
bool getMotor() const override
Returns the previously set motor status.
Definition: DriveMultiplexer.cc:75
openmsx::MSXDevice::unmappedWrite
static byte unmappedWrite[0x10000]
Definition: MSXDevice.hh:301
openmsx::WD2793::getIRQ
bool getIRQ(EmuTime::param time)
Definition: WD2793.cc:105
openmsx::ToshibaFDC::ToshibaFDC
ToshibaFDC(const DeviceConfig &config)
Definition: ToshibaFDC.cc:14
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
openmsx::WD2793::peekIRQ
bool peekIRQ(EmuTime::param time) const
Definition: WD2793.cc:110
openmsx::ToshibaFDC::getReadCacheLine
const byte * getReadCacheLine(word start) const override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for reading.
Definition: ToshibaFDC.cc:97
openmsx::WD2793::getStatusReg
byte getStatusReg(EmuTime::param time)
Definition: WD2793.cc:170
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::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::DriveMultiplexer::DRIVE_B
@ DRIVE_B
Definition: DriveMultiplexer.hh:17
openmsx::ToshibaFDC::getWriteCacheLine
byte * getWriteCacheLine(word address) const override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for writing.
Definition: ToshibaFDC.cc:146
openmsx::WD2793::getSectorReg
byte getSectorReg(EmuTime::param time)
Definition: WD2793.cc:236
openmsx::ToshibaFDC
Definition: ToshibaFDC.hh:9
openmsx::ToshibaFDC::peekMem
byte peekMem(word address, EmuTime::param time) const override
Read a byte from a given memory location.
Definition: ToshibaFDC.cc:50
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::ToshibaFDC::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: ToshibaFDC.cc:110
DriveMultiplexer.hh
WD2793.hh
openmsx::ToshibaFDC::serialize
void serialize(Archive &ar, unsigned version)
Definition: ToshibaFDC.cc:156
openmsx::MSXDevice::unmappedRead
static byte unmappedRead[0x10000]
Definition: MSXDevice.hh:300
openmsx::DriveMultiplexer::getSide
bool getSide() const override
Definition: DriveMultiplexer.cc:54
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::DriveMultiplexer::getSelectedDrive
DriveNum getSelectedDrive() const
Definition: DriveMultiplexer.hh:27
openmsx::DriveMultiplexer::selectDrive
void selectDrive(DriveNum num, EmuTime::param time)
Definition: DriveMultiplexer.cc:18
openmsx::WD2793::setCommandReg
void setCommandReg(byte value, EmuTime::param time)
Definition: WD2793.cc:122
openmsx::ToshibaFDC::readMem
byte readMem(word address, EmuTime::param time) override
Read a byte from a location at a certain time from this device.
Definition: ToshibaFDC.cc:19
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::DriveMultiplexer::diskChanged
bool diskChanged() override
Is disk changed?
Definition: DriveMultiplexer.cc:115
openmsx::WD2793::setTrackReg
void setTrackReg(byte value, EmuTime::param time)
Definition: WD2793.cc:216
openmsx
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:5