diff --git a/line.h b/line.h new file mode 100644 index 0000000..2078678 --- /dev/null +++ b/line.h @@ -0,0 +1,17 @@ +#ifndef _LINE_H +#define _LINE_H + +class Line { +public: + Line(): _state(false) {} + + operator bool() { return _state; } + void set(bool state) { _state = state; } + void clear() { set(false); } + void set() { set(true); } + +private: + volatile bool _state; +}; + +#endif diff --git a/pia.cpp b/pia.cpp index 81d2ea6..f72b5db 100644 --- a/pia.cpp +++ b/pia.cpp @@ -20,7 +20,7 @@ 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(DEBUG_PIA) Serial.print(millis()); Serial.print(" > "); Serial.print(a, 16); @@ -44,7 +44,7 @@ void PIA::write(Memory::address a, uint8_t b) { } uint8_t PIA::read(Memory::address a) { -#if defined(DEBUGGING) +#if defined(DEBUG_PIA) Serial.print(millis()); Serial.print(" < "); Serial.println(a, 16); diff --git a/via.cpp b/via.cpp new file mode 100644 index 0000000..3a3876d --- /dev/null +++ b/via.cpp @@ -0,0 +1,265 @@ +#include +#include +#include +#include + +#define VPORTB 0x00 +#define VPORTA 0x01 +#define DDRB 0x02 +#define DDRA 0x03 +#define T1LO 0x04 +#define T1HI 0x05 +#define T1LLO 0x06 +#define T1LHI 0x07 +#define T2LO 0x08 +#define T2HI 0x09 +#define SHIFT 0x0a +#define ACR 0x0b +#define PCR 0x0c +#define IFR 0x0d +#define IER 0x0e +#define VPORTA_NH 0x0f + +void VIA::write(Memory::address a, uint8_t b) { + switch (a & 0x0f) { + case VPORTB: + write_vportb(b); + break; + case VPORTA: + write_vporta(b); + break; + case DDRB: + write_vddrb(b); + break; + case DDRA: + write_vddra(b); + break; + case T1LO: + write_t1lo(b); + break; + case T1LLO: + write_t1llo(b); + break; + case T1HI: + write_t1hi(b); + break; + case T1LHI: + write_t1lhi(b); + break; + case T2LO: + write_t2lo(b); + break; + case T2HI: + write_t2hi(b); + break; + case SHIFT: + write_sr(b); + break; + case ACR: + write_acr(b); + break; + case PCR: + write_pcr(b); + break; + case IFR: + write_ifr(b); + break; + case IER: + write_ier(b); + break; + case VPORTA_NH: + write_vporta_nh(b); + break; + } +} + +void VIA::write_vportb(uint8_t b) { + _portb = (b & _ddrb); + clear_int(INT_CB1_ACTIVE | INT_CB2_ACTIVE); +} + +void VIA::write_vporta(uint8_t b) { + _porta = (b & _ddra); + clear_int(INT_CA1_ACTIVE | INT_CA2_ACTIVE); +} + +void VIA::write_t1llo(uint8_t b) { + _t1_latch = (_t1_latch & 0xff00) | b; +} + +void VIA::write_t1lhi(uint8_t b) { + _t1_latch = (_t1_latch & 0x00ff) | (b << 8); + clear_int(INT_TIMER1); +} + +void VIA::write_t1hi(uint8_t b) { + _t1 = _t1_latch; + start_timer1(); + clear_int(INT_TIMER1); +} + +void VIA::write_t2lo(uint8_t b) { + _t2 = b; + _timer2 = false; + clear_int(INT_TIMER2); +} + +void VIA::write_t2hi(uint8_t b) { + _t2 += (b << 8); + start_timer2(); + clear_int(INT_TIMER2); +} + +void VIA::write_sr(uint8_t b) { + _sr = b; + clear_int(INT_SR); +} + +void VIA::write_pcr(uint8_t b) { + _pcr = b; + CA2.set(b & 0x02); +} + +void VIA::write_acr(uint8_t b) { + _acr = b; + if (b & ACR_T1_CONTINUOUS) + start_timer1(); +} + +void VIA::write_ier(uint8_t b) { + if (b & INT_MASTER) + _ier |= b & 0x7f; + else + _ier &= ~(b & 0x7f); +} + +void VIA::write_vporta_nh(uint8_t b) { + _porta = (b & _ddra); +} + +uint8_t VIA::read(Memory::address a) { + switch (a & 0x0f) { + case VPORTB: + return read_vportb(); + case VPORTA: + return read_vporta(); + case DDRB: + return read_vddrb(); + case DDRA: + return read_vddra(); + case T1LO: + return read_t1lo(); + case T1HI: + return read_t1hi(); + case T1LLO: + return read_t1llo(); + case T1LHI: + return read_t1lhi(); + case T2LO: + return read_t2lo(); + case T2HI: + return read_t2hi(); + case SHIFT: + return read_sr(); + case ACR: + return read_acr(); + case PCR: + return read_pcr(); + case IFR: + return read_ifr(); + case IER: + return read_ier(); + case VPORTA_NH: + return read_vporta_nh(); + } + return 0x00; +} + +uint8_t VIA::read_vportb() { + return (_portb & _ddrb) | ~_ddrb; +} + +uint8_t VIA::read_vporta() { + return (_porta & _ddra) | ~_ddra; +} + +uint8_t VIA::read_t1lo() { + clear_int(INT_TIMER1); + return _t1 & 0xff; +} + +uint8_t VIA::read_t2lo() { + clear_int(INT_TIMER2); + return _t2 & 0xff; +} + +uint8_t VIA::read_sr() { + clear_int(INT_SR); + return _sr; +} + +uint8_t VIA::read_vporta_nh() { + return (_porta & _ddra) | ~_ddra; +} + +void VIA::tick() { + + uint32_t now = millis(); + if (_timer1) { + uint32_t interval = now - _t1_tick; + if (_t1 < interval) { + _t1 = 0; + _timer1 = false; + set_int(INT_TIMER1); + } else { + _t1 -= interval; + _t1_tick = now; + } + } + + if (_timer2) { + uint32_t interval = now - _t1_tick; + if (_t2 < interval) { + _t2 = 0; + _timer2 = false; + set_int(INT_TIMER2); + } else { + _t2 -= interval; + _t2_tick = now; + } + } +} + +void VIA::set_int(uint8_t i) { + _ifr |= i; + if ((_ier & INT_MASTER) && (_ier & i)) + set_interrupt(); +} + +void VIA::clear_int(uint8_t i) { + _ifr &= ~i; +} + +void VIA::write_vporta_in_bit(uint8_t bit, bool state) { + if (state) + _porta |= bit; + else + _porta &= ~bit; +} + +void VIA::write_vportb_in_bit(uint8_t bit, bool state) { + if (state) + _portb |= bit; + else + _portb &= ~bit; +} + +void VIA::start_timer1() { + _t1_tick = millis(); + _timer1 = true; +} + +void VIA::start_timer2() { + _t2_tick = millis(); + _timer2 = true; +} diff --git a/via.h b/via.h new file mode 100644 index 0000000..9f2918b --- /dev/null +++ b/via.h @@ -0,0 +1,98 @@ +#ifndef _VIA_H +#define _VIA_H + +class VIA { +public: + VIA(): _irq(0), _timer1(false), _timer2(false), _t1(0), _t2(0), _t1_latch(0), + _sr(0), _acr(0), _pcr(0), _ier(0), _ifr(0), _ddra(0), _ddrb(0), _porta(0), _portb(0) {} + + virtual void reset() { + _timer1 = _timer2 = false; + _t1 = _t2 = _t1_latch = 0; + _sr = _acr = _pcr = _ier = _ifr = _porta = _portb = _ddra = _ddrb = 0; + } + + void write(Memory::address, uint8_t); + uint8_t read(Memory::address); + + void write_vporta_in_bit(uint8_t, bool); + void write_vportb_in_bit(uint8_t, bool); + + void tick(); + + Line CA2; + + void register_irq(Line &irq) { _irq = &irq; } + + // acr + static const uint8_t ACR_SHIFT_MASK = 0x1c; + static const uint8_t ACR_T1_SET_PB7 = 0x80; + static const uint8_t ACR_T1_CONTINUOUS = 0x40; + static const uint8_t ACR_T2_COUNT_PB6 = 0x20; + static const uint8_t ACR_SO_T2_RATE = 0x10; + + // ier and ifr bits + static const uint8_t INT_MASTER = 0x80; + static const uint8_t INT_TIMER1 = 0x40; + static const uint8_t INT_TIMER2 = 0x20; + static const uint8_t INT_CB1_ACTIVE = 0x10; + static const uint8_t INT_CB2_ACTIVE = 0x08; + static const uint8_t INT_SR = 0x04; + static const uint8_t INT_CA1_ACTIVE = 0x02; + static const uint8_t INT_CA2_ACTIVE = 0x01; + +protected: + virtual void write_vportb(uint8_t); + virtual void write_vporta(uint8_t); + virtual void write_vddrb(uint8_t b) { _ddrb = b; } + virtual void write_vddra(uint8_t b) { _ddra = b; } + virtual void write_t1lo(uint8_t b) { write_t1llo(b); } + virtual void write_t1hi(uint8_t); + virtual void write_t1llo(uint8_t); + virtual void write_t1lhi(uint8_t); + virtual void write_t2lo(uint8_t); + virtual void write_t2hi(uint8_t); + virtual void write_sr(uint8_t); + virtual void write_acr(uint8_t b); + virtual void write_pcr(uint8_t b); + virtual void write_ifr(uint8_t b) { _ifr &= ~b; } + virtual void write_ier(uint8_t); + virtual void write_vporta_nh(uint8_t); + + virtual uint8_t read_vportb(); + virtual uint8_t read_vporta(); + virtual uint8_t read_vddrb() { return _ddrb; } + virtual uint8_t read_vddra() { return _ddra; } + virtual uint8_t read_t1lo(); + virtual uint8_t read_t1hi() { return _t1 / 0xff; } + virtual uint8_t read_t1llo() { return _t1_latch & 0xff; } + virtual uint8_t read_t1lhi() { return _t1_latch / 0xff; } + virtual uint8_t read_t2lo(); + virtual uint8_t read_t2hi() { return _t2 / 0xff; } + virtual uint8_t read_sr(); + virtual uint8_t read_acr() { return _acr; } + virtual uint8_t read_pcr() { return _pcr; } + virtual uint8_t read_ifr() { return _ifr; } + virtual uint8_t read_ier() { return _ier | 0x80; } + virtual uint8_t read_vporta_nh(); + + void set_interrupt() { if (_irq) _irq->set(); } + +private: + Line *_irq; + + void set_int(uint8_t); + void clear_int(uint8_t); + + void start_timer1(); + void start_timer2(); + volatile bool _timer1, _timer2; + volatile uint16_t _t1, _t2; + uint16_t _t1_latch; + volatile uint32_t _t1_tick, _t2_tick; + + uint8_t _sr, _acr, _pcr, _ier, _ifr, _ddra, _ddrb; + volatile uint8_t _porta, _portb; +}; + +#endif