mirror of
https://github.com/jscrane/r65emu.git
synced 2024-12-21 12:29:51 +00:00
adding VIA from PET
This commit is contained in:
parent
2b31012100
commit
fa8759415e
17
line.h
Normal file
17
line.h
Normal file
@ -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
|
4
pia.cpp
4
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);
|
||||
|
265
via.cpp
Normal file
265
via.cpp
Normal file
@ -0,0 +1,265 @@
|
||||
#include <Arduino.h>
|
||||
#include <memory.h>
|
||||
#include <line.h>
|
||||
#include <via.h>
|
||||
|
||||
#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;
|
||||
}
|
98
via.h
Normal file
98
via.h
Normal file
@ -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
|
Loading…
Reference in New Issue
Block a user