OXYGENHUB
◆ main openmsx / src / MSXKanji.cc
3.6 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
e8555c89 Andy McCall 1
#include "MSXKanji.hh"
2
3
#include "MSXException.hh"
4
#include "TclObject.hh"
5
#include "serialize.hh"
6
7
#include "one_of.hh"
8
9
namespace openmsx {
10
11
MSXKanji::MSXKanji(DeviceConfig& config)
12
	: MSXDevice(config)
13
	, rom(getName(), "Kanji ROM", config)
14
	, highAddressMask(config.getChildData("type", {}) == "hangul" ? 0x7F : 0x3F)
15
{
16
	auto level2ViaStr = config.getChildData("level_2_via", "read"); // default 'read' for bw compat
17
	if (level2ViaStr == "read") {
18
		level2Via = Level2Via::Read;
19
		portMask = 3;
20
	} else if (level2ViaStr == "write") {
21
		level2Via = Level2Via::Write;
22
		portMask = 3;
23
	} else if (level2ViaStr == "interlocked_write_read") {
24
		level2Via = Level2Via::InterlockedWriteRead;
25
		portMask = 3;
26
	} else if (level2ViaStr == "only_level_1") {
27
		level2Via = Level2Via::Read;
28
		portMask = 1; // implemented by redirecting level2 ports to level1
29
	} else {
30
		throw MSXException("MSXKanji: invalid value for 'level_2_via'");
31
	}
32
33
	auto size = rom.size();
34
	if (size != one_of(0x20000u, 0x40000u)) {
35
		throw MSXException("MSXKanji: wrong kanji ROM, it should be either 128kB or 256kB.");
36
	}
37
	if ((highAddressMask == 0x7F) && (size != 0x40000)) {
38
		throw MSXException("MSXKanji: for hangul type, the font ROM must be 256kB.");
39
	}
40
41
	reset(EmuTime::dummy());
42
}
43
44
void MSXKanji::reset(EmuTime /*time*/)
45
{
46
	adr = 0; // TODO check inital value
47
	writeLevel = 0;
48
}
49
50
void MSXKanji::writeIO(uint16_t port, uint8_t value, EmuTime /*time*/)
51
{
52
	port &= portMask;
53
	writeLevel = (port & 2) ? 1 : 0;
54
55
	switch (port & 1) {
56
	case 0:
57
		adr = (adr & 0x3f800) | ((value & 0x3f) << 5); // 6 bit column
58
		break;
59
	case 1:
60
		adr = (adr & 0x007e0) | ((value & highAddressMask) << 11); // 6 or 7 (for 'hangul') bit row
61
		break;
62
	}
63
	// note: write to either row/column resets the counter
64
}
65
66
MSXKanji::ReadImplResult MSXKanji::readImpl(uint16_t port) const
67
{
68
	uint8_t readLevel = (port & portMask & 2) ? 1 : 0;
69
70
	unsigned address = 0;
71
	switch (level2Via) {
72
	case Level2Via::Read:
73
		address = adr | (readLevel << 17);
74
		break;
75
	case Level2Via::InterlockedWriteRead:
76
		if (readLevel != writeLevel) return {.valid = false, .value = 0xFF};
77
		[[fallthrough]];
78
	case Level2Via::Write:
79
		address = adr | (writeLevel << 17);
80
		break;
81
	}
82
83
	auto value = (address < rom.size()) ? rom[address] : uint8_t(0xff);
84
	return {.valid = true, .value = value};
85
}
86
87
uint8_t MSXKanji::peekIO(uint16_t port, EmuTime /*time*/) const
88
{
89
	return readImpl(port).value;
90
}
91
92
uint8_t MSXKanji::readIO(uint16_t port, EmuTime /*time*/)
93
{
94
	auto [valid, value] = readImpl(port);
95
	if (valid) {
96
		adr = (adr & ~0x1f) | ((adr + 1) & 0x1f);
97
	}
98
	return value;
99
}
100
101
void MSXKanji::getExtraDeviceInfo(TclObject& result) const
102
{
103
	rom.getInfo(result);
104
}
105
106
// version 1 : initial version
107
// version 2 : replaced adr1/adr2 with a single shared adr, added writeLevel
108
template<typename Archive>
109
void MSXKanji::serialize(Archive& ar, unsigned version)
110
{
111
	ar.template serializeBase<MSXDevice>(*this);
112
	if (ar.versionBelow(version, 2)) {
113
		assert(Archive::IS_LOADER);
114
		ar.serialize("adr1", adr);
115
		//ar.serialize("adr2", adr); // ignored
116
		writeLevel = 0;
117
	} else {
118
		ar.serialize("adr",        adr,
119
		             "writeLevel", writeLevel);
120
	}
121
}
122
INSTANTIATE_SERIALIZE_METHODS(MSXKanji);
123
REGISTER_MSXDEVICE(MSXKanji, "Kanji");
124
125
/*
126
This really works!
127
128
10 DIM A(32)
129
20 FOR I=0 TO 4095
130
30 OUT &HD8, I MOD 64: OUT &HD9, I\64
131
40 FOR J=0 TO 31: A(J)=INP(&HD9): NEXT
132
50 FOR J=0 TO 7
133
60 PRINT RIGHT$("0000000"+BIN$(A(J)), 8);
134
70 PRINT RIGHT$("0000000"+BIN$(A(J+8)), 8)
135
80 NEXT
136
90 FOR J=16 TO 23
137
100 PRINT RIGHT$("0000000"+BIN$(A(J)), 8);
138
110 PRINT RIGHT$("0000000"+BIN$(A(J+8)), 8)
139
120 NEXT
140
130 PRINT
141
140 NEXT
142
*/
143
144
} // namespace openmsx