git.y1.nz

gbdk-2020

GameBoy Development Kit
download: https://git.y1.nz/archives/gbdk.tar.gz
README | Files | Log | Refs | LICENSE

gbdk-support/romusage/src/banks_summarized.c

      1 // This is free and unencumbered software released into the public domain.
      2 // For more information, please refer to <https://unlicense.org>
      3 // bbbbbr 2023
      4 
      5 #include <stdio.h>
      6 #include <string.h>
      7 #include <stdlib.h>
      8 #include <stdbool.h>
      9 #include <stdint.h>
     10 
     11 #include "common.h"
     12 #include "logging.h"
     13 #include "list.h"
     14 #include "banks.h"
     15 
     16 // === Summarized mode ===
     17 
     18 static void summarize_copy_areas(bank_item *, const bank_item *);
     19 static void summarize_copy_bank(bank_item *, const bank_item *);
     20 static bool check_apply_forced_max_bank(int * p_banknum, int bank_num_max_used, int bank_mem_type);
     21 static void summarize_fixup_sizes_and_names(list_type *);
     22 static bool summarize_try_merge_bank(const bank_item *, list_type *);
     23 
     24 // Copy (append) areas from one bank to another
     25 //
     26 // Translate banked areas addresses based on their bank number
     27 // Assumes: source and dest bank are valid, that areas from different banks don't overlap
     28 static void summarize_copy_modified_areas(bank_item * p_dest_bank, const bank_item * p_src_bank) {
     29 
     30     area_item * areas_to_copy = (area_item *)p_src_bank->area_list.p_array;
     31 
     32     // Copy areas from source bank to new summary bank
     33     for (int c = 0; c < p_src_bank->area_list.count; c++) {
     34 
     35         area_item new_area = areas_to_copy[c];
     36         // Scale area address up by bank number * bank size (factoring in whether bank start is 0 or 1 based)
     37         //
     38         // Handle special (-smWRAM or -smROM) case of a non-banked region merged with banked region.
     39         // This causes address range size to be 2x bank size and throws of base address calc for banked data
     40         // (to fix: bank - 1, and bank size / 2 )
     41         if ((p_src_bank->is_merged_bank) && (p_src_bank->bank_num > 0))
     42             new_area.start += (((p_src_bank->bank_num - p_src_bank->base_bank_num) - 1) * (p_src_bank->size_total / 2));
     43         else
     44             new_area.start += ((p_src_bank->bank_num - p_src_bank->base_bank_num) * p_src_bank->size_total);
     45 
     46         new_area.end = new_area.start + (new_area.length - 1);
     47 
     48         // Don't update bank size used here since that wouldn't factor in
     49         // overlapping areas, instead do it below in a single pass at the end
     50         // NO: p_dest_bank->size_used += new_area.length;
     51         list_additem(&(p_dest_bank->area_list), &new_area);
     52     }
     53 
     54     // Re-calculate size used in bank, taking overlapped areas into consideration
     55     //
     56     // For collapsing multiple banked regions with the same address range into
     57     // one bank, the address range would need to be scaled upward to accomodate
     58     // their larger virtual address range.
     59     //
     60     // Instead, make the assumption that areas have been previously clipped to be
     61     // within allowed ranges so that we don't need a stard/end range check and disable clipping. 
     62     p_dest_bank->size_used = bank_areas_calc_used(p_dest_bank, ADDR_NO_CLIP_MIN, ADDR_NO_CLIP_MAX);
     63 }
     64 
     65 
     66 // Copy a bank entry and it's areas
     67 static void summarize_copy_bank(bank_item * p_dest_bank, const bank_item * p_src_bank) {
     68 
     69     // Duplicate bank, re-initialize bank list & copy areas from source
     70     *p_dest_bank = *p_src_bank;
     71     p_dest_bank->size_used = 0;
     72     list_init(&(p_dest_bank->area_list), sizeof(area_item));
     73     summarize_copy_modified_areas(p_dest_bank, p_src_bank);
     74 }
     75 
     76 
     77 // Checks to see whether -F  : Force displayed Max ROM and SRAM bank range needs to be applied
     78 // Modifies p_banknum if so and returns true
     79 static bool check_apply_forced_max_bank(int * p_banknum, int bank_num_max_used, int bank_mem_type) {
     80 
     81     int forced_bank_num;
     82     char str_ROM[] = "ROM";
     83     char str_SRAM[] = "SRAM";
     84     char str_NONE[] = "UNKNOWN";
     85     char * p_str_banktype = str_NONE;
     86 
     87     if (option_forced_display_max_bank_ROM) {
     88 
     89         switch (bank_mem_type) {
     90             case BANK_MEM_TYPE_ROM:
     91                     forced_bank_num = option_forced_display_max_bank_ROM;
     92                     p_str_banktype = str_ROM;
     93                     break;
     94             case BANK_MEM_TYPE_SRAM:
     95                     forced_bank_num = option_forced_display_max_bank_SRAM;
     96                     p_str_banktype = str_SRAM;
     97                     break;
     98         }
     99 
    100         if (forced_bank_num < bank_num_max_used) {
    101             log_warning("Warning! Forced Max %s Bank %d is smaller than Max Used Bank %d\n", p_str_banktype, forced_bank_num, bank_num_max_used);
    102             if (option_error_on_warning)
    103                 set_exit_error();
    104         }
    105 
    106         *p_banknum = forced_bank_num;
    107         return true; // Success
    108     }
    109     return false; // Failure
    110 }
    111 
    112 
    113 // After banked regions have been merged, fix their names and sizes
    114 static void summarize_fixup_sizes_and_names(list_type * p_bank_list_summarized) {
    115 
    116     bank_item * banks_summarized = (bank_item *)p_bank_list_summarized->p_array;
    117 
    118     for (int c=0; c < p_bank_list_summarized->count; c++) {
    119         if (banks_summarized[c].is_banked) {
    120 
    121             // Some banked region bank nums are 0, don't process those
    122             // (no need to resize, resize code not built to handle it)
    123             if (banks_summarized[c].bank_num) {
    124 
    125                 // Save current as max "used" before replacing with max possible
    126                 int bank_num_max_used = banks_summarized[c].bank_num;
    127 
    128                 // ROM_X size: Round up bank num to next (power of 2) -1
    129                 // SRAM_X size: Round up to next (power of 4) - 1
    130                 // WRAM_X: Fixed number of banks on CGB, 7 always max
    131                 switch (banks_summarized[c].bank_mem_type) {
    132                     case BANK_MEM_TYPE_ROM:
    133                             if (! check_apply_forced_max_bank(&banks_summarized[c].bank_num, bank_num_max_used, banks_summarized[c].bank_mem_type))
    134                                 banks_summarized[c].bank_num = round_up_power_of_2((uint32_t)banks_summarized[c].bank_num + 1) - 1;
    135                             break;
    136                     case BANK_MEM_TYPE_SRAM:
    137                             if (! check_apply_forced_max_bank(&banks_summarized[c].bank_num, bank_num_max_used, banks_summarized[c].bank_mem_type)) {
    138                                 if      (banks_summarized[c].bank_num > 7) banks_summarized[c].bank_num = 15;
    139                                 else if (banks_summarized[c].bank_num > 3) banks_summarized[c].bank_num = 7;
    140                                 else if (banks_summarized[c].bank_num > 1) banks_summarized[c].bank_num = 3;
    141                             }
    142                             break;
    143                     case BANK_MEM_TYPE_WRAM: banks_summarized[c].bank_num = WRAM_X_MAX_BANKS;
    144                             break;
    145                 }
    146 
    147                 // Update bank total size (factoring in whether bank start is 0 or 1 based)
    148                 banks_summarized[c].size_total = ((banks_summarized[c].bank_num - banks_summarized[c].base_bank_num) + 1) *  banks_summarized[c].size_total;
    149 
    150                 // Handle special (-cWRAM or -cROM) case of a non-banked region merged with banked region.
    151                 // This causes address range size to be 2x which inflates total bank size. Divide by 2 to fix.
    152                 if (banks_summarized[c].is_merged_bank)
    153                     banks_summarized[c].size_total /= 2;
    154 
    155                 // Don't resize .end so that bank region shows correctly when rendered. charts will use ".size_total"
    156                 // banks_summarized[c].end = (banks_summarized[c].size_total - 1) + banks_summarized[c].start;
    157 
    158                 // Update Bank name with Used / Max - example: "ROM_1" with "ROM_Used/Max"
    159                 char new_name[BANK_MAX_STR];
    160                 // Strip bank name and underscore off the end if present
    161                 char * p_chr_underscore = strstr(banks_summarized[c].name, "_");
    162                 if (p_chr_underscore != NULL)
    163                     *p_chr_underscore = '\0';
    164 
    165                 int ret; // save result to suppress truncation warning, bank names will never be > 100 chars and truncation is fine if it got to that
    166                 ret = snprintf(new_name, sizeof(new_name), "%s_%d/%d", banks_summarized[c].name, bank_num_max_used, banks_summarized[c].bank_num);
    167                 ret = snprintf(banks_summarized[c].name, sizeof(banks_summarized[c].name), "%s", new_name);
    168             }
    169         }
    170     }
    171 }
    172 
    173 
    174 // Try to find a matching bank in summarized data
    175 // If found merge source bank into it
    176 static bool summarize_try_merge_bank(const bank_item * p_src_bank, list_type * p_bank_list_summarized) {
    177 
    178     bank_item * banks_summarized = (bank_item *)p_bank_list_summarized->p_array;
    179 
    180     // Check if bank type already exists in summarized data by start of memory region
    181     for (int dest_idx=0; dest_idx < p_bank_list_summarized->count; dest_idx++) {
    182         if (banks_summarized[dest_idx].start == p_src_bank->start) {
    183             // Found matching bank type, copy areas and bump up max bank used if needed
    184             summarize_copy_modified_areas(&banks_summarized[dest_idx], p_src_bank);
    185             banks_summarized[dest_idx].bank_num = max(banks_summarized[dest_idx].bank_num, p_src_bank->bank_num);
    186             return true; // Success
    187         }
    188     }
    189     return false; // Failed: no existing bank found to merge into
    190 }
    191 
    192 
    193 // Generate a summarized view with all banked
    194 // categories collapsed into to single ranges
    195 //
    196 // Data in the bank list is assumed to be good
    197 // and not requiring validation at this point
    198 void banklist_collapse_to_summary(const list_type * p_bank_list, list_type * p_bank_list_summarized) {
    199 
    200     bank_item * banks            = (bank_item *)p_bank_list->p_array;
    201     bank_item * banks_summarized = (bank_item *)p_bank_list_summarized->p_array;
    202     bank_item   new_bank;
    203 
    204     for (int src_idx=0; src_idx < p_bank_list->count; src_idx++) {
    205 
    206         // Add non-banked items directly without aggregating them
    207         // Assumes no dupes, or if dupes then intentional
    208         if (! banks[src_idx].is_banked) {
    209             summarize_copy_bank(&new_bank, &banks[src_idx]);
    210             list_additem(p_bank_list_summarized, &new_bank);
    211         } else {
    212             // Otherwise try to merge with an existing bank, or create a new entry in sumamrized data if needed
    213             if (! summarize_try_merge_bank(&banks[src_idx], p_bank_list_summarized)) {
    214                 summarize_copy_bank(&new_bank, &banks[src_idx]);
    215                 list_additem(p_bank_list_summarized, &new_bank);
    216             }
    217         }
    218     }
    219 
    220     summarize_fixup_sizes_and_names(p_bank_list_summarized);
    221 }

This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.