Browse Source

Begin work on disassembler; extend tracing.

master
Ben Kurtovic 8 years ago
parent
commit
235e4c7cff
9 changed files with 298 additions and 6 deletions
  1. +76
    -1
      src/disassembler.c
  2. +14
    -2
      src/disassembler.h
  3. +49
    -0
      src/disassembler/mnemonics.c
  4. +10
    -0
      src/disassembler/mnemonics.h
  5. +118
    -0
      src/disassembler/sizes.c
  6. +11
    -0
      src/disassembler/sizes.h
  7. +12
    -0
      src/mmu.c
  8. +1
    -0
      src/mmu.h
  9. +7
    -3
      src/z80.c

+ 76
- 1
src/disassembler.c View File

@@ -1,7 +1,82 @@
/* Copyright (C) 2014-2015 Ben Kurtovic <ben.kurtovic@gmail.com>
/* Copyright (C) 2014-2016 Ben Kurtovic <ben.kurtovic@gmail.com>
Released under the terms of the MIT License. See LICENSE for details. */

#include "disassembler.h"
#include "disassembler/mnemonics.h"
#include "disassembler/sizes.h"
#include "util.h"

/*
Format a sequence of bytes of a certain length as a pretty string.

The result must be freed by the caller.
*/
static char* format_bytestring(const uint8_t *bytes, size_t size)
{
if (!size)
return NULL;

char *str = cr_malloc(sizeof(char) * (3 * size));
size_t i;

for (i = 0; i < size; i++) {
snprintf(&str[3 * i], 3, "%02X", bytes[i]);
str[3 * i + 2] = ' ';
}
str[3 * size - 1] = '\0';
return str;
}

/*
Extract the arguments for the given instruction.

The return value must be free()d.
*/
static char* decode_argument(const uint8_t *bytes)
{
// TODO
(void) bytes;
return NULL;
}

/*
Free the given DisasInstr struct.
*/
void disas_instr_free(DisasInstr *instr)
{
free(instr->bytestr);
free(instr->line);
free(instr);
}

/*
Disassemble a single instruction starting at the given address.

Return a dynamically allocated structure containing various interesting
fields. This must be freed by the user with disas_instr_free().
*/
DisasInstr* disassemble_instruction(const uint8_t *bytes)
{
size_t size = get_instr_size(bytes);
char *bytestr = format_bytestring(bytes, size);
char *mnemonic = decode_mnemonic(bytes);
char *arg = decode_argument(bytes);
char *line;

if (arg) {
line = cr_malloc(strlen(mnemonic) + strlen(arg) + 2);
sprintf(line, "%s\t%s", mnemonic, arg);
free(arg);
} else {
line = cr_strdup(mnemonic);
}

DisasInstr *instr = cr_malloc(sizeof(DisasInstr));
instr->size = size;
instr->bytestr = bytestr;
instr->line = line;
return instr;
}

/*
Disassemble the binary file at the input path into z80 source code.


+ 14
- 2
src/disassembler.h View File

@@ -1,14 +1,26 @@
/* Copyright (C) 2014-2015 Ben Kurtovic <ben.kurtovic@gmail.com>
/* Copyright (C) 2014-2016 Ben Kurtovic <ben.kurtovic@gmail.com>
Released under the terms of the MIT License. See LICENSE for details. */

#pragma once

#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>

/* Structs */

// ...
typedef struct {
size_t size;
char *bytestr;
char *line;
} DisasInstr;

// typedef struct { ... } Disassembly;

/* Functions */

void disas_instr_free(DisasInstr*);

DisasInstr* disassemble_instruction(const uint8_t*);
// Disassembly* disassemble(const uint8_t*); // TODO
bool disassemble_file(const char*, const char*);

+ 49
- 0
src/disassembler/mnemonics.c View File

@@ -0,0 +1,49 @@
/* Copyright (C) 2014-2016 Ben Kurtovic <ben.kurtovic@gmail.com>
Released under the terms of the MIT License. See LICENSE for details. */

#include "mnemonics.h"

static char* instr_mnemonics[256] = {
/* 00 */ "nop", "ld", "ld", "inc", "inc", "dec", "ld", "rlca",
/* 08 */ "ex", "add", "ld", "dec", "inc", "dec", "ld", "rrca",
/* 10 */ "????", "????", "????", "????", "????", "????", "????", "????",
/* 18 */ "????", "????", "????", "????", "????", "????", "????", "????",
/* 20 */ "????", "????", "????", "????", "????", "????", "????", "????",
/* 28 */ "????", "????", "????", "????", "????", "????", "????", "????",
/* 30 */ "????", "????", "????", "????", "????", "????", "????", "????",
/* 38 */ "????", "????", "????", "????", "????", "????", "????", "????",
/* 40 */ "????", "????", "????", "????", "????", "????", "????", "????",
/* 48 */ "????", "????", "????", "????", "????", "????", "????", "????",
/* 50 */ "????", "????", "????", "????", "????", "????", "????", "????",
/* 58 */ "????", "????", "????", "????", "????", "????", "????", "????",
/* 60 */ "????", "????", "????", "????", "????", "????", "????", "????",
/* 68 */ "????", "????", "????", "????", "????", "????", "????", "????",
/* 70 */ "????", "????", "????", "????", "????", "????", "????", "????",
/* 78 */ "????", "????", "????", "????", "????", "????", "????", "????",
/* 80 */ "????", "????", "????", "????", "????", "????", "????", "????",
/* 88 */ "????", "????", "????", "????", "????", "????", "????", "????",
/* 90 */ "????", "????", "????", "????", "????", "????", "????", "????",
/* 98 */ "????", "????", "????", "????", "????", "????", "????", "????",
/* A0 */ "????", "????", "????", "????", "????", "????", "????", "????",
/* A8 */ "????", "????", "????", "????", "????", "????", "????", "????",
/* B0 */ "????", "????", "????", "????", "????", "????", "????", "????",
/* B8 */ "????", "????", "????", "????", "????", "????", "????", "????",
/* C0 */ "????", "????", "????", "????", "????", "????", "????", "????",
/* C8 */ "????", "????", "????", "????", "????", "????", "????", "????",
/* D0 */ "????", "????", "????", "????", "????", "????", "????", "????",
/* D8 */ "????", "????", "????", "????", "????", "????", "????", "????",
/* E0 */ "????", "????", "????", "????", "????", "????", "????", "????",
/* E8 */ "????", "????", "????", "????", "????", "????", "????", "????",
/* F0 */ "????", "????", "????", "????", "????", "????", "????", "????",
/* F8 */ "????", "????", "????", "????", "????", "????", "????", "????"
};

/*
Extract the assembly mnemonic for the given opcode.

The return value is a string literal and should not be freed.
*/
char* decode_mnemonic(const uint8_t *bytes)
{
return instr_mnemonics[bytes[0]]; // TODO: extended...
}

+ 10
- 0
src/disassembler/mnemonics.h View File

@@ -0,0 +1,10 @@
/* Copyright (C) 2014-2016 Ben Kurtovic <ben.kurtovic@gmail.com>
Released under the terms of the MIT License. See LICENSE for details. */

#pragma once

#include <stdint.h>

/* Functions */

char* decode_mnemonic(const uint8_t*);

+ 118
- 0
src/disassembler/sizes.c View File

@@ -0,0 +1,118 @@
/* Copyright (C) 2014-2016 Ben Kurtovic <ben.kurtovic@gmail.com>
Released under the terms of the MIT License. See LICENSE for details. */

#include "sizes.h"

static size_t instr_sizes[256] = {
1, 3, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1,
2, 3, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 2, 1,
2, 3, 3, 1, 1, 1, 2, 1, 2, 1, 3, 1, 1, 1, 2, 1,
2, 3, 3, 1, 1, 1, 2, 1, 2, 1, 3, 1, 1, 1, 2, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 3, 3, 3, 1, 2, 1, 1, 1, 3, 0, 3, 3, 2, 1,
1, 1, 3, 2, 3, 1, 2, 1, 1, 1, 3, 2, 3, 0, 2, 1,
1, 1, 3, 1, 3, 1, 2, 1, 1, 1, 3, 1, 3, 0, 2, 1,
1, 1, 3, 1, 3, 1, 2, 1, 1, 1, 3, 1, 3, 0, 2, 1
};

static size_t instr_sizes_extended[256] = {
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2,
2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2,
2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2,
2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2
};

static size_t instr_sizes_bits[256] = {
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2
};

static size_t instr_sizes_index[256] = {
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 4, 4, 2, 2, 2, 3, 2, 2, 2, 4, 2, 2, 2, 3, 2,
2, 2, 2, 2, 3, 3, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2,
2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2,
2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2,
3, 3, 3, 3, 3, 3, 2, 3, 2, 2, 2, 2, 2, 2, 3, 2,
2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2,
2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2,
2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2,
2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2
};

static size_t instr_sizes_index_bits[256] = {
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4
};

/*
Return the byte length of the instruction starting at the given address.
*/
size_t get_instr_size(const uint8_t *bytes)
{
uint8_t b = bytes[0];

if (b == 0xED)
return instr_sizes_extended[bytes[1]];
if (b == 0xCB)
return instr_sizes_bits[bytes[1]];
if (b == 0xDD || b == 0xFD) {
if (bytes[1] == 0xCB)
return instr_sizes_index_bits[bytes[2]];
return instr_sizes_index[bytes[1]];
}
return instr_sizes[b];
}

+ 11
- 0
src/disassembler/sizes.h View File

@@ -0,0 +1,11 @@
/* Copyright (C) 2014-2016 Ben Kurtovic <ben.kurtovic@gmail.com>
Released under the terms of the MIT License. See LICENSE for details. */

#pragma once

#include <stddef.h>
#include <stdint.h>

/* Functions */

size_t get_instr_size(const uint8_t*);

+ 12
- 0
src/mmu.c View File

@@ -161,3 +161,15 @@ bool mmu_write_byte(MMU *mmu, uint16_t addr, uint8_t value)
return true;
}
}

/*
Read four bytes of memory from the given address.
*/
uint32_t mmu_read_quad(MMU *mmu, uint16_t addr)
{
return (
mmu_read_byte(mmu, addr) +
(mmu_read_byte(mmu, addr + 1) << 8) +
(mmu_read_byte(mmu, addr + 2) << 16) +
(mmu_read_byte(mmu, addr + 3) << 24));
}

+ 1
- 0
src/mmu.h View File

@@ -28,3 +28,4 @@ void mmu_load_rom(MMU*, const uint8_t*, size_t);
void mmu_power(MMU*);
uint8_t mmu_read_byte(MMU*, uint16_t);
bool mmu_write_byte(MMU*, uint16_t, uint8_t);
uint32_t mmu_read_quad(MMU*, uint16_t);

+ 7
- 3
src/z80.c View File

@@ -169,8 +169,12 @@ static inline void increment_refresh_counter(Z80 *z80)
*/
static inline void trace_instruction(const Z80 *z80)
{
TRACE("PC @ 0x%04X", z80->regfile.pc)
// TODO
uint32_t quad = mmu_read_quad(z80->mmu, z80->regfile.pc);
uint8_t bytes[4] = {quad, quad >> 8, quad >> 16, quad >> 24};
DisasInstr *instr = disassemble_instruction(bytes);

TRACE("0x%04X: %11s %s", z80->regfile.pc, instr->bytestr, instr->line)
disas_instr_free(instr);
}

/*
@@ -185,9 +189,9 @@ bool z80_do_cycles(Z80 *z80, double cycles)
cycles -= z80->pending_cycles;
while (cycles > 0 && !z80->except) {
uint8_t opcode = mmu_read_byte(z80->mmu, z80->regfile.pc);
increment_refresh_counter(z80);
if (TRACE_LEVEL)
trace_instruction(z80);
increment_refresh_counter(z80);
cycles -= (*instruction_lookup_table[opcode])(z80, opcode);
}



Loading…
Cancel
Save