bin_to_com.c (5571B)
1// This is free and unencumbered software released into the public domain. 2// For more information, please refer to <https://unlicense.org> 3// bbbbbr 2020 4 5#include <stdio.h> 6#include <string.h> 7#include <stdlib.h> 8#include <unistd.h> 9#include <stdbool.h> 10#include <stdint.h> 11 12#include "common.h" 13#include "list.h" 14#include "files.h" 15#include "noi_file.h" 16#include "bin_to_com.h" 17 18 19uint8_t * banks[BANKS_MAX_COUNT] = {NULL}; 20uint16_t banks_len[BANKS_MAX_COUNT] = {0}; 21uint16_t banks_count = 0; 22 23 24void banks_cleanup(void) { 25 for (int c = 0; c <= BANKS_MAX_ID; c++) { 26 if (banks[c] != NULL) { 27 28 free(banks[c]); 29 banks[c] = NULL; 30 } 31 } 32} 33 34 35// Allocate memory for banks as banks are requested 36// If preceding banks are not yet allocated then do those too 37uint8_t * bank_get_ptr(uint16_t bank_num) { 38 39 if (bank_num > BANKS_MAX_ID) { 40 printf("makecom: ERROR: Requested bank %d is larger than max bank num %d!\n", bank_num, BANKS_MAX_ID); 41 exit(EXIT_FAILURE); 42 } 43 44 if (banks[bank_num] == NULL) { 45 46 // Make sure all banks leading up to requested are also allocated 47 for (int c = 0; c <= bank_num; c++) { 48 if (banks[c] == NULL) { 49 50 banks[c] = malloc(BANK_SIZE); 51 52 if (!banks[c]) { 53 printf("makecom: ERROR: Failed to allocate memory for bank %d!\n", c); 54 exit(EXIT_FAILURE); 55 } 56 57 // zero out buffer (though unused space will not get written out) 58 memset(banks[c], 0x00u, BANK_SIZE); 59 } 60 } 61 } 62 63 return banks[bank_num]; 64} 65 66 67 68// Copy data from source bin file at offset address into requested bank buffer 69void copy_to_bank(uint16_t bank_num, uint32_t rom_src_addr, uint32_t bank_out_addr, uint32_t length) { 70 71 // TODO: make sure bin src addr doesn't exceed source file buffer length 72 if ((rom_src_addr + length) > rom_buf_in_len) { 73 printf("makecom: ERROR: Can't copy %d bytes from %x for bank %d, would overflow past end of ROM source buffer of size %d!\n", length, rom_src_addr, bank_num, (uint32_t)rom_buf_in_len); 74 exit(EXIT_FAILURE); 75 } 76 77 if ((bank_out_addr + length) > BANK_SIZE) { 78 printf("makecom: ERROR: Can't copy %d bytes to %04x for bank %d, would overflow past end of bank buffer of size %d!\n",length, bank_out_addr, bank_num, BANK_SIZE); 79 exit(EXIT_FAILURE); 80 } 81 82 if (bank_num > banks_count) 83 banks_count = bank_num; 84 85 // Update length of bank data buffers (to allow for truncating output later) 86 if ((bank_out_addr + length) > banks_len[bank_num]) 87 banks_len[bank_num] = (bank_out_addr + length); 88 89 // printf("* copying... bank:%d from:%x to:%x len:%d\n", 90 // bank_num, rom_src_addr, bank_out_addr, length); 91 92 memcpy(bank_get_ptr(bank_num) + bank_out_addr, p_rom_buf_in + rom_src_addr, length); 93} 94 95 96void banks_write_out(void) { 97 98 // If any of below fails it will trigger exit() and cleanup() will be called 99 100 // Write first bank out, handled differently than rest 101 if ((banks[0] != NULL) && (banks_len[0] > 0)) { 102 // printf("Bank %d: Writing %d bytes to %s\n",0, banks_len[0], filename_out_com); 103 file_write_from_buffer(filename_out_com, banks[0], banks_len[0]); 104 } else { 105 printf("makecom: Error: Bank 0 was empty, no data written\n"); 106 exit; 107 } 108 109 // Write out remaining banks if applicable 110 char bank_fname[MAX_STR_LEN] = ""; 111 for (int c = 1; c <= BANKS_MAX_ID; c++) { 112 if ((banks[c] != NULL) && (banks_len[0] > 0)) { 113 // Format to 8.3 filename with bank num as zero padded extension 114 sprintf(bank_fname, "%s.%03d", filename_banks_base, c); 115 // printf("Bank %d: Writing %d bytes to %s\n",c, banks_len[c], bank_fname); 116 file_write_from_buffer(bank_fname, banks[c], banks_len[c]); 117 } else 118 break; // Exit loop on first unpopulated bank 119 } 120 121} 122 123 124 125int bin2com(void) { 126 127 symbol_item * symbols = (symbol_item *)symbol_list.p_array; 128 129 for(int c = 0; c < symbol_list.count; c++) { 130 131 // Only process completed symbols (start and length both set, lenth not zero) 132 if ((symbols[c].addr_start != SYM_VAL_UNSET) && 133 (symbols[c].length != SYM_VAL_UNSET) && 134 (symbols[c].length > 0)) { 135 136 // If symbol is for a bank > 0 137 if ((strncmp(symbols[c].name, "_CODE_", (sizeof("_CODE_") - 1)) == 0) && (symbols[c].bank_num > 0)) { 138 // Copy data from bank addr in source ROM to start of separate bank buffer 139 copy_to_bank(symbols[c].bank_num, symbols[c].src_rom_addr, BANK_START_ADDR, symbols[c].length); 140 } else { 141 // For remaining symbols (assume bank 0), relocate them by -100 when possible (addr -> addr - 100) 142 copy_to_bank(BANK_0, symbols[c].addr_start, BANK_0_RELOC_ADDR(symbols[c].addr_start), symbols[c].length); 143 } 144 } 145 } 146 147 // Patch in updated bank / overlay count and bank filename 148 if ((banks_count > 0) && (overlay_count_addr != SYM_VAL_UNSET) && (overlay_name_addr != SYM_VAL_UNSET)) { 149 150 if (overlay_count_addr > BANK_0_ADDR_OFFSET) 151 *(banks[0] + (overlay_count_addr - BANK_0_ADDR_OFFSET)) = banks_count; 152 153 if (overlay_name_addr > BANK_0_ADDR_OFFSET) 154 memcpy(banks[0] + (overlay_name_addr - BANK_0_ADDR_OFFSET), filename_overlay, COM_OVERLAY_NAME_LEN-1); 155 } 156 157 // No write the data out 158 banks_write_out(); 159 160 return EXIT_SUCCESS; 161} 162 163 164