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