OXYGENHUB
◆ main openmsx / src / fdc / ToshibaFDC.cc
3.9 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
1
#include "ToshibaFDC.hh"
2
3
#include "DriveMultiplexer.hh"
4
#include "WD2793.hh"
5
6
#include "CacheLine.hh"
7
#include "serialize.hh"
8
9
// Based on studying the code in the Toshiba disk ROM.
10
// Thanks to Arjen Zeilemaker for an annotated disassembly:
11
//   https://sourceforge.net/p/msxsyssrc/git/ci/master/tree/diskdrvs/hx-f101/driver.mac
12
//   https://sourceforge.net/p/msxsyssrc/git/ci/master/tree/diskdrvs/hx-34/driver.mac
13
14
namespace openmsx {
15
16
ToshibaFDC::ToshibaFDC(DeviceConfig& config)
17
	: WD2793BasedFDC(config)
18
{
19
	// ROM only visible in 0x4000-0x7FFF by default
20
	parseRomVisibility(config, 0x4000, 0x4000);
21
22
}
23
24
byte ToshibaFDC::readMem(uint16_t address, EmuTime time)
25
{
26
	switch (address) {
27
	case 0x7FF0:
28
		return controller.getStatusReg(time);
29
	case 0x7FF1:
30
		return controller.getTrackReg(time);
31
	case 0x7FF2:
32
		return controller.getSectorReg(time);
33
	case 0x7FF3:
34
		return controller.getDataReg(time);
35
	case 0x7FF6:
36
		return 0xFE | (multiplexer.diskChanged() ? 0 : 1);
37
	case 0x7FF7: {
38
		byte value = 0xFF;
39
		if (controller.getIRQ(time))  value &= ~0x40;
40
		if (controller.getDTRQ(time)) value &= ~0x80;
41
		return value;
42
	}
43
	default:
44
		return ToshibaFDC::peekMem(address, time);
45
	}
46
}
47
48
byte ToshibaFDC::peekMem(uint16_t address, EmuTime time) const
49
{
50
	switch (address) { // checked on real HW: no mirroring
51
	case 0x7FF0:
52
		return controller.peekStatusReg(time);
53
	case 0x7FF1:
54
		return controller.peekTrackReg(time);
55
	case 0x7FF2:
56
		return controller.peekSectorReg(time);
57
	case 0x7FF3:
58
		return controller.peekDataReg(time);
59
	case 0x7FF4:
60
		// ToshibaFDC HX-F101 disk ROM doesn't read this, but HX-34
61
		// does. No idea if this location is actually readable on
62
		// HX-F101, but currently the emulation is the same for both.
63
		return 0xFC
64
		      | (multiplexer.getSide() ? 1 : 0)
65
		      | (multiplexer.getMotor() ? 2 : 0);
66
	case 0x7FF5:
67
		return 0xFE | ((multiplexer.getSelectedDrive() == DriveMultiplexer::Drive::B) ? 1 : 0);
68
	case 0x7FF6:
69
		return 0xFE | (multiplexer.peekDiskChanged() ? 0 : 1);
70
	case 0x7FF7: {
71
		byte value = 0xFF; // unused bits read as 1
72
		if (controller.peekIRQ(time))  value &= ~0x40;
73
		if (controller.peekDTRQ(time)) value &= ~0x80;
74
		return value;
75
	}
76
	default:
77
		return MSXFDC::peekMem(address, time);
78
	}
79
}
80
81
const byte* ToshibaFDC::getReadCacheLine(uint16_t start) const
82
{
83
	if ((start & CacheLine::HIGH) == (0x7FF0 & CacheLine::HIGH)) {
84
		// FDC at 0x7FF0-0x7FF7
85
		return nullptr;
86
	} else {
87
		return MSXFDC::getReadCacheLine(start);
88
	}
89
}
90
91
void ToshibaFDC::writeMem(uint16_t address, byte value, EmuTime time)
92
{
93
	switch (address) {
94
	case 0x7FF0:
95
		controller.setCommandReg(value, time);
96
		break;
97
	case 0x7FF1:
98
		controller.setTrackReg(value, time);
99
		break;
100
	case 0x7FF2:
101
		controller.setSectorReg(value, time);
102
		break;
103
	case 0x7FF3:
104
		controller.setDataReg(value, time);
105
		break;
106
	case 0x7FF4:
107
		multiplexer.setSide((value & 0x01) != 0); // no effect on HX-F101 because it has single sided drive
108
		multiplexer.setMotor((value & 0x02) != 0, time);
109
		break;
110
	case 0x7FF5:
111
		// Disk ROM only writes the values 0 or 1.
112
		multiplexer.selectDrive((value & 1) ? DriveMultiplexer::Drive::B
113
		                                    : DriveMultiplexer::Drive::A,
114
		                        time);
115
		break;
116
	case 0x7FF6:
117
		// Disk ROM writes '1' (to drive A) and shortly after '0' (to drive B).
118
		// TODO What does this do? Activate the 'disk is changed' state?
119
		//      And if so, does the written value matter?
120
		break;
121
	case 0x7FF7:
122
		// Probably no function, disk ROM doesn't write to this address.
123
		break;
124
	}
125
}
126
127
byte* ToshibaFDC::getWriteCacheLine(uint16_t address)
128
{
129
	if ((address & CacheLine::HIGH) == (0x7FF0 & CacheLine::HIGH)) {
130
		return nullptr;
131
	} else {
132
		return unmappedWrite.data();
133
	}
134
}
135
136
template<typename Archive>
137
void ToshibaFDC::serialize(Archive& ar, unsigned /*version*/)
138
{
139
	ar.template serializeBase<WD2793BasedFDC>(*this);
140
}
141
INSTANTIATE_SERIALIZE_METHODS(ToshibaFDC);
142
REGISTER_MSXDEVICE(ToshibaFDC, "ToshibaFDC");
143
144
} // namespace openmsx