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