#include <stdlib.h>
+#include <string.h>
#include "cpu_65c02.h"
#define NMI_VECTOR 0xfffa
// gcc specific
#define INLINE __attribute__((always_inline))
-// convenient register access
-#define A (self->regs[CPU_65C02_REG_A])
-#define X (self->regs[CPU_65C02_REG_X])
-#define Y (self->regs[CPU_65C02_REG_Y])
-#define S (self->regs[CPU_65C02_REG_S])
-#define P (self->regs[CPU_65C02_REG_P])
-#define PC (self->pc)
+// convenient byte register access
+#define A (self->regs.b[CPU_65C02_REG_A])
+#define X (self->regs.b[CPU_65C02_REG_X])
+#define Y (self->regs.b[CPU_65C02_REG_Y])
+#define P (self->regs.b[CPU_65C02_REG_P])
+#define S (self->regs.b[CPU_65C02_REG_S])
+
+// convenient word register access
+#define SP (self->regs.w[CPU_65C02_REG_SP >> 1])
+#define PC (self->regs.w[CPU_65C02_REG_PC >> 1])
// convenient flags bit access
-#define FLAG_C (1 << CPU_65C02_BIT_C)
-#define FLAG_Z (1 << CPU_65C02_BIT_Z)
-#define FLAG_I (1 << CPU_65C02_BIT_I)
-#define FLAG_D (1 << CPU_65C02_BIT_D)
-#define FLAG_V (1 << CPU_65C02_BIT_V)
-#define FLAG_N (1 << CPU_65C02_BIT_N)
+#define FLAG_C (1 << CPU_65C02_REG_P_BIT_C)
+#define FLAG_Z (1 << CPU_65C02_REG_P_BIT_Z)
+#define FLAG_I (1 << CPU_65C02_REG_P_BIT_I)
+#define FLAG_D (1 << CPU_65C02_REG_P_BIT_D)
+#define FLAG_V (1 << CPU_65C02_REG_P_BIT_V)
+#define FLAG_N (1 << CPU_65C02_REG_P_BIT_N)
// read, write, fetch, push, pop byte/word for instruction decode/execute
// these routines automatically apply cycle count of 1 (byte) or 2 (word)
#define EA_A (CPU_65C02_REG_A - CPU_65C02_N_REGS)
#define EA_X (CPU_65C02_REG_X - CPU_65C02_N_REGS)
#define EA_Y (CPU_65C02_REG_Y - CPU_65C02_N_REGS)
-#define EA_S (CPU_65C02_REG_S - CPU_65C02_N_REGS)
#define EA_P (CPU_65C02_REG_P - CPU_65C02_N_REGS)
+#define EA_S (CPU_65C02_REG_S - CPU_65C02_N_REGS)
// lvalue modes
// effective address calculations that involve indexing require their
#define BMI(lvalue) cpu_65c02_bs(self, FLAG_N, (lvalue))
#define BNE(lvalue) cpu_65c02_bc(self, FLAG_Z, (lvalue))
#define BPL(lvalue) cpu_65c02_bc(self, FLAG_N, (lvalue))
-#define BRA(lvalue) cpu_65c02_jmp(self, (lvalue))
+#define BRA(lvalue) cpu_65c02_bc(self, 0, (lvalue))
#define BRK() cpu_65c02_brk(self)
#define BVC(lvalue) cpu_65c02_bc(self, FLAG_V, (lvalue))
#define BVS(lvalue) cpu_65c02_bs(self, FLAG_V, (lvalue))
#define TYA() cpu_65c02_ld(self, EA_A, Y)
#define WAI() cpu_65c02_wai(self)
+// initialization
+void cpu_65c02_init(
+ struct cpu_65c02 *self,
+ int pc,
+ int (*read_byte)(int addr),
+ void (*write_byte)(int addr, int data)
+) {
+ memset(self, 0, sizeof(struct cpu_65c02));
+ self->regs.w[CPU_65C02_REG_PC >> 1] = pc;
+ self->regs.b[CPU_65C02_REG_P] = 0x30;
+ self->regs.w[CPU_65C02_REG_SP >> 1] = 0x1ff;
+ self->read_byte = read_byte;
+ self->write_byte = write_byte;
+}
+
// memory (or internal register memory) access
INLINE int cpu_65c02_rb(struct cpu_65c02 *self, int addr) {
if (addr < 0)
- return self->regs[CPU_65C02_N_REGS + addr];
+ return self->regs.b[CPU_65C02_N_REGS + addr];
self->cycles += 1;
- return self->read_byte(addr);
+ return self->read_byte(addr & 0xffff);
}
INLINE int cpu_65c02_rw(struct cpu_65c02 *self, int addr) {
int data = RB(addr);
- return data | (RB((addr + 1) & 0xffff) << 8);
+ return data | (RB(addr + 1) << 8);
}
INLINE int cpu_65c02_rw_zpg(struct cpu_65c02 *self, int addr) {
- int data = RB(addr);
+ int data = RB(addr & 0xff);
return data | (RB((addr + 1) & 0xff) << 8);
}
INLINE void cpu_65c02_wb(struct cpu_65c02 *self, int addr, int data) {
self->cycles += 1;
if (addr < 0)
- self->regs[CPU_65C02_N_REGS + addr] = data;
+ self->regs.b[CPU_65C02_N_REGS + addr] = data;
else
self->write_byte(addr, data);
}
INLINE void cpu_65c02_ww(struct cpu_65c02 *self, int addr, int data) {
WB(addr, data & 0xff);
- WB((addr + 1) & 0xffff, data >> 8);
+ WB(addr + 1, data >> 8);
}
INLINE int cpu_65c02_fb(struct cpu_65c02 *self) {
- int data = RB(PC);
- PC = (PC + 1) & 0xffff;
+ int data = RB(PC++);
return data;
}
}
INLINE void cpu_65c02_phb(struct cpu_65c02 *self, int data) {
- WB(S | 0x100, data);
- S = (S - 1) & 0xff;
+ WB(SP, data);
+ --S;
}
INLINE void cpu_65c02_phw(struct cpu_65c02 *self, int data) {
}
INLINE int cpu_65c02_plb(struct cpu_65c02 *self) {
- S = (S + 1) & 0xff;
- return RB(S | 0x100);
+ ++S;
+ return RB(SP);
}
INLINE int cpu_65c02_plw(struct cpu_65c02 *self) {
INLINE int cpu_65c02_ea_rel(struct cpu_65c02 *self) {
int offset = FB();
- offset -= (offset << 1) & 0x100; // sign extend
- int addr = PC;
- self->cycles += ((addr & 0xff) + (offset & 0xff)) >> 8;
- return addr + offset;
+ return offset - ((offset << 1) & 0x100); // sign extend
}
INLINE int cpu_65c02_ea_zpg(struct cpu_65c02 *self) {
}
INLINE void cpu_65c02_bbr(struct cpu_65c02 *self, int rvalue, int lvalue) {
- if (rvalue == 0)
- PC = lvalue;
+ if (rvalue == 0) {
+ self->cycles += ((PC & 0xff) + (lvalue & 0xff)) >> 8;
+ PC = (PC + lvalue) & 0xffff;
+ }
}
INLINE void cpu_65c02_bbs(struct cpu_65c02 *self, int rvalue, int lvalue) {
- if (rvalue)
- PC = lvalue;
+ if (rvalue) {
+ self->cycles += ((PC & 0xff) + (lvalue & 0xff)) >> 8;
+ PC = (PC + lvalue) & 0xffff;
+ }
}
INLINE void cpu_65c02_bc(struct cpu_65c02 *self, int flag, int lvalue) {
- if ((P & flag) == 0)
- PC = lvalue;
+ if ((P & flag) == 0) {
+ self->cycles += ((PC & 0xff) + (lvalue & 0xff)) >> 8;
+ PC = (PC + lvalue) & 0xffff;
+ }
}
INLINE void cpu_65c02_bs(struct cpu_65c02 *self, int flag, int lvalue) {
- if (P & flag)
- PC = lvalue;
+ if (P & flag) {
+ self->cycles += ((PC & 0xff) + (lvalue & 0xff)) >> 8;
+ PC = (PC + lvalue) & 0xffff;
+ }
}
INLINE void cpu_65c02_bit(struct cpu_65c02 *self, int rvalue) {
#define CPU_65C02_REG_A 0
#define CPU_65C02_REG_X 1
#define CPU_65C02_REG_Y 2
-#define CPU_65C02_REG_S 3
-#define CPU_65C02_REG_P 4
-#define CPU_65C02_N_REGS 5
+#define CPU_65C02_REG_P 3
+#define CPU_65C02_REG_SP 4
+#define CPU_65C02_REG_S 4
+#define CPU_65C02_REG_PC 6
+#define CPU_65C02_N_REGS 8
// bits within REG_P
-#define CPU_65C02_BIT_C 0
-#define CPU_65C02_BIT_Z 1
-#define CPU_65C02_BIT_I 2
-#define CPU_65C02_BIT_D 3
-#define CPU_65C02_BIT_V 6
-#define CPU_65C02_BIT_N 7
+#define CPU_65C02_REG_P_BIT_C 0
+#define CPU_65C02_REG_P_BIT_Z 1
+#define CPU_65C02_REG_P_BIT_I 2
+#define CPU_65C02_REG_P_BIT_D 3
+#define CPU_65C02_REG_P_BIT_V 6
+#define CPU_65C02_REG_P_BIT_N 7
struct cpu_65c02 {
- uint8_t regs[CPU_65C02_N_REGS];
- uint16_t pc;
int cycles;
int (*read_byte)(int addr);
void (*write_byte)(int addr, int data);
+ union {
+ uint8_t b[CPU_65C02_N_REGS];
+ uint16_t w[CPU_65C02_N_REGS >> 1];
+ } regs;
};
+void cpu_65c02_init(
+ struct cpu_65c02 *self,
+ int pc,
+ int (*read_byte)(int addr),
+ void (*write_byte)(int addr, int data)
+);
void cpu_65c02_execute(struct cpu_65c02 *self);
#endif
mpu = py65.devices.mpu65c02.MPU(mem, 0)
disassembler = py65.disassembler.Disassembler(mpu)
-rvalue_ops = {
+rvalue_opcodes = {
'adc',
'and',
'bit',
if instr[0] == '???':
instr[0] = 'ill' # illegal opcode
if len(instr) >= 2:
- if instr[0] in rvalue_ops:
+ if instr[0] in rvalue_opcodes:
instr[1] = rvalue_modes[instr[1]]
else:
instr[1] = lvalue_modes[instr[1]]
while (true) {
#if REG_TRACE
printf(
- "pc=%04x a=%02x x=%02x y=%02x s=%02x p=%02x c=%d z=%d i=%d d=%d v=%d n=%d\n",
+ "pc=%04x a=%02x x=%02x y=%02x p=%02x s=%02x c=%d z=%d i=%d d=%d v=%d n=%d\n",
vrEmu6502GetPC(cpu),
vrEmu6502GetAcc(cpu),
vrEmu6502GetX(cpu),
vrEmu6502GetY(cpu),
- vrEmu6502GetStackPointer(cpu),
vrEmu6502GetStatus(cpu) | 0x30,
+ vrEmu6502GetStackPointer(cpu),
vrEmu6502GetStatus(cpu) & 1,
(vrEmu6502GetStatus(cpu) >> 1) & 1,
(vrEmu6502GetStatus(cpu) >> 2) & 1,
}
#else
struct cpu_65c02 cpu;
- memset(&cpu, 0, sizeof(struct cpu_65c02));
- cpu.pc = entry_point;
- cpu.regs[CPU_65C02_REG_S] = 0xff;
- cpu.regs[CPU_65C02_REG_P] = 0x30;
- cpu.read_byte = read_byte;
- cpu.write_byte = write_byte;
+ cpu_65c02_init(&cpu, entry_point, read_byte, write_byte);
while (true) {
#if REG_TRACE
printf(
- "pc=%04x a=%02x x=%02x y=%02x s=%02x p=%02x c=%d z=%d i=%d d=%d v=%d n=%d\n",
- cpu.pc,
- cpu.regs[CPU_65C02_REG_A],
- cpu.regs[CPU_65C02_REG_X],
- cpu.regs[CPU_65C02_REG_Y],
- cpu.regs[CPU_65C02_REG_S],
- cpu.regs[CPU_65C02_REG_P],
- (cpu.regs[CPU_65C02_REG_P] >> CPU_65C02_BIT_C) & 1,
- (cpu.regs[CPU_65C02_REG_P] >> CPU_65C02_BIT_Z) & 1,
- (cpu.regs[CPU_65C02_REG_P] >> CPU_65C02_BIT_I) & 1,
- (cpu.regs[CPU_65C02_REG_P] >> CPU_65C02_BIT_D) & 1,
- (cpu.regs[CPU_65C02_REG_P] >> CPU_65C02_BIT_V) & 1,
- (cpu.regs[CPU_65C02_REG_P] >> CPU_65C02_BIT_N) & 1
+ "pc=%04x a=%02x x=%02x y=%02x p=%02x s=%02x c=%d z=%d i=%d d=%d v=%d n=%d\n",
+ cpu.regs.w[CPU_65C02_REG_PC >> 1],
+ cpu.regs.b[CPU_65C02_REG_A],
+ cpu.regs.b[CPU_65C02_REG_X],
+ cpu.regs.b[CPU_65C02_REG_Y],
+ cpu.regs.b[CPU_65C02_REG_P],
+ cpu.regs.b[CPU_65C02_REG_S],
+ (cpu.regs.b[CPU_65C02_REG_P] >> CPU_65C02_REG_P_BIT_C) & 1,
+ (cpu.regs.b[CPU_65C02_REG_P] >> CPU_65C02_REG_P_BIT_Z) & 1,
+ (cpu.regs.b[CPU_65C02_REG_P] >> CPU_65C02_REG_P_BIT_I) & 1,
+ (cpu.regs.b[CPU_65C02_REG_P] >> CPU_65C02_REG_P_BIT_D) & 1,
+ (cpu.regs.b[CPU_65C02_REG_P] >> CPU_65C02_REG_P_BIT_V) & 1,
+ (cpu.regs.b[CPU_65C02_REG_P] >> CPU_65C02_REG_P_BIT_N) & 1
);
#endif
- int pc = cpu.pc;
+ int pc = cpu.regs.w[CPU_65C02_REG_PC >> 1];
cpu_65c02_execute(&cpu);
- if (pc == cpu.pc) {
+ if (pc == cpu.regs.w[CPU_65C02_REG_PC >> 1]) {
printf("hung at %04x\n", pc);
break;
}
return de;
}
-int mem_read_byte(int addr) {
+int read_byte(int addr) {
#if MEM_TRACE
int data = mem[addr];
printf("mem_addr=%04x rd=%02x\n", addr, data);
#endif
}
-void mem_write_byte(int addr, int data) {
+void write_byte(int addr, int data) {
#if MEM_TRACE
printf("mem_addr=%04x wr=%02x\n", addr, data);
#endif
mem[addr] = data;
}
-int io_read_byte(int addr) {
+int in_byte(int addr) {
#if IO_TRACE
int data = io_read[addr];
printf("io_addr=%04x rd=%02x\n", addr, data);
#endif
}
-void io_write_byte(int addr, int data) {
+void out_byte(int addr, int data) {
#if IO_TRACE
printf("io_addr=%04x wr=%02x\n", addr, data);
#endif
#if ALT_BACKEND
uint8_t rb(void *userdata, uint16_t addr) {
- return mem_read_byte(addr);
+ return read_byte(addr);
}
void wb(void *userdata, uint16_t addr, uint8_t val) {
- mem_write_byte(addr, val);
+ write_byte(addr, val);
}
uint8_t in(z80 *const z, uint8_t port) {
- return io_read_byte(port);
+ return in_byte(port);
}
void out(z80 *const z, uint8_t port, uint8_t val) {
- io_write_byte(port, val);
+ out_byte(port, val);
}
#endif
int entry_point = load_ihx(argv[1]);
mem[5] = 0xc9; // ret, for bdos emulation
+ mem[6] = 0xff; // memory top, lo byte
+ mem[7] = 0xff; // memory top, hi byte
#if ALT_BACKEND
z80 cpu;
while (true) {
#if REG_TRACE
printf(
- "pc=%04x af=%04x bc=%04x de=%04x hl=%04x sp=%04x ix=%04x iy=%04x cf=%d nf=%d pf=%d hf=%d zf=%d sf=%d\n",
+ "pc=%04x af=%04x bc=%04x de=%04x hl=%04x sp=%04x ix=%04x iy=%04x cf=%d nf=%d pv=%d hf=%d zf=%d sf=%d\n",
cpu.pc,
cpu.cf |
(cpu.nf << 1) |
struct cpu_z80 cpu;
memset(&cpu, 0, sizeof(struct cpu_z80));
cpu.pc = entry_point;
- cpu.regs[CPU_Z80_REG_S] = 0xff;
- cpu.regs[CPU_Z80_REG_P] = 0x30;
- cpu.mem_read_byte = mem_read_byte;
- cpu.mem_write_byte = mem_write_byte;
+ cpu.read_byte = read_byte;
+ cpu.write_byte = write_byte;
+ cpu.in_byte = in_byte;
+ cpu.out_byte = write_byte;
while (true) {
#if REG_TRACE
printf(
- "pc=%04x a=%02x x=%02x y=%02x s=%02x p=%02x c=%d z=%d i=%d d=%d v=%d n=%d\n",
+ "pc=%04x af=%04x bc=%04x de=%04x hl=%04x sp=%04x ix=%04x iy=%04x cf=%d nf=%d pv=%d hf=%d zf=%d sf=%d\n",
cpu.pc,
- cpu.regs[CPU_Z80_REG_A],
- cpu.regs[CPU_Z80_REG_X],
- cpu.regs[CPU_Z80_REG_Y],
- cpu.regs[CPU_Z80_REG_S],
- cpu.regs[CPU_Z80_REG_P],
- (cpu.regs[CPU_Z80_REG_P] >> CPU_Z80_BIT_C) & 1,
- (cpu.regs[CPU_Z80_REG_P] >> CPU_Z80_BIT_Z) & 1,
- (cpu.regs[CPU_Z80_REG_P] >> CPU_Z80_BIT_I) & 1,
- (cpu.regs[CPU_Z80_REG_P] >> CPU_Z80_BIT_D) & 1,
- (cpu.regs[CPU_Z80_REG_P] >> CPU_Z80_BIT_V) & 1,
- (cpu.regs[CPU_Z80_REG_P] >> CPU_Z80_BIT_N) & 1
+ cpu.regs[CPU_Z80_REG_AF] | (cpu.regs[CPU_REG_AF + 1] << 8),
+ cpu.regs[CPU_Z80_REG_BC] | (cpu.regs[CPU_REG_BC + 1] << 8),
+ cpu.regs[CPU_Z80_REG_DE] | (cpu.regs[CPU_REG_DE + 1] << 8),
+ cpu.regs[CPU_Z80_REG_HL] | (cpu.regs[CPU_REG_HL + 1] << 8),
+ cpu.regs[CPU_Z80_REG_SP] | (cpu.regs[CPU_REG_SP + 1] << 8),
+ cpu.regs[CPU_Z80_REG_IX] | (cpu.regs[CPU_REG_IX + 1] << 8),
+ cpu.regs[CPU_Z80_REG_IY] | (cpu.regs[CPU_REG_IY + 1] << 8),
+ (cpu.regs[CPU_Z80_REG_F] >> CPU_Z80_BIT_CF) & 1,
+ (cpu.regs[CPU_Z80_REG_F] >> CPU_Z80_BIT_NF) & 1,
+ (cpu.regs[CPU_Z80_REG_F] >> CPU_Z80_BIT_PV) & 1,
+ (cpu.regs[CPU_Z80_REG_F] >> CPU_Z80_BIT_HF) & 1,
+ (cpu.regs[CPU_Z80_REG_F] >> CPU_Z80_BIT_ZF) & 1,
+ (cpu.regs[CPU_Z80_REG_F] >> CPU_Z80_BIT_SF) & 1
);
#endif
- int pc = cpu.pc;
- cpu_z80_execute(&cpu);
- if (pc == cpu.pc) {
- printf("hung at %04x\n", pc);
+ if (cpu.pc == 0) {
+ putchar('\n');
break;
}
+ if (cpu.pc == 5) {
+ cpu.regs.w[CPU_Z80_REG_DE >> 1] = bdos(
+ cpu.regs.b[CPU_Z80_REG_C],
+ cpu.regs.w[CPU_Z80_REG_DE >> 1]
+ );
+ }
+ cpu_z80_execute(&cpu);
}
#endif