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