diff --git a/src/assembler.c b/src/assembler.c index d42e6be..31a1cdf 100644 --- a/src/assembler.c +++ b/src/assembler.c @@ -44,7 +44,7 @@ static ErrorInfo* resolve_defaults(AssemblerState *state) // check reported rom size is <= actual 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; return NULL; diff --git a/src/assembler/preprocessor.c b/src/assembler/preprocessor.c index 80abfc3..a7de4c0 100644 --- a/src/assembler/preprocessor.c +++ b/src/assembler/preprocessor.c @@ -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. 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 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_BLOCK diff --git a/src/rom.c b/src/rom.c index 34fcbfe..4fa0e5b 100644 --- a/src/rom.c +++ b/src/rom.c @@ -16,6 +16,7 @@ #define NUM_LOCATIONS 3 #define MAGIC_LEN 8 #define HEADER_SIZE 16 +#define SIZE_CODE_BUF 8 static size_t header_locations[NUM_LOCATIONS] = {0x7FF0, 0x3FF0, 0x1FF0}; 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) { - 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 diff --git a/src/util.c b/src/util.c index bb90c66..857bcb0 100644 --- a/src/util.c +++ b/src/util.c @@ -90,3 +90,54 @@ uint8_t region_string_to_code(const char *name) } 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; + } +} diff --git a/src/util.h b/src/util.h index 539cfba..b82df0c 100644 --- a/src/util.h +++ b/src/util.h @@ -11,3 +11,5 @@ uint8_t bcd_decode(uint8_t); uint64_t get_time_ns(); const char* region_code_to_string(uint8_t); uint8_t region_string_to_code(const char*); +size_t size_code_to_bytes(uint8_t); +uint8_t size_bytes_to_code(size_t);