From c2c824c55571457b73e7a95dcff9d722cbbca090 Mon Sep 17 00:00:00 2001 From: Thomas Daley Date: Wed, 18 Feb 2026 12:57:37 -0800 Subject: [PATCH 01/15] Update verbiage --- shared/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shared/README.md b/shared/README.md index 797c915..553006c 100644 --- a/shared/README.md +++ b/shared/README.md @@ -1,5 +1,5 @@ # shared All the code in here *should* be platform independent or -should at least be able to compile on both macOS and Windows. -Platform specific code can be found in the "windows/src", "macos/src" and "linux/src" directories. +should at least be able to compile on Windows, MacOS, and Linux. +Platform specific code can be found in their corresponding top-level directories. From d5fa295e86fcbb8f3fd7e08ed20f5388a7564799 Mon Sep 17 00:00:00 2001 From: Thomas Daley Date: Wed, 18 Feb 2026 14:49:33 -0800 Subject: [PATCH 02/15] rename linter script --- .github/workflows/lint.yml | 4 ++-- tools/{check_no_oo.sh => check_forbidden_tokens.sh} | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) rename tools/{check_no_oo.sh => check_forbidden_tokens.sh} (97%) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index ca66572..bb67b52 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -8,6 +8,6 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - name: Run no-OO linter + - name: Run forbidden tokens linter run: | - bash tools/check_no_oo.sh shared + bash tools/check_forbidden_tokens.sh shared diff --git a/tools/check_no_oo.sh b/tools/check_forbidden_tokens.sh similarity index 97% rename from tools/check_no_oo.sh rename to tools/check_forbidden_tokens.sh index f3f3d44..4db108f 100644 --- a/tools/check_no_oo.sh +++ b/tools/check_forbidden_tokens.sh @@ -2,7 +2,7 @@ set -euo pipefail # Simple linter to detect forbidden C++/OO tokens in the shared/ folder. -# Usage: tools/check_no_oo.sh [TARGET_DIR] +# Usage: tools/check_forbidden_tokens.sh [TARGET_DIR] ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)" TARGET_DIR="${1:-shared}" From eea38a7e85ac49d35c71e605e03c468f904b520c Mon Sep 17 00:00:00 2001 From: Thomas Daley Date: Thu, 19 Feb 2026 18:11:03 -0800 Subject: [PATCH 03/15] do we need cstd17? --- linux/makefile | 2 +- macos/makefile | 2 +- windows/makefile | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/linux/makefile b/linux/makefile index d3f472e..0510386 100644 --- a/linux/makefile +++ b/linux/makefile @@ -14,7 +14,7 @@ endif APP_EXE = $(APP_NAME) CC = g++ -CFLAGS = -std=c++17 -Wall -MMD -MP -DAPP_NAME='"$(APP_NAME)"' -DVERSION='"$(VERSION)"' -DSUB_VERSION='"$(SUB_VERSION)"' +CFLAGS = -std=c++11 -Wall -MMD -MP -DAPP_NAME='"$(APP_NAME)"' -DVERSION='"$(VERSION)"' -DSUB_VERSION='"$(SUB_VERSION)"' LFLAGS = -Wl,-rpath,'$$ORIGIN' # Use pkg-config to get GTK3 and audio backend flags diff --git a/macos/makefile b/macos/makefile index 67167b2..ecc2745 100644 --- a/macos/makefile +++ b/macos/makefile @@ -16,7 +16,7 @@ APP_BUNDLE = $(APP_NAME).app APP_EXE = $(APP_NAME) CC = clang++ -CFLAGS = -std=c++17 -Wall -mmacosx-version-min=11.0 -MMD -MP -DAPP_NAME='"$(APP_NAME)"' -DVERSION='"$(VERSION)"' -DSUB_VERSION='"$(SUB_VERSION)"' +CFLAGS = -std=c++11 -Wall -mmacosx-version-min=11.0 -MMD -MP -DAPP_NAME='"$(APP_NAME)"' -DVERSION='"$(VERSION)"' -DSUB_VERSION='"$(SUB_VERSION)"' LFLAGS = -mmacosx-version-min=11.0 INCS = -I../external/sdl/build/include/ -I../external/imgui/ -I../external/stb/ -I../external/lekkit/ LIBS = -L../external/sdl/build/lib/ -lSDL2-2.0.0 -framework Cocoa -framework OpenGL diff --git a/windows/makefile b/windows/makefile index e06e931..343d4b2 100644 --- a/windows/makefile +++ b/windows/makefile @@ -22,7 +22,7 @@ APP_PDB = $(APP_NAME).pdb APP_RES = $(APP_NAME).res CC = CL -CFLAGS = /std:c++17 /W4 /MD /nologo /w44996 "/DAPP_NAME=\"$(APP_NAME)\"" "/DVERSION=\"$(VERSION)\"" "/DSUB_VERSION=\"$(SUB_VERSION)\"" +CFLAGS = /std:c++11 /W4 /MD /nologo /w44996 "/DAPP_NAME=\"$(APP_NAME)\"" "/DVERSION=\"$(VERSION)\"" "/DSUB_VERSION=\"$(SUB_VERSION)\"" LFLAGS = /link \ /LIBPATH:..\external\sdl\build\lib \ From 4d9341cf474b21cee40d06259b7d8c26a7197177 Mon Sep 17 00:00:00 2001 From: Tom Daley Date: Sat, 21 Feb 2026 14:42:02 -0800 Subject: [PATCH 04/15] Compile C and C++ objects separately (#60) * builds working on macos * remove debug-vars target * attempt linux build * define M_PI manually * let's try using gnu standard? * add missing rule for linux/src dir * does order matter? * put linker flags at the end, where they were before * make macos consistent * convert long lines to multiline * try windows builds here we go... --- external/lekkit/{sha256.cc => sha256.c} | 0 linux/makefile | 84 +++++++++++------- macos/makefile | 74 ++++++++++------ shared/{audio.cc => audio.c} | 0 shared/audio.h | 12 +++ shared/{chip8.cc => chip8.c} | 4 +- shared/chip8.h | 45 ++++++---- shared/{display.cc => display.c} | 0 shared/display.h | 9 ++ shared/gui.cc | 1 - shared/gui.h | 10 +++ shared/{input.cc => input.c} | 4 +- shared/input.h | 9 ++ shared/main.cc | 1 + shared/opcodes.h | 18 ++-- shared/open_file_dialog.h | 8 ++ shared/{profiles.cc => profiles.c} | 0 shared/profiles.h | 8 ++ shared/quirks.h | 10 +++ shared/{toast.cc => toast.c} | 0 shared/toast.h | 8 ++ tools/generate_bootrom_header.py | 28 +++--- tools/generate_license_header.py | 10 ++- windows/makefile | 113 +++++++++++++----------- 24 files changed, 310 insertions(+), 146 deletions(-) rename external/lekkit/{sha256.cc => sha256.c} (100%) rename shared/{audio.cc => audio.c} (100%) rename shared/{chip8.cc => chip8.c} (99%) rename shared/{display.cc => display.c} (100%) rename shared/{input.cc => input.c} (95%) rename shared/{profiles.cc => profiles.c} (100%) rename shared/{toast.cc => toast.c} (100%) diff --git a/external/lekkit/sha256.cc b/external/lekkit/sha256.c similarity index 100% rename from external/lekkit/sha256.cc rename to external/lekkit/sha256.c diff --git a/linux/makefile b/linux/makefile index 0510386..f6550f9 100644 --- a/linux/makefile +++ b/linux/makefile @@ -1,11 +1,12 @@ APP_NAME = Kiwi8 -# Use VERSION if set, otherwise fall back to GITHUB_REF_NAME, then default to unknown +# Use VERSION if set, otherwise fall back to GITHUB_REF_NAME, then default to develop VERSION ?= $(GITHUB_REF_NAME) ifeq ($(VERSION),) VERSION = develop endif +# Use SUB_VERSION if set, otherwise fall back to GITHUB_SHA, then default to unknown SUB_VERSION ?= $(GITHUB_SHA) ifeq ($(SUB_VERSION),) SUB_VERSION = unknown @@ -13,9 +14,30 @@ endif APP_EXE = $(APP_NAME) -CC = g++ -CFLAGS = -std=c++11 -Wall -MMD -MP -DAPP_NAME='"$(APP_NAME)"' -DVERSION='"$(VERSION)"' -DSUB_VERSION='"$(SUB_VERSION)"' -LFLAGS = -Wl,-rpath,'$$ORIGIN' +CC = gcc +CXX = g++ +CFLAGS = -std=gnu11 +CPPFLAGS = -Wall \ + -MMD \ + -MP \ + -DAPP_NAME='"$(APP_NAME)"' \ + -DVERSION='"$(VERSION)"' \ + -DSUB_VERSION='"$(SUB_VERSION)"' + +CXXFLAGS = -std=gnu++11 + +INCLUDE_DIRS = -I../external/sdl/build/include/ \ + -I../external/imgui/ \ + -I../external/stb/ \ + -I../external/lekkit/ + +LDFLAGS = -L../external/sdl/build/lib \ + -lSDL2-2.0 \ + -lGL \ + -lm \ + -ldl \ + -lpthread \ + -Wl,-rpath,'$$ORIGIN' # Use pkg-config to get GTK3 and audio backend flags GTK3_CFLAGS = $(shell pkg-config --cflags gtk+-3.0) @@ -31,12 +53,9 @@ PIPEWIRE_LIBS = $(shell pkg-config --libs libpipewire-0.3) JACK_CFLAGS = $(shell pkg-config --cflags jack) JACK_LIBS = $(shell pkg-config --libs jack) -CFLAGS += $(GTK3_CFLAGS) $(ALSA_CFLAGS) $(PULSE_CFLAGS) $(PIPEWIRE_CFLAGS) $(JACK_CFLAGS) +CPPFLAGS += $(GTK3_CFLAGS) $(ALSA_CFLAGS) $(PULSE_CFLAGS) $(PIPEWIRE_CFLAGS) $(JACK_CFLAGS) +LDFLAGS += $(GTK3_LIBS) $(ALSA_LIBS) $(PULSE_LIBS) $(PIPEWIRE_LIBS) $(JACK_LIBS) -INCS = -I../external/sdl/build/include/ -I../external/imgui/ -I../external/stb/ -I../external/lekkit/ -LIBS = -L../external/sdl/build/lib -lSDL2-2.0 -lGL $(GTK3_LIBS) $(ALSA_LIBS) $(PULSE_LIBS) $(PIPEWIRE_LIBS) $(JACK_LIBS) $(ESD_LIBS) $(SNDIO_LIBS) -lm -ldl -lpthread - -# SDL dependency files SDL_LIB = ../external/sdl/build/lib/libSDL2-2.0.so.0 # Generated headers @@ -44,19 +63,21 @@ LICENSE_HEADER = ../shared/license.h 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/input.cc ../shared/main.cc \ - ../shared/toast.cc ../shared/open_file_dialog.cc ../shared/profiles.cc -IMGUI_SRCS = ../external/imgui/imgui.cpp ../external/imgui/imgui_draw.cpp ../external/imgui/imgui_impl_sdl.cpp -LINUX_SRCS = src/file_dialog.cc -SHA256_SRC = ../external/lekkit/sha256.cc - -# Object files (convert source paths to .o in current directory) -OBJS = $(notdir $(CORE_SRCS:.cc=.o)) \ - $(notdir $(IMGUI_SRCS:.cpp=.o)) \ - $(notdir $(LINUX_SRCS:.cc=.o)) \ - $(notdir $(SHA256_SRC:.cc=.o)) +OBJS = audio.o \ + chip8.o \ + display.o \ + gui.o \ + input.o \ + main.o \ + toast.o \ + open_file_dialog.o \ + profiles.o \ + imgui.o \ + imgui_draw.o \ + imgui_impl_sdl.o \ + sha256.o \ + file_dialog.o + DEPS = $(OBJS:.o=.d) PROFILES_INI = ../shared/profiles.ini @@ -66,7 +87,7 @@ PROFILES_INI = ../shared/profiles.ini .DEFAULT_GOAL := all -all: debug/profiles.ini debug/$(APP_EXE) release/profiles. release/$(APP_EXE) +all: debug/profiles.ini debug/$(APP_EXE) release/profiles.ini release/$(APP_EXE) # Build SDL (force rebuild with: make sdl) sdl: @@ -86,16 +107,19 @@ $(BOOTROM_HEADER): $(BOOTROM_SOURCE) # Pattern rules for incremental compilation %.o: src/%.cc - $(CC) $(CFLAGS) $(INCS) -c $< -o $@ + $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(INCLUDE_DIRS) -c $< -o $@ %.o: ../external/imgui/%.cpp - $(CC) $(CFLAGS) $(INCS) -c $< -o $@ + $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(INCLUDE_DIRS) -c $< -o $@ + +%.o: ../external/lekkit/%.c + $(CC) $(CFLAGS) $(CPPFLAGS) $(INCLUDE_DIRS) -c $< -o $@ -%.o: ../external/lekkit/%.cc - $(CC) $(CFLAGS) $(INCS) -c $< -o $@ +%.o: ../shared/%.c $(LICENSE_HEADER) $(BOOTROM_HEADER) + $(CC) $(CFLAGS) $(CPPFLAGS) $(INCLUDE_DIRS) -c $< -o $@ %.o: ../shared/%.cc $(LICENSE_HEADER) $(BOOTROM_HEADER) - $(CC) $(CFLAGS) $(INCS) -c $< -o $@ + $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(INCLUDE_DIRS) -c $< -o $@ debug/profiles.ini: $(PROFILES_INI) mkdir -p debug @@ -109,13 +133,13 @@ release/profiles.ini: $(PROFILES_INI) debug/$(APP_EXE): $(SDL_LIB) $(OBJS) mkdir -p debug cp $(SDL_LIB) debug/libSDL2-2.0.so.0 - $(CC) $(CFLAGS) -g $(INCS) $(LIBDIRS) $(OBJS) -o $@ $(LIBS) $(LFLAGS) + $(CXX) $(CXXFLAGS) $(CPPFLAGS) -g $(INCLUDE_DIRS) $(OBJS) -o $@ $(LDFLAGS) # release executable release/$(APP_EXE): $(SDL_LIB) $(OBJS) mkdir -p release cp $(SDL_LIB) release/libSDL2-2.0.so.0 - $(CC) $(CFLAGS) $(INCS) $(LIBDIRS) $(OBJS) -o $@ $(LIBS) $(LFLAGS) + $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(INCLUDE_DIRS) $(OBJS) -o $@ $(LDFLAGS) run-debug: debug/$(APP_EXE) ./debug/$(APP_EXE) diff --git a/macos/makefile b/macos/makefile index ecc2745..d3bb845 100644 --- a/macos/makefile +++ b/macos/makefile @@ -1,11 +1,12 @@ APP_NAME = Kiwi8 -# Use VERSION if set, otherwise fall back to GITHUB_REF_NAME, then default to unknown +# Use VERSION if set, otherwise fall back to GITHUB_REF_NAME, then default to develop VERSION ?= $(GITHUB_REF_NAME) ifeq ($(VERSION),) VERSION = develop endif +# Use SUB_VERSION if set, otherwise fall back to GITHUB_SHA, then default to unknown SUB_VERSION ?= $(GITHUB_SHA) ifeq ($(SUB_VERSION),) SUB_VERSION = unknown @@ -15,13 +16,27 @@ APP_MANIFEST = src/Info.plist APP_BUNDLE = $(APP_NAME).app APP_EXE = $(APP_NAME) -CC = clang++ -CFLAGS = -std=c++11 -Wall -mmacosx-version-min=11.0 -MMD -MP -DAPP_NAME='"$(APP_NAME)"' -DVERSION='"$(VERSION)"' -DSUB_VERSION='"$(SUB_VERSION)"' -LFLAGS = -mmacosx-version-min=11.0 -INCS = -I../external/sdl/build/include/ -I../external/imgui/ -I../external/stb/ -I../external/lekkit/ -LIBS = -L../external/sdl/build/lib/ -lSDL2-2.0.0 -framework Cocoa -framework OpenGL +CC = clang +CXX = clang++ +CFLAGS = -std=c11 +CPPFLAGS = -Wall \ + -mmacosx-version-min=11.0 \ + -MMD -MP -DAPP_NAME='"$(APP_NAME)"' \ + -DVERSION='"$(VERSION)"' \ + -DSUB_VERSION='"$(SUB_VERSION)"' + +CXXFLAGS = -std=c++11 +INCLUDE_DIRS = -I../external/sdl/build/include/ \ + -I../external/imgui/ \ + -I../external/stb/ \ + -I../external/lekkit/ + +LDFLAGS = -mmacosx-version-min=11.0 \ + -L../external/sdl/build/lib/ \ + -lSDL2-2.0.0 \ + -framework Cocoa \ + -framework OpenGL -# SDL dependency files SDL_LIB = ../external/sdl/build/lib/libSDL2-2.0.0.dylib # Generated headers @@ -29,19 +44,21 @@ LICENSE_HEADER = ../shared/license.h 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/input.cc ../shared/main.cc \ - ../shared/toast.cc ../shared/open_file_dialog.cc ../shared/profiles.cc -IMGUI_SRCS = ../external/imgui/imgui.cpp ../external/imgui/imgui_draw.cpp ../external/imgui/imgui_impl_sdl.cpp -SHA256_SRC = ../external/lekkit/sha256.cc -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)) \ - $(notdir $(SHA256_SRC:.cc=.o)) +OBJS = audio.o \ + chip8.o \ + display.o \ + gui.o \ + input.o \ + main.o \ + toast.o \ + open_file_dialog.o \ + profiles.o \ + imgui.o \ + imgui_draw.o \ + imgui_impl_sdl.o \ + sha256.o \ + file_dialog.o + DEPS = $(OBJS:.o=.d) PROFILES_INI = ../shared/profiles.ini @@ -75,16 +92,19 @@ $(APP_MANIFEST): $(APP_MANIFEST).in # Pattern rules for incremental compilation %.o: src/%.mm - $(CC) $(CFLAGS) $(INCS) -c $< -o $@ + $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(INCLUDE_DIRS) -c $< -o $@ %.o: ../external/imgui/%.cpp - $(CC) $(CFLAGS) $(INCS) -c $< -o $@ + $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(INCLUDE_DIRS) -c $< -o $@ + +%.o: ../external/lekkit/%.c + $(CC) $(CFLAGS) $(CPPFLAGS) $(INCLUDE_DIRS) -c $< -o $@ -%.o: ../external/lekkit/%.cc - $(CC) $(CFLAGS) $(INCS) -c $< -o $@ +%.o: ../shared/%.c $(LICENSE_HEADER) $(BOOTROM_HEADER) + $(CC) $(CFLAGS) $(CPPFLAGS) $(INCLUDE_DIRS) -c $< -o $@ %.o: ../shared/%.cc $(LICENSE_HEADER) $(BOOTROM_HEADER) - $(CC) $(CFLAGS) $(INCS) -c $< -o $@ + $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(INCLUDE_DIRS) -c $< -o $@ debug/profiles.ini: $(PROFILES_INI) mkdir -p debug @@ -98,7 +118,7 @@ release/$(APP_BUNDLE)/Contents/Resources/profiles.ini: $(PROFILES_INI) debug/$(APP_EXE): $(SDL_LIB) $(OBJS) mkdir -p debug cp $(SDL_LIB) debug/libSDL2-2.0.0.dylib - $(CC) $(CFLAGS) -g $(LIBS) $(INCS) $(OBJS) -o $@ $(LFLAGS) + $(CXX) $(CXXFLAGS) $(CPPFLAGS) -g $(INCLUDE_DIRS) $(OBJS) -o $@ $(LDFLAGS) # Set the dylib's install name to be relative to the bundle install_name_tool -id @executable_path/libSDL2-2.0.0.dylib debug/libSDL2-2.0.0.dylib @@ -109,7 +129,7 @@ debug/$(APP_EXE): $(SDL_LIB) $(OBJS) # release executable (inside .app bundle) release/$(APP_BUNDLE)/Contents/MacOS/$(APP_EXE): $(SDL_LIB) $(OBJS) mkdir -p release/$(APP_BUNDLE)/Contents/MacOS - $(CC) $(CFLAGS) $(LIBS) $(INCS) $(OBJS) -o $@ $(LFLAGS) + $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(INCLUDE_DIRS) $(OBJS) -o $@ $(LDFLAGS) # Fix executable's reference to SDL (from @rpath to bundle-relative path) install_name_tool -change @rpath/libSDL2-2.0.0.dylib @executable_path/../Frameworks/libSDL2-2.0.0.dylib release/$(APP_BUNDLE)/Contents/MacOS/$(APP_EXE) 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 index 78088a0..00a7166 100644 --- a/shared/audio.h +++ b/shared/audio.h @@ -1,9 +1,17 @@ #ifndef AUDIO_H #define AUDIO_H +#ifdef __cplusplus +extern "C" { +#endif + #include #include +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + #define TAU (2.0 * M_PI) #define AMPLITUDE 28000 // Max amplitude for signed 16-bit #define SAMPLE_RATE 48000 @@ -25,4 +33,8 @@ extern struct audio audio; void audio_destroy(void); int audio_init(void); +#ifdef __cplusplus +} +#endif + #endif // AUDIO_H diff --git a/shared/chip8.cc b/shared/chip8.c similarity index 99% rename from shared/chip8.cc rename to shared/chip8.c index 98a1bb5..76af933 100644 --- a/shared/chip8.cc +++ b/shared/chip8.c @@ -92,7 +92,7 @@ int chip8_init( /* load fontset */ for(int i = 0; i < FONTS_SIZE; ++i) { - chip8.memory[i] = chip8.chip8_fontset[i]; + chip8.memory[i] = chip8_fontset[i]; } /* Initialize ROM profile database */ @@ -222,7 +222,7 @@ void chip8_soft_reset() { /* load fontset */ for(int i = 0; i < FONTS_SIZE; ++i) { - chip8.memory[i] = chip8.chip8_fontset[i]; + chip8.memory[i] = chip8_fontset[i]; } /* copy the entire rom to memory starting from 0x200 */ diff --git a/shared/chip8.h b/shared/chip8.h index b1414e3..d6e438d 100644 --- a/shared/chip8.h +++ b/shared/chip8.h @@ -1,9 +1,14 @@ #ifndef CHIP8_H #define CHIP8_H +#ifdef __cplusplus +extern "C" { +#endif + #include "bootrom.h" // Generated at build time from roms/Kiwi8_logo_2.ch8 #include "quirks.h" #include +#include #define MEM_SIZE 4096 #define NUM_REGISTERS 16 @@ -15,6 +20,24 @@ #define MAX_CYCLES_PER_STEP 50 #define TICKS 60 /* hz - Timer count down rate */ +static 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 + }; + struct chip8 { /* number of cycles per step */ int cycles; @@ -63,23 +86,7 @@ struct chip8 { /* 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 */ @@ -138,4 +145,8 @@ void execFX55(void); void execFX65(void); void execUnknown(void); +#ifdef __cplusplus +} #endif + +#endif // 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 index 3f0e04c..e57e8d8 100644 --- a/shared/display.h +++ b/shared/display.h @@ -1,8 +1,13 @@ #ifndef DISPLAY_H #define DISPLAY_H +#ifdef __cplusplus +extern "C" { +#endif + #include #include +#include #define WIDTH 64 #define HEIGHT 32 @@ -51,4 +56,8 @@ void display_toggle_vsync(void); void display_raise_window(void); void display_render_frame(unsigned char **frame); +#ifdef __cplusplus +} +#endif + #endif diff --git a/shared/gui.cc b/shared/gui.cc index 098b6df..635e322 100644 --- a/shared/gui.cc +++ b/shared/gui.cc @@ -1,5 +1,4 @@ #include "gui.h" -#include "chip8.h" #include "display.h" #include "imgui.h" #include "imgui_impl_sdl.h" diff --git a/shared/gui.h b/shared/gui.h index 15c8cc1..b3619c7 100644 --- a/shared/gui.h +++ b/shared/gui.h @@ -1,7 +1,13 @@ #ifndef GUI_H #define GUI_H +#ifdef __cplusplus +extern "C" { +#endif + #include +#include +#include "chip8.h" #define MENU_HEIGHT 38 @@ -34,4 +40,8 @@ void gui_process_events(SDL_Event *event); void gui_new_frame(void); void gui_render(void); +#ifdef __cplusplus +} +#endif + #endif diff --git a/shared/input.cc b/shared/input.c similarity index 95% rename from shared/input.cc rename to shared/input.c index 7951ea4..9684c06 100644 --- a/shared/input.cc +++ b/shared/input.c @@ -60,8 +60,8 @@ static int input_process_events(void) { if (input.state[SDL_SCANCODE_RALT]) gui.show_fps_flag = !gui.show_fps_flag; /* slow/raise emulation speed */ - if (input.state[SDL_SCANCODE_PAGEDOWN]) (chip8.cycles -1 < MIN_CYCLES_PER_STEP ) ? chip8.cycles = MIN_CYCLES_PER_STEP : chip8.cycles -= 1; - if (input.state[SDL_SCANCODE_PAGEUP]) (chip8.cycles +1 > MAX_CYCLES_PER_STEP ) ? chip8.cycles = MAX_CYCLES_PER_STEP : chip8.cycles += 1; + if (input.state[SDL_SCANCODE_PAGEDOWN]) (chip8.cycles -1 < MIN_CYCLES_PER_STEP ) ? (chip8.cycles = MIN_CYCLES_PER_STEP) : (chip8.cycles -= 1); + if (input.state[SDL_SCANCODE_PAGEUP]) (chip8.cycles +1 > MAX_CYCLES_PER_STEP ) ? (chip8.cycles = MAX_CYCLES_PER_STEP) : (chip8.cycles += 1); } /* window events */ diff --git a/shared/input.h b/shared/input.h index 9aeb87b..f635f96 100644 --- a/shared/input.h +++ b/shared/input.h @@ -1,6 +1,11 @@ #ifndef INPUT_H #define INPUT_H +#ifdef __cplusplus +extern "C" { +#endif + +#include #include #define NUM_KEYS 16 @@ -32,4 +37,8 @@ extern struct input input; void input_reset(void); int input_poll(void); +#ifdef __cplusplus +} +#endif + #endif diff --git a/shared/main.cc b/shared/main.cc index ae89475..0ecbad5 100644 --- a/shared/main.cc +++ b/shared/main.cc @@ -2,6 +2,7 @@ #include "usage.h" #include #include +#include int main(int argc, char **argv){ diff --git a/shared/opcodes.h b/shared/opcodes.h index 7cb1318..e10c1d7 100644 --- a/shared/opcodes.h +++ b/shared/opcodes.h @@ -2,6 +2,10 @@ #ifndef OPCODES_H #define OPCODES_H +#ifdef __cplusplus +extern "C" { +#endif + #include "chip8.h" #include "display.h" /* for WIDTH and HEIGHT */ #include "input.h" @@ -103,7 +107,7 @@ inline void exec8XY4() { carry, and to 0 when there isn't */ unsigned short sum; sum = chip8.V[OP_Y] + chip8.V[OP_X]; - (sum > 0xFF) ? chip8.V[0xF] = 1 : chip8.V[0xF] = 0; + (sum > 0xFF) ? (chip8.V[0xF] = 1) : (chip8.V[0xF] = 0); /* only the lowest 8 bits are kept */ chip8.V[OP_X] = (unsigned char) sum; @@ -112,7 +116,7 @@ inline void exec8XY4() { 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 */ - (chip8.V[OP_Y] > chip8.V[OP_X]) ? chip8.V[0xF] = 0 : chip8.V[0xF] = 1; + (chip8.V[OP_Y] > chip8.V[OP_X]) ? (chip8.V[0xF] = 0) : (chip8.V[0xF] = 1); chip8.V[OP_X] -= chip8.V[OP_Y]; } @@ -120,19 +124,19 @@ 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. */ chip8.V[0xF] = chip8.V[OP_X] & 0x01; - chip8.quirks.shift_quirk ? chip8.V[OP_X] >>= 1 : chip8.V[OP_X] = chip8.V[OP_Y] >> 1; + chip8.quirks.shift_quirk ? (chip8.V[OP_X] >>= 1) : (chip8.V[OP_X] = chip8.V[OP_Y] >> 1); } 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. */ - (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[0xF] = 0) : (chip8.V[0xF] = 1); chip8.V[OP_X] = chip8.V[OP_Y] - chip8.V[OP_X]; } 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. */ chip8.V[0xF] = (chip8.V[OP_X] & 0x80) >> 7; - chip8.quirks.shift_quirk ? chip8.V[OP_X] <<= 1 : chip8.V[OP_X] = chip8.V[OP_Y] << 1; + chip8.quirks.shift_quirk ? (chip8.V[OP_X] <<= 1) : (chip8.V[OP_X] = chip8.V[OP_Y] << 1); } inline void exec9XY0() { @@ -273,4 +277,8 @@ inline void execUnknown() { fprintf (stderr, "Unknown opcode: 0x%X\n", chip8.opcode); } +#ifdef __cplusplus +} +#endif + #endif // OPCODES_H diff --git a/shared/open_file_dialog.h b/shared/open_file_dialog.h index 042c722..a0837b3 100644 --- a/shared/open_file_dialog.h +++ b/shared/open_file_dialog.h @@ -1,6 +1,10 @@ #ifndef OPEN_FILE_DIALOG_H #define OPEN_FILE_DIALOG_H +#ifdef __cplusplus +extern "C" { +#endif + #ifdef __APPLE__ #include /* PATH_MAX */ #endif @@ -16,4 +20,8 @@ int open_file_dialog(char *rom_name); +#ifdef __cplusplus +} +#endif + #endif diff --git a/shared/profiles.cc b/shared/profiles.c similarity index 100% rename from shared/profiles.cc rename to shared/profiles.c diff --git a/shared/profiles.h b/shared/profiles.h index c621baa..59d6602 100644 --- a/shared/profiles.h +++ b/shared/profiles.h @@ -1,6 +1,10 @@ #ifndef PROFILES_H #define PROFILES_H +#ifdef __cplusplus +extern "C" { +#endif + #include #include "quirks.h" #include "sha256.h" @@ -25,4 +29,8 @@ const struct profile* profile_lookup(const sha256_hash_t *sha256); * Also adds profile to runtime hashmap immediately */ void profiles_save_current(void); +#ifdef __cplusplus +} +#endif + #endif /* PROFILES_H */ diff --git a/shared/quirks.h b/shared/quirks.h index eb8501d..bd620db 100644 --- a/shared/quirks.h +++ b/shared/quirks.h @@ -1,6 +1,12 @@ #ifndef QUIRKS_H #define QUIRKS_H +#ifdef __cplusplus +extern "C" { +#endif + +#include + /* * X-macro list of all quirk fields. * Format: X(field_name, default_value) @@ -33,4 +39,8 @@ static inline struct quirks quirks_get_defaults(void) { return defaults; } +#ifdef __cplusplus +} +#endif + #endif // QUIRKS_H diff --git a/shared/toast.cc b/shared/toast.c similarity index 100% rename from shared/toast.cc rename to shared/toast.c diff --git a/shared/toast.h b/shared/toast.h index 87241e6..9816700 100644 --- a/shared/toast.h +++ b/shared/toast.h @@ -1,6 +1,10 @@ #ifndef TOAST_H #define TOAST_H +#ifdef __cplusplus +extern "C" { +#endif + /* Toast struct definition */ struct toast { char message[256]; @@ -31,4 +35,8 @@ const struct toast* toast_get_toasts(int *count); int toast_is_active(const struct toast *t); void toast_get_info(const struct toast *t, const char **message, int *type, double *time); +#ifdef __cplusplus +} #endif + +#endif // TOAST_H diff --git a/tools/generate_bootrom_header.py b/tools/generate_bootrom_header.py index 3d717fa..bfa742c 100644 --- a/tools/generate_bootrom_header.py +++ b/tools/generate_bootrom_header.py @@ -9,28 +9,28 @@ def generate_header(rom_file, output_file): """Generate C++ header with ROM data as byte array.""" - + if not os.path.exists(rom_file): print(f"Error: ROM file '{rom_file}' not found", file=sys.stderr) sys.exit(1) - + # Read binary data with open(rom_file, 'rb') as f: rom_data = f.read() - + rom_size = len(rom_data) rom_name = os.path.splitext(os.path.basename(rom_file))[0] - + # Format bytes as hex, 8 per line hex_lines = [] for i in range(0, rom_size, 8): chunk = rom_data[i:i+8] hex_bytes = ', '.join(f'0x{b:02x}' for b in chunk) hex_lines.append(f' {hex_bytes}') - + # Join with commas and newlines formatted_data = ',\n'.join(hex_lines) - + # Generate header content header_content = f"""// Auto-generated file - DO NOT EDIT // Generated from {os.path.basename(rom_file)} @@ -38,27 +38,35 @@ def generate_header(rom_file, output_file): #ifndef BOOTROM_H #define BOOTROM_H +#ifdef __cplusplus +extern "C" {{ +#endif + #define BOOTROM_SIZE {rom_size} /* {os.path.basename(rom_file)} */ -const unsigned char bootrom[BOOTROM_SIZE] = {{ +static const unsigned char bootrom[BOOTROM_SIZE] = {{ {formatted_data} }}; +#ifdef __cplusplus +}} +#endif + #endif // BOOTROM_H """ - + # Write header file with open(output_file, 'w', encoding='utf-8') as f: f.write(header_content) - + print(f"Generated {output_file} from {rom_file} ({rom_size} bytes)") if __name__ == '__main__': if len(sys.argv) != 3: print("Usage: python3 generate_bootrom_header.py ") sys.exit(1) - + rom_file = sys.argv[1] output_file = sys.argv[2] generate_header(rom_file, output_file) diff --git a/tools/generate_license_header.py b/tools/generate_license_header.py index e9ec1ff..d44d7b2 100644 --- a/tools/generate_license_header.py +++ b/tools/generate_license_header.py @@ -59,9 +59,17 @@ def generate_header(license_file, output_file): #ifndef LICENSE_H #define LICENSE_H -const char* LICENSE_TEXT = +#ifdef __cplusplus +extern "C" {{ +#endif + +static const char* LICENSE_TEXT = {chr(10).join(cpp_lines)}; +#ifdef __cplusplus +}} +#endif + #endif // LICENSE_H """ diff --git a/windows/makefile b/windows/makefile index 343d4b2..c262232 100644 --- a/windows/makefile +++ b/windows/makefile @@ -1,6 +1,6 @@ APP_NAME = Kiwi8 -# Use VERSION if set, otherwise fall back to GITHUB_REF_NAME, then default to unknown +# Use VERSION if set, otherwise fall back to GITHUB_REF_NAME, then default to develop !IFNDEF VERSION !IFDEF GITHUB_REF_NAME VERSION = $(GITHUB_REF_NAME) @@ -9,6 +9,7 @@ VERSION = develop !ENDIF !ENDIF +# Use SUB_VERSION if set, otherwise fall back to GITHUB_SHA, then default to unknown !IFNDEF SUB_VERSION !IFDEF GITHUB_SHA SUB_VERSION = $(GITHUB_SHA) @@ -17,66 +18,76 @@ SUB_VERSION = unknown !ENDIF !ENDIF +# Detect architecture from environment (set by MSVC vcvarsall.bat) +# VSCMD_ARG_TGT_ARCH is set to x64, x86, arm64, or arm +!IFNDEF SDL_ARCH +!IFDEF VSCMD_ARG_TGT_ARCH +SDL_ARCH = $(VSCMD_ARG_TGT_ARCH) +!ELSE +SDL_ARCH = x64 +!ENDIF +!ENDIF + APP_EXE = $(APP_NAME).exe APP_PDB = $(APP_NAME).pdb APP_RES = $(APP_NAME).res CC = CL -CFLAGS = /std:c++11 /W4 /MD /nologo /w44996 "/DAPP_NAME=\"$(APP_NAME)\"" "/DVERSION=\"$(VERSION)\"" "/DSUB_VERSION=\"$(SUB_VERSION)\"" - -LFLAGS = /link \ - /LIBPATH:..\external\sdl\build\lib \ - /ENTRY:mainCRTStartup - -INCS = /I..\.shared \ +CXX = CL +CFLAGS = /std:c11 +CPPFLAGS = /W4 \ + /MD \ + /nologo \ + /w44996 \ + "/DAPP_NAME=\"$(APP_NAME)\"" \ + "/DVERSION=\"$(VERSION)\"" \ + "/DSUB_VERSION=\"$(SUB_VERSION)\"" + +CXXFLAGS = /std:c++11 +INCLUDE_DIRS = /I..\shared \ /I..\external\sdl\build\include \ /I..\external\imgui \ /I..\external\stb \ /I..\external\lekkit -LIBS = user32.lib \ +LDFLAGS = /link \ + /LIBPATH:..\external\sdl\build\lib \ + /ENTRY:mainCRTStartup \ + user32.lib \ SDL2.lib \ SDL2main.lib \ opengl32.lib \ Comdlg32.lib \ Shell32.lib -# SDL dependency files +# SDL2.dll is built in the same step as the static libs SDL_LIB = ..\external\sdl\build\lib\SDL2.lib -SDL_DLL = ..\external\sdl\build\bin\SDL2.dll # Generated headers LICENSE_HEADER = ..\shared\license.h 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\input.cc ..\shared\main.cc \ - ..\shared\toast.cc ..\shared\open_file_dialog.cc ..\shared\profiles.cc -IMGUI_SRCS = ..\external\imgui\imgui.cpp ..\external\imgui\imgui_draw.cpp ..\external\imgui\imgui_impl_sdl.cpp -WINDOWS_SRCS = src\file_dialog.cc -SHA256_SRC = ..\external\lekkit\sha256.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 toast.obj profiles.obj open_file_dialog.obj imgui.obj imgui_draw.obj \ - file_dialog.obj sha256.obj +OBJS = audio.obj \ + chip8.obj \ + display.obj \ + gui.obj \ + imgui_impl_sdl.obj \ + input.obj \ + main.obj \ + toast.obj \ + profiles.obj \ + open_file_dialog.obj \ + imgui.obj \ + imgui_draw.obj \ + file_dialog.obj \ + sha256.obj PROFILES_INI = ..\shared\profiles.ini # Default target all: debug\profiles.ini debug\$(APP_EXE) release\profiles.ini release\$(APP_EXE) -# Detect architecture from environment (set by MSVC vcvarsall.bat) -# VSCMD_ARG_TGT_ARCH is set to x64, x86, arm64, or arm -!IFNDEF SDL_ARCH -!IFDEF VSCMD_ARG_TGT_ARCH -SDL_ARCH = $(VSCMD_ARG_TGT_ARCH) -!ELSE -SDL_ARCH = x64 -!ENDIF -!ENDIF # Build SDL (force rebuild with: nmake sdl) sdl: @@ -86,9 +97,6 @@ sdl: $(SDL_LIB): powershell -ExecutionPolicy Bypass -File build_sdl.ps1 -ARCH $(SDL_ARCH) -$(SDL_DLL): $(SDL_LIB) - @REM DLL is created by same script that creates LIB - # Generate license header from LICENSE file $(LICENSE_HEADER): ..\LICENSE python3 ..\tools\generate_license_header.py ..\LICENSE $(LICENSE_HEADER) @@ -98,24 +106,27 @@ $(BOOTROM_HEADER): $(BOOTROM_SOURCE) python3 ..\tools\generate_bootrom_header.py $(BOOTROM_SOURCE) $(BOOTROM_HEADER) # Inference rules for incremental compilation -{..\shared}.cc{}.obj: - $(CC) $(CFLAGS) /c $(INCS) $< - {src}.cc{}.obj: - $(CC) $(CFLAGS) /c $(INCS) $< + $(CXX) $(CXXFLAGS) $(CPPFLAGS) /c $(INCLUDE_DIRS) $< {..\external\imgui}.cpp{}.obj: - $(CC) $(CFLAGS) /c $(INCS) $< + $(CXX) $(CXXFLAGS) $(CPPFLAGS) /c $(INCLUDE_DIRS) $< -{..\external\lekkit}.cc{}.obj: - $(CC) $(CFLAGS) /c $(INCS) $< +{..\external\lekkit}.c{}.obj: + $(CC) $(CFLAGS) $(CPPFLAGS) /c $(INCLUDE_DIRS) $< + +{..\shared}.c{}.obj: + $(CC) $(CFLAGS) $(CPPFLAGS) /c $(INCLUDE_DIRS) $< + +{..\shared}.cc{}.obj: + $(CXX) $(CXXFLAGS) $(CPPFLAGS) /c $(INCLUDE_DIRS) $< # Explicit rules for files depending on generated headers gui.obj: ..\shared\gui.cc $(LICENSE_HEADER) - $(CC) $(CFLAGS) /c $(INCS) ..\shared\gui.cc + $(CC) $(CFLAGS) $(CPPFLAGS) /c $(INCLUDE_DIRS) ..\shared\gui.cc -chip8.obj: ..\shared\chip8.cc $(BOOTROM_HEADER) - $(CC) $(CFLAGS) /c $(INCS) ..\shared\chip8.cc +chip8.obj: ..\shared\chip8.c $(BOOTROM_HEADER) + $(CC) $(CFLAGS) $(CPPFLAGS) /c $(INCLUDE_DIRS) ..\shared\chip8.c $(APP_RES): src\Kiwi8.rc resources\Kiwi8.ico RC src\Kiwi8.rc @@ -129,16 +140,16 @@ release\profiles.ini: $(PROFILES_INI) IF NOT EXIST release MKDIR release COPY $(PROFILES_INI) release\profiles.ini -debug\$(APP_EXE): $(SDL_LIB) $(SDL_DLL) $(OBJS) $(APP_RES) - $(CC) $(CFLAGS) /Zi /Fe$(APP_NAME) $(INCS) $(OBJS) $(APP_RES) $(LIBS) $(LFLAGS) /SUBSYSTEM:CONSOLE +debug\$(APP_EXE): $(SDL_LIB) $(OBJS) $(APP_RES) + $(CXX) $(CXXFLAGS) $(CPPFLAGS) /Zi /Fe$(APP_NAME) $(INCLUDE_DIRS) $(OBJS) $(APP_RES) $(LDFLAGS) /SUBSYSTEM:CONSOLE IF NOT EXIST debug MKDIR debug - COPY $(SDL_DLL) debug\SDL2.dll + COPY ..\external\sdl\build\bin\SDL2.dll debug\SDL2.dll MOVE $(APP_EXE) $@ -release\$(APP_EXE): $(SDL_LIB) $(SDL_DLL) $(OBJS) $(APP_RES) - $(CC) $(CFLAGS) /Fe$(APP_NAME) $(INCS) $(OBJS) $(APP_RES) $(LIBS) $(LFLAGS) /SUBSYSTEM:WINDOWS +release\$(APP_EXE): $(SDL_LIB) $(OBJS) $(APP_RES) + $(CXX) $(CXXFLAGS) $(CPPFLAGS) /Fe$(APP_NAME) $(INCLUDE_DIRS) $(OBJS) $(APP_RES) $(LDFLAGS) /SUBSYSTEM:WINDOWS IF NOT EXIST release MKDIR release - COPY $(SDL_DLL) release\SDL2.dll + COPY ..\external\sdl\build\bin\SDL2.dll release\SDL2.dll MOVE $(APP_EXE) $@ run-debug: From 651bb314adb0a7ef52465d7e2c9050378fa127e4 Mon Sep 17 00:00:00 2001 From: Thomas Daley Date: Sat, 21 Feb 2026 15:13:23 -0800 Subject: [PATCH 05/15] have each OS only supply the impl not another unnecessary header --- linux/makefile | 6 +-- linux/src/file_dialog.h | 9 ----- .../{file_dialog.cc => open_file_dialog.cc} | 13 ++++++- macos/makefile | 6 +-- macos/src/file_dialog.h | 9 ----- .../{file_dialog.mm => open_file_dialog.mm} | 12 +++++- shared/open_file_dialog.cc | 38 ------------------- windows/makefile | 3 +- windows/src/file_dialog.h | 6 --- .../{file_dialog.cc => open_file_dialog.cc} | 4 ++ 10 files changed, 34 insertions(+), 72 deletions(-) delete mode 100644 linux/src/file_dialog.h rename linux/src/{file_dialog.cc => open_file_dialog.cc} (82%) delete mode 100644 macos/src/file_dialog.h rename macos/src/{file_dialog.mm => open_file_dialog.mm} (77%) delete mode 100644 shared/open_file_dialog.cc delete mode 100644 windows/src/file_dialog.h rename windows/src/{file_dialog.cc => open_file_dialog.cc} (90%) diff --git a/linux/makefile b/linux/makefile index f6550f9..e55b5c0 100644 --- a/linux/makefile +++ b/linux/makefile @@ -26,7 +26,8 @@ CPPFLAGS = -Wall \ CXXFLAGS = -std=gnu++11 -INCLUDE_DIRS = -I../external/sdl/build/include/ \ +INCLUDE_DIRS = -I../shared \ + -I../external/sdl/build/include/ \ -I../external/imgui/ \ -I../external/stb/ \ -I../external/lekkit/ @@ -75,8 +76,7 @@ OBJS = audio.o \ imgui.o \ imgui_draw.o \ imgui_impl_sdl.o \ - sha256.o \ - file_dialog.o + sha256.o DEPS = $(OBJS:.o=.d) diff --git a/linux/src/file_dialog.h b/linux/src/file_dialog.h deleted file mode 100644 index 617a50a..0000000 --- a/linux/src/file_dialog.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef FILE_DIALOG_H -#define FILE_DIALOG_H - -#include -#include - -std::vector open_file_dialog(const std::string &title, const std::string &defaultDir, const std::vector &filterExtensions); - -#endif diff --git a/linux/src/file_dialog.cc b/linux/src/open_file_dialog.cc similarity index 82% rename from linux/src/file_dialog.cc rename to linux/src/open_file_dialog.cc index 56e7974..45513ce 100644 --- a/linux/src/file_dialog.cc +++ b/linux/src/open_file_dialog.cc @@ -1,6 +1,8 @@ -#include "file_dialog.h" +#include "open_file_dialog.h" #include #include +#include +#include std::vector open_file_dialog(const std::string &title, const std::string &defaultDir, const std::vector &filterExtensions) { std::vector result; @@ -65,3 +67,12 @@ std::vector open_file_dialog(const std::string &title, const std::s return result; } + +int open_file_dialog(char *rom_name) { + std::vector fileTypes = {"ch8", "CH8", "chip-8", "CHIP-8", "Chip-8"}; + const char* defaultDir = ""; // unify behavior: let OS choose last-used/home + std::vector files = open_file_dialog("Chip8", defaultDir, fileTypes); + if (files.empty()) return 1; + snprintf(rom_name, 256, "%s", files[0].c_str()); + return 0; +} diff --git a/macos/makefile b/macos/makefile index d3bb845..11ed66c 100644 --- a/macos/makefile +++ b/macos/makefile @@ -26,7 +26,8 @@ CPPFLAGS = -Wall \ -DSUB_VERSION='"$(SUB_VERSION)"' CXXFLAGS = -std=c++11 -INCLUDE_DIRS = -I../external/sdl/build/include/ \ +INCLUDE_DIRS = -I../shared \ + -I../external/sdl/build/include/ \ -I../external/imgui/ \ -I../external/stb/ \ -I../external/lekkit/ @@ -56,8 +57,7 @@ OBJS = audio.o \ imgui.o \ imgui_draw.o \ imgui_impl_sdl.o \ - sha256.o \ - file_dialog.o + sha256.o DEPS = $(OBJS:.o=.d) diff --git a/macos/src/file_dialog.h b/macos/src/file_dialog.h deleted file mode 100644 index 0474469..0000000 --- a/macos/src/file_dialog.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef APPLE_FILE_DIALOG_H -#define APPLE_FILE_DIALOG_H - -#include -#include - -std::vectoropen_file_dialog(char const * const aTitle, char const * const aDefaultPathAndFile, const std::vector & filters); - -#endif diff --git a/macos/src/file_dialog.mm b/macos/src/open_file_dialog.mm similarity index 77% rename from macos/src/file_dialog.mm rename to macos/src/open_file_dialog.mm index f672321..2e5e422 100644 --- a/macos/src/file_dialog.mm +++ b/macos/src/open_file_dialog.mm @@ -1,8 +1,9 @@ -#import "file_dialog.h" +#import "open_file_dialog.h" #import #import #include #include +#include std::vectoropen_file_dialog( char const * const aTitle , @@ -41,3 +42,12 @@ } return fileList; } + +int open_file_dialog(char *rom_name) { + std::vector fileTypes = {"ch8", "CH8", "chip-8", "CHIP-8", "Chip-8"}; + const char* defaultDir = ""; // unify behavior: let OS choose last-used/home + std::vector files = open_file_dialog("Chip8", defaultDir, fileTypes); + if (files.empty()) return 1; + snprintf(rom_name, 256, "%s", files[0].c_str()); + return 0; +} diff --git a/shared/open_file_dialog.cc b/shared/open_file_dialog.cc deleted file mode 100644 index c69a80d..0000000 --- a/shared/open_file_dialog.cc +++ /dev/null @@ -1,38 +0,0 @@ -#include "open_file_dialog.h" - -#include -#include -#include - -#ifdef __APPLE__ -#include "../macos/src/file_dialog.h" -#endif - -#ifdef _WIN32 -#include "../windows/src/file_dialog.h" -#endif - -#ifdef __linux__ -#include "../linux/src/file_dialog.h" -#endif - -/* Returns 0 on success, 1 on error (or user hit cancel) */ -int open_file_dialog(char *rom_name) { - - #if defined(__APPLE__) || defined(__linux__) - // Common flow for Apple and Linux: both return a vector - std::vector fileTypes = {"ch8", "CH8", "chip-8", "CHIP-8", "Chip-8"}; - const char* defaultDir = ""; // unify behavior: let OS choose last-used/home - std::vector files = open_file_dialog("Chip8", defaultDir, fileTypes); - if (files.empty()) return 1; - snprintf(rom_name, 256, "%s", files[0].c_str()); - return 0; - - #elif defined(_WIN32) - // Windows API variant writes directly into buffer and returns int - return open_file_dialog(rom_name, "Chip8\0*.ch8\0All\0*.*\0"); - - #else - return 1; - #endif -} diff --git a/windows/makefile b/windows/makefile index c262232..4bbf845 100644 --- a/windows/makefile +++ b/windows/makefile @@ -72,15 +72,14 @@ OBJS = audio.obj \ chip8.obj \ display.obj \ gui.obj \ - imgui_impl_sdl.obj \ input.obj \ main.obj \ toast.obj \ profiles.obj \ open_file_dialog.obj \ + imgui_impl_sdl.obj \ imgui.obj \ imgui_draw.obj \ - file_dialog.obj \ sha256.obj PROFILES_INI = ..\shared\profiles.ini diff --git a/windows/src/file_dialog.h b/windows/src/file_dialog.h deleted file mode 100644 index 989b4bc..0000000 --- a/windows/src/file_dialog.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef WIN32_FILE_DIALOG_H -#define WIN32_FILE_DIALOG_H - -int open_file_dialog(char *rom_name, char *filters); - -#endif diff --git a/windows/src/file_dialog.cc b/windows/src/open_file_dialog.cc similarity index 90% rename from windows/src/file_dialog.cc rename to windows/src/open_file_dialog.cc index af0a338..c3731d0 100644 --- a/windows/src/file_dialog.cc +++ b/windows/src/open_file_dialog.cc @@ -38,3 +38,7 @@ int open_file_dialog(char *rom_name, char *filters) { strcpy(rom_name, szFile); return 0; } + +int open_file_dialog(char *rom_name) { + return open_file_dialog(rom_name, "Chip8\0*.ch8\0All\0*.*\0"); +} From 5bee11b6c1baca96b957c632641b001cc1abae15 Mon Sep 17 00:00:00 2001 From: Thomas Daley Date: Sat, 21 Feb 2026 15:23:22 -0800 Subject: [PATCH 06/15] there is no std=c++11 flag for MSVC --- windows/makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/windows/makefile b/windows/makefile index 4bbf845..9bcaa8d 100644 --- a/windows/makefile +++ b/windows/makefile @@ -43,7 +43,7 @@ CPPFLAGS = /W4 \ "/DVERSION=\"$(VERSION)\"" \ "/DSUB_VERSION=\"$(SUB_VERSION)\"" -CXXFLAGS = /std:c++11 +CXXFLAGS = /std:c11 INCLUDE_DIRS = /I..\shared \ /I..\external\sdl\build\include \ /I..\external\imgui \ From 077cb4dbe6abf2ae6ab1c376f152d3f1a1647311 Mon Sep 17 00:00:00 2001 From: Thomas Daley Date: Sat, 21 Feb 2026 15:23:55 -0800 Subject: [PATCH 07/15] fix include --- windows/src/open_file_dialog.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/windows/src/open_file_dialog.cc b/windows/src/open_file_dialog.cc index c3731d0..b85e087 100644 --- a/windows/src/open_file_dialog.cc +++ b/windows/src/open_file_dialog.cc @@ -1,4 +1,4 @@ -#include "file_dialog.h" +#include "open_file_dialog.h" #include #include #include From 0abb72fed7196523aa4a5f69744fc06d1c4fc61d Mon Sep 17 00:00:00 2001 From: Thomas Daley Date: Sun, 22 Feb 2026 10:03:41 -0800 Subject: [PATCH 08/15] does this work with MSVC? --- shared/chip8.c | 76 ++++++++++++++++++++++++------------------------ shared/chip8.h | 72 ++++++++++++++++++++++----------------------- shared/opcodes.h | 72 ++++++++++++++++++++++----------------------- 3 files changed, 110 insertions(+), 110 deletions(-) diff --git a/shared/chip8.c b/shared/chip8.c index 76af933..d472b34 100644 --- a/shared/chip8.c +++ b/shared/chip8.c @@ -346,53 +346,53 @@ void chip8_execute_opcode(){ switch (OP) { case 0x0: switch (OP_NNN) { - case 0x0E0: exec00E0(); break; - case 0x0EE: exec00EE(); break; - default: exec0NNN(); break; + case 0x0E0: exec_00E0(); break; + case 0x0EE: exec_00EE(); break; + default: exec_0NNN(); break; } break; - case 0x1: exec1NNN(); break; - case 0x2: exec2NNN(); break; - case 0x3: exec3XNN(); break; - case 0x4: exec4XNN(); break; - case 0x5: exec5XY0(); break; - case 0x6: exec6XNN(); break; - case 0x7: exec7XNN(); break; + case 0x1: exec_1NNN(); break; + case 0x2: exec_2NNN(); break; + case 0x3: exec_3XNN(); break; + case 0x4: exec_4XNN(); break; + case 0x5: exec_5XY0(); break; + case 0x6: exec_6XNN(); break; + case 0x7: exec_7XNN(); break; case 0x8: switch (OP_N) { - case 0x0: exec8XY0(); break; - case 0x1: exec8XY1(); break; - case 0x2: exec8XY2(); break; - case 0x3: exec8XY3(); break; - case 0x4: exec8XY4(); break; - case 0x5: exec8XY5(); break; - case 0x6: exec8XY6(); break; - case 0x7: exec8XY7(); break; - case 0xE: exec8XYE(); break; - default: execUnknown(); break; + case 0x0: exec_8XY0(); break; + case 0x1: exec_8XY1(); break; + case 0x2: exec_8XY2(); break; + case 0x3: exec_8XY3(); break; + case 0x4: exec_8XY4(); break; + case 0x5: exec_8XY5(); break; + case 0x6: exec_8XY6(); break; + case 0x7: exec_8XY7(); break; + case 0xE: exec_8XYE(); break; + default: exec_unknown(); break; } break; - case 0x9: exec9XY0(); break; - case 0xA: execANNN(); break; - case 0xB: execBNNN(); break; - case 0xC: execCXNN(); break; - case 0xD: execDXYN(); break; + case 0x9: exec_9XY0(); break; + case 0xA: exec_ANNN(); break; + case 0xB: exec_BNNN(); break; + case 0xC: exec_CXNN(); break; + case 0xD: exec_DXYN(); break; case 0xE: switch(OP_NN) { - case 0x9E: execEX9E(); break; - case 0xA1: execEXA1(); break; - default: execUnknown(); break; + case 0x9E: exec_EX9E(); break; + case 0xA1: exec_EXA1(); break; + default: exec_unknown(); break; } break; case 0xF: switch (OP_NN) { - case 0x07: execFX07(); break; - case 0x0A: execFX0A(); break; - case 0x15: execFX15(); break; - case 0x18: execFX18(); break; - case 0x1E: execFX1E(); break; - case 0x29: execFX29(); break; - case 0x33: execFX33(); break; - case 0x55: execFX55(); break; - case 0x65: execFX65(); break; - default: execUnknown(); break; + case 0x07: exec_FX07(); break; + case 0x0A: exec_FX0A(); break; + case 0x15: exec_FX15(); break; + case 0x18: exec_FX18(); break; + case 0x1E: exec_FX1E(); break; + case 0x29: exec_FX29(); break; + case 0x33: exec_FX33(); break; + case 0x55: exec_FX55(); break; + case 0x65: exec_FX65(); break; + default: exec_unknown(); break; } break; } } diff --git a/shared/chip8.h b/shared/chip8.h index d6e438d..150604f 100644 --- a/shared/chip8.h +++ b/shared/chip8.h @@ -108,42 +108,42 @@ 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); +// void exec_00E0(void); +// void exec_00EE(void); +// void exec_0NNN(void); +// void exec_1NNN(void); +// void exec_2NNN(void); +// void exec_3XNN(void); +// void exec_4XNN(void); +// void exec_5XY0(void); +// void exec_6XNN(void); +// void exec_7XNN(void); +// void exec_8XY0(void); +// void exec_8XY1(void); +// void exec_8XY2(void); +// void exec_8XY3(void); +// void exec_8XY4(void); +// void exec_8XY5(void); +// void exec_8XY6(void); +// void exec_8XY7(void); +// void exec_8XYE(void); +// void exec_9XY0(void); +// void exec_ANNN(void); +// void exec_BNNN(void); +// void exec_CXNN(void); +// void exec_DXYN(void); +// void exec_EX9E(void); +// void exec_EXA1(void); +// void exec_FX07(void); +// void exec_FX0A(void); +// void exec_FX15(void); +// void exec_FX18(void); +// void exec_FX1E(void); +// void exec_FX29(void); +// void exec_FX33(void); +// void exec_FX55(void); +// void exec_FX65(void); +// void exec_unknown(void); #ifdef __cplusplus } diff --git a/shared/opcodes.h b/shared/opcodes.h index e10c1d7..871c14d 100644 --- a/shared/opcodes.h +++ b/shared/opcodes.h @@ -21,7 +21,7 @@ extern "C" { #define OP_X ((chip8.opcode & 0x0F00) >> 8) #define OP_Y ((chip8.opcode & 0x00F0) >> 4) -inline void exec00E0() { +static inline void exec_00E0() { /* 0x00E0: clears the screen */ for (int i = 0; i < WIDTH; i++) { memset(chip8.vram[i], 0, HEIGHT * sizeof(unsigned char)); @@ -29,80 +29,80 @@ inline void exec00E0() { chip8.draw_flag = 1; } -inline void exec00EE() { +static inline void exec_00EE() { /* 0x00EE: returns from subroutine */ chip8.sp--; chip8.PC = chip8.stack[chip8.sp]; } -inline void exec0NNN() { +static inline void exec_0NNN() { /* 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. */ } -inline void exec1NNN() { +static inline void exec_1NNN() { /* 0x1NNN: jumps to address NNN */ chip8.PC = OP_NNN; } -inline void exec2NNN() { +static inline void exec_2NNN() { /* 0x2NNN: calls subroutine at NNN */ chip8.stack[chip8.sp] = chip8.PC; chip8.sp++; chip8.PC = OP_NNN; } -inline void exec3XNN() { +static inline void exec_3XNN() { /* 0x3XNN: skips the next instruction if VX equals NN */ if (chip8.V[OP_X] == OP_NN) chip8.PC += 2; } -inline void exec4XNN() { +static inline void exec_4XNN() { /* 0x4XNN: skips the next instruction if VX doesn't equal NN */ if (chip8.V[OP_X] != OP_NN) chip8.PC += 2; } -inline void exec5XY0() { +static inline void exec_5XY0() { /* 0x5XY0: skips the next instruction if VX equals VY */ if (chip8.V[OP_X] == chip8.V[OP_Y]) chip8.PC += 2; } -inline void exec6XNN() { +static inline void exec_6XNN() { /* 0x6XNN: sets VX to NN */ chip8.V[OP_X] = OP_NN; } -inline void exec7XNN() { +static inline void exec_7XNN() { /* 0x7XNN: adds NN to VX */ chip8.V[OP_X] += OP_NN; } -inline void exec8XY0() { +static inline void exec_8XY0() { /* 0x8XY0: sets VX to the value of VY */ chip8.V[OP_X] = chip8.V[OP_Y]; } -inline void exec8XY1() { +static inline void exec_8XY1() { /* 0x8XY1: sets VX to VX or VY */ chip8.V[OP_X] |= chip8.V[OP_Y]; if (chip8.quirks.logic_vf_quirk) chip8.V[0xF] = 0; } -inline void exec8XY2() { +static inline void exec_8XY2() { /* 0x8XY2: sets VX to VX and VY */ chip8.V[OP_X] &= chip8.V[OP_Y]; if (chip8.quirks.logic_vf_quirk) chip8.V[0xF] = 0; } -inline void exec8XY3() { +static inline void exec_8XY3() { /* 0x8XY3: sets VX to VX xor VY */ chip8.V[OP_X] ^= chip8.V[OP_Y]; if (chip8.quirks.logic_vf_quirk) chip8.V[0xF] = 0; } -inline void exec8XY4() { +static inline void exec_8XY4() { /* 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; @@ -113,50 +113,50 @@ inline void exec8XY4() { chip8.V[OP_X] = (unsigned char) sum; } -inline void exec8XY5() { +static inline void exec_8XY5() { /* 0x8XY5: VY is subtracted from VX. VF is set to 0 when there's a borrow, and 1 when there isn't */ (chip8.V[OP_Y] > chip8.V[OP_X]) ? (chip8.V[0xF] = 0) : (chip8.V[0xF] = 1); chip8.V[OP_X] -= chip8.V[OP_Y]; } -inline void exec8XY6() { +static inline void exec_8XY6() { /* 0x8XY6: shifts VX right by one. VF is set to the value of the least significant bit of VX before the shift. */ chip8.V[0xF] = chip8.V[OP_X] & 0x01; chip8.quirks.shift_quirk ? (chip8.V[OP_X] >>= 1) : (chip8.V[OP_X] = chip8.V[OP_Y] >> 1); } -inline void exec8XY7() { +static inline void exec_8XY7() { /* 0x8XY7: sets VX to VY minus VX. VF is set to 0 when there's a borrow, and 1 when there isn't. */ (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]; } -inline void exec8XYE() { +static inline void exec_8XYE() { /* 0x8XYE: shifts VX left by one. VF is set to the value of the most significant bit of VX before the shift. */ chip8.V[0xF] = (chip8.V[OP_X] & 0x80) >> 7; chip8.quirks.shift_quirk ? (chip8.V[OP_X] <<= 1) : (chip8.V[OP_X] = chip8.V[OP_Y] << 1); } -inline void exec9XY0() { +static inline void exec_9XY0() { /* 0x9XY0: skips the next instruction if VX doesn't equal VY */ if (chip8.V[OP_X] != chip8.V[OP_Y]) chip8.PC +=2; } -inline void execANNN() { +static inline void exec_ANNN() { /* ANNN: sets I to the address NNN */ chip8.I = OP_NNN; } -inline void execBNNN() { +static inline void exec_BNNN() { /* BNNN: jumps to the address NNN plus V0 or VX (quirk) */ chip8.PC = OP_NNN + (chip8.quirks.jump_quirk ? chip8.V[OP_X] : chip8.V[0]); } -inline void execCXNN() { +static inline void exec_CXNN() { /* CXNN: sets VX to the result of a bitwise and operation on a random number and NN */ chip8.V[OP_X] = (rand() % 0xFF) & OP_NN; } -inline void execDXYN() { +static inline void exec_DXYN() { /* 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 @@ -185,21 +185,21 @@ inline void execDXYN() { chip8.draw_flag = 1; } -inline void execEX9E() { +static inline void exec_EX9E() { /* EX9E: skips the next instruction if the key stored in VX is pressed */ if(input.keys[chip8.V[OP_X]] == 1) chip8.PC += 2; } -inline void execEXA1() { +static inline void exec_EXA1() { /* EXA1: skips the next instruction if the key stored in VX isn't pressed */ if(input.keys[chip8.V[OP_X]] == 0) chip8.PC += 2; } -inline void execFX07() { +static inline void exec_FX07() { /* FX07: sets VX to delay timer */ chip8.V[OP_X] = chip8.delay_timer; } -inline void execFX0A() { +static inline void exec_FX0A() { /* FX0A: pause execution until a key is pressed and store result in V[X] */ if (chip8.cpu_halt) { if (!input.awaiting_key_press) { @@ -214,17 +214,17 @@ inline void execFX0A() { input.awaiting_key_press = 1; } -inline void execFX15() { +static inline void exec_FX15() { /* FX15: sets the delay timer to VX */ chip8.delay_timer = chip8.V[OP_X]; } -inline void execFX18() { +static inline void exec_FX18() { /* FX18: sets the sound timer to VX */ chip8.sound_timer = chip8.V[OP_X]; } -inline void execFX1E() { +static inline void exec_FX1E() { /* FX1E: adds VX to I VF is set to 1 when range overflow (I+VX>0xFFF), and 0 when there isn't. */ @@ -237,13 +237,13 @@ inline void execFX1E() { } } -inline void execFX29() { +static inline void exec_FX29() { /* 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. */ chip8.I = chip8.V[OP_X] * 0x05; } -inline void execFX33() { +static inline void exec_FX33() { /* FX33: stores the binary-coded decimal representation of VX at the addresses I, I plus 1, and I plus 2 */ chip8.memory[chip8.I] = chip8.V[OP_X] / 100; @@ -251,7 +251,7 @@ inline void execFX33() { chip8.memory[chip8.I + 2] = (chip8.V[OP_X] % 100) % 10; } -inline void execFX55() { +static inline void exec_FX55() { /* FX55: stores V0 to VX in memory starting at address I */ for (int i = 0; i <= OP_X; i++) { chip8.memory[chip8.I + i] = chip8.V[i]; @@ -262,7 +262,7 @@ inline void execFX55() { if (!chip8.quirks.load_store_quirk) chip8.I += OP_X + 1; } -inline void execFX65() { +static inline void exec_FX65() { /* FX65: fills V0 to VX with values from memory starting at address I */ for (int i = 0; i <= OP_X; i++) { chip8.V[i] = chip8.memory[chip8.I + i]; @@ -273,7 +273,7 @@ inline void execFX65() { if (!chip8.quirks.load_store_quirk) chip8.I += OP_X + 1; } -inline void execUnknown() { +static inline void exec_unknown() { fprintf (stderr, "Unknown opcode: 0x%X\n", chip8.opcode); } From ff23221c32e915d09cfd5618db40cd29d58fc302 Mon Sep 17 00:00:00 2001 From: Thomas Daley Date: Sun, 22 Feb 2026 10:08:37 -0800 Subject: [PATCH 09/15] remove old declarations --- shared/chip8.h | 38 -------------------------------------- 1 file changed, 38 deletions(-) diff --git a/shared/chip8.h b/shared/chip8.h index 150604f..be65d98 100644 --- a/shared/chip8.h +++ b/shared/chip8.h @@ -107,44 +107,6 @@ int chip8_load_bootrom(void); void chip8_fetch_opcode(void); void chip8_execute_opcode(void); -/* opcode helpers */ -// void exec_00E0(void); -// void exec_00EE(void); -// void exec_0NNN(void); -// void exec_1NNN(void); -// void exec_2NNN(void); -// void exec_3XNN(void); -// void exec_4XNN(void); -// void exec_5XY0(void); -// void exec_6XNN(void); -// void exec_7XNN(void); -// void exec_8XY0(void); -// void exec_8XY1(void); -// void exec_8XY2(void); -// void exec_8XY3(void); -// void exec_8XY4(void); -// void exec_8XY5(void); -// void exec_8XY6(void); -// void exec_8XY7(void); -// void exec_8XYE(void); -// void exec_9XY0(void); -// void exec_ANNN(void); -// void exec_BNNN(void); -// void exec_CXNN(void); -// void exec_DXYN(void); -// void exec_EX9E(void); -// void exec_EXA1(void); -// void exec_FX07(void); -// void exec_FX0A(void); -// void exec_FX15(void); -// void exec_FX18(void); -// void exec_FX1E(void); -// void exec_FX29(void); -// void exec_FX33(void); -// void exec_FX55(void); -// void exec_FX65(void); -// void exec_unknown(void); - #ifdef __cplusplus } #endif From 95ade0d33348ab568f10db4edb4fc54f88915248 Mon Sep 17 00:00:00 2001 From: Thomas Daley Date: Sun, 22 Feb 2026 12:59:18 -0800 Subject: [PATCH 10/15] add missing extern C --- shared/usage.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/shared/usage.h b/shared/usage.h index 17d98e7..db40a55 100644 --- a/shared/usage.h +++ b/shared/usage.h @@ -1,6 +1,10 @@ #ifndef USAGE_H #define USAGE_H +#ifdef __cplusplus +extern "C" { +#endif + /* Centralized usage/help text for CLI and GUI */ static const char *USAGE_TEXT = "Usage: Kiwi8 [options] [rom_file]\n" @@ -12,4 +16,8 @@ static const char *USAGE_TEXT = "\n" "Note: Quirks are configured per-ROM via profiles.ini or GUI.\n"; +#ifdef __cplusplus +} +#endif + #endif /* USAGE_H */ From 35912a8a294ee9338bd01c98177c74228a5e2450 Mon Sep 17 00:00:00 2001 From: Thomas Daley Date: Mon, 23 Feb 2026 21:16:55 -0800 Subject: [PATCH 11/15] add compat.h for cross platform limits --- shared/chip8.c | 7 ++++--- shared/chip8.h | 3 ++- shared/compat.h | 26 ++++++++++++++++++++++++++ shared/profiles.c | 7 ++++--- shared/profiles.h | 3 ++- 5 files changed, 38 insertions(+), 8 deletions(-) create mode 100644 shared/compat.h diff --git a/shared/chip8.c b/shared/chip8.c index d472b34..08a7199 100644 --- a/shared/chip8.c +++ b/shared/chip8.c @@ -7,6 +7,7 @@ #include "profiles.h" #include "sha256.h" #include "toast.h" +#include "compat.h" #include "open_file_dialog.h" #include #include @@ -193,10 +194,10 @@ int chip8_load_rom(const char *rom_filepath) { } else { /* load ROM from GUI */ - char new_rom_name[PATH_MAX]; - open_file_dialog(new_rom_name) ? + char new_rom_filepath[PATH_MAX]; + open_file_dialog(new_rom_filepath) ? printf("User aborted the open file dialog.\n") : - chip8_load_rom(new_rom_name); + chip8_load_rom(new_rom_filepath); /* flip GUI toggle */ gui.load_rom_flag = 0; diff --git a/shared/chip8.h b/shared/chip8.h index be65d98..2ef4f5e 100644 --- a/shared/chip8.h +++ b/shared/chip8.h @@ -5,6 +5,7 @@ extern "C" { #endif +#include "compat.h" #include "bootrom.h" // Generated at build time from roms/Kiwi8_logo_2.ch8 #include "quirks.h" #include @@ -62,7 +63,7 @@ struct chip8 { unsigned int rom_size; /* rom profile tracking */ - char rom_filename[256]; /* basename of currently loaded ROM */ + char rom_filename[FILENAME_MAX]; /* basename of currently loaded ROM */ int rom_loaded; /* 1 if user ROM loaded, 0 if bootrom */ /* registers */ diff --git a/shared/compat.h b/shared/compat.h new file mode 100644 index 0000000..e1c1785 --- /dev/null +++ b/shared/compat.h @@ -0,0 +1,26 @@ +#ifndef COMPAT_H +#define COMPAT_H + +#include + +// Handle missing PATH_MAX on some systems +#if defined(__APPLE__) || defined(__linux__) + #include +#elif defined(_WIN32) + #include + #ifndef PATH_MAX + #define PATH_MAX MAX_PATH + #endif +#endif + +#ifndef PATH_MAX + #define PATH_MAX 2048 +#endif +#ifndef FILENAME_MAX + #define FILENAME_MAX 2048 +#endif +#ifndef LINE_MAX + #define LINE_MAX 4096 +#endif + +#endif // COMPAT_H diff --git a/shared/profiles.c b/shared/profiles.c index 2fd080f..b00d1f7 100644 --- a/shared/profiles.c +++ b/shared/profiles.c @@ -1,4 +1,5 @@ #include "profiles.h" +#include "compat.h" #define STB_DS_IMPLEMENTATION #include "stb_ds.h" #include "sha256.h" @@ -13,7 +14,7 @@ static struct { sha256_hash_t key; struct profile value; } *profile_map = NULL; /* Track which path we loaded profiles.ini from */ -static char loaded_profiles_path[512] = ""; +static char loaded_profiles_path[FILENAME_MAX] = ""; /* Quirk field descriptor table — generated from QUIRK_FIELDS X-macro in quirks.h */ static const struct { @@ -58,7 +59,7 @@ static void parse_profiles_ini(void) { FILE *file = fopen(loaded_profiles_path, "r"); if (!file) return; - char line[512]; + char line[LINE_MAX]; sha256_hash_t current_sha256 = {0}; int has_current = 0; struct profile current_profile; @@ -164,7 +165,7 @@ static int resolve_profiles_path(void) { } /* Build search paths relative to executable */ - char search_paths[2][512]; + char search_paths[2][LINE_MAX]; char *base_path = SDL_GetBasePath(); if (!base_path) { printf("Warning: Could not determine executable path. Trying current directory.\n"); diff --git a/shared/profiles.h b/shared/profiles.h index 59d6602..687d5e6 100644 --- a/shared/profiles.h +++ b/shared/profiles.h @@ -8,12 +8,13 @@ extern "C" { #include #include "quirks.h" #include "sha256.h" +#include "compat.h" typedef struct { uint8_t bytes[32]; } sha256_hash_t; struct profile { sha256_hash_t sha256; - char rom_name[256]; + char rom_name[FILENAME_MAX]; struct quirks quirks; }; From 274a4d0eeae894168f40a186b67875baaf14bc0a Mon Sep 17 00:00:00 2001 From: Thomas Daley Date: Mon, 23 Feb 2026 21:18:14 -0800 Subject: [PATCH 12/15] change rom_name to rom_filepath where appropriate --- linux/src/open_file_dialog.cc | 4 ++-- macos/src/open_file_dialog.mm | 5 +++-- shared/open_file_dialog.h | 17 ++--------------- windows/src/open_file_dialog.cc | 8 ++++---- 4 files changed, 11 insertions(+), 23 deletions(-) diff --git a/linux/src/open_file_dialog.cc b/linux/src/open_file_dialog.cc index 45513ce..08f639a 100644 --- a/linux/src/open_file_dialog.cc +++ b/linux/src/open_file_dialog.cc @@ -68,11 +68,11 @@ std::vector open_file_dialog(const std::string &title, const std::s return result; } -int open_file_dialog(char *rom_name) { +int open_file_dialog(char *rom_filepath) { std::vector fileTypes = {"ch8", "CH8", "chip-8", "CHIP-8", "Chip-8"}; const char* defaultDir = ""; // unify behavior: let OS choose last-used/home std::vector files = open_file_dialog("Chip8", defaultDir, fileTypes); if (files.empty()) return 1; - snprintf(rom_name, 256, "%s", files[0].c_str()); + snprintf(rom_filepath, 256, "%s", files[0].c_str()); return 0; } diff --git a/macos/src/open_file_dialog.mm b/macos/src/open_file_dialog.mm index 2e5e422..439d19c 100644 --- a/macos/src/open_file_dialog.mm +++ b/macos/src/open_file_dialog.mm @@ -1,4 +1,5 @@ #import "open_file_dialog.h" +#import "compat.h" #import #import #include @@ -43,11 +44,11 @@ return fileList; } -int open_file_dialog(char *rom_name) { +int open_file_dialog(char *rom_filepath) { std::vector fileTypes = {"ch8", "CH8", "chip-8", "CHIP-8", "Chip-8"}; const char* defaultDir = ""; // unify behavior: let OS choose last-used/home std::vector files = open_file_dialog("Chip8", defaultDir, fileTypes); if (files.empty()) return 1; - snprintf(rom_name, 256, "%s", files[0].c_str()); + snprintf(rom_filepath, 256, "%s", files[0].c_str()); return 0; } diff --git a/shared/open_file_dialog.h b/shared/open_file_dialog.h index a0837b3..bcfabcb 100644 --- a/shared/open_file_dialog.h +++ b/shared/open_file_dialog.h @@ -5,23 +5,10 @@ extern "C" { #endif -#ifdef __APPLE__ -#include /* PATH_MAX */ -#endif - -#ifdef _WIN32 -#include /* MAX_PATH */ -#define PATH_MAX MAX_PATH -#endif - -#ifdef __linux__ -#include /* PATH_MAX */ -#endif - -int open_file_dialog(char *rom_name); +int open_file_dialog(char *rom_filepath); #ifdef __cplusplus } #endif -#endif +#endif // OPEN_FILE_DIALOG_H diff --git a/windows/src/open_file_dialog.cc b/windows/src/open_file_dialog.cc index b85e087..ac4e3de 100644 --- a/windows/src/open_file_dialog.cc +++ b/windows/src/open_file_dialog.cc @@ -4,7 +4,7 @@ #include #include -int open_file_dialog(char *rom_name, char *filters) { +int open_file_dialog(char *rom_filepath, char *filters) { /* open file dialogue */ char cwd[MAX_PATH]; GetCurrentDirectory(MAX_PATH, cwd); @@ -35,10 +35,10 @@ int open_file_dialog(char *rom_name, char *filters) { return 1; } - strcpy(rom_name, szFile); + strcpy(rom_filepath, szFile); return 0; } -int open_file_dialog(char *rom_name) { - return open_file_dialog(rom_name, "Chip8\0*.ch8\0All\0*.*\0"); +int open_file_dialog(char *rom_filepath) { + return open_file_dialog(rom_filepath, "Chip8\0*.ch8\0All\0*.*\0"); } From 1ada9d6c8d74e541c2e459fadaba049ba0caca39 Mon Sep 17 00:00:00 2001 From: Thomas Daley Date: Mon, 23 Feb 2026 21:22:59 -0800 Subject: [PATCH 13/15] Use compat.h --- linux/src/open_file_dialog.cc | 3 ++- macos/src/open_file_dialog.mm | 2 +- windows/src/open_file_dialog.cc | 7 ++++--- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/linux/src/open_file_dialog.cc b/linux/src/open_file_dialog.cc index 08f639a..368112b 100644 --- a/linux/src/open_file_dialog.cc +++ b/linux/src/open_file_dialog.cc @@ -1,4 +1,5 @@ #include "open_file_dialog.h" +#include "compat.h" #include #include #include @@ -73,6 +74,6 @@ int open_file_dialog(char *rom_filepath) { const char* defaultDir = ""; // unify behavior: let OS choose last-used/home std::vector files = open_file_dialog("Chip8", defaultDir, fileTypes); if (files.empty()) return 1; - snprintf(rom_filepath, 256, "%s", files[0].c_str()); + snprintf(rom_filepath, PATH_MAX, "%s", files[0].c_str()); return 0; } diff --git a/macos/src/open_file_dialog.mm b/macos/src/open_file_dialog.mm index 439d19c..adf60c8 100644 --- a/macos/src/open_file_dialog.mm +++ b/macos/src/open_file_dialog.mm @@ -49,6 +49,6 @@ int open_file_dialog(char *rom_filepath) { const char* defaultDir = ""; // unify behavior: let OS choose last-used/home std::vector files = open_file_dialog("Chip8", defaultDir, fileTypes); if (files.empty()) return 1; - snprintf(rom_filepath, 256, "%s", files[0].c_str()); + snprintf(rom_filepath, PATH_MAX, "%s", files[0].c_str()); return 0; } diff --git a/windows/src/open_file_dialog.cc b/windows/src/open_file_dialog.cc index ac4e3de..459715f 100644 --- a/windows/src/open_file_dialog.cc +++ b/windows/src/open_file_dialog.cc @@ -1,4 +1,5 @@ #include "open_file_dialog.h" +#include "compat.h" #include #include #include @@ -6,12 +7,12 @@ int open_file_dialog(char *rom_filepath, char *filters) { /* open file dialogue */ - char cwd[MAX_PATH]; - GetCurrentDirectory(MAX_PATH, cwd); + char cwd[PATH_MAX]; + GetCurrentDirectory(PATH_MAX, cwd); OPENFILENAME ofn; - char szFile[MAX_PATH]; + char szFile[PATH_MAX]; /* open a file name */ ZeroMemory( &ofn , sizeof( ofn)); From 0182779869f0357ca13a351622bcb728185798b6 Mon Sep 17 00:00:00 2001 From: Thomas Daley Date: Mon, 23 Feb 2026 21:30:00 -0800 Subject: [PATCH 14/15] set better defaults --- shared/compat.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/shared/compat.h b/shared/compat.h index e1c1785..7700140 100644 --- a/shared/compat.h +++ b/shared/compat.h @@ -14,13 +14,13 @@ #endif #ifndef PATH_MAX - #define PATH_MAX 2048 + #define PATH_MAX 4096 #endif #ifndef FILENAME_MAX - #define FILENAME_MAX 2048 + #define FILENAME_MAX 256 #endif #ifndef LINE_MAX - #define LINE_MAX 4096 + #define LINE_MAX 2048 #endif #endif // COMPAT_H From 1228470c09f90ec6e488a0ceec842588b7c675d6 Mon Sep 17 00:00:00 2001 From: Thomas Daley Date: Mon, 23 Feb 2026 21:34:36 -0800 Subject: [PATCH 15/15] use linux include --- shared/compat.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/shared/compat.h b/shared/compat.h index 7700140..9feeb8c 100644 --- a/shared/compat.h +++ b/shared/compat.h @@ -4,8 +4,10 @@ #include // Handle missing PATH_MAX on some systems -#if defined(__APPLE__) || defined(__linux__) +#if defined(__APPLE__) #include +#elif defined(__linux__) + #include #elif defined(_WIN32) #include #ifndef PATH_MAX