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