diff --git a/TODO.md b/TODO.md deleted file mode 100644 index 988b75c..0000000 --- a/TODO.md +++ /dev/null @@ -1,11 +0,0 @@ -- more PIA: check out vice - -PIA init-sequence -5021 > 12 7F -5021 > 11 A7 -5022 > 13 A7 -5023 > 12 5C -5025 > 12 D -5026 > 12 0 - -http://mamedev.org/source/src/mess/machine/apple1.c.html diff --git a/io.cpp b/io.cpp index 16b9a48..30932c2 100644 --- a/io.cpp +++ b/io.cpp @@ -12,11 +12,6 @@ #include "hardware.h" #include "config.h" -#define ROWS 24 -#define COLS 40 -static unsigned r, c; -static char screen[ROWS][COLS]; - void io::reset() { Display::begin(BG_COLOUR, FG_COLOUR, ORIENT); clear(); @@ -28,7 +23,7 @@ void io::reset() { screen[j][i] = ' '; _loading = false; - pia::reset(); + PIA::reset(); } void io::load() { @@ -78,13 +73,14 @@ static const uint8_t shiftmap[] PROGMEM = { }; void io::down(uint8_t scan) { - set_porta(0); if (isshift(scan)) _shift = true; } void io::enter(uint8_t key) { - set_porta(key + 0x80); + PIA::write_ca1(false); + PIA::write_porta_in(key + 0x80); + PIA::write_ca1(true); } void io::up(uint8_t scan) { @@ -142,25 +138,21 @@ void io::display(uint8_t b) { void io::write_portb(uint8_t b) { b &= 0x7f; display(b); - pia::write_portb(b); + PIA::write_portb(b); } -uint8_t io::read_porta_cr() { - uint8_t b = pia::read_porta_cr(); - if (b != 0xa7) - return b; - +uint8_t io::read_cra() { if (_loading) { if (files.more()) enter(files.read()); else _loading = false; } - return b; + return PIA::read_cra(); } void io::checkpoint(Stream &s) { - pia::checkpoint(s); + PIA::checkpoint(s); s.write(r); s.write(c); for (int j = 0; j < ROWS; j++) @@ -169,7 +161,7 @@ void io::checkpoint(Stream &s) { } void io::restore(Stream &s) { - pia::restore(s); + PIA::restore(s); r = s.read(); c = s.read(); for (int j = 0; j < ROWS; j++) diff --git a/io.h b/io.h index 9d19df9..619e0ec 100644 --- a/io.h +++ b/io.h @@ -1,30 +1,37 @@ #ifndef _IO_H #define _IO_H -// http://mamedev.org/source/src/mess/machine/apple1.c.html -class io: public Display, Keyboard, public pia { +class io: public Memory::Device, public Display, Keyboard, public PIA { public: - io(filer &files): files(files) {} + io(filer &files): Memory::Device(Memory::page_size), files(files) {} virtual void reset(); - virtual void down(uint8_t scan); - virtual void up(uint8_t scan); + virtual void down(uint8_t); + virtual void up(uint8_t); + + virtual void operator=(uint8_t b) { PIA::write(_acc, b); } + virtual operator uint8_t() { return PIA::read(_acc); } virtual void checkpoint(Stream &); virtual void restore(Stream &); virtual void write_portb(uint8_t); - virtual uint8_t read_porta_cr(); + virtual uint8_t read_cra(); void load(); filer &files; + + static const uint8_t ROWS = 24; + static const uint8_t COLS = 40; + private: void display(uint8_t); void draw(char, int, int); void enter(uint8_t); - bool _shift; - bool _loading; + bool _shift, _loading; + uint8_t r, c; + char screen[ROWS][COLS]; }; #endif diff --git a/pia.cpp b/pia.cpp index a5e06fb..53ba09d 100644 --- a/pia.cpp +++ b/pia.cpp @@ -2,60 +2,178 @@ #include #include "pia.h" -void pia::operator=(uint8_t b) { +// 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(_acc, 16); + Serial.print(a, 16); Serial.print(' '); Serial.println(b, 16); #endif - switch(_acc % 4) { + switch(a % 4) { case 0: - write_porta(b); + output_selected(cra)? write_porta(b): write_ddra(b); break; case 1: - write_porta_cr(b); + write_cra(b); break; case 2: - write_portb(b); + output_selected(crb)? write_portb(b): write_ddrb(b); break; case 3: - write_portb_cr(b); + write_crb(b); break; } } -pia::operator uint8_t() { +uint8_t PIA::read(Memory::address a) { #if defined(DEBUGGING) Serial.print(millis()); Serial.print(" < "); - Serial.println(_acc, 16); + Serial.println(a, 16); #endif - switch (_acc % 4) { + switch (a % 4) { case 0: - return read_porta(); + return output_selected(cra)? read_porta(): read_ddra(); case 1: - return read_porta_cr(); + return read_cra(); case 2: - return read_portb(); + return output_selected(crb)? read_portb(): read_ddrb(); case 3: - return read_portb_cr(); + return read_crb(); } return 0xff; } -void pia::checkpoint(Stream &s) { - s.write(portb_cr); - s.write(portb); - s.write(porta_cr); - s.write(porta); +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) { - portb_cr = s.read(); - portb = s.read(); - porta_cr = s.read(); - porta = s.read(); +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 index 1818429..8104ff1 100644 --- a/pia.h +++ b/pia.h @@ -1,51 +1,57 @@ #ifndef __PIA_H__ #define __PIA_H__ -class pia: public Memory::Device { +// Motorola 6820 / 6821 PIA +// https://en.wikipedia.org/wiki/Peripheral_Interface_Adapter +class PIA { public: - pia(): Memory::Device(256), portb_cr(0), porta_cr(0) {} - virtual void reset() { portb_cr = porta_cr = 0; } + 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) {} - void operator=(uint8_t); - operator uint8_t(); + 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: - // write to the "external" side of the port - void set_porta(uint8_t b) { - porta = b; - if (b & 0x80) - porta_cr = 0xa7; - } + // 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(); - // "device-side" operations (called from memory interface) - uint8_t read_porta() { return porta; } - virtual uint8_t read_porta_cr() { - if (porta_cr & 0x80) { - porta_cr = 0; - return 0xa7; - } - return porta_cr; - } - uint8_t read_portb() { return portb; } - uint8_t read_portb_cr() { return portb_cr; } - - void write_porta(uint8_t b) { porta = b; } - void write_porta_cr(uint8_t b) { - if (!(porta_cr & 0x80) && b >= 0x80) - porta_cr |= 0x80; - else - porta_cr = b; - } - virtual void write_portb(uint8_t b) { portb = b; } - void write_portb_cr(uint8_t b) { - if (portb_cr < 0x80) - portb_cr = b; - } + 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 portb_cr, portb, porta_cr, porta; + 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