commit b26428cdee50521ae6910959f6bd191ac87e903a Author: raxracks Date: Sat Jan 27 00:39:48 2024 +1300 first commit diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..6b7af56 --- /dev/null +++ b/Makefile @@ -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 diff --git a/config.cfg b/config.cfg new file mode 100644 index 0000000..4bf3790 --- /dev/null +++ b/config.cfg @@ -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; +} diff --git a/emulator b/emulator new file mode 100755 index 0000000..b1686aa Binary files /dev/null and b/emulator differ diff --git a/emulator.c b/emulator.c new file mode 100644 index 0000000..3ffe7d5 --- /dev/null +++ b/emulator.c @@ -0,0 +1,272 @@ +#include +#include +#include +#include + +#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; +} diff --git a/game.asm b/game.asm new file mode 100644 index 0000000..fd8d92d --- /dev/null +++ b/game.asm @@ -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) + + diff --git a/hello b/hello new file mode 100644 index 0000000..a2d7a75 Binary files /dev/null and b/hello differ diff --git a/hello.asm b/hello.asm new file mode 100644 index 0000000..5b71b27 --- /dev/null +++ b/hello.asm @@ -0,0 +1,4 @@ +LDA #10 +LDX #$1 +STA $20 +INC $2000, X diff --git a/hello.o b/hello.o new file mode 100644 index 0000000..ba69d58 Binary files /dev/null and b/hello.o differ diff --git a/helloworld.nes b/helloworld.nes new file mode 100644 index 0000000..b56f4ae Binary files /dev/null and b/helloworld.nes differ diff --git a/implemented.txt b/implemented.txt new file mode 100644 index 0000000..fa8d60f --- /dev/null +++ b/implemented.txt @@ -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) diff --git a/include/slibs b/include/slibs new file mode 160000 index 0000000..63edb93 --- /dev/null +++ b/include/slibs @@ -0,0 +1 @@ +Subproject commit 63edb9343b6787883a667b69ece86bde005ab311 diff --git a/temp.asm b/temp.asm new file mode 100644 index 0000000..136b5a0 --- /dev/null +++ b/temp.asm @@ -0,0 +1,6 @@ +LDA hello, X +INX +LDA hello, X + +.DATA +hello: .byte "hello world", 0