PIA refactoring (#6)

* PIA cleanup

* move Apple1-dependent bits onto io class

* implement irq_a1 and irq_b1

* irq2 + cleanups

* ddr part 1

* ddr processing part 2

* ...
This commit is contained in:
Stephen Crane 2023-09-27 10:35:18 +01:00 committed by GitHub
parent c129e717d8
commit 44c3cc1ea7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 208 additions and 96 deletions

11
TODO.md
View File

@ -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

26
io.cpp
View File

@ -12,11 +12,6 @@
#include "hardware.h" #include "hardware.h"
#include "config.h" #include "config.h"
#define ROWS 24
#define COLS 40
static unsigned r, c;
static char screen[ROWS][COLS];
void io::reset() { void io::reset() {
Display::begin(BG_COLOUR, FG_COLOUR, ORIENT); Display::begin(BG_COLOUR, FG_COLOUR, ORIENT);
clear(); clear();
@ -28,7 +23,7 @@ void io::reset() {
screen[j][i] = ' '; screen[j][i] = ' ';
_loading = false; _loading = false;
pia::reset(); PIA::reset();
} }
void io::load() { void io::load() {
@ -78,13 +73,14 @@ static const uint8_t shiftmap[] PROGMEM = {
}; };
void io::down(uint8_t scan) { void io::down(uint8_t scan) {
set_porta(0);
if (isshift(scan)) if (isshift(scan))
_shift = true; _shift = true;
} }
void io::enter(uint8_t key) { 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) { void io::up(uint8_t scan) {
@ -142,25 +138,21 @@ void io::display(uint8_t b) {
void io::write_portb(uint8_t b) { void io::write_portb(uint8_t b) {
b &= 0x7f; b &= 0x7f;
display(b); display(b);
pia::write_portb(b); PIA::write_portb(b);
} }
uint8_t io::read_porta_cr() { uint8_t io::read_cra() {
uint8_t b = pia::read_porta_cr();
if (b != 0xa7)
return b;
if (_loading) { if (_loading) {
if (files.more()) if (files.more())
enter(files.read()); enter(files.read());
else else
_loading = false; _loading = false;
} }
return b; return PIA::read_cra();
} }
void io::checkpoint(Stream &s) { void io::checkpoint(Stream &s) {
pia::checkpoint(s); PIA::checkpoint(s);
s.write(r); s.write(r);
s.write(c); s.write(c);
for (int j = 0; j < ROWS; j++) for (int j = 0; j < ROWS; j++)
@ -169,7 +161,7 @@ void io::checkpoint(Stream &s) {
} }
void io::restore(Stream &s) { void io::restore(Stream &s) {
pia::restore(s); PIA::restore(s);
r = s.read(); r = s.read();
c = s.read(); c = s.read();
for (int j = 0; j < ROWS; j++) for (int j = 0; j < ROWS; j++)

23
io.h
View File

@ -1,30 +1,37 @@
#ifndef _IO_H #ifndef _IO_H
#define _IO_H #define _IO_H
// http://mamedev.org/source/src/mess/machine/apple1.c.html class io: public Memory::Device, public Display, Keyboard, public PIA {
class io: public Display, Keyboard, public pia {
public: public:
io(filer &files): files(files) {} io(filer &files): Memory::Device(Memory::page_size), files(files) {}
virtual void reset(); virtual void reset();
virtual void down(uint8_t scan); virtual void down(uint8_t);
virtual void up(uint8_t scan); 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 checkpoint(Stream &);
virtual void restore(Stream &); virtual void restore(Stream &);
virtual void write_portb(uint8_t); virtual void write_portb(uint8_t);
virtual uint8_t read_porta_cr(); virtual uint8_t read_cra();
void load(); void load();
filer &files; filer &files;
static const uint8_t ROWS = 24;
static const uint8_t COLS = 40;
private: private:
void display(uint8_t); void display(uint8_t);
void draw(char, int, int); void draw(char, int, int);
void enter(uint8_t); void enter(uint8_t);
bool _shift; bool _shift, _loading;
bool _loading; uint8_t r, c;
char screen[ROWS][COLS];
}; };
#endif #endif

166
pia.cpp
View File

@ -2,60 +2,178 @@
#include <memory.h> #include <memory.h>
#include "pia.h" #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) #if defined(DEBUGGING)
Serial.print(millis()); Serial.print(millis());
Serial.print(" > "); Serial.print(" > ");
Serial.print(_acc, 16); Serial.print(a, 16);
Serial.print(' '); Serial.print(' ');
Serial.println(b, 16); Serial.println(b, 16);
#endif #endif
switch(_acc % 4) { switch(a % 4) {
case 0: case 0:
write_porta(b); output_selected(cra)? write_porta(b): write_ddra(b);
break; break;
case 1: case 1:
write_porta_cr(b); write_cra(b);
break; break;
case 2: case 2:
write_portb(b); output_selected(crb)? write_portb(b): write_ddrb(b);
break; break;
case 3: case 3:
write_portb_cr(b); write_crb(b);
break; break;
} }
} }
pia::operator uint8_t() { uint8_t PIA::read(Memory::address a) {
#if defined(DEBUGGING) #if defined(DEBUGGING)
Serial.print(millis()); Serial.print(millis());
Serial.print(" < "); Serial.print(" < ");
Serial.println(_acc, 16); Serial.println(a, 16);
#endif #endif
switch (_acc % 4) { switch (a % 4) {
case 0: case 0:
return read_porta(); return output_selected(cra)? read_porta(): read_ddra();
case 1: case 1:
return read_porta_cr(); return read_cra();
case 2: case 2:
return read_portb(); return output_selected(crb)? read_portb(): read_ddrb();
case 3: case 3:
return read_portb_cr(); return read_crb();
} }
return 0xff; return 0xff;
} }
void pia::checkpoint(Stream &s) { void PIA::checkpoint(Stream &s) {
s.write(portb_cr); s.write(crb);
s.write(portb); s.write(outb);
s.write(porta_cr); s.write(inb);
s.write(porta); 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) { void PIA::restore(Stream &s) {
portb_cr = s.read(); crb = s.read();
portb = s.read(); outb = s.read();
porta_cr = s.read(); inb = s.read();
porta = 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);
}

78
pia.h
View File

@ -1,51 +1,57 @@
#ifndef __PIA_H__ #ifndef __PIA_H__
#define __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: public:
pia(): Memory::Device(256), portb_cr(0), porta_cr(0) {} PIA(): outb(0), inb(0), crb(0), outa(0), ina(0), cra(0), ddrb(0), ddra(0),
virtual void reset() { portb_cr = porta_cr = 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); virtual void reset() {
operator uint8_t(); 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 checkpoint(Stream &);
void restore(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: protected:
// write to the "external" side of the port // overrideable device memory interface
void set_porta(uint8_t b) { virtual uint8_t read_ddra() { return ddra; }
porta = b; virtual uint8_t read_porta();
if (b & 0x80) virtual uint8_t read_cra();
porta_cr = 0xa7; virtual uint8_t read_ddrb() { return ddrb; }
} virtual uint8_t read_portb();
virtual uint8_t read_crb();
// "device-side" operations (called from memory interface) virtual void write_ddra(uint8_t b) { ddra = b; }
uint8_t read_porta() { return porta; } virtual void write_porta(uint8_t b) { outa = b; }
virtual uint8_t read_porta_cr() { virtual void write_cra(uint8_t b) { cra = (b & 0x3f); }
if (porta_cr & 0x80) { virtual void write_ddrb(uint8_t b) { ddrb = b; }
porta_cr = 0; virtual void write_portb(uint8_t b) { outb = b; }
return 0xa7; virtual void write_crb(uint8_t b) { crb = (b & 0x3f); }
}
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;
}
private: 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 #endif