From 19f0b16f4ffe766574a385f4737919a5f2df0c19 Mon Sep 17 00:00:00 2001 From: bbbbbr Date: Mon, 18 Nov 2024 20:18:04 -0800 Subject: [PATCH 1/4] NEs: Experimental support for GBDK flavor of NES --- Changelog.md | 3 +++ src/bank_templates.c | 57 ++++++++++++++++++++++++++++++++++++++++++-- src/common.h | 3 ++- src/romusage.c | 8 ++++--- 4 files changed, 65 insertions(+), 6 deletions(-) diff --git a/Changelog.md b/Changelog.md index 9d8ed3a..85fe25b 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,6 +1,9 @@ Changelog ========= +# Version 1.3.1 +- Experimental support for GBDK's flavor of NES (`-p:NES1"`) .noi/.map files + # Version 1.3.0 - `-b:HEXVAL:[...]` Set hex bytes treated as Empty in ROM files (.gb/etc) (default `FF`(255), ex use 255 AND 0: `-b:FF:00` - Improve error messaging diff --git a/src/bank_templates.c b/src/bank_templates.c index 34eb4ed..0b2d034 100644 --- a/src/bank_templates.c +++ b/src/bank_templates.c @@ -1,6 +1,6 @@ // This is free and unencumbered software released into the public domain. // For more information, please refer to -// bbbbbr 2020 +// bbbbbr 2024 #include #include @@ -58,7 +58,7 @@ const bank_item WRAM_nonbanked = {"WRAM", 0xC000, 0xDFFF, BANKED_YES, 0xDFFF, const bank_item HRAM = {"HRAM", 0xFF80, 0xFFFE, BANKED_NO, 0xFFFE, 0,0,0, BANK_MEM_TYPE_HRAM, BANK_STARTNUM_0, BANK_MERGED_NO, HIDDEN_NO}; -// ===== Game Gear ===== +// ===== Game Gear / SMS (GBDK specific) ===== // https://www.smspower.org/Development/MemoryMap @@ -66,17 +66,58 @@ const bank_item HRAM = {"HRAM", 0xFF80, 0xFFFE, BANKED_NO, 0xFFFE, // _LIT_ is at base address 0x8000 (assets) // _DATA_N is also at base address 0x8000 (RAM) +// ROM const bank_item smsgg_ROM_0 = {"ROM_0", 0x0000, 0x3FFF, BANKED_NO, 0x7FFF, 0,0,0, BANK_MEM_TYPE_ROM, BANK_STARTNUM_0, BANK_MERGED_NO, HIDDEN_NO}; const bank_item smsgg_ROM_X_banked = {"ROM_", 0x4000, 0x7FFF, BANKED_YES, 0x7FFF, 0,0,0, BANK_MEM_TYPE_ROM, BANK_STARTNUM_1, BANK_MERGED_NO, HIDDEN_NO}; // Merged version const bank_item smsgg_ROM_nonbanked = {"ROM", 0x0000, 0x7FFF, BANKED_YES, 0x7FFF, 0,0,0, BANK_MEM_TYPE_ROM, BANK_STARTNUM_0, BANK_MERGED_YES, HIDDEN_NO}; +// ROM Data const bank_item smsgg_LIT_X_banked = {"LIT_", 0x8000, 0xBFFF, BANKED_YES, 0xBFFF, 0,0,0, BANK_MEM_TYPE_ROM, BANK_STARTNUM_1, BANK_MERGED_NO, HIDDEN_NO}; + +// RAM // Data can also be in the 0x8000 region.. requires some special handling in banks_check() const bank_item smsgg_DATA_X_banked = {"DATA_", 0x8000, 0xBFFF, BANKED_YES, 0xBFFF, 0,0,0, BANK_MEM_TYPE_SRAM, BANK_STARTNUM_1, BANK_MERGED_NO, HIDDEN_NO}; const bank_item smsgg_RAM_nonbanked = {"RAM", 0xC000, 0xDFFF, BANKED_YES, 0xDFFF, 0,0,0, BANK_MEM_TYPE_WRAM, BANK_STARTNUM_0, BANK_MERGED_YES, HIDDEN_NO}; +// ===== NES (GBDK specific) ===== + +// https://en.wikibooks.org/wiki/NES_Programming/Memory_Map +// https://www.nesdev.org/wiki/CPU_memory_map +// +// Michel: +// - One fixed 16kB bank at 0xC000 - 0xFFFF +// - Sometimes uses segment _HOME, sometimes _CODE +// - _XINIT I believe (to initialize data segment) +// - Switchable bank at 0x8000-0xBFFF +// - Will use segments named _CODE_n, where n is a bank number +// - _DATA / _BSS usually start at 0x300, and go up to 0x7FF +// - _ZP uses (part of) 0x00-0FF +// - Overlay segments OSEG / GBDKOVR also use part of 0x00-0xFF, for parameter passing +// - 0x100-0x1FF is stack, which you can probably ignore for your purposes +// - 0x200-02FF is currently hardcoded as OAM page +// +// zero_page_ram: 0x0000 - 0x00FF +// ram: 0x0100 - 0x07FF +// rom_x_banked: 0x8000 - 0xBFFF +// rom_0: 0xC000 - 0xFFFF + +// Name Start End Is Banked? Oflow End (statsx3) Bank Type Base Bank Num Merged version Hidden +// RAM +const bank_item nes1_RAM_ZP = {"ZPAGE", 0x0000, 0x00FF, BANKED_NO, 0x00FF, 0,0,0, BANK_MEM_TYPE_HRAM, BANK_STARTNUM_0, BANK_MERGED_NO, HIDDEN_NO}; +const bank_item nes1_RAM = {"RAM", 0x0100, 0x07FF, BANKED_NO, 0x07FF, 0,0,0, BANK_MEM_TYPE_WRAM, BANK_STARTNUM_0, BANK_MERGED_NO, HIDDEN_NO}; + +// SRAM +const bank_item nes1_SRAM = {"SRAM", 0x6000, 0x7FFF, BANKED_NO, 0x7FFF, 0,0,0, BANK_MEM_TYPE_SRAM, BANK_STARTNUM_0, BANK_MERGED_NO, HIDDEN_NO}; + +// ROM +const bank_item nes1_ROM_X_banked = {"ROM_", 0x8000, 0xBFFF, BANKED_YES, 0xFFFF, 0,0,0, BANK_MEM_TYPE_ROM, BANK_STARTNUM_1, BANK_MERGED_NO, HIDDEN_NO}; +const bank_item nes1_ROM_0 = {"ROM_0", 0xC000, 0xFFFF, BANKED_NO, 0xFFFF, 0,0,0, BANK_MEM_TYPE_ROM, BANK_STARTNUM_0, BANK_MERGED_NO, HIDDEN_NO}; +// Merged version +const bank_item nes1_ROM_nonbanked = {"ROM", 0x8000, 0xFFFF, BANKED_YES, 0xFFFF, 0,0,0, BANK_MEM_TYPE_ROM, BANK_STARTNUM_0, BANK_MERGED_YES, HIDDEN_NO}; + + static int bank_template_add(int idx, bank_item * p_bank_templates, const bank_item * p_bank) { if (idx >= BANK_TEMPLATES_MAX) { @@ -108,6 +149,18 @@ int bank_templates_load(bank_item * p_bank_templates) { idx = bank_template_add(idx, p_bank_templates, &smsgg_DATA_X_banked); idx = bank_template_add(idx, p_bank_templates, &smsgg_RAM_nonbanked); + } + else if (get_option_platform() == OPT_PLAT_NES_GBDK_1) { + if (option_merged_banks & OPT_MERGED_BANKS_ROM) { + idx = bank_template_add(idx, p_bank_templates, &nes1_ROM_nonbanked); + } else { + idx = bank_template_add(idx, p_bank_templates, &nes1_ROM_X_banked); + idx = bank_template_add(idx, p_bank_templates, &nes1_ROM_0); + } + idx = bank_template_add(idx, p_bank_templates, &nes1_RAM_ZP); + idx = bank_template_add(idx, p_bank_templates, &nes1_RAM); + idx = bank_template_add(idx, p_bank_templates, &nes1_SRAM); + } else { // implied: if (get_option_platform() == OPT_PLAT_GAMEBOY) { diff --git a/src/common.h b/src/common.h index a70baba..b8232cb 100644 --- a/src/common.h +++ b/src/common.h @@ -36,7 +36,8 @@ #define OPT_MERGED_BANKS_ROM 2u #define OPT_PLAT_GAMEBOY 0u -#define OPT_PLAT_SMS_GG_GBDK 1u // GBDK specific layout of sms/gg +#define OPT_PLAT_SMS_GG_GBDK 1u // GBDK specific layout for SMS/GG +#define OPT_PLAT_NES_GBDK_1 2u // GBDK specific layout for NES #define BANKS_HIDE_SZ 30 // How many hide substrings to support #define BANKS_HIDE_MAX (BANKS_HIDE_SZ - 1) diff --git a/src/romusage.c b/src/romusage.c index bce142b..efc7bab 100644 --- a/src/romusage.c +++ b/src/romusage.c @@ -1,6 +1,6 @@ // This is free and unencumbered software released into the public domain. // For more information, please refer to -// bbbbbr 2020 +// bbbbbr 2024 #include #include @@ -19,7 +19,7 @@ #include "cdb_file.h" #include "rom_file.h" -#define VERSION "version 1.3.0" +#define VERSION "version 1.3.1" enum { HELP_FULL = 0, @@ -54,7 +54,7 @@ static void display_help(int mode) { "\n" "Options\n" "-h : Show this help\n" - "-p:SMS_GG : Set platform to GBDK SMS/Game Gear (changes memory map templates)\n" + "-p : Set platform (GBDK specific), \"-p:SMS_GG\" for SMS/Game Gear, \"-p:NES1\" for NES\n" "\n" "-a : Show Areas in each Bank. Optional sort by, address:\"-aA\" or size:\"-aS\" \n" "-g : Show a small usage graph per bank (-gA for ascii style)\n" @@ -173,6 +173,8 @@ int handle_args(int argc, char * argv[]) { } else if (strstr(argv[i], "-p:SMS_GG") == argv[i]) { set_option_platform(OPT_PLAT_SMS_GG_GBDK); + } else if (strstr(argv[i], "-p:NES1") == argv[i]) { + set_option_platform(OPT_PLAT_NES_GBDK_1); } else if (strstr(argv[i], "-g") == argv[i]) { banks_output_show_minigraph(true); From b913b662e94a138209be323a5219d1823f3c7784 Mon Sep 17 00:00:00 2001 From: bbbbbr Date: Mon, 18 Nov 2024 21:05:54 -0800 Subject: [PATCH 2/4] Build: basic test --- Makefile | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/Makefile b/Makefile index fdb5635..c5da4de 100644 --- a/Makefile +++ b/Makefile @@ -92,6 +92,43 @@ package: ${MAKE} linuxzip +.PHONY: test + +test: + echo "see test-norepo" + +updatetest: + echo "see updatetest-norepo" + + +test-norepo: + mkdir -p test_norepo/output + rm -f test_norepo/output/test_run.txt + find test_norepo/gb/* -iname "*.map" -type f | xargs -I {} $(BIN) -g -a "{}" >> test_norepo/output/test_run.txt 2>&1 + find test_norepo/gb/* -iname "*.noi" -type f | xargs -I {} $(BIN) -g -a "{}" >> test_norepo/output/test_run.txt 2>&1 + find test_norepo/gb/* -iname "*.ihx" -type f | xargs -I {} $(BIN) -g -a "{}" >> test_norepo/output/test_run.txt 2>&1 + find test_norepo/gb/* -iname "*.cdb" -type f | xargs -I {} $(BIN) -g -a "{}" >> test_norepo/output/test_run.txt 2>&1 + find test_norepo/gb/* -iname "*.gb" -type f | xargs -I {} $(BIN) -g -a "{}" >> test_norepo/output/test_run.txt 2>&1 + # GG + find test_norepo/smsgg/* -iname "*.map" -type f | xargs -I {} $(BIN) -p:SMS_GG -g -a "{}" >> test_norepo/output/test_run.txt 2>&1 + find test_norepo/smsgg/* -iname "*.noi" -type f | xargs -I {} $(BIN) -p:SMS_GG -g -a "{}" >> test_norepo/output/test_run.txt 2>&1 + find test_norepo/smsgg/* -iname "*.gg" -type f | xargs -I {} $(BIN) -p:SMS_GG -g -a "{}" >> test_norepo/output/test_run.txt 2>&1 + + diff --brief test_norepo/output/test_ref.txt test_norepo/output/test_run.txt + +updatetest-norepo: + rm -f test_norepo/output/test_ref.txt + find test_norepo/gb/* -iname "*.map" -type f | xargs -I {} $(BIN) -g -a "{}" >> test_norepo/output/test_ref.txt 2>&1 + find test_norepo/gb/* -iname "*.noi" -type f | xargs -I {} $(BIN) -g -a "{}" >> test_norepo/output/test_ref.txt 2>&1 + find test_norepo/gb/* -iname "*.ihx" -type f | xargs -I {} $(BIN) -g -a "{}" >> test_norepo/output/test_ref.txt 2>&1 + find test_norepo/gb/* -iname "*.cdb" -type f | xargs -I {} $(BIN) -g -a "{}" >> test_norepo/output/test_ref.txt 2>&1 + find test_norepo/gb/* -iname "*.gb" -type f | xargs -I {} $(BIN) -g -a "{}" >> test_norepo/output/test_ref.txt 2>&1 + # GG + find test_norepo/smsgg/* -iname "*.map" -type f | xargs -I {} $(BIN) -p:SMS_GG -g -a "{}" >> test_norepo/output/test_ref.txt 2>&1 + find test_norepo/smsgg/* -iname "*.noi" -type f | xargs -I {} $(BIN) -p:SMS_GG -g -a "{}" >> test_norepo/output/test_ref.txt 2>&1 + find test_norepo/smsgg/* -iname "*.gg" -type f | xargs -I {} $(BIN) -p:SMS_GG -g -a "{}" >> test_norepo/output/test_ref.txt 2>&1 + + # create necessary directories after Makefile is parsed but before build # info prevents the command from being pasted into the makefile $(info $(shell mkdir -p $(MKDIRS))) From a31104719f7aa6ed57e67e347199aa829294541b Mon Sep 17 00:00:00 2001 From: bbbbbr Date: Mon, 18 Nov 2024 21:14:31 -0800 Subject: [PATCH 3/4] Allow areas with leading underscores for .noi/.map files --- Changelog.md | 1 + src/map_file.c | 10 +++++++--- src/noi_file.c | 9 ++++----- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/Changelog.md b/Changelog.md index 85fe25b..38fa24d 100644 --- a/Changelog.md +++ b/Changelog.md @@ -3,6 +3,7 @@ Changelog # Version 1.3.1 - Experimental support for GBDK's flavor of NES (`-p:NES1"`) .noi/.map files +- Allow areas with leading underscores for .noi/.map files # Version 1.3.0 - `-b:HEXVAL:[...]` Set hex bytes treated as Empty in ROM files (.gb/etc) (default `FF`(255), ex use 255 AND 0: `-b:FF:00` diff --git a/src/map_file.c b/src/map_file.c index f30108b..001c458 100644 --- a/src/map_file.c +++ b/src/map_file.c @@ -131,10 +131,14 @@ int map_file_process_areas(char * filename_in) { } } - // GBDK Areas: Only parse lines that start with '_' character (Area summary lines) - else if (strline_in[0] == '_') { - if (str_split(strline_in, p_words, " =.") == GBDK_AREA_SPLIT_WORDS) + // Previous filtering now discontinued, areas with no leading "_" are allowed : GBDK Areas: Only parse lines that start with '_' character (Area summary lines) + // else if (strline_in[0] == '_') { + // } + else if (str_split(strline_in, p_words, " =.") == GBDK_AREA_SPLIT_WORDS) { + // Require a secondary match on a known column value ("bytes") to filter matches better + if (strstr(p_words[4], "bytes")) { add_area_gbdk(p_words); + } } } // end: while still lines to process diff --git a/src/noi_file.c b/src/noi_file.c index 6b8ce04..2c7e566 100644 --- a/src/noi_file.c +++ b/src/noi_file.c @@ -134,12 +134,11 @@ int noi_file_process_areas(char * filename_in) { while ( fgets(strline_in, sizeof(strline_in), noi_file) != NULL) { // Require minimum length to match - if (strlen(strline_in) >= NOI_REC_START_LEN) { + if (strlen(strline_in) >= strlen("DEF l_")) { // Match either _S_egment or _L_ength records - if ( (strncmp(strline_in, "DEF l__", NOI_REC_START_LEN) == 0) || - (strncmp(strline_in, "DEF s__", NOI_REC_START_LEN) == 0)) { - + if ( (strncmp(strline_in, "DEF l_", strlen("DEF l_") ) == 0) || + (strncmp(strline_in, "DEF s_", strlen("DEF s_") ) == 0)) { // Split string into words separated by spaces cols = 0; @@ -157,7 +156,7 @@ int noi_file_process_areas(char * filename_in) { if (cols == NOI_REC_COUNT_MATCH) { if ( !(strstr(p_words[2], "SFR")) && // Exclude SFR areas (not actually located at addresses in area listing) - !(strstr(p_words[2], "HRAM")) ) { // Exclude HRAM area + !(strstr(p_words[2], "HRAM")) ) { // Exclude HRAM area // TODO: remove the HRAM discard? (now that there is an HRAM section) noi_arealist_add(p_words[1], p_words[2], p_words[3]); } From 0b0ebc6392307726916434dab88c687563b003eb Mon Sep 17 00:00:00 2001 From: bbbbbr Date: Mon, 18 Nov 2024 21:15:19 -0800 Subject: [PATCH 4/4] A few NES tests, git ignore test_norepo dir --- .gitignore | 1 + Makefile | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/.gitignore b/.gitignore index 1e459c5..db99a35 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ todo.txt bin/ obj/ package/ +test_norepo/ diff --git a/Makefile b/Makefile index c5da4de..15eca5d 100644 --- a/Makefile +++ b/Makefile @@ -113,9 +113,15 @@ test-norepo: find test_norepo/smsgg/* -iname "*.map" -type f | xargs -I {} $(BIN) -p:SMS_GG -g -a "{}" >> test_norepo/output/test_run.txt 2>&1 find test_norepo/smsgg/* -iname "*.noi" -type f | xargs -I {} $(BIN) -p:SMS_GG -g -a "{}" >> test_norepo/output/test_run.txt 2>&1 find test_norepo/smsgg/* -iname "*.gg" -type f | xargs -I {} $(BIN) -p:SMS_GG -g -a "{}" >> test_norepo/output/test_run.txt 2>&1 + # NES + find test_norepo/nes/* -iname "*.map" -type f | xargs -I {} $(BIN) -p:NES1 -g -a "{}" >> test_norepo/output/test_run.txt 2>&1 + find test_norepo/nes/* -iname "*.noi" -type f | xargs -I {} $(BIN) -p:NES1 -g -a "{}" >> test_norepo/output/test_run.txt 2>&1 diff --brief test_norepo/output/test_ref.txt test_norepo/output/test_run.txt +test-norepo-diff: + diff test_norepo/output/test_ref.txt test_norepo/output/test_run.txt + updatetest-norepo: rm -f test_norepo/output/test_ref.txt find test_norepo/gb/* -iname "*.map" -type f | xargs -I {} $(BIN) -g -a "{}" >> test_norepo/output/test_ref.txt 2>&1 @@ -127,6 +133,9 @@ updatetest-norepo: find test_norepo/smsgg/* -iname "*.map" -type f | xargs -I {} $(BIN) -p:SMS_GG -g -a "{}" >> test_norepo/output/test_ref.txt 2>&1 find test_norepo/smsgg/* -iname "*.noi" -type f | xargs -I {} $(BIN) -p:SMS_GG -g -a "{}" >> test_norepo/output/test_ref.txt 2>&1 find test_norepo/smsgg/* -iname "*.gg" -type f | xargs -I {} $(BIN) -p:SMS_GG -g -a "{}" >> test_norepo/output/test_ref.txt 2>&1 + # NES + find test_norepo/nes/* -iname "*.map" -type f | xargs -I {} $(BIN) -p:NES1 -g -a "{}" >> test_norepo/output/test_ref.txt 2>&1 + find test_norepo/nes/* -iname "*.noi" -type f | xargs -I {} $(BIN) -p:NES1 -g -a "{}" >> test_norepo/output/test_ref.txt 2>&1 # create necessary directories after Makefile is parsed but before build