Kaynağa Gözat

Implement serialize_binary() and header writing.

master
Ben Kurtovic 9 yıl önce
ebeveyn
işleme
05c63c3f1c
5 değiştirilmiş dosya ile 109 ekleme ve 46 silme
  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 Dosyayı Görüntüle

@@ -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 Dosyayı Görüntüle

@@ -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 Dosyayı Görüntüle

@@ -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 Dosyayı Görüntüle

@@ -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 Dosyayı Görüntüle

@@ -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);

Yükleniyor…
İptal
Kaydet