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 disk rom
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
32namespace openmsx {
33
34static constexpr int DRIVE_A_SELECT = 0x01;
35static constexpr int DRIVE_B_SELECT = 0x02;
36static constexpr int DRIVE_A_NOT_READY = 0x01;
37static constexpr int DRIVE_B_NOT_READY = 0x02;
38static constexpr int DISK_A_CHANGED = 0x04;
39static constexpr int DISK_B_CHANGED = 0x08;
40static constexpr int MOTOR_ON = 0x04;
41static constexpr int DATA_REQUEST = 0x40;
42static constexpr int INTR_REQUEST = 0x80;
43
44
46 : WD2793BasedFDC(config, "", true, DiskDrive::TrackMode::YAMAHA_FD_03)
47{
48 if (rom->size() != one_of(0x4000u, 0x8000u)) {
49 throw MSXException("YamahaFDC ROM size must be 16kB or 32kB.");
50 }
52}
53
54void YamahaFDC::reset(EmuTime::param time)
55{
57 writeMem(0x7FE0, 0x00, time);
58}
59
60byte 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
90byte 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->size()) {
116 return (*rom)[address - 0x4000];
117 } else {
118 return 255;
119 }
120 }
121}
122
123const 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->size()) {
129 return &(*rom)[start - 0x4000];
130 } else {
131 return unmappedRead.data();
132 }
133}
134
135void 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 auto 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
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.data();
184 }
185}
186
187template<typename Archive>
188void YamahaFDC::serialize(Archive& ar, unsigned /*version*/)
189{
190 ar.template serializeBase<WD2793BasedFDC>(*this);
191}
194
195} // namespace openmsx
#define REGISTER_MSXDEVICE(CLASS, NAME)
Definition MSXDevice.hh:356
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(Drive 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 std::array< byte, 0x10000 > unmappedRead
Definition MSXDevice.hh:306
static std::array< byte, 0x10000 > unmappedWrite
Definition MSXDevice.hh:307
EmuTime::param getCurrentTime() const
Definition MSXDevice.cc:125
std::optional< Rom > rom
Definition MSXFDC.hh:33
void reset(EmuTime::param time) override
This method is called on reset.
DriveMultiplexer multiplexer
uint8_t peekDataReg(EmuTime::param time) const
Definition WD2793.cc:314
bool peekIRQ(EmuTime::param time) const
Definition WD2793.cc:99
uint8_t getStatusReg(EmuTime::param time)
Definition WD2793.cc:159
void setTrackReg(uint8_t value, EmuTime::param time)
Definition WD2793.cc:205
void setSectorReg(uint8_t value, EmuTime::param time)
Definition WD2793.cc:220
uint8_t getTrackReg(EmuTime::param time) const
Definition WD2793.cc:210
uint8_t peekSectorReg(EmuTime::param time) const
Definition WD2793.cc:230
bool peekDTRQ(EmuTime::param time) const
Definition WD2793.cc:84
void setCommandReg(uint8_t value, EmuTime::param time)
Definition WD2793.cc:111
uint8_t peekTrackReg(EmuTime::param time) const
Definition WD2793.cc:215
bool getDTRQ(EmuTime::param time) const
Definition WD2793.cc:79
uint8_t peekStatusReg(EmuTime::param time) const
Definition WD2793.cc:199
uint8_t getDataReg(EmuTime::param time)
Definition WD2793.cc:249
void setDataReg(uint8_t value, EmuTime::param time)
Definition WD2793.cc:235
bool getIRQ(EmuTime::param time) const
Definition WD2793.cc:94
uint8_t getSectorReg(EmuTime::param time) const
Definition WD2793.cc:225
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) 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:11
uint16_t word
16 bit unsigned integer
Definition openmsx.hh:29
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)