15static constexpr byte LIMITED_RANGE_VALUE = 0x01;
16static constexpr byte DISABLED_VALUE = 0x80;
21 , timerIRQ(getMotherBoard(),
MSXDevice::getName() +
".IRQtimer")
22 , rxrdyIRQ(getMotherBoard(),
MSXDevice::getName() +
".IRQrxrdy")
23 , isExternalMSXMIDI(config.findChild(
"external") != nullptr)
24 , isEnabled(!isExternalMSXMIDI)
25 , outConnector(
MSXDevice::getPluggingController(),
"MSX-MIDI-out")
26 , i8251(getScheduler(), interface, getCurrentTime())
27 , i8254(getScheduler(), &cntr0, nullptr, &cntr2, getCurrentTime())
38 if (isExternalMSXMIDI) {
42 "Bad MSX-MIDI configuration, when using "
43 "'external', you cannot specify I/O ports!");
56 if (isExternalMSXMIDI) {
57 registerIOports(DISABLED_VALUE | LIMITED_RANGE_VALUE);
64 timerIRQlatch =
false;
65 timerIRQenabled =
false;
67 rxrdyIRQlatch =
false;
68 rxrdyIRQenabled =
false;
71 if (isExternalMSXMIDI) {
72 registerIOports(DISABLED_VALUE | LIMITED_RANGE_VALUE);
87 return i8251.
readIO(port & 1, time);
95 return i8254.
readIO(port & 3, time);
111 return i8251.
peekIO(port & 1, time);
119 return i8254.
peekIO(port & 3, time);
127 if (isExternalMSXMIDI && ((port & 0xFF) == 0xE2)) {
129 registerIOports(value);
138 i8251.
writeIO(port & 1, value, time);
141 setTimerIRQ(
false, time);
149 i8254.
writeIO(port & 3, value, time);
154void MSXMidi::registerIOports(
byte value)
156 assert(isExternalMSXMIDI);
157 bool newIsEnabled = (value & DISABLED_VALUE) == 0;
158 bool newIsLimited = (value & LIMITED_RANGE_VALUE) != 0;
161 if (newIsEnabled != isEnabled) {
168 cpuInterface.register_IO_InOut_range(0xE0, 2,
this);
170 cpuInterface.register_IO_InOut_range(0xE8, 8,
this);
174 if (isLimitedTo8251) {
175 cpuInterface.unregister_IO_InOut_range(0xE0, 2,
this);
177 cpuInterface.unregister_IO_InOut_range(0xE8, 8,
this);
181 }
else if (isEnabled && (newIsLimited != isLimitedTo8251)) {
186 cpuInterface.unregister_IO_InOut_range(0xE8, 8,
this);
187 cpuInterface.register_IO_InOut_range (0xE0, 2,
this);
190 cpuInterface.unregister_IO_InOut_range(0xE0, 2,
this);
191 cpuInterface.register_IO_InOut_range (0xE8, 8,
this);
195 isEnabled = newIsEnabled;
196 isLimitedTo8251 = newIsLimited;
199void MSXMidi::setTimerIRQ(
bool status, EmuTime::param time)
201 if (timerIRQlatch != status) {
202 timerIRQlatch = status;
203 if (timerIRQenabled) {
204 timerIRQ.
set(timerIRQlatch);
206 updateEdgeEvents(time);
210void MSXMidi::enableTimerIRQ(
bool enabled, EmuTime::param time)
212 if (timerIRQenabled != enabled) {
213 timerIRQenabled = enabled;
215 timerIRQ.
set(timerIRQenabled);
217 updateEdgeEvents(time);
221void MSXMidi::updateEdgeEvents(EmuTime::param time)
223 bool wantEdges = timerIRQenabled && !timerIRQlatch;
227void MSXMidi::setRxRDYIRQ(
bool status)
229 if (rxrdyIRQlatch != status) {
230 rxrdyIRQlatch = status;
231 if (rxrdyIRQenabled) {
232 rxrdyIRQ.
set(rxrdyIRQlatch);
237void MSXMidi::enableRxRDYIRQ(
bool enabled)
239 if (rxrdyIRQenabled != enabled) {
240 rxrdyIRQenabled = enabled;
241 if (!rxrdyIRQenabled && rxrdyIRQlatch) {
250void MSXMidi::Interface::setRxRDY(
bool status, EmuTime::param )
252 auto& midi =
OUTER(MSXMidi, interface);
253 midi.setRxRDYIRQ(status);
256void MSXMidi::Interface::setDTR(
bool status, EmuTime::param time)
258 auto& midi =
OUTER(MSXMidi, interface);
259 midi.enableTimerIRQ(status, time);
262void MSXMidi::Interface::setRTS(
bool status, EmuTime::param )
264 auto& midi =
OUTER(MSXMidi, interface);
265 midi.enableRxRDYIRQ(status);
268bool MSXMidi::Interface::getDSR(EmuTime::param )
270 const auto& midi =
OUTER(MSXMidi, interface);
271 return midi.timerIRQ.getState();
274bool MSXMidi::Interface::getCTS(EmuTime::param )
279void MSXMidi::Interface::setDataBits(DataBits bits)
281 auto& midi =
OUTER(MSXMidi, interface);
282 midi.outConnector.setDataBits(bits);
285void MSXMidi::Interface::setStopBits(StopBits bits)
287 auto& midi =
OUTER(MSXMidi, interface);
288 midi.outConnector.setStopBits(bits);
291void MSXMidi::Interface::setParityBit(
bool enable, Parity parity)
293 auto& midi =
OUTER(MSXMidi, interface);
294 midi.outConnector.setParityBit(enable, parity);
297void MSXMidi::Interface::recvByte(
byte value, EmuTime::param time)
299 auto& midi =
OUTER(MSXMidi, interface);
300 midi.outConnector.recvByte(value, time);
303void MSXMidi::Interface::signal(EmuTime::param time)
305 const auto& midi =
OUTER(MSXMidi, interface);
306 midi.getPluggedMidiInDev().signal(time);
312void MSXMidi::Counter0::signal(ClockPin& pin, EmuTime::param time)
314 auto& midi =
OUTER(MSXMidi, cntr0);
315 ClockPin& clk = midi.i8251.getClockPin();
316 if (pin.isPeriodic()) {
317 clk.setPeriodicState(pin.getTotalDuration(),
318 pin.getHighDuration(), time);
320 clk.setState(pin.getState(time), time);
324void MSXMidi::Counter0::signalPosEdge(ClockPin& , EmuTime::param )
332void MSXMidi::Counter2::signal(ClockPin& pin, EmuTime::param time)
334 auto& midi =
OUTER(MSXMidi, cntr2);
335 ClockPin& clk = midi.i8254.getClockPin(1);
336 if (pin.isPeriodic()) {
337 clk.setPeriodicState(pin.getTotalDuration(),
338 pin.getHighDuration(), time);
340 clk.setState(pin.getState(time), time);
344void MSXMidi::Counter2::signalPosEdge(ClockPin& , EmuTime::param time)
346 auto& midi =
OUTER(MSXMidi, cntr2);
347 midi.setTimerIRQ(
true, time);
384template<
typename Archive>
387 ar.template serializeBase<MSXDevice>(*
this);
389 ar.template serializeBase<MidiInConnector>(*
this);
390 ar.serialize(
"outConnector", outConnector,
391 "timerIRQ", timerIRQ,
392 "rxrdyIRQ", rxrdyIRQ,
393 "timerIRQlatch", timerIRQlatch,
394 "timerIRQenabled", timerIRQenabled,
395 "rxrdyIRQlatch", rxrdyIRQlatch,
396 "rxrdyIRQenabled", rxrdyIRQenabled,
399 if (ar.versionAtLeast(version, 2)) {
400 bool newIsEnabled = isEnabled;
401 bool newIsLimitedTo8251 = isLimitedTo8251;
402 ar.serialize(
"isEnabled", newIsEnabled,
403 "isLimitedTo8251", newIsLimitedTo8251);
404 if constexpr (Archive::IS_LOADER) {
405 if (isExternalMSXMIDI) {
406 registerIOports((newIsEnabled ? 0x00 : DISABLED_VALUE) | (newIsLimitedTo8251 ? LIMITED_RANGE_VALUE : 0x00));
#define REGISTER_MSXDEVICE(CLASS, NAME)
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 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)
void setParityBit(bool enable, Parity parity) override
bool isRecvEnabled() const
uint8_t peekIO(uint16_t port, EmuTime::param time) const
void writeIO(uint16_t port, uint8_t value, EmuTime::param time)
uint8_t readIO(uint16_t port, EmuTime::param time)
ClockPin & getClockPin(unsigned cntr)
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 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 setStopBits(StopBits bits) override
void setParityBit(bool enable, Parity parity) 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.
This file implemented 3 utility functions:
uint16_t word
16 bit unsigned integer
#define OUTER(type, member)
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)