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 constexpr int DRIVE_A_SELECT = 0x01;
35 static constexpr int DRIVE_B_SELECT = 0x02;
36 static constexpr int DRIVE_A_NOT_READY = 0x01;
37 static constexpr int DRIVE_B_NOT_READY = 0x02;
38 static constexpr int DISK_A_CHANGED = 0x04;
39 static constexpr int DISK_B_CHANGED = 0x08;
40 static constexpr int MOTOR_ON = 0x04;
41 static constexpr int DATA_REQUEST = 0x40;
42 static constexpr 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  switch (address & 0x3FFF) {
63  case 0x3FC0:
64  return controller.getStatusReg(time);
65  case 0x3FC1:
66  return controller.getTrackReg(time);
67  case 0x3FC2:
68  return controller.getSectorReg(time);
69  case 0x3FC3:
70  return controller.getDataReg(time);
71  case 0x3FE0: {
72  byte value = 0;
73  if (!multiplexer.isDiskInserted(DriveMultiplexer::DRIVE_A)) value |= DRIVE_A_NOT_READY;
74  if (!multiplexer.isDiskInserted(DriveMultiplexer::DRIVE_B)) value |= DRIVE_B_NOT_READY;
75  // note: peekDiskChanged() instead of diskChanged() because we don't want an implicit reset
76  if (multiplexer.peekDiskChanged(DriveMultiplexer::DRIVE_A)) value |= DISK_A_CHANGED;
77  if (multiplexer.peekDiskChanged(DriveMultiplexer::DRIVE_B)) value |= DISK_B_CHANGED;
78  if (controller.getIRQ(time)) value |= INTR_REQUEST;
79  if (controller.getDTRQ(time)) value |= DATA_REQUEST;
80  return value;
81  }
82  case 0x3FF0:
84  [[fallthrough]];
85  default:
86  return peekMem(address, time);
87  }
88 }
89 
90 byte YamahaFDC::peekMem(word address, EmuTime::param time) const
91 {
92  switch (address & 0x3FFF) {
93  case 0x3FC0:
94  return controller.peekStatusReg(time);
95  case 0x3FC1:
96  return controller.peekTrackReg(time);
97  case 0x3FC2:
98  return controller.peekSectorReg(time);
99  case 0x3FC3:
100  return controller.peekDataReg(time);
101  case 0x3FE0: {
102  byte value = 0;
103  if (!multiplexer.isDiskInserted(DriveMultiplexer::DRIVE_A)) value |= DRIVE_A_NOT_READY;
104  if (!multiplexer.isDiskInserted(DriveMultiplexer::DRIVE_B)) value |= DRIVE_B_NOT_READY;
105  if (multiplexer.peekDiskChanged(DriveMultiplexer::DRIVE_A)) value |= DISK_A_CHANGED;
106  if (multiplexer.peekDiskChanged(DriveMultiplexer::DRIVE_B)) value |= DISK_B_CHANGED;
107  if (controller.peekIRQ(time)) value |= INTR_REQUEST;
108  if (controller.peekDTRQ(time)) value |= DATA_REQUEST;
109  return value;
110  }
111  case 0x3FF0:
112  // don't clear on peek
113  [[fallthrough]];
114  default:
115  if (unsigned(address - 0x4000) < rom->getSize()) {
116  return (*rom)[address - 0x4000];
117  } else {
118  return 255;
119  }
120  }
121 }
122 
123 const byte* YamahaFDC::getReadCacheLine(word start) const
124 {
125  if ((start & 0x3FFF & CacheLine::HIGH) == (0x3FC0 & CacheLine::HIGH)) {
126  // FDC at 0x7FC0-0x7FFF or 0xBFC0-0xBFFF
127  return nullptr;
128  } else if (unsigned(start - 0x4000) < rom->getSize()) {
129  return &(*rom)[start - 0x4000];
130  } else {
131  return unmappedRead;
132  }
133 }
134 
135 void YamahaFDC::writeMem(word address, byte value, EmuTime::param time)
136 {
137  switch (address & 0x3fff) {
138  case 0x3FC0:
139  controller.setCommandReg(value, time);
140  break;
141  case 0x3FC1:
142  controller.setTrackReg(value, time);
143  break;
144  case 0x3FC2:
145  controller.setSectorReg(value, time);
146  break;
147  case 0x3FC3:
148  controller.setDataReg(value, time);
149  break;
150  case 0x3FE0: {
151  DriveMultiplexer::DriveNum drive = [&] {
152  switch (value & (DRIVE_A_SELECT | DRIVE_B_SELECT)) {
153  case DRIVE_A_SELECT:
155  case DRIVE_B_SELECT:
157  default:
158  // No drive selected or two drives at same time
159  // The motor is enabled for all drives at the same time, so
160  // in a real machine you must take care to do not select more
161  // than one drive at the same time (you could get data
162  // collision).
164  }
165  }();
166  multiplexer.selectDrive(drive, time);
167  multiplexer.setSide(false);
168  multiplexer.setMotor((value & MOTOR_ON) != 0, time);
169  break;
170  }
171  case 0x3FF0:
173  break;
174  }
175 }
176 
177 byte* YamahaFDC::getWriteCacheLine(word address) const
178 {
179  if ((address & 0x3FFF & CacheLine::HIGH) == (0x3FC0 & CacheLine::HIGH)) {
180  // FDC at 0x7FC0-0x7FFF or 0xBFC0-0xBFFF
181  return nullptr;
182  } else {
183  return unmappedWrite;
184  }
185 }
186 
187 template<typename Archive>
188 void YamahaFDC::serialize(Archive& ar, unsigned /*version*/)
189 {
190  ar.template serializeBase<WD2793BasedFDC>(*this);
191 }
194 
195 } // namespace openmsx
Definition: one_of.hh:7
This (abstract) class defines the DiskDrive interface.
Definition: DiskDrive.hh:13
void setMotor(bool status, EmuTime::param time) override
Set motor on/off.
bool peekDiskChanged() const override
void selectDrive(DriveNum num, EmuTime::param time)
bool isDiskInserted() const override
Is drive ready?
bool diskChanged() override
Is disk changed?
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
std::unique_ptr< Rom > rom
Definition: MSXFDC.hh:31
void reset(EmuTime::param time) override
This method is called on reset.
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
void serialize(Archive &ar, unsigned version)
Definition: YamahaFDC.cc:188
void reset(EmuTime::param time) override
This method is called on reset.
Definition: YamahaFDC.cc:54
byte * getWriteCacheLine(word address) const override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for writing.
Definition: YamahaFDC.cc:177
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:123
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
byte peekMem(word address, EmuTime::param time) const override
Read a byte from a given memory location.
Definition: YamahaFDC.cc:90
YamahaFDC(const DeviceConfig &config)
Definition: YamahaFDC.cc:45
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:135
constexpr unsigned HIGH
Definition: CacheLine.hh:10
This file implemented 3 utility functions:
Definition: Autofire.cc:9
constexpr int DATA_REQUEST
Definition: VictorFDC.cc:31
REGISTER_MSXDEVICE(ChakkariCopy, "ChakkariCopy")
uint16_t word
16 bit unsigned integer
Definition: openmsx.hh:29
constexpr int INTR_REQUEST
Definition: VictorFDC.cc:32
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:983