diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..062f5fd --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +# This ignore the build artifacts produced from running/building the Odin source code +*.bin +*.o diff --git a/2-ibm-logo.ch8 b/2-ibm-logo.ch8 new file mode 100644 index 0000000..677f227 Binary files /dev/null and b/2-ibm-logo.ch8 differ diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..d1954da --- /dev/null +++ b/Makefile @@ -0,0 +1,16 @@ +APP_NAME := my_app +SRC := ./src + +.PHONY: all dev release clean + +all: + odin run $(SRC) -define:DEV=true + +dev: + odin build $(SRC) -out:$(APP_NAME) -define:DEV=true + +release: + odin build $(SRC) -out:$(APP_NAME) -o:speed + +clean: + rm -f $(APP_NAME) diff --git a/src/machine/display.odin b/src/machine/display.odin new file mode 100644 index 0000000..a2f7f8d --- /dev/null +++ b/src/machine/display.odin @@ -0,0 +1,3 @@ +package machine + +// Display will handle all the screen drawing with raylib etc diff --git a/src/machine/machine.odin b/src/machine/machine.odin new file mode 100644 index 0000000..a63ecc4 --- /dev/null +++ b/src/machine/machine.odin @@ -0,0 +1,84 @@ +package machine + +import "core:os" +import "core:log" + +System :: struct { + // 4kb ram + memory: [4096]u8, + // 16 general purpose 8bit registers 0 -> F + v: [16]u8, + // Call stack, up to 16, 2 byte addresses. + stack: [16]u16, + // Stack pointer + sp: u8, + // index register + i: u16, + // PC program counter + pc: u16, + // 64x32-pixel monochrome display + display: [64][32]u8, + keypad: [16]bool, + delay_timer: u8, + sound_timer: u8, +} + +FONT_SET := [80]u8 { + 0xF0, 0x90, 0x90, 0x90, 0xF0, // 0 + 0x20, 0x60, 0x20, 0x20, 0x70, // 1 + 0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2 + 0xF0, 0x10, 0xF0, 0x10, 0xF0, // 3 + 0x90, 0x90, 0xF0, 0x10, 0x10, // 4 + 0xF0, 0x80, 0xF0, 0x10, 0xF0, // 5 + 0xF0, 0x80, 0xF0, 0x90, 0xF0, // 6 + 0xF0, 0x10, 0x20, 0x40, 0x40, // 7 + 0xF0, 0x90, 0xF0, 0x90, 0xF0, // 8 + 0xF0, 0x90, 0xF0, 0x10, 0xF0, // 9 + 0xF0, 0x90, 0xF0, 0x90, 0x90, // A + 0xE0, 0x90, 0xE0, 0x90, 0xE0, // B + 0xF0, 0x80, 0x80, 0x80, 0xF0, // C + 0xE0, 0x90, 0x90, 0x90, 0xE0, // D + 0xF0, 0x80, 0xF0, 0x80, 0xF0, // E + 0xF0, 0x80, 0xF0, 0x80, 0x80 // F +} + +init :: proc() -> System { + log.info("Booting chip 8 cpu") + + // Structs are zero initialized so timers, sp etc are good. + s := System { pc = 0x200 } + + // load fonts into the memory + for v, i in FONT_SET { + s.memory[i] = v + } + + return s +} + +load_rom :: proc(s: ^System, file_path: string) -> os.Error { + log.info("Loading rom from file") + + data, read_err := os.read_entire_file(file_path, context.allocator) + if read_err != os.ERROR_NONE { + log.errorf("failed to read rom %v", read_err) + return read_err + } + defer delete(data) + + for byte,i in data { + s.memory[0x200 + i] = byte + } + + log.infof("First few bytes: %X %X %X %X", s.memory[0x200], s.memory[0x201], s.memory[0x202], s.memory[0x203]) + + return nil +} + +// fetch decode execute loop +run :: proc(s: ^System) { + log.info("=== TODO loop ===") + // maybe needs a few functions for the 'screen' ie raylib. + // also a cycle function or something that will do the ops +} + diff --git a/src/main.odin b/src/main.odin new file mode 100644 index 0000000..78f3587 --- /dev/null +++ b/src/main.odin @@ -0,0 +1,51 @@ +package main + +import "core:log" +import "core:mem" + +import chip "machine" + +// false = release default +DEV :: #config(DEV, false) + +main :: proc() { + context.logger = log.create_console_logger() + defer log.destroy_console_logger(context.logger) + + when DEV { + track: mem.Tracking_Allocator + mem.tracking_allocator_init(&track, context.allocator) + defer mem.tracking_allocator_destroy(&track) + + context.allocator = mem.tracking_allocator(&track) + } + + // Init the Chip 8 "cpu" + system := chip.init() + + // load rom, hardcoded for now, will eventually be cli or gui + err := chip.load_rom(&system, "./2-ibm-logo.ch8") + if err != nil { + panic("failed to load rom!") + } + + // start the cycle + chip.run(&system) + + when DEV { + if len(track.allocation_map) > 0 { + log.errorf("\nMEMORY LEAKS: %v allocation(s)", len(track.allocation_map)) + for _, entry in track.allocation_map { + log.errorf(" %v bytes @ %v", entry.size, entry.location) + } + } + + if len(track.bad_free_array) > 0 { + log.errorf("\nBAD FREES: %v", len(track.bad_free_array)) + + for entry in track.bad_free_array { + log.errorf(" %v @ %v", entry.memory, entry.location) + } + } + } +}