bsnes-plus/bsnes/snes/chip/dos/dos_serial.cpp
MrL314 cba7d05f72
dos: fixed floppy memory bug, added xml mapping
fixed bug where floppy data buffer from previous session would be saved to next session's floppy buffer when cartridge loaded.
added xml parsing option for remapping dos
added FDC_RESET_STANDBY debugging output, however standby and clock functionality are not implemented yet.
added debugging output detecting whether a floppy disk image already exists for a current rom, and creates a new disk only if one doesn't exist.
2021-07-26 17:30:06 -04:00

154 lines
2.9 KiB
C++

#ifdef DOS_CPP
DOSSerial::DOSSerial() {
reset();
}
DOSSerial::~DOSSerial() {
}
void DOSSerial::init() {
reset();
}
void DOSSerial::reset() {
reset(0);
reset(1);
irq_enable = false;
}
void DOSSerial::power() {
reset();
}
void DOSSerial::unload() {
}
void DOSSerial::reset(bool channel) {
memset(&channels[channel], 0, sizeof(channels[0]));
}
uint8 DOSSerial::read(uint3 addr) {
auto& channel = channels[!(addr & 2)];
uint8 data = 0;
if (addr & 1) {
// reading data from peripheral
data = channel.rx_buffer[0];
if (channel.rx_count
&& !Memory::debugger_access()) {
channel.rx_buffer[0] = channel.rx_buffer[1];
channel.rx_buffer[1] = channel.rx_buffer[2];
channel.rx_buffer[2] = 0;
channel.rx_count--;
if (!channel.rx_count)
channel.rx_irq_pending = false;
dos.irq_process();
}
} else {
// reading register
switch (channel.nreg) {
case 0x00:
data = ((!!channel.rx_count) << 0)
| ((!channel.tx_count) << 2);
break;
case 0x01:
data = (channel.rx_overflow << 5);
break;
case 0x03:
data = irq_status();
break;
}
if (!Memory::debugger_access())
channel.nreg = 0;
}
return data;
}
void DOSSerial::write(uint3 addr, uint8 data) {
if (Memory::debugger_access())
return;
auto& channel = channels[!(addr & 2)];
if (addr & 1) {
// writing data to peripheral (TODO)
} else if (channel.nreg == 0) {
// selecting register
channel.nreg = data & 7;
// SCC command codes
switch ((data >> 3) & 7) {
case 1: // point high
channel.nreg |= 8;
break;
case 6: // error reset
channel.rx_overflow = false;
break;
case 7: // interrupt reset
dos.irq_process();
break;
}
} else {
// writing to register
switch (channel.nreg) {
case 1: // TX/RX interrupt control
channel.tx_irq_enable = (data & 0x2);
channel.rx_irq_enable = (data >> 3) & 0x3;
break;
case 3: // RX control
channel.rx_enable = (data & 0x1);
break;
case 5: // TX control
channel.tx_enable = (data & 0x8);
break;
case 9: // master interrupt control
irq_enable = (data & 0x8);
if (data & 0x80) reset(0);
if (data & 0x40) reset(1);
dos.irq_process();
break;
}
channel.nreg = 0;
}
}
void DOSSerial::send_data(bool num, uint8 data) {
auto& channel = channels[num];
if (channel.rx_enable) {
if (channel.rx_count < 3) {
channel.rx_buffer[channel.rx_count++] = data;
} else {
channel.rx_overflow = true;
}
if (channel.rx_irq_enable) {
channel.rx_irq_pending = true;
dos.irq_process();
}
}
}
uint8 DOSSerial::irq_status() const {
return (channels[1].tx_irq_pending << 1)
| (channels[1].rx_irq_pending << 2)
| (channels[0].tx_irq_pending << 4)
| (channels[0].rx_irq_pending << 5);
}
#endif