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 
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  invalidateMemCache(0x3C00, 0x0300);
118  invalidateMemCache(0x7C00, 0x0300);
119  invalidateMemCache(0xBC00, 0x0300);
120  invalidateMemCache(0xFC00, 0x0300);
121  }
122 
123  byte bank = getBank();
124  if (internalBank != &rom[0x4000 * bank]) {
125  internalBank = &rom[0x4000 * bank];
126  invalidateMemCache(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*/)
137 {
138  return readLatch;
139 }
140 word SunriseIDE::readData(EmuTime::param time)
141 {
142  word result = device[selectedDevice]->readData(time);
143  return result;
144 }
145 
146 byte SunriseIDE::readReg(nibble reg, EmuTime::param time)
147 {
148  byte result;
149  if (reg == 14) {
150  // alternate status register
151  reg = 7;
152  }
153  if (softReset) {
154  if (reg == 7) {
155  // read status
156  result = 0xFF; // BUSY
157  } else {
158  // all others
159  result = 0x7F; // don't care
160  }
161  } else {
162  if (reg == 0) {
163  result = readData(time) & 0xFF;
164  } else {
165  result = device[selectedDevice]->readReg(reg, time);
166  if (reg == 6) {
167  result &= 0xEF;
168  result |= selectedDevice ? 0x10 : 0x00;
169  }
170  }
171  }
172  return result;
173 }
174 
175 void SunriseIDE::writeDataLow(byte value)
176 {
177  writeLatch = value;
178 }
179 void SunriseIDE::writeDataHigh(byte value, EmuTime::param time)
180 {
181  word temp = (value << 8) | writeLatch;
182  writeData(temp, time);
183 }
184 void SunriseIDE::writeData(word value, EmuTime::param time)
185 {
186  device[selectedDevice]->writeData(value, time);
187 }
188 
189 void SunriseIDE::writeReg(nibble reg, byte value, EmuTime::param time)
190 {
191  if (softReset) {
192  if ((reg == 14) && !(value & 0x04)) {
193  // clear SRST
194  softReset = false;
195  }
196  // ignore all other writes
197  } else {
198  if (reg == 0) {
199  writeData((value << 8) | value, time);
200  } else {
201  if ((reg == 14) && (value & 0x04)) {
202  // set SRST
203  softReset = true;
204  device[0]->reset(time);
205  device[1]->reset(time);
206  } else {
207  if (reg == 6) {
208  selectedDevice = (value & 0x10) ? 1 : 0;
209  }
210  device[selectedDevice]->writeReg(reg, value, time);
211  }
212  }
213  }
214 }
215 
216 template<typename Archive>
217 void SunriseIDE::serialize(Archive& ar, unsigned /*version*/)
218 {
219  ar.template serializeBase<MSXDevice>(*this);
220  ar.serializePolymorphic("master", *device[0]);
221  ar.serializePolymorphic("slave", *device[1]);
222  ar.serialize("readLatch", readLatch,
223  "writeLatch", writeLatch,
224  "selectedDevice", selectedDevice,
225  "control", control,
226  "softReset", softReset);
227 
228  if (ar.isLoader()) {
229  // restore internalBank, ideRegsEnabled
230  writeControl(control);
231  }
232 }
234 REGISTER_MSXDEVICE(SunriseIDE, "SunriseIDE");
235 
236 
237 SunriseIDE::Blocks::Blocks(SunriseIDE& device)
238  : RomBlockDebuggableBase(device)
239 {
240 }
241 
242 byte SunriseIDE::Blocks::read(unsigned address)
243 {
244  if ((address < 0x4000) || (address >= 0x8000)) return 255;
245  auto& ide = OUTER(SunriseIDE, romBlockDebug);
246  return ide.getBank();
247 }
248 
249 } // namespace openmsx
~SunriseIDE() override
uint8_t byte
8 bit unsigned integer
Definition: openmsx.hh:26
REGISTER_MSXDEVICE(ChakkariCopy, "ChakkariCopy")
const XMLElement * findChild(std::string_view name) const
Definition: DeviceConfig.cc:61
void reset(EmuTime::param time) override
This method is called on reset.
Definition: SunriseIDE.cc:35
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
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
static byte unmappedRead[0x10000]
Definition: MSXDevice.hh:274
EmuTime::param getCurrentTime() const
Definition: MSXDevice.cc:129
void serialize(Archive &ar, unsigned version)
Definition: SunriseIDE.cc:217
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:5
An MSXDevice is an emulated hardware component connected to the bus of the emulated MSX...
Definition: MSXDevice.hh:31
uint8_t nibble
4 bit integer
Definition: openmsx.hh:23
SunriseIDE(const DeviceConfig &config)
Definition: SunriseIDE.cc:10
unsigned getSize() const
Definition: Rom.hh:32
uint16_t word
16 bit unsigned integer
Definition: openmsx.hh:29
void powerUp(EmuTime::param time) override
This method is called when MSX is powered up.
Definition: SunriseIDE.cc:29
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:981
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
string getName(KeyCode keyCode)
Translate key code to key name.
Definition: Keys.cc:589
std::unique_ptr< IDEDevice > create(const DeviceConfig &config)
uint8_t reverseByte(uint8_t a)
Reverse the bits in a byte.
Definition: Math.hh:212
#define OUTER(type, member)
Definition: outer.hh:38
void invalidateMemCache(word start, unsigned size)
Invalidate CPU memory-mapping cache.
Definition: MSXDevice.cc:454