diff --git a/gbdk-support/romusage/src/bank_templates.c b/gbdk-support/romusage/src/bank_templates.c index 5bf39d74..34eb4edf 100644 --- a/gbdk-support/romusage/src/bank_templates.c +++ b/gbdk-support/romusage/src/bank_templates.c @@ -37,25 +37,25 @@ // ===== Game Boy ===== // ROM -const bank_item ROM_0 = {"ROM_0", 0x0000, 0x3FFF, BANKED_NO, 0x7FFF, 0,0,0, BANK_MEM_TYPE_ROM, BANK_STARTNUM_0, BANK_MERGED_NO}; -const bank_item ROM_X_banked = {"ROM_", 0x4000, 0x7FFF, BANKED_YES, 0x7FFF, 0,0,0, BANK_MEM_TYPE_ROM, BANK_STARTNUM_1, BANK_MERGED_NO}; +const bank_item 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 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 ROM_nonbanked = {"ROM", 0x0000, 0x7FFF, BANKED_YES, 0x7FFF, 0,0,0, BANK_MEM_TYPE_ROM, BANK_STARTNUM_0, BANK_MERGED_YES}; +const bank_item ROM_nonbanked = {"ROM", 0x0000, 0x7FFF, BANKED_YES, 0x7FFF, 0,0,0, BANK_MEM_TYPE_ROM, BANK_STARTNUM_0, BANK_MERGED_YES, HIDDEN_NO}; // VRAM -const bank_item VRAM = {"VRAM_", 0x8000, 0x9FFF, BANKED_YES, 0x9FFF, 0,0,0, BANK_MEM_TYPE_VRAM, BANK_STARTNUM_0, BANK_MERGED_NO}; +const bank_item VRAM = {"VRAM_", 0x8000, 0x9FFF, BANKED_YES, 0x9FFF, 0,0,0, BANK_MEM_TYPE_VRAM, BANK_STARTNUM_0, BANK_MERGED_NO, HIDDEN_NO}; // SRAM -const bank_item SRAM = {"SRAM_", 0xA000, 0xBFFF, BANKED_YES, 0xBFFF, 0,0,0, BANK_MEM_TYPE_SRAM, BANK_STARTNUM_0, BANK_MERGED_NO}; +const bank_item SRAM = {"SRAM_", 0xA000, 0xBFFF, BANKED_YES, 0xBFFF, 0,0,0, BANK_MEM_TYPE_SRAM, BANK_STARTNUM_0, BANK_MERGED_NO, HIDDEN_NO}; // WRAM -const bank_item WRAM_0 = {"WRAM_LO", 0xC000, 0xCFFF, BANKED_NO, 0xDFFF, 0,0,0, BANK_MEM_TYPE_WRAM, BANK_STARTNUM_0, BANK_MERGED_NO}; -const bank_item WRAM_X_banked = {"WRAM_HI_",0xD000, 0xDFFF, BANKED_YES, 0xDFFF, 0,0,0, BANK_MEM_TYPE_WRAM, BANK_STARTNUM_1, BANK_MERGED_NO}; +const bank_item WRAM_0 = {"WRAM_LO", 0xC000, 0xCFFF, BANKED_NO, 0xDFFF, 0,0,0, BANK_MEM_TYPE_WRAM, BANK_STARTNUM_0, BANK_MERGED_NO, HIDDEN_NO}; +const bank_item WRAM_X_banked = {"WRAM_HI_",0xD000, 0xDFFF, BANKED_YES, 0xDFFF, 0,0,0, BANK_MEM_TYPE_WRAM, BANK_STARTNUM_1, BANK_MERGED_NO, HIDDEN_NO}; // Merged version -const bank_item WRAM_nonbanked = {"WRAM", 0xC000, 0xDFFF, BANKED_YES, 0xDFFF, 0,0,0, BANK_MEM_TYPE_WRAM, BANK_STARTNUM_0, BANK_MERGED_YES}; +const bank_item WRAM_nonbanked = {"WRAM", 0xC000, 0xDFFF, BANKED_YES, 0xDFFF, 0,0,0, BANK_MEM_TYPE_WRAM, BANK_STARTNUM_0, BANK_MERGED_YES, HIDDEN_NO}; // HRAM -const bank_item HRAM = {"HRAM", 0xFF80, 0xFFFE, BANKED_NO, 0xFFFE, 0,0,0, BANK_MEM_TYPE_HRAM, BANK_STARTNUM_0, BANK_MERGED_NO}; +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 ===== @@ -66,15 +66,15 @@ 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) -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}; -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}; +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}; +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}; -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}; +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}; // 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}; -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}; +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}; static int bank_template_add(int idx, bank_item * p_bank_templates, const bank_item * p_bank) { diff --git a/gbdk-support/romusage/src/banks.c b/gbdk-support/romusage/src/banks.c index cd5c9c15..2bae518c 100644 --- a/gbdk-support/romusage/src/banks.c +++ b/gbdk-support/romusage/src/banks.c @@ -657,6 +657,16 @@ static void bank_fill_area_gaps_with_unknown(void) { } +// Check if a bank name matches any substrings on the hide list +static bool bank_name_check_hidden(char * str_bank_name) { + + for (int c = 0; c < banks_hide_count; c++) { + if (strstr(str_bank_name, banks_hide_list[c])) return true; + } + return false; +} + + // Print banks to output void banklist_finalize_and_show(void) { @@ -672,6 +682,7 @@ void banklist_finalize_and_show(void) { for (c = 0; c < bank_list.count; c++) { // Sort areas in bank and calculate usage banks[c].size_used = bank_areas_calc_used(&banks[c], banks[c].start, banks[c].end); + banks[c].hidden = bank_name_check_hidden(banks[c].name); if (get_option_area_sort() == OPT_AREA_SORT_SIZE_DESC) qsort (banks[c].area_list.p_array, banks[c].area_list.count, sizeof(area_item), area_item_compare_size_desc); @@ -725,7 +736,7 @@ void bank_areas_split_to_buckets(bank_item * p_bank, uint32_t range_start, uint3 bank_item bank_copy = *p_bank; bank_copy.area_list.p_array = (void *)malloc(bank_copy.area_list.size * bank_copy.area_list.typesize); if (!bank_copy.area_list.p_array) { - log_error("ERROR: Failed to reallocate memory for list!\n"); + log_error("Error: Failed to reallocate memory for list!\n"); exit(EXIT_FAILURE); } // Copy main list of areas to copy of bank for modification diff --git a/gbdk-support/romusage/src/banks.h b/gbdk-support/romusage/src/banks.h index 8ce9f31c..762b7e8d 100644 --- a/gbdk-support/romusage/src/banks.h +++ b/gbdk-support/romusage/src/banks.h @@ -39,6 +39,9 @@ #define BANK_MERGED_NO false #define BANK_MERGED_YES true +#define HIDDEN_NO false +#define HIDDEN_YES true + #define MINIGRAPH_SIZE (2 * 14) // Number of characters wide (inside edge brackets) #define LARGEGRAPH_BYTES_PER_CHAR 16 @@ -79,6 +82,7 @@ typedef struct bank_item { int base_bank_num; bool is_merged_bank; // End of templating vars + bool hidden; // TODO: track overflow bytes and report them in graph list_type area_list; diff --git a/gbdk-support/romusage/src/banks_print.c b/gbdk-support/romusage/src/banks_print.c index e8246644..4deda9c3 100644 --- a/gbdk-support/romusage/src/banks_print.c +++ b/gbdk-support/romusage/src/banks_print.c @@ -254,12 +254,15 @@ void banklist_printall(list_type * p_bank_list) { // Print all banks for (c = 0; c < p_bank_list->count; c++) { - bank_print_info(&banks[c]); - fprintf(stdout,"\n"); + if (!banks[c].hidden) { + bank_print_info(&banks[c]); + fprintf(stdout,"\n"); - if (get_option_area_sort() != OPT_AREA_SORT_HIDE) // This is a hack-workaround, TODO:fixme - if (banks_display_areas) - bank_print_area(&banks[c]); + if (get_option_area_sort() != OPT_AREA_SORT_HIDE) { // This is a hack-workaround, TODO:fixme + if (banks_display_areas) + bank_print_area(&banks[c]); + } + } } // End: Print all banks loop @@ -333,10 +336,12 @@ void banklist_printall_json(list_type * p_bank_list) { // Print each bank as an array object item for (c = 0; c < p_bank_list->count; c++) { - // Comma separator between array items - if (c > 0) fprintf(stdout," ,\n"); + if (!banks[c].hidden) { + // Comma separator between array items + if (c > 0) fprintf(stdout," ,\n"); - bank_print_info_json(&banks[c]); + bank_print_info_json(&banks[c]); + } } // JSON array footer diff --git a/gbdk-support/romusage/src/cdb_file.c b/gbdk-support/romusage/src/cdb_file.c index a9f63c9e..6c30b191 100644 --- a/gbdk-support/romusage/src/cdb_file.c +++ b/gbdk-support/romusage/src/cdb_file.c @@ -10,6 +10,7 @@ #include #include "common.h" +#include "logging.h" #include "list.h" #include "banks.h" #include "cdb_file.h" @@ -288,7 +289,10 @@ int cdb_file_process_symbols(char * filename_in) { cdb_symbollist_add_all_to_banks(); } // end: if valid file - else return (false); + else { + log_error("Error: Failed to open input file %s\n", filename_in); + return false; + } return true; } diff --git a/gbdk-support/romusage/src/common.c b/gbdk-support/romusage/src/common.c index fa9deec6..6f7c0a7c 100644 --- a/gbdk-support/romusage/src/common.c +++ b/gbdk-support/romusage/src/common.c @@ -3,12 +3,14 @@ // bbbbbr 2020 #include +#include #include #include #include #include "common.h" #include "logging.h" +#include "rom_file.h" bool banks_display_areas = false; bool banks_display_headers = false; @@ -38,6 +40,8 @@ bool option_percentage_based_color = false; uint32_t option_area_hide_size = OPT_AREA_HIDE_SIZE_DEFAULT; bool exit_error = false; +int banks_hide_count = 0; +char banks_hide_list[BANKS_HIDE_SZ][DEFAULT_STR_LEN]; // Turn on/off display of areas within bank @@ -151,7 +155,7 @@ void set_option_area_hide_size(uint32_t value) { // -sP:DEFAULT:ROM:VRAM:SRAM:WRAM:HRAM // // Custom color scheme for output -bool option_set_displayed_bank_range(char * arg_str) { +bool set_option_displayed_bank_range(char * arg_str) { #define MAX_SPLIT_WORDS 4 #define EXPECTED_COLS 3 @@ -223,6 +227,54 @@ bool get_option_display_asciistyle(void) { } +// Add a substring for hiding banks +bool set_option_banks_hide_add(char * str_bank_hide_substring) { + + if (banks_hide_count < BANKS_HIDE_SZ) { + snprintf(banks_hide_list[banks_hide_count], (DEFAULT_STR_LEN - 1), "%s", str_bank_hide_substring); + banks_hide_count++; + return true; + } else + log_error("Error: no bank hide string slots available\n"); + + + return false; +} + + +// Set hex bytes treated as Empty in ROM files (.gb/etc) -b:HEXVAL:HEXVAL... +// -b:FF +// Value passed in has "-e" stripped off the front +bool set_option_binary_rom_empty_values(char * arg_str) { + + #define MAX_ROMFILE_ENTRIES 256 + #define MIN_EXPECTED_ENTRIES 1 + + char entries_found; + char * p_str; + char * p_words[MAX_ROMFILE_ENTRIES]; + + // Clear existing defaults + romfile_empty_value_table_clear(); + + // Split string into words separated by : chars + entries_found = 0; + p_str = strtok(arg_str,":"); + while (p_str != NULL) + { + p_words[entries_found++] = p_str; + p_str = strtok(NULL, "-:"); + if (entries_found >= MAX_ROMFILE_ENTRIES) break; + } + + for (int c = 0; c < entries_found; c++) + romfile_empty_value_table_add_entry( (uint8_t)strtol(p_words[c], NULL, 16) ); + + if (entries_found >= MIN_EXPECTED_ENTRIES) + return true; + else + return false; // Signal failure +} void set_exit_error(void) { diff --git a/gbdk-support/romusage/src/common.h b/gbdk-support/romusage/src/common.h index c740a40a..a70baba3 100644 --- a/gbdk-support/romusage/src/common.h +++ b/gbdk-support/romusage/src/common.h @@ -38,6 +38,9 @@ #define OPT_PLAT_GAMEBOY 0u #define OPT_PLAT_SMS_GG_GBDK 1u // GBDK specific layout of sms/gg +#define BANKS_HIDE_SZ 30 // How many hide substrings to support +#define BANKS_HIDE_MAX (BANKS_HIDE_SZ - 1) + extern bool banks_display_areas; extern bool banks_display_headers; @@ -64,6 +67,9 @@ extern unsigned int option_merged_banks; extern uint32_t option_area_hide_size; extern bool exit_error; +extern int banks_hide_count; +extern char banks_hide_list[BANKS_HIDE_SZ][DEFAULT_STR_LEN]; + void set_option_all_areas_exclusive(bool value); void set_option_quiet_mode(bool value); @@ -81,9 +87,11 @@ void set_option_show_compact(bool value); void set_option_show_json(bool value); void set_option_summarized(bool value); -bool option_set_displayed_bank_range(char * arg_str); +bool set_option_displayed_bank_range(char * arg_str); void set_option_merged_banks(unsigned int value); +bool set_option_banks_hide_add(char * str_bank_hide_substring); +bool set_option_binary_rom_empty_values(char * arg_str); int get_option_input_source(void); int get_option_area_sort(void); @@ -99,4 +107,5 @@ uint32_t round_up_power_of_2(uint32_t val); uint32_t min(uint32_t a, uint32_t b); uint32_t max(uint32_t a, uint32_t b); + #endif // _COMMON_H \ No newline at end of file diff --git a/gbdk-support/romusage/src/ihx_file.c b/gbdk-support/romusage/src/ihx_file.c index 3a41fac6..996ba609 100644 --- a/gbdk-support/romusage/src/ihx_file.c +++ b/gbdk-support/romusage/src/ihx_file.c @@ -229,7 +229,6 @@ void area_convert_and_add(area_item area) { int ihx_file_process_areas(char * filename_in) { - int ret = true; // default to success char cols; char strline_in[MAX_STR_LEN] = ""; FILE * ihx_file = fopen(filename_in, "r"); @@ -301,9 +300,11 @@ int ihx_file_process_areas(char * filename_in) { fclose(ihx_file); } // end: if valid file - else - ret = false; + else { + log_error("Error: Failed to open input file %s\n", filename_in); + return false; + } - return ret; + return true; } diff --git a/gbdk-support/romusage/src/list.c b/gbdk-support/romusage/src/list.c index 361bd199..c4eabf94 100644 --- a/gbdk-support/romusage/src/list.c +++ b/gbdk-support/romusage/src/list.c @@ -21,7 +21,7 @@ void list_init(list_type * p_list, size_t array_typesize) { p_list->p_array = (void *)malloc(p_list->size * p_list->typesize); if (!p_list->p_array) { - log_error("ERROR: Failed to allocate memory for list!\n"); + log_error("Error: Failed to allocate memory for list!\n"); exit(EXIT_FAILURE); } } @@ -54,7 +54,7 @@ void list_additem(list_type * p_list, void * p_newitem) { p_list->p_array = (void *)realloc(p_list->p_array, p_list->size * p_list->typesize); // If realloc failed, free original buffer before quitting if (!p_list->p_array) { - log_error("ERROR: Failed to reallocate memory for list!\n"); + log_error("Error: Failed to reallocate memory for list!\n"); if (tmp_list) { free(tmp_list); tmp_list = NULL; diff --git a/gbdk-support/romusage/src/map_file.c b/gbdk-support/romusage/src/map_file.c index 31466366..f30108b6 100644 --- a/gbdk-support/romusage/src/map_file.c +++ b/gbdk-support/romusage/src/map_file.c @@ -10,6 +10,7 @@ #include #include "common.h" +#include "logging.h" #include "banks.h" #include "map_file.h" @@ -141,7 +142,10 @@ int map_file_process_areas(char * filename_in) { fclose(map_file); } // end: if valid file - else return (false); + else { + log_error("Error: Failed to open input file %s\n", filename_in); + return false; + } return true; } diff --git a/gbdk-support/romusage/src/noi_file.c b/gbdk-support/romusage/src/noi_file.c index c600bd8a..6b8ce04a 100644 --- a/gbdk-support/romusage/src/noi_file.c +++ b/gbdk-support/romusage/src/noi_file.c @@ -10,6 +10,7 @@ #include #include "common.h" +#include "logging.h" #include "list.h" #include "banks.h" #include "noi_file.h" @@ -172,7 +173,10 @@ int noi_file_process_areas(char * filename_in) { noi_arealist_add_all_to_banks(); } // end: if valid file - else return (false); + else { + log_error("Error: Failed to open input file %s\n", filename_in); + return false; + } return true; } diff --git a/gbdk-support/romusage/src/rom_file.c b/gbdk-support/romusage/src/rom_file.c index 232bbd69..e96a5fa2 100644 --- a/gbdk-support/romusage/src/rom_file.c +++ b/gbdk-support/romusage/src/rom_file.c @@ -17,8 +17,15 @@ #define ADDR_UNSET 0xFFFFFFFF -#define EMPTY_CONSECUTIVE_THRESHOLD 16 -#define EMPTY_VAL 0xFF + +#define EMPTY_RUN_TOO_SHORT(length, threshold) ((length > 0) && (length < threshold)) + +#define EMPTY_VALUE_MAX_COUNT 256 +#define EMPTY_DEFAULT_CONSECUTIVE_THRESHOLD 17 +#define EMPTY_0x00_CONSECUTIVE_THRESHOLD 128 // Larger threshold for 0x00 empty values due to possible sparse arrays +bool empty_values[EMPTY_VALUE_MAX_COUNT]; +uint32_t empty_consecutive_thresholds[EMPTY_VALUE_MAX_COUNT]; + #define BANK_SIZE 0x4000 #define BANK_ADDR_MASK 0x00003FFF #define BANK_NUM_MASK 0xFFFFC000 @@ -27,6 +34,36 @@ #define ROM_ADDR_TO_BANKED(addr) ((addr & BANK_ADDR_MASK) | ((addr & BANK_NUM_MASK) << BANK_NUM_UPSHIFT)) + +// Clear the empty values table to all values disabled +// should be called to remove defaults +void romfile_empty_value_table_clear(void) { + for (int c = 0; c < EMPTY_VALUE_MAX_COUNT; c++) + empty_values[c] = false; +} + + +// Set a byte value in the empty values table to true, range is 0-255 (byte) +void romfile_empty_value_table_add_entry(uint8_t value) { + empty_values[value] = true; +} + + +// Call this before processing option arguments +void romfile_init_defaults(void) { + + // Default is: only value considered empty is 0xFF + romfile_empty_value_table_clear(); + empty_values[0xFF] = true; + + // "Empty" 0x00 byte values use a longer run length threshold than other values due to possible sparse arrays + for (int c = 0; c < EMPTY_VALUE_MAX_COUNT; c++) { + empty_consecutive_thresholds[c] = EMPTY_DEFAULT_CONSECUTIVE_THRESHOLD; + } + empty_consecutive_thresholds[0x00] = EMPTY_0x00_CONSECUTIVE_THRESHOLD; +} + + // Read from a file into a buffer (will allocate needed memory) // Returns NULL if reading file didn't succeed uint8_t * file_read_into_buffer(char * filename, uint32_t *ret_size) { @@ -50,25 +87,23 @@ uint8_t * file_read_into_buffer(char * filename, uint32_t *ret_size) { } // Read was successful, set return size *ret_size = fsize; - } else log_error("ERROR: Failed to allocate memory to read file %s\n", filename); + } else log_error("Error: Failed to allocate memory to read file %s\n", filename); - } else log_error("ERROR: Failed to read size of file %s\n", filename); + } else log_error("Error: Failed to read size of file %s\n", filename); fclose(file_in); - } else log_error("ERROR: Failed to open input file %s\n", filename); + } else log_error("Error: Failed to open input file %s\n", filename); return filedata; } // Calculate a range, adjust it's bank num and add try adding to banks if valid -static void rom_add_range(area_item range, uint32_t cur_idx, uint32_t empty_run, bool romsize_32K_or_less) { +static void rom_add_range(area_item range, bool romsize_32K_or_less) { + // If active range ended, add to areas if (range.start != ADDR_UNSET) { - // Range ended, add to areas - range.end = cur_idx - empty_run; - // Don't try to virtual translate address for binary ROM // files 32K or smaller, most likely they're unbanked. if (!romsize_32K_or_less) { @@ -101,9 +136,11 @@ int rom_file_process(char * filename_in) { uint8_t * p_buf = NULL; uint32_t buf_idx = 0; uint32_t buf_length = 0; - uint32_t empty_run = 0; + uint32_t empty_run_length; + uint32_t empty_run_length_threshold; + uint8_t empty_run_value; uint32_t bank_bytes = 0; - area_item rom_range; + area_item used_rom_range; bool romsize_32K_or_less; set_option_input_source(OPT_INPUT_SRC_ROM); @@ -112,50 +149,91 @@ int rom_file_process(char * filename_in) { p_buf = file_read_into_buffer(filename_in, &buf_length); romsize_32K_or_less = (buf_length <= 0x8000); - rom_range.name[0] = '\0'; // Rom file ranges don't have names, set string to empty - rom_range.start = ADDR_UNSET; + used_rom_range.name[0] = '\0'; // Rom file ranges don't have names, set string to empty if (p_buf) { // Loop through all ROM bytes while (buf_idx < buf_length) { + // This is looking for "Used" ranges broken up by non-"Empty" ranges + // // Process each bank (0x4000 bytes in a row) separately // and close out any ranges that might span between them if (buf_length > BANK_SIZE) bank_bytes = BANK_SIZE; else bank_bytes = buf_length; + // Reset range state values for each bank pass + used_rom_range.start = ADDR_UNSET; + empty_run_length = 0; + while (bank_bytes) { - // Split buffer up into runs of non-zero bytes - // with a threshold of N zero bytes in a row to split them - if (p_buf[buf_idx] != EMPTY_VAL) { - if (rom_range.start == ADDR_UNSET) - rom_range.start = buf_idx; - empty_run = 0; - } else { - empty_run++; + // Split buffer up into potential runs of "Used" bytes with a + // threshold of N non-empty same value bytes in a row to split them up - // Handle current run/range if present and over threshold. - // Otherwise ignore the "empty" vals since it may be data of that value - if ((empty_run > EMPTY_CONSECUTIVE_THRESHOLD) && - (rom_range.start != ADDR_UNSET)) { + uint8_t cur_byte_value = p_buf[buf_idx]; - // Add range then flag as cleared and prep for a new range - rom_add_range(rom_range, buf_idx, empty_run, romsize_32K_or_less); - rom_range.start = ADDR_UNSET; + // Continue an existing run if the value matches the current runs value (0x00 or 0xFF) + if ((empty_run_length > 0) && (cur_byte_value == empty_run_value)) { + empty_run_length++; + + // If the current "Empty" range is over the threshold it means + // any existing "Used" data range needs to be closed out and submitted. + // + // Otherwise the "Empty" values may be part of data and can be ignored + if ((empty_run_length >= empty_run_length_threshold) && + (used_rom_range.start != ADDR_UNSET)) { + + // Add range and back-calculate last "Used" range address using start of "empty" address + used_rom_range.end = buf_idx - empty_run_length; + rom_add_range(used_rom_range, romsize_32K_or_less); + // Clear as ready for new range + used_rom_range.start = ADDR_UNSET; } } + else { + // Close out pending failed (too short) "Empty" run + if (EMPTY_RUN_TOO_SHORT(empty_run_length, empty_run_length_threshold)) { + // If no range started, then convert it to a "Used" range since the bytes aren't actually empty + if (used_rom_range.start == ADDR_UNSET) used_rom_range.start = buf_idx - empty_run_length; + } + + // Start a potential "Empty" new run + if (empty_values[cur_byte_value] == true) { + empty_run_length = 1; + empty_run_value = cur_byte_value; + // "Empty" 0x00 byte values use a longer run length threshold due to possible sparse arrays + empty_run_length_threshold = empty_consecutive_thresholds[cur_byte_value]; + } + // Not "Empty", so reset "Empty" length + else { + empty_run_length = 0; + // Start a potential "Used" (non-empty) data range if one isn't active. + if (used_rom_range.start == ADDR_UNSET) used_rom_range.start = buf_idx; + } + + } buf_idx++; bank_bytes--; } // end: while still _bank_ bytes to process - // Close out a remaining run if one exists (at last byte which is -1 of current) - // Flag as cleared and prep for a new range - rom_add_range(rom_range, buf_idx - 1, empty_run, romsize_32K_or_less); - rom_range.start = ADDR_UNSET; + // End of Bank Cleanup + + // Potentially Empty bytes at the end of a bank that don't meet threshold... might be empty? + // + // // Convert "Empty" run to "Used" if it didn't cross the "Empty" threshold + // if (EMPTY_RUN_TOO_SHORT(empty_run_length, empty_run_length_threshold)) { + // if (used_rom_range.start == ADDR_UNSET) used_rom_range.start = buf_idx - empty_run_length; + // } + + // Close pending "Used" run if needed (at last byte which is -1 of current) + if (used_rom_range.start != ADDR_UNSET) { + used_rom_range.end = (buf_idx - 1); + rom_add_range(used_rom_range, romsize_32K_or_less); + } } // End main buffer loop @@ -165,7 +243,10 @@ int rom_file_process(char * filename_in) { } } // end: if valid file - else return (false); + else { + log_error("Error: Failed to open input file %s\n", filename_in); + return false; + } return true; } diff --git a/gbdk-support/romusage/src/rom_file.h b/gbdk-support/romusage/src/rom_file.h index b68708e3..a3d89695 100644 --- a/gbdk-support/romusage/src/rom_file.h +++ b/gbdk-support/romusage/src/rom_file.h @@ -3,3 +3,6 @@ // bbbbbr 2020 int rom_file_process(char * filename_in); +void romfile_empty_value_table_clear(void); +void romfile_empty_value_table_add_entry(uint8_t value); +void romfile_init_defaults(void); diff --git a/gbdk-support/romusage/src/romusage.c b/gbdk-support/romusage/src/romusage.c index 5a97f9d8..bce142bf 100644 --- a/gbdk-support/romusage/src/romusage.c +++ b/gbdk-support/romusage/src/romusage.c @@ -19,10 +19,15 @@ #include "cdb_file.h" #include "rom_file.h" -#define VERSION "version 1.2.8" +#define VERSION "version 1.3.0" + +enum { + HELP_FULL = 0, + HELP_BRIEF +}; void static display_cdb_warning(void); -void static display_help(void); +void static display_help(int mode); int handle_args(int argc, char * argv[]); static bool matches_extension(char *, char *); static void init(void); @@ -42,7 +47,7 @@ static void display_cdb_warning() { " ************************ NOTICE ************************ \n"); } -static void display_help(void) { +static void display_help(int mode) { fprintf(stdout, "romusage input_file.[map|noi|ihx|cdb|.gb[c]|.pocket|.duck|.gg|.sms] [options]\n" VERSION", by bbbbbr\n" @@ -60,6 +65,7 @@ static void display_help(void) { "\n" "-m : Manually specify an Area -m:NAME:HEXADDR:HEXLENGTH\n" "-e : Manually specify an Area that should not overlap -e:NAME:HEXADDR:HEXLENGTH\n" + "-b : Set hex bytes treated as Empty in ROM files (.gb/etc) -b:HEXVAL[...] (default FF)\n" "-E : All areas are exclusive (except HEADERs), warn for any overlaps\n" "-q : Quiet, no output except warnings and errors\n" "-Q : Suppress output of warnings and errors\n" @@ -73,11 +79,15 @@ static void display_help(void) { "-smROM : Show Merged ROM_0 and ROM_1 output (i.e. bare 32K ROM)\n" "-smWRAM : Show Merged WRAM_0 and WRAM_1 output (i.e DMG/MGB not CGB)\n" " -sm* compatible with banked ROM_x or WRAM_x when used with -B\n" - "-sJ : Show JSON output. Some options not applicable. When used, -Q recommended\n" - "-nB : Hide warning banner (for .cdb output)\n" - "-nA : Hide areas (shown by default in .cdb output)\n" - "-z : Hide areas smaller than SIZE -z:DECSIZE\n" - "\n" + "-sJ : Show JSON output. Some options not applicable. When used, -Q recommended\n" + "-nB : Hide warning banner (for .cdb output)\n" + "-nA : Hide areas (shown by default in .cdb output)\n" + "-z : Hide areas smaller than SIZE -z:DECSIZE\n" + "-nMEM : Hide banks matching case sensitive substring (ex hide all RAM: -nMEM:RAM)\n" + "\n"); + + if (mode == HELP_FULL) { + fprintf(stdout, "Use: Read a .map, .noi, .cdb or .ihx file to display area sizes\n" "Example 1: \"romusage build/MyProject.map\"\n" "Example 2: \"romusage build/MyProject.noi -a -e:STACK:DEFF:100 -e:SHADOW_OAM:C000:A0\"\n" @@ -85,6 +95,7 @@ static void display_help(void) { "Example 4: \"romusage build/MyProject.map -q -R\"\n" "Example 5: \"romusage build/MyProject.noi -sR -sP:90:32:90:35:33:36\"\n" "Example 6: \"romusage build/MyProject.map -sRp -g -B -F:255:15 -smROM -smWRAM\"\n" + "Example 7: \"romusage build/MyProject.gb -g -b:FF:00\"\n" "\n" "Notes:\n" " * GBDK / RGBDS map file format detection is automatic.\n" @@ -97,6 +108,7 @@ static void display_help(void) { " so bank totals may be incorrect/missing.\n" " * GB/GBC/ROM files are just guessing, no promises.\n" ); + } } @@ -114,19 +126,15 @@ int handle_args(int argc, char * argv[]) { int i; if( argc < 2 ) { - display_help(); + display_help(HELP_FULL); return false; } - // Copy input filename (if not preceded with option dash) - if (argv[1][0] != '-') - snprintf(filename_in, sizeof(filename_in), "%s", argv[1]); - // Start at first optional argument, argc is zero based - for (i = 1; i <= (argc -1); i++ ) { + for (i = 0; i <= (argc -1); i++ ) { if (strstr(argv[i], "-h") == argv[i]) { - display_help(); + display_help(HELP_FULL); show_help_and_exit = true; return true; // Don't parse further input when -h is used } else if (strstr(argv[i], "-a") == argv[i]) { @@ -144,8 +152,8 @@ int handle_args(int argc, char * argv[]) { } } else if (strstr(argv[i], "-sP") == argv[i]) { if (!set_option_custom_bank_colors(argv[i])) { - fprintf(stdout,"malformed custom color palette: %s\n\n", argv[i]); - display_help(); + log_error("Malformed -sP custom color palette: %s\n\n", argv[i]); + // display_help(); return false; } } else if (strstr(argv[i], "-sH") == argv[i]) { @@ -178,9 +186,15 @@ int handle_args(int argc, char * argv[]) { } else if (strstr(argv[i], "-B") == argv[i]) { set_option_summarized(true); } else if (strstr(argv[i], "-F") == argv[i]) { - if (!option_set_displayed_bank_range(argv[i])) { - fprintf(stdout,"Malformed -F forced display max bank range\n\n"); - display_help(); + if (!set_option_displayed_bank_range(argv[i])) { + log_error("Malformed -F forced display max bank range\n\n"); + // display_help(); + return false; + } + + } else if (strstr(argv[i], "-b") == argv[i]) { + if (!set_option_binary_rom_empty_values(argv[i] + strlen("-b"))) { + log_error("Malformed or no entries found -b set hex values treated as empty for ROM files: %s\n\n", argv[i]); return false; } @@ -199,19 +213,31 @@ int handle_args(int argc, char * argv[]) { } else if (strstr(argv[i], "-z:") == argv[i]) { set_option_area_hide_size( strtol(argv[i] + 3, NULL, 10)); + } else if (strstr(argv[i], "-nMEM:") == argv[i]) { + if (!set_option_banks_hide_add(argv[i] + strlen("-nMEM:"))) { + log_error("Adding memory region to hide failed: %s\n\n", argv[i]); + // display_help(); + return false; + } + } else if ((strstr(argv[i], "-m") == argv[i]) || (strstr(argv[i], "-e") == argv[i])) { if (!area_manual_queue(argv[i])) { - fprintf(stdout,"Malformed manual area argument: %s\n\n", argv[i]); - display_help(); + log_error("Malformed -m or -e manual area argument: %s\n\n", argv[i]); + // display_help(); return false; } + } else if (argv[i][0] == '-') { - fprintf(stdout,"Unknown argument: %s\n\n", argv[i]); - display_help(); + log_error("Error: Unknown argument: %s\n\n", argv[i]); + display_help(HELP_BRIEF); return false; } + // Copy input filename (if not preceded with option dash) + else if (argv[i][0] != '-') { + snprintf(filename_in, sizeof(filename_in), "%s", argv[i]); + } } return true; @@ -235,6 +261,7 @@ static void init(void) { cdb_init(); noi_init(); banks_init(); + romfile_init_defaults(); } @@ -305,13 +332,14 @@ int main( int argc, char *argv[] ) { if (!get_option_hide_banners()) display_cdb_warning(); ret = EXIT_SUCCESS; // Exit with success } + } else { + log_error("Error: Incompatible file extension\n"); } - } } - if (ret == EXIT_FAILURE) - printf("Problem with filename or unable to open file! %s\n", filename_in); + // if (ret == EXIT_FAILURE) + // printf("Problem with filename or unable to open file! %s\n", filename_in); // Override exit code if was set during processing if (get_exit_error())