diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c3c12cf --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.o +emu816 diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..ca033fe --- /dev/null +++ b/Makefile @@ -0,0 +1,23 @@ + +CPPFLAGS=-O + +all: emu816 + +clean: + $(RM) *.o + $(RM) emu816 + +emu816: wdc816.o emu816.o mem816.o program.o + g++ wdc816.o emu816.o mem816.o program.o -o emu816 + +wdc816.o: \ + wdc816.cc wdc816.h + +emu816.o: \ + emu816.cc emu816.h wdc816.h mem816.h + +mem816.o: \ + mem816.cc mem816.h wdc816.h + +program.o: \ + program.cc emu816.h mem816.h wdc816.h diff --git a/emu816.cc b/emu816.cc new file mode 100644 index 0000000..45a7786 --- /dev/null +++ b/emu816.cc @@ -0,0 +1,521 @@ + +// TODO: decimal mode + +#include "emu816.h" + +#ifdef CHIPKIT +#include "WProgram.h" +#else +# include +# include + +using namespace std; +#endif + +//============================================================================== +//------------------------------------------------------------------------------ + +emu816::emu816(mem816 &mem) + : mem(mem) +{ } + +emu816::~emu816() +{ } + +void emu816::reset() +{ + e = 1; + pbr = 0x00 << 16; + dbr = 0x00 << 16; + dp.w = 0x0000; + sp.w = 0x0100; + pc = mem.getWord(0xfffc); + p.b = 0x34; + + interrupted = false; +} + +void emu816::step() +{ + // Check for NMI/IRQ + + SHOWPC(); + + switch (mem.getByte (join(pbr, pc++))) { + case 0x00: op_brk(am_immb()); break; + case 0x01: op_ora(am_dpix()); break; + case 0x02: op_cop(am_immb()); break; + case 0x03: op_ora(am_srel()); break; + case 0x04: op_tsb(am_dpag()); break; + case 0x05: op_ora(am_dpag()); break; + case 0x06: op_asl(am_dpag()); break; + case 0x07: op_ora(am_dpil()); break; + case 0x08: op_php(am_impl()); break; + case 0x09: op_ora(am_immm()); break; + case 0x0a: op_asla(am_acc()); break; + case 0x0b: op_phd(am_impl()); break; + case 0x0c: op_tsb(am_absl()); break; + case 0x0d: op_ora(am_absl()); break; + case 0x0e: op_asl(am_absl()); break; + case 0x0f: op_ora(am_alng()); break; + + case 0x10: op_bpl(am_rela()); break; + case 0x11: op_ora(am_dpiy()); break; + case 0x12: op_ora(am_dpgi()); break; + case 0x13: op_ora(am_sriy()); break; + case 0x14: op_trb(am_dpag()); break; + case 0x15: op_ora(am_dpgx()); break; + case 0x16: op_asl(am_dpgx()); break; + case 0x17: op_ora(am_dily()); break; + case 0x18: op_clc(am_impl()); break; + case 0x19: op_ora(am_absy()); break; + case 0x1a: op_inca(am_acc()); break; + case 0x1b: op_tcs(am_impl()); break; + case 0x1c: op_trb(am_absl()); break; + case 0x1d: op_ora(am_absx()); break; + case 0x1e: op_asl(am_absx()); break; + case 0x1f: op_ora(am_alnx()); break; + + case 0x20: op_jsr(am_absl()); break; + case 0x21: op_and(am_dpix()); break; + case 0x22: op_jsl(am_alng()); break; + case 0x23: op_and(am_srel()); break; + case 0x24: op_bit(am_dpag()); break; + case 0x25: op_and(am_dpag()); break; + case 0x26: op_rol(am_dpag()); break; + case 0x27: op_and(am_dpil()); break; + case 0x28: op_plp(am_impl()); break; + case 0x29: op_and(am_immm()); break; + case 0x2a: op_rola(am_acc()); break; + case 0x2b: op_pld(am_impl()); break; + case 0x2c: op_bit(am_absl()); break; + case 0x2d: op_and(am_absl()); break; + case 0x2e: op_rol(am_absl()); break; + case 0x2f: op_and(am_alng()); break; + + case 0x30: op_bmi(am_rela()); break; + case 0x31: op_and(am_dpiy()); break; + case 0x32: op_and(am_dpgi()); break; + case 0x33: op_and(am_sriy()); break; + case 0x34: op_bit(am_dpgx()); break; + case 0x35: op_and(am_dpgx()); break; + case 0x36: op_rol(am_dpgx()); break; + case 0x37: op_and(am_dily()); break; + case 0x38: op_sec(am_impl()); break; + case 0x39: op_and(am_absy()); break; + case 0x3a: op_deca(am_acc()); break; + case 0x3b: op_tsc(am_impl()); break; + case 0x3c: op_bit(am_absx()); break; + case 0x3d: op_and(am_absx()); break; + case 0x3e: op_rol(am_absx()); break; + case 0x3f: op_and(am_alnx()); break; + + case 0x40: op_rti(am_impl()); break; + case 0x41: op_eor(am_dpix()); break; + case 0x42: op_wdm(am_immb()); break; + case 0x43: op_eor(am_srel()); break; + case 0x44: op_mvp(am_immw()); break; + case 0x45: op_eor(am_dpag()); break; + case 0x46: op_lsr(am_dpag()); break; + case 0x47: op_eor(am_dpil()); break; + case 0x48: op_pha(am_impl()); break; + case 0x49: op_eor(am_immm()); break; + case 0x4a: op_lsra(am_impl()); break; + case 0x4b: op_phk(am_impl()); break; + case 0x4c: op_jmp(am_absl()); break; + case 0x4d: op_eor(am_absl()); break; + case 0x4e: op_lsr(am_absl()); break; + case 0x4f: op_eor(am_alng()); break; + + case 0x50: op_bvc(am_rela()); break; + case 0x51: op_eor(am_dpiy()); break; + case 0x52: op_eor(am_dpgi()); break; + case 0x53: op_eor(am_sriy()); break; + case 0x54: op_mvn(am_immw()); break; + case 0x55: op_eor(am_dpgx()); break; + case 0x56: op_lsr(am_dpgx()); break; + case 0x57: op_eor(am_dpil()); break; + case 0x58: op_cli(am_impl()); break; + case 0x59: op_eor(am_absy()); break; + case 0x5a: op_phy(am_impl()); break; + case 0x5b: op_tcd(am_impl()); break; + case 0x5c: op_jmp(am_alng()); break; + case 0x5d: op_eor(am_absx()); break; + case 0x5e: op_lsr(am_absx()); break; + case 0x5f: op_eor(am_alnx()); break; + + case 0x60: op_rts(am_impl()); break; + case 0x61: op_adc(am_dpix()); break; + case 0x62: op_per(am_lrel()); break; + case 0x63: op_adc(am_srel()); break; + case 0x64: op_stz(am_dpag()); break; + case 0x65: op_adc(am_dpag()); break; + case 0x66: op_ror(am_dpag()); break; + case 0x67: op_adc(am_dpil()); break; + case 0x68: op_pla(am_impl()); break; + case 0x69: op_adc(am_immm()); break; + case 0x6a: op_rora(am_impl()); break; + case 0x6b: op_rtl(am_impl()); break; + case 0x6c: op_jmp(am_absi()); break; + case 0x6d: op_adc(am_absl()); break; + case 0x6e: op_ror(am_absl()); break; + case 0x6f: op_adc(am_alng()); break; + + case 0x70: op_bvs(am_rela()); break; + case 0x71: op_adc(am_dpiy()); break; + case 0x72: op_adc(am_dpgi()); break; + case 0x73: op_adc(am_sriy()); break; + case 0x74: op_stz(am_dpgx()); break; + case 0x75: op_adc(am_dpgx()); break; + case 0x76: op_ror(am_dpgx()); break; + case 0x77: op_adc(am_dily()); break; + case 0x78: op_sei(am_impl()); break; + case 0x79: op_adc(am_absy()); break; + case 0x7a: op_ply(am_impl()); break; + case 0x7b: op_tdc(am_impl()); break; + case 0x7c: op_jmp(am_abxi()); break; + case 0x7d: op_adc(am_absx()); break; + case 0x7e: op_ror(am_absx()); break; + case 0x7f: op_adc(am_alnx()); break; + + case 0x80: op_bra(am_rela()); break; + case 0x81: op_sta(am_dpix()); break; + case 0x82: op_brl(am_lrel()); break; + case 0x83: op_sta(am_srel()); break; + case 0x84: op_sty(am_dpag()); break; + case 0x85: op_sta(am_dpag()); break; + case 0x86: op_stx(am_dpag()); break; + case 0x87: op_sta(am_dpil()); break; + case 0x88: op_dey(am_impl()); break; + case 0x89: op_biti(am_immm()); break; + case 0x8a: op_txa(am_impl()); break; + case 0x8b: op_phb(am_impl()); break; + case 0x8c: op_sty(am_absl()); break; + case 0x8d: op_sta(am_absl()); break; + case 0x8e: op_stx(am_absl()); break; + case 0x8f: op_sta(am_alng()); break; + + case 0x90: op_bcc(am_rela()); break; + case 0x91: op_sta(am_dpiy()); break; + case 0x92: op_sta(am_dpgi()); break; + case 0x93: op_sta(am_sriy()); break; + case 0x94: op_sty(am_dpgx()); break; + case 0x95: op_sta(am_dpgx()); break; + case 0x96: op_stx(am_dpgy()); break; + case 0x97: op_sta(am_dily()); break; + case 0x98: op_tya(am_impl()); break; + case 0x99: op_sta(am_absy()); break; + case 0x9a: op_txs(am_impl()); break; + case 0x9b: op_txy(am_impl()); break; + case 0x9c: op_stz(am_absl()); break; + case 0x9d: op_sta(am_absx()); break; + case 0x9e: op_stz(am_absx()); break; + case 0x9f: op_sta(am_alnx()); break; + + case 0xa0: op_ldy(am_immx()); break; + case 0xa1: op_lda(am_dpix()); break; + case 0xa2: op_ldx(am_immx()); break; + case 0xa3: op_lda(am_srel()); break; + case 0xa4: op_ldy(am_dpag()); break; + case 0xa5: op_lda(am_dpag()); break; + case 0xa6: op_ldx(am_dpag()); break; + case 0xa7: op_lda(am_dpil()); break; + case 0xa8: op_tay(am_impl()); break; + case 0xa9: op_lda(am_immm()); break; + case 0xaa: op_tax(am_impl()); break; + case 0xab: op_plb(am_impl()); break; + case 0xac: op_ldy(am_absl()); break; + case 0xad: op_lda(am_absl()); break; + case 0xae: op_ldx(am_absl()); break; + case 0xaf: op_lda(am_alng()); break; + + case 0xb0: op_bcs(am_rela()); break; + case 0xb1: op_lda(am_dpiy()); break; + case 0xb2: op_lda(am_dpgi()); break; + case 0xb3: op_lda(am_sriy()); break; + case 0xb4: op_ldy(am_dpgx()); break; + case 0xb5: op_lda(am_dpgx()); break; + case 0xb6: op_ldx(am_dpgy()); break; + case 0xb7: op_lda(am_dpil()); break; + case 0xb8: op_clv(am_impl()); break; + case 0xb9: op_lda(am_absy()); break; + case 0xba: op_tsx(am_impl()); break; + case 0xbb: op_tyx(am_impl()); break; + case 0xbc: op_ldy(am_absx()); break; + case 0xbd: op_lda(am_absx()); break; + case 0xbe: op_ldx(am_absy()); break; + case 0xbf: op_lda(am_alng()); break; + + case 0xc0: op_cpy(am_immx()); break; + case 0xc1: op_cmp(am_dpix()); break; + case 0xc2: op_rep(am_immb()); break; + case 0xc3: op_cmp(am_srel()); break; + case 0xc4: op_cpy(am_dpag()); break; + case 0xc5: op_cmp(am_dpag()); break; + case 0xc6: op_dec(am_dpag()); break; + case 0xc7: op_cmp(am_dpil()); break; + case 0xc8: op_iny(am_impl()); break; + case 0xc9: op_cmp(am_immm()); break; + case 0xca: op_dex(am_impl()); break; + case 0xcb: op_wai(am_impl()); break; + case 0xcc: op_cpy(am_absl()); break; + case 0xcd: op_cmp(am_absl()); break; + case 0xce: op_dec(am_absl()); break; + case 0xcf: op_cmp(am_alng()); break; + + case 0xd0: op_bne(am_rela()); break; + case 0xd1: op_cmp(am_dpiy()); break; + case 0xd2: op_cmp(am_dpgi()); break; + case 0xd3: op_cmp(am_sriy()); break; + case 0xd4: op_pei(am_dpgi()); break; + case 0xd5: op_cmp(am_dpgx()); break; + case 0xd6: op_dec(am_dpgx()); break; + case 0xd7: op_cmp(am_dily()); break; + case 0xd8: op_cld(am_impl()); break; + case 0xd9: op_cmp(am_absy()); break; + case 0xda: op_phx(am_impl()); break; + case 0xdb: op_stp(am_impl()); break; + case 0xdc: op_jmp(am_abil()); break; + case 0xdd: op_cmp(am_absx()); break; + case 0xde: op_dec(am_absx()); break; + case 0xdf: op_cmp(am_alnx()); break; + + case 0xe0: op_cpx(am_immx()); break; + case 0xe1: op_sbc(am_dpix()); break; + case 0xe2: op_sep(am_immb()); break; + case 0xe3: op_sbc(am_srel()); break; + case 0xe4: op_cpx(am_dpag()); break; + case 0xe5: op_sbc(am_dpag()); break; + case 0xe6: op_inc(am_dpag()); break; + case 0xe7: op_sbc(am_dpil()); break; + case 0xe8: op_inx(am_impl()); break; + case 0xe9: op_sbc(am_immm()); break; + case 0xea: op_nop(am_impl()); break; + case 0xeb: op_xba(am_impl()); break; + case 0xec: op_cpx(am_absl()); break; + case 0xed: op_sbc(am_absl()); break; + case 0xee: op_inc(am_absl()); break; + case 0xef: op_sbc(am_alng()); break; + + case 0xf0: op_beq(am_rela()); break; + case 0xf1: op_sbc(am_dpiy()); break; + case 0xf2: op_sbc(am_dpgi()); break; + case 0xf3: op_sbc(am_sriy()); break; + case 0xf4: op_pea(am_immw()); break; + case 0xf5: op_sbc(am_dpgx()); break; + case 0xf6: op_inc(am_dpgx()); break; + case 0xf7: op_sbc(am_dily()); break; + case 0xf8: op_sed(am_impl()); break; + case 0xf9: op_sbc(am_absy()); break; + case 0xfa: op_plx(am_impl()); break; + case 0xfb: op_xce(am_impl()); break; + case 0xfc: op_jsr(am_abxi()); break; + case 0xfd: op_sbc(am_absx()); break; + case 0xfe: op_inc(am_absx()); break; + case 0xff: op_sbc(am_alnx()); break; + } + + ENDL(); +} + +//============================================================================== +// Debugging Utilities +//------------------------------------------------------------------------------ + +#ifdef CHIPKIT +void emu816::show() +{ + Serial.print (toHex(pbr, 2)); + Serial.print (':'); + Serial.print (toHex(pc, 4)); + Serial.print (' '); + Serial.print (toHex(mem.getByte(join(pbr, pc)), 2)); +} + +void emu816::bytes(unsigned int count) +{ + if (count > 0) { + Serial.print(' '); + Serial.print(toHex(mem.getByte(bank(pbr) | (pc + 0)), 2)); + } + else + Serial.print(" "); + + if (count > 1) { + Serial.print(' '); + Serial.print(toHex(mem.getByte(bank(pbr) | (pc + 1)), 2)); + } + else + Serial.print(" "); + + if (count > 2) { + Serial.print(' '); + Serial.print(toHex(mem.getByte(bank(pbr) | (pc + 2)), 2)); + } + else + Serial.print(" "); + + Serial.print(' '); +} + +void emu816::dump(const char *mnem, Addr ea) +{ + Serial.print(mnem); + Serial.print(" {"); + Serial.print(toHex(ea, 4)); + Serial.print('}'); + + Serial.print(" E="); + Serial.print(toHex(e, 1)); + + Serial.print(" P="); + Serial.print(p.f_n ? 'N' : '.'); + Serial.print(p.f_v ? 'V' : '.'); + Serial.print(p.f_m ? 'M' : '.'); + Serial.print(p.f_x ? 'X' : '.'); + Serial.print(p.f_d ? 'D' : '.'); + Serial.print(p.f_i ? 'I' : '.'); + Serial.print(p.f_z ? 'Z' : '.'); + Serial.print(p.f_c ? 'C' : '.'); + + Serial.print(" A="); + if (e || p.f_m) { + Serial.print(toHex(hi(a.w), 2)); + Serial.print('['); + } + else { + Serial.print('['); + Serial.print(toHex(hi(a.w), 2)); + } + Serial.print(toHex(a.b, 2)); + Serial.print(']'); + + Serial.print(" X="); + if (e || p.f_x) { + Serial.print(toHex(hi(x.w), 2)); + Serial.print('['); + } + else { + Serial.print('['); + Serial.print(toHex(hi(x.w), 2)); + } + Serial.print(toHex(x.b, 2)); + Serial.print(']'); + + Serial.print(" Y="); + if (e || p.f_x) { + Serial.print(toHex(hi(y.w), 2)); + Serial.print('['); + } + else { + Serial.print('['); + Serial.print(toHex(hi(y.w), 2)); + } + Serial.print(toHex(y.b, 2)); + Serial.print(']'); + + Serial.print(" DP="); + Serial.print(toHex(dp.w, 4)); + + Serial.print(" SP="); + if (e) { + Serial.print(toHex(hi(sp.w), 2)); + Serial.print('['); + } + else { + Serial.print('['); + Serial.print(toHex(hi(sp.w), 2)); + } + Serial.print(toHex(sp.b, 2)); + Serial.print(']'); + + Serial.print(" {"); + Serial.print(' '); + Serial.print(toHex(mem.getByte(sp.w + 1), 2)); + Serial.print(' '); + Serial.print(toHex(mem.getByte(sp.w + 2), 2)); + Serial.print(' '); + Serial.print(toHex(mem.getByte(sp.w + 3), 2)); + Serial.print(' '); + Serial.print(toHex(mem.getByte(sp.w + 4), 2)); + Serial.print(" }"); + + Serial.print(" DBR="); + Serial.print(toHex(dbr, 2)); +} +#else +void emu816::show() +{ + cout << toHex(pbr, 2); + cout << ':' << toHex(pc, 4); + cout << ' ' << toHex(mem.getByte(join(pbr, pc)), 2); +} + +void emu816::bytes(unsigned int count) +{ + if (count > 0) + cout << ' ' << toHex(mem.getByte(bank(pbr) | (pc + 0)), 2); + else + cout << " "; + + if (count > 1) + cout << ' ' << toHex(mem.getByte(bank(pbr) | (pc + 1)), 2); + else + cout << " "; + + if (count > 2) + cout << ' ' << toHex(mem.getByte(bank(pbr) | (pc + 2)), 2); + else + cout << " "; + + cout << ' '; +} + +void emu816::dump(const char *mnem, Addr ea) +{ + cout << mnem << " {" << toHex(ea, 4) << '}'; + + cout << " E=" << toHex(e, 1); + cout << " P=" << + (p.f_n ? 'N' : '.') << + (p.f_v ? 'V' : '.') << + (p.f_m ? 'M' : '.') << + (p.f_x ? 'X' : '.') << + (p.f_d ? 'D' : '.') << + (p.f_i ? 'I' : '.') << + (p.f_z ? 'Z' : '.') << + (p.f_c ? 'C' : '.'); + cout << " A="; + if (e || p.f_m) + cout << toHex(hi(a.w), 2) << '['; + else + cout << '[' << toHex(hi(a.w), 2); + cout << toHex(a.b, 2) << ']'; + cout << " X="; + if (e || p.f_x) + cout << toHex(hi(x.w), 2) << '['; + else + cout << '[' << toHex(hi(x.w), 2); + cout << toHex(x.b, 2) << ']'; + cout << " Y="; + if (e || p.f_x) + cout << toHex(hi(y.w), 2) << '['; + else + cout << '[' << toHex(hi(y.w), 2); + cout << toHex(y.b, 2) << ']'; + cout << " DP=" << toHex(dp.w, 4); + cout << " SP="; + if (e) + cout << toHex(hi(sp.w), 2) << '['; + else + cout << '[' << toHex(hi(sp.w), 2); + cout << toHex(sp.b, 2) << ']'; + cout << " {"; + cout << ' ' << toHex(mem.getByte(sp.w + 1), 2); + cout << ' ' << toHex(mem.getByte(sp.w + 2), 2); + cout << ' ' << toHex(mem.getByte(sp.w + 3), 2); + cout << ' ' << toHex(mem.getByte(sp.w + 4), 2); + cout << " }"; + cout << " DBR=" << toHex(dbr, 2); +} +#endif diff --git a/emu816.h b/emu816.h new file mode 100644 index 0000000..0443cea --- /dev/null +++ b/emu816.h @@ -0,0 +1,1469 @@ +#ifndef EMU816 +#define EMU816 +#include "mem816.h" + +#if 1 +# define TRACE(MNEM) { dump(MNEM, ea); } +# define BYTES(N) { bytes(N); pc += N; } +# define SHOWPC() { show(); } +# ifdef CHIPKIT +# define ENDL() { Serial.println (); } +# else +# define ENDL() { cout << endl; } +# endif +#else +# define TRACE(MNEM) +# define BYTES(N) { pc += N; } +# define SHOWPC() +# define ENDL() +#endif + +class emu816 : + public wdc816 +{ +public: + emu816(mem816 &mem); + ~emu816(); + + void reset(); + void step(); + +private: + union { + struct { + Bit f_c : 1; + Bit f_z : 1; + Bit f_i : 1; + Bit f_d : 1; + Bit f_x : 1; + Bit f_m : 1; + Bit f_v : 1; + Bit f_n : 1; + }; + Byte b; + } p; + + Bit e; + + union { + Byte b; + Word w; + } a, x, y, sp, dp; + + Word pc; + Byte pbr, dbr; + + mem816 &mem; + + bool interrupted; + unsigned long cycles; + + void show(); + void bytes(unsigned int); + void dump(const char *, Addr); + + INLINE void pushByte(Byte value) + { + mem.setByte(sp.w, value); + + if (e) + --sp.b; + else + --sp.w; + } + + INLINE void pushWord(Word value) + { + pushByte(hi(value)); + pushByte(lo(value)); + } + + INLINE Byte pullByte() + { + if (e) + ++sp.b; + else + ++sp.w; + + return (mem.getByte(sp.w)); + } + + INLINE Word pullWord() + { + register Byte l = pullByte(); + register Byte h = pullByte(); + + return (join(l, h)); + } + + // Absolute - a + INLINE Addr am_absl() + { + register Addr ea = join (dbr, mem.getWord(bank(pbr) | pc)); + + BYTES(2); + return (ea); + } + + // Absolute Indexed X - a,X + INLINE Addr am_absx() + { + register Addr ea = join(dbr, mem.getWord(bank(pbr) | pc)) + x.w; + + BYTES(2); + return (ea); + } + + // Absolute Indexed Y - a,Y + INLINE Addr am_absy() + { + register Addr ea = join(dbr, mem.getWord(bank(pbr) | pc)) + y.w; + + BYTES(2); + return (ea); + } + + // Absolute Indirect - (a) + INLINE Addr am_absi() + { + register Addr ia = join(0, mem.getWord(bank(pbr) | pc)); + + BYTES(2); + return (join(0, mem.getWord(ia))); + } + + // Absolute Indexed Indirect - (a,X) + INLINE Addr am_abxi() + { + register Addr ia = join(pbr, mem.getWord(bank(pbr) | pc)) + x.w; + + BYTES(2); + return (join(pbr, mem.getWord(ia))); + } + + // Absolute Long - >a + INLINE Addr am_alng() + { + Addr ea = mem.getAddr(bank(pbr) | pc); + + BYTES(3); + return (ea); + } + + // Absolute Long Indexed - >a,X + INLINE Addr am_alnx() + { + register Addr ea = mem.getAddr(bank(pbr) | pc) + x.w; + + BYTES(3); + return (ea); + } + + // Absolute Indirect Long - [a] + INLINE Addr am_abil() + { + register Addr ia = bank(0) | mem.getWord(bank(pbr) | pc); + + BYTES(2); + return (mem.getAddr(ia)); + } + + // Direct Page - d + INLINE Addr am_dpag() + { + Byte offset = mem.getByte(bank(pbr) | pc); + + BYTES(1); + return (bank(0) | (Word)(dp.w + offset)); + } + + // Direct Page Indexed X - d,X + INLINE Addr am_dpgx() + { + Byte offset = mem.getByte(bank(pbr) | pc) + x.b; + + BYTES(1); + return (bank(0) | (Word)(dp.w + offset)); + } + + // Direct Page Indexed Y - d,Y + INLINE Addr am_dpgy() + { + Byte offset = mem.getByte(bank(pbr) | pc) + y.b; + + BYTES(1); + return (bank(0) | (Word)(dp.w + offset)); + } + + // Direct Page Indirect - (d) + INLINE Addr am_dpgi() + { + Byte disp = mem.getByte(bank(pbr) | pc); + + BYTES(1); + return (bank(dbr) | mem.getWord(bank(0) | (Word)(dp.w + disp))); + } + + // Direct Page Indexed Indirect - (d,x) + INLINE Addr am_dpix() + { + Byte disp = mem.getByte(bank(pbr) | pc); + + BYTES(1); + return (bank(dbr) | mem.getWord(bank(0) | (Word)(dp.w + disp + x.w))); + } + + // Direct Page Indirect Indexed - (d),Y + INLINE Addr am_dpiy() + { + Byte disp = mem.getByte(bank(pbr) | pc); + + BYTES(1); + return (bank(dbr) | mem.getWord(bank(0) | (dp.w + disp)) + y.w); + } + + // Direct Page Indirect Long - [d] + INLINE Addr am_dpil() + { + Byte disp = mem.getByte(bank(pbr) | pc); + + BYTES(1); + return (mem.getAddr(bank(0) | (Word)(dp.w + disp))); + } + + // Direct Page Indirect Long Indexed - [d],Y + INLINE Addr am_dily() + { + Byte disp = mem.getByte(bank(pbr) | pc); + + BYTES(1); + return (mem.getAddr(bank(0) | (Word)(dp.w + disp)) + y.w); + } + + // Implied/Stack + INLINE Addr am_impl() + { + BYTES(0); + return (0); + } + + // Accumulator + INLINE Addr am_acc() + { + BYTES(0); + return (0); + } + + // Immediate Byte + INLINE Addr am_immb() + { + Addr ea = bank(pbr) | pc; + + BYTES(1); + return (ea); + } + + // Immediate Word + INLINE Addr am_immw() + { + Addr ea = bank(pbr) | pc; + + BYTES(2); + return (ea); + } + + // Immediate based on size of A/M + INLINE Addr am_immm() + { + Addr ea = bank(pbr) | pc; + unsigned int size = (e || p.f_m) ? 1 : 2; + + BYTES(size); + return (ea); + } + + // Immediate based on size of X/Y + INLINE Addr am_immx() + { + Addr ea = bank(pbr) | pc; + unsigned int size = (e || p.f_x) ? 1 : 2; + + BYTES(size); + return (ea); + } + + INLINE Addr am_lrel() + { + Word disp = mem.getWord(bank(pbr) | pc); + + BYTES(2); + return (bank(pbr) | (Word)(pc + (signed short)disp)); + } + + INLINE Addr am_rela() + { + Byte disp = mem.getByte(bank(pbr) | pc); + + BYTES(1); + return (bank(pbr) | (Word)(pc + (signed char)disp)); + } + + // Stack Relative - d,S + INLINE Addr am_srel() + { + Byte disp = mem.getByte(bank(pbr) | pc); + + BYTES(1); + + if (e) + return((bank(0) | join(sp.b + disp, hi(sp.w)))); + else + return (bank(0) | (Word)(sp.w + disp)); + } + + // Stack Relative Indirect Indexed Y - (d,S),Y + INLINE Addr am_sriy() + { + Byte disp = mem.getByte(bank(pbr) | pc); + register Word ia; + + BYTES(1); + + if (e) + ia = mem.getWord(join(sp.b + disp, hi(sp.w))); + else + ia = mem.getWord(bank(0) | (sp.w + disp)); + + return (bank(dbr) | (Word)(ia + y.w)); + } + + INLINE void setn(unsigned int flag) + { + p.f_n = flag ? 1 : 0; + } + + INLINE void setv(unsigned int flag) + { + p.f_v = flag ? 1 : 0; + } + + INLINE void setd(unsigned int flag) + { + p.f_d = flag ? 1 : 0; + } + + INLINE void seti(unsigned int flag) + { + p.f_i = flag ? 1 : 0; + } + + INLINE void setz(unsigned int flag) + { + p.f_z = flag ? 1 : 0; + } + + INLINE void setc(unsigned int flag) + { + p.f_c = flag ? 1 : 0; + } + + INLINE void setnz_b(Byte value) + { + setn(value & 0x80); + setz(value == 0); + } + + INLINE void setnz_w(Word value) + { + setn(value & 0x8000); + setz(value == 0); + } + + INLINE void op_adc(Addr ea) + { + TRACE("ADC"); + + if (e || p.f_m) { + Byte data = mem.getByte(ea); + Word temp = a.b + data + p.f_c; + + setc(temp & 0x100); + setv((~(a.b ^ data)) & (a.b ^ temp) & 0x80); + setnz_b(a.b = lo(temp)); + } + else { + Word data = mem.getWord(ea); + int temp = a.w + data + p.f_c; + + setc(temp & 0x100); + setv((~(a.w ^ data)) & (a.w ^ temp) & 0x8000); + setnz_w(a.w = (Word)temp); + } + } + + INLINE void op_and(Addr ea) + { + TRACE("AND"); + + if (e || p.f_m) + setnz_b(a.b &= mem.getByte(ea)); + else + setnz_w(a.w &= mem.getWord(ea)); + } + + INLINE void op_asl(Addr ea) + { + TRACE("ASL"); + + if (e || p.f_m) { + register Byte data = mem.getByte(ea); + + setc(data & 0x80); + setnz_b(data <<= 1); + mem.setByte(ea, data); + } + else { + register Word data = mem.getWord(ea); + + setc(data & 0x8000); + setnz_w(data <<= 1); + mem.setWord(ea, data); + } + } + + INLINE void op_asla(Addr ea) + { + TRACE("ASL"); + + if (e || p.f_m) { + setc(a.b & 0x80); + setnz_b(a.b <<= 1); + mem.setByte(ea, a.b); + } + else { + setc(a.w & 0x8000); + setnz_w(a.w <<= 1); + mem.setWord(ea, a.w); + } + } + + INLINE void op_bcc(Addr ea) + { + TRACE("BCC"); + + if (p.f_c == 0) + pc = (Word)ea; + } + + INLINE void op_bcs(Addr ea) + { + TRACE("BCS"); + + if (p.f_c == 1) + pc = (Word)ea; + } + + INLINE void op_beq(Addr ea) + { + TRACE("BEQ"); + + if (p.f_z == 1) + pc = (Word)ea; + } + + INLINE void op_bit(Addr ea) + { + TRACE("BIT"); + + if (e || p.f_m) { + register Byte data = mem.getByte(ea); + + setz((a.b & data) == 0); + setn(data & 0x80); + setv(data & 0x40); + } + else { + register Word data = mem.getWord(ea); + + setz((a.w & data) == 0); + setn(data & 0x8000); + setv(data & 0x4000); + } + } + + INLINE void op_biti(Addr ea) + { + TRACE("BIT"); + + if (e || p.f_m) { + register Byte data = mem.getByte(ea); + + setz((a.b & data) == 0); + } + else { + register Word data = mem.getWord(ea); + + setz((a.w & data) == 0); + } + } + + INLINE void op_bmi(Addr ea) + { + TRACE("BMI"); + + if (p.f_n == 1) + pc = (Word)ea; + } + + INLINE void op_bne(Addr ea) + { + TRACE("BNE"); + + if (p.f_z == 0) + pc = (Word)ea; + } + + INLINE void op_bpl(Addr ea) + { + TRACE("BPL"); + + if (p.f_n == 0) + pc = (Word)ea; + } + + INLINE void op_bra(Addr ea) + { + TRACE("BRA"); + + pc = (Word)ea; + } + + INLINE void op_brk(Addr ea) + { + TRACE("BRK"); + + if (e) { + pushWord(pc); + pushByte(p.b | 0x10); + + p.f_i = 1; + p.f_d = 0; + pbr = 0; + + pc = mem.getWord(0xfffe); + } + else { + pushByte(pbr); + pushWord(pc); + pushByte(p.b); + + p.f_i = 1; + p.f_d = 0; + pbr = 0; + + pc = mem.getWord(0xffe6); + } + } + + INLINE void op_brl(Addr ea) + { + TRACE("BRL"); + + pc = (Word)ea; + } + + INLINE void op_bvc(Addr ea) + { + TRACE("BVC"); + + if (p.f_v == 0) + pc = (Word)ea; + } + + INLINE void op_bvs(Addr ea) + { + TRACE("BVS"); + + if (p.f_v == 1) + pc = (Word)ea; + } + + INLINE void op_clc(Addr ea) + { + TRACE("CLC"); + + setc(0); + } + + INLINE void op_cld(Addr ea) + { + TRACE("CLD") + + setd(0); + } + + INLINE void op_cli(Addr ea) + { + TRACE("CLI") + + seti(0); + } + + INLINE void op_clv(Addr ea) + { + TRACE("CLD") + + setv(0); + } + + INLINE void op_cmp(Addr ea) + { + TRACE("CMP"); + + if (e || p.f_m) { + Byte data = mem.getByte(ea); + Word temp = a.b - data; + + setc(temp & 0x100); + setnz_b(lo(temp)); + } + else { + Word data = mem.getWord(ea); + Addr temp = a.w - data; + + setc(temp & 0x10000L); + setnz_w((Word)temp); + } + } + + INLINE void op_cop(Addr ea) + { + TRACE("COP"); + + if (e) { + pushWord(pc); + pushByte(p.b); + + p.f_i = 1; + p.f_d = 0; + pbr = 0; + + pc = mem.getWord(0xfff4); + } + else { + pushByte(pbr); + pushWord(pc); + pushByte(p.b); + + p.f_i = 1; + p.f_d = 0; + pbr = 0; + + pc = mem.getWord(0xffe4); + } + } + + INLINE void op_cpx(Addr ea) + { + TRACE("CPX"); + + if (e || p.f_x) { + Byte data = mem.getByte(ea); + setnz_b(x.b - data); + setc(x.b >= data); + } + else { + Word data = mem.getWord(ea); + setnz_w(x.w - data); + setc(x.w >= data); + } + } + + INLINE void op_cpy(Addr ea) + { + TRACE("CPY"); + + if (e || p.f_x) { + Byte data = mem.getByte(ea); + setnz_b(y.b - data); + setc(y.b >= data); + } + else { + Word data = mem.getWord(ea); + setnz_w(y.w - data); + setc(y.w >= data); + } + } + + INLINE void op_dec(Addr ea) + { + TRACE("DEC"); + + if (e || p.f_m) { + register Byte data = mem.getByte(ea); + + mem.setByte(ea, ++data); + setnz_b(data); + } + else { + register Word data = mem.getWord(ea); + + mem.setWord(ea, ++data); + setnz_w(data); + } + } + + INLINE void op_deca(Addr ea) + { + TRACE("DEC"); + + if (e || p.f_m) + setnz_b(--a.b); + else + setnz_w(--a.w); + } + + INLINE void op_dex(Addr ea) + { + TRACE("DEX"); + + if (e || p.f_x) + setnz_b(x.b -= 1); + else + setnz_w(x.w -= 1); + } + + INLINE void op_dey(Addr ea) + { + TRACE("DEY"); + + if (e || p.f_x) + setnz_b(y.b -= 1); + else + setnz_w(y.w -= 1); + } + + INLINE void op_eor(Addr ea) + { + TRACE("EOR"); + + if (e || p.f_m) + setnz_b(a.b ^= mem.getByte(ea)); + else + setnz_w(a.w ^= mem.getWord(ea)); + } + + INLINE void op_inc(Addr ea) + { + TRACE("INC"); + + if (e || p.f_m) { + register Byte data = mem.getByte(ea); + + mem.setByte(ea, ++data); + setnz_b(data); + } + else { + register Word data = mem.getWord(ea); + + mem.setWord(ea, ++data); + setnz_w(data); + } + } + + INLINE void op_inca(Addr ea) + { + TRACE("INC"); + + if (e || p.f_m) + setnz_b(++a.b); + else + setnz_w(++a.w); + } + + INLINE void op_inx(Addr ea) + { + TRACE("INX"); + + if (e || p.f_x) + setnz_b(++x.b); + else + setnz_w(++x.w); + } + + INLINE void op_iny(Addr ea) + { + TRACE("INY"); + + if (e || p.f_x) + setnz_b(++y.b); + else + setnz_w(++y.w); + } + + INLINE void op_jmp(Addr ea) + { + TRACE("JMP"); + + pbr = lo(ea >> 16); + pc = (Word)ea; + } + + INLINE void op_jsl(Addr ea) + { + TRACE("JSL"); + + pushByte(pbr); + pushWord(pc - 1); + + pbr = lo(ea >> 16); + pc = (Word)ea; + } + + INLINE void op_jsr(Addr ea) + { + TRACE("JSR"); + + pushWord(pc - 1); + + pc = (Word)ea; + } + + INLINE void op_lda(Addr ea) + { + TRACE("LDA"); + + if (e || p.f_m) + setnz_b(a.b = mem.getByte(ea)); + else + setnz_w(a.w = mem.getWord(ea)); + } + + INLINE void op_ldx(Addr ea) + { + TRACE("LDX"); + + if (e || p.f_x) + setnz_b(lo(x.w = mem.getByte(ea))); + else + setnz_w(x.w = mem.getWord(ea)); + } + + INLINE void op_ldy(Addr ea) + { + TRACE("LDY"); + + if (e || p.f_x) + setnz_b(lo(y.w = mem.getByte(ea))); + else + setnz_w(y.w = mem.getWord(ea)); + } + + INLINE void op_lsr(Addr ea) + { + TRACE("LSR"); + + if (e || p.f_m) { + register Byte data = mem.getByte(ea); + + setc(data & 0x01); + setnz_b(data >>= 1); + mem.setByte(ea, data); + } + else { + register Word data = mem.getWord(ea); + + setc(data & 0x0001); + setnz_w(data >>= 1); + mem.setWord(ea, data); + } + } + + INLINE void op_lsra(Addr ea) + { + TRACE("LSR"); + + if (e || p.f_m) { + setc(a.b & 0x01); + setnz_b(a.b >>= 1); + mem.setByte(ea, a.b); + } + else { + setc(a.w & 0x0001); + setnz_w(a.w >>= 1); + mem.setWord(ea, a.w); + } + } + + INLINE void op_mvn(Addr ea) + { + TRACE("MVN"); + } + + INLINE void op_mvp(Addr ea) + { + TRACE("MVP"); + } + + INLINE void op_nop(Addr ea) + { + TRACE("NOP"); + } + + INLINE void op_ora(Addr ea) + { + TRACE("ORA"); + + if (e || p.f_m) + setnz_b(a.b |= mem.getByte(ea)); + else + setnz_w(a.w |= mem.getWord(ea)); + } + + INLINE void op_pea(Addr ea) + { + TRACE("PEA"); + + pushWord(mem.getWord(ea)); + } + + INLINE void op_pei(Addr ea) + { + TRACE("PEI"); + } + + INLINE void op_per(Addr ea) + { + TRACE("PER"); + } + + INLINE void op_pha(Addr ea) + { + TRACE("PHA"); + + if (e || p.f_m) + pushByte(a.b); + else + pushWord(a.w); + } + + INLINE void op_phb(Addr ea) + { + TRACE("PHB"); + + pushByte(dbr); + } + + INLINE void op_phd(Addr ea) + { + TRACE("PHD"); + + pushWord(dp.w); + } + + INLINE void op_phk(Addr ea) + { + TRACE("PHK"); + + pushByte(pbr); + } + + INLINE void op_php(Addr ea) + { + TRACE("PHP"); + + pushByte(p.b); + } + + INLINE void op_phx(Addr ea) + { + TRACE("PHX"); + + if (e || p.f_x) + pushByte(x.b); + else + pushWord(x.w); + } + + INLINE void op_phy(Addr ea) + { + TRACE("PHY"); + + if (e || p.f_x) + pushByte(y.b); + else + pushWord(y.w); + } + + INLINE void op_pla(Addr ea) + { + TRACE("PLA"); + + if (e || p.f_m) + setnz_b(a.b = pullByte()); + else + setnz_w(a.w = pullWord()); + } + + INLINE void op_plb(Addr ea) + { + TRACE("PLB"); + + setnz_b(dbr = pullByte()); + } + + INLINE void op_pld(Addr ea) + { + TRACE("PLD"); + + setnz_w(dp.w = pullWord()); + } + + INLINE void op_plk(Addr ea) + { + TRACE("PLK"); + + setnz_b(dbr = pullByte()); + } + + INLINE void op_plp(Addr ea) + { + TRACE("PLP"); + + if (e) + p.b = pullByte() | 0x30; + else { + p.b = pullByte(); + + if (p.f_x) { + x.w = x.b; + y.w = y.b; + } + } + } + + INLINE void op_plx(Addr ea) + { + TRACE("PLX"); + + if (e || p.f_x) + setnz_b(lo(x.w = pullByte())); + else + setnz_w(x.w = pullWord()); + } + + INLINE void op_ply(Addr ea) + { + TRACE("PLY"); + + if (e || p.f_x) + setnz_b(lo(y.w = pullByte())); + else + setnz_w(y.w = pullWord()); + } + + INLINE void op_rep(Addr ea) + { + TRACE("REP"); + + p.b &= ~mem.getByte(ea); + if (e) p.f_m = p.f_x = 1; + } + + INLINE void op_rol(Addr ea) + { + TRACE("ROL"); + + if (e || p.f_m) { + register Byte data = mem.getByte(ea); + register Byte carry = p.f_c ? 0x01 : 0x00; + + setc(data & 0x80); + setnz_b(data = (data << 1) | carry); + mem.setByte(ea, data); + } + else { + register Word data = mem.getWord(ea); + register Word carry = p.f_c ? 0x0001 : 0x0000; + + setc(data & 0x8000); + setnz_w(data = (data << 1) | carry); + mem.setWord(ea, data); + } + } + + INLINE void op_rola(Addr ea) + { + TRACE("ROL"); + + if (e || p.f_m) { + register Byte carry = p.f_c ? 0x01 : 0x00; + + setc(a.b & 0x80); + setnz_b(a.b = (a.b << 1) | carry); + mem.setByte(ea, a.b); + } + else { + register Word carry = p.f_c ? 0x0001 : 0x0000; + + setc(a.w & 0x8000); + setnz_w(a.w = (a.w << 1) | carry); + mem.setWord(ea, a.w); + } + } + + INLINE void op_ror(Addr ea) + { + TRACE("ROR"); + + if (e || p.f_m) { + register Byte data = mem.getByte(ea); + register Byte carry = p.f_c ? 0x80 : 0x00; + + setc(data & 0x80); + setnz_b(data = (data >> 1) | carry); + mem.setByte(ea, data); + } + else { + register Word data = mem.getWord(ea); + register Word carry = p.f_c ? 0x8000 : 0x0000; + + setc(data & 0x8000); + setnz_w(data = (data >> 1) | carry); + mem.setWord(ea, data); + } + } + + INLINE void op_rora(Addr ea) + { + TRACE("ROR"); + + if (e || p.f_m) { + register Byte carry = p.f_c ? 0x80 : 0x00; + + setc(a.b & 0x80); + setnz_b(a.b = (a.b >> 1) | carry); + mem.setByte(ea, a.b); + } + else { + register Word carry = p.f_c ? 0x8000 : 0x0000; + + setc(a.w & 0x8000); + setnz_w(a.w = (a.w >> 1) | carry); + mem.setWord(ea, a.w); + } + } + + INLINE void op_rtl(Addr ea) + { + TRACE("RTL"); + + pc = pullWord(); + pbr = pullByte(); + } + + INLINE void op_rti(Addr ea) + { + TRACE("RTI"); + + if (e) { + p.b = pullByte(); + pc = pullWord(); + } + else { + p.b = pullByte(); + pc = pullWord(); + pbr = pullByte(); + } + p.f_i = 0; + } + + INLINE void op_rts(Addr ea) + { + TRACE("RTS"); + + pc = pullWord() + 1; + } + + INLINE void op_sbc(Addr ea) + { + TRACE("SBC"); + + if (e || p.f_m) { + Byte data = ~mem.getByte(ea); + Word temp = a.b + data + p.f_c; + + setc(temp & 0x100); + setv((~(a.b ^ data)) & (a.b ^ temp) & 0x80); + setnz_b(a.b = lo(temp)); + } + else { + Word data = ~mem.getWord(ea); + int temp = a.w + data + p.f_c; + + setc(temp & 0x100); + setv((~(a.w ^ data)) & (a.w ^ temp) & 0x8000); + setnz_w(a.w = (Word)temp); + } + } + + INLINE void op_sec(Addr ea) + { + TRACE("SEC"); + + setc(1); + } + + INLINE void op_sed(Addr ea) + { + TRACE("SED"); + + setd(1); + } + + INLINE void op_sei(Addr ea) + { + TRACE("SEI"); + + seti(1); + } + + INLINE void op_sep(Addr ea) + { + TRACE("SEP"); + + p.b |= mem.getByte(ea); + if (e) p.f_m = p.f_x = 1; + + if (p.f_x) { + x.w = x.b; + y.w = y.b; + } + } + + INLINE void op_sta(Addr ea) + { + TRACE("STA"); + + if (e || p.f_m) + mem.setByte(ea, a.b); + else + mem.setWord(ea, a.w); + } + + INLINE void op_stp(Addr ea) + { + TRACE("STP"); + + if (!interrupted) { + pc -= 1; + } + else + interrupted = false; + } + + INLINE void op_stx(Addr ea) + { + TRACE("STX"); + + if (e || p.f_x) + mem.setByte(ea, x.b); + else + mem.setWord(ea, x.w); + } + + INLINE void op_sty(Addr ea) + { + TRACE("STY"); + + if (e || p.f_x) + mem.setByte(ea, y.b); + else + mem.setWord(ea, y.w); + } + + INLINE void op_stz(Addr ea) + { + TRACE("STZ"); + + if (e || p.f_m) + mem.setByte(ea, 0); + else + mem.setWord(ea, 0); + } + + INLINE void op_tax(Addr ea) + { + TRACE("TAX"); + + if (e || p.f_x) + setnz_b(lo(x.w = a.b)); + else + setnz_w(x.w = a.w); + } + + INLINE void op_tay(Addr ea) + { + TRACE("TAY"); + + if (e || p.f_x) + setnz_b(lo(y.w = a.b)); + else + setnz_w(y.w = a.w); + } + + INLINE void op_tcd(Addr ea) + { + TRACE("TCD"); + + dp.w = a.w; + } + + INLINE void op_tdc(Addr ea) + { + TRACE("TDC"); + + if (e || p.f_m) + setnz_b(lo(a.w = dp.w)); + else + setnz_w(a.w = dp.w); + } + + INLINE void op_tcs(Addr ea) + { + TRACE("TCS"); + + sp.w = e ? (0x0100 | a.b) : a.w; + } + + INLINE void op_trb(Addr ea) + { + TRACE("TRB"); + + if (e || p.f_m) { + register Byte data = mem.getByte(ea); + + mem.setByte(ea, data & ~a.b); + setz((a.b & data) == 0); + } + else { + register Word data = mem.getWord(ea); + + mem.setWord(ea, data & ~a.w); + setz((a.w & data) == 0); + } + } + + INLINE void op_tsb(Addr ea) + { + TRACE("TSB"); + + if (e || p.f_m) { + register Byte data = mem.getByte(ea); + + mem.setByte(ea, data | a.b); + setz((a.b & data) == 0); + } + else { + register Word data = mem.getWord(ea); + + mem.setWord(ea, data | a.w); + setz((a.w & data) == 0); + } + } + + INLINE void op_tsc(Addr ea) + { + TRACE("TSC"); + + if (e || p.f_m) + setnz_b(lo(a.w = sp.w)); + else + setnz_w(a.w = sp.w); + } + + INLINE void op_tsx(Addr ea) + { + TRACE("TSX"); + } + + INLINE void op_txa(Addr ea) + { + TRACE("TXA"); + } + + INLINE void op_txs(Addr ea) + { + TRACE("TXS"); + } + + INLINE void op_txy(Addr ea) + { + TRACE("TXY"); + + if (e || p.f_x) + setnz_b(lo(y.w = x.w)); + else + setnz_w(y.w = x.w); + } + + INLINE void op_tya(Addr ea) + { + TRACE("TYA"); + + if (e || p.f_m) + setnz_b(a.b = y.b); + else + setnz_w(a.w = p.f_x ? y.b : y.w); + } + + INLINE void op_tyx(Addr ea) + { + TRACE("TYX"); + + if (e || p.f_x) + setnz_b(lo(x.w = y.w)); + else + setnz_w(x.w = y.w); + } + + INLINE void op_wai(Addr ea) + { + TRACE("WAI"); + + if (!interrupted) { + pc -= 1; + } + else + interrupted = false; + } + + INLINE void op_wdm(Addr ea) + { + TRACE("WDM"); + } + + INLINE void op_xba(Addr ea) + { + TRACE("XBA"); + + a.w = swap(a.w); + setnz_b(a.b); + } + + INLINE void op_xce(Addr ea) + { + TRACE("XCE"); + + unsigned char oe = e; + + e = p.f_c; + p.f_c = oe; + + if (e) { + sp.w = 0x0100 | sp.b; + dp.w = 0x0000; + } + } +}; +#endif diff --git a/mem816.cc b/mem816.cc new file mode 100644 index 0000000..56b9bc3 --- /dev/null +++ b/mem816.cc @@ -0,0 +1,15 @@ + +#include "mem816.h" + +mem816::mem816(Addr memMask, Addr ramSize, const Byte *pROM) + : memMask(memMask), ramSize(ramSize), pROM(pROM) +{ + pRAM = new Byte[ramSize]; +} + +mem816::mem816(Addr memMask, Addr ramSize, Byte *pRAM, const Byte *pROM) + : memMask(memMask), ramSize(ramSize), pRAM (pRAM), pROM(pROM) +{ } + +mem816::~mem816() +{ } diff --git a/mem816.h b/mem816.h new file mode 100644 index 0000000..2fb4f93 --- /dev/null +++ b/mem816.h @@ -0,0 +1,50 @@ +#ifndef MEM816 +#define MEM816 +#include "wdc816.h" + +class mem816 : + public wdc816 +{ +public: + mem816(Addr memMask, Addr ramSize, const Byte *pROM); + mem816(Addr memMask, Addr ramSize, Byte *pRAM, const Byte *pROM); + ~mem816(); + + INLINE Byte getByte(Addr ea) + { + if ((ea &= memMask) < ramSize) + return (pRAM[ea]); + + return (pROM[ea - ramSize]); + } + + INLINE Word getWord(Addr ea) + { + return (join(getByte(ea + 0), getByte(ea + 1))); + } + + INLINE Addr getAddr(Addr ea) + { + return (join(getByte(ea + 0), getWord(ea + 0))); + } + + INLINE void setByte(Addr ea, Byte data) + { + if ((ea &= memMask) < ramSize) + pRAM[ea] = data; + } + + INLINE void setWord(Addr ea, Word data) + { + setByte(ea + 0, lo(data)); + setByte(ea + 1, hi(data)); + } + +private: + const Addr memMask; + const Addr ramSize; + + Byte *pRAM; + const Byte *pROM; +}; +#endif diff --git a/program.cc b/program.cc new file mode 100644 index 0000000..8ef756c --- /dev/null +++ b/program.cc @@ -0,0 +1,103 @@ + +#include +#include +#include + +using namespace std; + +#include "mem816.h" +#include "emu816.h" + +//============================================================================== +// Memory Definitions and Access +//------------------------------------------------------------------------------ + +#define RAM_SIZE (384 * 1024) +#define ROM_SIZE (128 * 1024L) +#define MEM_MASK (512 * 1024L - 1) + +// The ROM area 128K +const wdc816::Byte ROM[ROM_SIZE] = +{ + 0x00, 0x00, 0x00, +}; + +mem816 mem(MEM_MASK, RAM_SIZE, ROM); +emu816 emu(mem); + +//============================================================================== +//------------------------------------------------------------------------------ + +void setup() +{ + emu.reset(); +} + +void loop() +{ + emu.step(); +} + +//============================================================================== +//------------------------------------------------------------------------------ + +unsigned int toNybble(char ch) +{ + if ((ch >= '0') && (ch <= '9')) return (ch - '0'); + if ((ch >= 'A') && (ch <= 'F')) return (ch - 'A' + 10); + if ((ch >= 'a') && (ch <= 'f')) return (ch - 'a' + 10); + return (0); +} + +unsigned int toByte(string &str, int &offset) +{ + unsigned int h = toNybble(str[offset++]) << 4; + unsigned int l = toNybble(str[offset++]); + + return (h | l); +} + +unsigned long toAddr(string &str, int &offset) +{ + unsigned long h = toByte(str, offset) << 16; + unsigned long m = toByte(str, offset) << 8; + unsigned long l = toByte(str, offset); + + return (h | m | l); +} + +void load(char *filename) +{ + ifstream file(filename); + string line; + + if (file.is_open()) { + cout << ">> Loading S28: " << filename << endl; + + while (!file.eof()) { + file >> line; + if ((line[0] == 'S') && (line[1] == '2')) { + int offset = 2; + unsigned int count = toByte(line, offset); + unsigned long addr = toAddr(line, offset); + count -= 4; + while (count-- > 0) { + mem.setByte(addr++, toByte(line, offset)); + } + } + } + } + + file.close(); +} + +int main(int argc, char **argv) +{ + for (int index = 1; index < argc;) + load(argv[index++]); + + setup(); + for (;;) loop(); + + return(0); +} diff --git a/wdc816.cc b/wdc816.cc new file mode 100644 index 0000000..e306c10 --- /dev/null +++ b/wdc816.cc @@ -0,0 +1,20 @@ +#include "wdc816.h" + +wdc816::wdc816() +{ } + +wdc816::~wdc816() +{ } + +char *wdc816::toHex(unsigned long value, unsigned int digits) +{ + static char buffer[16]; + unsigned int offset = sizeof(buffer);; + + buffer[--offset] = 0; + while (digits-- > 0) { + buffer[--offset] = "0123456789ABCDEF"[value & 0xf]; + value >>= 4; + } + return (&(buffer[offset])); +} diff --git a/wdc816.h b/wdc816.h new file mode 100644 index 0000000..8cf963a --- /dev/null +++ b/wdc816.h @@ -0,0 +1,63 @@ +#ifndef WDC816 +#define WDC816 + +//#define CHIPKIT + +#ifdef CHIPKIT +#define INLINE inline +#else +#define INLINE inline +#endif + +class wdc816 +{ +public: + // Common types for memory and register sizes + typedef unsigned char Bit; + typedef unsigned char Byte; + typedef unsigned short Word; + typedef unsigned long Addr; + + wdc816 (); + ~wdc816(); + + // Convert a value to a hex string. + static char *toHex(unsigned long value, unsigned int digits); + + // Return the low byte of a word + INLINE static Byte lo(Word value) + { + return ((Byte) value); + } + + // Return the high byte of a word + INLINE static Byte hi(Word value) + { + return (lo(value >> 8)); + } + + // Convert the bank number into a address + INLINE static Addr bank(Byte b) + { + return (b << 16); + } + + // Combine two bytes into a word + INLINE static Word join(Byte l, Byte h) + { + return (l | (h << 8)); + } + + // Combine a bank and an word into an address + INLINE static Addr join(Byte b, Word a) + { + return (bank(b) | a); + } + + // Swap the high and low bytes of a word + INLINE static Word swap(Word value) + { + return ((value >> 8) | (value << 8)); + } +}; +#endif