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