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.