| @@ -44,7 +44,7 @@ static ErrorInfo* resolve_defaults(AssemblerState *state) | |||||
| // check reported rom size is <= actual rom size | // check reported rom size is <= actual rom size | ||||
| // if (!state.header.rom_size) | // if (!state.header.rom_size) | ||||
| // set to actual rom size | |||||
| // set to actual rom size using util's size_bytes_to_code() | |||||
| (void) state; | (void) state; | ||||
| return NULL; | return NULL; | ||||
| @@ -306,6 +306,14 @@ static ErrorInfo* build_asm_lines( | |||||
| } | } | ||||
| /* | /* | ||||
| Return whether the given header offset is a valid location. | |||||
| */ | |||||
| static inline bool is_header_offset_valid(uint16_t offset) | |||||
| { | |||||
| return offset == 0x7FF0 || offset == 0x3FF0 || offset == 0x1FF0; | |||||
| } | |||||
| /* | |||||
| Parse the region code string in an ASMLine and store it in *result. | Parse the region code string in an ASMLine and store it in *result. | ||||
| Return true on success and false on failure; in the latter case, *result is | Return true on success and false on failure; in the latter case, *result is | ||||
| @@ -334,11 +342,20 @@ static bool parse_region_string(uint8_t *result, const ASMLine *line) | |||||
| } | } | ||||
| /* | /* | ||||
| Return whether the given header offset is a valid location. | |||||
| Parse the size code in an ASMLine and store it in *result. | |||||
| Return true on success and false on failure. | |||||
| */ | */ | ||||
| static inline bool is_header_offset_valid(uint16_t offset) | |||||
| static bool parse_size_code(uint8_t *result, const ASMLine *line) | |||||
| { | { | ||||
| return offset == 0x7FF0 || offset == 0x3FF0 || offset == 0x1FF0; | |||||
| uint32_t bytes; | |||||
| if (!parse_uint32_t(&bytes, line, DIR_ROM_DECLSIZE)) | |||||
| return false; | |||||
| uint8_t code = size_bytes_to_code(bytes); | |||||
| if (code) | |||||
| return (*result = code), true; | |||||
| return false; | |||||
| } | } | ||||
| /* | /* | ||||
| @@ -417,8 +434,12 @@ ErrorInfo* preprocess(AssemblerState *state, const LineBuffer *source) | |||||
| END_DIRECTIVE | END_DIRECTIVE | ||||
| BEGIN_DIRECTIVE(DIR_ROM_DECLSIZE, uint8_t, state->header.rom_size, 0) | BEGIN_DIRECTIVE(DIR_ROM_DECLSIZE, uint8_t, state->header.rom_size, 0) | ||||
| // TODO: fixme | |||||
| FAIL(ED_PP_UNKNOWN) | |||||
| PARSER_BRANCH(uint8_t, { | |||||
| CLAMP_RANGE(0x10) | |||||
| VALIDATE(size_code_to_bytes(arg)) | |||||
| }, { | |||||
| VALIDATE(parse_size_code(&arg, line)) | |||||
| }) | |||||
| END_DIRECTIVE | END_DIRECTIVE | ||||
| END_DIRECTIVE_BLOCK | END_DIRECTIVE_BLOCK | ||||
| @@ -16,6 +16,7 @@ | |||||
| #define NUM_LOCATIONS 3 | #define NUM_LOCATIONS 3 | ||||
| #define MAGIC_LEN 8 | #define MAGIC_LEN 8 | ||||
| #define HEADER_SIZE 16 | #define HEADER_SIZE 16 | ||||
| #define SIZE_CODE_BUF 8 | |||||
| static size_t header_locations[NUM_LOCATIONS] = {0x7FF0, 0x3FF0, 0x1FF0}; | static size_t header_locations[NUM_LOCATIONS] = {0x7FF0, 0x3FF0, 0x1FF0}; | ||||
| static const char header_magic[MAGIC_LEN + 1] = "TMR SEGA"; | static const char header_magic[MAGIC_LEN + 1] = "TMR SEGA"; | ||||
| @@ -100,18 +101,17 @@ static uint16_t compute_checksum(const uint8_t *data, size_t size, uint8_t range | |||||
| */ | */ | ||||
| static const char* parse_reported_size(uint8_t value) | static const char* parse_reported_size(uint8_t value) | ||||
| { | { | ||||
| switch (value) { | |||||
| case 0xA: return "8 KB"; | |||||
| case 0xB: return "16 KB"; | |||||
| case 0xC: return "32 KB"; | |||||
| case 0xD: return "48 KB"; | |||||
| case 0xE: return "64 KB"; | |||||
| case 0xF: return "128 KB"; | |||||
| case 0x0: return "256 KB"; | |||||
| case 0x1: return "512 KB"; | |||||
| case 0x2: return "1 MB"; | |||||
| default: return "Unknown"; | |||||
| } | |||||
| static char buffer[SIZE_CODE_BUF]; | |||||
| size_t size = size_code_to_bytes(value); | |||||
| if (!size) | |||||
| strncpy(buffer, "Unknown", SIZE_CODE_BUF); | |||||
| else if (size >= (1 << 20)) | |||||
| snprintf(buffer, SIZE_CODE_BUF, "%zu MB", size >> 20); | |||||
| else | |||||
| snprintf(buffer, SIZE_CODE_BUF, "%zu KB", size >> 10); | |||||
| return buffer; | |||||
| } | } | ||||
| #endif | #endif | ||||
| @@ -90,3 +90,54 @@ uint8_t region_string_to_code(const char *name) | |||||
| } | } | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| /* | |||||
| Return the number of bytes in a ROM image based on its header size code. | |||||
| 0 is returned if the code is invalid. | |||||
| */ | |||||
| size_t size_code_to_bytes(uint8_t code) | |||||
| { | |||||
| #define KB << 10 | |||||
| #define MB << 20 | |||||
| switch (code) { | |||||
| case 0xA: return 8 KB; | |||||
| case 0xB: return 16 KB; | |||||
| case 0xC: return 32 KB; | |||||
| case 0xD: return 48 KB; | |||||
| case 0xE: return 64 KB; | |||||
| case 0xF: return 128 KB; | |||||
| case 0x0: return 256 KB; | |||||
| case 0x1: return 512 KB; | |||||
| case 0x2: return 1 MB; | |||||
| default: return 0; | |||||
| } | |||||
| #undef KB | |||||
| #undef MB | |||||
| } | |||||
| /* | |||||
| Given the number of bytes in a ROM image, return the size code. | |||||
| 0 is returned if the size is invalid. | |||||
| */ | |||||
| uint8_t size_bytes_to_code(size_t bytes) | |||||
| { | |||||
| if (bytes & ((1 << 10) - 1)) | |||||
| return 0; // Not an even number of KB | |||||
| switch (bytes >> 10) { | |||||
| case 8: return 0xA; | |||||
| case 16: return 0xB; | |||||
| case 32: return 0xC; | |||||
| case 48: return 0xD; | |||||
| case 64: return 0xE; | |||||
| case 128: return 0xF; | |||||
| case 256: return 0x0; | |||||
| case 512: return 0x1; | |||||
| case 1024: return 0x2; | |||||
| default: return 0; | |||||
| } | |||||
| } | |||||
| @@ -11,3 +11,5 @@ uint8_t bcd_decode(uint8_t); | |||||
| uint64_t get_time_ns(); | uint64_t get_time_ns(); | ||||
| const char* region_code_to_string(uint8_t); | const char* region_code_to_string(uint8_t); | ||||
| uint8_t region_string_to_code(const char*); | uint8_t region_string_to_code(const char*); | ||||
| size_t size_code_to_bytes(uint8_t); | |||||
| uint8_t size_bytes_to_code(size_t); | |||||