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