openMSX
SunriseIDE.cc
Go to the documentation of this file.
1#include "SunriseIDE.hh"
2#include "IDEDeviceFactory.hh"
3#include "IDEDevice.hh"
4#include "Math.hh"
5#include "serialize.hh"
6#include "outer.hh"
7
8namespace openmsx {
9
11 : MSXDevice(config)
12 , romBlockDebug(*this)
13 , rom(getName() + " ROM", "rom", config)
14 , internalBank(nullptr) // make valgrind happy
15 , ideRegsEnabled(false)
16{
17 device[0] = IDEDeviceFactory::create(
18 DeviceConfig(config, config.findChild("master")));
19 device[1] = IDEDeviceFactory::create(
20 DeviceConfig(config, config.findChild("slave")));
21
23}
24
25SunriseIDE::~SunriseIDE() = default;
26
27void SunriseIDE::powerUp(EmuTime::param time)
28{
29 writeControl(0xFF);
30 reset(time);
31}
32
33void SunriseIDE::reset(EmuTime::param time)
34{
35 selectedDevice = 0;
36 softReset = false;
37 device[0]->reset(time);
38 device[1]->reset(time);
39}
40
41byte SunriseIDE::readMem(word address, EmuTime::param time)
42{
43 if (ideRegsEnabled && ((address & 0x3E00) == 0x3C00)) {
44 // 0x7C00 - 0x7DFF ide data register
45 if ((address & 1) == 0) {
46 return readDataLow(time);
47 } else {
48 return readDataHigh(time);
49 }
50 }
51 if (ideRegsEnabled && ((address & 0x3F00) == 0x3E00)) {
52 // 0x7E00 - 0x7EFF ide registers
53 return readReg(address & 0xF, time);
54 }
55 if ((0x4000 <= address) && (address < 0x8000)) {
56 // read normal (flash) rom
57 return internalBank[address & 0x3FFF];
58 }
59 // read nothing
60 return 0xFF;
61}
62
63const byte* SunriseIDE::getReadCacheLine(word start) const
64{
65 if (ideRegsEnabled && ((start & 0x3E00) == 0x3C00)) {
66 return nullptr;
67 }
68 if (ideRegsEnabled && ((start & 0x3F00) == 0x3E00)) {
69 return nullptr;
70 }
71 if ((0x4000 <= start) && (start < 0x8000)) {
72 return &internalBank[start & 0x3FFF];
73 }
74 return unmappedRead;
75}
76
77void SunriseIDE::writeMem(word address, byte value, EmuTime::param time)
78{
79 if ((address & 0xBF04) == 0x0104) {
80 // control register
81 writeControl(value);
82 return;
83 }
84 if (ideRegsEnabled && ((address & 0x3E00) == 0x3C00)) {
85 // 0x7C00 - 0x7DFF ide data register
86 if ((address & 1) == 0) {
87 writeDataLow(value);
88 } else {
89 writeDataHigh(value, time);
90 }
91 return;
92 }
93 if (ideRegsEnabled && ((address & 0x3F00) == 0x3E00)) {
94 // 0x7E00 - 0x7EFF ide registers
95 writeReg(address & 0xF, value, time);
96 return;
97 }
98 // all other writes ignored
99}
100
101byte SunriseIDE::getBank() const
102{
103 byte bank = Math::reverseByte(control & 0xF8);
104 if (bank >= (rom.getSize() / 0x4000)) {
105 bank &= ((rom.getSize() / 0x4000) - 1);
106 }
107 return bank;
108}
109
110void SunriseIDE::writeControl(byte value)
111{
112 control = value;
113 if (ideRegsEnabled != (control & 1)) {
114 ideRegsEnabled = control & 1;
115 invalidateDeviceRCache(0x3C00, 0x0300);
116 invalidateDeviceRCache(0x7C00, 0x0300);
117 invalidateDeviceRCache(0xBC00, 0x0300);
118 invalidateDeviceRCache(0xFC00, 0x0300);
119 }
120
121 byte bank = getBank();
122 if (internalBank != &rom[0x4000 * bank]) {
123 internalBank = &rom[0x4000 * bank];
124 invalidateDeviceRCache(0x4000, 0x4000);
125 }
126}
127
128byte SunriseIDE::readDataLow(EmuTime::param time)
129{
130 word temp = readData(time);
131 readLatch = temp >> 8;
132 return temp & 0xFF;
133}
134byte SunriseIDE::readDataHigh(EmuTime::param /*time*/) const
135{
136 return readLatch;
137}
138word SunriseIDE::readData(EmuTime::param time)
139{
140 return device[selectedDevice]->readData(time);
141}
142
143byte SunriseIDE::readReg(nibble reg, EmuTime::param time)
144{
145 if (reg == 14) {
146 // alternate status register
147 reg = 7;
148 }
149 if (softReset) {
150 if (reg == 7) {
151 // read status
152 return 0xFF; // BUSY
153 } else {
154 // all others
155 return 0x7F; // don't care
156 }
157 } else {
158 if (reg == 0) {
159 return readData(time) & 0xFF;
160 } else {
161 byte result = device[selectedDevice]->readReg(reg, time);
162 if (reg == 6) {
163 result &= 0xEF;
164 result |= selectedDevice ? 0x10 : 0x00;
165 }
166 return result;
167 }
168 }
169}
170
171void SunriseIDE::writeDataLow(byte value)
172{
173 writeLatch = value;
174}
175void SunriseIDE::writeDataHigh(byte value, EmuTime::param time)
176{
177 word temp = (value << 8) | writeLatch;
178 writeData(temp, time);
179}
180void SunriseIDE::writeData(word value, EmuTime::param time)
181{
182 device[selectedDevice]->writeData(value, time);
183}
184
185void SunriseIDE::writeReg(nibble reg, byte value, EmuTime::param time)
186{
187 if (softReset) {
188 if ((reg == 14) && !(value & 0x04)) {
189 // clear SRST
190 softReset = false;
191 }
192 // ignore all other writes
193 } else {
194 if (reg == 0) {
195 writeData((value << 8) | value, time);
196 } else {
197 if ((reg == 14) && (value & 0x04)) {
198 // set SRST
199 softReset = true;
200 device[0]->reset(time);
201 device[1]->reset(time);
202 } else {
203 if (reg == 6) {
204 selectedDevice = (value & 0x10) ? 1 : 0;
205 }
206 device[selectedDevice]->writeReg(reg, value, time);
207 }
208 }
209 }
210}
211
212template<typename Archive>
213void SunriseIDE::serialize(Archive& ar, unsigned /*version*/)
214{
215 ar.template serializeBase<MSXDevice>(*this);
216 ar.serializePolymorphic("master", *device[0]);
217 ar.serializePolymorphic("slave", *device[1]);
218 ar.serialize("readLatch", readLatch,
219 "writeLatch", writeLatch,
220 "selectedDevice", selectedDevice,
221 "control", control,
222 "softReset", softReset);
223
224 if constexpr (Archive::IS_LOADER) {
225 // restore internalBank, ideRegsEnabled
226 writeControl(control);
227 }
228}
231
232
233SunriseIDE::Blocks::Blocks(SunriseIDE& device)
234 : RomBlockDebuggableBase(device)
235{
236}
237
238byte SunriseIDE::Blocks::read(unsigned address)
239{
240 if ((address < 0x4000) || (address >= 0x8000)) return 255;
241 auto& ide = OUTER(SunriseIDE, romBlockDebug);
242 return ide.getBank();
243}
244
245} // namespace openmsx
const XMLElement * findChild(std::string_view name) const
Definition: DeviceConfig.cc:66
An MSXDevice is an emulated hardware component connected to the bus of the emulated MSX.
Definition: MSXDevice.hh:33
void invalidateDeviceRCache()
Definition: MSXDevice.hh:210
static byte unmappedRead[0x10000]
Definition: MSXDevice.hh:301
EmuTime::param getCurrentTime() const
Definition: MSXDevice.cc:126
unsigned getSize() const
Definition: Rom.hh:34
void reset(EmuTime::param time) override
This method is called on reset.
Definition: SunriseIDE.cc:33
~SunriseIDE() override
SunriseIDE(const DeviceConfig &config)
Definition: SunriseIDE.cc:10
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: SunriseIDE.cc:77
void serialize(Archive &ar, unsigned version)
Definition: SunriseIDE.cc:213
const byte * getReadCacheLine(word start) const override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for reading.
Definition: SunriseIDE.cc:63
void powerUp(EmuTime::param time) override
This method is called when MSX is powered up.
Definition: SunriseIDE.cc:27
byte readMem(word address, EmuTime::param time) override
Read a byte from a location at a certain time from this device.
Definition: SunriseIDE.cc:41
constexpr uint8_t reverseByte(uint8_t a)
Reverse the bits in a byte.
Definition: Math.hh:120
std::unique_ptr< IDEDevice > create(const DeviceConfig &config)
std::string getName(KeyCode keyCode)
Translate key code to key name.
Definition: Keys.cc:727
This file implemented 3 utility functions:
Definition: Autofire.cc:9
uint8_t nibble
4 bit integer
Definition: openmsx.hh:23
REGISTER_MSXDEVICE(ChakkariCopy, "ChakkariCopy")
uint16_t word
16 bit unsigned integer
Definition: openmsx.hh:29
#define OUTER(type, member)
Definition: outer.hh:41
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:1009