openMSX
VictorFDC.cc
Go to the documentation of this file.
1 #include "VictorFDC.hh"
2 #include "CacheLine.hh"
3 #include "DriveMultiplexer.hh"
4 #include "WD2793.hh"
5 #include "serialize.hh"
6 
7 // This implementation is documented in the HC-95 service manual:
8 //
9 // FDD interface:
10 // 7FF8 I/O FDC STATUS/COMMAND
11 // 7FF9 I/O FDC TRACK REGISTER
12 // 7FFA I/O FDC SECTOR REGISTER
13 // 7FFB I/O FDC DATA REGISTER
14 // 7FFC I/O bit 0 A DRIVE MOTOR ON/OFF "1" ON
15 // I/O bit 1 B DRIVE MOTOR ON/OFF "1" ON
16 // I/O bit 2 DRIVE SELECT "0" A DRIVE "1" B DRIVE
17 // O bit 3 SIDE SELECT "0" SIDE 0 "1" SIDE 1
18 // I SIDE SELECT "1" SIDE 0 "0" SIDE 1
19 // I/O bit 4 DRIVE ENABLE "0" ENABLE
20 // bit 5 unused
21 // I bit 6 FDC DATA REQUEST "1" REQUEST
22 // I bit 7 FDC INTERRUPT REQUEST "1" REQUEST
23 
24 namespace openmsx {
25 
26 constexpr int DRIVE_A_MOTOR = 0x01;
27 constexpr int DRIVE_B_MOTOR = 0x02;
28 constexpr int DRIVE_SELECT = 0x04;
29 constexpr int SIDE_SELECT = 0x08;
30 constexpr int DRIVE_DISABLE = 0x10; // renamed due to inverse logic
31 constexpr int DATA_REQUEST = 0x40;
32 constexpr int INTR_REQUEST = 0x80;
33 
34 
36  : WD2793BasedFDC(config)
37 {
39 }
40 
41 void VictorFDC::reset(EmuTime::param time)
42 {
44  // initialize in such way that drives are disabled
45  // (and motors off, etc.)
46  // TODO: test on real machine (this is an assumption)
47  writeMem(0x7FFC, DRIVE_DISABLE, time);
48 }
49 
50 byte VictorFDC::readMem(word address, EmuTime::param time)
51 {
52  byte value;
53  switch (address) {
54  case 0x7FF8:
55  value = controller.getStatusReg(time);
56  break;
57  case 0x7FF9:
58  value = controller.getTrackReg(time);
59  break;
60  case 0x7FFA:
61  value = controller.getSectorReg(time);
62  break;
63  case 0x7FFB:
64  value = controller.getDataReg(time);
65  break;
66  case 0x7FFC:
67  value = driveControls;
68  if (controller.getIRQ(time)) value |= INTR_REQUEST;
69  if (controller.getDTRQ(time)) value |= DATA_REQUEST;
70  value ^= SIDE_SELECT; // inverted
71  break;
72  default:
73  value = VictorFDC::peekMem(address, time);
74  break;
75  }
76  return value;
77 }
78 
79 byte VictorFDC::peekMem(word address, EmuTime::param time) const
80 {
81  byte value;
82  switch (address) {
83  case 0x7FF8:
84  value = controller.peekStatusReg(time);
85  break;
86  case 0x7FF9:
87  value = controller.peekTrackReg(time);
88  break;
89  case 0x7FFA:
90  value = controller.peekSectorReg(time);
91  break;
92  case 0x7FFB:
93  value = controller.peekDataReg(time);
94  break;
95  case 0x7FFC:
96  value = driveControls;
97  if (controller.peekIRQ(time)) value |= INTR_REQUEST;
98  if (controller.peekDTRQ(time)) value |= DATA_REQUEST;
99  value ^= SIDE_SELECT; // inverted
100  break;
101  default:
102  if ((0x4000 <= address) && (address < 0x8000)) {
103  // ROM only visible in 0x4000-0x7FFF
104  value = MSXFDC::peekMem(address, time);
105  } else {
106  value = 255;
107  }
108  break;
109  }
110  return value;
111 }
112 
113 const byte* VictorFDC::getReadCacheLine(word start) const
114 {
115  if ((start & CacheLine::HIGH) == (0x7FF8 & CacheLine::HIGH)) {
116  // FDC at 0x7FF8-0x7FFC
117  return nullptr;
118  } else if ((0x4000 <= start) && (start < 0x8000)) {
119  // ROM at 0x4000-0x7FFF
120  return MSXFDC::getReadCacheLine(start);
121  } else {
122  return unmappedRead;
123  }
124 }
125 
126 void VictorFDC::writeMem(word address, byte value, EmuTime::param time)
127 {
128  switch (address) {
129  case 0x7FF8:
130  controller.setCommandReg(value, time);
131  break;
132  case 0x7FF9:
133  controller.setTrackReg(value, time);
134  break;
135  case 0x7FFA:
136  controller.setSectorReg(value, time);
137  break;
138  case 0x7FFB:
139  controller.setDataReg(value, time);
140  break;
141  case 0x7FFC:
143  if ((value & DRIVE_DISABLE) != 0) {
145  } else {
147  }
148  multiplexer.selectDrive(drive, time);
149  multiplexer.setSide((value & SIDE_SELECT) != 0);
150  multiplexer.setMotor((drive == DriveMultiplexer::DRIVE_A) ? ((value & DRIVE_A_MOTOR) != 0) : ((value & DRIVE_B_MOTOR) != 0), time); // this is not 100% correct: the motors can be controlled independently via bit 0 and 1
151  // back up for reading:
152  driveControls = value & (DRIVE_A_MOTOR | DRIVE_B_MOTOR | DRIVE_SELECT | SIDE_SELECT | DRIVE_DISABLE);
153  break;
154  }
155 }
156 
157 byte* VictorFDC::getWriteCacheLine(word address) const
158 {
159  if ((address & CacheLine::HIGH) == (0x7FF8 & CacheLine::HIGH)) {
160  // FDC at 0x7FF8-0x7FFC
161  return nullptr;
162  } else {
163  return unmappedWrite;
164  }
165 }
166 
168 {
169  // OK, because this device doesn't call any 'fillDeviceXXXCache()'functions.
170  return true;
171 }
172 
173 
174 template<typename Archive>
175 void VictorFDC::serialize(Archive& ar, unsigned /*version*/)
176 {
177  ar.template serializeBase<WD2793BasedFDC>(*this);
178  ar.serialize("driveControls", driveControls);
179 }
182 
183 } // 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
openmsx::SIDE_SELECT
constexpr int SIDE_SELECT
Definition: VictorFDC.cc:29
openmsx::VictorFDC::readMem
byte readMem(word address, EmuTime::param time) override
Read a byte from a location at a certain time from this device.
Definition: VictorFDC.cc:50
serialize.hh
openmsx::VictorFDC::serialize
void serialize(Archive &ar, unsigned version)
Definition: VictorFDC.cc:175
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::VictorFDC::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: VictorFDC.cc:126
openmsx::MSXDevice::unmappedWrite
static byte unmappedWrite[0x10000]
Definition: MSXDevice.hh:301
openmsx::WD2793::getIRQ
bool getIRQ(EmuTime::param time)
Definition: WD2793.cc:105
VictorFDC.hh
openmsx::VictorFDC::peekMem
byte peekMem(word address, EmuTime::param time) const override
Read a byte from a given memory location.
Definition: VictorFDC.cc:79
openmsx::VictorFDC::getWriteCacheLine
byte * getWriteCacheLine(word address) const override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for writing.
Definition: VictorFDC.cc:157
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::WD2793::getStatusReg
byte getStatusReg(EmuTime::param time)
Definition: WD2793.cc:170
openmsx::DRIVE_SELECT
constexpr int DRIVE_SELECT
Definition: VictorFDC.cc:28
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::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::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::VictorFDC
Definition: VictorFDC.hh:9
openmsx::WD2793::getSectorReg
byte getSectorReg(EmuTime::param time)
Definition: WD2793.cc:236
openmsx::MSXDevice::getCurrentTime
EmuTime::param getCurrentTime() const
Definition: MSXDevice.cc:131
INSTANTIATE_SERIALIZE_METHODS
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:981
openmsx::DriveMultiplexer::DRIVE_A
@ DRIVE_A
Definition: DriveMultiplexer.hh:16
openmsx::VictorFDC::allowUnaligned
bool allowUnaligned() const override
By default we don't allow unaligned <mem> specifications in the config file.
Definition: VictorFDC.cc:167
openmsx::WD2793::setDataReg
void setDataReg(byte value, EmuTime::param time)
Definition: WD2793.cc:246
CacheLine.hh
openmsx::VictorFDC::getReadCacheLine
const byte * getReadCacheLine(word start) const override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for reading.
Definition: VictorFDC.cc:113
openmsx::DATA_REQUEST
constexpr int DATA_REQUEST
Definition: VictorFDC.cc:31
openmsx::VictorFDC::VictorFDC
VictorFDC(const DeviceConfig &config)
Definition: VictorFDC.cc:35
openmsx::DRIVE_DISABLE
constexpr int DRIVE_DISABLE
Definition: VictorFDC.cc:30
DriveMultiplexer.hh
WD2793.hh
openmsx::DRIVE_B_MOTOR
constexpr int DRIVE_B_MOTOR
Definition: VictorFDC.cc:27
openmsx::DRIVE_A_MOTOR
constexpr int DRIVE_A_MOTOR
Definition: VictorFDC.cc:26
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::DriveMultiplexer::DriveNum
DriveNum
Definition: DriveMultiplexer.hh:15
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::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::VictorFDC::reset
void reset(EmuTime::param time) override
This method is called on reset.
Definition: VictorFDC.cc:41