openMSX
YamahaFDC.cc
Go to the documentation of this file.
1 #include "YamahaFDC.hh"
2 #include "CacheLine.hh"
3 #include "DriveMultiplexer.hh"
4 #include "MSXException.hh"
5 #include "Rom.hh"
6 #include "WD2793.hh"
7 #include "one_of.hh"
8 #include "serialize.hh"
9 
10 // This is derived by disassembly of the Yamaha FD-03 diskrom
11 // https://sourceforge.net/p/msxsyssrc/git/ci/master/tree/diskdrvs/fd-03/
12 //
13 // FDD interface:
14 // 7FC0 I/O FDC STATUS/COMMAND
15 // 7FC1 I/O FDC TRACK REGISTER
16 // 7FC2 I/O FDC SECTOR REGISTER
17 // 7FC3 I/O FDC DATA REGISTER
18 // 7FE0 O bit 0 SELECT DRIVE A "1" ON
19 // I bit 0 READY DRIVE A "0" READY, "1" NOT READY
20 // O bit 1 SELECT DRIVE B "1" ON
21 // I bit 1 READY DRIVE B "0" READY, "1" NOT READY
22 // O bit 2 MOTOR "1" ON
23 // I bit 2 DISK CHANGE DRIVE A "1" CHANGED
24 // O bit 3 UNKNOWN FUNCTION
25 // I bit 3 DISK CHANGE DRIVE B "1" CHANGED
26 // I bit 6 FDC DATA REQUEST "1" REQUEST
27 // I bit 7 FDC INTERRUPT REQUEST "1" REQUEST
28 //
29 // 7FF0 O RESET DISK CHANGE DRIVE A
30 // I RESET DISK CHANGE DRIVE B
31 
32 namespace openmsx {
33 
34 static const int DRIVE_A_SELECT = 0x01;
35 static const int DRIVE_B_SELECT = 0x02;
36 static const int DRIVE_A_NOT_READY = 0x01;
37 static const int DRIVE_B_NOT_READY = 0x02;
38 static const int DISK_A_CHANGED = 0x04;
39 static const int DISK_B_CHANGED = 0x08;
40 static const int MOTOR_ON = 0x04;
41 static const int DATA_REQUEST = 0x40;
42 static const int INTR_REQUEST = 0x80;
43 
44 
46  : WD2793BasedFDC(config, "", true, DiskDrive::TrackMode::YAMAHA_FD_03)
47 {
48  if (rom->getSize() != one_of(0x4000u, 0x8000u)) {
49  throw MSXException("YamahaFDC ROM size must be 16kB or 32kB.");
50  }
52 }
53 
54 void YamahaFDC::reset(EmuTime::param time)
55 {
57  writeMem(0x7FE0, 0x00, time);
58 }
59 
60 byte YamahaFDC::readMem(word address, EmuTime::param time)
61 {
62  byte value;
63  switch (address & 0x3FFF) {
64  case 0x3FC0:
65  value = controller.getStatusReg(time);
66  break;
67  case 0x3FC1:
68  value = controller.getTrackReg(time);
69  break;
70  case 0x3FC2:
71  value = controller.getSectorReg(time);
72  break;
73  case 0x3FC3:
74  value = controller.getDataReg(time);
75  break;
76  case 0x3FE0:
77  value = 0;
78  if (!multiplexer.isDiskInserted(DriveMultiplexer::DRIVE_A)) value |= DRIVE_A_NOT_READY;
79  if (!multiplexer.isDiskInserted(DriveMultiplexer::DRIVE_B)) value |= DRIVE_B_NOT_READY;
80  // note: peekDiskChanged() instead of diskChanged() because we don't want an implicit reset
81  if (multiplexer.peekDiskChanged(DriveMultiplexer::DRIVE_A)) value |= DISK_A_CHANGED;
82  if (multiplexer.peekDiskChanged(DriveMultiplexer::DRIVE_B)) value |= DISK_B_CHANGED;
83  if (controller.getIRQ(time)) value |= INTR_REQUEST;
84  if (controller.getDTRQ(time)) value |= DATA_REQUEST;
85  break;
86  case 0x3FF0:
88  value = peekMem(address, time);
89  break;
90  default:
91  value = peekMem(address, time);
92  break;
93  }
94  return value;
95 }
96 
97 byte YamahaFDC::peekMem(word address, EmuTime::param time) const
98 {
99  byte value;
100  switch (address & 0x3FFF) {
101  case 0x3FC0:
102  value = controller.peekStatusReg(time);
103  break;
104  case 0x3FC1:
105  value = controller.peekTrackReg(time);
106  break;
107  case 0x3FC2:
108  value = controller.peekSectorReg(time);
109  break;
110  case 0x3FC3:
111  value = controller.peekDataReg(time);
112  break;
113  case 0x3FE0:
114  value = 0;
115  if (!multiplexer.isDiskInserted(DriveMultiplexer::DRIVE_A)) value |= DRIVE_A_NOT_READY;
116  if (!multiplexer.isDiskInserted(DriveMultiplexer::DRIVE_B)) value |= DRIVE_B_NOT_READY;
117  if (multiplexer.peekDiskChanged(DriveMultiplexer::DRIVE_A)) value |= DISK_A_CHANGED;
118  if (multiplexer.peekDiskChanged(DriveMultiplexer::DRIVE_B)) value |= DISK_B_CHANGED;
119  if (controller.peekIRQ(time)) value |= INTR_REQUEST;
120  if (controller.peekDTRQ(time)) value |= DATA_REQUEST;
121  break;
122  case 0x3FF0:
123  // don't clear on peek
124  [[fallthrough]];
125  default:
126  if (unsigned(address - 0x4000) < rom->getSize()) {
127  value = (*rom)[address - 0x4000];
128  } else {
129  value = 255;
130  }
131  break;
132  }
133  return value;
134 }
135 
136 const byte* YamahaFDC::getReadCacheLine(word start) const
137 {
138  if ((start & 0x3FFF & CacheLine::HIGH) == (0x3FC0 & CacheLine::HIGH)) {
139  // FDC at 0x7FC0-0x7FFF or 0xBFC0-0xBFFF
140  return nullptr;
141  } else if (unsigned(start - 0x4000) < rom->getSize()) {
142  return &(*rom)[start - 0x4000];
143  } else {
144  return unmappedRead;
145  }
146 }
147 
148 void YamahaFDC::writeMem(word address, byte value, EmuTime::param time)
149 {
150  switch (address & 0x3fff) {
151  case 0x3FC0:
152  controller.setCommandReg(value, time);
153  break;
154  case 0x3FC1:
155  controller.setTrackReg(value, time);
156  break;
157  case 0x3FC2:
158  controller.setSectorReg(value, time);
159  break;
160  case 0x3FC3:
161  controller.setDataReg(value, time);
162  break;
163  case 0x3FE0:
165  switch (value & (DRIVE_A_SELECT | DRIVE_B_SELECT)) {
166  case DRIVE_A_SELECT:
168  break;
169  case DRIVE_B_SELECT:
171  break;
172  default:
173  // No drive selected or two drives at same time
174  // The motor is enabled for all drives at the same time, so
175  // in a real machine you must take care to do not select more
176  // than one drive at the same time (you could get data
177  // collision).
179  }
180  multiplexer.selectDrive(drive, time);
181  multiplexer.setSide(false);
182  multiplexer.setMotor((value & MOTOR_ON) != 0, time);
183  break;
184  case 0x3FF0:
186  break;
187  }
188 }
189 
190 byte* YamahaFDC::getWriteCacheLine(word address) const
191 {
192  if ((address & 0x3FFF & CacheLine::HIGH) == (0x3FC0 & CacheLine::HIGH)) {
193  // FDC at 0x7FC0-0x7FFF or 0xBFC0-0xBFFF
194  return nullptr;
195  } else {
196  return unmappedWrite;
197  }
198 }
199 
200 template<typename Archive>
201 void YamahaFDC::serialize(Archive& ar, unsigned /*version*/)
202 {
203  ar.template serializeBase<WD2793BasedFDC>(*this);
204 }
207 
208 } // namespace openmsx
one_of.hh
openmsx::WD2793BasedFDC::multiplexer
DriveMultiplexer multiplexer
Definition: WD2793BasedFDC.hh:25
openmsx::YamahaFDC::readMem
byte readMem(word address, EmuTime::param time) override
Read a byte from a location at a certain time from this device.
Definition: YamahaFDC.cc:60
serialize.hh
Rom.hh
openmsx::DriveMultiplexer::peekDiskChanged
bool peekDiskChanged() const override
Definition: DriveMultiplexer.cc:125
openmsx::DiskDrive
This (abstract) class defines the DiskDrive interface.
Definition: DiskDrive.hh:13
openmsx::INTR_REQUEST
constexpr int INTR_REQUEST
Definition: VictorFDC.cc:32
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::WD2793::getIRQ
bool getIRQ(EmuTime::param time)
Definition: WD2793.cc:105
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
MSXException.hh
openmsx::MSXException
Definition: MSXException.hh:10
openmsx::YamahaFDC::getReadCacheLine
const byte * getReadCacheLine(word start) const override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for reading.
Definition: YamahaFDC.cc:136
openmsx::WD2793::getStatusReg
byte getStatusReg(EmuTime::param time)
Definition: WD2793.cc:170
openmsx::YamahaFDC::reset
void reset(EmuTime::param time) override
This method is called on reset.
Definition: YamahaFDC.cc:54
openmsx::CacheLine::HIGH
constexpr unsigned HIGH
Definition: CacheLine.hh:10
openmsx::WD2793BasedFDC
Definition: WD2793BasedFDC.hh:12
openmsx::YamahaFDC::serialize
void serialize(Archive &ar, unsigned version)
Definition: YamahaFDC.cc:201
openmsx::DriveMultiplexer::setMotor
void setMotor(bool status, EmuTime::param time) override
Set motor on/off.
Definition: DriveMultiplexer.cc:69
openmsx::YamahaFDC::YamahaFDC
YamahaFDC(const DeviceConfig &config)
Definition: YamahaFDC.cc:45
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::YamahaFDC::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: YamahaFDC.cc:148
openmsx::WD2793BasedFDC::reset
void reset(EmuTime::param time) override
This method is called on reset.
Definition: WD2793BasedFDC.cc:17
openmsx::DriveMultiplexer::DRIVE_B
@ DRIVE_B
Definition: DriveMultiplexer.hh:17
openmsx::WD2793::getSectorReg
byte getSectorReg(EmuTime::param time)
Definition: WD2793.cc:236
openmsx::MSXDevice::getCurrentTime
EmuTime::param getCurrentTime() const
Definition: MSXDevice.cc:131
openmsx::YamahaFDC
Definition: YamahaFDC.hh:9
openmsx::DriveMultiplexer::isDiskInserted
bool isDiskInserted() const override
Is drive ready?
Definition: DriveMultiplexer.cc:28
one_of
Definition: one_of.hh:7
INSTANTIATE_SERIALIZE_METHODS
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:981
YamahaFDC.hh
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::DATA_REQUEST
constexpr int DATA_REQUEST
Definition: VictorFDC.cc:31
DriveMultiplexer.hh
WD2793.hh
openmsx::MSXFDC::rom
std::unique_ptr< Rom > rom
Definition: MSXFDC.hh:30
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::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::YamahaFDC::peekMem
byte peekMem(word address, EmuTime::param time) const override
Read a byte from a given memory location.
Definition: YamahaFDC.cc:97
openmsx::DriveMultiplexer::DriveNum
DriveNum
Definition: DriveMultiplexer.hh:15
openmsx::WD2793::peekDataReg
byte peekDataReg(EmuTime::param time) const
Definition: WD2793.cc:325
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
openmsx::YamahaFDC::getWriteCacheLine
byte * getWriteCacheLine(word address) const override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for writing.
Definition: YamahaFDC.cc:190