OXYGENHUB
◆ main openmsx / src / fdc / PhilipsFDC.cc
4.9 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
e8555c89 Andy McCall 1
#include "PhilipsFDC.hh"
2
3
#include "DriveMultiplexer.hh"
4
#include "WD2793.hh"
5
6
#include "CacheLine.hh"
7
#include "serialize.hh"
8
9
namespace openmsx {
10
11
PhilipsFDC::PhilipsFDC(DeviceConfig& config)
12
	: WD2793BasedFDC(config)
13
{
14
	// ROM only visible in 0x4000-0x7FFF by default
15
	parseRomVisibility(config, 0x4000, 0x4000);
16
	reset(getCurrentTime());
17
}
18
19
void PhilipsFDC::reset(EmuTime time)
20
{
21
	WD2793BasedFDC::reset(time);
22
	writeMem(0x3FFC, 0x00, time);
23
	writeMem(0x3FFD, 0x00, time);
24
}
25
26
byte PhilipsFDC::readMem(uint16_t address, EmuTime time)
27
{
28
	switch (address & 0x3FFF) {
29
	case 0x3FF8:
30
		return controller.getStatusReg(time);
31
	case 0x3FF9:
32
		return controller.getTrackReg(time);
33
	case 0x3FFA:
34
		return controller.getSectorReg(time);
35
	case 0x3FFB:
36
		return controller.getDataReg(time);
37
	case 0x3FFD: {
38
		byte res = driveReg & ~4;
39
		if (!multiplexer.diskChanged()) {
40
			res |= 4;
41
		}
42
		return res;
43
	}
44
	case 0x3FFF: {
45
		// bit 6: !intrq
46
		// bit 7: !dtrq
47
		// bit 5: !type1 (Philips VY-0010/JVC HC-FC303, pin 2 of FDD
48
		//                interface, indicates DS drive)
49
		// bit 4: !type0 (Philips VY-0010/JVC HC-FC303, pin 1 of FDD
50
		//                interface)
51
		// Other bits are not connected, according to service manuals
52
		// of VY-0010 and Sony HBD-50.
53
		byte value = 0xFF; // all bits are pulled up to 1
54
		if (controller.getIRQ(time)) value &= ~0x40;
55
		if (controller.getDTRQ(time)) value &= ~0x80;
56
		return value;
57
	}
58
	default:
59
		return PhilipsFDC::peekMem(address, time);
60
	}
61
}
62
63
byte PhilipsFDC::peekMem(uint16_t address, EmuTime time) const
64
{
65
	// FDC registers are mirrored in
66
	//   0x3FF8-0x3FFF
67
	//   0x7FF8-0x7FFF
68
	//   0xBFF8-0xBFFF
69
	//   0xFFF8-0xFFFF
70
	switch (address & 0x3FFF) {
71
	case 0x3FF8:
72
		return controller.peekStatusReg(time);
73
	case 0x3FF9:
74
		return controller.peekTrackReg(time);
75
	case 0x3FFA:
76
		return controller.peekSectorReg(time);
77
	case 0x3FFB:
78
		return controller.peekDataReg(time);
79
	case 0x3FFC:
80
		// bit 0 = side select
81
		// TODO check other bits !!
82
		return sideReg; // return multiplexer.getSideSelect();
83
	case 0x3FFD: {
84
		// bit 1,0 -> drive number
85
		// (00 or 10: drive A, 01: drive B, 11: nothing)
86
		// bit 2 -> 0 iff disk changed
87
		//      TODO This is required on Sony_HB-F500P.
88
		//           Do other machines have this bit as well?
89
		// bit 7 -> motor on
90
		// TODO check other bits !!
91
		byte res = driveReg & ~4;
92
		if (!multiplexer.peekDiskChanged()) {
93
			res |= 4;
94
		}
95
		return res;
96
	}
97
	case 0x3FFE:
98
		// not used
99
		return 255;
100
	case 0x3FFF: {
101
		// Drive control IRQ and DRQ lines are not connected to Z80
102
		// interrupt request
103
		// bit 6: !intrq
104
		// bit 7: !dtrq
105
		// bit 5: !type1 (Philips VY-0010/JVC HC-FC303, pin 2 of FDD
106
		//                interface, indicates DS drive)
107
		// bit 4: !type0 (Philips VY-0010/JVC HC-FC303, pin 1 of FDD
108
		//                interface)
109
		// Other bits are not connected, according to service manuals
110
		// of VY-0010 and Sony HBD-50.
111
		byte value = 0xFF; // all bits are pulled up to 1
112
		if (controller.peekIRQ(time)) value &= ~0x40;
113
		if (controller.peekDTRQ(time)) value &= ~0x80;
114
		return value;
115
	}
116
	default:
117
		return MSXFDC::peekMem(address, time);
118
	}
119
}
120
121
const byte* PhilipsFDC::getReadCacheLine(uint16_t start) const
122
{
123
	// if address overlap 0x7ff8-0x7ffb then return nullptr,
124
	// else normal ROM behaviour
125
	if ((start & 0x3FF8 & CacheLine::HIGH) == (0x3FF8 & CacheLine::HIGH)) {
126
		return nullptr;
127
	} else {
128
		return MSXFDC::getReadCacheLine(start);
129
	}
130
}
131
132
void PhilipsFDC::writeMem(uint16_t address, byte value, EmuTime time)
133
{
134
	switch (address & 0x3FFF) {
135
	case 0x3FF8:
136
		controller.setCommandReg(value, time);
137
		break;
138
	case 0x3FF9:
139
		controller.setTrackReg(value, time);
140
		break;
141
	case 0x3FFA:
142
		controller.setSectorReg(value, time);
143
		break;
144
	case 0x3FFB:
145
		controller.setDataReg(value, time);
146
		break;
147
	case 0x3FFC:
148
		// bit 0 = side select
149
		// TODO check other bits !!
150
		sideReg = value;
151
		multiplexer.setSide(value & 1);
152
		break;
153
	case 0x3FFD:
154
		// bit 1,0 -> drive number
155
		// (00 or 10: drive A, 01: drive B, 11: nothing)
156
		// TODO bit 6 -> drive LED (0 -> off, 1 -> on)
157
		// bit 7 -> motor on
158
		// TODO check other bits !!
159
		driveReg = value;
160
		auto drive = [&] {
161
			switch (value & 3) {
162
				case 0:
163
				case 2:
164
					return DriveMultiplexer::Drive::A;
165
				case 1:
166
					return DriveMultiplexer::Drive::B;
167
				case 3:
168
				default:
169
					return DriveMultiplexer::Drive::NONE;
170
			}
171
		}();
172
		multiplexer.selectDrive(drive, time);
173
		multiplexer.setMotor((value & 128) != 0, time);
174
		break;
175
	}
176
}
177
178
byte* PhilipsFDC::getWriteCacheLine(uint16_t address)
179
{
180
	if ((address & 0x3FF8) == (0x3FF8 & CacheLine::HIGH)) {
181
		return nullptr;
182
	} else {
183
		return unmappedWrite.data();
184
	}
185
}
186
187
188
template<typename Archive>
189
void PhilipsFDC::serialize(Archive& ar, unsigned /*version*/)
190
{
191
	ar.template serializeBase<WD2793BasedFDC>(*this);
192
	ar.serialize("sideReg",  sideReg,
193
	             "driveReg", driveReg);
194
}
195
INSTANTIATE_SERIALIZE_METHODS(PhilipsFDC);
196
REGISTER_MSXDEVICE(PhilipsFDC, "PhilipsFDC");
197
198
} // namespace openmsx