mirror of
https://github.com/jscrane/r65emu.git
synced 2024-12-14 10:31:14 +00:00
initial commit
This commit is contained in:
parent
8a2b10561f
commit
a19bbc6898
39
acia.h
Normal file
39
acia.h
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* acia.h -- ACIA device
|
||||
*/
|
||||
struct acia {
|
||||
|
||||
// status bits returned by operator byte
|
||||
//
|
||||
static const byte rdrf = 1 << 0;
|
||||
static const byte tdre = 1 << 1;
|
||||
static const byte dcd = 1 << 2;
|
||||
static const byte cts = 1 << 3;
|
||||
static const byte fe = 1 << 4;
|
||||
static const byte ovrn = 1 << 5;
|
||||
static const byte pc = 1 << 6;
|
||||
static const byte irq = 1 << 7;
|
||||
|
||||
// control operations (four combinable groups)
|
||||
//
|
||||
static const byte cd1 = 0x00; // divide by 1
|
||||
static const byte cd16 = 0x01; // divide by 16
|
||||
static const byte cd64 = 0x02; // divide by 64
|
||||
static const byte reset = 0x03; // master reset
|
||||
|
||||
static const byte ws7e2 = 0 << 2; // parity
|
||||
static const byte ws7o2 = 1 << 2;
|
||||
static const byte ws7e1 = 2 << 2;
|
||||
static const byte ws7o1 = 3 << 2;
|
||||
static const byte ws8n2 = 4 << 2;
|
||||
static const byte ws8n1 = 5 << 2;
|
||||
static const byte ws8e1 = 6 << 2;
|
||||
static const byte ws8o1 = 7 << 2;
|
||||
|
||||
static const byte lrts_dti = 0 << 5; // /rts, disable trans irq
|
||||
static const byte lrts_eti = 1 << 5; // /rts, enable
|
||||
static const byte hrts_dti = 2 << 5; // rts, disable
|
||||
static const byte lrts_dti_brk = 3 << 5; // /rts, disable, send brk
|
||||
|
||||
static const byte eri = 1 << 7; // enable receive interrupt
|
||||
};
|
26
cpu.h
Normal file
26
cpu.h
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* cpu.h
|
||||
*/
|
||||
#ifndef _CPU_H
|
||||
#define _CPU_H
|
||||
|
||||
#ifndef _SETJMP_H
|
||||
#include <setjmp.h>
|
||||
#endif
|
||||
|
||||
class CPU {
|
||||
public:
|
||||
virtual void reset () =0;
|
||||
virtual Memory::address run (unsigned instructions) =0;
|
||||
virtual void raise (int level) =0;
|
||||
virtual char *status () =0;
|
||||
|
||||
typedef void (*statfn) (const char *, ...);
|
||||
|
||||
protected:
|
||||
CPU (Memory *m, jmp_buf *e, statfn s): _memory(m), _err(e), _status(s){}
|
||||
Memory *_memory;
|
||||
jmp_buf *_err;
|
||||
statfn _status;
|
||||
};
|
||||
#endif
|
34
hardware.h
Normal file
34
hardware.h
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* The hardware configuration of the machine.
|
||||
* (This should be the same for all emulated devices.)
|
||||
*/
|
||||
#ifndef __HARDWARE_H
|
||||
#define __HARDWARE_H
|
||||
|
||||
// TFT display...
|
||||
// NOTE: edit memorysaver.h to select the correct chip for your display!
|
||||
// Daniel Rebollo's boosterpack
|
||||
#define TFT_BACKLIGHT PD_6
|
||||
#define TFT_MODEL SSD1289
|
||||
// TFT01_2.4: http://www.elecfreaks.com/store/24-tft-lcd-tft0124-p-110.html
|
||||
// #undef TFT_BACKLIGHT
|
||||
// #define TFT_MODEL S6D1121_8
|
||||
#define TFT_RS PC_6
|
||||
#define TFT_WR PC_5
|
||||
#define TFT_CS PC_7
|
||||
#define TFT_RST PC_4
|
||||
|
||||
// SPI-RAM
|
||||
#define SPIRAM_CS PE_0
|
||||
#define SPIRAM_SPI 1
|
||||
#define SPIRAM_DEV SPI_for_SD
|
||||
|
||||
// PS/2 keyboard
|
||||
#define KBD_DATA PE_4
|
||||
#define KBD_IRQ PE_5
|
||||
|
||||
// "tape" storage...
|
||||
#define SD_CS PF_3
|
||||
#define SD_SPI 1
|
||||
|
||||
#endif
|
24
memory.cpp
Normal file
24
memory.cpp
Normal file
@ -0,0 +1,24 @@
|
||||
#include "memory.h"
|
||||
|
||||
void Memory::put (Device &dev, address b) {
|
||||
Device **d = _pages + b/page_size;
|
||||
|
||||
int size = dev.pages();
|
||||
while (size--)
|
||||
*d++ = &dev;
|
||||
|
||||
dev.base(b);
|
||||
}
|
||||
|
||||
class NullDevice: public Memory::Device {
|
||||
public:
|
||||
NullDevice(): Memory::Device(65536) {}
|
||||
void operator= (byte b) {}
|
||||
operator byte() { return 0; }
|
||||
} nd;
|
||||
|
||||
Memory::Memory() {
|
||||
put(nd, 0);
|
||||
}
|
||||
|
||||
|
49
memory.h
Normal file
49
memory.h
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* memory.h
|
||||
*/
|
||||
#ifndef _MEMORY_H
|
||||
#define _MEMORY_H
|
||||
|
||||
typedef unsigned char byte;
|
||||
|
||||
class Memory {
|
||||
public:
|
||||
typedef unsigned short address;
|
||||
static const int page_size = 256;
|
||||
|
||||
class Device {
|
||||
public:
|
||||
Device (int bytes): _pages(bytes/page_size) {}
|
||||
virtual ~Device () {}
|
||||
int pages () const { return _pages; }
|
||||
void access (address a) { _acc=a-_base; }
|
||||
void base (address a) { _base=a; }
|
||||
address base () const { return _base; }
|
||||
|
||||
virtual void operator= (byte) =0;
|
||||
virtual operator byte () =0;
|
||||
|
||||
protected:
|
||||
address _acc, _base;
|
||||
private:
|
||||
int _pages;
|
||||
};
|
||||
|
||||
// insert a new device instance
|
||||
//
|
||||
void put (Device &d, address at);
|
||||
Device *get (address at) const { return _pages[at/page_size]; }
|
||||
|
||||
// primary access interface
|
||||
//
|
||||
Device &operator[] (address a) {
|
||||
Device *d = get (a);
|
||||
d->access (a);
|
||||
return *d;
|
||||
}
|
||||
|
||||
Memory();
|
||||
private:
|
||||
Device *_pages[256];
|
||||
};
|
||||
#endif
|
10
prom.h
Normal file
10
prom.h
Normal file
@ -0,0 +1,10 @@
|
||||
class prom: public Memory::Device {
|
||||
public:
|
||||
virtual void operator= (byte) {}
|
||||
virtual operator byte () { return _mem[_acc]; }
|
||||
|
||||
prom(const byte *mem, int bytes): Memory::Device(bytes), _mem(mem) {}
|
||||
|
||||
private:
|
||||
const byte *_mem;
|
||||
};
|
81
ps2drv.cpp
Normal file
81
ps2drv.cpp
Normal file
@ -0,0 +1,81 @@
|
||||
#include <Energia.h>
|
||||
#include "ps2drv.h"
|
||||
|
||||
#define BUFFER_SIZE 16
|
||||
static volatile uint8_t buffer[BUFFER_SIZE];
|
||||
static volatile uint8_t head, tail;
|
||||
static bool isbrk;
|
||||
static uint8_t DataPin;
|
||||
|
||||
// The ISR for the external interrupt
|
||||
void ps2interrupt(void)
|
||||
{
|
||||
static uint8_t bitcount=0;
|
||||
static uint8_t incoming=0;
|
||||
static uint32_t prev_ms=0;
|
||||
uint32_t now_ms;
|
||||
uint8_t n, val;
|
||||
|
||||
val = digitalRead(DataPin);
|
||||
now_ms = millis();
|
||||
if (now_ms - prev_ms > 250) {
|
||||
bitcount = 0;
|
||||
incoming = 0;
|
||||
}
|
||||
prev_ms = now_ms;
|
||||
n = bitcount - 1;
|
||||
if (n <= 7) {
|
||||
incoming |= (val << n);
|
||||
}
|
||||
bitcount++;
|
||||
if (bitcount == 11) {
|
||||
uint8_t i = head + 1;
|
||||
if (i == BUFFER_SIZE) i = 0;
|
||||
if (i != tail) {
|
||||
buffer[i] = incoming;
|
||||
head = i;
|
||||
}
|
||||
bitcount = 0;
|
||||
incoming = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool PS2Driver::available() {
|
||||
if (head == tail)
|
||||
return false;
|
||||
|
||||
uint8_t i = tail+1;
|
||||
if (i == BUFFER_SIZE) i = 0;
|
||||
if (buffer[i] == 0xf0)
|
||||
return i != head;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PS2Driver::isbreak() {
|
||||
bool b = isbrk;
|
||||
isbrk = false;
|
||||
return b;
|
||||
}
|
||||
|
||||
int PS2Driver::read() {
|
||||
if (head == tail)
|
||||
return -1;
|
||||
|
||||
uint8_t i = tail+1;
|
||||
if (i == BUFFER_SIZE) i = 0;
|
||||
tail = i;
|
||||
if (buffer[i] == 0xf0) {
|
||||
isbrk = true;
|
||||
return read();
|
||||
}
|
||||
return buffer[i];
|
||||
}
|
||||
|
||||
void PS2Driver::begin(uint8_t data_pin, uint8_t irq_pin)
|
||||
{
|
||||
DataPin = data_pin;
|
||||
pinMode(irq_pin, INPUT_PULLUP);
|
||||
pinMode(data_pin, INPUT_PULLUP);
|
||||
attachInterrupt(irq_pin, ps2interrupt, FALLING);
|
||||
head = tail = 0;
|
||||
}
|
46
ps2drv.h
Normal file
46
ps2drv.h
Normal file
@ -0,0 +1,46 @@
|
||||
#ifndef __PS2DRV_H
|
||||
#define __PS2DRV_H
|
||||
|
||||
class PS2Driver
|
||||
{
|
||||
public:
|
||||
PS2Driver() {}
|
||||
|
||||
/**
|
||||
* Starts the keyboard "service" by registering the external interrupt.
|
||||
* setting the pin modes correctly and driving those needed to high.
|
||||
* The propably best place to call this method is in the setup routine.
|
||||
*/
|
||||
void begin(uint8_t dataPin, uint8_t irq_pin);
|
||||
|
||||
/**
|
||||
* Returns true if there is a char to be read, false if not.
|
||||
*/
|
||||
bool available();
|
||||
|
||||
/**
|
||||
* returns true if the key has been released
|
||||
*/
|
||||
bool isbreak();
|
||||
|
||||
/**
|
||||
* Returns the scancode last received from the keyboard.
|
||||
* If there is no char available, -1 is returned.
|
||||
*/
|
||||
int read();
|
||||
};
|
||||
|
||||
#define PS2_F1 0x05
|
||||
#define PS2_F2 0x06
|
||||
#define PS2_F3 0x04
|
||||
#define PS2_F4 0x0C
|
||||
#define PS2_F5 0x03
|
||||
#define PS2_F6 0x0B
|
||||
#define PS2_F7 0x83
|
||||
#define PS2_F8 0x0A
|
||||
#define PS2_F9 0x01
|
||||
#define PS2_F10 0x09
|
||||
#define PS2_F11 0x78
|
||||
#define PS2_F12 0x07
|
||||
|
||||
#endif
|
264
r6502.cpp
Normal file
264
r6502.cpp
Normal file
@ -0,0 +1,264 @@
|
||||
#include <stdio.h>
|
||||
#include <Stream.h>
|
||||
|
||||
#include "memory.h"
|
||||
#include "cpu.h"
|
||||
#include "r6502.h"
|
||||
|
||||
Memory::address r6502::run (unsigned clocks) {
|
||||
while (clocks--)
|
||||
{
|
||||
byte op = (*_memory)[PC];
|
||||
#ifdef CPU_DEBUG
|
||||
_status ("%04x: %02x [%02x %02x %02x, %02x]\r", PC, op, A, X, Y, flags());
|
||||
#endif
|
||||
PC++;
|
||||
(this->*_ops[op])();
|
||||
}
|
||||
return PC;
|
||||
}
|
||||
|
||||
byte r6502::flags() {
|
||||
P.bits.N = ((N & 0x80) != 0);
|
||||
P.bits.V = V;
|
||||
P.bits.Z = !Z;
|
||||
P.bits.C = C;
|
||||
P.bits._ = 1;
|
||||
return P.value;
|
||||
}
|
||||
|
||||
char *r6502::status () {
|
||||
static char buf[128];
|
||||
flags();
|
||||
sprintf (buf, "aa xx yy sp nv_bdizc _pc_\r\n"
|
||||
"%02x %02x %02x %02x %d%d%d%d%d%d%d%d %04x\r\n",
|
||||
A, X, Y, S, P.bits.N, P.bits.V, P.bits._, P.bits.B,
|
||||
P.bits.D, P.bits.I, P.bits.Z, P.bits.C, PC);
|
||||
return buf;
|
||||
}
|
||||
|
||||
void r6502::checkpoint(Stream &s)
|
||||
{
|
||||
s.write(PC / 0xff);
|
||||
s.write(PC % 0xff);
|
||||
s.write(S);
|
||||
s.write(A);
|
||||
s.write(X);
|
||||
s.write(Y);
|
||||
s.write(N);
|
||||
s.write(V);
|
||||
s.write(B);
|
||||
s.write(D);
|
||||
s.write(I);
|
||||
s.write(Z);
|
||||
s.write(C);
|
||||
s.write(P.value);
|
||||
}
|
||||
|
||||
void r6502::restore(Stream &s)
|
||||
{
|
||||
byte hi = s.read(), lo = s.read();
|
||||
PC = hi * 0xff + lo;
|
||||
S = s.read();
|
||||
A = s.read();
|
||||
X = s.read();
|
||||
Y = s.read();
|
||||
N = s.read();
|
||||
V = s.read();
|
||||
B = s.read();
|
||||
D = s.read();
|
||||
I = s.read();
|
||||
Z = s.read();
|
||||
C = s.read();
|
||||
P.value = s.read();
|
||||
}
|
||||
|
||||
void r6502::raise (int level) {
|
||||
if (level < 0)
|
||||
nmi ();
|
||||
else if (!P.bits.I)
|
||||
irq ();
|
||||
else
|
||||
_irq = true;
|
||||
}
|
||||
|
||||
void r6502::irq () {
|
||||
pusha (PC);
|
||||
P.bits.B = 0;
|
||||
pushb (flags ());
|
||||
P.bits.B = 1;
|
||||
P.bits.I = 1;
|
||||
PC = vector (ibvec);
|
||||
_irq = false;
|
||||
}
|
||||
|
||||
void r6502::brk () {
|
||||
if (!P.bits.I) {
|
||||
pusha (PC);
|
||||
P.bits.B = 1;
|
||||
php ();
|
||||
P.bits.I = 1;
|
||||
PC = vector (ibvec);
|
||||
}
|
||||
P.bits.B = 1;
|
||||
P.bits._ = 1;
|
||||
}
|
||||
|
||||
void r6502::rti () {
|
||||
plp ();
|
||||
PC = popa ();
|
||||
}
|
||||
|
||||
void r6502::cli () {
|
||||
P.bits.I = 0;
|
||||
if (_irq)
|
||||
irq();
|
||||
}
|
||||
|
||||
void r6502::nmi () {
|
||||
pusha (PC);
|
||||
php ();
|
||||
P.bits.I = 1;
|
||||
PC = vector (nmivec);
|
||||
}
|
||||
|
||||
// php and plp are complicated by the representation
|
||||
// of the processor state for efficient normal operation
|
||||
void r6502::php () {
|
||||
P.bits.B = 1;
|
||||
pushb (flags ());
|
||||
}
|
||||
|
||||
void r6502::plp () {
|
||||
P.value = popb ();
|
||||
N = P.bits.N? 0x80: 0;
|
||||
V = P.bits.V;
|
||||
Z = !P.bits.Z;
|
||||
C = P.bits.C;
|
||||
}
|
||||
|
||||
void r6502::rts () {
|
||||
PC = popa ()+1;
|
||||
}
|
||||
|
||||
void r6502::jsr () {
|
||||
pusha (PC+1);
|
||||
PC = vector (PC);
|
||||
}
|
||||
|
||||
void r6502::_adc (byte d) {
|
||||
if (P.bits.D) {
|
||||
int r = _fromBCD[A] + _fromBCD[d] + C;
|
||||
C = (r > 99);
|
||||
if (C) r -= 100;
|
||||
A = _toBCD[r];
|
||||
} else {
|
||||
unsigned short u = (unsigned short)A + (unsigned short)d + (unsigned short)C;
|
||||
short s = (char)A + (char)d + (char)C;
|
||||
C = (u < 0 || u > 255);
|
||||
V = (s > 127 || s < -128);
|
||||
A = (u & 0xff);
|
||||
}
|
||||
N = (A & 0x80);
|
||||
Z = A;
|
||||
}
|
||||
|
||||
void r6502::sbcd (byte d) {
|
||||
int r = _fromBCD[A] - _fromBCD[d] - !C;
|
||||
C = (r >= 0);
|
||||
if (r < 0) r += 100;
|
||||
A = _toBCD[r & 0xff];
|
||||
N = (A & 0x80);
|
||||
Z = A;
|
||||
// V not tested for: http://www.6502.org/tutorials/decimal_mode.html
|
||||
}
|
||||
|
||||
void r6502::ill () {
|
||||
_status ("Illegal instruction at %04x!\r\n%s", (PC-1), status());
|
||||
longjmp (*_err, 1);
|
||||
}
|
||||
|
||||
void r6502::reset ()
|
||||
{
|
||||
P.value = 0;
|
||||
P.bits._ = 1;
|
||||
P.bits.B = 1;
|
||||
_irq = false;
|
||||
S = 0xff;
|
||||
PC = vector(resvec);
|
||||
}
|
||||
|
||||
r6502::r6502 (Memory *m, jmp_buf *e, CPU::statfn s): CPU (m,e,s) {
|
||||
|
||||
for (int i=0; i < 256; i++) {
|
||||
_fromBCD[i] = ((i >> 4) & 0x0f)*10 + (i & 0x0f);
|
||||
_toBCD[i] = (((i % 100) / 10) << 4) | (i % 10);
|
||||
}
|
||||
|
||||
OP *p = _ops;
|
||||
*p++=&r6502::brk; *p++=&r6502::ora_ix; *p++=&r6502::ill; *p++=&r6502::ill;
|
||||
*p++=&r6502::nop2; *p++=&r6502::ora_z; *p++=&r6502::asl_z; *p++=&r6502::ill;
|
||||
*p++=&r6502::php; *p++=&r6502::ora_; *p++=&r6502::asl; *p++=&r6502::ill;
|
||||
*p++=&r6502::nop3; *p++=&r6502::ora_a; *p++=&r6502::asl_a; *p++=&r6502::ill;
|
||||
*p++=&r6502::bpl; *p++=&r6502::ora_iy; *p++=&r6502::ill; *p++=&r6502::ill;
|
||||
*p++=&r6502::nop2; *p++=&r6502::ora_zx; *p++=&r6502::asl_zx; *p++=&r6502::ill;
|
||||
*p++=&r6502::clc; *p++=&r6502::ora_ay; *p++=&r6502::nop; *p++=&r6502::ill;
|
||||
*p++=&r6502::nop2; *p++=&r6502::ora_ax; *p++=&r6502::asl_ax; *p++=&r6502::ill;
|
||||
*p++=&r6502::jsr; *p++=&r6502::and_ix; *p++=&r6502::ill; *p++=&r6502::ill;
|
||||
*p++=&r6502::bit_z; *p++=&r6502::and_z; *p++=&r6502::rol_z; *p++=&r6502::ill;
|
||||
*p++=&r6502::plp; *p++=&r6502::and_; *p++=&r6502::rol; *p++=&r6502::ill;
|
||||
*p++=&r6502::bit_a; *p++=&r6502::and_a; *p++=&r6502::rol_a; *p++=&r6502::ill;
|
||||
*p++=&r6502::bmi; *p++=&r6502::and_iy; *p++=&r6502::ill; *p++=&r6502::ill;
|
||||
*p++=&r6502::nop2; *p++=&r6502::and_zx; *p++=&r6502::rol_zx; *p++=&r6502::ill;
|
||||
*p++=&r6502::sec; *p++=&r6502::and_ay; *p++=&r6502::nop; *p++=&r6502::ill;
|
||||
*p++=&r6502::nop3; *p++=&r6502::and_ax; *p++=&r6502::rol_ax; *p++=&r6502::ill;
|
||||
*p++=&r6502::rti; *p++=&r6502::eor_ix; *p++=&r6502::ill; *p++=&r6502::ill;
|
||||
*p++=&r6502::nop2; *p++=&r6502::eor_z; *p++=&r6502::lsr_z; *p++=&r6502::ill;
|
||||
*p++=&r6502::pha; *p++=&r6502::eor_; *p++=&r6502::lsr_; *p++=&r6502::ill;
|
||||
*p++=&r6502::jmp; *p++=&r6502::eor_a; *p++=&r6502::lsr_a; *p++=&r6502::ill;
|
||||
*p++=&r6502::bvc; *p++=&r6502::eor_iy; *p++=&r6502::ill; *p++=&r6502::ill;
|
||||
*p++=&r6502::nop2; *p++=&r6502::eor_zx; *p++=&r6502::lsr_zx; *p++=&r6502::ill;
|
||||
*p++=&r6502::cli; *p++=&r6502::eor_ay; *p++=&r6502::nop; *p++=&r6502::ill;
|
||||
*p++=&r6502::nop3; *p++=&r6502::eor_ax; *p++=&r6502::lsr_ax; *p++=&r6502::ill;
|
||||
*p++=&r6502::rts; *p++=&r6502::adc_ix; *p++=&r6502::ill; *p++=&r6502::ill;
|
||||
*p++=&r6502::nop2; *p++=&r6502::adc_z; *p++=&r6502::ror_z; *p++=&r6502::ill;
|
||||
*p++=&r6502::pla; *p++=&r6502::adc_; *p++=&r6502::ror_; *p++=&r6502::ill;
|
||||
*p++=&r6502::jmp_i; *p++=&r6502::adc_a; *p++=&r6502::ror_a; *p++=&r6502::ill;
|
||||
*p++=&r6502::bvs; *p++=&r6502::adc_iy; *p++=&r6502::ill; *p++=&r6502::ill;
|
||||
*p++=&r6502::nop2; *p++=&r6502::adc_zx; *p++=&r6502::ror_zx; *p++=&r6502::ill;
|
||||
*p++=&r6502::sei; *p++=&r6502::adc_ay; *p++=&r6502::nop; *p++=&r6502::ill;
|
||||
*p++=&r6502::nop3; *p++=&r6502::adc_ax; *p++=&r6502::ror_ax; *p++=&r6502::ill;
|
||||
*p++=&r6502::nop2; *p++=&r6502::sta_ix; *p++=&r6502::nop2; *p++=&r6502::ill;
|
||||
*p++=&r6502::sty_z; *p++=&r6502::sta_z; *p++=&r6502::stx_z; *p++=&r6502::ill;
|
||||
*p++=&r6502::dey; *p++=&r6502::nop2; *p++=&r6502::txa; *p++=&r6502::ill;
|
||||
*p++=&r6502::sty_a; *p++=&r6502::sta_a; *p++=&r6502::stx_a; *p++=&r6502::ill;
|
||||
*p++=&r6502::bcc; *p++=&r6502::sta_iy; *p++=&r6502::ill; *p++=&r6502::ill;
|
||||
*p++=&r6502::sty_zx; *p++=&r6502::sta_zx; *p++=&r6502::stx_zy; *p++=&r6502::ill;
|
||||
*p++=&r6502::tya; *p++=&r6502::sta_ay; *p++=&r6502::txs; *p++=&r6502::ill;
|
||||
*p++=&r6502::ill; *p++=&r6502::sta_ax; *p++=&r6502::ill; *p++=&r6502::ill;
|
||||
*p++=&r6502::ldy_; *p++=&r6502::lda_ix; *p++=&r6502::ldx_; *p++=&r6502::lax_ix;
|
||||
*p++=&r6502::ldy_z; *p++=&r6502::lda_z; *p++=&r6502::ldx_z; *p++=&r6502::lax_z;
|
||||
*p++=&r6502::tay; *p++=&r6502::lda_; *p++=&r6502::tax; *p++=&r6502::ill;
|
||||
*p++=&r6502::ldy_a; *p++=&r6502::lda_a; *p++=&r6502::ldx_a; *p++=&r6502::lax_a;
|
||||
*p++=&r6502::bcs; *p++=&r6502::lda_iy; *p++=&r6502::ill; *p++=&r6502::lax_iy;
|
||||
*p++=&r6502::ldy_zx; *p++=&r6502::lda_zx; *p++=&r6502::ldx_zy; *p++=&r6502::lax_zy;
|
||||
*p++=&r6502::clv; *p++=&r6502::lda_ay; *p++=&r6502::tsx; *p++=&r6502::ill;
|
||||
*p++=&r6502::ldy_ax; *p++=&r6502::lda_ax; *p++=&r6502::ldx_ay; *p++=&r6502::lax_ay;
|
||||
*p++=&r6502::cpy_; *p++=&r6502::cmp_ix; *p++=&r6502::nop2; *p++=&r6502::ill;
|
||||
*p++=&r6502::cpy_z; *p++=&r6502::cmp_z; *p++=&r6502::dec_z; *p++=&r6502::ill;
|
||||
*p++=&r6502::iny; *p++=&r6502::cmp_; *p++=&r6502::dex; *p++=&r6502::ill;
|
||||
*p++=&r6502::cpy_a; *p++=&r6502::cmp_a; *p++=&r6502::dec_a; *p++=&r6502::ill;
|
||||
*p++=&r6502::bne; *p++=&r6502::cmp_iy; *p++=&r6502::ill; *p++=&r6502::ill;
|
||||
*p++=&r6502::nop2; *p++=&r6502::cmp_zx; *p++=&r6502::dec_zx; *p++=&r6502::ill;
|
||||
*p++=&r6502::cld; *p++=&r6502::cmp_ay; *p++=&r6502::nop; *p++=&r6502::ill;
|
||||
*p++=&r6502::nop3; *p++=&r6502::cmp_ax; *p++=&r6502::dec_ax; *p++=&r6502::ill;
|
||||
*p++=&r6502::cpx_; *p++=&r6502::sbc_ix; *p++=&r6502::nop2; *p++=&r6502::ill;
|
||||
*p++=&r6502::cpx_z; *p++=&r6502::sbc_z; *p++=&r6502::inc_z; *p++=&r6502::ill;
|
||||
*p++=&r6502::inx; *p++=&r6502::sbc_; *p++=&r6502::nop; *p++=&r6502::ill;
|
||||
*p++=&r6502::cpx_a; *p++=&r6502::sbc_a; *p++=&r6502::inc_a; *p++=&r6502::ill;
|
||||
*p++=&r6502::beq; *p++=&r6502::sbc_iy; *p++=&r6502::ill; *p++=&r6502::ill;
|
||||
*p++=&r6502::nop2; *p++=&r6502::sbc_zx; *p++=&r6502::inc_zx; *p++=&r6502::ill;
|
||||
*p++=&r6502::sed; *p++=&r6502::sbc_ay; *p++=&r6502::nop; *p++=&r6502::ill;
|
||||
*p++=&r6502::nop3; *p++=&r6502::sbc_ax; *p++=&r6502::inc_ax; *p++=&r6502::ill;
|
||||
}
|
||||
|
316
r6502.h
Normal file
316
r6502.h
Normal file
@ -0,0 +1,316 @@
|
||||
/*
|
||||
* r6502.h
|
||||
*/
|
||||
#ifndef _R6502_H
|
||||
#define _R6502_H
|
||||
|
||||
#undef PC
|
||||
class Stream;
|
||||
|
||||
class r6502: public CPU {
|
||||
public:
|
||||
void raise(int);
|
||||
void reset();
|
||||
Memory::address run(unsigned);
|
||||
char *status();
|
||||
void checkpoint(Stream &);
|
||||
void restore(Stream &);
|
||||
|
||||
r6502 (Memory *, jmp_buf *, CPU::statfn);
|
||||
private:
|
||||
/* registers */
|
||||
Memory::address PC;
|
||||
byte S, A, X, Y;
|
||||
byte N, V, B, D, I, Z, C;
|
||||
union {
|
||||
struct {
|
||||
unsigned C:1;
|
||||
unsigned Z:1;
|
||||
unsigned I:1;
|
||||
unsigned D:1;
|
||||
unsigned B:1;
|
||||
unsigned _:1; // unused
|
||||
unsigned V:1;
|
||||
unsigned N:1;
|
||||
} bits;
|
||||
byte value;
|
||||
} P;
|
||||
byte _toBCD[256], _fromBCD[256]; // BCD maps
|
||||
bool _irq; // interrupt pending
|
||||
|
||||
void irq();
|
||||
void nmi();
|
||||
byte flags();
|
||||
|
||||
/* stack */
|
||||
inline void pusha (Memory::address ret) {
|
||||
(*_memory)[0x0100+S--] = ret >> 8;
|
||||
(*_memory)[0x0100+S--] = ret & 0xff;
|
||||
}
|
||||
|
||||
inline void pushb (byte b) {
|
||||
(*_memory)[0x0100+S--] = b;
|
||||
}
|
||||
|
||||
inline byte popb () {
|
||||
return (*_memory)[++S+0x0100];
|
||||
}
|
||||
|
||||
inline Memory::address popa () {
|
||||
byte b = popb ();
|
||||
return ((popb () << 8) | b);
|
||||
}
|
||||
|
||||
static const Memory::address nmivec = 0xfffa;
|
||||
static const Memory::address resvec = 0xfffc;
|
||||
static const Memory::address ibvec = 0xfffe;
|
||||
|
||||
inline Memory::address vector(Memory::address v) {
|
||||
return ((*_memory)[v+1] << 8) | (*_memory)[v];
|
||||
}
|
||||
|
||||
/* operators */
|
||||
inline void _cmp (byte a) { Z=N=A-a; C=(A>=a); }
|
||||
inline void _cpx (byte a) { Z=N=X-a; C=(X>=a); }
|
||||
inline void _cpy (byte a) { Z=N=Y-a; C=(Y>=a); }
|
||||
inline void _and (byte a) { Z=N=A&=a; }
|
||||
inline void _eor (byte a) { Z=N=A^=a; }
|
||||
inline void _ora (byte a) { Z=N=A|=a; }
|
||||
inline void _lda (byte a) { Z=N=A=a; }
|
||||
inline void _ldx (byte a) { Z=N=X=a; }
|
||||
inline void _ldy (byte a) { Z=N=Y=a; }
|
||||
|
||||
/* modes */
|
||||
inline Memory::address _a () {
|
||||
Memory::address a = (*_memory)[PC++];
|
||||
return a | ((*_memory)[PC++] << 8);
|
||||
}
|
||||
inline Memory::address _ax () { return _a()+X; }
|
||||
inline Memory::address _ay () { return _a()+Y; }
|
||||
inline Memory::address _z () { return (*_memory)[PC++]; }
|
||||
inline Memory::address _zx () { return (_z()+X) & 0xff; }
|
||||
inline Memory::address _zy () { return (_z()+Y) & 0xff; }
|
||||
inline Memory::address _i (Memory::address a) {
|
||||
return ((*_memory)[a+1]<<8)|(*_memory)[a];
|
||||
}
|
||||
inline Memory::address _ix () { return _i(_zx()); }
|
||||
inline Memory::address _iy () { return _i((*_memory)[PC++])+Y; }
|
||||
|
||||
void _adc (byte a);
|
||||
void _sbc (byte a) { if (P.bits.D) sbcd(a); else _adc(~a); }
|
||||
void sbcd (byte a);
|
||||
|
||||
inline byte __ror (byte b) {
|
||||
N=b>>1; if (C) N|=0x80; C=b&1; return Z=N;
|
||||
}
|
||||
inline void _ror (Memory::address a) {
|
||||
(*_memory)[a] = __ror((*_memory)[a]);
|
||||
}
|
||||
inline byte __rol (byte b) {
|
||||
N=b<<1; if (C) N|=1; C=(b&0x80)!=0; return Z=N;
|
||||
}
|
||||
inline void _rol (Memory::address a) {
|
||||
(*_memory)[a] = __rol((*_memory)[a]);
|
||||
}
|
||||
inline byte __asl (byte b) { C=(b&0x80)!=0; return Z=N=b<<1; }
|
||||
inline void _asl (Memory::address a) {
|
||||
(*_memory)[a] = __asl((*_memory)[a]);
|
||||
}
|
||||
inline byte __lsr (byte b) { C=b&1; Z=b>>1; N=0; return Z; }
|
||||
inline void _lsr (Memory::address a) {
|
||||
(*_memory)[a] = __lsr((*_memory)[a]);
|
||||
}
|
||||
inline void _inc (Memory::address a) {
|
||||
Z=N=1+(*_memory)[a]; (*_memory)[a]=Z;
|
||||
}
|
||||
inline void _dec (Memory::address a) {
|
||||
Z=N=(*_memory)[a]-1; (*_memory)[a]=Z;
|
||||
}
|
||||
inline void _bit (byte z) { V=((z & 0x40)!=0); N=(z & 0x80); Z=(A & z); }
|
||||
inline void _bra() {
|
||||
byte b = (*_memory)[PC];
|
||||
PC += b;
|
||||
if (b > 127) PC -= 0x0100;
|
||||
}
|
||||
|
||||
/* dispatch table */
|
||||
typedef void (r6502::*OP)(); OP _ops[256];
|
||||
|
||||
/* operations */
|
||||
void brk ();
|
||||
void ora_ix () { _ora ((*_memory)[_ix()]); }
|
||||
void ill ();
|
||||
void nop2 () { PC++; }
|
||||
void ora_z () { _ora ((*_memory)[_z()]); }
|
||||
void asl_z () { _asl (_z()); }
|
||||
void php ();
|
||||
void ora_ () { _ora ((*_memory)[PC++]); }
|
||||
void asl () { C=(A&0x80)!=0; Z=N=A<<=1; }
|
||||
void nop3 () { PC+=2; }
|
||||
void ora_a () { _ora ((*_memory)[_a()]); }
|
||||
void asl_a () { _asl (_a()); }
|
||||
// 10
|
||||
void bpl () { if (!(N & 0x80)) _bra(); PC++; }
|
||||
void ora_iy () { _ora ((*_memory)[_iy()]); }
|
||||
void ora_zx () { _ora ((*_memory)[_zx()]); }
|
||||
void asl_zx () { _asl (_zx()); }
|
||||
void clc () { C=0; }
|
||||
void ora_ay () { _ora ((*_memory)[_ay()]); }
|
||||
void nop () { }
|
||||
void ora_ax () { _ora ((*_memory)[_ax()]); }
|
||||
void asl_ax () { _asl (_ax()); }
|
||||
// 20
|
||||
void jsr ();
|
||||
void and_ix () { _and ((*_memory)[_ix()]); }
|
||||
void bit_z () { _bit ((*_memory)[_z()]); }
|
||||
void and_z () { _and ((*_memory)[_z()]); }
|
||||
void rol_z () { _rol (_z()); }
|
||||
void plp ();
|
||||
void and_ () { _and ((*_memory)[PC++]); }
|
||||
void rol () { A=__rol (A); }
|
||||
void bit_a () { _bit ((*_memory)[_a()]); }
|
||||
void and_a () { _and ((*_memory)[_a()]); }
|
||||
void rol_a () { _rol (_a()); }
|
||||
// 30
|
||||
void bmi () { if (N & 0x80) _bra(); PC++; }
|
||||
void and_iy () { _and ((*_memory)[_iy()]); }
|
||||
void and_zx () { _and ((*_memory)[_zx()]); }
|
||||
void rol_zx () { _rol (_zx()); }
|
||||
void sec () { C=1; }
|
||||
void and_ay () { _and ((*_memory)[_ay()]); }
|
||||
void and_ax () { _and ((*_memory)[_ax()]); }
|
||||
void rol_ax () { _rol (_ax()); }
|
||||
// 40
|
||||
void rti ();
|
||||
void eor_ix () { _eor ((*_memory)[_ix()]); }
|
||||
void eor_z () { _eor ((*_memory)[_z()]); }
|
||||
void lsr_z () { _lsr (_z()); }
|
||||
void pha () { pushb (A); }
|
||||
void eor_ () { _eor ((*_memory)[PC++]); }
|
||||
void lsr_ () { A=__lsr(A); }
|
||||
void jmp () { PC = _a (); }
|
||||
void eor_a () { _eor ((*_memory)[_a()]); }
|
||||
void lsr_a () { _lsr (_a()); }
|
||||
// 50
|
||||
void bvc () { if (!V) _bra(); PC++; }
|
||||
void eor_iy () { _eor ((*_memory)[_iy()]); }
|
||||
void eor_zx () { _eor ((*_memory)[_zx()]); }
|
||||
void lsr_zx () { _lsr (_zx()); }
|
||||
void cli ();
|
||||
void eor_ay () { _eor ((*_memory)[_ay()]); }
|
||||
void eor_ax () { _eor ((*_memory)[_ax()]); }
|
||||
void lsr_ax () { _lsr (_ax()); }
|
||||
// 60
|
||||
void rts ();
|
||||
void adc_ix () { _adc ((*_memory)[_ix()]); }
|
||||
void adc_z () { _adc ((*_memory)[_z()]); }
|
||||
void ror_z () { _ror (_z()); }
|
||||
void pla () { Z=N=A=popb (); }
|
||||
void adc_ () { _adc ((*_memory)[PC++]); }
|
||||
void ror_ () { A=__ror (A); }
|
||||
void jmp_i () { PC = _i(_a()); }
|
||||
void adc_a () { _adc ((*_memory)[_a()]); }
|
||||
void ror_a () { _ror (_a()); }
|
||||
// 70
|
||||
void bvs () { if (V) _bra(); PC++; }
|
||||
void adc_iy () { _adc ((*_memory)[_iy()]); }
|
||||
void adc_zx () { _adc ((*_memory)[_zx()]); }
|
||||
void ror_zx () { _ror (_zx ()); }
|
||||
void sei () { P.bits.I = 1; }
|
||||
void adc_ay () { _adc ((*_memory)[_ay()]); }
|
||||
void adc_ax () { _adc ((*_memory)[_ax()]); }
|
||||
void ror_ax () { _ror (_ax ()); }
|
||||
// 80
|
||||
void sta_ix () { (*_memory)[_ix()] = A; }
|
||||
void sty_z () { (*_memory)[_z()] = Y; }
|
||||
void sta_z () { (*_memory)[_z()] = A; }
|
||||
void stx_z () { (*_memory)[_z()] = X; }
|
||||
void dey () { Z=N=--Y; }
|
||||
void txa () { Z=N=A=X; }
|
||||
void sty_a () { (*_memory)[_a()] = Y; }
|
||||
void sta_a () { (*_memory)[_a()] = A; }
|
||||
void stx_a () { (*_memory)[_a()] = X; }
|
||||
// 90
|
||||
void bcc () { if (!C) _bra(); PC++; }
|
||||
void sta_iy () { (*_memory)[_iy()] = A; }
|
||||
void sty_zx () { (*_memory)[_zx()] = Y; }
|
||||
void sta_zx () { (*_memory)[_zx()] = A; }
|
||||
void stx_zy () { (*_memory)[_zy()] = X; }
|
||||
void tya () { Z=N=A=Y; }
|
||||
void sta_ay () { (*_memory)[_ay()] = A; }
|
||||
void txs () { S=X; }
|
||||
void sta_ax () { (*_memory)[_ax()] = A; }
|
||||
// a0
|
||||
void ldy_ () { _ldy ((*_memory)[PC++]); }
|
||||
void lda_ix () { _lda ((*_memory)[_ix()]); }
|
||||
void ldx_ () { _ldx ((*_memory)[PC++]); }
|
||||
void lax_ix () { lda_ix (); X=A; }
|
||||
void ldy_z () { _ldy ((*_memory)[_z()]); }
|
||||
void lda_z () { _lda ((*_memory)[_z()]); }
|
||||
void ldx_z () { _ldx ((*_memory)[_z()]); }
|
||||
void lax_z () { lda_z (); X=A; }
|
||||
void tay () { Z=N=Y=A; }
|
||||
void lda_ () { _lda ((*_memory)[PC++]); }
|
||||
void tax () { Z=N=X=A; }
|
||||
void ldy_a () { _ldy ((*_memory)[_a()]); }
|
||||
void lda_a () { _lda ((*_memory)[_a()]); }
|
||||
void ldx_a () { _ldx ((*_memory)[_a()]); }
|
||||
void lax_a () { lda_a (); X=A; }
|
||||
// b0
|
||||
void bcs () { if (C) _bra(); PC++; }
|
||||
void lda_iy () { _lda ((*_memory)[_iy()]); }
|
||||
void lax_iy () { lda_iy (); X=A; }
|
||||
void ldy_zx () { _ldy ((*_memory)[_zx()]); }
|
||||
void lda_zx () { _lda ((*_memory)[_zx()]); }
|
||||
void ldx_zy () { _ldx ((*_memory)[_zy()]); }
|
||||
void lax_zy () { ldx_zy (); A=X; }
|
||||
void clv () { V=0; }
|
||||
void lda_ay () { _lda ((*_memory)[_ay()]); }
|
||||
void tsx () { Z=N=X=S; }
|
||||
void ldy_ax () { _ldy ((*_memory)[_ax()]); }
|
||||
void lda_ax () { _lda ((*_memory)[_ax()]); }
|
||||
void ldx_ay () { _ldx ((*_memory)[_ay()]); }
|
||||
void lax_ay () { ldx_ay (); A=X; }
|
||||
// c0
|
||||
void cpy_ () { _cpy ((*_memory)[PC++]); }
|
||||
void cmp_ix () { _cmp ((*_memory)[_ix()]); }
|
||||
void cpy_z () { _cpy ((*_memory)[_z()]); }
|
||||
void cmp_z () { _cmp ((*_memory)[_z()]); }
|
||||
void dec_z () { _dec (_z()); }
|
||||
void iny () { Z=N=++Y; }
|
||||
void cmp_ () { _cmp ((*_memory)[PC++]); }
|
||||
void dex () { Z=N=--X; }
|
||||
void cpy_a () { _cpy ((*_memory)[_a()]); }
|
||||
void cmp_a () { _cmp ((*_memory)[_a()]); }
|
||||
void dec_a () { _dec (_a()); }
|
||||
// d0
|
||||
void bne () { if (Z) _bra(); PC++; }
|
||||
void cmp_iy () { _cmp ((*_memory)[_iy()]); }
|
||||
void cmp_zx () { _cmp ((*_memory)[_zx()]); }
|
||||
void dec_zx () { _dec (_zx()); }
|
||||
void cld () { P.bits.D = 0; }
|
||||
void cmp_ay () { _cmp ((*_memory)[_ay()]); }
|
||||
void cmp_ax () { _cmp ((*_memory)[_ax()]); }
|
||||
void dec_ax () { _dec (_ax()); }
|
||||
// e0
|
||||
void cpx_ () { _cpx ((*_memory)[PC++]); }
|
||||
void sbc_ix () { _sbc ((*_memory)[_ix()]); }
|
||||
void cpx_z () { _cpx ((*_memory)[_z()]); }
|
||||
void sbc_z () { _sbc ((*_memory)[_z()]); }
|
||||
void inc_z () { _inc (_z()); }
|
||||
void inx () { Z=N=++X; }
|
||||
void sbc_ () { _sbc ((*_memory)[PC++]); }
|
||||
void cpx_a () { _cpx ((*_memory)[_a()]); }
|
||||
void sbc_a () { _sbc ((*_memory)[_a()]); }
|
||||
void inc_a () { _inc (_a()); }
|
||||
// f0
|
||||
void beq () { if (!Z) _bra(); PC++; }
|
||||
void sbc_iy () { _sbc ((*_memory)[_iy()]); }
|
||||
void sbc_zx () { _sbc ((*_memory)[_zx()]); }
|
||||
void inc_zx () { _inc (_zx()); }
|
||||
void sed () { P.bits.D = 1; }
|
||||
void sbc_ay () { _sbc ((*_memory)[_ay()]); }
|
||||
void sbc_ax () { _sbc ((*_memory)[_ax()]); }
|
||||
void inc_ax () { _inc (_ax()); }
|
||||
};
|
||||
#endif
|
13
r65emu.h
Normal file
13
r65emu.h
Normal file
@ -0,0 +1,13 @@
|
||||
#ifndef _R65EMU_H
|
||||
#define _R65EMU_H
|
||||
|
||||
#include "memory.h"
|
||||
#include "cpu.h"
|
||||
#include "r6502.h"
|
||||
#include "ram.h"
|
||||
#include "spiram.h"
|
||||
#include "prom.h"
|
||||
#include "ps2drv.h"
|
||||
#include "hardware.h"
|
||||
|
||||
#endif
|
17
ram.h
Normal file
17
ram.h
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef _RAM_H
|
||||
#define _RAM_H
|
||||
|
||||
class ram: public Memory::Device {
|
||||
public:
|
||||
virtual void operator= (byte c) { _mem[_acc] = c; }
|
||||
virtual operator byte () { return _mem[_acc]; }
|
||||
|
||||
void checkpoint(Stream &s) { s.write(_mem, sizeof(_mem)); }
|
||||
void restore(Stream &s) { s.readBytes((char *)_mem, sizeof(_mem)); }
|
||||
|
||||
ram (): Memory::Device(sizeof(_mem)) {}
|
||||
|
||||
private:
|
||||
byte _mem[1024];
|
||||
};
|
||||
#endif
|
47
spiram.cpp
Normal file
47
spiram.cpp
Normal file
@ -0,0 +1,47 @@
|
||||
#include <SPI.h>
|
||||
#include <SpiRAM.h>
|
||||
#include "memory.h"
|
||||
#include "spiram.h"
|
||||
#include "hardware.h"
|
||||
|
||||
extern SPIClass SPIRAM_DEV;
|
||||
|
||||
SpiRAM spiRam(SPIRAM_DEV, SPIRAM_CS);
|
||||
|
||||
void spiram::begin(byte cs, int module)
|
||||
{
|
||||
SPI_for_SD.setModule(module);
|
||||
SPI_for_SD.setClockDivider(SPI_CLOCK_DIV16);
|
||||
SPI_for_SD.setDataMode(SPI_MODE0);
|
||||
pinMode(PF_3, OUTPUT);
|
||||
pinMode(cs, OUTPUT);
|
||||
}
|
||||
|
||||
void spiram::operator=(byte b)
|
||||
{
|
||||
spiRam.write_byte(_acc, b);
|
||||
}
|
||||
|
||||
spiram::operator byte()
|
||||
{
|
||||
return spiRam.read_byte(_acc);
|
||||
}
|
||||
|
||||
void spiram::checkpoint(Stream &s)
|
||||
{
|
||||
char buf[Memory::page_size];
|
||||
for (int i = 0; i < pages(); i++) {
|
||||
spiRam.read_stream(i * Memory::page_size, buf, sizeof(buf));
|
||||
s.write((byte *)buf, sizeof(buf));
|
||||
}
|
||||
}
|
||||
|
||||
void spiram::restore(Stream &s)
|
||||
{
|
||||
char buf[Memory::page_size];
|
||||
for (int i = 0; i < pages(); i++) {
|
||||
s.readBytes(buf, sizeof(buf));
|
||||
spiRam.write_stream(i * Memory::page_size, buf, sizeof(buf));
|
||||
}
|
||||
}
|
||||
|
16
spiram.h
Normal file
16
spiram.h
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef __SPIRAM_H__
|
||||
#define __SPIRAM_H__
|
||||
|
||||
class spiram: public Memory::Device {
|
||||
public:
|
||||
virtual void operator= (byte c);
|
||||
virtual operator byte ();
|
||||
|
||||
void checkpoint(Stream &s);
|
||||
void restore(Stream &s);
|
||||
|
||||
spiram(int bytes): Memory::Device(bytes) {}
|
||||
void begin(byte cs, int module);
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user