diff --git a/acia.cpp b/acia.cpp index b76d174..bfd9ab1 100644 --- a/acia.cpp +++ b/acia.cpp @@ -4,8 +4,8 @@ #include "serialio.h" #include "acia.h" -void acia::operator=(uint8_t b) { - if (_acc & 1) { +void ACIA::write(Memory::address a, uint8_t b) { + if (a & 1) { _device->write(b); return; } @@ -42,8 +42,8 @@ void acia::operator=(uint8_t b) { // FIXME: more } -acia::operator uint8_t() { - if (_acc & 1) +uint8_t ACIA::read(Memory::address a) { + if (a & 1) return _device->read(); return _device->more()? rdrf | tdre: tdre; diff --git a/acia.h b/acia.h index a2dd3f3..b20cec9 100644 --- a/acia.h +++ b/acia.h @@ -1,12 +1,14 @@ #ifndef __ACIA_H__ #define __ACIA_H__ -class acia: public Memory::Device { -public: - void operator= (uint8_t); - operator uint8_t(); +// Motorola 6850 ACIA - acia(serialio &d): Memory::Device(256), _device(&d) {} +class ACIA { +public: + void write(Memory::address, uint8_t); + uint8_t read(Memory::address); + + ACIA(serialio &d): _device(&d) {} // status bits // diff --git a/pia.cpp b/pia.cpp new file mode 100644 index 0000000..53ba09d --- /dev/null +++ b/pia.cpp @@ -0,0 +1,179 @@ +#include +#include +#include "pia.h" + +// see: https://github.com/mamedev/mame/blob/master/src/devices/machine/6821pia.cpp +// and: https://github.com/mamedev/mame/blob/master/src/devices/machine/6821pia.h + +inline bool c1_low_to_high(uint8_t cr) { return cr & 0x02; } + +inline bool c1_high_to_low(uint8_t cr) { return !c1_low_to_high(cr); } + +inline bool c2_output(uint8_t cr) { return cr & 0x20; } + +inline bool c2_input(uint8_t cr) { return !c2_input(cr); } + +inline bool c2_low_to_high(uint8_t cr) { return cr & 0x10; } + +inline bool c2_high_to_low(uint8_t cr) { return !c2_low_to_high(cr); } + +inline bool output_selected(uint8_t cr) { return cr & 0x04; } + +void PIA::write(Memory::address a, uint8_t b) { +#if defined(DEBUGGING) + Serial.print(millis()); + Serial.print(" > "); + Serial.print(a, 16); + Serial.print(' '); + Serial.println(b, 16); +#endif + switch(a % 4) { + case 0: + output_selected(cra)? write_porta(b): write_ddra(b); + break; + case 1: + write_cra(b); + break; + case 2: + output_selected(crb)? write_portb(b): write_ddrb(b); + break; + case 3: + write_crb(b); + break; + } +} + +uint8_t PIA::read(Memory::address a) { +#if defined(DEBUGGING) + Serial.print(millis()); + Serial.print(" < "); + Serial.println(a, 16); +#endif + switch (a % 4) { + case 0: + return output_selected(cra)? read_porta(): read_ddra(); + case 1: + return read_cra(); + case 2: + return output_selected(crb)? read_portb(): read_ddrb(); + case 3: + return read_crb(); + } + return 0xff; +} + +void PIA::checkpoint(Stream &s) { + s.write(crb); + s.write(outb); + s.write(inb); + s.write(ddrb); + s.write(cra); + s.write(outa); + s.write(ina); + s.write(ddra); + s.write(irq_b1); + s.write(irq_b2); + s.write(irq_a1); + s.write(irq_a2); + s.write(cb1); + s.write(cb2); + s.write(ca1); + s.write(ca2); +} + +void PIA::restore(Stream &s) { + crb = s.read(); + outb = s.read(); + inb = s.read(); + ddrb = s.read(); + cra = s.read(); + outa = s.read(); + ina = s.read(); + ddra = s.read(); + irq_b1 = s.read(); + irq_b2 = s.read(); + irq_a1 = s.read(); + irq_a2 = s.read(); + cb1 = s.read(); + cb2 = s.read(); + ca1 = s.read(); + ca2 = s.read(); +} + +void PIA::write_ca1(bool state) { + + if (ca1 == state) + return; + + if ((state && c1_low_to_high(cra)) || (!state && c1_high_to_low(cra))) + irq_a1 = true; + + ca1 = state; +} + +void PIA::write_ca2(bool state) { + + if (ca2 == state || !c2_input(cra)) + return; + + if ((state && c2_low_to_high(cra)) || (!state && c2_high_to_low(cra))) + irq_a2 = true; + + ca2 = state; +} + +void PIA::write_cb1(bool state) { + + if (cb1 == state) + return; + + if ((state && c1_low_to_high(crb)) || (!state && c1_high_to_low(crb))) + irq_b1 = true; + + cb1 = state; +} + +void PIA::write_cb2(bool state) { + + if (cb2 == state || !c2_input(crb)) + return; + + if ((state && c2_low_to_high(crb)) || (!state && c2_high_to_low(crb))) + irq_b2 = true; + + cb2 = state; +} + +uint8_t PIA::read_cra() { + uint8_t b = cra; + + if (irq_a1) + b |= IRQ1; + + if (irq_a2 && c2_input(cra)) + b |= IRQ2; + + return b; +} + +uint8_t PIA::read_crb() { + uint8_t b = crb; + + if (irq_b1) + b |= IRQ1; + + if (irq_b2 && c2_input(crb)) + b |= IRQ2; + + return b; +} + +uint8_t PIA::read_porta() { + irq_a1 = irq_a2 = false; + return (ina & ~ddra) | (outa & ddra); +} + +uint8_t PIA::read_portb() { + irq_b1 = irq_b2 = false; + return (inb & ~ddrb) | (outb & ddrb); +} diff --git a/pia.h b/pia.h new file mode 100644 index 0000000..8104ff1 --- /dev/null +++ b/pia.h @@ -0,0 +1,57 @@ +#ifndef __PIA_H__ +#define __PIA_H__ + +// Motorola 6820 / 6821 PIA +// https://en.wikipedia.org/wiki/Peripheral_Interface_Adapter +class PIA { +public: + PIA(): outb(0), inb(0), crb(0), outa(0), ina(0), cra(0), ddrb(0), ddra(0), + ca1(false), ca2(false), cb1(false), cb2(false), + irq_a1(false), irq_a2(false), irq_b1(false), irq_b2(false) {} + + virtual void reset() { + outb = inb = crb = ddrb = outa = ina = cra = ddra = 0; + irq_a1 = irq_a2 = irq_b1 = irq_b2 = ca1 = ca2 = cb1 = cb2 = false; + } + + // device memory interface + void write(Memory::address, uint8_t); + uint8_t read(Memory::address); + + void checkpoint(Stream &); + void restore(Stream &); + + // device input (external) interface + void write_porta_in(uint8_t b) { ina = b; } + void write_ca1(bool); + void write_ca2(bool); + void write_portb_in(uint8_t b) { inb = b; } + void write_cb1(bool); + void write_cb2(bool); + + static const uint8_t IRQ1 = 0x80; + static const uint8_t IRQ2 = 0x40; + +protected: + // overrideable device memory interface + virtual uint8_t read_ddra() { return ddra; } + virtual uint8_t read_porta(); + virtual uint8_t read_cra(); + virtual uint8_t read_ddrb() { return ddrb; } + virtual uint8_t read_portb(); + virtual uint8_t read_crb(); + + virtual void write_ddra(uint8_t b) { ddra = b; } + virtual void write_porta(uint8_t b) { outa = b; } + virtual void write_cra(uint8_t b) { cra = (b & 0x3f); } + virtual void write_ddrb(uint8_t b) { ddrb = b; } + virtual void write_portb(uint8_t b) { outb = b; } + virtual void write_crb(uint8_t b) { crb = (b & 0x3f); } + +private: + uint8_t cra, ina, outa, ddra; + uint8_t crb, inb, outb, ddrb; + bool ca1, ca2, irq_a1, irq_a2; + bool cb1, cb2, irq_b1, irq_b2; +}; +#endif