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