OXYGENHUB
◆ main openmsx / src / SVIPPI.cc
5.8 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
1
#include "SVIPPI.hh"
2
3
#include "CassettePort.hh"
4
#include "GlobalSettings.hh"
5
#include "JoystickPort.hh"
6
#include "MSXMotherBoard.hh"
7
#include "Reactor.hh"
8
#include "serialize.hh"
9
10
// Keyboard Matrix
11
//
12
//  Column/ |  0  |  1  |  2  |  3  |  4  |  5  |  6  |  7  |
13
//  Line    |     |     |     |     |     |     |     |     |
14
//  --------+-----+-----+-----+-----+-----+-----+-----+-----|
15
//   0      |  0  |  1  |  2  |  3  |  4  |  5  |  6  |  7  |
16
//   1      |  8  |  9  |  :  |  '  |  ,  |  =  |  .  |  /  |
17
//   2      |  -  |  A  |  B  |  C  |  D  |  E  |  F  |  G  |
18
//   3      |  H  |  I  |  J  |  K  |  L  |  M  |  N  |  O  |
19
//   4      |  P  |  Q  |  R  |  S  |  T  |  U  |  V  |  W  |
20
//   5      |  X  |  Y  |  Z  |  [  |  \  |  ]  | BS  | UP  |
21
//   6      |SHIFT|CTRL |LGRAP|RGRAP| ESC |STOP |ENTER|LEFT |
22
//   7      | F1  | F2  | F3  | F4  | F5  | CLS | INS |DOWN |
23
//   8      |SPACE| TAB | DEL |CAPS | SEL |PRINT|     |RIGHT|
24
//   9*     |  0  |  1  |  2  |  3  |  4  |  5  |  6  |  7  |
25
//  10*     |  8  |  9  |  +  |  -  |  *  |  /  |  .  |  ,  |
26
//  ---------------------------------------------------------
27
//  * Numerical keypad (SVI-328 only)
28
29
//  PPI Port A Input (98H)
30
//  Bit Name      Description
31
//   0  TA        Paddle or tablet 1, /SENSE
32
//   1  TB        Paddle or tablet 1, EOC
33
//   2  TC        Paddle or tablet 2, /SENSE
34
//   3  TD        Paddle or tablet 2, EOC
35
//   4  /TRIGGER1 Joystick 1, Trigger
36
//   5  /TRIGGER2 Joystick 2, Trigger
37
//   6  /READY    Cassette, Ready
38
//   7  CASR      Cassette, Read data
39
//
40
//  PPI Port B Input (99H)
41
//  Bit Name Description
42
//   0  IN0  Keyboard, Column status of selected line
43
//   1  IN1  Keyboard, Column status of selected line
44
//   2  IN2  Keyboard, Column status of selected line
45
//   3  IN3  Keyboard, Column status of selected line
46
//   4  IN4  Keyboard, Column status of selected line
47
//   5  IN5  Keyboard, Column status of selected line
48
//   6  IN6  Keyboard, Column status of selected line
49
//   7  IN7  Keyboard, Column status of selected line
50
//
51
//  PPI Port C Output (96H)
52
//  Bit Name   Description
53
//   0  KB0    Keyboard, Line select 0
54
//   1  KB1    Keyboard, Line select 1
55
//   2  KB2    Keyboard, Line select 2
56
//   3  KB3    Keyboard, Line select 3
57
//   4  CASON  Cassette, Motor relay control (0=on, 1=off)
58
//   5  CASW   Cassette, Write data
59
//   6  CASAUD Cassette, Audio control (1=enable other channel in, 0=disable channel)
60
//   7  SOUND  Keyboard, Click sound bit (pulse)
61
//
62
//  PPI Mode control, Output (97H)
63
//
64
//  PPI Port C, Input (9AH)
65
66
namespace openmsx {
67
68
// MSXDevice
69
70
SVIPPI::SVIPPI(const DeviceConfig& config)
71
	: MSXDevice(config)
72
	, cassettePort(getMotherBoard().getCassettePort())
73
	, i8255(*this, getCurrentTime(), config.getGlobalSettings().getInvalidPpiModeSetting())
74
	, click(config)
75
	, keyboard(
76
		config.getMotherBoard(),
77
		config.getMotherBoard().getScheduler(),
78
		config.getMotherBoard().getCommandController(),
79
		config.getMotherBoard().getReactor().getEventDistributor(),
80
		config.getMotherBoard().getMSXEventDistributor(),
81
		config.getMotherBoard().getStateChangeDistributor(),
82
		Keyboard::Matrix::SVI, config)
83
{
84
	ports[0] = &getMotherBoard().getJoystickPort(0);
85
	ports[1] = &getMotherBoard().getJoystickPort(1);
86
87
	auto time = getCurrentTime();
88
	ports[0]->write(0, time); // TODO correct?  Bit2 must be 0 otherwise
89
	ports[1]->write(0, time); //      e.g. KeyJoystick doesn't work
90
91
	reset(time);
92
}
93
94
void SVIPPI::reset(EmuTime time)
95
{
96
	i8255.reset(time);
97
	click.reset(time);
98
}
99
100
uint8_t SVIPPI::readIO(uint16_t port, EmuTime time)
101
{
102
	return i8255.read(port & 0x03, time);
103
}
104
105
uint8_t SVIPPI::peekIO(uint16_t port, EmuTime time) const
106
{
107
	return i8255.peek(port & 0x03, time);
108
}
109
110
void SVIPPI::writeIO(uint16_t port, uint8_t value, EmuTime time)
111
{
112
	i8255.write(port & 0x03, value, time);
113
}
114
115
116
// I8255Interface
117
118
uint8_t SVIPPI::readA(EmuTime time)
119
{
120
	uint8_t triggers = ((ports[0]->read(time) & 0x10) ? 0x10 : 0) |
121
	                   ((ports[1]->read(time) & 0x10) ? 0x20 : 0);
122
123
	//uint8_t cassetteReady = cassettePort.Ready() ? 0 : 0x40;
124
	uint8_t cassetteReady = 0; // ready
125
126
	uint8_t cassetteInput = cassettePort.cassetteIn(time) ? 0x80 : 0x00;
127
128
	return triggers | cassetteReady | cassetteInput;
129
}
130
uint8_t SVIPPI::peekA(EmuTime /*time*/) const
131
{
132
	return 0; // TODO
133
}
134
void SVIPPI::writeA(uint8_t /*value*/, EmuTime /*time*/)
135
{
136
}
137
138
uint8_t SVIPPI::readB(EmuTime time)
139
{
140
	return peekB(time);
141
}
142
uint8_t SVIPPI::peekB(EmuTime /*time*/) const
143
{
144
	return keyboard.getKeys()[selectedRow];
145
}
146
void SVIPPI::writeB(uint8_t /*value*/, EmuTime /*time*/)
147
{
148
}
149
150
uint4_t SVIPPI::readC1(EmuTime time)
151
{
152
	return peekC1(time);
153
}
154
uint4_t SVIPPI::peekC1(EmuTime /*time*/) const
155
{
156
	return 15; // TODO check this
157
}
158
uint4_t SVIPPI::readC0(EmuTime time)
159
{
160
	return peekC0(time);
161
}
162
uint4_t SVIPPI::peekC0(EmuTime /*time*/) const
163
{
164
	return selectedRow;
165
}
166
void SVIPPI::writeC1(uint4_t value, EmuTime time)
167
{
168
	if ((prevBits ^ value) & 1) {
169
		cassettePort.setMotor((value & 1) == 0, time); // 0=0n, 1=Off
170
	}
171
	if ((prevBits ^ value) & 2) {
172
		cassettePort.cassetteOut((value & 2) != 0, time);
173
	}
174
	//if ((prevBits ^ value) & 4) {
175
	//	cassetteDevice.Mute(); // CASAUD, mute case speaker (1=enable, 0=disable)
176
	//}
177
	if ((prevBits ^ value) & 8) {
178
		click.setClick((value & 8) != 0, time);
179
	}
180
	prevBits = value;
181
}
182
void SVIPPI::writeC0(uint4_t value, EmuTime /*time*/)
183
{
184
	selectedRow = value;
185
}
186
187
template<typename Archive>
188
void SVIPPI::serialize(Archive& ar, unsigned /*version*/)
189
{
190
	ar.template serializeBase<MSXDevice>(*this);
191
	ar.serialize("i8255", i8255);
192
193
	// merge prevBits and selectedRow into one byte
194
	auto portC = uint8_t((prevBits << 4) | (selectedRow << 0));
195
	ar.serialize("portC", portC);
196
	if constexpr (Archive::IS_LOADER) {
197
		selectedRow = (portC >> 0) & 0xF;
198
		uint4_t bits = (portC >> 4) & 0xF;
199
		writeC1(bits, getCurrentTime());
200
	}
201
	ar.serialize("keyboard", keyboard);
202
}
203
INSTANTIATE_SERIALIZE_METHODS(SVIPPI);
204
REGISTER_MSXDEVICE(SVIPPI, "SVI-328 PPI");
205
206
} // namespace openmsx