Преглед изворни кода

Implement serialize_binary() and header writing.

master
Ben Kurtovic пре 9 година
родитељ
комит
05c63c3f1c
5 измењених фајлова са 109 додато и 46 уклоњено
  1. +53
    -4
      src/assembler.c
  2. +1
    -41
      src/rom.c
  3. +5
    -0
      src/rom.h
  4. +48
    -1
      src/util.c
  5. +2
    -0
      src/util.h

+ 53
- 4
src/assembler.c Прегледај датотеку

@@ -101,16 +101,65 @@ static ErrorInfo* resolve_symbols(AssemblerState *state)
}

/*
Write the ROM header to the binary. Header contents are explained in rom.c.
*/
static void write_header(const ASMHeaderInfo *info, uint8_t *binary)
{
uint8_t *header = binary + info->offset;

// Bytes 0-7: magic string
memcpy(header, rom_header_magic, HEADER_MAGIC_LEN);
header += HEADER_MAGIC_LEN;

// Bytes 8, 9: unused
*(header++) = 0x00;
*(header++) = 0x00;

// Bytes A, B: checksum
if (info->checksum) {
uint16_t checksum = compute_checksum(binary, 0, info->rom_size);
*header = checksum & 0xFF;
*(header + 1) = checksum >> 8;
} else {
*header = *(header + 1) = 0x00;
}
header += 2;

// Bytes C, D: product code (least significant two bytes)
*header = bcd_encode(info->product_code % 100);
*(header + 1) = bcd_encode((info->product_code / 100) % 100);
header += 2;

// Byte E: product code (most significant nibble), version
*header = (info->product_code / 10000) << 4 | (info->version & 0x0F);
header++;

// Byte F: region code, ROM size
*header = (info->region << 4) | (info->rom_size & 0x0F);
}

/*
Convert finalized ASMInstructions and ASMData into a binary data block.

This function should never fail.
*/
static void serialize_binary(AssemblerState *state, uint8_t *binary)
static void serialize_binary(const AssemblerState *state, uint8_t *binary)
{
// TODO
memset(binary, 0xFF, state->rom_size);

const ASMInstruction *inst = state->instructions;
while (inst) {
memcpy(binary + inst->loc.offset, inst->bytes, inst->loc.length);
inst = inst->next;
}

const ASMData *data = state->data;
while (data) {
memcpy(binary + data->loc.offset, data->bytes, data->loc.length);
data = data->next;
}

for (size_t i = 0; i < state->rom_size; i++)
binary[i] = 'X';
write_header(&state->header, binary);
}

/*


+ 1
- 41
src/rom.c Прегледај датотеку

@@ -14,11 +14,9 @@
#include "util.h"

#define NUM_LOCATIONS 3
#define MAGIC_LEN 8
#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";

#ifdef DEBUG_MODE
/*
@@ -44,44 +42,6 @@ static void print_header(const uint8_t *header)
}
#endif

/*
Compute the correct ROM data checksum.

If the summable region (as specified by the range parameter) is too large,
we'll compute the checksum over the default range (0x0000-0x7FF0), or the
largest possible range.
*/
static uint16_t compute_checksum(const uint8_t *data, size_t size, uint8_t range)
{
size_t low_region, high_region;
switch (range & 0xF) {
case 0xA: low_region = 0x1FEF; high_region = 0; break;
case 0xB: low_region = 0x3FEF; high_region = 0; break;
case 0xC: low_region = 0x7FEF; high_region = 0; break;
case 0xD: low_region = 0xBFEF; high_region = 0; break;
case 0xE: low_region = 0x7FEF; high_region = 0x0FFFF; break;
case 0xF: low_region = 0x7FEF; high_region = 0x1FFFF; break;
case 0x0: low_region = 0x7FEF; high_region = 0x3FFFF; break;
case 0x1: low_region = 0x7FEF; high_region = 0x7FFFF; break;
case 0x2: low_region = 0x7FEF; high_region = 0xFFFFF; break;
default: low_region = 0x7FEF; high_region = 0; break;
}

if (low_region >= size)
low_region = (size >= 0x4000) ? 0x3FEF : 0x1FEF;
if (high_region >= size)
high_region = 0;

uint16_t sum = 0;
for (size_t index = 0; index <= low_region; index++)
sum += data[index];
if (high_region) {
for (size_t index = 0x08000; index <= high_region; index++)
sum += data[index];
}
return sum;
}

#ifdef DEBUG_MODE
/*
DEBUG FUNCTION: Given a ROM size, return a pretty string.
@@ -171,7 +131,7 @@ static bool find_and_read_header(ROM *rom)
}
DEBUG(" - trying location 0x%zX:", location)
header = &rom->data[location];
if (memcmp(header, header_magic, MAGIC_LEN)) {
if (memcmp(header, rom_header_magic, HEADER_MAGIC_LEN)) {
DEBUG(" - magic not present")
}
else {


+ 5
- 0
src/rom.h Прегледај датотеку

@@ -9,7 +9,12 @@
#define ROM_SIZE_MIN (32 << 10) // 32 KB
#define ROM_SIZE_MAX ( 1 << 20) // 1 MB

/* Header info */

#define HEADER_SIZE 16
#define HEADER_MAGIC_LEN 8

static const char rom_header_magic[HEADER_MAGIC_LEN + 1] = "TMR SEGA";

/* Error strings */



+ 48
- 1
src/util.c Прегледај датотеку

@@ -20,7 +20,15 @@
#define NS_PER_SEC 1000000000

/*
Convert a BCD-encoded hexadecimal number to decimal.
Convert a decimal integer to BCD-encoded form.
*/
uint8_t bcd_encode(uint8_t num)
{
return ((num / 10) << 4) | (num % 10);
}

/*
Convert a BCD-encoded integer to decimal.
*/
uint8_t bcd_decode(uint8_t num)
{
@@ -141,3 +149,42 @@ uint8_t size_bytes_to_code(size_t bytes)
default: return INVALID_SIZE_CODE;
}
}

/*
Compute a ROM data checksum.

If the summable region (as specified by the range parameter) is too large
(as specified by the size parameter), we'll compute the checksum over the
default range (0x0000-0x7FF0), or the largest possible range. If size is
zero, we will compute it over the given range regardless.
*/
uint16_t compute_checksum(const uint8_t *data, size_t size, uint8_t range)
{
size_t low_region, high_region;
switch (range & 0xF) {
case 0xA: low_region = 0x1FEF; high_region = 0; break;
case 0xB: low_region = 0x3FEF; high_region = 0; break;
case 0xC: low_region = 0x7FEF; high_region = 0; break;
case 0xD: low_region = 0xBFEF; high_region = 0; break;
case 0xE: low_region = 0x7FEF; high_region = 0x0FFFF; break;
case 0xF: low_region = 0x7FEF; high_region = 0x1FFFF; break;
case 0x0: low_region = 0x7FEF; high_region = 0x3FFFF; break;
case 0x1: low_region = 0x7FEF; high_region = 0x7FFFF; break;
case 0x2: low_region = 0x7FEF; high_region = 0xFFFFF; break;
default: low_region = 0x7FEF; high_region = 0; break;
}

if (size && low_region >= size)
low_region = (size >= 0x4000) ? 0x3FEF : 0x1FEF;
if (size && high_region >= size)
high_region = 0;

uint16_t sum = 0;
for (size_t index = 0; index <= low_region; index++)
sum += data[index];
if (high_region) {
for (size_t index = 0x08000; index <= high_region; index++)
sum += data[index];
}
return sum;
}

+ 2
- 0
src/util.h Прегледај датотеку

@@ -9,9 +9,11 @@

/* Functions */

uint8_t bcd_encode(uint8_t);
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);
uint16_t compute_checksum(const uint8_t*, size_t, uint8_t);

Loading…
Откажи
Сачувај