22 , timerIRQlatch(false), timerIRQenabled(false)
23 , rxrdyIRQlatch(false), rxrdyIRQenabled(false)
24 , isExternalMSXMIDI(config.findChild(
"external") != nullptr)
25 , isEnabled(!isExternalMSXMIDI)
26 , isLimitedTo8251(true)
27 , outConnector(
MSXDevice::getPluggingController(),
"msx-midi-out")
28 , i8251(getScheduler(), interf, getCurrentTime())
29 , i8254(getScheduler(), &cntr0, nullptr, &cntr2, getCurrentTime())
40 if (isExternalMSXMIDI) {
44 "Bad MSX-MIDI configuration, when using "
45 "'external', you cannot specify I/O ports!");
58 if (isExternalMSXMIDI) {
66 timerIRQlatch =
false;
67 timerIRQenabled =
false;
69 rxrdyIRQlatch =
false;
70 rxrdyIRQenabled =
false;
73 if (isExternalMSXMIDI) {
89 return i8251.
readIO(port & 1, time);
97 return i8254.
readIO(port & 3, time);
113 return i8251.
peekIO(port & 1, time);
121 return i8254.
peekIO(port & 3, time);
129 if (isExternalMSXMIDI && ((port & 0xFF) == 0xE2)) {
131 registerIOports(value);
140 i8251.
writeIO(port & 1, value, time);
143 setTimerIRQ(
false, time);
151 i8254.
writeIO(port & 3, value, time);
156 void MSXMidi::registerIOports(
byte value)
158 assert(isExternalMSXMIDI);
162 if (newIsEnabled != isEnabled) {
169 registerRange(0xE0, 2);
171 registerRange(0xE8, 8);
175 if (isLimitedTo8251) {
176 unregisterRange(0xE0, 2);
178 unregisterRange(0xE8, 8);
182 }
else if (isEnabled && (newIsLimited != isLimitedTo8251)) {
187 unregisterRange(0xE8, 8);
188 registerRange (0xE0, 2);
191 unregisterRange(0xE0, 2);
192 registerRange (0xE8, 8);
196 isEnabled = newIsEnabled;
197 isLimitedTo8251 = newIsLimited;
200 void MSXMidi::registerRange(
byte port,
unsigned num)
202 for (
auto i :
xrange(num)) {
207 void MSXMidi::unregisterRange(
byte port,
unsigned num)
209 for (
auto i :
xrange(num)) {
215 void MSXMidi::setTimerIRQ(
bool status, EmuTime::param time)
217 if (timerIRQlatch != status) {
218 timerIRQlatch = status;
219 if (timerIRQenabled) {
220 timerIRQ.
set(timerIRQlatch);
222 updateEdgeEvents(time);
226 void MSXMidi::enableTimerIRQ(
bool enabled, EmuTime::param time)
228 if (timerIRQenabled != enabled) {
229 timerIRQenabled = enabled;
231 timerIRQ.
set(timerIRQenabled);
233 updateEdgeEvents(time);
237 void MSXMidi::updateEdgeEvents(EmuTime::param time)
239 bool wantEdges = timerIRQenabled && !timerIRQlatch;
243 void MSXMidi::setRxRDYIRQ(
bool status)
245 if (rxrdyIRQlatch != status) {
246 rxrdyIRQlatch = status;
247 if (rxrdyIRQenabled) {
248 rxrdyIRQ.
set(rxrdyIRQlatch);
253 void MSXMidi::enableRxRDYIRQ(
bool enabled)
255 if (rxrdyIRQenabled != enabled) {
256 rxrdyIRQenabled = enabled;
257 if (!rxrdyIRQenabled && rxrdyIRQlatch) {
266 void MSXMidi::I8251Interf::setRxRDY(
bool status, EmuTime::param )
269 midi.setRxRDYIRQ(status);
272 void MSXMidi::I8251Interf::setDTR(
bool status, EmuTime::param time)
275 midi.enableTimerIRQ(status, time);
278 void MSXMidi::I8251Interf::setRTS(
bool status, EmuTime::param )
281 midi.enableRxRDYIRQ(status);
284 bool MSXMidi::I8251Interf::getDSR(EmuTime::param )
287 return midi.timerIRQ.getState();
290 bool MSXMidi::I8251Interf::getCTS(EmuTime::param )
295 void MSXMidi::I8251Interf::setDataBits(DataBits bits)
298 midi.outConnector.setDataBits(bits);
301 void MSXMidi::I8251Interf::setStopBits(StopBits bits)
304 midi.outConnector.setStopBits(bits);
307 void MSXMidi::I8251Interf::setParityBit(
bool enable, ParityBit parity)
310 midi.outConnector.setParityBit(enable, parity);
313 void MSXMidi::I8251Interf::recvByte(
byte value, EmuTime::param time)
316 midi.outConnector.recvByte(value, time);
319 void MSXMidi::I8251Interf::signal(EmuTime::param time)
322 midi.getPluggedMidiInDev().signal(time);
328 void MSXMidi::Counter0::signal(
ClockPin& pin, EmuTime::param time)
331 ClockPin& clk = midi.i8251.getClockPin();
332 if (pin.isPeriodic()) {
333 clk.setPeriodicState(pin.getTotalDuration(),
334 pin.getHighDuration(), time);
336 clk.setState(pin.getState(time), time);
340 void MSXMidi::Counter0::signalPosEdge(
ClockPin& , EmuTime::param )
348 void MSXMidi::Counter2::signal(
ClockPin& pin, EmuTime::param time)
351 ClockPin& clk = midi.i8254.getClockPin(1);
352 if (pin.isPeriodic()) {
353 clk.setPeriodicState(pin.getTotalDuration(),
354 pin.getHighDuration(), time);
356 clk.setState(pin.getState(time), time);
360 void MSXMidi::Counter2::signalPosEdge(
ClockPin& , EmuTime::param time)
363 midi.setTimerIRQ(
true, time);
400 template<
typename Archive>
403 ar.template serializeBase<MSXDevice>(*
this);
405 ar.template serializeBase<MidiInConnector>(*
this);
406 ar.serialize(
"outConnector", outConnector,
407 "timerIRQ", timerIRQ,
408 "rxrdyIRQ", rxrdyIRQ,
409 "timerIRQlatch", timerIRQlatch,
410 "timerIRQenabled", timerIRQenabled,
411 "rxrdyIRQlatch", rxrdyIRQlatch,
412 "rxrdyIRQenabled", rxrdyIRQenabled,
415 if (ar.versionAtLeast(version, 2)) {
416 bool newIsEnabled = isEnabled;
417 bool newIsLimitedTo8251 = isLimitedTo8251;
418 ar.serialize(
"isEnabled", newIsEnabled,
419 "isLimitedTo8251", newIsLimitedTo8251);
420 if constexpr (Archive::IS_LOADER) {
421 if (isExternalMSXMIDI) {
void generateEdgeSignals(bool wanted, EmuTime::param time)
void setState(bool status, EmuTime::param time)
void setPeriodicState(EmuDuration::param total, EmuDuration::param hi, EmuTime::param time)
const XMLElement * findChild(std::string_view name) const
byte peekIO(word port, EmuTime::param time) const
void setStopBits(StopBits bits) override
void recvByte(byte value, EmuTime::param time) override
void setParityBit(bool enable, ParityBit parity) override
void writeIO(word port, byte value, EmuTime::param time)
void reset(EmuTime::param time)
void setDataBits(DataBits bits) override
byte readIO(word port, EmuTime::param time)
bool isRecvEnabled() const
byte peekIO(word port, EmuTime::param time) const
byte readIO(word port, EmuTime::param time)
ClockPin & getClockPin(unsigned cntr)
void writeIO(word port, byte value, EmuTime::param time)
ClockPin & getOutputPin(unsigned cntr)
void set()
Set the interrupt request on the bus.
void reset()
Reset the interrupt request on the bus.
void register_IO_Out(byte port, MSXDevice *device)
Devices can register their Out ports.
void register_IO_In(byte port, MSXDevice *device)
Devices can register their In ports.
void unregister_IO_In(byte port, MSXDevice *device)
void unregister_IO_Out(byte port, MSXDevice *device)
An MSXDevice is an emulated hardware component connected to the bus of the emulated MSX.
EmuTime::param getCurrentTime() const
MSXCPUInterface & getCPUInterface() const
bool acceptsData() override
MSXMidi(const DeviceConfig &config)
void recvByte(byte value, EmuTime::param time) override
void serialize(Archive &ar, unsigned version)
byte readIO(word port, EmuTime::param time) override
Read a byte from an IO port at a certain time from this device.
void setDataBits(DataBits bits) override
byte peekIO(word port, EmuTime::param time) const override
Read a byte from a given IO port.
void setParityBit(bool enable, ParityBit parity) override
void setStopBits(StopBits bits) override
void reset(EmuTime::param time) override
This method is called on reset.
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.
std::string getName(KeyCode keyCode)
Translate key code to key name.
This file implemented 3 utility functions:
constexpr byte DISABLED_VALUE
REGISTER_MSXDEVICE(ChakkariCopy, "ChakkariCopy")
uint16_t word
16 bit unsigned integer
constexpr byte LIMITED_RANGE_VALUE
#define OUTER(type, member)
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
constexpr auto xrange(T e)