230 lines
4.8 KiB
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;
|
|
}
|