collapseos/emul/z80/acia.c
Virgil Dupras 3581beace0 rc2014: de-buffer MC6850 and SIO drivers
The buffer's implementation wasn't buying us much in exchange for its
complexity. A modern machine was still too fast for it (copy/pasting
text from a modern machine would send bytes too fast for the RC2014)
and in the (theoretical so far) case of COS-to-COS communication, the
buffer didn't help in cases where the baud rate was faster than the
processing of each byte received (for example, if the byte was written
directly to EEPROM).

I'm scrapping it and, instead, use the RTS flag to signal the other
side when we're ready to receive a new byte.

Also, implement driver for channel B in SIO. I will need it to talk
to my TRS-80 4P.
2020-12-29 21:36:19 -05:00

88 lines
1.6 KiB
C

#include <stdio.h>
#include "acia.h"
static void _check_irq(ACIA *acia)
{
// do we have RDRF?
if ((acia->status & 0x01) && (acia->control & 0x80)) {
acia->status |= 0x80;
}
// do we have TDRE?
if ((acia->status & 0x02) && ((acia->control & 0xe0) == 0xe0)) {
acia->status |= 0x80;
}
}
void acia_init(ACIA *acia)
{
acia->status = 0x02; // TDRE
acia->control = 0x00;
acia->rx = 0;
acia->tx = 0;
acia->in_int = false;
}
bool acia_has_irq(ACIA *acia)
{
if (acia->in_int) {
return false;
}
acia->in_int = acia->status & 0x80;
return acia->in_int;
}
bool acia_hasrx(ACIA *acia)
{
return acia->status & 0x01; // RDRF
}
bool acia_hastx(ACIA *acia)
{
return !(acia->status & 0x02); // TRDE
}
uint8_t acia_read(ACIA *acia)
{
acia->status |= 0x02; // TRDE high
_check_irq(acia);
return acia->tx;
}
void acia_write(ACIA *acia, uint8_t val)
{
if (acia->control & 0x40) { // RTS high
fprintf(stderr, "ACIA RTS high: can't send byte\n");
return;
}
acia->status |= 0x01; // RDRF high
acia->rx = val;
_check_irq(acia);
}
uint8_t acia_ctl_rd(ACIA *acia)
{
return acia->status;
}
void acia_ctl_wr(ACIA *acia, uint8_t val)
{
acia->control = val;
_check_irq(acia);
}
uint8_t acia_data_rd(ACIA *acia)
{
acia->status &= ~0x81; // RDRF and IRQ low
acia->in_int = false;
return acia->rx;
}
void acia_data_wr(ACIA *acia, uint8_t val)
{
acia->tx = val;
acia->status &= ~0x82; // TRDE and IRQ low
acia->in_int = false;
_check_irq(acia);
}