From 2062499f0c17e7564e30b4a9c7ae96a32491c5c1 Mon Sep 17 00:00:00 2001 From: Tal Hayon Date: Fri, 13 May 2022 18:44:14 +0300 Subject: [PATCH] Initial version of enum extractor script --- .gitignore | 1 + Makefile | 22 ++++++++---- asm/macros/scripts.inc | 9 +++-- data/scripts.s | 3 ++ data/scripts/hyruleTown/script_Din.inc | 14 ++++---- include/definitions.h | 3 ++ include/droptables.h | 2 ++ include/hitbox.h | 3 ++ include/kinstone.h | 1 + include/projectile.h | 2 ++ tools/extract_include_enum.py | 48 ++++++++++++++++++++++++++ tools/src/preproc/asm_file.cpp | 11 +++--- tools/src/preproc/preproc.cpp | 16 +++++++-- tools/src/preproc/preproc.h | 1 + 14 files changed, 112 insertions(+), 24 deletions(-) create mode 100755 tools/extract_include_enum.py diff --git a/.gitignore b/.gitignore index 69ee3035..c4230656 100644 --- a/.gitignore +++ b/.gitignore @@ -22,6 +22,7 @@ tools/binutils # scripts *.py +!tools/extract_include_enum.py *.pl # graphics diff --git a/Makefile b/Makefile index 54d6666e..4971df80 100644 --- a/Makefile +++ b/Makefile @@ -57,15 +57,18 @@ DATA_ASM_SUBDIR = data SONG_SUBDIR = sound/songs MID_SUBDIR = sound/songs/midi ASSET_SUBDIR = assets +ENUM_INCLUDE_SUBDIR = enum_include C_BUILDDIR = $(OBJ_DIR)/$(C_SUBDIR) ASM_BUILDDIR = $(OBJ_DIR)/$(ASM_SUBDIR) +ASM_ENUM_INCLUDE_DIR = $(ASM_BUILDDIR)/$(ENUM_INCLUDE_SUBDIR) DATA_ASM_BUILDDIR = $(OBJ_DIR)/$(DATA_ASM_SUBDIR) SONG_BUILDDIR = $(OBJ_DIR)/$(SONG_SUBDIR) MID_BUILDDIR = $(OBJ_DIR)/$(MID_SUBDIR) ASSET_BUILDDIR = $(OBJ_DIR)/$(ASSET_SUBDIR) +PREPROC_INC_PATHS = $(ASSET_BUILDDIR) $(ASM_ENUM_INCLUDE_DIR) -ASFLAGS := -mcpu=arm7tdmi --defsym $(GAME_VERSION)=1 --defsym REVISION=$(REVISION) --defsym $(GAME_LANGUAGE)=1 -I $(ASSET_SUBDIR) -I $(ASSET_BUILDDIR) +ASFLAGS := -mcpu=arm7tdmi --defsym $(GAME_VERSION)=1 --defsym REVISION=$(REVISION) --defsym $(GAME_LANGUAGE)=1 -I $(ASSET_SUBDIR) -I $(ASSET_BUILDDIR) -I $(ASM_ENUM_INCLUDE_DIR) CC1 := tools/agbcc/bin/agbcc override CFLAGS += -O2 -Wimplicit -Wparentheses -Werror -Wno-multichar -g3 @@ -90,6 +93,7 @@ SCANINC := tools/bin/scaninc PREPROC := tools/bin/preproc FIX := tools/bin/gbafix ASSET_PROCESSOR := tools/bin/asset_processor +ENUM_PROCESSOR := tools/extract_include_enum.py ASSET_CONFIGS = assets/assets.json assets/gfx.json assets/map.json assets/samples.json assets/sounds.json TRANSLATIONS = translations/USA.bin translations/English.bin translations/French.bin translations/German.bin translations/Spanish.bin translations/Italian.bin @@ -142,10 +146,13 @@ SONG_OBJS := $(patsubst $(SONG_SUBDIR)/%.s,$(SONG_BUILDDIR)/%.o,$(SONG_SRCS)) MID_SRCS := $(wildcard $(MID_SUBDIR)/*.mid) MID_OBJS := $(patsubst $(MID_SUBDIR)/%.mid,$(MID_BUILDDIR)/%.o,$(MID_SRCS)) +ENUM_ASM_SRCS := $(wildcard include/*.h) +ENUM_ASM_HEADERS := $(patsubst include/%.h,$(ASM_ENUM_INCLUDE_DIR)/%.inc,$(ENUM_ASM_SRCS)) + OBJS := $(C_OBJS) $(ASM_OBJS) $(DATA_ASM_OBJS) $(SONG_OBJS) $(MID_OBJS) OBJS_REL := $(patsubst $(OBJ_DIR)/%,%,$(OBJS)) -SUBDIRS := $(sort $(dir $(OBJS))) +SUBDIRS := $(sort $(dir $(OBJS) $(ENUM_ASM_HEADERS))) $(shell mkdir -p $(SUBDIRS)) @@ -253,16 +260,19 @@ $(ASM_BUILDDIR)/%.o: asm_dep = $(shell $(SCANINC) -I . $(ASM_SUBDIR)/$*.s) endif $(ASM_BUILDDIR)/%.o: $(ASM_SUBDIR)/%.s $$(asm_dep) - $(PREPROC) $(BUILD_NAME) $< | $(AS) $(ASFLAGS) -o $@ + $(PREPROC) $(BUILD_NAME) $< -- $(PREPROC_INC_PATHS) | $(AS) $(ASFLAGS) -o $@ + +$(ASM_ENUM_INCLUDE_DIR)/%.inc: include/%.h + $(ENUM_PROCESSOR) $< $(CC) "-D__attribute__(x)=" "-E" "-nostdinc" "-Itools/agbcc" "-Itools/agbcc/include" "-iquote include" > $@ ifeq ($(NODEP),1) $(DATA_ASM_BUILDDIR)/%.o: data_dep := else -$(DATA_ASM_BUILDDIR)/%.o: data_dep = $(shell $(SCANINC) -I . -I $(ASSET_SUBDIR) -I $(ASSET_BUILDDIR) $(DATA_ASM_SUBDIR)/$*.s) +$(DATA_ASM_BUILDDIR)/%.o: data_dep = $(shell $(SCANINC) -I . -I $(ASSET_SUBDIR) -I $(ASSET_BUILDDIR) -I $(ASM_ENUM_INCLUDE_DIR) $(DATA_ASM_SUBDIR)/$*.s) endif -$(DATA_ASM_BUILDDIR)/%.o: $(DATA_ASM_SUBDIR)/%.s $$(data_dep) - $(PREPROC) $(BUILD_NAME) $< charmap.txt | $(CPP) -I include -nostdinc -undef -Wno-unicode - | $(AS) $(ASFLAGS) -o $@ +$(DATA_ASM_BUILDDIR)/%.o: $(DATA_ASM_SUBDIR)/%.s $$(data_dep) $(ENUM_ASM_HEADERS) + $(PREPROC) $(BUILD_NAME) $< charmap.txt -- $(PREPROC_INC_PATHS) | $(CPP) -I include -nostdinc -undef -Wno-unicode - | $(AS) $(ASFLAGS) -o $@ $(SONG_BUILDDIR)/%.o: $(SONG_SUBDIR)/%.s $(AS) $(ASFLAGS) -I sound -o $@ $< diff --git a/asm/macros/scripts.inc b/asm/macros/scripts.inc index 3822f008..01a6aa85 100644 --- a/asm/macros/scripts.inc +++ b/asm/macros/scripts.inc @@ -484,9 +484,14 @@ .2byte \s .endm -.macro MessageNoOverlap s:req +.macro MessageNoOverlap a:req, b .2byte 0x085b - .2byte \s + .ifnb \b + .byte \b + .byte \a + .else + .2byte \a + .endif .endm .macro MessageFromTargetPos a:req, b:req diff --git a/data/scripts.s b/data/scripts.s index b23bc221..5007fed0 100644 --- a/data/scripts.s +++ b/data/scripts.s @@ -3,6 +3,9 @@ .include "asm/macros/scripts.inc" + .include "flags.inc" + .include "message.inc" + .syntax unified .text diff --git a/data/scripts/hyruleTown/script_Din.inc b/data/scripts/hyruleTown/script_Din.inc index 4b0c3e8c..142de31e 100644 --- a/data/scripts/hyruleTown/script_Din.inc +++ b/data/scripts/hyruleTown/script_Din.inc @@ -5,7 +5,7 @@ SCRIPT_START script_Din SetAnimationState 0x0004 DoPostScriptAction 0x0001 DoPostScriptAction 0x000a - CheckGlobalFlag 0x0047 + CheckGlobalFlag GOMAN_RENTED_HOUSE JumpIf script_08011CC2 EndBlock script_08011C9A: @@ -17,7 +17,7 @@ script_08011C9A: SetPlayerIdle FacePlayer DoPostScriptAction 0x0000 - MessageNoOverlap 0x4515 + MessageNoOverlap TEXT_HAPPY_HEARTH, 0x15 WaitUntilTextboxCloses EnablePlayerControl SetAnimationState 0x0004 @@ -26,9 +26,9 @@ script_08011C9A: script_08011CC2: EndBlock BeginBlock - CheckGlobalFlag 0x002c + CheckGlobalFlag RENTED_HOUSE_NAYRU JumpIf script_08011C9A - CheckGlobalFlag 0x002d + CheckGlobalFlag RENTED_HOUSE_FARORE JumpIf script_08011C9A CheckEntityInteractType JumpIfNot script_08011CC2 @@ -36,7 +36,7 @@ script_08011CC2: SetPlayerIdle FacePlayer DoPostScriptAction 0x0000 - MessageNoOverlap 0x3105 + MessageNoOverlap TEXT_GORMAN_ORACLES, 0x5 WaitUntilTextboxCloses CheckTextboxResult JumpIf script_08011D0E @@ -51,9 +51,9 @@ script_08011D00: FacePlayer DoPostScriptAction 0x0000 script_08011D0E: - MessageNoOverlap 0x3108 + MessageNoOverlap TEXT_GORMAN_ORACLES, 0x8 WaitUntilTextboxCloses - SetGlobalFlag 0x002b + SetGlobalFlag RENTED_HOUSE_DIN EnablePlayerControl SetAnimationState 0x0004 DoPostScriptAction 0x0001 diff --git a/include/definitions.h b/include/definitions.h index 896e125b..7a18b709 100644 --- a/include/definitions.h +++ b/include/definitions.h @@ -1,6 +1,9 @@ #ifndef SPRITEDATA_H #define SPRITEDATA_H +#include "gba/types.h" +#include "entity.h" + // Definition for enemies and projectiles typedef struct EnemyDefinition { u16 gfx; diff --git a/include/droptables.h b/include/droptables.h index f05ae94e..78d75970 100644 --- a/include/droptables.h +++ b/include/droptables.h @@ -1,6 +1,8 @@ #ifndef TMC_DROPTABLES_H #define TMC_DROPTABLES_H +#include "global.h" + typedef union { struct { s16 none; diff --git a/include/hitbox.h b/include/hitbox.h index 483c7e1d..0426c992 100644 --- a/include/hitbox.h +++ b/include/hitbox.h @@ -1,5 +1,8 @@ #ifndef HITBOX_H #define HITBOX_H + +#include "entity.h" + extern const Hitbox gHitbox_0; extern const Hitbox gHitbox_1; extern const Hitbox gHitbox_2; diff --git a/include/kinstone.h b/include/kinstone.h index a293104a..987446e4 100644 --- a/include/kinstone.h +++ b/include/kinstone.h @@ -2,6 +2,7 @@ #define KINSTONE_H #include "global.h" +#include "entity.h" extern void sub_08018C58(u32); diff --git a/include/projectile.h b/include/projectile.h index dd73d433..64df8ac4 100644 --- a/include/projectile.h +++ b/include/projectile.h @@ -1,6 +1,8 @@ #ifndef PROJECTILE_H #define PROJECTILE_H +#include "entity.h" + Entity* CreateProjectile(u32); bool32 IsProjectileOffScreen(Entity*); diff --git a/tools/extract_include_enum.py b/tools/extract_include_enum.py new file mode 100755 index 00000000..7e30abe2 --- /dev/null +++ b/tools/extract_include_enum.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python3 + +import argparse +import pycparser + +class EnumVisitor(pycparser.c_ast.NodeVisitor): + def __init__(self, file): + self.file = file + def visit_Enum(self, enum): + if enum.coord.file != self.file: + return + next_value = 0 + for enum_value in enum.values.enumerators: + if enum_value.value is not None: + # Unsure how to handle assignment of non-numerical value - maybe leave as is? + if isinstance(enum_value.value, pycparser.c_ast.Constant): + next_value_str = enum_value.value.value + next_value = int(next_value_str, 16) if "x" in next_value_str else int(next_value_str) + print(f".set {enum_value.name}, {next_value}") + next_value += 1 + else: + print(f".set {enum_value.name}, {next_value}") + next_value += 1 + +def main(): + parser = argparse.ArgumentParser(description="Prints out enum values for assembler.", prefix_chars='+') + parser.add_argument("file", help="input include file") + parser.add_argument("cpp", help="c pre-processor") + parser.add_argument("cppflags", help="c pre-processor flags", nargs="*") + + args = parser.parse_args() + ast = pycparser.parse_file(args.file, True, args.cpp, args.cppflags) + + # print guard + guard_prefix = args.file.replace("include/", "") + guard_prefix = guard_prefix.replace(".", "_") + guard_name = guard_prefix.upper() + "_ASM_INC" + print(f".ifndef {guard_name}") + print(f".set {guard_name}, 1\n") + + visitor = EnumVisitor(args.file) + visitor.visit(ast) + + print(f"\n.endif @ {guard_name}") + + +if __name__ == '__main__': + main() diff --git a/tools/src/preproc/asm_file.cpp b/tools/src/preproc/asm_file.cpp index 30d6758f..283fed68 100644 --- a/tools/src/preproc/asm_file.cpp +++ b/tools/src/preproc/asm_file.cpp @@ -30,14 +30,13 @@ AsmFile::AsmFile(std::string filename) : m_filename(filename) { FILE* fp = std::fopen(filename.c_str(), "rb"); - if (fp == NULL) { - // The include might be an asset. - fp = std::fopen(("build/" + g_buildName + "/assets/" + filename).c_str(), "rb"); - - if (fp == NULL) - FATAL_ERROR("Failed to open \"%s\" for reading.\n", filename.c_str()); + for (int i = 0; fp == NULL && i < g_incPaths.size(); i++) { + fp = std::fopen((g_incPaths[i] + "/" + filename).c_str(), "rb"); } + if (fp == NULL) + FATAL_ERROR("Failed to open \"%s\" for reading.\n", filename.c_str()); + std::fseek(fp, 0, SEEK_END); m_size = std::ftell(fp); diff --git a/tools/src/preproc/preproc.cpp b/tools/src/preproc/preproc.cpp index 2aada83d..40bc66e2 100644 --- a/tools/src/preproc/preproc.cpp +++ b/tools/src/preproc/preproc.cpp @@ -19,7 +19,9 @@ // THE SOFTWARE. #include +#include #include +#include #include "preproc.h" #include "asm_file.h" #include "c_file.h" @@ -27,6 +29,7 @@ Charmap* g_charmap; std::string g_buildName; +std::vector g_incPaths; void PrintAsmBytes(unsigned char* s, int length) { if (length > 0) { @@ -117,13 +120,20 @@ char* GetFileExtension(char* filename) { } int main(int argc, char** argv) { - if (argc != 4 && argc != 3) { - std::fprintf(stderr, "Usage: %s BUILD_NAME SRC_FILE CHARMAP_FILE", argv[0]); + if (argc < 3) { + std::fprintf(stderr, "Usage: %s BUILD_NAME SRC_FILE [CHARMAP_FILE] -- [ASM INC PATH] ...", argv[0]); return 1; } + int pathStart = 0; + while (pathStart < argc && strcmp(argv[pathStart], "--") != 0) pathStart++; + + for (int i = pathStart + 1; i < argc; i++) { + g_incPaths.push_back(argv[i]); + } + g_buildName = std::string(argv[1]); - g_charmap = new Charmap(argc == 4 ? argv[3] : ""); + g_charmap = new Charmap(argc > 3 && pathStart > 3 ? argv[3] : ""); char* extension = GetFileExtension(argv[2]); diff --git a/tools/src/preproc/preproc.h b/tools/src/preproc/preproc.h index f896b6ae..f194dcda 100644 --- a/tools/src/preproc/preproc.h +++ b/tools/src/preproc/preproc.h @@ -49,5 +49,6 @@ const unsigned long kMaxCharmapSequenceLength = 16; extern Charmap* g_charmap; extern std::string g_buildName; +extern std::vector g_incPaths; #endif // PREPROC_H