From e01ab151c250c962bae1bc1317037b002f35da9a Mon Sep 17 00:00:00 2001 From: Thomas Daley Date: Thu, 15 Jan 2026 21:15:01 -0800 Subject: [PATCH 01/16] convert classes to stucts --- shared/Audio.cc | 55 ++++----- shared/Audio.h | 29 +++-- shared/Chip8.cc | 227 +++++++++++++++++++------------------- shared/Chip8.h | 275 +++++++++++++++++++++------------------------ shared/Display.cc | 142 ++++++++++++------------ shared/Display.h | 80 +++++++------- shared/Gui.cc | 161 ++++++++++++++------------- shared/Gui.h | 94 ++++++++-------- shared/Input.cc | 127 +++++++++++---------- shared/Input.h | 64 +++++------ shared/main.cc | 9 +- shared/opcodes.cc | 276 +++++++++++++++++++++++----------------------- 12 files changed, 760 insertions(+), 779 deletions(-) diff --git a/shared/Audio.cc b/shared/Audio.cc index 90f310ca..17540bb6 100644 --- a/shared/Audio.cc +++ b/shared/Audio.cc @@ -1,58 +1,61 @@ #include "Audio.h" #include -Audio::Audio() { - wave_position = 0; - wave_increment = ((double) TONE * (2.0 * M_PI)) / (double) FREQUENCY; +/* Global audio instance */ +struct audio audio; + +void audio_create(void) { + audio.wave_position = 0; + audio.wave_increment = ((double) TONE * (2.0 * M_PI)) / (double) FREQUENCY; } -Audio::~Audio() { +void audio_destroy(void) { /* pause & close the audio */ - SDL_PauseAudioDevice(device, 1); - if (device) SDL_CloseAudioDevice(device); - free(audio_buffer); + SDL_PauseAudioDevice(audio.device, 1); + if (audio.device) SDL_CloseAudioDevice(audio.device); + free(audio.audio_buffer); } -int Audio::Initialize() { - audiospec.freq = FREQUENCY; - audiospec.format = AUDIO_U8; /* unsigned 8-bit data stream */ - audiospec.channels = 1; /* mono */ - audiospec.samples = 2048; /* must be a power of 2 */ - audiospec.callback = NULL; - audiospec.userdata = NULL; +int audio_initialize(void) { + audio.audiospec.freq = FREQUENCY; + audio.audiospec.format = AUDIO_U8; /* unsigned 8-bit data stream */ + audio.audiospec.channels = 1; /* mono */ + audio.audiospec.samples = 2048; /* must be a power of 2 */ + audio.audiospec.callback = NULL; + audio.audiospec.userdata = NULL; /* open default audio device (allow audio changes) */ - device = SDL_OpenAudioDevice(NULL, 0, &audiospec, NULL, SDL_AUDIO_ALLOW_ANY_CHANGE); + audio.device = SDL_OpenAudioDevice(NULL, 0, &audio.audiospec, NULL, SDL_AUDIO_ALLOW_ANY_CHANGE); - if (!device) { + if (!audio.device) { fprintf(stderr, "Error: %s\n", SDL_GetError()); return 1; } /* ~.5 seconds worth of audio (probably overkill) */ - audio_buffer = (unsigned char *)malloc(SAMPLES_PER_FRAME * 30); - if (!audio_buffer) { + audio.audio_buffer = (unsigned char *)malloc(SAMPLES_PER_FRAME * 30); + if (!audio.audio_buffer) { fprintf(stderr, "Unable to allocate memory for audio buffer.\n"); return 1; } /* start playing audio */ - SDL_PauseAudioDevice(device, 0); + SDL_PauseAudioDevice(audio.device, 0); return 0; } -void Audio::SineWave(int length) { +static void audio_sine_wave(int length) { for (int i = 0; i < length; i++) { /* sine wave varies from 120 - 134 */ - audio_buffer[i] = (unsigned char) ((AMPLITUDE * sin(wave_position)) + BIAS); - wave_position += wave_increment; + audio.audio_buffer[i] = (unsigned char) ((AMPLITUDE * sin(audio.wave_position)) + BIAS); + audio.wave_position += audio.wave_increment; } } -void Audio::Beep(int length) { - if (SDL_GetQueuedAudioSize(device) < (SAMPLES_PER_FRAME * 2)) { - SineWave(length); - SDL_QueueAudio(device, audio_buffer, length); +void audio_beep(int length) { + if (SDL_GetQueuedAudioSize(audio.device) < (SAMPLES_PER_FRAME * 2)) { + audio_sine_wave(length); + SDL_QueueAudio(audio.device, audio.audio_buffer, length); } } diff --git a/shared/Audio.h b/shared/Audio.h index 6efa4836..04fd27ca 100644 --- a/shared/Audio.h +++ b/shared/Audio.h @@ -9,23 +9,22 @@ #define BIAS 127 #define SAMPLES_PER_FRAME ((FREQUENCY / 60) * 3) -class Audio { - private: - SDL_AudioSpec audiospec; - SDL_AudioDeviceID device; - unsigned char *audio_buffer; +struct audio { + SDL_AudioSpec audiospec; + SDL_AudioDeviceID device; + unsigned char *audio_buffer; - double wave_position; - double wave_increment; - - void SineWave(int length); + double wave_position; + double wave_increment; +}; - public: +/* Global audio instance */ +extern struct audio audio; - Audio(); - ~Audio(); - int Initialize(); - void Beep(int length); -}; +/* Audio functions */ +void audio_create(void); +void audio_destroy(void); +int audio_initialize(void); +void audio_beep(int length); #endif diff --git a/shared/Chip8.cc b/shared/Chip8.cc index 4cf3e66b..2cbc2d31 100644 --- a/shared/Chip8.cc +++ b/shared/Chip8.cc @@ -5,30 +5,33 @@ #include #include -Chip8::Chip8() { - cycles = CYCLES_PER_STEP; - paused = 0; - muted = 0; - vwrap = 1; - display = Display(); - input = Input(); - vram = NULL; - rom = NULL; +/* Global chip8 instance */ +struct chip8 chip8; + +void chip8_create() { + chip8.cycles = CYCLES_PER_STEP; + chip8.paused = 0; + chip8.muted = 0; + chip8.vwrap = 1; + display_create(); + chip8.vram = NULL; + chip8.rom = NULL; } -Chip8::~Chip8() { +void chip8_destroy() { /* clean-up */ - if (vram) { + if (chip8.vram) { for (int i = 0; i < WIDTH; i++) { - free(vram[i]); + free(chip8.vram[i]); } - free(vram); + free(chip8.vram); } - free(rom); + free(chip8.rom); + display_destroy(); SDL_Quit(); } -int Chip8::Initialize( +int chip8_initialize( bool fullscreen, bool load_store_quirk, bool shift_quirk, @@ -47,90 +50,90 @@ int Chip8::Initialize( return 1; } - this->load_store_quirk = load_store_quirk; - this->shift_quirk = shift_quirk; - this->vwrap = vwrap; - this->muted = muted; + chip8.load_store_quirk = load_store_quirk; + chip8.shift_quirk = shift_quirk; + chip8.vwrap = vwrap; + chip8.muted = muted; /* init vram */ - vram = (unsigned char **) malloc(WIDTH * sizeof(unsigned char *)); + chip8.vram = (unsigned char **) malloc(WIDTH * sizeof(unsigned char *)); const char *err_str = "Unable to allocate memory on the heap.\n"; - if (!vram) { + if (!chip8.vram) { fprintf(stderr, "%s", err_str); return 1; } - memset(vram, 0, WIDTH * sizeof(unsigned char *)); + memset(chip8.vram, 0, WIDTH * sizeof(unsigned char *)); for (int i = 0; i < WIDTH; i++) { - vram[i] = (unsigned char *) malloc(HEIGHT * sizeof(unsigned char)); - if (!vram[i]) { + chip8.vram[i] = (unsigned char *) malloc(HEIGHT * sizeof(unsigned char)); + if (!chip8.vram[i]) { fprintf(stderr, "%s", err_str); return 1; } - memset(vram[i], 0, HEIGHT * sizeof(unsigned char)); + memset(chip8.vram[i], 0, HEIGHT * sizeof(unsigned char)); } /* init audio, display, input */ - audio.Initialize(); + audio_initialize(); - if (display.Initialize( + if (display_initialize( fullscreen, - &this->cycles, - &this->paused, - &this->load_store_quirk, - &this->shift_quirk, - &this->vwrap, - &this->muted + &chip8.cycles, + &chip8.paused, + &chip8.load_store_quirk, + &chip8.shift_quirk, + &chip8.vwrap, + &chip8.muted ) ) return 1; - input.Initialize( - &this->display, - &this->cycles, - &this->cpu_halt, - &this->paused, - &this->muted + input_initialize( + &display, + &chip8.cycles, + &chip8.cpu_halt, + &chip8.paused, + &chip8.muted ); /* init registers and memory once */ - memset(V, 0 , NUM_REGISTERS); - memset(memory, 0, MEM_SIZE); - memset(stack, 0, STACK_DEPTH); - I = 0; - PC = ENTRY_POINT; - sp = 0; - delay_timer = 0; - sound_timer = 0; - cpu_halt = 0; - draw_flag = 1; + memset(chip8.V, 0 , NUM_REGISTERS); + memset(chip8.memory, 0, MEM_SIZE); + memset(chip8.stack, 0, STACK_DEPTH); + chip8.I = 0; + chip8.PC = ENTRY_POINT; + chip8.sp = 0; + chip8.delay_timer = 0; + chip8.sound_timer = 0; + chip8.cpu_halt = 0; + chip8.draw_flag = 1; /* load fontset */ for(int i = 0; i < FONTS_SIZE; ++i) { - memory[i] = chip8_fontset[i]; + chip8.memory[i] = chip8.chip8_fontset[i]; } - return LoadBootRom(); + return chip8_load_bootrom(); } -int Chip8::LoadBootRom() { - free(rom); - rom_size = BOOTROM_SIZE; - rom = (unsigned char *)malloc(rom_size); - if(!rom) { +int chip8_load_bootrom() { + free(chip8.rom); + chip8.rom_size = BOOTROM_SIZE; + chip8.rom = (unsigned char *)malloc(chip8.rom_size); + if(!chip8.rom) { fprintf(stderr, "Unable to allocate memory for rom.\n"); return 1; } - memset(rom, 0 , rom_size); + memset(chip8.rom, 0 , chip8.rom_size); /* save for later (soft-resets) */ - memcpy(rom, bootrom, rom_size); + memcpy(chip8.rom, bootrom, chip8.rom_size); /* copy the entire rom to memory starting from 0x200 */ - memcpy(memory + ENTRY_POINT, bootrom, BOOTROM_SIZE); + memcpy(chip8.memory + ENTRY_POINT, bootrom, BOOTROM_SIZE); return 0; } -int Chip8::Load(const char *rom_name) { +int chip8_load(const char *rom_name) { if (rom_name) { /* open the file */ FILE *file; @@ -142,29 +145,29 @@ int Chip8::Load(const char *rom_name) { /* get file size */ fseek(file, 0, SEEK_END); - rom_size = ftell(file); + chip8.rom_size = ftell(file); rewind(file); - if (rom_size > MEM_SIZE - ENTRY_POINT) { + if (chip8.rom_size > MEM_SIZE - ENTRY_POINT) { fprintf(stderr, "Rom is too large or not formatted properly.\n"); return 1; } /* allocate or free and reallocate as necessary */ - free(rom); - rom = (unsigned char *)malloc(rom_size); - if(!rom) { + free(chip8.rom); + chip8.rom = (unsigned char *)malloc(chip8.rom_size); + if(!chip8.rom) { fprintf(stderr, "Unable to allocate memory for rom.\n"); return 1; } - memset(rom, 0 , rom_size); + memset(chip8.rom, 0 , chip8.rom_size); /* save the rom for later (soft-resets) */ - if (!fread(rom, sizeof(unsigned char), rom_size, file)) { + if (!fread(chip8.rom, sizeof(unsigned char), chip8.rom_size, file)) { fprintf(stderr, "Unable to read Rom file after successfully opening.\n"); return 1; } - SoftReset(); + chip8_soft_reset(); fclose(file); } else { @@ -172,56 +175,56 @@ int Chip8::Load(const char *rom_name) { char new_rom_name[PATH_MAX]; openFileDialog(new_rom_name) ? fprintf(stderr, "User aborted the open file dialog.\n") : - Load(new_rom_name); + chip8_load(new_rom_name); /* flip GUI toggle */ - display.gui.load_rom_flag = 0; + gui.load_rom_flag = 0; display.lost_window_focus = 1; } return 0; } -void Chip8::SoftReset() { +void chip8_soft_reset() { /* clear the vram */ for (int i = 0; i < WIDTH; i++) { - memset(vram[i], 0, HEIGHT * sizeof(unsigned char)); + memset(chip8.vram[i], 0, HEIGHT * sizeof(unsigned char)); } /* reset the state of the input keys */ - input.Reset(); + input_reset(); /* clear registers and the stack */ - memset(V, 0 , NUM_REGISTERS); - memset(stack, 0, STACK_DEPTH); - memset(memory, 0, MEM_SIZE); + memset(chip8.V, 0 , NUM_REGISTERS); + memset(chip8.stack, 0, STACK_DEPTH); + memset(chip8.memory, 0, MEM_SIZE); /* load fontset */ for(int i = 0; i < FONTS_SIZE; ++i) { - memory[i] = chip8_fontset[i]; + chip8.memory[i] = chip8.chip8_fontset[i]; } /* copy the entire rom to memory starting from 0x200 */ - memcpy(memory + ENTRY_POINT, rom, rom_size); + memcpy(chip8.memory + ENTRY_POINT, chip8.rom, chip8.rom_size); /* re-initialize program counter, stack pointer, timers, etc. */ - I = 0; - PC = ENTRY_POINT; - sp = 0; - delay_timer = 0; - sound_timer = 0; - cpu_halt = 0; - draw_flag = 1; + chip8.I = 0; + chip8.PC = ENTRY_POINT; + chip8.sp = 0; + chip8.delay_timer = 0; + chip8.sound_timer = 0; + chip8.cpu_halt = 0; + chip8.draw_flag = 1; /* un-pause (if paused) whenever we Soft-Reset */ - paused = 0; + chip8.paused = 0; /* flip the GUI bit */ - display.gui.soft_reset_flag = 0; + gui.soft_reset_flag = 0; } -void Chip8::Run(){ +void chip8_run(){ int event; unsigned int t1; unsigned int t2; @@ -238,30 +241,30 @@ void Chip8::Run(){ t1 = SDL_GetTicks(); - event = input.Poll(); + event = input_poll(); /* do something based on response... */ if (event & USER_QUIT) return; - if (event & LOAD_ROM) Load(NULL); - if (event & SOFT_RESET) SoftReset(); + if (event & LOAD_ROM) chip8_load(NULL); + if (event & SOFT_RESET) chip8_soft_reset(); - if (!paused) { + if (!chip8.paused) { /* emulate a number of cycles */ - StepCpu(cycles); + chip8_step_cpu(chip8.cycles); /* update Audio */ - if (sound_timer > 0 && !muted) audio.Beep(SAMPLES_PER_FRAME); + if (chip8.sound_timer > 0 && !chip8.muted) audio_beep(SAMPLES_PER_FRAME); /* check internal timers */ - UpdateTimers(); + chip8_update_timers(); } /* draw a frame if we need to */ - if (draw_flag && display.limit_fps_flag) { - display.RenderFrame(vram); - draw_flag = 0; + if (chip8.draw_flag && display.limit_fps_flag) { + display_render_frame(chip8.vram); + chip8.draw_flag = 0; } else { - display.RenderFrame(NULL); + display_render_frame(NULL); } t2 = SDL_GetTicks(); @@ -276,34 +279,34 @@ void Chip8::Run(){ } } -void Chip8::UpdateTimers(){ +void chip8_update_timers(){ /* update timers at 60 Hz */ - if (!cpu_halt) { - if(delay_timer > 0) delay_timer--; - if(sound_timer > 0) sound_timer--; + if (!chip8.cpu_halt) { + if(chip8.delay_timer > 0) chip8.delay_timer--; + if(chip8.sound_timer > 0) chip8.sound_timer--; } } -void Chip8::StepCpu(int cycles){ +void chip8_step_cpu(int cycles){ /* execute a batch of instructions */ for (int i = 0; i < cycles; i++) { - FetchOpcode(); - ExecuteOpcode(); + chip8_fetch_opcode(); + chip8_execute_opcode(); /* draw */ - if(draw_flag && !display.limit_fps_flag){ - display.RenderFrame(vram); - draw_flag = 0; + if(chip8.draw_flag && !display.limit_fps_flag){ + display_render_frame(chip8.vram); + chip8.draw_flag = 0; } } } -void Chip8::FetchOpcode() { +void chip8_fetch_opcode() { /* fetch two bytes while being careful of byte alignment */ - opcode = memory[PC] << 8 | memory[PC + 1]; + chip8.opcode = chip8.memory[chip8.PC] << 8 | chip8.memory[chip8.PC + 1]; } -void Chip8::ExecuteOpcode(){ +void chip8_execute_opcode(){ switch (OP) { case 0x0: switch (OP_NNN) { diff --git a/shared/Chip8.h b/shared/Chip8.h index 01dc5506..e52714e2 100644 --- a/shared/Chip8.h +++ b/shared/Chip8.h @@ -34,157 +34,130 @@ #define MAX_CYCLES_PER_STEP 50 #define TICKS 60 /* hz - Timer count down rate */ -class Chip8 { - - private: - - /* number of cycles per step */ - int cycles; - - /* whether or not cpu is currently halted by opcode FX0A */ - bool cpu_halt; - - /* whether ot not emulation is currently paused. - This is different from CPU's HALT state. */ - bool paused; - - /* Two quirks of the Chip8 CPU. - Some games assume these are enabled to run correctly. - - Load/store quirks - Instructions OxFX55 and 0xFX65 increments - value of I register but some CHIP-8 programs assumes that - they don't. Enabling this quirk causes I register to become - unchanged after the instruction. - - Shift quirks - Shift instructions originally shift register - VY and store results in register VX. Some CHIP-8 programs - incorrectly assumes that the VX register is shifted by this - instruction, and VY remains unmodified. Enabling this quirk - causes VX to become shifted and VY remain untouched. */ - bool load_store_quirk; - bool shift_quirk; - - /* vertical wrapping toggle */ - bool vwrap; - - /* two bytes for each instruction */ - unsigned short opcode; - - /* 0x000-0x1FF - Chip 8 interpreter (contains font set in emu) - 0x050-0x0A0 - Used for the built in 4x5 pixel font set (0-F) - 0x200-0xFFF - Program ROM and work RAM */ - unsigned char memory[MEM_SIZE]; - - /* copy of the rom for soft resetting */ - unsigned char *rom; - unsigned int rom_size; - - /* 15 general prupose regsiters, and a carry flag register */ - unsigned char V[NUM_REGISTERS]; - - /* index register and program counter */ - unsigned short I; - unsigned short PC; - - unsigned char delay_timer; - unsigned char sound_timer; - - /* stack with maximum of 16 levels */ - unsigned short stack[STACK_DEPTH]; - unsigned short sp; - - Input input; - Display display; - Audio audio; - - /* mute audio toggle */ - bool muted; - - /* if this flag is enabled, draw a frame at the end of the cycle */ - int draw_flag; - - /* 1-bit encoded screen pixels (64x32) */ - unsigned char **vram; - - const unsigned char chip8_fontset[FONTS_SIZE] = { - 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 - }; - - int LoadBootRom(); - void SoftReset(); - void UpdateTimers(); - void StepCpu(int cycles); - void FetchOpcode(); - void ExecuteOpcode(); - - /* definitions in opcodes.cc */ - inline void exec00E0(); - inline void exec00EE(); - inline void exec0NNN(); - inline void exec1NNN(); - inline void exec2NNN(); - inline void exec3XNN(); - inline void exec4XNN(); - inline void exec5XY0(); - inline void exec6XNN(); - inline void exec7XNN(); - inline void exec8XY0(); - inline void exec8XY1(); - inline void exec8XY2(); - inline void exec8XY3(); - inline void exec8XY4(); - inline void exec8XY5(); - inline void exec8XY6(); - inline void exec8XY7(); - inline void exec8XYE(); - inline void exec9XY0(); - inline void execANNN(); - inline void execBNNN(); - inline void execCXNN(); - inline void execDXYN(); - inline void execEX9E(); - inline void execEXA1(); - inline void execFX07(); - inline void execFX0A(); - inline void execFX15(); - inline void execFX18(); - inline void execFX1E(); - inline void execFX29(); - inline void execFX33(); - inline void execFX55(); - inline void execFX65(); - inline void execUnknown(); - - public: - - Chip8(); - ~Chip8(); - - int Initialize( - bool fullscreen, - bool load_store_quirk, - bool shift_quirk, - bool vwrap, - bool muted - ); - - int Load(const char *rom_name); - void Run(); +struct chip8 { + /* number of cycles per step */ + int cycles; + + /* whether or not cpu is currently halted by opcode FX0A */ + bool cpu_halt; + + /* whether or not emulation is currently paused. */ + bool paused; + + /* CPU quirks */ + bool load_store_quirk; + bool shift_quirk; + + /* vertical wrapping toggle */ + bool vwrap; + + /* two bytes for each instruction */ + unsigned short opcode; + + /* memory */ + unsigned char memory[MEM_SIZE]; + + /* copy of the rom for soft resetting */ + unsigned char *rom; + unsigned int rom_size; + + /* registers */ + unsigned char V[NUM_REGISTERS]; + unsigned short I; + unsigned short PC; + + unsigned char delay_timer; + unsigned char sound_timer; + + /* stack */ + unsigned short stack[STACK_DEPTH]; + unsigned short sp; + + /* mute audio toggle */ + bool muted; + + /* draw flag */ + int draw_flag; + + /* 1-bit encoded screen pixels (64x32) */ + unsigned char **vram; + + const unsigned char chip8_fontset[FONTS_SIZE] = { + 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 + 0x20, 0x60, 0x20, 0x20, 0x70, // B + 0xF0, 0x80, 0xF0, 0x80, 0xF0, // C + 0xF0, 0x80, 0xF0, 0x80, 0x80, // D + 0xF0, 0x90, 0x90, 0xF0, 0x90 // F + }; }; +/* Global chip8 instance */ +extern struct chip8 chip8; + +/* Chip8 functions */ +void chip8_create(void); +void chip8_destroy(void); +int chip8_initialize( + bool fullscreen, + bool load_store_quirk, + bool shift_quirk, + bool vwrap, + bool muted +); +int chip8_load(const char *rom_name); +void chip8_run(void); +void chip8_update_timers(void); +void chip8_step_cpu(int cycles); +void chip8_soft_reset(void); +int chip8_load_bootrom(void); +void chip8_fetch_opcode(void); +void chip8_execute_opcode(void); + +/* opcode helpers */ +void exec00E0(void); +void exec00EE(void); +void exec0NNN(void); +void exec1NNN(void); +void exec2NNN(void); +void exec3XNN(void); +void exec4XNN(void); +void exec5XY0(void); +void exec6XNN(void); +void exec7XNN(void); +void exec8XY0(void); +void exec8XY1(void); +void exec8XY2(void); +void exec8XY3(void); +void exec8XY4(void); +void exec8XY5(void); +void exec8XY6(void); +void exec8XY7(void); +void exec8XYE(void); +void exec9XY0(void); +void execANNN(void); +void execBNNN(void); +void execCXNN(void); +void execDXYN(void); +void execEX9E(void); +void execEXA1(void); +void execFX07(void); +void execFX0A(void); +void execFX15(void); +void execFX18(void); +void execFX1E(void); +void execFX29(void); +void execFX33(void); +void execFX55(void); +void execFX65(void); +void execUnknown(void); #endif diff --git a/shared/Display.cc b/shared/Display.cc index 7ab9eb46..cc23150b 100644 --- a/shared/Display.cc +++ b/shared/Display.cc @@ -3,41 +3,47 @@ #include #include -Display::Display(){ - WINDOW_WIDTH = WIDTH * (int)SCALE; - WINDOW_HEIGHT = HEIGHT * (int)SCALE; - back_buffer = NULL; - window = NULL; - fullscreen_flag = 0; - vsync_flag = 0; - limit_fps_flag = 1; - lost_window_focus = 0; +/* Global display instance */ +struct display display; + +void display_create(void){ + display.WINDOW_WIDTH = WIDTH * (int)SCALE; + display.WINDOW_HEIGHT = HEIGHT * (int)SCALE; + display.back_buffer = NULL; + display.window = NULL; + display.fullscreen_flag = 0; + display.vsync_flag = 0; + display.limit_fps_flag = 1; + display.lost_window_focus = 0; /* set rendering colors */ - background_color[0] = (float) DEFAULT_BACKGROUND_R / (float) 0xFF; - background_color[1] = (float) DEFAULT_BACKGROUND_G / (float) 0xFF; - background_color[2] = (float) DEFAULT_BACKGROUND_B / (float) 0xFF; + display.background_color[0] = (float) DEFAULT_BACKGROUND_R / (float) 0xFF; + display.background_color[1] = (float) DEFAULT_BACKGROUND_G / (float) 0xFF; + display.background_color[2] = (float) DEFAULT_BACKGROUND_B / (float) 0xFF; - foreground_color[0] = (float) DEFAULT_FOREGROUND_R / (float) 0xFF; - foreground_color[1] = (float) DEFAULT_FOREGROUND_G / (float) 0xFF; - foreground_color[2] = (float) DEFAULT_FOREGROUND_B / (float) 0xFF; + display.foreground_color[0] = (float) DEFAULT_FOREGROUND_R / (float) 0xFF; + display.foreground_color[1] = (float) DEFAULT_FOREGROUND_G / (float) 0xFF; + display.foreground_color[2] = (float) DEFAULT_FOREGROUND_B / (float) 0xFF; + + /* initialize gui state */ + gui_create(); } -Display::~Display(){ +void display_destroy(void){ /* clean-up */ - if (back_buffer) { + if (display.back_buffer) { for (int i = 0; i < WIDTH; i++) { - free(back_buffer[i]); + free(display.back_buffer[i]); } - free(back_buffer); + free(display.back_buffer); } - gui.~Gui(); - SDL_GL_DeleteContext(glcontext); - SDL_DestroyWindow(window); + gui_cleanup(); + SDL_GL_DeleteContext(display.glcontext); + SDL_DestroyWindow(display.window); } -int Display::Initialize( +int display_initialize( bool fullscreen, int *steps, bool *paused, @@ -50,22 +56,22 @@ int Display::Initialize( int window_mode = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE; /* init the backbuffer */ - back_buffer = (unsigned char **) malloc(WIDTH * sizeof(unsigned char *)); + display.back_buffer = (unsigned char **) malloc(WIDTH * sizeof(unsigned char *)); const char *err_str = "Unable to allocate memory on the heap.\n"; - if(!back_buffer) { + if(!display.back_buffer) { fprintf(stderr, "%s", err_str); return 1; } - memset(back_buffer, 0, WIDTH * sizeof(unsigned char *)); + memset(display.back_buffer, 0, WIDTH * sizeof(unsigned char *)); for (int i = 0; i < WIDTH; i++) { - back_buffer[i] = (unsigned char *) malloc(HEIGHT * sizeof(unsigned char)); - if(!back_buffer[i]) { + display.back_buffer[i] = (unsigned char *) malloc(HEIGHT * sizeof(unsigned char)); + if(!display.back_buffer[i]) { fprintf(stderr, "%s", err_str); return 1; } - memset(back_buffer[i], 0, HEIGHT * sizeof(unsigned char)); + memset(display.back_buffer[i], 0, HEIGHT * sizeof(unsigned char)); } /* setup window with openGL context */ @@ -75,21 +81,21 @@ int Display::Initialize( SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2); - window = SDL_CreateWindow( + display.window = SDL_CreateWindow( "Kiwi8", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, - WINDOW_WIDTH, - WINDOW_HEIGHT, + display.WINDOW_WIDTH, + display.WINDOW_HEIGHT, window_mode ); - if (window == NULL) { + if (display.window == NULL) { fprintf(stderr, "Error: %s\n", SDL_GetError()); return 1; } - glcontext = SDL_GL_CreateContext(window); + display.glcontext = SDL_GL_CreateContext(display.window); /* disable V-Sync */ SDL_GL_SetSwapInterval(0); @@ -104,7 +110,7 @@ int Display::Initialize( 0, GL_RGB, GL_UNSIGNED_BYTE, - (GLvoid *) texture + (GLvoid *) display.texture ); /* configure the texture */ @@ -115,8 +121,8 @@ int Display::Initialize( glEnable(GL_TEXTURE_2D); /* setup ImGui binding */ - gui.Initialize( - this, + gui_initialize( + &display, steps, paused, load_store_quirk, @@ -126,79 +132,79 @@ int Display::Initialize( ); /* set to fullscreen mode if flag present */ - if (fullscreen) ToggleFullscreen(); + if (fullscreen) display_toggle_fullscreen(); return 0; } -void Display::Resize(int x, int y) { +void display_resize(int x, int y) { /* get the current window size */ - WINDOW_WIDTH = x; - WINDOW_HEIGHT = y; + display.WINDOW_WIDTH = x; + display.WINDOW_HEIGHT = y; } -void Display::ToggleFullscreen() { +void display_toggle_fullscreen(void) { /* check if already fullscreen */ - if (SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN_DESKTOP) { + if (SDL_GetWindowFlags(display.window) & SDL_WINDOW_FULLSCREEN_DESKTOP) { /* set windowed */ - SDL_SetWindowFullscreen(window, 0); + SDL_SetWindowFullscreen(display.window, 0); SDL_ShowCursor(SDL_ENABLE); - fullscreen_flag = 0; + display.fullscreen_flag = 0; } else { /* set fullscreen */ - SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP); + SDL_SetWindowFullscreen(display.window, SDL_WINDOW_FULLSCREEN_DESKTOP); /* currently, a new ImGui Frame will draw the mouse cursor regardless of SDL2's cursor visibility function */ SDL_ShowCursor(SDL_DISABLE); - fullscreen_flag = 1; + display.fullscreen_flag = 1; } } -void Display::ToggleVsync() { +void display_toggle_vsync(void) { if (SDL_GL_GetSwapInterval()) { SDL_GL_SetSwapInterval(0); - vsync_flag = 0; + display.vsync_flag = 0; } else { SDL_GL_SetSwapInterval(1); - vsync_flag = 1; + display.vsync_flag = 1; } } -void Display::RaiseWindow() { - SDL_RaiseWindow(window); - lost_window_focus = 0; +void display_raise_window(void) { + SDL_RaiseWindow(display.window); + display.lost_window_focus = 0; } -void Display::RenderFrame(unsigned char **frame){ - gui.NewFrame(); +void display_render_frame(unsigned char **frame){ + gui_new_frame(); /* copy the frame to back_buffer */ if (frame != NULL) { for (int i = 0; i < WIDTH; i++) { - memcpy(back_buffer[i], frame[i], HEIGHT * sizeof(unsigned char)); + memcpy(display.back_buffer[i], frame[i], HEIGHT * sizeof(unsigned char)); } } /* set Viewport & Clear the screen (sets the background color) */ - glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT); + glViewport(0, 0, display.WINDOW_WIDTH, display.WINDOW_HEIGHT); glClearColor(0.0, 0.0, 0.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); for (int i = 0; i < WIDTH; i++){ for (int j = 0; j < HEIGHT; j++){ - if (back_buffer[i][HEIGHT-j-1]) { + if (display.back_buffer[i][HEIGHT-j-1]) { /* Fill the foreground pixel */ - texture[j][i][0] = (unsigned char)(foreground_color[0] * (float) 0xFF); //R - texture[j][i][1] = (unsigned char)(foreground_color[1] * (float) 0xFF); //G - texture[j][i][2] = (unsigned char)(foreground_color[2] * (float) 0xFF); //B + display.texture[j][i][0] = (unsigned char)(display.foreground_color[0] * (float) 0xFF); //R + display.texture[j][i][1] = (unsigned char)(display.foreground_color[1] * (float) 0xFF); //G + display.texture[j][i][2] = (unsigned char)(display.foreground_color[2] * (float) 0xFF); //B } else { /* Fill the background pixel */ - texture[j][i][0] = (unsigned char)(background_color[0] * (float) 0xFF); //R - texture[j][i][1] = (unsigned char)(background_color[1] * (float) 0xFF); //G - texture[j][i][2] = (unsigned char)(background_color[2] * (float) 0xFF); //B + display.texture[j][i][0] = (unsigned char)(display.background_color[0] * (float) 0xFF); //R + display.texture[j][i][1] = (unsigned char)(display.background_color[1] * (float) 0xFF); //G + display.texture[j][i][2] = (unsigned char)(display.background_color[2] * (float) 0xFF); //B } } } @@ -213,12 +219,12 @@ void Display::RenderFrame(unsigned char **frame){ HEIGHT, GL_RGB, GL_UNSIGNED_BYTE, - (GLvoid *) texture + (GLvoid *) display.texture ); /* create room at the top for menu bar */ float top_edge = gui.show_menu_flag ? - (float)(WINDOW_HEIGHT - MENU_HEIGHT) / WINDOW_HEIGHT : (float) 1.0; + (float)(display.WINDOW_HEIGHT - MENU_HEIGHT) / display.WINDOW_HEIGHT : (float) 1.0; /* render the texture */ glBegin(GL_QUADS); @@ -241,6 +247,6 @@ void Display::RenderFrame(unsigned char **frame){ glEnd(); - gui.Render(); - SDL_GL_SwapWindow(window); + gui_render(); + SDL_GL_SwapWindow(display.window); } diff --git a/shared/Display.h b/shared/Display.h index 4dfc9734..97efb020 100644 --- a/shared/Display.h +++ b/shared/Display.h @@ -17,55 +17,49 @@ #define DEFAULT_FOREGROUND_G 200 #define DEFAULT_FOREGROUND_B 255 -class Display { +struct display { + SDL_GLContext glcontext; - private: + /* texture of 32x64x3 bytes (R, G, B) */ + unsigned char texture[HEIGHT][WIDTH][3]; - SDL_GLContext glcontext; + /* most recent copy of the chip8 vram */ + unsigned char **back_buffer; - /* texture of 32x64x3 bytes (R, G, B) */ - unsigned char texture[HEIGHT][WIDTH][3]; + int WINDOW_WIDTH; + int WINDOW_HEIGHT; - /* most recent copy of the chip8 vram */ - unsigned char **back_buffer; + bool fullscreen_flag; + bool vsync_flag; + bool limit_fps_flag; + bool lost_window_focus; - int WINDOW_WIDTH; - int WINDOW_HEIGHT; + /* RGB colors for foreground/background */ + float background_color[3]; + float foreground_color[3]; - - public: - - Gui gui; - - bool fullscreen_flag; - bool vsync_flag; - bool limit_fps_flag; - bool lost_window_focus; - - /* RGB colors for foreground/background */ - float background_color[3]; - float foreground_color[3]; - - SDL_Window *window; - - Display(); - ~Display(); - - int Initialize( - bool fullscreen, - int *cycles, - bool *paused, - bool *load_store_quirk, - bool *shift_quirk, - bool *vwrap, - bool *muted - ); - - void Resize(int x, int y); - void ToggleFullscreen(); - void ToggleVsync(); - void RaiseWindow(); - void RenderFrame(unsigned char **frame); + SDL_Window *window; }; +/* Global display instance */ +extern struct display display; + +/* Display functions */ +void display_create(void); +void display_destroy(void); +int display_initialize( + bool fullscreen, + int *cycles, + bool *paused, + bool *load_store_quirk, + bool *shift_quirk, + bool *vwrap, + bool *muted +); +void display_resize(int x, int y); +void display_toggle_fullscreen(void); +void display_toggle_vsync(void); +void display_raise_window(void); +void display_render_frame(unsigned char **frame); + #endif diff --git a/shared/Gui.cc b/shared/Gui.cc index 51c93398..e5dc709e 100644 --- a/shared/Gui.cc +++ b/shared/Gui.cc @@ -4,25 +4,32 @@ #include "license.h" // Generated at build time from LICENSE #include -Gui::Gui() { - soft_reset_flag = 0; - load_rom_flag = 0; - quit_flag = 0; - show_menu_flag = 1; - show_fps_flag = 0; - - show_controls = 0; - show_license = 0; - show_about = 0; - show_usage = 0; +/* Forward declarations for static helpers */ +static void gui_main_menu(void); +static void gui_help_windows(void); + +/* Global gui instance */ +struct gui gui; + +void gui_create(void) { + gui.soft_reset_flag = 0; + gui.load_rom_flag = 0; + gui.quit_flag = 0; + gui.show_menu_flag = 1; + gui.show_fps_flag = 0; + + gui.show_controls = 0; + gui.show_license = 0; + gui.show_about = 0; + gui.show_usage = 0; } -Gui::~Gui() { +void gui_cleanup(void) { ImGui_ImplSdl_Shutdown(); } -void Gui::Initialize( - Display *display, +void gui_initialize( + struct display *display, int *cycles, bool *paused, bool *load_store_quirk, @@ -31,15 +38,15 @@ void Gui::Initialize( bool *mute ) { - this->display = display; + gui.display = display; /* connect pointers to chip8 toggles */ - this->cycles = cycles; - this->paused = paused; - this->load_store_quirk = load_store_quirk; - this->shift_quirk = shift_quirk; - this->vwrap = vwrap; - this->mute = mute; + gui.cycles = cycles; + gui.paused = paused; + gui.load_store_quirk = load_store_quirk; + gui.shift_quirk = shift_quirk; + gui.vwrap = vwrap; + gui.mute = mute; ImGui_ImplSdl_Init(display->window); @@ -47,64 +54,64 @@ void Gui::Initialize( ImGui::GetIO().IniFilename = NULL; } -void Gui::ProcessEvents(SDL_Event *event) { +void gui_process_events(SDL_Event *event) { ImGui_ImplSdl_ProcessEvent(event); } -void Gui::NewFrame() { - ImGui_ImplSdl_NewFrame(display->window); - MainMenu(); +void gui_new_frame(void) { + ImGui_ImplSdl_NewFrame(display.window); + gui_main_menu(); } -void Gui::MainMenu() { +static void gui_main_menu(void) { bool before; - if (show_menu_flag) { + if (gui.show_menu_flag) { if (ImGui::BeginMainMenuBar()) { if (ImGui::BeginMenu("File")) { - ImGui::MenuItem("Load ROM...", NULL, &load_rom_flag); - ImGui::MenuItem("Exit", "Esc", &quit_flag); + ImGui::MenuItem("Load ROM...", NULL, &gui.load_rom_flag); + ImGui::MenuItem("Exit", "Esc", &gui.quit_flag); ImGui::EndMenu(); } if (ImGui::BeginMenu("View")) { - ImGui::MenuItem("Show Menu", "Left-Alt", &show_menu_flag); - ImGui::MenuItem("Show FPS", "Right-Alt", &show_fps_flag); + ImGui::MenuItem("Show Menu", "Left-Alt", &gui.show_menu_flag); + ImGui::MenuItem("Show FPS", "Right-Alt", &gui.show_fps_flag); /* fullscreen toggle */ - before = display->fullscreen_flag; - ImGui::MenuItem("Fullscreen", "Enter", &(display->fullscreen_flag)); - if (before != display->fullscreen_flag) display->ToggleFullscreen(); + before = display.fullscreen_flag; + ImGui::MenuItem("Fullscreen", "Enter", &(display.fullscreen_flag)); + if (before != display.fullscreen_flag) display_toggle_fullscreen(); ImGui::EndMenu(); } if (ImGui::BeginMenu("Emulation")) { - ImGui::MenuItem("Reset", "F5", &soft_reset_flag); - ImGui::MenuItem("Pause", "P", paused); + ImGui::MenuItem("Reset", "F5", &gui.soft_reset_flag); + ImGui::MenuItem("Pause", "P", gui.paused); /* CPU frequency */ if (ImGui::BeginMenu("CPU Frequency")){ ImGui::MenuItem("", "PageDown/PageUp", !!0); - int cpu_frequency = *cycles * TICKS; + int cpu_frequency = *(gui.cycles) * TICKS; ImGui::SliderInt("Hz", &cpu_frequency, TICKS, TICKS * MAX_CYCLES_PER_STEP, "%.f"); - *cycles = cpu_frequency / TICKS; - before = (*cycles == CYCLES_PER_STEP); + *(gui.cycles) = cpu_frequency / TICKS; + before = (*(gui.cycles) == CYCLES_PER_STEP); ImGui::MenuItem("Default", "720 Hz", &before); - if (before) *cycles = CYCLES_PER_STEP; + if (before) *(gui.cycles) = CYCLES_PER_STEP; ImGui::EndMenu(); } - ImGui::MenuItem("Load/Store Quirk", NULL, load_store_quirk); - ImGui::MenuItem("Shift Quirk", NULL, shift_quirk); - ImGui::MenuItem("Vertical Wrapping", NULL, vwrap); + ImGui::MenuItem("Load/Store Quirk", NULL, gui.load_store_quirk); + ImGui::MenuItem("Shift Quirk", NULL, gui.shift_quirk); + ImGui::MenuItem("Vertical Wrapping", NULL, gui.vwrap); ImGui::EndMenu(); } if (ImGui::BeginMenu("Settings")) { - ImGui::MenuItem("Mute Audio", "M", mute); - ImGui::MenuItem("60 FPS Limit", NULL, &(display->limit_fps_flag)); + ImGui::MenuItem("Mute Audio", "M", gui.mute); + ImGui::MenuItem("60 FPS Limit", NULL, &(display.limit_fps_flag)); /* toggle Vsync is disabled for now because it doesn't really @@ -124,24 +131,24 @@ void Gui::MainMenu() { /* color chooser */ if (ImGui::BeginMenu("Colors")) { - ImGui::ColorEdit3("Background", display->background_color); - ImGui::ColorEdit3("Foreground", display->foreground_color); + ImGui::ColorEdit3("Background", display.background_color); + ImGui::ColorEdit3("Foreground", display.foreground_color); before = ( - display->background_color[0] == ((float) DEFAULT_BACKGROUND_R / (float) 0xFF) && - display->background_color[1] == ((float) DEFAULT_BACKGROUND_G / (float) 0xFF) && - display->background_color[2] == ((float) DEFAULT_BACKGROUND_B / (float) 0xFF) && - display->foreground_color[0] == ((float) DEFAULT_FOREGROUND_R / (float) 0xFF) && - display->foreground_color[1] == ((float) DEFAULT_FOREGROUND_G / (float) 0xFF) && - display->foreground_color[2] == ((float) DEFAULT_FOREGROUND_B / (float) 0xFF) + display.background_color[0] == ((float) DEFAULT_BACKGROUND_R / (float) 0xFF) && + display.background_color[1] == ((float) DEFAULT_BACKGROUND_G / (float) 0xFF) && + display.background_color[2] == ((float) DEFAULT_BACKGROUND_B / (float) 0xFF) && + display.foreground_color[0] == ((float) DEFAULT_FOREGROUND_R / (float) 0xFF) && + display.foreground_color[1] == ((float) DEFAULT_FOREGROUND_G / (float) 0xFF) && + display.foreground_color[2] == ((float) DEFAULT_FOREGROUND_B / (float) 0xFF) ); ImGui::MenuItem("Default", NULL, &before); if (before) { - display->background_color[0] = (float) DEFAULT_BACKGROUND_R / (float) 0xFF; - display->background_color[1] = (float) DEFAULT_BACKGROUND_G / (float) 0xFF; - display->background_color[2] = (float) DEFAULT_BACKGROUND_B / (float) 0xFF; - display->foreground_color[0] = (float) DEFAULT_FOREGROUND_R / (float) 0xFF; - display->foreground_color[1] = (float) DEFAULT_FOREGROUND_G / (float) 0xFF; - display->foreground_color[2] = (float) DEFAULT_FOREGROUND_B / (float) 0xFF; + display.background_color[0] = (float) DEFAULT_BACKGROUND_R / (float) 0xFF; + display.background_color[1] = (float) DEFAULT_BACKGROUND_G / (float) 0xFF; + display.background_color[2] = (float) DEFAULT_BACKGROUND_B / (float) 0xFF; + display.foreground_color[0] = (float) DEFAULT_FOREGROUND_R / (float) 0xFF; + display.foreground_color[1] = (float) DEFAULT_FOREGROUND_G / (float) 0xFF; + display.foreground_color[2] = (float) DEFAULT_FOREGROUND_B / (float) 0xFF; } ImGui::EndMenu(); } @@ -149,23 +156,23 @@ void Gui::MainMenu() { } if (ImGui::BeginMenu("Help")) { - ImGui::MenuItem("Usage", NULL, &show_usage); - ImGui::MenuItem("Controls", NULL, &show_controls); - ImGui::MenuItem("License", NULL, &show_license); - ImGui::MenuItem("About", NULL, &show_about); + ImGui::MenuItem("Usage", NULL, &gui.show_usage); + ImGui::MenuItem("Controls", NULL, &gui.show_controls); + ImGui::MenuItem("License", NULL, &gui.show_license); + ImGui::MenuItem("About", NULL, &gui.show_about); ImGui::EndMenu(); } ImGui::EndMainMenuBar(); } } - HelpWindows(); + gui_help_windows(); } -void Gui::HelpWindows() { - if (show_usage) { +static void gui_help_windows(void) { + if (gui.show_usage) { ImGui::SetNextWindowSize(ImVec2(270, 150), ImGuiSetCond_Appearing); ImGui::SetNextWindowPosCenter(ImGuiSetCond_Appearing); - ImGui::Begin("Usage", &show_usage); + ImGui::Begin("Usage", &gui.show_usage); ImGui::TextWrapped( "Alternatively, you may launch Kiwi8\n" @@ -181,10 +188,10 @@ void Gui::HelpWindows() { ImGui::End(); } - if (show_controls) { + if (gui.show_controls) { ImGui::SetNextWindowSize(ImVec2(345, 245), ImGuiSetCond_Appearing); ImGui::SetNextWindowPosCenter(ImGuiSetCond_Appearing); - ImGui::Begin("Controls", &show_controls); + ImGui::Begin("Controls", &gui.show_controls); ImGui::TextWrapped( "The Chip-8 uses a 16 digit hexadecimal keypad.\n" @@ -207,19 +214,19 @@ void Gui::HelpWindows() { ImGui::End(); } - if (show_license) { + if (gui.show_license) { ImGui::SetNextWindowSize(ImVec2(500, 230), ImGuiSetCond_Appearing); ImGui::SetNextWindowPosCenter(ImGuiSetCond_Appearing); - ImGui::Begin("License", &show_license); + ImGui::Begin("License", &gui.show_license); ImGui::TextWrapped("%s", LICENSE_TEXT); ImGui::End(); } - if (show_about) { + if (gui.show_about) { ImGui::SetNextWindowSize(ImVec2(330, 120), ImGuiSetCond_Appearing); ImGui::SetNextWindowPosCenter(ImGuiSetCond_Appearing); - ImGui::Begin("About", &show_about); + ImGui::Begin("About", &gui.show_about); // Truncate COMMIT_HASH to first 7 characters for display char short_hash[8]; @@ -237,15 +244,15 @@ void Gui::HelpWindows() { ImGui::End(); } - if (show_fps_flag) { - if (show_menu_flag) { + if (gui.show_fps_flag) { + if (gui.show_menu_flag) { ImGui::SetNextWindowPos(ImVec2(1, 21)); } else { ImGui::SetNextWindowPos(ImVec2(1, 2)); } if (!ImGui::Begin( "FPS", - &show_fps_flag, + &gui.show_fps_flag, ImVec2(0, 0), 0.3f, ImGuiWindowFlags_NoTitleBar | @@ -268,6 +275,6 @@ void Gui::HelpWindows() { } } -void Gui::Render() { +void gui_render(void) { ImGui::Render(); } diff --git a/shared/Gui.h b/shared/Gui.h index e64f3f81..22e7c6e3 100644 --- a/shared/Gui.h +++ b/shared/Gui.h @@ -8,57 +8,49 @@ #define MENU_HEIGHT 38 /* forward declaration */ -class Display; - -class Gui { - - private: - - /* pointers to chip-8 data */ - Display *display; - - int *cycles; - bool *paused; - bool *load_store_quirk; - bool *shift_quirk; - bool *vwrap; - bool *mute; - - /* help-window toggles */ - bool show_controls; - bool show_license; - bool show_about; - bool show_usage; - - void MainMenu(); - void HelpWindows(); - - public: - - bool soft_reset_flag; - bool load_rom_flag; - bool quit_flag; - bool show_menu_flag; - bool show_fps_flag; - - Gui(); - ~Gui(); - - void Initialize( - Display *display, - int *cycles, - bool *paused, - bool *load_store_quirk, - bool *shift_quirk, - bool *vwrap, - bool *mute - ); - - void ProcessEvents(SDL_Event *event); - void NewFrame(); - void Render(); - - +struct display; + +struct gui { + /* pointers to chip-8 data */ + struct display *display; + + int *cycles; + bool *paused; + bool *load_store_quirk; + bool *shift_quirk; + bool *vwrap; + bool *mute; + + /* help-window toggles */ + bool show_controls; + bool show_license; + bool show_about; + bool show_usage; + + bool soft_reset_flag; + bool load_rom_flag; + bool quit_flag; + bool show_menu_flag; + bool show_fps_flag; }; +/* Global gui instance */ +extern struct gui gui; + +/* Gui functions */ +void gui_create(void); +void gui_cleanup(void); +void gui_initialize( + struct display *display, + int *cycles, + bool *paused, + bool *load_store_quirk, + bool *shift_quirk, + bool *vwrap, + bool *mute +); +void gui_process_events(SDL_Event *event); +void gui_new_frame(void); +void gui_render(void); + #endif diff --git a/shared/Input.cc b/shared/Input.cc index aac6cf53..c4feebcb 100644 --- a/shared/Input.cc +++ b/shared/Input.cc @@ -1,123 +1,130 @@ #include "Chip8.h" #include "Input.h" #include "Display.h" +/* Forward declarations for static helpers */ +static int input_process_events(void); +static void input_process_keys(void); -Input::Input() { + +/* Global input instance */ +struct input input; + +void input_create(void) { /* empty */ } -Input::~Input() { +void input_destroy(void) { /* empty */ } -void Input::Initialize( - Display *display, +void input_initialize( + struct display *display, int *cycles, bool *cpu_halt, bool *paused, bool *muted ) { - this->cycles = cycles; - this->display = display; - this->cpu_halt = cpu_halt; - this->paused = paused; - this->muted = muted; - Reset(); + input.cycles = cycles; + input.display = display; + input.cpu_halt = cpu_halt; + input.paused = paused; + input.muted = muted; + input_reset(); } -void Input::Reset() { - awaiting_key_press = 0; - memset(keys, 0, NUM_KEYS); +void input_reset(void) { + input.awaiting_key_press = 0; + memset(input.keys, 0, NUM_KEYS); } -int Input::Poll() { +int input_poll(void) { int response = CONTINUE; /* purge any queued events */ - while (SDL_PollEvent(&event)) { + while (SDL_PollEvent(&input.event)) { - state = SDL_GetKeyboardState(NULL); + input.state = SDL_GetKeyboardState(NULL); /* check GUI */ - display->gui.ProcessEvents(&event); - if (display->gui.quit_flag) response |= USER_QUIT; - if (display->gui.soft_reset_flag) response |= SOFT_RESET; - if (display->gui.load_rom_flag) response |= LOAD_ROM; + gui_process_events(&input.event); + if (gui.quit_flag) response |= USER_QUIT; + if (gui.soft_reset_flag) response |= SOFT_RESET; + if (gui.load_rom_flag) response |= LOAD_ROM; /* check SDL events (window & hotkeys) */ - response |= ProcessEvents(); + response |= input_process_events(); /* check chip-8 input */ - ProcessKeys(); + input_process_keys(); } return response; } -int Input::ProcessEvents() { +static int input_process_events(void) { int response = CONTINUE; /* cose when the user clicks 'X' */ - if (event.type == SDL_QUIT) response = USER_QUIT; + if (input.event.type == SDL_QUIT) response = USER_QUIT; /* keystroke events */ - if (event.type == SDL_KEYDOWN) { - if (state[SDL_SCANCODE_ESCAPE]) response = USER_QUIT; - if (state[SDL_SCANCODE_F5]) response = SOFT_RESET; - if (state[SDL_SCANCODE_RETURN]) display->ToggleFullscreen(); - if (state[SDL_SCANCODE_P]) *paused = !(*paused); - if (state[SDL_SCANCODE_M]) *muted = !(*muted); - if (state[SDL_SCANCODE_LALT]) display->gui.show_menu_flag = !display->gui.show_menu_flag; - if (state[SDL_SCANCODE_RALT]) display->gui.show_fps_flag = !display->gui.show_fps_flag; + if (input.event.type == SDL_KEYDOWN) { + if (input.state[SDL_SCANCODE_ESCAPE]) response = USER_QUIT; + if (input.state[SDL_SCANCODE_F5]) response = SOFT_RESET; + if (input.state[SDL_SCANCODE_RETURN]) display_toggle_fullscreen(); + if (input.state[SDL_SCANCODE_P]) *(input.paused) = !(*(input.paused)); + if (input.state[SDL_SCANCODE_M]) *(input.muted) = !(*(input.muted)); + if (input.state[SDL_SCANCODE_LALT]) gui.show_menu_flag = !gui.show_menu_flag; + if (input.state[SDL_SCANCODE_RALT]) gui.show_fps_flag = !gui.show_fps_flag; /* slow/raise emulation speed */ - if (state[SDL_SCANCODE_PAGEDOWN]) (*cycles -1 < MIN_CYCLES_PER_STEP ) ? *cycles = MIN_CYCLES_PER_STEP : *cycles -= 1; - if (state[SDL_SCANCODE_PAGEUP]) (*cycles +1 > MAX_CYCLES_PER_STEP ) ? *cycles = MAX_CYCLES_PER_STEP : *cycles += 1; + if (input.state[SDL_SCANCODE_PAGEDOWN]) (*(input.cycles) -1 < MIN_CYCLES_PER_STEP ) ? *(input.cycles) = MIN_CYCLES_PER_STEP : *(input.cycles) -= 1; + if (input.state[SDL_SCANCODE_PAGEUP]) (*(input.cycles) +1 > MAX_CYCLES_PER_STEP ) ? *(input.cycles) = MAX_CYCLES_PER_STEP : *(input.cycles) += 1; } /* window events */ - if (event.window.type == SDL_WINDOWEVENT){ + if (input.event.window.type == SDL_WINDOWEVENT){ /* update the current rendering screen space */ - if (event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) display->Resize(event.window.data1, event.window.data2); + if (input.event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) display_resize(input.event.window.data1, input.event.window.data2); - if (event.window.event == SDL_WINDOWEVENT_FOCUS_GAINED) { + if (input.event.window.event == SDL_WINDOWEVENT_FOCUS_GAINED) { /* TODO: resume the emulator, if paused_on_focus_loss */ } - if (event.window.event == SDL_WINDOWEVENT_FOCUS_LOST) { + if (input.event.window.event == SDL_WINDOWEVENT_FOCUS_LOST) { /* focus is lost when a user tries to laod a rom */ - if (display->lost_window_focus) display->RaiseWindow(); + if (display.lost_window_focus) display_raise_window(); } /* the window manager requests that the window be closed */ - if (event.window.event == SDL_WINDOWEVENT_CLOSE) response = USER_QUIT; + if (input.event.window.event == SDL_WINDOWEVENT_CLOSE) response = USER_QUIT; } return response; } -void Input::ProcessKeys() { +static void input_process_keys(void) { /* map the state of the keys */ - keys[0x1] = state[SDL_SCANCODE_1]; - keys[0x2] = state[SDL_SCANCODE_2]; - keys[0x3] = state[SDL_SCANCODE_3]; - keys[0xC] = state[SDL_SCANCODE_4]; - keys[0x4] = state[SDL_SCANCODE_Q]; - keys[0x5] = state[SDL_SCANCODE_W]; - keys[0x6] = state[SDL_SCANCODE_E]; - keys[0xD] = state[SDL_SCANCODE_R]; - keys[0x7] = state[SDL_SCANCODE_A]; - keys[0x8] = state[SDL_SCANCODE_S]; - keys[0x9] = state[SDL_SCANCODE_D]; - keys[0xE] = state[SDL_SCANCODE_F]; - keys[0xA] = state[SDL_SCANCODE_Z]; - keys[0x0] = state[SDL_SCANCODE_X]; - keys[0xB] = state[SDL_SCANCODE_C]; - keys[0xF] = state[SDL_SCANCODE_V]; + input.keys[0x1] = input.state[SDL_SCANCODE_1]; + input.keys[0x2] = input.state[SDL_SCANCODE_2]; + input.keys[0x3] = input.state[SDL_SCANCODE_3]; + input.keys[0xC] = input.state[SDL_SCANCODE_4]; + input.keys[0x4] = input.state[SDL_SCANCODE_Q]; + input.keys[0x5] = input.state[SDL_SCANCODE_W]; + input.keys[0x6] = input.state[SDL_SCANCODE_E]; + input.keys[0xD] = input.state[SDL_SCANCODE_R]; + input.keys[0x7] = input.state[SDL_SCANCODE_A]; + input.keys[0x8] = input.state[SDL_SCANCODE_S]; + input.keys[0x9] = input.state[SDL_SCANCODE_D]; + input.keys[0xE] = input.state[SDL_SCANCODE_F]; + input.keys[0xA] = input.state[SDL_SCANCODE_Z]; + input.keys[0x0] = input.state[SDL_SCANCODE_X]; + input.keys[0xB] = input.state[SDL_SCANCODE_C]; + input.keys[0xF] = input.state[SDL_SCANCODE_V]; /* check if cpu is awaiting a keypress for opcode FX0A */ - if (cpu_halt && awaiting_key_press) { + if (input.cpu_halt && input.awaiting_key_press) { for (int i = 0; i < NUM_KEYS; i++) { - if (keys[i]) { - awaiting_key_press = 0; + if (input.keys[i]) { + input.awaiting_key_press = 0; } } } diff --git a/shared/Input.h b/shared/Input.h index d82c59a7..949435da 100644 --- a/shared/Input.h +++ b/shared/Input.h @@ -13,45 +13,41 @@ can represent a unique bit position */ #define LOAD_ROM 4 /* forward declaration */ -class Display; +struct display; -class Input { - private: - /* for processing window/keyboard events */ - SDL_Event event; - const unsigned char *state; +struct input { + /* for processing window/keyboard events */ + SDL_Event event; + const unsigned char *state; - Display *display; + struct display *display; - int *cycles; - bool *cpu_halt; - bool *paused; - bool *muted; + int *cycles; + bool *cpu_halt; + bool *paused; + bool *muted; - int ProcessEvents(); - void ProcessKeys(); - - public: - Input(); - ~Input(); - - /* chip-8 HEX based keypad (0x0-0xF) */ - unsigned char keys[NUM_KEYS]; - - /* for opcode 0xFX0A */ - bool awaiting_key_press; - - void Initialize( - Display *display, - int *cycles, - bool *cpu_halt, - bool *paused, - bool *muted - ); - - void Reset(); - int Poll(); + /* chip-8 HEX based keypad (0x0-0xF) */ + unsigned char keys[NUM_KEYS]; + /* for opcode 0xFX0A */ + bool awaiting_key_press; }; +/* Global input instance */ +extern struct input input; + +/* Input functions */ +void input_create(void); +void input_destroy(void); +void input_initialize( + struct display *display, + int *cycles, + bool *cpu_halt, + bool *paused, + bool *muted +); +void input_reset(void); +int input_poll(void); + #endif diff --git a/shared/main.cc b/shared/main.cc index a130477e..cbd29c92 100644 --- a/shared/main.cc +++ b/shared/main.cc @@ -13,7 +13,7 @@ int main(int argc, char **argv){ bool shift_quirk = 1; bool vwrap = 1; bool muted = 0; - Chip8 chip = Chip8(); + chip8_create(); /* parse and set any options present */ for (int i = 1; i < argc; i++){ @@ -38,7 +38,7 @@ int main(int argc, char **argv){ } /* calling initialize() also loads the bootrom */ - if (chip.Initialize( + if (chip8_initialize( fullscreen, load_store_quirk, shift_quirk, @@ -49,9 +49,10 @@ int main(int argc, char **argv){ /* load ROM from argument vector */ if (argc >= 2 && *argv[1] != '-') { - if (chip.Load(argv[1])) return 1; + if (chip8_load(argv[1])) return 1; } - chip.Run(); + chip8_run(); + chip8_destroy(); return 0; } diff --git a/shared/opcodes.cc b/shared/opcodes.cc index 3dcd6b12..4eeb5201 100644 --- a/shared/opcodes.cc +++ b/shared/opcodes.cc @@ -3,180 +3,180 @@ #include /* rand() */ /* Decode the instruction */ -#define OP ((opcode & 0xF000) >> 12) -#define OP_NNN (opcode & 0x0FFF) -#define OP_NN (opcode & 0x00FF) -#define OP_N (opcode & 0x000F) -#define OP_X ((opcode & 0x0F00) >> 8) -#define OP_Y ((opcode & 0x00F0) >> 4) - -inline void Chip8::exec00E0() { +#define OP ((chip8.opcode & 0xF000) >> 12) +#define OP_NNN (chip8.opcode & 0x0FFF) +#define OP_NN (chip8.opcode & 0x00FF) +#define OP_N (chip8.opcode & 0x000F) +#define OP_X ((chip8.opcode & 0x0F00) >> 8) +#define OP_Y ((chip8.opcode & 0x00F0) >> 4) + +inline void exec00E0() { /* 0x00E0: clears the screen */ for (int i = 0; i < WIDTH; i++) { - memset(vram[i], 0, HEIGHT * sizeof(unsigned char)); + memset(chip8.vram[i], 0, HEIGHT * sizeof(unsigned char)); } - draw_flag = 1; - PC += 2; + chip8.draw_flag = 1; + chip8.PC += 2; } -inline void Chip8::exec00EE() { +inline void exec00EE() { /* 0x00EE: returns from subroutine */ - sp--; - PC = stack[sp]; - PC += 2; + chip8.sp--; + chip8.PC = chip8.stack[chip8.sp]; + chip8.PC += 2; } -inline void Chip8::exec0NNN() { +inline void exec0NNN() { /* 0x0NNN: SYS addr - jump to a machine code routine at nnn. This instruction is only used on the old computers on which Chip-8 was originally implemented. It is ignored by modern interpreters. */ - PC += 2; + chip8.PC += 2; } -inline void Chip8::exec1NNN() { +inline void exec1NNN() { /* 0x1NNN: jumps to address NNN */ - PC = OP_NNN; + chip8.PC = OP_NNN; } -inline void Chip8::exec2NNN() { +inline void exec2NNN() { /* 0x2NNN: calls subroutine at NNN */ - stack[sp] = PC; - sp++; - PC = OP_NNN; + chip8.stack[chip8.sp] = chip8.PC; + chip8.sp++; + chip8.PC = OP_NNN; } -inline void Chip8::exec3XNN() { +inline void exec3XNN() { /* 0x3XNN: skips the next instruction if VX equals NN */ - if (V[OP_X] == OP_NN) PC += 2; - PC += 2; + if (chip8.V[OP_X] == OP_NN) chip8.PC += 2; + chip8.PC += 2; } -inline void Chip8::exec4XNN() { +inline void exec4XNN() { /* 0x4XNN: skips the next instruction if VX doesn't equal NN */ - if (V[OP_X] != OP_NN) PC += 2; - PC += 2; + if (chip8.V[OP_X] != OP_NN) chip8.PC += 2; + chip8.PC += 2; } -inline void Chip8::exec5XY0() { +inline void exec5XY0() { /* 0x5XY0: skips the next instruction if VX equals VY */ - if (V[OP_X] == V[OP_Y]) PC += 2; - PC += 2; + if (chip8.V[OP_X] == chip8.V[OP_Y]) chip8.PC += 2; + chip8.PC += 2; } -inline void Chip8::exec6XNN() { +inline void exec6XNN() { /* 0x6XNN: sets VX to NN */ - V[OP_X] = OP_NN; - PC += 2; + chip8.V[OP_X] = OP_NN; + chip8.PC += 2; } -inline void Chip8::exec7XNN() { +inline void exec7XNN() { /* 0x7XNN: adds NN to VX */ - V[OP_X] += OP_NN; - PC += 2; + chip8.V[OP_X] += OP_NN; + chip8.PC += 2; } -inline void Chip8::exec8XY0() { +inline void exec8XY0() { /* 0x8XY0: sets VX to the value of VY */ - V[OP_X] = V[OP_Y]; - PC += 2; + chip8.V[OP_X] = chip8.V[OP_Y]; + chip8.PC += 2; } -inline void Chip8::exec8XY1() { +inline void exec8XY1() { /* 0x8XY1: sets VX to VX or VY */ - V[OP_X] |= V[OP_Y]; - PC += 2; + chip8.V[OP_X] |= chip8.V[OP_Y]; + chip8.PC += 2; } -inline void Chip8::exec8XY2() { +inline void exec8XY2() { /* 0x8XY2: sets VX to VX and VY */ - V[OP_X] &= V[OP_Y]; - PC += 2; + chip8.V[OP_X] &= chip8.V[OP_Y]; + chip8.PC += 2; } -inline void Chip8::exec8XY3() { +inline void exec8XY3() { /* 0x8XY3: sets VX to VX xor VY */ - V[OP_X] ^= V[OP_Y]; - PC += 2; + chip8.V[OP_X] ^= chip8.V[OP_Y]; + chip8.PC += 2; } -inline void Chip8::exec8XY4() { +inline void exec8XY4() { /* 0x8XY4: adds VY to VX. VF is set to 1 when there's a carry, and to 0 when there isn't */ unsigned short sum; - sum = V[OP_Y] + V[OP_X]; - (sum > 0xFF) ? V[0xF] = 1 : V[0xF] = 0; + sum = chip8.V[OP_Y] + chip8.V[OP_X]; + (sum > 0xFF) ? chip8.V[0xF] = 1 : chip8.V[0xF] = 0; /* only the lowest 8 bits are kept */ - V[OP_X] = (unsigned char) sum; - PC += 2; + chip8.V[OP_X] = (unsigned char) sum; + chip8.PC += 2; } -inline void Chip8::exec8XY5() { +inline void exec8XY5() { /* 0x8XY5: VY is subtracted from VX. VF is set to 0 when there's a borrow, and 1 when there isn't */ - (V[OP_Y] > V[OP_X]) ? V[0xF] = 0 : V[0xF] = 1; - V[OP_X] -= V[OP_Y]; - PC += 2; + (chip8.V[OP_Y] > chip8.V[OP_X]) ? chip8.V[0xF] = 0 : chip8.V[0xF] = 1; + chip8.V[OP_X] -= chip8.V[OP_Y]; + chip8.PC += 2; } -inline void Chip8::exec8XY6() { +inline void exec8XY6() { /* 0x8XY6: shifts VX right by one. VF is set to the value of the least significant bit of VX before the shift. */ - V[0xF] = V[OP_X] & 0x01; - shift_quirk? V[OP_X] >>= 1 : V[OP_X] = V[OP_Y] >> 1; - PC += 2; + chip8.V[0xF] = chip8.V[OP_X] & 0x01; + chip8.shift_quirk ? chip8.V[OP_X] >>= 1 : chip8.V[OP_X] = chip8.V[OP_Y] >> 1; + chip8.PC += 2; } -inline void Chip8::exec8XY7() { +inline void exec8XY7() { /* 0x8XY7: sets VX to VY minus VX. VF is set to 0 when there's a borrow, and 1 when there isn't. */ - (V[OP_X] > V[OP_Y]) ? V[0xF] = 0 : V[0xF] = 1; - V[OP_X] = V[OP_Y] - V[OP_X]; - PC += 2; + (chip8.V[OP_X] > chip8.V[OP_Y]) ? chip8.V[0xF] = 0 : chip8.V[0xF] = 1; + chip8.V[OP_X] = chip8.V[OP_Y] - chip8.V[OP_X]; + chip8.PC += 2; } -inline void Chip8::exec8XYE() { +inline void exec8XYE() { /* 0x8XYE: shifts VX left by one. VF is set to the value of the most significant bit of VX before the shift. */ - V[0xF] = (V[OP_X] & 0x80) >> 7; - shift_quirk ? V[OP_X] <<= 1 : V[OP_X] = V[OP_Y] << 1; - PC += 2; + chip8.V[0xF] = (chip8.V[OP_X] & 0x80) >> 7; + chip8.shift_quirk ? chip8.V[OP_X] <<= 1 : chip8.V[OP_X] = chip8.V[OP_Y] << 1; + chip8.PC += 2; } -inline void Chip8::exec9XY0() { +inline void exec9XY0() { /* 0x9XY0: skips the next instruction if VX doesn't equal VY */ - if (V[OP_X] != V[OP_Y]) PC +=2; - PC += 2; + if (chip8.V[OP_X] != chip8.V[OP_Y]) chip8.PC +=2; + chip8.PC += 2; } -inline void Chip8::execANNN() { +inline void execANNN() { /* ANNN: sets I to the address NNN */ - I = OP_NNN; - PC += 2; + chip8.I = OP_NNN; + chip8.PC += 2; } -inline void Chip8::execBNNN() { +inline void execBNNN() { /* BNNN: jumps to the address NNN plus V0 */ - PC = OP_NNN + V[0]; + chip8.PC = OP_NNN + chip8.V[0]; } -inline void Chip8::execCXNN() { +inline void execCXNN() { /* CXNN: sets VX to the result of a bitwise and operation on a random number and NN */ - V[OP_X] = (rand() % 0xFF) & OP_NN; - PC += 2; + chip8.V[OP_X] = (rand() % 0xFF) & OP_NN; + chip8.PC += 2; } -inline void Chip8::execDXYN() { +inline void execDXYN() { /* DXYN: draws a sprite at coordinate (VX, VY) that has a width of 8 vram and a height of N vram. Each row of 8 vram is read as bit-coded starting from memory location I; I value doesn’t change after the execution of this instruction. As described above, VF is set to 1 if any screen vram are flipped from set to unset when the sprite is drawn, and to 0 if that doesn’t happen */ - unsigned short x = V[OP_X]; - unsigned short y = V[OP_Y]; + unsigned short x = chip8.V[OP_X]; + unsigned short y = chip8.V[OP_Y]; unsigned short height = OP_N; unsigned short pixel; - V[0xF] = 0; + chip8.V[0xF] = 0; for (unsigned char yline = 0; yline < height; yline++) { - pixel = memory[I + yline]; + pixel = chip8.memory[chip8.I + yline]; for(unsigned char xline = 0; xline < 8; xline++) { if((pixel & (0x80 >> xline)) != 0) { @@ -185,123 +185,123 @@ inline void Chip8::execDXYN() { wrapping to the top of the screen if you (y % HEIGHT) */ unsigned char true_x = (x + xline) % WIDTH; unsigned char true_y = (y + yline); - if(vwrap) true_y = true_y % HEIGHT; + if(chip8.vwrap) true_y = true_y % HEIGHT; /* OOB check is needed when vwrap is turned off so some poorly written games won't crash */ if (true_x < WIDTH && true_y < HEIGHT) { /* collision */ - if(vram[true_x][true_y] == 1) V[0xF] = 1; + if(chip8.vram[true_x][true_y] == 1) chip8.V[0xF] = 1; /* toggle the pixel */ - vram[true_x][true_y] ^= 1; + chip8.vram[true_x][true_y] ^= 1; } } } } - draw_flag = 1; - PC += 2; + chip8.draw_flag = 1; + chip8.PC += 2; } -inline void Chip8::execEX9E() { +inline void execEX9E() { /* EX9E: skips the next instruction if the key stored in VX is pressed */ - if(input.keys[V[OP_X]] == 1) PC += 2; - PC += 2; + if(input.keys[chip8.V[OP_X]] == 1) chip8.PC += 2; + chip8.PC += 2; } -inline void Chip8::execEXA1() { +inline void execEXA1() { /* EXA1: skips the next instruction if the key stored in VX isn't pressed */ - if(input.keys[V[OP_X]] == 0) PC += 2; - PC += 2; + if(input.keys[chip8.V[OP_X]] == 0) chip8.PC += 2; + chip8.PC += 2; } -inline void Chip8::execFX07() { +inline void execFX07() { /* FX07: sets VX to delay timer */ - V[OP_X] = delay_timer; - PC += 2; + chip8.V[OP_X] = chip8.delay_timer; + chip8.PC += 2; } -inline void Chip8::execFX0A() { +inline void execFX0A() { /* FX0A: pause execution until a key is pressed and store result in V[X] */ - if (cpu_halt) { + if (chip8.cpu_halt) { if (!input.awaiting_key_press) { for (int i = 0; i < NUM_KEYS; i++) { - if (input.keys[i] != 0) V[OP_X] = i; + if (input.keys[i] != 0) chip8.V[OP_X] = i; } - cpu_halt = 0; - PC += 2; + chip8.cpu_halt = 0; + chip8.PC += 2; return; } } - cpu_halt = 1; + chip8.cpu_halt = 1; input.awaiting_key_press = 1; } -inline void Chip8::execFX15() { +inline void execFX15() { /* FX15: sets the delay timer to VX */ - delay_timer = V[OP_X]; - PC += 2; + chip8.delay_timer = chip8.V[OP_X]; + chip8.PC += 2; } -inline void Chip8::execFX18() { +inline void execFX18() { /* FX18: sets the sound timer to VX */ - sound_timer = V[OP_X]; - PC += 2; + chip8.sound_timer = chip8.V[OP_X]; + chip8.PC += 2; } -inline void Chip8::execFX1E() { +inline void execFX1E() { /* FX1E: adds VX to I VF is set to 1 when range overflow (I+VX>0xFFF), and 0 when there isn't. */ unsigned short sum; - sum = I + V[OP_X]; - if (sum > 0xFFF) V[0xF] = 1; - else V[0xF] = 0; - I += V[OP_X]; - PC += 2; + sum = chip8.I + chip8.V[OP_X]; + if (sum > 0xFFF) chip8.V[0xF] = 1; + else chip8.V[0xF] = 0; + chip8.I += chip8.V[OP_X]; + chip8.PC += 2; } -inline void Chip8::execFX29() { +inline void execFX29() { /* FX29: sets I to the location of the sprite for the character in VX. Characters 0-F (in hexadecimal) are represented by a 4x5 font. */ - I = V[OP_X] * 0x05; - PC += 2; + chip8.I = chip8.V[OP_X] * 0x05; + chip8.PC += 2; } -inline void Chip8::execFX33() { +inline void execFX33() { /* FX33: stores the binary-coded decimal representation of VX at the addresses I, I plus 1, and I plus 2 */ - memory[I] = V[OP_X] / 100; - memory[I + 1] = (V[OP_X] / 10) % 10; - memory[I + 2] = (V[OP_X] % 100) % 10; - PC += 2; + chip8.memory[chip8.I] = chip8.V[OP_X] / 100; + chip8.memory[chip8.I + 1] = (chip8.V[OP_X] / 10) % 10; + chip8.memory[chip8.I + 2] = (chip8.V[OP_X] % 100) % 10; + chip8.PC += 2; } -inline void Chip8::execFX55() { +inline void execFX55() { /* FX55: stores V0 to VX in memory starting at address I */ for (int i = 0; i <= OP_X; i++) { - memory[I + i] = V[i]; + chip8.memory[chip8.I + i] = chip8.V[i]; } /* on the original interpreter, when the operation is done, I = I + X + 1. */ - if (!load_store_quirk) I += OP_X + 1; - PC += 2; + if (!chip8.load_store_quirk) chip8.I += OP_X + 1; + chip8.PC += 2; } -inline void Chip8::execFX65() { +inline void execFX65() { /* FX65: fills V0 to VX with values from memory starting at address I */ for (int i = 0; i <= OP_X; i++) { - V[i] = memory[I + i]; + chip8.V[i] = chip8.memory[chip8.I + i]; } /* on the original interpreter, when the operation is done, I = I + X + 1. */ - if (!load_store_quirk) I += OP_X + 1; - PC += 2; + if (!chip8.load_store_quirk) chip8.I += OP_X + 1; + chip8.PC += 2; } -inline void Chip8::execUnknown() { - fprintf (stderr, "Unknown opcode: 0x%X\n", opcode); - PC+=2; +inline void execUnknown() { + fprintf (stderr, "Unknown opcode: 0x%X\n", chip8.opcode); + chip8.PC+=2; } From a41cec32c7c34958ad09da52c3c4a4994b62d271 Mon Sep 17 00:00:00 2001 From: Thomas Daley Date: Thu, 15 Jan 2026 21:35:30 -0800 Subject: [PATCH 02/16] convert branch slashes to dashes --- .github/workflows/build-reusable.yml | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-reusable.yml b/.github/workflows/build-reusable.yml index 1197a58e..f214b9eb 100644 --- a/.github/workflows/build-reusable.yml +++ b/.github/workflows/build-reusable.yml @@ -10,6 +10,10 @@ jobs: steps: - uses: actions/checkout@v4 + - name: Sanitize branch name for artifact naming + id: sanitize + run: echo "ref_name=$(echo '${{ github.ref_name }}' | sed 's/\//-/g')" >> $GITHUB_OUTPUT + - name: Cache SDL uses: actions/cache@v4 with: @@ -21,6 +25,8 @@ jobs: brew install cmake pkg-config nasm - name: Build macOS (x86_64 + arm64) + env: + GITHUB_REF_NAME: ${{ steps.sanitize.outputs.ref_name }} run: | cd MacOS make clean @@ -29,7 +35,7 @@ jobs: - name: Upload macOS build artifact uses: actions/upload-artifact@v4 with: - name: Kiwi8-${{ github.ref_name }}-macOS + name: Kiwi8-${{ steps.sanitize.outputs.ref_name }}-macOS path: MacOS/release/ retention-days: 7 @@ -38,6 +44,11 @@ jobs: steps: - uses: actions/checkout@v4 + - name: Sanitize branch name for artifact naming + id: sanitize + shell: pwsh + run: echo "ref_name=$('${{ github.ref_name }}'.Replace('/', '-'))" >> $env:GITHUB_OUTPUT + - name: Cache SDL uses: actions/cache@v4 with: @@ -50,6 +61,8 @@ jobs: arch: amd64 - name: Build Windows (x64) + env: + GITHUB_REF_NAME: ${{ steps.sanitize.outputs.ref_name }} shell: cmd run: | cd Windows @@ -59,6 +72,6 @@ jobs: - name: Upload Windows build artifact uses: actions/upload-artifact@v4 with: - name: Kiwi8-${{ github.ref_name }}-Windows + name: Kiwi8-${{ steps.sanitize.outputs.ref_name }}-Windows path: Windows\release\ retention-days: 7 From 918e8f96ff2e943ca633564962ad7341407289f4 Mon Sep 17 00:00:00 2001 From: Thomas Daley Date: Thu, 15 Jan 2026 21:52:28 -0800 Subject: [PATCH 03/16] convert slashes to dashes --- .github/workflows/build-reusable.yml | 4 ++-- windows/makefile | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-reusable.yml b/.github/workflows/build-reusable.yml index f214b9eb..a95e5ba2 100644 --- a/.github/workflows/build-reusable.yml +++ b/.github/workflows/build-reusable.yml @@ -26,7 +26,7 @@ jobs: - name: Build macOS (x86_64 + arm64) env: - GITHUB_REF_NAME: ${{ steps.sanitize.outputs.ref_name }} + VERSION: ${{ steps.sanitize.outputs.ref_name }} run: | cd MacOS make clean @@ -62,7 +62,7 @@ jobs: - name: Build Windows (x64) env: - GITHUB_REF_NAME: ${{ steps.sanitize.outputs.ref_name }} + VERSION: ${{ steps.sanitize.outputs.ref_name }} shell: cmd run: | cd Windows diff --git a/windows/makefile b/windows/makefile index 97118841..14dfcc84 100644 --- a/windows/makefile +++ b/windows/makefile @@ -1,11 +1,13 @@ APP_NAME = Kiwi8 -# Use GITHUB_REF_NAME from GitHub Actions, or default values for local builds +# Use VERSION if set, otherwise fall back to GITHUB_REF_NAME, then default to unknown +!IFNDEF VERSION !IFDEF GITHUB_REF_NAME VERSION = $(GITHUB_REF_NAME) !ELSE VERSION = unknown !ENDIF +!ENDIF !IFDEF GITHUB_SHA COMMIT_HASH = $(GITHUB_SHA) From 642d3a9cf350bf512d0d2ec4c9e7a04cc12f979a Mon Sep 17 00:00:00 2001 From: Thomas Daley Date: Thu, 15 Jan 2026 21:58:36 -0800 Subject: [PATCH 04/16] use COMMIT_HASH directly as well --- .github/workflows/build-reusable.yml | 2 ++ macos/makefile | 7 +++++-- windows/makefile | 2 ++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-reusable.yml b/.github/workflows/build-reusable.yml index a95e5ba2..2fc6382a 100644 --- a/.github/workflows/build-reusable.yml +++ b/.github/workflows/build-reusable.yml @@ -27,6 +27,7 @@ jobs: - name: Build macOS (x86_64 + arm64) env: VERSION: ${{ steps.sanitize.outputs.ref_name }} + COMMIT_HASH: ${{ github.sha }} run: | cd MacOS make clean @@ -63,6 +64,7 @@ jobs: - name: Build Windows (x64) env: VERSION: ${{ steps.sanitize.outputs.ref_name }} + COMMIT_HASH: ${{ github.sha }} shell: cmd run: | cd Windows diff --git a/macos/makefile b/macos/makefile index f9a0e43d..e0910e63 100644 --- a/macos/makefile +++ b/macos/makefile @@ -1,12 +1,15 @@ APP_NAME = Kiwi8 -# Use GITHUB_REF_NAME from GitHub Actions, or default values for local builds +# Use VERSION if set, otherwise fall back to GITHUB_REF_NAME, then default to unknown VERSION ?= $(GITHUB_REF_NAME) ifeq ($(VERSION),) VERSION = unknown endif -COMMIT_HASH := $(if $(GITHUB_SHA),$(GITHUB_SHA),unknown) +COMMIT_HASH ?= $(GITHUB_SHA) +ifeq ($(COMMIT_HASH),) +COMMIT_HASH = unknown +endif APP_MANIFEST = src/Info.plist APP_BUNDLE = $(APP_NAME).app diff --git a/windows/makefile b/windows/makefile index 14dfcc84..8f6735fe 100644 --- a/windows/makefile +++ b/windows/makefile @@ -9,11 +9,13 @@ VERSION = unknown !ENDIF !ENDIF +!IFNDEF COMMIT_HASH !IFDEF GITHUB_SHA COMMIT_HASH = $(GITHUB_SHA) !ELSE COMMIT_HASH = unknown !ENDIF +!ENDIF APP_EXE = $(APP_NAME).exe APP_PDB = $(APP_NAME).pdb From dd05d5e1a38d2a4e2782b579924da5001ff43678 Mon Sep 17 00:00:00 2001 From: Thomas Daley Date: Thu, 15 Jan 2026 22:10:36 -0800 Subject: [PATCH 05/16] rename files --- shared/{Audio.cc => audio.c} | 0 shared/{Audio.h => audio.h} | 0 shared/{Chip8.cc => chip8.c} | 0 shared/{Chip8.h => chip8.h} | 0 shared/{Display.cc => display.c} | 0 shared/{Display.h => display.h} | 0 shared/{Gui.cc => gui.c} | 0 shared/{Gui.h => gui.h} | 0 shared/{imgui_impl_sdl.cc => imgui_impl_sdl.c} | 0 shared/{Input.cc => input.c} | 0 shared/{Input.h => input.h} | 0 shared/{main.cc => main.c} | 0 shared/{opcodes.cc => opcodes.c} | 0 shared/{open_file_dialog.cc => open_file_dialog.c} | 0 14 files changed, 0 insertions(+), 0 deletions(-) rename shared/{Audio.cc => audio.c} (100%) rename shared/{Audio.h => audio.h} (100%) rename shared/{Chip8.cc => chip8.c} (100%) rename shared/{Chip8.h => chip8.h} (100%) rename shared/{Display.cc => display.c} (100%) rename shared/{Display.h => display.h} (100%) rename shared/{Gui.cc => gui.c} (100%) rename shared/{Gui.h => gui.h} (100%) rename shared/{imgui_impl_sdl.cc => imgui_impl_sdl.c} (100%) rename shared/{Input.cc => input.c} (100%) rename shared/{Input.h => input.h} (100%) rename shared/{main.cc => main.c} (100%) rename shared/{opcodes.cc => opcodes.c} (100%) rename shared/{open_file_dialog.cc => open_file_dialog.c} (100%) diff --git a/shared/Audio.cc b/shared/audio.c similarity index 100% rename from shared/Audio.cc rename to shared/audio.c diff --git a/shared/Audio.h b/shared/audio.h similarity index 100% rename from shared/Audio.h rename to shared/audio.h diff --git a/shared/Chip8.cc b/shared/chip8.c similarity index 100% rename from shared/Chip8.cc rename to shared/chip8.c diff --git a/shared/Chip8.h b/shared/chip8.h similarity index 100% rename from shared/Chip8.h rename to shared/chip8.h diff --git a/shared/Display.cc b/shared/display.c similarity index 100% rename from shared/Display.cc rename to shared/display.c diff --git a/shared/Display.h b/shared/display.h similarity index 100% rename from shared/Display.h rename to shared/display.h diff --git a/shared/Gui.cc b/shared/gui.c similarity index 100% rename from shared/Gui.cc rename to shared/gui.c diff --git a/shared/Gui.h b/shared/gui.h similarity index 100% rename from shared/Gui.h rename to shared/gui.h diff --git a/shared/imgui_impl_sdl.cc b/shared/imgui_impl_sdl.c similarity index 100% rename from shared/imgui_impl_sdl.cc rename to shared/imgui_impl_sdl.c diff --git a/shared/Input.cc b/shared/input.c similarity index 100% rename from shared/Input.cc rename to shared/input.c diff --git a/shared/Input.h b/shared/input.h similarity index 100% rename from shared/Input.h rename to shared/input.h diff --git a/shared/main.cc b/shared/main.c similarity index 100% rename from shared/main.cc rename to shared/main.c diff --git a/shared/opcodes.cc b/shared/opcodes.c similarity index 100% rename from shared/opcodes.cc rename to shared/opcodes.c diff --git a/shared/open_file_dialog.cc b/shared/open_file_dialog.c similarity index 100% rename from shared/open_file_dialog.cc rename to shared/open_file_dialog.c From 72f6d5b65213c3d8958ea75bcf7af2b7861e13a5 Mon Sep 17 00:00:00 2001 From: Thomas Daley Date: Thu, 15 Jan 2026 22:10:51 -0800 Subject: [PATCH 06/16] rename files --- macos/makefile | 10 +++++----- shared/audio.c | 2 +- shared/chip8.c | 4 ++-- shared/chip8.h | 6 +++--- shared/display.c | 4 ++-- shared/display.h | 2 +- shared/gui.c | 6 +++--- shared/input.c | 6 +++--- shared/main.c | 2 +- shared/opcodes.c | 2 +- windows/makefile | 18 +++++++++--------- 11 files changed, 31 insertions(+), 31 deletions(-) diff --git a/macos/makefile b/macos/makefile index e0910e63..98d712e1 100644 --- a/macos/makefile +++ b/macos/makefile @@ -30,15 +30,15 @@ BOOTROM_HEADER = ../shared/bootrom.h BOOTROM_SOURCE = ../roms/Kiwi8_logo_2.ch8 # Source files -CORE_SRCS = ../shared/Audio.cc ../shared/Chip8.cc ../shared/Display.cc ../shared/Gui.cc \ - ../shared/imgui_impl_sdl.cc ../shared/Input.cc ../shared/main.cc \ - ../shared/opcodes.cc ../shared/open_file_dialog.cc +CORE_SRCS = ../shared/audio.c ../shared/chip8.c ../shared/display.c ../shared/gui.c \ + ../shared/imgui_impl_sdl.c ../shared/input.c ../shared/main.c \ + ../shared/opcodes.c ../shared/open_file_dialog.c IMGUI_SRCS = ../external/imgui/imgui.cpp ../external/imgui/imgui_demo.cpp \ ../external/imgui/imgui_draw.cpp MACOS_SRCS = src/file_dialog.mm # Object files (convert source paths to .o in current directory) -OBJS = $(notdir $(CORE_SRCS:.cc=.o)) $(notdir $(IMGUI_SRCS:.cpp=.o)) $(notdir $(MACOS_SRCS:.mm=.o)) +OBJS = $(notdir $(CORE_SRCS:.c=.o)) $(notdir $(IMGUI_SRCS:.cpp=.o)) $(notdir $(MACOS_SRCS:.mm=.o)) DEPS = $(OBJS:.o=.d) # Include auto-generated dependency files (must be before targets) @@ -69,7 +69,7 @@ $(APP_MANIFEST): $(APP_MANIFEST).in sed -e 's/@APP_NAME@/$(APP_NAME)/g' -e 's/@VERSION@/$(VERSION)/g' -e 's/@COMMIT_HASH@/$(COMMIT_HASH)/g' $< > $@ # Pattern rules for incremental compilation -%.o: ../shared/%.cc $(LICENSE_HEADER) $(BOOTROM_HEADER) +%.o: ../shared/%.c $(LICENSE_HEADER) $(BOOTROM_HEADER) $(CC) $(CFLAGS) $(INCS) -c $< -o $@ %.o: ../external/imgui/%.cpp diff --git a/shared/audio.c b/shared/audio.c index 17540bb6..ac2737fc 100644 --- a/shared/audio.c +++ b/shared/audio.c @@ -1,4 +1,4 @@ -#include "Audio.h" +#include "audio.h" #include /* Global audio instance */ diff --git a/shared/chip8.c b/shared/chip8.c index 2cbc2d31..5027f39d 100644 --- a/shared/chip8.c +++ b/shared/chip8.c @@ -1,5 +1,5 @@ -#include "Chip8.h" -#include "opcodes.cc" +#include "chip8.h" +#include "opcodes.c" #include "open_file_dialog.h" #include #include diff --git a/shared/chip8.h b/shared/chip8.h index e52714e2..754b0835 100644 --- a/shared/chip8.h +++ b/shared/chip8.h @@ -2,9 +2,9 @@ #define CHIP8_H #include "bootrom.h" // Generated at build time from roms/Kiwi8_logo_2.ch8 -#include "Display.h" -#include "Input.h" -#include "Audio.h" +#include "display.h" +#include "input.h" +#include "audio.h" // APP_NAME is defined by the compiler via -DAPP_NAME="..." // Falls back to generic name if not defined (shouldn't happen in normal builds) diff --git a/shared/display.c b/shared/display.c index cc23150b..e2d2f022 100644 --- a/shared/display.c +++ b/shared/display.c @@ -1,5 +1,5 @@ -#include "Display.h" -#include "Gui.h" +#include "display.h" +#include "gui.h" #include #include diff --git a/shared/display.h b/shared/display.h index 97efb020..3a1755d4 100644 --- a/shared/display.h +++ b/shared/display.h @@ -1,7 +1,7 @@ #ifndef DISPLAY_H #define DISPLAY_H -#include "Gui.h" +#include "gui.h" #include #define WIDTH 64 diff --git a/shared/gui.c b/shared/gui.c index e5dc709e..c0483e59 100644 --- a/shared/gui.c +++ b/shared/gui.c @@ -1,6 +1,6 @@ -#include "Chip8.h" -#include "Display.h" -#include "Gui.h" +#include "chip8.h" +#include "display.h" +#include "gui.h" #include "license.h" // Generated at build time from LICENSE #include diff --git a/shared/input.c b/shared/input.c index c4feebcb..cd4ca665 100644 --- a/shared/input.c +++ b/shared/input.c @@ -1,6 +1,6 @@ -#include "Chip8.h" -#include "Input.h" -#include "Display.h" +#include "chip8.h" +#include "input.h" +#include "display.h" /* Forward declarations for static helpers */ static int input_process_events(void); static void input_process_keys(void); diff --git a/shared/main.c b/shared/main.c index cbd29c92..d3e6d7d8 100644 --- a/shared/main.c +++ b/shared/main.c @@ -1,4 +1,4 @@ -#include "Chip8.h" +#include "chip8.h" #include #ifdef _WIN32 diff --git a/shared/opcodes.c b/shared/opcodes.c index 4eeb5201..14fc777d 100644 --- a/shared/opcodes.c +++ b/shared/opcodes.c @@ -1,4 +1,4 @@ -#include "Chip8.h" +#include "chip8.h" #include #include /* rand() */ diff --git a/windows/makefile b/windows/makefile index 8f6735fe..1701cd08 100644 --- a/windows/makefile +++ b/windows/makefile @@ -47,15 +47,15 @@ BOOTROM_HEADER = ..\shared\bootrom.h BOOTROM_SOURCE = ..\roms\Kiwi8_logo_2.ch8 # Source files -CORE_SRCS = ..\shared\Audio.cc ..\shared\Chip8.cc ..\shared\Display.cc ..\shared\Gui.cc \ - ..\shared\imgui_impl_sdl.cc ..\shared\Input.cc ..\shared\main.cc \ - ..\shared\opcodes.cc ..\shared\open_file_dialog.cc +CORE_SRCS = ..\shared\Audio.c ..\shared\Chip8.c ..\shared\Display.c ..\shared\Gui.c \ + ..\shared\imgui_impl_sdl.c ..\shared\Input.c ..\shared\main.c \ + ..\shared\opcodes.c ..\shared\open_file_dialog.c IMGUI_SRCS = ..\external\imgui\imgui.cpp ..\external\imgui\imgui_demo.cpp \ ..\external\imgui\imgui_draw.cpp WINDOWS_SRCS = src\file_dialog.cc # Object files (all built in current directory) -OBJS = Audio.obj Chip8.obj Display.obj Gui.obj imgui_impl_sdl.obj Input.obj \ +OBJS = audio.obj chip8.obj display.obj gui.obj imgui_impl_sdl.obj input.obj \ main.obj opcodes.obj open_file_dialog.obj imgui.obj imgui_demo.obj \ imgui_draw.obj file_dialog.obj @@ -83,7 +83,7 @@ $(BOOTROM_HEADER): $(BOOTROM_SOURCE) python3 ..\tools\generate_bootrom_header.py $(BOOTROM_SOURCE) $(BOOTROM_HEADER) # Inference rules for incremental compilation -{..\shared}.cc{}.obj: +{..\shared}.c{}.obj: $(CC) $(CFLAGS) /c $(INCS) $< {..\external\imgui}.cpp{}.obj: @@ -93,11 +93,11 @@ $(BOOTROM_HEADER): $(BOOTROM_SOURCE) $(CC) $(CFLAGS) /c $(INCS) $< # Explicit rules for files depending on generated headers -Gui.obj: ..\shared\Gui.cc $(LICENSE_HEADER) - $(CC) $(CFLAGS) /c $(INCS) ..\shared\Gui.cc +gui.obj: ..\shared\gui.c $(LICENSE_HEADER) + $(CC) $(CFLAGS) /c $(INCS) ..\shared\gui.c -Chip8.obj: ..\shared\Chip8.cc $(BOOTROM_HEADER) - $(CC) $(CFLAGS) /c $(INCS) ..\shared\Chip8.cc +chip8.obj: ..\shared\chip8.c $(BOOTROM_HEADER) + $(CC) $(CFLAGS) /c $(INCS) ..\shared\chip8.c $(APP_RES): src\Kiwi8.rc resources\Kiwi8.ico RC src\Kiwi8.rc From ba2c9c87103ac3dc0000c6d50c90d23123010c23 Mon Sep 17 00:00:00 2001 From: Thomas Daley Date: Thu, 15 Jan 2026 22:21:37 -0800 Subject: [PATCH 07/16] move file extension back --- macos/makefile | 10 +++++----- shared/{audio.c => audio.cc} | 0 shared/{chip8.c => chip8.cc} | 2 +- shared/{display.c => display.cc} | 0 shared/{gui.c => gui.cc} | 0 shared/{imgui_impl_sdl.c => imgui_impl_sdl.cc} | 0 shared/{input.c => input.cc} | 0 shared/{main.c => main.cc} | 0 shared/{opcodes.c => opcodes.cc} | 0 .../{open_file_dialog.c => open_file_dialog.cc} | 0 windows/makefile | 16 ++++++++-------- 11 files changed, 14 insertions(+), 14 deletions(-) rename shared/{audio.c => audio.cc} (100%) rename shared/{chip8.c => chip8.cc} (99%) rename shared/{display.c => display.cc} (100%) rename shared/{gui.c => gui.cc} (100%) rename shared/{imgui_impl_sdl.c => imgui_impl_sdl.cc} (100%) rename shared/{input.c => input.cc} (100%) rename shared/{main.c => main.cc} (100%) rename shared/{opcodes.c => opcodes.cc} (100%) rename shared/{open_file_dialog.c => open_file_dialog.cc} (100%) diff --git a/macos/makefile b/macos/makefile index 98d712e1..0ad31124 100644 --- a/macos/makefile +++ b/macos/makefile @@ -30,15 +30,15 @@ BOOTROM_HEADER = ../shared/bootrom.h BOOTROM_SOURCE = ../roms/Kiwi8_logo_2.ch8 # Source files -CORE_SRCS = ../shared/audio.c ../shared/chip8.c ../shared/display.c ../shared/gui.c \ - ../shared/imgui_impl_sdl.c ../shared/input.c ../shared/main.c \ - ../shared/opcodes.c ../shared/open_file_dialog.c +CORE_SRCS = ../shared/audio.cc ../shared/chip8.cc ../shared/display.cc ../shared/gui.cc \ + ../shared/imgui_impl_sdl.cc ../shared/input.cc ../shared/main.cc \ + ../shared/opcodes.cc ../shared/open_file_dialog.cc IMGUI_SRCS = ../external/imgui/imgui.cpp ../external/imgui/imgui_demo.cpp \ ../external/imgui/imgui_draw.cpp MACOS_SRCS = src/file_dialog.mm # Object files (convert source paths to .o in current directory) -OBJS = $(notdir $(CORE_SRCS:.c=.o)) $(notdir $(IMGUI_SRCS:.cpp=.o)) $(notdir $(MACOS_SRCS:.mm=.o)) +OBJS = $(notdir $(CORE_SRCS:.cc=.o)) $(notdir $(IMGUI_SRCS:.cpp=.o)) $(notdir $(MACOS_SRCS:.mm=.o)) DEPS = $(OBJS:.o=.d) # Include auto-generated dependency files (must be before targets) @@ -69,7 +69,7 @@ $(APP_MANIFEST): $(APP_MANIFEST).in sed -e 's/@APP_NAME@/$(APP_NAME)/g' -e 's/@VERSION@/$(VERSION)/g' -e 's/@COMMIT_HASH@/$(COMMIT_HASH)/g' $< > $@ # Pattern rules for incremental compilation -%.o: ../shared/%.c $(LICENSE_HEADER) $(BOOTROM_HEADER) +%.o: ../shared/%.cc $(LICENSE_HEADER) $(BOOTROM_HEADER) $(CC) $(CFLAGS) $(INCS) -c $< -o $@ %.o: ../external/imgui/%.cpp diff --git a/shared/audio.c b/shared/audio.cc similarity index 100% rename from shared/audio.c rename to shared/audio.cc diff --git a/shared/chip8.c b/shared/chip8.cc similarity index 99% rename from shared/chip8.c rename to shared/chip8.cc index 5027f39d..35dc1cd1 100644 --- a/shared/chip8.c +++ b/shared/chip8.cc @@ -1,5 +1,5 @@ #include "chip8.h" -#include "opcodes.c" +#include "opcodes.cc" #include "open_file_dialog.h" #include #include diff --git a/shared/display.c b/shared/display.cc similarity index 100% rename from shared/display.c rename to shared/display.cc diff --git a/shared/gui.c b/shared/gui.cc similarity index 100% rename from shared/gui.c rename to shared/gui.cc diff --git a/shared/imgui_impl_sdl.c b/shared/imgui_impl_sdl.cc similarity index 100% rename from shared/imgui_impl_sdl.c rename to shared/imgui_impl_sdl.cc diff --git a/shared/input.c b/shared/input.cc similarity index 100% rename from shared/input.c rename to shared/input.cc diff --git a/shared/main.c b/shared/main.cc similarity index 100% rename from shared/main.c rename to shared/main.cc diff --git a/shared/opcodes.c b/shared/opcodes.cc similarity index 100% rename from shared/opcodes.c rename to shared/opcodes.cc diff --git a/shared/open_file_dialog.c b/shared/open_file_dialog.cc similarity index 100% rename from shared/open_file_dialog.c rename to shared/open_file_dialog.cc diff --git a/windows/makefile b/windows/makefile index 1701cd08..5478727b 100644 --- a/windows/makefile +++ b/windows/makefile @@ -47,9 +47,9 @@ BOOTROM_HEADER = ..\shared\bootrom.h BOOTROM_SOURCE = ..\roms\Kiwi8_logo_2.ch8 # Source files -CORE_SRCS = ..\shared\Audio.c ..\shared\Chip8.c ..\shared\Display.c ..\shared\Gui.c \ - ..\shared\imgui_impl_sdl.c ..\shared\Input.c ..\shared\main.c \ - ..\shared\opcodes.c ..\shared\open_file_dialog.c +CORE_SRCS = ..\shared\audio.cc ..\shared\chip8.cc ..\shared\display.cc ..\shared\gui.cc \ + ..\shared\imgui_impl_sdl.cc ..\shared\input.cc ..\shared\main.cc \ + ..\shared\opcodes.cc ..\shared\open_file_dialog.cc IMGUI_SRCS = ..\external\imgui\imgui.cpp ..\external\imgui\imgui_demo.cpp \ ..\external\imgui\imgui_draw.cpp WINDOWS_SRCS = src\file_dialog.cc @@ -83,7 +83,7 @@ $(BOOTROM_HEADER): $(BOOTROM_SOURCE) python3 ..\tools\generate_bootrom_header.py $(BOOTROM_SOURCE) $(BOOTROM_HEADER) # Inference rules for incremental compilation -{..\shared}.c{}.obj: +{..\shared}.cc{}.obj: $(CC) $(CFLAGS) /c $(INCS) $< {..\external\imgui}.cpp{}.obj: @@ -93,11 +93,11 @@ $(BOOTROM_HEADER): $(BOOTROM_SOURCE) $(CC) $(CFLAGS) /c $(INCS) $< # Explicit rules for files depending on generated headers -gui.obj: ..\shared\gui.c $(LICENSE_HEADER) - $(CC) $(CFLAGS) /c $(INCS) ..\shared\gui.c +gui.obj: ..\shared\gui.cc $(LICENSE_HEADER) + $(CC) $(CFLAGS) /c $(INCS) ..\shared\gui.cc -chip8.obj: ..\shared\chip8.c $(BOOTROM_HEADER) - $(CC) $(CFLAGS) /c $(INCS) ..\shared\chip8.c +chip8.obj: ..\shared\chip8.cc $(BOOTROM_HEADER) + $(CC) $(CFLAGS) /c $(INCS) ..\shared\chip8.cc $(APP_RES): src\Kiwi8.rc resources\Kiwi8.ico RC src\Kiwi8.rc From ea23032c6cdc7e0d2b74c9da969dd8a6e3980d68 Mon Sep 17 00:00:00 2001 From: Thomas Daley Date: Thu, 15 Jan 2026 22:43:05 -0800 Subject: [PATCH 08/16] fix broken audio --- shared/chip8.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/shared/chip8.cc b/shared/chip8.cc index 35dc1cd1..1c8f6163 100644 --- a/shared/chip8.cc +++ b/shared/chip8.cc @@ -73,6 +73,8 @@ int chip8_initialize( } /* init audio, display, input */ + /* set up audio wave parameters before starting device */ + audio_create(); audio_initialize(); if (display_initialize( From 3de901be2cf6a3724040f63d8aa4a59478f0c67f Mon Sep 17 00:00:00 2001 From: Thomas Daley Date: Thu, 15 Jan 2026 22:45:55 -0800 Subject: [PATCH 09/16] fix plist --- macos/src/Info.plist.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/macos/src/Info.plist.in b/macos/src/Info.plist.in index 744de438..4657f808 100644 --- a/macos/src/Info.plist.in +++ b/macos/src/Info.plist.in @@ -15,7 +15,7 @@ CFBundleShortVersionString @VERSION@ CFBundleVersion - @SUB_VERSION@ + @COMMIT_HASH@ LSMinimumSystemVersion 11.0 NSHighResolutionCapable From 9a7bd1af9f9aefbf0f38bc77216f96ff4c460b14 Mon Sep 17 00:00:00 2001 From: Thomas Daley Date: Thu, 15 Jan 2026 23:03:36 -0800 Subject: [PATCH 10/16] change fallback version --- macos/makefile | 2 +- shared/chip8.h | 2 +- windows/makefile | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/macos/makefile b/macos/makefile index 0ad31124..d47a5e77 100644 --- a/macos/makefile +++ b/macos/makefile @@ -3,7 +3,7 @@ APP_NAME = Kiwi8 # Use VERSION if set, otherwise fall back to GITHUB_REF_NAME, then default to unknown VERSION ?= $(GITHUB_REF_NAME) ifeq ($(VERSION),) -VERSION = unknown +VERSION = develop endif COMMIT_HASH ?= $(GITHUB_SHA) diff --git a/shared/chip8.h b/shared/chip8.h index 754b0835..e2c96990 100644 --- a/shared/chip8.h +++ b/shared/chip8.h @@ -15,7 +15,7 @@ // VERSION is defined by the compiler via -DVERSION="..." // Falls back to unknown if not defined (shouldn't happen in normal builds) #ifndef VERSION -#define VERSION "unknown" +#define VERSION "develop" #endif // COMMIT_HASH is defined by the compiler via -DCOMMIT_HASH="..." diff --git a/windows/makefile b/windows/makefile index 5478727b..c483d032 100644 --- a/windows/makefile +++ b/windows/makefile @@ -5,7 +5,7 @@ APP_NAME = Kiwi8 !IFDEF GITHUB_REF_NAME VERSION = $(GITHUB_REF_NAME) !ELSE -VERSION = unknown +VERSION = develop !ENDIF !ENDIF From 3be77ed7dbe827321c3f8a1c66d7220e9c1f2e3b Mon Sep 17 00:00:00 2001 From: Thomas Daley Date: Thu, 15 Jan 2026 23:04:40 -0800 Subject: [PATCH 11/16] comment --- shared/chip8.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/shared/chip8.h b/shared/chip8.h index e2c96990..1fe3a3ee 100644 --- a/shared/chip8.h +++ b/shared/chip8.h @@ -7,19 +7,16 @@ #include "audio.h" // APP_NAME is defined by the compiler via -DAPP_NAME="..." -// Falls back to generic name if not defined (shouldn't happen in normal builds) #ifndef APP_NAME #define APP_NAME "Kiwi8" #endif // VERSION is defined by the compiler via -DVERSION="..." -// Falls back to unknown if not defined (shouldn't happen in normal builds) #ifndef VERSION #define VERSION "develop" #endif // COMMIT_HASH is defined by the compiler via -DCOMMIT_HASH="..." -// Falls back to generic name if not defined (shouldn't happen in normal builds) #ifndef COMMIT_HASH #define COMMIT_HASH "unknown" #endif From 7a6127144ab17dd26edeeaba620a200c8decf337 Mon Sep 17 00:00:00 2001 From: Thomas Daley Date: Thu, 15 Jan 2026 23:27:22 -0800 Subject: [PATCH 12/16] format --- shared/main.cc | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/shared/main.cc b/shared/main.cc index d3e6d7d8..30944002 100644 --- a/shared/main.cc +++ b/shared/main.cc @@ -39,13 +39,12 @@ int main(int argc, char **argv){ /* calling initialize() also loads the bootrom */ if (chip8_initialize( - fullscreen, - load_store_quirk, - shift_quirk, - vwrap, - muted - ) - ) return 1; + fullscreen, + load_store_quirk, + shift_quirk, + vwrap, + muted + )) return 1; /* load ROM from argument vector */ if (argc >= 2 && *argv[1] != '-') { From 99bb08e0968bc510169acc323861425f010552cb Mon Sep 17 00:00:00 2001 From: Thomas Daley Date: Thu, 15 Jan 2026 23:38:56 -0800 Subject: [PATCH 13/16] format --- shared/main.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/shared/main.cc b/shared/main.cc index 30944002..be78d62e 100644 --- a/shared/main.cc +++ b/shared/main.cc @@ -32,7 +32,6 @@ int main(int argc, char **argv){ if (*pos == 'S') shift_quirk = 0; if (*pos == 'V') vwrap = 0; pos++; - } } } From 362a56a198f5483f5fba6c93755091ef13675cd7 Mon Sep 17 00:00:00 2001 From: Thomas Daley Date: Fri, 16 Jan 2026 11:01:31 -0800 Subject: [PATCH 14/16] bandaid overflow quirk for now --- shared/opcodes.cc | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/shared/opcodes.cc b/shared/opcodes.cc index 14fc777d..0d5cc1a2 100644 --- a/shared/opcodes.cc +++ b/shared/opcodes.cc @@ -177,6 +177,7 @@ inline void execDXYN() { for (unsigned char yline = 0; yline < height; yline++) { pixel = chip8.memory[chip8.I + yline]; + for(unsigned char xline = 0; xline < 8; xline++) { if((pixel & (0x80 >> xline)) != 0) { @@ -185,6 +186,7 @@ inline void execDXYN() { wrapping to the top of the screen if you (y % HEIGHT) */ unsigned char true_x = (x + xline) % WIDTH; unsigned char true_y = (y + yline); + if(chip8.vwrap) true_y = true_y % HEIGHT; /* OOB check is needed when vwrap is turned off @@ -255,8 +257,12 @@ inline void execFX1E() { and 0 when there isn't. */ unsigned short sum; sum = chip8.I + chip8.V[OP_X]; - if (sum > 0xFFF) chip8.V[0xF] = 1; - else chip8.V[0xF] = 0; + + // TODO: Add quirk toggle for this behavior + // Commented out to fix compatibility issues with: AnimalRace + //if (sum > 0xFFF) chip8.V[0xF] = 1; + //else chip8.V[0xF] = 0; + chip8.I += chip8.V[OP_X]; chip8.PC += 2; } From 7a2f4feaea33e743900cd88c33347270dca368e8 Mon Sep 17 00:00:00 2001 From: Thomas Daley Date: Fri, 16 Jan 2026 11:16:13 -0800 Subject: [PATCH 15/16] whitespace --- shared/main.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/shared/main.cc b/shared/main.cc index be78d62e..92a1d706 100644 --- a/shared/main.cc +++ b/shared/main.cc @@ -13,6 +13,7 @@ int main(int argc, char **argv){ bool shift_quirk = 1; bool vwrap = 1; bool muted = 0; + chip8_create(); /* parse and set any options present */ From 5e6cfe3be8267af039cbbeee6389845b5a294104 Mon Sep 17 00:00:00 2001 From: Thomas Daley Date: Fri, 16 Jan 2026 11:31:07 -0800 Subject: [PATCH 16/16] remove imgui demo code --- macos/makefile | 3 +-- windows/makefile | 7 +++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/macos/makefile b/macos/makefile index d47a5e77..2b8472c3 100644 --- a/macos/makefile +++ b/macos/makefile @@ -33,8 +33,7 @@ BOOTROM_SOURCE = ../roms/Kiwi8_logo_2.ch8 CORE_SRCS = ../shared/audio.cc ../shared/chip8.cc ../shared/display.cc ../shared/gui.cc \ ../shared/imgui_impl_sdl.cc ../shared/input.cc ../shared/main.cc \ ../shared/opcodes.cc ../shared/open_file_dialog.cc -IMGUI_SRCS = ../external/imgui/imgui.cpp ../external/imgui/imgui_demo.cpp \ - ../external/imgui/imgui_draw.cpp +IMGUI_SRCS = ../external/imgui/imgui.cpp ../external/imgui/imgui_draw.cpp MACOS_SRCS = src/file_dialog.mm # Object files (convert source paths to .o in current directory) diff --git a/windows/makefile b/windows/makefile index c483d032..49ad33d5 100644 --- a/windows/makefile +++ b/windows/makefile @@ -50,14 +50,13 @@ BOOTROM_SOURCE = ..\roms\Kiwi8_logo_2.ch8 CORE_SRCS = ..\shared\audio.cc ..\shared\chip8.cc ..\shared\display.cc ..\shared\gui.cc \ ..\shared\imgui_impl_sdl.cc ..\shared\input.cc ..\shared\main.cc \ ..\shared\opcodes.cc ..\shared\open_file_dialog.cc -IMGUI_SRCS = ..\external\imgui\imgui.cpp ..\external\imgui\imgui_demo.cpp \ - ..\external\imgui\imgui_draw.cpp +IMGUI_SRCS = ..\external\imgui\imgui.cpp ..\external\imgui\imgui_draw.cpp WINDOWS_SRCS = src\file_dialog.cc # Object files (all built in current directory) OBJS = audio.obj chip8.obj display.obj gui.obj imgui_impl_sdl.obj input.obj \ - main.obj opcodes.obj open_file_dialog.obj imgui.obj imgui_demo.obj \ - imgui_draw.obj file_dialog.obj + main.obj opcodes.obj open_file_dialog.obj imgui.obj imgui_draw.obj \ + file_dialog.obj # Default target