int fix_labels(void) { struct section *s = NULL; struct label *l, *m; /* fix labels' addresses */ l = labels_first; while (l != NULL) { if (l->status == LABEL_STATUS_LABEL || l->status == LABEL_STATUS_SYMBOL || l->status == LABEL_STATUS_BREAKPOINT) { if (l->section_status == ON) { s = sec_first; while (s != NULL) { if (s->id == l->section) { l->bank = s->bank; l->address += s->address; l->rom_address = l->address + bankaddress[l->bank]; if (s->status != SECTION_STATUS_ABSOLUTE) l->address += slots[l->slot].address; break; } s = s->next; } } else { l->rom_address = l->address + bankaddress[l->bank]; l->address += slots[l->slot].address; } } l = l->next; } /* check out if a label exists more than once in a different place */ l = labels_first; while (l != NULL) { if (is_label_anonymous(l->name) == FAILED && (l->status == LABEL_STATUS_LABEL || l->status == LABEL_STATUS_DEFINE)) { m = l->next; while (m != NULL) { if (strcmp(m->name, l->name) == 0) { if (l->address != m->address && !(m->name[0] == '*' || m->name[0] == '_')) { if (l->status == LABEL_STATUS_DEFINE) fprintf(stderr, "%s: FIX_LABELS: Definition \"%s\" was defined more than once.\n", get_file_name(l->file_id), l->name); else fprintf(stderr, "%s:%s:%d: FIX_LABELS: Label \"%s\" was defined more than once.\n", get_file_name(l->file_id), get_source_file_name(l->file_id, l->file_id_source), l->linenumber, l->name); return FAILED; } } m = m->next; } } l = l->next; } return SUCCEEDED; }
int mem_insert_ref(int address, unsigned char data) { if (address > romsize || address < 0) { fprintf(stderr, "%s:%s:%d: MEM_INSERT: Address $%x is out of the output range $0-$%x.\n", get_file_name(memory_file_id), get_source_file_name(memory_file_id, memory_file_id_source), memory_line_number, address, romsize); return FAILED; } if (rom_usage[address] > 1 && rom[address] != data) { if (memory_line_number != 0) fprintf(stderr, "%s:%s:%d: MEM_INSERT: Overwrite at $%x (old $%.2x new $%.2x).\n", get_file_name(memory_file_id), get_source_file_name(memory_file_id, memory_file_id_source), memory_line_number, address, rom[address], data); else fprintf(stderr, "%s:%s:[WLA]: MEM_INSERT: Overwrite at $%x (old $%.2x new $%.2x).\n", get_file_name(memory_file_id), get_source_file_name(memory_file_id, memory_file_id_source), address, rom[address], data); } rom_usage[address]++; rom[address] = data; return SUCCEEDED; }
int discard_unused_sections(void) { struct section *s; int a = 0, b = -1; /* iterate section discarding until there's no change in the amount of dropped sections */ while (a != b) { s = sec_first; while (s != NULL) { s->referenced = 0; s = s->next; } a = b; discard_iteration(); b = 0; s = sec_first; while (s != NULL) { if (s->referenced == 0) s->alive = NO; else s->alive = YES; if (s->alive == NO) b++; s = s->next; } } if (verbose_mode == ON) { /* announce all the unreferenced sections that will get dropped */ s = sec_first; while (s != NULL) { if (s->alive == NO) fprintf(stderr, "DISCARD: %s: %s: Section \"%s\" was discarded.\n", get_file_name(s->file_id), get_source_file_name(s->file_id, s->file_id_source), s->name); s = s->next; } } return SUCCEEDED; }
int insert_sections(void) { struct section *s, **sa; int d, f, i, x, t, q, sn, p; char *ram_slots[256], *c; /* initialize ram slots */ for (i = 0; i < 256; i++) ram_slots[i] = NULL; /* find all touched slots */ s = sec_first; while (s != NULL) { if (s->status == SECTION_STATUS_RAM && ram_slots[s->slot] == NULL) { ram_slots[s->slot] = malloc(slots[s->slot].size); if (ram_slots[s->slot] == NULL) { fprintf(stderr, "INSERT_SECTIONS: Out of memory error.\n"); return FAILED; } memset(ram_slots[s->slot], 0, slots[s->slot].size); } s = s->next; } /* count the sections */ i = 0; s = sec_first; while (s != NULL) { /* no references - skip it */ if (s->alive == YES) i++; s = s->next; } sn = i; if (sn == 0) return SUCCEEDED; sa = malloc(sizeof(struct section *) * sn); if (sa == NULL) { fprintf(stderr, "INSERT_SECTIONS: Out of memory error.\n"); return FAILED; } /* insert the sections into an array for sorting */ i = 0; s = sec_first; while (s != NULL) { /* no references - skip it */ if (s->alive == YES) sa[i++] = s; s = s->next; } /* sort the sections by size, biggest first */ qsort(sa, sn, sizeof(struct section *), _sections_sort); /* print the sizes (DEBUG) */ /* for (d = 0; d < i; d++) fprintf(stderr, "SIZE: %d\n", sa[d]->size); */ /* ram sections */ p = 0; while (p < sn) { s = sa[p++]; /* search for free space */ if (s->status == SECTION_STATUS_RAM) { c = ram_slots[s->slot]; i = slots[s->slot].size; t = 0; for (x = 0; x < i; x++, c++) { if (*c == 0) { for (q = 0; x < i && q < s->size; x++, q++, c++) { if (*c != 0) break; } if (q == s->size) { t = 1; break; } } } if (t == 0) { fprintf(stderr, "INSERT_SECTIONS: No room for RAM section \"%s\" (%d bytes) in slot %d.\n", s->name, s->size, s->slot); return FAILED; } /* mark as used */ c = c - s->size; for (i = 0; i < s->size; i++, c++) *c = 1; s->address = c - s->size - ram_slots[s->slot]; } } /* free tmp memory */ for (i = 0; i < 256; i++) { if (ram_slots[i] != NULL) free(ram_slots[i]); } /* force sections */ p = 0; while (p < sn) { s = sa[p++]; if (s->status == SECTION_STATUS_FORCE) { memory_file_id = s->file_id; banksize = banksizes[s->bank]; pc_bank = s->address; pc_slot = slots[s->slot].address + pc_bank; pc_full = pc_bank + bankaddress[s->bank]; pc_slot_max = slots[s->slot].address + slots[s->slot].size; d = pc_full; i = d + s->size; s->output_address = d; section_overwrite = OFF; if (i > romsize) { fprintf(stderr, "%s:%s: INSERT_SECTIONS: Section \"%s\" (%d bytes) goes beyond the ROM size.\n", get_file_name(s->file_id), get_source_file_name(s->file_id, s->file_id_source), s->name, s->size); return FAILED; } if (s->address + s->size > banksize) { fprintf(stderr, "%s:%s: INSERT_SECTIONS: Section \"%s\" (%d bytes) overflows from ROM bank %d.\n", get_file_name(s->file_id), get_source_file_name(s->file_id, s->file_id_source), s->name, s->size, s->bank); return FAILED; } for (; d < i; d++) { if (rom_usage[d] != 0 && rom[d] != s->data[d - pc_full]) break; } if (d == i) { for (i = 0; i < s->size; i++) { if (mem_insert_pc(s->data[i], s->slot, s->bank) == FAILED) return FAILED; } } else { fprintf(stderr, "%s:%s: INSERT_SECTIONS: No room for section \"%s\" (%d bytes).\n", get_file_name(s->file_id), get_source_file_name(s->file_id, s->file_id_source), s->name, s->size); return FAILED; } } } /* absolute sections */ p = 0; while (p < sn) { s = sa[p++]; if (s->status == SECTION_STATUS_ABSOLUTE) { d = s->address; s->output_address = d; section_overwrite = ON; for (i = 0; i < s->size; i++) { if (mem_insert(d + i, s->data[i]) == FAILED) return FAILED; } } } /* semisubfree sections */ p = 0; while (p < sn) { s = sa[p++]; if (s->status == SECTION_STATUS_SEMISUBFREE) { pc_bank = 0; d = bankaddress[s->bank]; /* align the starting address */ f = (pc_bank + d) % s->alignment; if (f > 0) pc_bank += s->alignment - f; i = FAILED; while (i == FAILED) { f = pc_bank; for (x = 0; pc_bank < s->address && rom_usage[pc_bank + d] == 0 && x < s->size; pc_bank++, x++) ; if (x == s->size) { i = SUCCEEDED; break; } if (pc_bank == s->address) { fprintf(stderr, "%s:%s: INSERT_SECTIONS: No room for section \"%s\" (%d bytes) in ROM bank %d.\n", get_file_name(s->file_id), get_source_file_name(s->file_id, s->file_id_source), s->name, s->size, s->bank); return FAILED; } /* find the next starting address */ f = (pc_bank + d) % s->alignment; if (f > 0) pc_bank += s->alignment - f; for (; pc_bank < s->address && rom_usage[pc_bank + d] != 0; pc_bank += s->alignment) ; } memory_file_id = s->file_id; banksize = banksizes[s->bank]; pc_bank = f; pc_slot = slots[s->slot].address + pc_bank; pc_full = pc_bank + bankaddress[s->bank]; pc_slot_max = slots[s->slot].address + slots[s->slot].size; s->address = pc_bank; s->output_address = pc_full; section_overwrite = OFF; for (i = 0; i < s->size; i++) { if (mem_insert_pc(s->data[i], s->slot, s->bank) == FAILED) return FAILED; } } } /* free & semifree sections */ p = 0; while (p < sn) { s = sa[p++]; if (s->status == SECTION_STATUS_FREE || s->status == SECTION_STATUS_SEMIFREE) { pc_bank = s->address; d = bankaddress[s->bank]; /* align the starting address */ f = (pc_bank + d) % s->alignment; if (f > 0) pc_bank += s->alignment - f; i = FAILED; while (i == FAILED) { f = pc_bank; for (x = 0; pc_bank < banksizes[s->bank] && rom_usage[pc_bank + d] == 0 && x < s->size; pc_bank++, x++) ; if (x == s->size) { i = SUCCEEDED; break; } if (pc_bank == banksizes[s->bank]) { fprintf(stderr, "%s:%s: INSERT_SECTIONS: No room for section \"%s\" (%d bytes) in ROM bank %d.\n", get_file_name(s->file_id), get_source_file_name(s->file_id, s->file_id_source), s->name, s->size, s->bank); return FAILED; } /* find the next starting address */ f = (pc_bank + d) % s->alignment; if (f > 0) pc_bank += s->alignment - f; for (; pc_bank < banksizes[s->bank] && rom_usage[pc_bank + d] != 0; pc_bank += s->alignment) ; } memory_file_id = s->file_id; banksize = banksizes[s->bank]; pc_bank = f; pc_slot = slots[s->slot].address + pc_bank; pc_full = pc_bank + bankaddress[s->bank]; pc_slot_max = slots[s->slot].address + slots[s->slot].size; s->address = pc_bank; s->output_address = pc_full; section_overwrite = OFF; for (i = 0; i < s->size; i++) { if (mem_insert_pc(s->data[i], s->slot, s->bank) == FAILED) return FAILED; } } } /* superfree sections */ p = 0; while (p < sn) { s = sa[p++]; if (s->status == SECTION_STATUS_SUPERFREE) { /* go through all the banks */ i = FAILED; f = 0; for (q = 0; i == FAILED && q < rombanks; q++) { pc_bank = 0; d = bankaddress[q]; /* align the starting address */ f = (pc_bank + d) % s->alignment; if (f > 0) pc_bank += s->alignment - f; /* if the slotsize and banksize differ -> try the next bank */ if (banksizes[q] != slots[s->slot].size) continue; while (i == FAILED) { f = pc_bank; for (x = 0; pc_bank < banksizes[q] && rom_usage[pc_bank + d] == 0 && x < s->size; pc_bank++, x++) ; if (x == s->size) { i = SUCCEEDED; break; } if (pc_bank == banksizes[q]) break; /* find the next starting address */ f = (pc_bank + d) % s->alignment; if (f > 0) pc_bank += s->alignment - f; for (; pc_bank < banksizes[s->bank] && rom_usage[pc_bank + d] != 0; pc_bank += s->alignment) ; } } if (i == SUCCEEDED) { s->bank = q-1; memory_file_id = s->file_id; banksize = banksizes[s->bank]; pc_bank = f; pc_slot = pc_bank; pc_full = pc_bank + bankaddress[s->bank]; pc_slot_max = slots[s->slot].size; s->address = pc_bank; s->output_address = pc_full; section_overwrite = OFF; for (i = 0; i < s->size; i++) if (mem_insert_pc(s->data[i], s->slot, s->bank) == FAILED) return FAILED; } else { fprintf(stderr, "%s:%s: INSERT_SECTIONS: No room for section \"%s\" (%d bytes).\n", get_file_name(s->file_id), get_source_file_name(s->file_id, s->file_id_source), s->name, s->size); return FAILED; } } } /* overwrite sections */ p = 0; while (p < sn) { s = sa[p++]; if (s->status == SECTION_STATUS_OVERWRITE) { memory_file_id = s->file_id; banksize = banksizes[s->bank]; pc_bank = s->address; pc_slot = slots[s->slot].address + pc_bank; pc_full = pc_bank + bankaddress[s->bank]; pc_slot_max = slots[s->slot].address + slots[s->slot].size; s->output_address = pc_full; section_overwrite = ON; if (pc_full + s->size > romsize) { fprintf(stderr, "%s:%s: INSERT_SECTIONS: Section \"%s\" (%d bytes) goes beyond the ROM size.\n", get_file_name(s->file_id), get_source_file_name(s->file_id, s->file_id_source), s->name, s->size); return FAILED; } if (s->address + s->size > banksize) { fprintf(stderr, "%s:%s: INSERT_SECTIONS: Section \"%s\" (%d bytes) overflows from ROM bank %d.\n", get_file_name(s->file_id), get_source_file_name(s->file_id, s->file_id_source), s->name, s->size, s->bank); return FAILED; } for (i = 0; i < s->size; i++) { if (mem_insert_pc(s->data[i], s->slot, s->bank) == FAILED) return FAILED; } } } free(sa); return SUCCEEDED; }
int fix_references(void) { struct reference *r; struct section *s = NULL; struct label *l, lt; int i, x; section_overwrite = OFF; /* insert references */ r = reference_first; while (r != NULL) { x = r->address; /* search for the section of the reference and fix the address */ if (r->section_status == ON) { s = sec_first; while (s != NULL) { if (s->id == r->section) { r->bank = s->bank; x += s->address; r->address += s->address; break; } s = s->next; } /* reference is inside a discarded section? */ if (s != NULL && s->alive == NO) { r = r->next; continue; } if (s == NULL) { if (write_bank_header_references(r) == FAILED) return FAILED; r = r->next; continue; } } if (!(r->section_status == ON && s->status == SECTION_STATUS_ABSOLUTE)) { x += bankaddress[r->bank]; r->address += slots[r->slot].address; } /* find the destination */ l = labels_first; /* request for bank number? */ if (r->name[0] == ':') { if (is_label_anonymous(&r->name[1]) == SUCCEEDED) { l = get_closest_anonymous_label(&r->name[1], x, r->file_id, l, r->section_status, r->section); } else if (strcmp(&r->name[1], "CADDR") == 0 || strcmp(&r->name[1], "caddr") == 0) { lt.status = LABEL_STATUS_LABEL; strcpy(lt.name, &r->name[1]); lt.address = r->address; lt.bank = r->bank; lt.section_status = OFF; l = < } else { while (l != NULL) { if (strcmp(l->name, &r->name[1]) == 0 && l->status != LABEL_STATUS_SYMBOL && l->status != LABEL_STATUS_BREAKPOINT) break; l = l->next; } } if (l == NULL) { fprintf(stderr, "%s:%s:%d: FIX_REFERENCES: Bank number request for an unknown label \"%s\".\n", get_file_name(r->file_id), get_source_file_name(r->file_id, r->file_id_source), r->linenumber, &r->name[1]); return FAILED; } if (cpu_65816 != 0) i = get_snes_pc_bank(l) >> 16; else i = l->bank; memory_file_id = r->file_id; memory_file_id_source = r->file_id_source; memory_line_number = r->linenumber; /* direct 16bit */ if (r->type == REFERENCE_TYPE_DIRECT_16BIT || r->type == REFERENCE_TYPE_RELATIVE_16BIT) { mem_insert_ref(x, i & 0xFF); mem_insert_ref(x + 1, (i >> 8) & 0xFF); } /* direct / relative 8bit with a definition */ else if (l->status == LABEL_STATUS_DEFINE) {
else i = l->bank; memory_file_id = r->file_id; memory_file_id_source = r->file_id_source; memory_line_number = r->linenumber; /* direct 16bit */ if (r->type == REFERENCE_TYPE_DIRECT_16BIT || r->type == REFERENCE_TYPE_RELATIVE_16BIT) { mem_insert_ref(x, i & 0xFF); mem_insert_ref(x + 1, (i >> 8) & 0xFF); } /* direct / relative 8bit with a definition */ else if (l->status == LABEL_STATUS_DEFINE) { fprintf(stderr, "%s:%s:%d: FIX_REFERENCES: Bank number request for a definition \"%s\"?\n", get_file_name(r->file_id), get_source_file_name(r->file_id, r->file_id_source), r->linenumber, l->name); return FAILED; } /* direct 24bit */ else if (r->type == REFERENCE_TYPE_DIRECT_24BIT) { mem_insert_ref(x, i & 0xFF); mem_insert_ref(x + 1, (i >> 8) & 0xFF); mem_insert_ref(x + 2, (i >> 16) & 0xFF); } /* relative/direct 8bit with a label */ else { mem_insert_ref(x, i & 0xFF); } } /* normal reference */ else {