15static constexpr byte LIMITED_RANGE_VALUE = 0x01;
16static constexpr byte DISABLED_VALUE = 0x80;
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;
160 if (newIsEnabled != isEnabled) {
167 registerRange(0xE0, 2);
169 registerRange(0xE8, 8);
173 if (isLimitedTo8251) {
174 unregisterRange(0xE0, 2);
176 unregisterRange(0xE8, 8);
180 }
else if (isEnabled && (newIsLimited != isLimitedTo8251)) {
185 unregisterRange(0xE8, 8);
186 registerRange (0xE0, 2);
189 unregisterRange(0xE0, 2);
190 registerRange (0xE8, 8);
194 isEnabled = newIsEnabled;
195 isLimitedTo8251 = newIsLimited;
198void MSXMidi::registerRange(
byte port,
unsigned num)
200 for (
auto i :
xrange(num)) {
205void MSXMidi::unregisterRange(
byte port,
unsigned num)
207 for (
auto i :
xrange(num)) {
213void MSXMidi::setTimerIRQ(
bool status, EmuTime::param time)
215 if (timerIRQlatch != status) {
216 timerIRQlatch = status;
217 if (timerIRQenabled) {
218 timerIRQ.
set(timerIRQlatch);
220 updateEdgeEvents(time);
224void MSXMidi::enableTimerIRQ(
bool enabled, EmuTime::param time)
226 if (timerIRQenabled != enabled) {
227 timerIRQenabled = enabled;
229 timerIRQ.
set(timerIRQenabled);
231 updateEdgeEvents(time);
235void MSXMidi::updateEdgeEvents(EmuTime::param time)
237 bool wantEdges = timerIRQenabled && !timerIRQlatch;
241void MSXMidi::setRxRDYIRQ(
bool status)
243 if (rxrdyIRQlatch != status) {
244 rxrdyIRQlatch = status;
245 if (rxrdyIRQenabled) {
246 rxrdyIRQ.
set(rxrdyIRQlatch);
251void MSXMidi::enableRxRDYIRQ(
bool enabled)
253 if (rxrdyIRQenabled != enabled) {
254 rxrdyIRQenabled = enabled;
255 if (!rxrdyIRQenabled && rxrdyIRQlatch) {
264void MSXMidi::Interface::setRxRDY(
bool status, EmuTime::param )
267 midi.setRxRDYIRQ(status);
270void MSXMidi::Interface::setDTR(
bool status, EmuTime::param time)
273 midi.enableTimerIRQ(status, time);
276void MSXMidi::Interface::setRTS(
bool status, EmuTime::param )
279 midi.enableRxRDYIRQ(status);
282bool MSXMidi::Interface::getDSR(EmuTime::param )
285 return midi.timerIRQ.getState();
288bool MSXMidi::Interface::getCTS(EmuTime::param )
293void MSXMidi::Interface::setDataBits(DataBits bits)
296 midi.outConnector.setDataBits(bits);
299void MSXMidi::Interface::setStopBits(StopBits bits)
302 midi.outConnector.setStopBits(bits);
305void MSXMidi::Interface::setParityBit(
bool enable, ParityBit parity)
308 midi.outConnector.setParityBit(enable, parity);
311void MSXMidi::Interface::recvByte(
byte value, EmuTime::param time)
314 midi.outConnector.recvByte(value, time);
317void MSXMidi::Interface::signal(EmuTime::param time)
320 midi.getPluggedMidiInDev().signal(time);
326void MSXMidi::Counter0::signal(
ClockPin& pin, EmuTime::param time)
329 ClockPin& clk = midi.i8251.getClockPin();
330 if (pin.isPeriodic()) {
331 clk.setPeriodicState(pin.getTotalDuration(),
332 pin.getHighDuration(), time);
334 clk.setState(pin.getState(time), time);
338void MSXMidi::Counter0::signalPosEdge(
ClockPin& , EmuTime::param )
346void MSXMidi::Counter2::signal(
ClockPin& pin, EmuTime::param time)
349 ClockPin& clk = midi.i8254.getClockPin(1);
350 if (pin.isPeriodic()) {
351 clk.setPeriodicState(pin.getTotalDuration(),
352 pin.getHighDuration(), time);
354 clk.setState(pin.getState(time), time);
358void MSXMidi::Counter2::signalPosEdge(
ClockPin& , EmuTime::param time)
361 midi.setTimerIRQ(
true, time);
398template<
typename Archive>
401 ar.template serializeBase<MSXDevice>(*
this);
403 ar.template serializeBase<MidiInConnector>(*
this);
404 ar.serialize(
"outConnector", outConnector,
405 "timerIRQ", timerIRQ,
406 "rxrdyIRQ", rxrdyIRQ,
407 "timerIRQlatch", timerIRQlatch,
408 "timerIRQenabled", timerIRQenabled,
409 "rxrdyIRQlatch", rxrdyIRQlatch,
410 "rxrdyIRQenabled", rxrdyIRQenabled,
413 if (ar.versionAtLeast(version, 2)) {
414 bool newIsEnabled = isEnabled;
415 bool newIsLimitedTo8251 = isLimitedTo8251;
416 ar.serialize(
"isEnabled", newIsEnabled,
417 "isLimitedTo8251", newIsLimitedTo8251);
418 if constexpr (Archive::IS_LOADER) {
419 if (isExternalMSXMIDI) {
420 registerIOports((newIsEnabled ? 0x00 : DISABLED_VALUE) | (newIsLimitedTo8251 ? LIMITED_RANGE_VALUE : 0x00));
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
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 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:
REGISTER_MSXDEVICE(ChakkariCopy, "ChakkariCopy")
uint16_t word
16 bit unsigned integer
#define OUTER(type, member)
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
constexpr auto xrange(T e)