235 lines
5.2 KiB
C
235 lines
5.2 KiB
C
#include <assert.h>
|
|
|
|
#include "cpu.h"
|
|
#include "opcodes.h"
|
|
|
|
extern void reset6502(void);
|
|
extern void step6502(void);
|
|
|
|
uint8_t cpu_memory[65536] = {
|
|
[0xfffc] = 0x0,
|
|
[0xfffd] = 0x0,
|
|
};
|
|
|
|
uint8_t read6502(uint16_t address)
|
|
{
|
|
return cpu_memory[address];
|
|
}
|
|
|
|
void write6502(uint16_t address, uint8_t value)
|
|
{
|
|
cpu_memory[address] = value;
|
|
}
|
|
|
|
extern uint16_t pc;
|
|
extern uint8_t sp, a, x, y, status;
|
|
|
|
cpu_history_t cpu_history[65536] = { 0 };
|
|
int cpu_history_len;
|
|
int cpu_history_ix;
|
|
|
|
void cpu_get_state(cpu_state_t * state) {
|
|
*state = (cpu_state_t){
|
|
.a = a,
|
|
.y = y,
|
|
.x = x,
|
|
.pc = pc,
|
|
.sp = sp,
|
|
.status = status,
|
|
};
|
|
}
|
|
|
|
static inline void update_history(void)
|
|
{
|
|
instruction_t instruction = decode_ins[cpu_memory[pc]];
|
|
addressing_mode_t addressing_mode = addressing_modes[instruction.mode];
|
|
|
|
if (cpu_history_len < 65536)
|
|
cpu_history_len++;
|
|
|
|
cpu_history[cpu_history_ix] = (cpu_history_t){
|
|
.state = (cpu_state_t){
|
|
.a = a,
|
|
.y = y,
|
|
.x = x,
|
|
.pc = pc,
|
|
.sp = sp,
|
|
.status = status,
|
|
},
|
|
.pc_mem = { cpu_memory[pc], cpu_memory[pc+1], cpu_memory[pc+2] },
|
|
.value = (addressing_mode.func)(pc),
|
|
};
|
|
|
|
cpu_history_ix = (cpu_history_ix + 1) & 0xffff;
|
|
}
|
|
|
|
void cpu_reset(void)
|
|
{
|
|
reset6502();
|
|
|
|
cpu_history_len = 0;
|
|
cpu_history_ix = 0;
|
|
}
|
|
|
|
void cpu_step(void)
|
|
{
|
|
update_history();
|
|
step6502();
|
|
}
|
|
|
|
static uint8_t * mem = cpu_memory;
|
|
|
|
uint16_t absolute(uint16_t _pc)
|
|
{
|
|
uint16_t effective = ((uint16_t)mem[_pc + 2] << 8) | ((uint16_t)mem[_pc + 1] << 0);
|
|
|
|
return effective;
|
|
}
|
|
|
|
uint16_t absolute_indexed_indirect(uint16_t _pc)
|
|
{
|
|
uint16_t effective = (((uint16_t)mem[_pc + 2] << 8) | ((uint16_t)mem[_pc + 1] << 0))
|
|
+ x;
|
|
|
|
uint16_t indirect = ((uint16_t)mem[effective + 1] << 8)
|
|
| ((uint16_t)mem[effective + 0] << 0);
|
|
|
|
return indirect;
|
|
}
|
|
|
|
uint16_t absolute_indexed_with_x(uint16_t _pc)
|
|
{
|
|
uint16_t effective = (((uint16_t)mem[_pc + 2] << 8) | ((uint16_t)mem[_pc + 1] << 0))
|
|
+ x;
|
|
|
|
return effective;
|
|
}
|
|
|
|
uint16_t absolute_indexed_with_y(uint16_t _pc)
|
|
{
|
|
uint16_t effective = (((uint16_t)mem[_pc + 2] << 8) | ((uint16_t)mem[_pc + 1] << 0))
|
|
+ y;
|
|
|
|
return effective;
|
|
}
|
|
|
|
uint16_t absolute_indirect(uint16_t _pc)
|
|
{
|
|
uint16_t effective = (((uint16_t)mem[_pc + 2] << 8) | ((uint16_t)mem[_pc + 1] << 0))
|
|
+ y;
|
|
|
|
uint16_t indirect = ((uint16_t)mem[effective + 1] << 8)
|
|
| ((uint16_t)mem[effective + 0] << 0);
|
|
|
|
return indirect;
|
|
}
|
|
|
|
uint16_t accumulator(uint16_t _pc)
|
|
{
|
|
return a;
|
|
}
|
|
|
|
uint16_t immediate(uint16_t _pc)
|
|
{
|
|
return (uint8_t)mem[_pc + 1];
|
|
}
|
|
|
|
uint16_t implied(uint16_t _pc)
|
|
{
|
|
return 0; // ???
|
|
}
|
|
|
|
uint16_t program_counter_relative(uint16_t _pc)
|
|
{
|
|
uint16_t effective = _pc + 2 + ((int8_t)mem[_pc + 1]);
|
|
|
|
return effective;
|
|
}
|
|
|
|
uint16_t stack(uint16_t _pc)
|
|
{
|
|
uint16_t effective = (0x01 << 8) | (sp << 0);
|
|
|
|
return effective;
|
|
}
|
|
|
|
uint16_t zero_page(uint16_t _pc)
|
|
{
|
|
uint16_t effective = (0x00 << 8) | ((uint16_t)mem[_pc + 1] << 0);
|
|
|
|
return effective;
|
|
}
|
|
|
|
uint16_t zero_page_indexed_indirect(uint16_t _pc)
|
|
{
|
|
uint8_t base = x + ((uint8_t)mem[_pc + 1] << 0);
|
|
|
|
uint16_t effective = (0x00 << 8) | base;
|
|
|
|
uint16_t indirect = ((uint16_t)mem[effective + 1] << 8)
|
|
| ((uint16_t)mem[effective + 0] << 0);
|
|
|
|
return indirect;
|
|
}
|
|
|
|
uint16_t zero_page_indexed_with_x(uint16_t _pc)
|
|
{
|
|
uint8_t base = x + ((uint8_t)mem[_pc + 1] << 0);
|
|
|
|
uint16_t effective = (0x00 << 8) | base;
|
|
|
|
return effective;
|
|
}
|
|
|
|
uint16_t zero_page_indexed_with_y(uint16_t _pc)
|
|
{
|
|
uint8_t base = y + ((uint8_t)mem[_pc + 1] << 0);
|
|
|
|
uint16_t effective = (0x00 << 8) | base;
|
|
|
|
return effective;
|
|
}
|
|
|
|
uint16_t zero_page_indirect(uint16_t _pc)
|
|
{
|
|
uint8_t base = ((uint8_t)mem[_pc + 1] << 0);
|
|
|
|
uint16_t effective = (0x00 << 8) | base;
|
|
|
|
uint16_t indirect = ((uint16_t)mem[effective + 1] << 8)
|
|
| ((uint16_t)mem[effective + 0] << 0);
|
|
|
|
return indirect;
|
|
}
|
|
|
|
uint16_t zero_page_indirect_indexed_with_y(uint16_t _pc)
|
|
{
|
|
uint8_t base = ((uint8_t)mem[_pc + 1] << 0);
|
|
|
|
uint16_t indirect = ((uint16_t)mem[base + 1] << 8)
|
|
| ((uint16_t)mem[base + 0] << 0);
|
|
|
|
uint16_t effective = indirect + y;
|
|
|
|
return effective;
|
|
}
|
|
|
|
addressing_mode_t addressing_modes[16] = {
|
|
[A] = { .alen = 2, .olen = 2, .func = absolute },
|
|
[AII] = { .alen = 2, .olen = 2, .func = absolute_indexed_indirect },
|
|
[AIX] = { .alen = 2, .olen = 2, .func = absolute_indexed_with_x },
|
|
[AIY] = { .alen = 2, .olen = 2, .func = absolute_indexed_with_y },
|
|
[AI] = { .alen = 2, .olen = 2, .func = absolute_indirect },
|
|
[ACC] = { .alen = 0, .olen = 1, .func = accumulator },
|
|
[IMM] = { .alen = 1, .olen = 1, .func = immediate },
|
|
[I] = { .alen = 0, .olen = 0, .func = implied },
|
|
[R] = { .alen = 1, .olen = 2, .func = program_counter_relative },
|
|
[S] = { .alen = 0, .olen = 2, .func = stack },
|
|
[ZP] = { .alen = 1, .olen = 2, .func = zero_page },
|
|
[ZPII] = { .alen = 1, .olen = 2, .func = zero_page_indexed_indirect },
|
|
[ZPX] = { .alen = 1, .olen = 2, .func = zero_page_indexed_with_x },
|
|
[ZPY] = { .alen = 1, .olen = 2, .func = zero_page_indexed_with_y },
|
|
[ZPI] = { .alen = 1, .olen = 2, .func = zero_page_indirect },
|
|
[ZPIY] = { .alen = 1, .olen = 2, .func = zero_page_indirect_indexed_with_y },
|
|
};
|