yemu/src/6502/6502.c

230 lines
4.8 KiB
C

#include <yemu/6502.h>
#include <stdio.h>
#include <stdlib.h>
struct CPU cpu;
struct MEMORY mem;
void memory_init () {
for (int i = 0; i < MAX_MEMORY; i++){
mem.memory[i] = 0;
}
}
void reset () {
cpu.PC = 0x0000; // FIXME //0xFFFC;
cpu.SP = 0x0000; //FIXME
cpu.A = cpu.X = cpu.Y = 0;
cpu.C = cpu.Z = cpu.I = cpu.D = cpu.B = cpu.V = cpu.N = 0;
memory_init(mem);
}
void dump_cpu(struct CPU cpu) {
printf("PC: %04X\n", cpu.PC);
printf("SP: %04X\n", cpu.SP);
printf("A: %04X\n", cpu.A);
printf("X: %04X\n", cpu.X);
printf("Y: %04X\n", cpu.Y);
printf("Flags: C: %X, Z: %X, I: %X, ", cpu.C, cpu.Z, cpu.I);
printf("D: %X, V: %X, N: %X\n", cpu.D, cpu.V, cpu.N);
}
byte fetch_byte() {
byte data = mem.memory[cpu.PC];
cpu.PC++;
return data;
}
word fetch_word() {
word data = mem.memory[cpu.PC];
cpu.PC++;
data |= (mem.memory[cpu.PC] << 8);
cpu.PC++;
return data;
}
byte read_byte(word addr) {
byte data = mem.memory[addr];
cpu.PC++;
return data;
}
word read_word(word addr) {
word data = mem.memory[addr];
data |= (mem.memory[addr+1] << 8);
cpu.PC++;
cpu.PC++;
return data;
}
void write_byte(byte addr, byte value) {
mem.memory[addr] = value;
}
void write_word(byte addr, word value) {
mem.memory[addr] = value & 0xFF;
mem.memory[addr+1] = (value >> 8);
}
void execute() {
while (1) {
byte instruction = fetch_byte();
byte value;
byte zero_page_addr;
byte zero_page_x_addr;
byte zero_page_y_addr;
word jsr_addr;
switch(instruction) {
case INS_LDA_IM:
value = fetch_byte();
cpu.A = value;
cpu.Z = (cpu.A == 0);
cpu.N = (cpu.A & 0x40) > 0; // 0x40 means 0b1000000 (fixed to not receive a warning from compiler)
break;
case INS_LDA_ZP:
zero_page_addr = fetch_byte();
cpu.A = read_byte(zero_page_addr);
cpu.Z = (cpu.A == 0);
cpu.N = (cpu.A & 0x40) > 0;
break;
case INS_LDA_ZPX:
zero_page_x_addr = cpu.X + fetch_byte();
cpu.A = read_byte(zero_page_x_addr);
cpu.Z = (cpu.A == 0);
cpu.N = (cpu.A & 0x40) > 0;
break;
case INS_LDX_IM:
value = fetch_byte();
cpu.X = value;
cpu.Z = (cpu.X == 0);
cpu.N = (cpu.X & 0x40) > 0;
break;
case INS_LDX_ZP:
zero_page_addr = fetch_byte();
cpu.X = read_byte(zero_page_addr);
cpu.Z = (cpu.X == 0);
cpu.N = (cpu.X & 0x40) > 0;
break;
case INS_LDX_ZPY:
zero_page_y_addr = cpu.Y + fetch_byte();
cpu.X = read_byte(zero_page_y_addr);
cpu.Z = (cpu.X == 0);
cpu.N = (cpu.X & 0x40) > 0;
break;
case INS_LDY_IM:
value = fetch_byte();
cpu.Y = value;
cpu.Z = (cpu.Y == 0);
cpu.N = (cpu.Y & 0x40) > 0;
break;
case INS_LDY_ZP:
zero_page_addr = fetch_byte();
cpu.Y = read_byte(zero_page_addr);
cpu.Z = (cpu.Y == 0);
cpu.N = (cpu.Y & 0x40) > 0;
break;
case INS_LDY_ZPX:
zero_page_x_addr = cpu.Y + fetch_byte();
cpu.Y = read_byte(zero_page_x_addr);
cpu.Z = (cpu.Y == 0);
cpu.N = (cpu.Y & 0x40) > 0;
break;
case INS_TAX:
cpu.X = cpu.A;
cpu.Z = (cpu.X == 0);
cpu.N = (cpu.X & 0x40) > 0;
cpu.PC++;
break;
case INS_TAY:
cpu.Y = cpu.A;
cpu.Z = (cpu.Y == 0);
cpu.N = (cpu.Y & 0x40) > 0;
cpu.PC++;
break;
case INS_TSX:
cpu.X = cpu.SP;
cpu.Z = (cpu.X == 0);
cpu.N = (cpu.X & 0x40) > 0;
cpu.PC++;
break;
case INS_TXA:
cpu.A = cpu.X;
cpu.Z = (cpu.A == 0);
cpu.N = (cpu.A & 0x40) > 0;
cpu.PC++;
break;
case INS_TXS:
cpu.SP = cpu.X;
cpu.PC++;
break;
case INS_TYA:
cpu.A = cpu.Y;
cpu.Z = (cpu.A == 0);
cpu.N = (cpu.A & 0x40) > 0;
cpu.PC++;
break;
case INS_JSR:
jsr_addr = fetch_word();
write_word(cpu.PC - 1, cpu.SP);
cpu.SP++;
cpu.PC = jsr_addr;
break;
case INS_RTS:
// TODO
break;
case INS_6502_NOP:
break;
case INS_INX:
cpu.X++;
cpu.Z = (cpu.X == 0);
cpu.N = (cpu.X & 0x40) > 0;
break;
case INS_INY:
cpu.Y++;
cpu.Z = (cpu.Y == 0);
cpu.N = (cpu.Y & 0x40) > 0;
break;
case INS_DEX:
cpu.X--;
cpu.Z = (cpu.X == 0);
cpu.N = (cpu.X & 0x40) > 0;
break;
case INS_DEY:
cpu.Y--;
cpu.Z = (cpu.Y == 0);
cpu.N = (cpu.Y & 0x40) > 0;
break;
case 0x00: // EOF
return;
default:
printf("%04X: Unhandled instruction: %04X\n", cpu.PC, instruction);
return;
}
}
}
void init6502(FILE *infile) {
reset();
char ch;
int pos = 0;
while (1) { // FIXME
ch = fgetc(infile);
if (ch == EOF)
break;
mem.memory[pos] = ch;
pos++;
}
mem.memory[pos] = EOF;
execute();
dump_cpu(cpu);
return;
}