@@ -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. | |||
@@ -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*); |
@@ -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... | |||
} |
@@ -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*); |
@@ -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]; | |||
} |
@@ -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*); |
@@ -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)); | |||
} |
@@ -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); |
@@ -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); | |||
} | |||