openMSX
SC3000PPI.cc
Go to the documentation of this file.
1#include "SC3000PPI.hh"
2#include "MSXMotherBoard.hh"
3#include "Reactor.hh"
4#include "CassettePort.hh"
5#include "JoystickPort.hh"
6#include "XMLElement.hh"
7#include "GlobalSettings.hh"
8#include "serialize.hh"
9
10namespace openmsx {
11
12// MSXDevice
13
15 : MSXDevice(config)
16 , cassettePort(getMotherBoard().getCassettePort())
17 , i8255(*this, getCurrentTime(), config.getGlobalSettings().getInvalidPpiModeSetting())
18 , keyboard(
19 config.getMotherBoard(),
20 config.getMotherBoard().getScheduler(),
21 config.getMotherBoard().getCommandController(),
22 config.getMotherBoard().getReactor().getEventDistributor(),
23 config.getMotherBoard().getMSXEventDistributor(),
24 config.getMotherBoard().getStateChangeDistributor(),
25 Keyboard::MATRIX_SEGA, config)
26{
27 MSXMotherBoard& motherBoard = getMotherBoard();
28 auto time = getCurrentTime();
29
30 for (unsigned i = 0; i < 2; i++) {
31 ports[i] = &motherBoard.getJoystickPort(i);
32 // Clear strobe bit, or MSX joysticks will stay silent.
33 ports[i]->write(0xFB, time);
34 }
35
36 reset(time);
37}
38
39void SC3000PPI::reset(EmuTime::param time)
40{
41 i8255.reset(time);
42}
43
44byte SC3000PPI::readIO(word port, EmuTime::param time)
45{
46 return i8255.read(port & 0x03, time);
47}
48
49byte SC3000PPI::peekIO(word port, EmuTime::param time) const
50{
51 return i8255.peek(port & 0x03, time);
52}
53
54void SC3000PPI::writeIO(word port, byte value, EmuTime::param time)
55{
56 i8255.write(port & 0x03, value, time);
57}
58
59
60// I8255Interface
61
62byte SC3000PPI::readA(EmuTime::param time)
63{
64 return peekA(time);
65}
66byte SC3000PPI::peekA(EmuTime::param time) const
67{
68 if (selectedRow == 7) {
69 // Joystick hardware cannot detect when it's being read, so using the
70 // read method for peeking should be safe.
71 byte joy1 = ports[0]->read(time) & 0x3F;
72 byte joy2 = ports[1]->read(time) & 0x3F;
73 return joy1 | (joy2 << 6);
74 } else {
75 return keyboard.getKeys()[selectedRow];
76 }
77}
78void SC3000PPI::writeA(byte /*value*/, EmuTime::param /*time*/)
79{
80}
81
82byte SC3000PPI::readB(EmuTime::param time)
83{
84 return peekB(time);
85}
86byte SC3000PPI::peekB(EmuTime::param time) const
87{
88 // TODO: Are bits 4-7 available regardless of which keyboard row is selected?
89 // That would make sense, but check the schematics.
90 if (selectedRow == 7) {
91 // Joystick hardware cannot detect when it's being read, so using the
92 // read method for peeking should be safe.
93 byte joy2 = ports[1]->read(time) & 0x3F;
94 return 0xF0 | (joy2 >> 2);
95 } else {
96 /*
97 Signal Description
98
99 PB0 Keyboard input
100 PB1 Keyboard input
101 PB2 Keyboard input
102 PB3 Keyboard input
103 PB4 /CONT input from cartridge terminal B-11
104 PB5 FAULT input from printer
105 PB6 BUSY input from printer
106 PB7 Cassette tape input
107 */
108 auto keys = keyboard.getKeys()[selectedRow + 7];
109 return 0xF0 | keys;
110 }
111}
112void SC3000PPI::writeB(byte /*value*/, EmuTime::param /*time*/)
113{
114}
115
116nibble SC3000PPI::readC1(EmuTime::param time)
117{
118 return peekC1(time);
119}
120nibble SC3000PPI::peekC1(EmuTime::param /*time*/) const
121{
122 // TODO: Check.
123 return 15;
124}
125nibble SC3000PPI::readC0(EmuTime::param time)
126{
127 return peekC0(time);
128}
129nibble SC3000PPI::peekC0(EmuTime::param /*time*/) const
130{
131 // TODO: Is this selection readable at all? And if so, what is the value
132 // of bit 3?
133 return selectedRow;
134}
135void SC3000PPI::writeC1(nibble value, EmuTime::param time)
136{
137 if ((prevBits ^ value) & 1) {
138 cassettePort.setMotor((value & 1) == 0, time); // 0=0n, 1=Off
139 }
140 if ((prevBits ^ value) & 2) {
141 cassettePort.cassetteOut((value & 2) != 0, time);
142 }
143 //if ((prevBits ^ value) & 4) {
144 // cassetteDevice.Mute(); // CASAUD, mute case speaker (1=enable, 0=disable)
145 //}
146 //if ((prevBits ^ value) & 8) {
147 // click.setClick((value & 8) != 0, time);
148 //}
149 prevBits = value;
150}
151void SC3000PPI::writeC0(nibble value, EmuTime::param /*time*/)
152{
153 selectedRow = value & 7;
154 //fprintf(stderr, "SC3000PPI: selected row %d\n", selectedRow);
155}
156
157template<typename Archive>
158void SC3000PPI::serialize(Archive& ar, unsigned /*version*/)
159{
160 ar.template serializeBase<MSXDevice>(*this);
161 ar.serialize("i8255", i8255);
162
163 // merge prevBits and selectedRow into one byte
164 byte portC = (prevBits << 4) | (selectedRow << 0);
165 ar.serialize("portC", portC);
166 if constexpr (Archive::IS_LOADER) {
167 selectedRow = (portC >> 0) & 0xF;
168 nibble bits = (portC >> 4) & 0xF;
169 writeC1(bits, getCurrentTime());
170 }
171 ar.serialize("keyboard", keyboard);
172}
175
176} // 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.
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
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)
Connects SC-3000 peripherals to the PPI (8255).
Definition: SC3000PPI.hh:18
byte readIO(word port, EmuTime::param time) override
Read a byte from an IO port at a certain time from this device.
Definition: SC3000PPI.cc:44
SC3000PPI(const DeviceConfig &config)
Definition: SC3000PPI.cc:14
byte peekIO(word port, EmuTime::param time) const override
Read a byte from a given IO port.
Definition: SC3000PPI.cc:49
void reset(EmuTime::param time) override
This method is called on reset.
Definition: SC3000PPI.cc:39
void serialize(Archive &ar, unsigned version)
Definition: SC3000PPI.cc:158
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: SC3000PPI.cc:54
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
constexpr auto keys(Map &&map)
Definition: view.hh:463
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:1021