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