OXYGENHUB
◆ main openmsx / src / fdc / CanonFDC.cc
3.7 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
e8555c89 Andy McCall 1
#include "CanonFDC.hh"
2
3
#include "CacheLine.hh"
4
#include "serialize.hh"
5
6
// Technical info and discussion on:
7
//    https://www.msx.org/forum/msx-talk/hardware/canon-v-30f-msx2?page=8
8
//
9
// 0x7FF8: MB8877A command register (W) / Status register (R)
10
// 0x7FF9: MB8877A track register  (R/W)
11
// 0x7FFA: MB8877A sector register (R/W)
12
// 0x7FFB: MB8877A data register   (R/W)
13
// 0x7FFC: drive control
14
//   b1,b0: (R/W) drive select (0 = drive 0, 1 = drive 1, 3 = deselect drive)
15
//   b2:    (R/W) side select (0 = side 0, 1 = side 1)
16
//   b3:    (R/W) motor on (1 = motor on)
17
//   b4:     (R)  disk changed (0 = changed)
18
//   b5      (R)  some sort of ready (1 = ready)
19
//   b6      (R)  DRQ (1 = DRQ)
20
//   b7      (R)  IRQ (1 = IRQ)
21
// Hardware registers are also visible in page 2 (0xBFF8-0xBFFC).
22
23
namespace openmsx {
24
25
CanonFDC::CanonFDC(DeviceConfig& config)
26
	: WD2793BasedFDC(config)
27
{
28
	reset(getCurrentTime());
29
}
30
31
void CanonFDC::reset(EmuTime time)
32
{
33
	WD2793BasedFDC::reset(time);
34
	writeMem(0x3FFC, 0, time);
35
}
36
37
byte CanonFDC::readMem(uint16_t address, EmuTime time)
38
{
39
	switch (address & 0x3FFF) {
40
	case 0x3FF8:
41
		return controller.getStatusReg(time);
42
	case 0x3FF9:
43
		return controller.getTrackReg(time);
44
	case 0x3FFA:
45
		return controller.getSectorReg(time);
46
	case 0x3FFB:
47
		return controller.getDataReg(time);
48
	case 0x3FFC: {
49
		// At address 0x76F4 in the disk ROM bit 5 is checked. If this
50
		// bit is 0, the code executes a delay loop. Not sure what that
51
		// is for. Some kind of hardware debug feature??
52
		byte value = 0x30 | controlReg;
53
		if (controller.getIRQ(time))  value |= 0x40;
54
		if (controller.getDTRQ(time)) value |= 0x80;
55
		if (multiplexer.diskChanged()) value &= ~0x10;
56
		return value;
57
	}
58
	default:
59
		return CanonFDC::peekMem(address, time);
60
	}
61
}
62
63
byte CanonFDC::peekMem(uint16_t address, EmuTime time) const
64
{
65
	switch (address & 0x3FFF) {
66
	case 0x3FF8:
67
		return controller.peekStatusReg(time);
68
	case 0x3FF9:
69
		return controller.peekTrackReg(time);
70
	case 0x3FFA:
71
		return controller.peekSectorReg(time);
72
	case 0x3FFB:
73
		return controller.peekDataReg(time);
74
	case 0x3FFC: {
75
		byte value = 0x30 | controlReg;
76
		if (controller.peekIRQ(time))  value |= 0x40;
77
		if (controller.peekDTRQ(time)) value |= 0x80;
78
		if (multiplexer.peekDiskChanged()) value &= ~0x10;
79
		return value;
80
	}
81
	default:
82
		return MSXFDC::peekMem(address, time);
83
	}
84
}
85
86
const byte* CanonFDC::getReadCacheLine(uint16_t start) const
87
{
88
	if ((start & 0x3FFF & CacheLine::HIGH) == (0x3FF0 & CacheLine::HIGH)) {
89
		// FDC at 0x7FF8-0x7FFC and 0xBFF8-0xBFFC
90
		return nullptr;
91
	} else {
92
		return MSXFDC::getReadCacheLine(start);
93
	}
94
}
95
96
void CanonFDC::writeMem(uint16_t address, byte value, EmuTime time)
97
{
98
	switch (address & 0x3FFF) {
99
	case 0x3FF8:
100
		controller.setCommandReg(value, time);
101
		break;
102
	case 0x3FF9:
103
		controller.setTrackReg(value, time);
104
		break;
105
	case 0x3FFA:
106
		controller.setSectorReg(value, time);
107
		break;
108
	case 0x3FFB:
109
		controller.setDataReg(value, time);
110
		break;
111
	case 0x3FFC: {
112
		controlReg = value & 0x0F;
113
		auto drive = [&] {
114
			switch (value & 3) {
115
			case 0:  return DriveMultiplexer::Drive::A;
116
			case 1:  return DriveMultiplexer::Drive::B;
117
			default: return DriveMultiplexer::Drive::NONE;
118
			}
119
		}();
120
		multiplexer.selectDrive(drive, time);
121
		multiplexer.setSide ((value & 0x04) != 0);
122
		multiplexer.setMotor((value & 0x08) != 0, time);
123
		break;
124
	}
125
	}
126
}
127
128
byte* CanonFDC::getWriteCacheLine(uint16_t address)
129
{
130
	if ((address & 0x3FFF & CacheLine::HIGH) == (0x3FF0 & CacheLine::HIGH)) {
131
		return nullptr;
132
	} else {
133
		return unmappedWrite.data();
134
	}
135
}
136
137
template<typename Archive>
138
void CanonFDC::serialize(Archive& ar, unsigned /*version*/)
139
{
140
	ar.template serializeBase<WD2793BasedFDC>(*this);
141
	ar.serialize("controlReg", controlReg);
142
}
143
INSTANTIATE_SERIALIZE_METHODS(CanonFDC);
144
REGISTER_MSXDEVICE(CanonFDC, "CanonFDC");
145
146
} // namespace openmsx