diff --git a/.github/workflows/wiki.yml b/.github/workflows/wiki.yml deleted file mode 100644 index 5e34927..0000000 --- a/.github/workflows/wiki.yml +++ /dev/null @@ -1,40 +0,0 @@ -name: GitHub Wiki upload - -on: - push: - branches: [ "main" ] - paths: [docs/**, .github/workflows/wiki.yml] - -concurrency: - group: wiki - cancel-in-progress: true - -permissions: - contents: write - -jobs: - wiki: - name: Publish to GitHub Wiki - runs-on: ubuntu-latest - steps: - - name: Checkout Code - uses: actions/checkout@v4 - with: - repository: ${{github.repository}} - path: ${{github.repository}} - - - name: Checkout Wiki - uses: actions/checkout@v4 - with: - repository: ${{github.repository}}.wiki - path: ${{github.repository}}.wiki - - - name: Push to wiki - run: | - set -e - cd $GITHUB_WORKSPACE/${{github.repository}}.wiki - cp -r $GITHUB_WORKSPACE/${{github.repository}}/docs/* . - git config --local user.email "action@github.com" - git config --local user.name "GitHub Action" - git add . - git diff-index --quiet HEAD || git commit -m "action: wiki sync" && git push \ No newline at end of file diff --git a/Makefile b/Makefile index 0067bb5..a6281e5 100644 --- a/Makefile +++ b/Makefile @@ -9,21 +9,53 @@ SRC_MAIN = src/main.c $(SRC_COMMON) FLAGS = -Wall -Wextra -Werror -g -std=c11 -pedantic +## Optional embedded image +# e.g. make build EMBED_IMAGE=images/2048.obj +EMBED_IMAGE ?= +EMBED_OBJ := +EMBED_GLUE := +ifneq ($(strip $(EMBED_IMAGE)),) +EMBED_OBJ := $(EMBED_IMAGE:.obj=.o) +EMBED_GLUE := images/embed_glue.o +endif + TEST_DIR = test -.PHONY: all build clean test +.PHONY: all build clean test distclean all: build -build: +build: $(EMBED_OBJ) $(EMBED_GLUE) mkdir -p $(DIR) - $(CC) $(INC) $(SRC_MAIN) -o $(BIN) $(FLAGS) + $(CC) $(INC) $(SRC_MAIN) $(EMBED_OBJ) $(EMBED_GLUE) -o $(BIN) $(FLAGS) + +# Convert raw image to linkable object (ld -b binary) +%.o: %.obj + ld -r -b binary -o $@ $< + +# Glue exposes vbo_image_start/end for the chosen image +images/embed_glue.o: $(EMBED_OBJ) + @stem=_binary_$$(echo $(EMBED_IMAGE) | sed 's/[^A-Za-z0-9_]/_/g'); \ + mkdir -p images; \ + printf '%s\n' \ + '/* generated */' \ + "extern const unsigned char $${stem}_start[];" \ + "extern const unsigned char $${stem}_end[];" \ + "const unsigned char* vbo_image_start = $${stem}_start;" \ + "const unsigned char* vbo_image_end = $${stem}_end;" \ + > images/embed_glue.c; \ + $(CC) -c images/embed_glue.c -o images/embed_glue.o $(FLAGS) clean: rm -f $(BIN) rm -f $(TEST_DIR)/test_utils + rm -f images/embed_glue.c images/embed_glue.o + +distclean: clean + ifneq ($(strip $(EMBED_OBJ)),) + rm -f $(EMBED_OBJ) + endif -# Basic, explicit test target invoking compile lines for each test file test: $(CC) $(INC) $(TEST_DIR)/test_utils.c src/utils.c src/hardware.c -o $(TEST_DIR)/test_utils $(FLAGS) $(TEST_DIR)/test_utils diff --git a/include/utils.h b/include/utils.h index e034d0f..d1faf4b 100644 --- a/include/utils.h +++ b/include/utils.h @@ -7,6 +7,7 @@ #include #include #include +#include void handle_interrupt(int signal); void disable_input_buffering(); @@ -14,6 +15,7 @@ void restore_input_buffering(); void update_flags(uint16_t r); void mem_write(uint16_t address, uint16_t val); void read_image_file(FILE* file); +void read_image_buffer(const uint8_t* data, size_t size); int read_image(const char* image_path); diff --git a/src/main.c b/src/main.c index cb4f458..a32fab8 100644 --- a/src/main.c +++ b/src/main.c @@ -13,14 +13,11 @@ #include "utils.h" -int load_arguments(int argc, const char* argv[]) +static int load_arguments(int argc, const char* argv[]) { - if (argc < 2) - { - printf("vbo [image-path] ...\n"); - exit(2); + if (argc < 2) { + return -1; // no CLI images } - for (int j = 1; j < argc; ++j) { if (!read_image(argv[j])) @@ -40,9 +37,25 @@ int setup() return 0; } + +// optional embedded image (weak) +extern const unsigned char* vbo_image_start __attribute__((weak)); +extern const unsigned char* vbo_image_end __attribute__((weak)); + + int main(int argc, const char* argv[]) { - load_arguments(argc, argv); + int arg_status = load_arguments(argc, argv); + + if (arg_status < 0) { + if (vbo_image_start && vbo_image_end && vbo_image_end > vbo_image_start) { + size_t size = (size_t)(vbo_image_end - vbo_image_start); + read_image_buffer(vbo_image_start, size); + } else { + printf("vbo [image-path] ...\n"); + exit(2); + } + } setup(); diff --git a/src/utils.c b/src/utils.c index ea60538..6042813 100644 --- a/src/utils.c +++ b/src/utils.c @@ -95,6 +95,28 @@ void read_image_file(FILE* file) } } +// Load an image from an in-memory buffer containing the on-disk image format +void read_image_buffer(const uint8_t* data, size_t size) +{ + if (data == NULL || size < sizeof(uint16_t)) { + fprintf(stderr, "Image buffer too small or null\n"); + return; + } + // first two bytes: big-endian origin + uint16_t origin = (uint16_t)((data[0] << 8) | data[1]); + + size_t bytes_remaining = size - sizeof(uint16_t); + size_t words = bytes_remaining / sizeof(uint16_t); + const uint8_t* p = data + sizeof(uint16_t); + + uint16_t* dst = memory + origin; + size_t i; + for (i = 0; i < words && (origin + i) < MEMORY_MAX; ++i) { + uint16_t val = (uint16_t)((p[2*i] << 8) | p[2*i + 1]); + dst[i] = val; + } +} + int read_image(const char* image_path) { FILE* file = fopen(image_path, "rb");