From a19bbc68984f2387fe09e241f60c3a74208893a3 Mon Sep 17 00:00:00 2001 From: Stephen Crane Date: Sat, 18 Oct 2014 12:33:48 +0100 Subject: [PATCH] initial commit --- acia.h | 39 +++++++ cpu.h | 26 +++++ hardware.h | 34 ++++++ memory.cpp | 24 ++++ memory.h | 49 +++++++++ prom.h | 10 ++ ps2drv.cpp | 81 ++++++++++++++ ps2drv.h | 46 ++++++++ r6502.cpp | 264 ++++++++++++++++++++++++++++++++++++++++++++ r6502.h | 316 +++++++++++++++++++++++++++++++++++++++++++++++++++++ r65emu.h | 13 +++ ram.h | 17 +++ spiram.cpp | 47 ++++++++ spiram.h | 16 +++ 14 files changed, 982 insertions(+) create mode 100644 acia.h create mode 100644 cpu.h create mode 100644 hardware.h create mode 100644 memory.cpp create mode 100644 memory.h create mode 100644 prom.h create mode 100644 ps2drv.cpp create mode 100644 ps2drv.h create mode 100644 r6502.cpp create mode 100644 r6502.h create mode 100644 r65emu.h create mode 100644 ram.h create mode 100644 spiram.cpp create mode 100644 spiram.h diff --git a/acia.h b/acia.h new file mode 100644 index 0000000..06a9540 --- /dev/null +++ b/acia.h @@ -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 +}; diff --git a/cpu.h b/cpu.h new file mode 100644 index 0000000..4d41e47 --- /dev/null +++ b/cpu.h @@ -0,0 +1,26 @@ +/* + * cpu.h + */ +#ifndef _CPU_H +#define _CPU_H + +#ifndef _SETJMP_H +#include +#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 diff --git a/hardware.h b/hardware.h new file mode 100644 index 0000000..58e1060 --- /dev/null +++ b/hardware.h @@ -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 diff --git a/memory.cpp b/memory.cpp new file mode 100644 index 0000000..f5395fc --- /dev/null +++ b/memory.cpp @@ -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); +} + + diff --git a/memory.h b/memory.h new file mode 100644 index 0000000..9944fe8 --- /dev/null +++ b/memory.h @@ -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 diff --git a/prom.h b/prom.h new file mode 100644 index 0000000..c06048b --- /dev/null +++ b/prom.h @@ -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; +}; diff --git a/ps2drv.cpp b/ps2drv.cpp new file mode 100644 index 0000000..0efd5c9 --- /dev/null +++ b/ps2drv.cpp @@ -0,0 +1,81 @@ +#include +#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; +} diff --git a/ps2drv.h b/ps2drv.h new file mode 100644 index 0000000..65c8019 --- /dev/null +++ b/ps2drv.h @@ -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 diff --git a/r6502.cpp b/r6502.cpp new file mode 100644 index 0000000..0bcd739 --- /dev/null +++ b/r6502.cpp @@ -0,0 +1,264 @@ +#include +#include + +#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; +} + diff --git a/r6502.h b/r6502.h new file mode 100644 index 0000000..ebf66b6 --- /dev/null +++ b/r6502.h @@ -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 diff --git a/r65emu.h b/r65emu.h new file mode 100644 index 0000000..c5765d4 --- /dev/null +++ b/r65emu.h @@ -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 diff --git a/ram.h b/ram.h new file mode 100644 index 0000000..5ebd418 --- /dev/null +++ b/ram.h @@ -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 diff --git a/spiram.cpp b/spiram.cpp new file mode 100644 index 0000000..fff96c5 --- /dev/null +++ b/spiram.cpp @@ -0,0 +1,47 @@ +#include +#include +#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)); + } +} + diff --git a/spiram.h b/spiram.h new file mode 100644 index 0000000..a98683d --- /dev/null +++ b/spiram.h @@ -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