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
24namespace openmsx {
25
26static constexpr int DRIVE_A_MOTOR = 0x01;
27static constexpr int DRIVE_B_MOTOR = 0x02;
28static constexpr int DRIVE_SELECT = 0x04;
29static constexpr int SIDE_SELECT = 0x08;
30static constexpr int DRIVE_DISABLE = 0x10; // renamed due to inverse logic
31static constexpr int DATA_REQUEST = 0x40;
32static constexpr int INTR_REQUEST = 0x80;
33
34
36 : WD2793BasedFDC(config)
37{
39}
40
41void 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
50byte VictorFDC::readMem(word address, EmuTime::param time)
51{
52 switch (address) {
53 case 0x7FF8:
54 return controller.getStatusReg(time);
55 case 0x7FF9:
56 return controller.getTrackReg(time);
57 case 0x7FFA:
58 return controller.getSectorReg(time);
59 case 0x7FFB:
60 return controller.getDataReg(time);
61 case 0x7FFC: {
62 byte value = driveControls;
63 if (controller.getIRQ(time)) value |= INTR_REQUEST;
64 if (controller.getDTRQ(time)) value |= DATA_REQUEST;
65 value ^= SIDE_SELECT; // inverted
66 return value;
67 }
68 default:
69 return VictorFDC::peekMem(address, time);
70 }
71}
72
73byte VictorFDC::peekMem(word address, EmuTime::param time) const
74{
75 switch (address) {
76 case 0x7FF8:
77 return controller.peekStatusReg(time);
78 case 0x7FF9:
79 return controller.peekTrackReg(time);
80 case 0x7FFA:
81 return controller.peekSectorReg(time);
82 case 0x7FFB:
83 return controller.peekDataReg(time);
84 case 0x7FFC: {
85 byte value = driveControls;
86 if (controller.peekIRQ(time)) value |= INTR_REQUEST;
87 if (controller.peekDTRQ(time)) value |= DATA_REQUEST;
88 value ^= SIDE_SELECT; // inverted
89 return value;
90 }
91 default:
92 if ((0x4000 <= address) && (address < 0x8000)) {
93 // ROM only visible in 0x4000-0x7FFF
94 return MSXFDC::peekMem(address, time);
95 } else {
96 return 255;
97 }
98 }
99}
100
101const byte* VictorFDC::getReadCacheLine(word start) const
102{
103 if ((start & CacheLine::HIGH) == (0x7FF8 & CacheLine::HIGH)) {
104 // FDC at 0x7FF8-0x7FFC
105 return nullptr;
106 } else if ((0x4000 <= start) && (start < 0x8000)) {
107 // ROM at 0x4000-0x7FFF
108 return MSXFDC::getReadCacheLine(start);
109 } else {
110 return unmappedRead.data();
111 }
112}
113
114void VictorFDC::writeMem(word address, byte value, EmuTime::param time)
115{
116 switch (address) {
117 case 0x7FF8:
118 controller.setCommandReg(value, time);
119 break;
120 case 0x7FF9:
121 controller.setTrackReg(value, time);
122 break;
123 case 0x7FFA:
124 controller.setSectorReg(value, time);
125 break;
126 case 0x7FFB:
127 controller.setDataReg(value, time);
128 break;
129 case 0x7FFC:
131 = ((value & DRIVE_DISABLE) != 0)
133 : (((value & DRIVE_SELECT) != 0) ? DriveMultiplexer::DRIVE_B
135 multiplexer.selectDrive(drive, time);
136 multiplexer.setSide((value & SIDE_SELECT) != 0);
137 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
138 // back up for reading:
139 driveControls = value & (DRIVE_A_MOTOR | DRIVE_B_MOTOR | DRIVE_SELECT | SIDE_SELECT | DRIVE_DISABLE);
140 break;
141 }
142}
143
145{
146 if ((address & CacheLine::HIGH) == (0x7FF8 & CacheLine::HIGH)) {
147 // FDC at 0x7FF8-0x7FFC
148 return nullptr;
149 } else {
150 return unmappedWrite.data();
151 }
152}
153
155{
156 // OK, because this device doesn't call any 'fillDeviceXXXCache()'functions.
157 return true;
158}
159
160
161template<typename Archive>
162void VictorFDC::serialize(Archive& ar, unsigned /*version*/)
163{
164 ar.template serializeBase<WD2793BasedFDC>(*this);
165 ar.serialize("driveControls", driveControls);
166}
169
170} // namespace openmsx
void setMotor(bool status, EmuTime::param time) override
Set motor on/off.
void selectDrive(DriveNum num, EmuTime::param time)
void setSide(bool side) override
Side select.
static std::array< byte, 0x10000 > unmappedRead
Definition: MSXDevice.hh:302
static std::array< byte, 0x10000 > unmappedWrite
Definition: MSXDevice.hh:303
EmuTime::param getCurrentTime() const
Definition: MSXDevice.cc:125
byte peekMem(word address, EmuTime::param time) const override
Read a byte from a given memory location.
Definition: MSXFDC.cc:55
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:60
void reset(EmuTime::param time) override
This method is called on reset.
Definition: VictorFDC.cc:41
byte * getWriteCacheLine(word address) const override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for writing.
Definition: VictorFDC.cc:144
bool allowUnaligned() const override
By default we don't allow unaligned <mem> specifications in the config file.
Definition: VictorFDC.cc:154
void serialize(Archive &ar, unsigned version)
Definition: VictorFDC.cc:162
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
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:114
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:101
VictorFDC(const DeviceConfig &config)
Definition: VictorFDC.cc:35
byte peekMem(word address, EmuTime::param time) const override
Read a byte from a given memory location.
Definition: VictorFDC.cc:73
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
constexpr unsigned HIGH
Definition: CacheLine.hh:10
This file implemented 3 utility functions:
Definition: Autofire.cc:9
REGISTER_MSXDEVICE(ChakkariCopy, "ChakkariCopy")
uint16_t word
16 bit unsigned integer
Definition: openmsx.hh:29
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:1021