mirror of
https://github.com/raxracks/6502.git
synced 2024-07-07 21:31:17 +12:00
first commit
This commit is contained in:
commit
b26428cdee
7
Makefile
Normal file
7
Makefile
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
emulator: emulator.c
|
||||||
|
gcc emulator.c -o emulator -g -Iinclude
|
||||||
|
hello: hello.asm
|
||||||
|
ca65 hello.asm -o hello.o
|
||||||
|
ld65 hello.o -o hello -C config.cfg
|
||||||
|
run: hello emulator
|
||||||
|
./emulator hello
|
9
config.cfg
Normal file
9
config.cfg
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
MEMORY {
|
||||||
|
RAM: start = $0000, size = $4000, type = rw;
|
||||||
|
ROM: start = $8000, size = $8000, type = ro;
|
||||||
|
}
|
||||||
|
|
||||||
|
SEGMENTS {
|
||||||
|
CODE: load = "ROM", type = ro;
|
||||||
|
DATA: load = "ROM", type = ro;
|
||||||
|
}
|
272
emulator.c
Normal file
272
emulator.c
Normal file
|
@ -0,0 +1,272 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <slibs/slibs.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#define NEGATIVE 1 << 7
|
||||||
|
#define OVERFLOW 1 << 6
|
||||||
|
#define BREAK 1 << 4
|
||||||
|
#define DECIMAL 1 << 3
|
||||||
|
#define INTERRUPT 1 << 2
|
||||||
|
#define ZERO 1 << 1
|
||||||
|
#define CARRY 1 << 0
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t A;
|
||||||
|
uint8_t X;
|
||||||
|
uint8_t Y;
|
||||||
|
uint8_t SP;
|
||||||
|
uint8_t P;
|
||||||
|
uint16_t PC;
|
||||||
|
} CPU;
|
||||||
|
|
||||||
|
CPU cpu = { 0 };
|
||||||
|
uint8_t* memory;
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
assert(argc > 1);
|
||||||
|
|
||||||
|
sl_string code = { 0 };
|
||||||
|
sl_read_file(argv[1], &code);
|
||||||
|
|
||||||
|
memory = malloc(sizeof(uint8_t) * 0xffff);
|
||||||
|
memcpy(memory + 0x8000, code.data, code.size);
|
||||||
|
|
||||||
|
for(cpu.PC = 0; cpu.PC < code.size; cpu.PC++) {
|
||||||
|
uint8_t opcode = code.data[cpu.PC];
|
||||||
|
uint8_t one = code.data[cpu.PC + 1];
|
||||||
|
uint8_t two = code.data[cpu.PC + 2];
|
||||||
|
uint16_t word = (two << 8) | one;
|
||||||
|
|
||||||
|
uint8_t h_nib = (opcode >> 4) & 0xF;
|
||||||
|
uint8_t l_nib = opcode & 0xF;
|
||||||
|
|
||||||
|
printf("%d: 0x%02X (h_nib: 0x%X, l_nib: 0x%X)\n", cpu.PC, opcode, h_nib, l_nib);
|
||||||
|
|
||||||
|
switch(h_nib) {
|
||||||
|
case 0x8:
|
||||||
|
switch(l_nib) {
|
||||||
|
case 0x1:
|
||||||
|
printf(" ∟ STA ($%02X, X)\n", one);
|
||||||
|
memory[memory[one + cpu.X]] = cpu.A;
|
||||||
|
cpu.PC++;
|
||||||
|
break;
|
||||||
|
case 0x5:
|
||||||
|
printf(" ∟ STA $%02X\n", one);
|
||||||
|
memory[one] = cpu.A;
|
||||||
|
cpu.PC++;
|
||||||
|
break;
|
||||||
|
case 0x6:
|
||||||
|
printf(" ∟ STX $%02X\n", one);
|
||||||
|
memory[one] = cpu.X;
|
||||||
|
cpu.PC++;
|
||||||
|
break;
|
||||||
|
case 0xD:
|
||||||
|
printf(" ∟ STA $%04X\n", word);
|
||||||
|
memory[word] = cpu.A;
|
||||||
|
cpu.PC += 2;
|
||||||
|
break;
|
||||||
|
case 0xE:
|
||||||
|
printf(" ∟ STX $%04X\n", word);
|
||||||
|
memory[word] = cpu.X;
|
||||||
|
cpu.PC += 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x9:
|
||||||
|
switch(l_nib) {
|
||||||
|
case 0x1:
|
||||||
|
printf(" ∟ STA ($%02X), Y\n", one);
|
||||||
|
memory[memory[one] + cpu.Y] = cpu.A;
|
||||||
|
cpu.PC++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x5:
|
||||||
|
printf(" ∟ STA $%02X, X\n", word);
|
||||||
|
memory[one + cpu.X] = cpu.A;
|
||||||
|
cpu.PC++;
|
||||||
|
break;
|
||||||
|
case 0x9:
|
||||||
|
printf(" ∟ STA $%04X, Y\n", word);
|
||||||
|
memory[word + cpu.Y] = cpu.A;
|
||||||
|
cpu.PC += 2;
|
||||||
|
break;
|
||||||
|
case 0xD:
|
||||||
|
printf(" ∟ STA $%04X, X\n", word);
|
||||||
|
memory[word + cpu.X] = cpu.A;
|
||||||
|
cpu.PC += 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0xA:
|
||||||
|
switch(l_nib) {
|
||||||
|
case 0x0:
|
||||||
|
printf(" ∟ LDY #$%02X\n", one);
|
||||||
|
cpu.Y = one;
|
||||||
|
cpu.PC++;
|
||||||
|
break;
|
||||||
|
case 0x1:
|
||||||
|
printf(" ∟ LDA ($%02X, X)\n", one);
|
||||||
|
cpu.A = memory[memory[one + cpu.X]];
|
||||||
|
printf("addr: %x val: %x\n", memory[one + cpu.X], cpu.A);
|
||||||
|
cpu.PC++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x2:
|
||||||
|
printf(" ∟ LDX #$%02X\n", one);
|
||||||
|
cpu.X = one;
|
||||||
|
cpu.PC++;
|
||||||
|
break;
|
||||||
|
case 0x4:
|
||||||
|
printf(" ∟ LDY $%02X\n", one);
|
||||||
|
cpu.Y = memory[one];
|
||||||
|
cpu.PC++;
|
||||||
|
break;
|
||||||
|
case 0x5:
|
||||||
|
printf(" ∟ LDA $%02X\n", one);
|
||||||
|
cpu.A = memory[one];
|
||||||
|
cpu.PC++;
|
||||||
|
break;
|
||||||
|
case 0x6:
|
||||||
|
printf(" ∟ LDX $%02X\n", one);
|
||||||
|
cpu.X = memory[one];
|
||||||
|
cpu.PC++;
|
||||||
|
break;
|
||||||
|
case 0x9:
|
||||||
|
printf(" ∟ LDA #$%02X\n", one);
|
||||||
|
cpu.A = one;
|
||||||
|
cpu.PC++;
|
||||||
|
break;
|
||||||
|
case 0xC:
|
||||||
|
printf(" ∟ LDY $%04X\n", word);
|
||||||
|
cpu.Y = memory[word];
|
||||||
|
cpu.PC += 2;
|
||||||
|
break;
|
||||||
|
case 0xD:
|
||||||
|
printf(" ∟ LDA $%04X\n", word);
|
||||||
|
cpu.A = memory[word];
|
||||||
|
cpu.PC += 2;
|
||||||
|
break;
|
||||||
|
case 0xE:
|
||||||
|
printf(" ∟ LDX $%04X\n", word);
|
||||||
|
cpu.X = memory[word];
|
||||||
|
cpu.PC += 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0xB:
|
||||||
|
switch(l_nib) {
|
||||||
|
case 0x1:
|
||||||
|
printf(" ∟ LDA ($%02X), Y\n", one);
|
||||||
|
cpu.A = memory[memory[one] + cpu.Y];
|
||||||
|
printf("addr: %x val: %x\n", memory[one] + cpu.Y, cpu.A);
|
||||||
|
cpu.PC++;
|
||||||
|
break;
|
||||||
|
case 0x4:
|
||||||
|
printf(" ∟ LDY $%02X, X\n", one);
|
||||||
|
cpu.Y = memory[one + cpu.X];
|
||||||
|
printf("addr: %x val: %x\n", one + cpu.X, cpu.Y);
|
||||||
|
cpu.PC++;
|
||||||
|
break;
|
||||||
|
case 0x5:
|
||||||
|
printf(" ∟ LDA $%02X, X\n", one);
|
||||||
|
cpu.A = memory[one + cpu.X];
|
||||||
|
printf("addr: %x val: %x\n", one + cpu.X, cpu.A);
|
||||||
|
cpu.PC++;
|
||||||
|
break;
|
||||||
|
case 0x6:
|
||||||
|
printf(" ∟ LDX $%02X, Y\n", one);
|
||||||
|
cpu.X = memory[one + cpu.Y];
|
||||||
|
printf("addr: %x val: %x\n", one + cpu.Y, cpu.X);
|
||||||
|
cpu.PC++;
|
||||||
|
break;
|
||||||
|
case 0x9:
|
||||||
|
printf(" ∟ LDA $%04X, Y\n", word);
|
||||||
|
cpu.A = memory[word + cpu.Y];
|
||||||
|
printf("addr: %x val: %x\n", word + cpu.Y, cpu.A);
|
||||||
|
cpu.PC++;
|
||||||
|
break;
|
||||||
|
case 0xC:
|
||||||
|
printf(" ∟ LDY $%04X, X\n", word);
|
||||||
|
cpu.Y = memory[word + cpu.X];
|
||||||
|
printf("addr: %x val: %x\n", word + cpu.X, cpu.Y);
|
||||||
|
cpu.PC += 2;
|
||||||
|
break;
|
||||||
|
case 0xD:
|
||||||
|
printf(" ∟ LDA $%04X, X\n", word);
|
||||||
|
cpu.A = memory[word + cpu.X];
|
||||||
|
printf("addr: %x val: %x\n", word + cpu.X, cpu.A);
|
||||||
|
cpu.PC += 2;
|
||||||
|
break;
|
||||||
|
case 0xE:
|
||||||
|
printf(" ∟ LDX $%04X, Y\n", word);
|
||||||
|
cpu.X = memory[word + cpu.Y];
|
||||||
|
printf("addr: %x val: %x\n", word + cpu.Y, cpu.X);
|
||||||
|
cpu.PC += 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0xC:
|
||||||
|
switch(l_nib) {
|
||||||
|
case 0x8:
|
||||||
|
printf(" ∟ INY\n");
|
||||||
|
cpu.Y++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0xE:
|
||||||
|
switch(l_nib) {
|
||||||
|
case 0x6:
|
||||||
|
printf(" ∟ INC $%02X\n", one);
|
||||||
|
memory[one]++;
|
||||||
|
cpu.PC++;
|
||||||
|
break;
|
||||||
|
case 0x8:
|
||||||
|
printf(" ∟ INX\n");
|
||||||
|
cpu.X++;
|
||||||
|
break;
|
||||||
|
case 0xE:
|
||||||
|
printf(" ∟ INC $%04X\n", word);
|
||||||
|
memory[word]++;
|
||||||
|
cpu.PC += 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0xF:
|
||||||
|
switch(l_nib) {
|
||||||
|
case 0x6:
|
||||||
|
printf(" ∟ INC $%02X, X\n", one);
|
||||||
|
memory[one + cpu.X]++;
|
||||||
|
cpu.PC++;
|
||||||
|
break;
|
||||||
|
case 0xE:
|
||||||
|
printf(" ∟ INC $%04X, X\n", word);
|
||||||
|
memory[word + cpu.X]++;
|
||||||
|
cpu.PC += 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf(" ∟ Unimplemented\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("CPU State:\n"
|
||||||
|
"A\t:\t0x%08X\n"
|
||||||
|
"X\t:\t0x%08X\n"
|
||||||
|
"Y\t:\t0x%08X\n"
|
||||||
|
"SP\t:\t0x%08X\n"
|
||||||
|
"P\t:\t0x%08X\n"
|
||||||
|
"PC\t:\t0x%016X\n\n"
|
||||||
|
, cpu.A, cpu.X, cpu.Y, cpu.SP, cpu.P, cpu.PC);
|
||||||
|
|
||||||
|
printf("Memory State:\n");
|
||||||
|
for(int i = 0; i < 0xffff; i++) {
|
||||||
|
if(memory[i] != 0x0) {
|
||||||
|
printf("0x%04X: 0x%02X (0b%08b)\n", i, memory[i], memory[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
40
game.asm
Normal file
40
game.asm
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
.segment "CODE"
|
||||||
|
|
||||||
|
.proc main
|
||||||
|
main:
|
||||||
|
; Initialize PPU
|
||||||
|
LDA #%10000000 ; Set the bit 7 to $2000 to use $2000-$2FFF for nametables
|
||||||
|
STA $2000
|
||||||
|
LDA #%00011110 ; Enable rendering, enable sprites, and make sure background is visible
|
||||||
|
STA $2001
|
||||||
|
|
||||||
|
; Load sprite data into OAM
|
||||||
|
LDX #0 ; Initialize X register to zero
|
||||||
|
LDA SpriteData,X ; Load the first byte of sprite data
|
||||||
|
STA $0200,X ; Store it in the Object Attribute Memory (OAM)
|
||||||
|
INX ; Increment X to load the next byte
|
||||||
|
LDA SpriteData,X ; Load the second byte of sprite data (attributes)
|
||||||
|
STA $0200,X ; Store it in OAM
|
||||||
|
INX ; Increment X to load the next byte (X position)
|
||||||
|
LDA SpriteData,X ; Load the third byte of sprite data (X position)
|
||||||
|
STA $0200,X ; Store it in OAM
|
||||||
|
|
||||||
|
; Infinite loop
|
||||||
|
forever:
|
||||||
|
JMP forever
|
||||||
|
|
||||||
|
.endproc
|
||||||
|
|
||||||
|
.segment "DATA"
|
||||||
|
|
||||||
|
SpriteData:
|
||||||
|
.byte $00 ; Tile index for the sprite
|
||||||
|
.byte $20 ; Attributes (palette, flipping, etc.)
|
||||||
|
.byte $80 ; X position of the sprite
|
||||||
|
; Additional sprite data can be added here
|
||||||
|
|
||||||
|
.segment "BSS"
|
||||||
|
|
||||||
|
; Define uninitialized memory (if needed)
|
||||||
|
|
||||||
|
|
BIN
helloworld.nes
Normal file
BIN
helloworld.nes
Normal file
Binary file not shown.
39
implemented.txt
Normal file
39
implemented.txt
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
==== LDA (completed) ====
|
||||||
|
LDA #
|
||||||
|
LDA $ (Z)
|
||||||
|
LDA $ (A)
|
||||||
|
LDA $, X (Z)
|
||||||
|
LDA $, X (A)
|
||||||
|
LDA $, Y (A)
|
||||||
|
LDA ($, X)
|
||||||
|
LDA ($), Y
|
||||||
|
|
||||||
|
==== LDX (completed) ====
|
||||||
|
LDX #
|
||||||
|
LDX $ (Z)
|
||||||
|
LDX $ (A)
|
||||||
|
LDX $, Y (Z)
|
||||||
|
LDX $, Y (A)
|
||||||
|
|
||||||
|
==== LDY (completed) ====
|
||||||
|
LDY #
|
||||||
|
LDY $ (Z)
|
||||||
|
LDY $ (A)
|
||||||
|
LDY $, X (Z)
|
||||||
|
LDY $, X (A)
|
||||||
|
|
||||||
|
==== STA (completed) ====
|
||||||
|
STA $ (Z)
|
||||||
|
STA $ (A)
|
||||||
|
STA $, X (Z)
|
||||||
|
STA $, X (A)
|
||||||
|
STA ($, X)
|
||||||
|
STA ($), Y
|
||||||
|
|
||||||
|
==== INC (completed) ====
|
||||||
|
INX
|
||||||
|
INY
|
||||||
|
INC $ (Z)
|
||||||
|
INC $ (A)
|
||||||
|
INC $, X (Z)
|
||||||
|
INC $, X (A)
|
1
include/slibs
Submodule
1
include/slibs
Submodule
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 63edb9343b6787883a667b69ece86bde005ab311
|
Loading…
Reference in a new issue