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  , 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 
25 SunriseIDE::~SunriseIDE() = default;
26 
27 void SunriseIDE::powerUp(EmuTime::param time)
28 {
29  writeControl(0xFF);
30  reset(time);
31 }
32 
33 void SunriseIDE::reset(EmuTime::param time)
34 {
35  selectedDevice = 0;
36  softReset = false;
37  device[0]->reset(time);
38  device[1]->reset(time);
39 }
40 
41 byte 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 
63 const 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 
77 void 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 
101 byte 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 
110 void 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 
128 byte SunriseIDE::readDataLow(EmuTime::param time)
129 {
130  word temp = readData(time);
131  readLatch = temp >> 8;
132  return temp & 0xFF;
133 }
134 byte SunriseIDE::readDataHigh(EmuTime::param /*time*/) const
135 {
136  return readLatch;
137 }
138 word SunriseIDE::readData(EmuTime::param time)
139 {
140  return device[selectedDevice]->readData(time);
141 }
142 
143 byte 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 
171 void SunriseIDE::writeDataLow(byte value)
172 {
173  writeLatch = value;
174 }
175 void SunriseIDE::writeDataHigh(byte value, EmuTime::param time)
176 {
177  word temp = (value << 8) | writeLatch;
178  writeData(temp, time);
179 }
180 void SunriseIDE::writeData(word value, EmuTime::param time)
181 {
182  device[selectedDevice]->writeData(value, time);
183 }
184 
185 void 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 
212 template<typename Archive>
213 void 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 
233 SunriseIDE::Blocks::Blocks(SunriseIDE& device)
234  : RomBlockDebuggableBase(device)
235 {
236 }
237 
238 byte 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:169
std::unique_ptr< IDEDevice > create(const DeviceConfig &config)
std::string getName(KeyCode keyCode)
Translate key code to key name.
Definition: Keys.cc:728
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