DSP asm/disasm: Lots of cleanup, mostly. I may have broken the DSP debugger a bit. will fix it properly later..

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@2968 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
hrydgard 2009-04-14 20:44:03 +00:00
parent 0c65e2fe11
commit d25d6b5f98
10 changed files with 1227 additions and 1219 deletions

View File

@ -23,50 +23,34 @@
#include "assemble.h"
#include "disassemble.h"
DSPAssembler::DSPAssembler()
: include_dir(0),
current_param(0),
cur_addr(0),
labels_count(0),
cur_pass(0)
{
include_dir = 0;
current_param = 0;
}
DSPAssembler::~DSPAssembler()
{
}
bool Assemble(const char *text, std::vector<u16> *code)
{
const char *fname = "tmp.asm";
gd_globals_t gdg;
memset(&gdg, 0, sizeof(gdg));
gdg.pc = 0;
// gdg.decode_registers = false;
// gdg.decode_names = false;
gdg.print_tabs = false;
gdg.ext_separator = '\'';
gdg.buffer = 0;
AssemblerSettings settings;
memset(&settings, 0, sizeof(settings));
settings.pc = 0;
// settings.decode_registers = false;
// settings.decode_names = false;
settings.print_tabs = false;
settings.ext_separator = '\'';
settings.buffer = 0;
if (!File::WriteStringToFile(true, text, fname))
return false;
// TODO: fix the terrible api of the assembler.
DSPAssembler assembler;
DSPAssembler assembler(settings);
assembler.gd_ass_init_pass(1);
if (!assembler.gd_ass_file(&gdg, fname, 1))
if (!assembler.gd_ass_file(fname, 1))
return false;
assembler.gd_ass_init_pass(2);
if (!assembler.gd_ass_file(&gdg, fname, 2))
if (!assembler.gd_ass_file(fname, 2))
return false;
code->resize(gdg.buffer_size);
for (int i = 0; i < gdg.buffer_size; i++) {
(*code)[i] = *(u16 *)(gdg.buffer + i * 2);
code->resize(assembler.gdg_buffer_size);
for (int i = 0; i < assembler.gdg_buffer_size; i++) {
(*code)[i] = *(u16 *)(assembler.gdg_buffer + i * 2);
}
return true;
}
@ -86,18 +70,17 @@ bool Disassemble(const std::vector<u16> &code, bool line_numbers, std::string *t
FILE* t = fopen(tmp2, "w");
if (t != NULL)
{
gd_globals_t gdg;
memset(&gdg, 0, sizeof(gdg));
AssemblerSettings settings;
// These two prevent roundtripping.
gdg.show_hex = false;
gdg.show_pc = line_numbers;
gdg.ext_separator = '\'';
gdg.decode_names = false;
gdg.decode_registers = true;
settings.show_hex = false;
settings.show_pc = line_numbers;
settings.ext_separator = '\'';
settings.decode_names = false;
settings.decode_registers = true;
DSPDisassembler disasm;
bool success = disasm.gd_dis_file(&gdg, tmp1, t);
DSPDisassembler disasm(settings);
bool success = disasm.gd_dis_file(tmp1, t);
fclose(t);
File::ReadFileToString(true, tmp2, text);

View File

@ -234,11 +234,11 @@ const DSPOPCTemplate opcodes[] =
{"INCM", 0x7400, 0xfeff, DSPInterpreter::incm, nop, 1 | P_EXT, 1, {{P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
{"INC", 0x7600, 0xfeff, DSPInterpreter::inc, nop, 1 | P_EXT, 1, {{P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
{"INC", 0x7600, 0xfeff, DSPInterpreter::inc, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
{"DECM", 0x7800, 0xfeff, DSPInterpreter::decm, nop, 1 | P_EXT, 1, {{P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
{"DEC", 0x7a00, 0xfeff, DSPInterpreter::dec, nop, 1 | P_EXT, 1, {{P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
{"NEG", 0x7c00, 0xfeff, DSPInterpreter::neg, nop, 1 | P_EXT, 1, {{P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
{"MOVNP", 0x7e00, 0xfeff, DSPInterpreter::movnp, nop, 1 | P_EXT, 1, {{P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
{"DEC", 0x7a00, 0xfeff, DSPInterpreter::dec, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
{"NEG", 0x7c00, 0xfeff, DSPInterpreter::neg, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
{"MOVNP", 0x7e00, 0xfeff, DSPInterpreter::movnp, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
{"TST", 0xb100, 0xf7ff, DSPInterpreter::tst, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
@ -278,19 +278,19 @@ const DSPOPCTemplate opcodes[] =
{"ORC", 0x3E00, 0xfeff, DSPInterpreter::orc, nop, 1 | P_EXT, 1, {{P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, // Hermes doesn't list this
{"MULX", 0xa000, 0xe7ff, DSPInterpreter::mulx, nop, 1 | P_EXT, 2, {{P_REGM18, 1, 0, 11, 0x1000}, {P_REGM19, 1, 0, 10, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
{"MULXMVZ", 0xa200, 0xe6ff, DSPInterpreter::mulxmvz, nop, 1 | P_EXT, 3, {{P_REGM18, 1, 0, 11, 0x1000}, {P_REGM19, 1, 0, 10, 0x0800}, {P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
{"MULXAC", 0xa400, 0xe6ff, DSPInterpreter::mulxac, nop, 1 | P_EXT, 3, {{P_REGM18, 1, 0, 11, 0x1000}, {P_REGM19, 1, 0, 10, 0x0800}, {P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
{"MULXMV", 0xa600, 0xe6ff, DSPInterpreter::mulxmv, nop, 1 | P_EXT, 3, {{P_REGM18, 1, 0, 11, 0x1000}, {P_REGM19, 1, 0, 10, 0x0800}, {P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
{"MULXMVZ", 0xa200, 0xe6ff, DSPInterpreter::mulxmvz, nop, 1 | P_EXT, 3, {{P_REGM18, 1, 0, 11, 0x1000}, {P_REGM19, 1, 0, 10, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
{"MULXAC", 0xa400, 0xe6ff, DSPInterpreter::mulxac, nop, 1 | P_EXT, 3, {{P_REGM18, 1, 0, 11, 0x1000}, {P_REGM19, 1, 0, 10, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
{"MULXMV", 0xa600, 0xe6ff, DSPInterpreter::mulxmv, nop, 1 | P_EXT, 3, {{P_REGM18, 1, 0, 11, 0x1000}, {P_REGM19, 1, 0, 10, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
{"MUL", 0x9000, 0xf7ff, DSPInterpreter::mul, nop, 1 | P_EXT, 2, {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
{"MULMVZ", 0x9200, 0xf6ff, DSPInterpreter::mulmvz, nop, 1 | P_EXT, 3, {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
{"MULAC", 0x9400, 0xf6ff, DSPInterpreter::mulac, nop, 1 | P_EXT, 3, {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
{"MULMV", 0x9600, 0xf6ff, DSPInterpreter::mulmv, nop, 1 | P_EXT, 3, {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
{"MULMVZ", 0x9200, 0xf6ff, DSPInterpreter::mulmvz, nop, 1 | P_EXT, 3, {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
{"MULAC", 0x9400, 0xf6ff, DSPInterpreter::mulac, nop, 1 | P_EXT, 3, {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
{"MULMV", 0x9600, 0xf6ff, DSPInterpreter::mulmv, nop, 1 | P_EXT, 3, {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
{"MULC", 0xc000, 0xe7ff, DSPInterpreter::mulc, nop, 1 | P_EXT, 2, {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
{"MULCMVZ", 0xc200, 0xe6ff, DSPInterpreter::mulcmvz, nop, 1 | P_EXT, 3, {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
{"MULCAC", 0xc400, 0xe6ff, DSPInterpreter::mulcac, nop, 1 | P_EXT, 3, {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
{"MULCMV", 0xc600, 0xe6ff, DSPInterpreter::mulcmv, nop, 1 | P_EXT, 3, {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
{"MULCMVZ", 0xc200, 0xe6ff, DSPInterpreter::mulcmvz, nop, 1 | P_EXT, 3, {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
{"MULCAC", 0xc400, 0xe6ff, DSPInterpreter::mulcac, nop, 1 | P_EXT, 3, {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
{"MULCMV", 0xc600, 0xe6ff, DSPInterpreter::mulcmv, nop, 1 | P_EXT, 3, {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
{"ADDR", 0x4000, 0xf8ff, DSPInterpreter::addr, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_REG18, 1, 0, 9, 0x0600}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
{"ADDAX", 0x4800, 0xfcff, DSPInterpreter::addax, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_REG18, 1, 0, 9, 0x0200}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
@ -315,8 +315,7 @@ const DSPOPCTemplate cw =
const DSPOPCTemplate opcodes_ext[] =
{
{
// FIXME: guessing this is cr need checking
{"CR", 0x0000, 0x00fc, DSPInterpreter::Ext::cr, nop, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, NULL, NULL,},
{"DR", 0x0004, 0x00fc, DSPInterpreter::Ext::dr, nop, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, NULL, NULL,},
@ -410,10 +409,10 @@ const pdlabel_t regnames[] =
{0x01, "AR1", "Addr Reg 01",},
{0x02, "AR2", "Addr Reg 02",},
{0x03, "AR3", "Addr Reg 03",},
{0x04, "IX0", "Index Reg 1(04)",},
{0x05, "IX1", "Index Reg 2(05)",},
{0x06, "IX2", "Index Reg 3(06)",},
{0x07, "IX3", "Indec Reg 4(07)",},
{0x04, "IX0", "Index Reg 0(04)",},
{0x05, "IX1", "Index Reg 1(05)",},
{0x06, "IX2", "Index Reg 2(06)",},
{0x07, "IX3", "Indec Reg 3(07)",},
{0x08, "R08", "Register 08",},
{0x09, "R09", "Register 09",},
{0x0a, "R10", "Register 10",},
@ -422,7 +421,7 @@ const pdlabel_t regnames[] =
{0x0d, "ST1", "Data stack",},
{0x0e, "ST2", "Loop addr stack",},
{0x0f, "ST3", "Loop counter",},
{0x00, "AC0.H", "Accu High 0",},
{0x10, "AC0.H", "Accu High 0",},
{0x11, "AC1.H", "Accu High 1",},
{0x12, "CR", "Config Register",},
{0x13, "SR", "Special Register",},
@ -439,7 +438,7 @@ const pdlabel_t regnames[] =
{0x1e, "AC0.M", "Accu Mid 0",},
{0x1f, "AC1.M", "Accu Mid 1",},
// To resolve special names.
// To resolve combined register names.
{0x20, "ACC0", "Accu Full 0",},
{0x21, "ACC1", "Accu Full 1",},
{0x22, "AX0", "Extra Accu 0",},
@ -451,7 +450,6 @@ dspInstFunc opTable[OPTABLE_SIZE];
dspInstFunc prologueTable[OPTABLE_SIZE];
dspInstFunc epilogueTable[OPTABLE_SIZE];
const char* pdname(u16 val)
{
static char tmpstr[12]; // nasty

View File

@ -24,6 +24,11 @@
// The ones that end with _D are the opposite one - if the bit specify
// ACC0, then ACC_D will be ACC1.
// The values of these are very important.
// For the reg ones, the value >> 8 is the base register.
// & 0x80 means it's a "D".
enum partype_t
{
P_NONE = 0x0000,
@ -37,15 +42,15 @@ enum partype_t
P_REGM18 = P_REG | 0x1810, // used in multiply instructions
P_REG19 = P_REG | 0x1900,
P_REGM19 = P_REG | 0x1910, // used in multiply instructions
P_REG1A = P_REG | 0x1a00,
P_REG1A = P_REG | 0x1a80,
P_REG1C = P_REG | 0x1c00,
// P_ACC = P_REG | 0x1c10, // used for global accum (gcdsptool's value)
P_ACC_D = P_REG | 0x1c80,
P_ACCL = P_REG | 0x1c00, // used for mid accum
P_ACCM = P_REG | 0x1e00, // used for mid accum
P_ACCL = P_REG | 0x1c00, // used for low part of accum
P_ACCM = P_REG | 0x1e00, // used for mid part of accum
// The following are not in gcdsptool
P_ACCM_D = P_REG | 0x1e80,
P_ACC = P_REG | 0x2000, // used for global accum.
P_ACC = P_REG | 0x2000, // used for full accum.
P_AX = P_REG | 0x2200,
P_REGS_MASK = 0x03f80, // gcdsptool's value = 0x01f80
P_REF = P_REG | 0x4000,

File diff suppressed because it is too large Load Diff

View File

@ -31,32 +31,32 @@
#include "Common.h"
#include "disassemble.h"
#include "DSPTables.h"
enum err_t
{
ERR_OK = 0,
ERR_UNKNOWN,
ERR_UNKNOWN_OPCODE,
ERR_NOT_ENOUGH_PARAMETERS,
ERR_TOO_MANY_PARAMETERS,
ERR_WRONG_PARAMETER,
ERR_EXPECTED_PARAM_STR,
ERR_EXPECTED_PARAM_VAL,
ERR_EXPECTED_PARAM_REG,
ERR_EXPECTED_PARAM_MEM,
ERR_EXPECTED_PARAM_IMM,
ERR_INCORRECT_BIN,
ERR_INCORRECT_HEX,
ERR_INCORRECT_DEC,
ERR_LABEL_EXISTS,
ERR_UNKNOWN_LABEL,
ERR_NO_MATCHING_BRACKETS,
ERR_EXT_CANT_EXTEND_OPCODE,
ERR_EXT_PAR_NOT_EXT,
ERR_WRONG_PARAMETER_ACC,
ERR_WRONG_PARAMETER_MID_ACC,
ERR_INVALID_REGISTER,
ERR_OUT_RANGE_NUMBER
enum err_t
{
ERR_OK = 0,
ERR_UNKNOWN,
ERR_UNKNOWN_OPCODE,
ERR_NOT_ENOUGH_PARAMETERS,
ERR_TOO_MANY_PARAMETERS,
ERR_WRONG_PARAMETER,
ERR_EXPECTED_PARAM_STR,
ERR_EXPECTED_PARAM_VAL,
ERR_EXPECTED_PARAM_REG,
ERR_EXPECTED_PARAM_MEM,
ERR_EXPECTED_PARAM_IMM,
ERR_INCORRECT_BIN,
ERR_INCORRECT_HEX,
ERR_INCORRECT_DEC,
ERR_LABEL_EXISTS,
ERR_UNKNOWN_LABEL,
ERR_NO_MATCHING_BRACKETS,
ERR_EXT_CANT_EXTEND_OPCODE,
ERR_EXT_PAR_NOT_EXT,
ERR_WRONG_PARAMETER_ACC,
ERR_WRONG_PARAMETER_MID_ACC,
ERR_INVALID_REGISTER,
ERR_OUT_RANGE_NUMBER
};
// Unless you want labels to carry over between files, you probably
@ -64,72 +64,69 @@ enum err_t
class DSPAssembler
{
public:
DSPAssembler();
DSPAssembler(const AssemblerSettings &settings);
~DSPAssembler();
void Assemble(const char *text, std::vector<u16> *code);
typedef struct fass_t
{
FILE *fsrc;
u32 code_line;
bool failed;
} fass_t;
struct label_t
{
char *label;
s32 addr;
};
struct param_t
{
u32 val;
partype_t type;
char *str;
};
enum segment_t
{
SEGMENT_CODE = 0,
SEGMENT_DATA,
SEGMENT_OVERLAY,
SEGMENT_MAX
struct label_t
{
label_t(const char *lbl, s32 address) : label(lbl), addr(address) {}
std::string label;
s32 addr;
};
void gd_ass_init_pass(int pass);
bool gd_ass_file(gd_globals_t *gdg, const char *fname, int pass);
struct param_t
{
u32 val;
partype_t type;
char *str;
};
enum segment_t
{
SEGMENT_CODE = 0,
SEGMENT_DATA,
SEGMENT_OVERLAY,
SEGMENT_MAX
};
void gd_ass_init_pass(int pass);
bool gd_ass_file(const char *fname, int pass);
char *gdg_buffer;
int gdg_buffer_size;
private:
void parse_error(err_t err_code, fass_t *fa, const char *extra_info = NULL);
void gd_ass_register_label(const char *label, u16 lval);
void gd_ass_clear_labels();
s32 strtoval(const char *str);
char *find_brackets(char *src, char *dst);
u32 parse_exp(const char *ptr);
u32 parse_exp_f(const char *ptr, fass_t *fa);
u32 get_params(char *parstr, param_t *par, fass_t *fa);
const opc_t *find_opcode(const char *opcode, u32 par_count, const opc_t * const opcod, u32 opcod_size, fass_t *fa);
bool verify_params(const opc_t *opc, param_t *par, u32 count, fass_t *fa);
void build_code(const opc_t *opc, param_t *par, u32 par_count, u16 *outbuf);
void parse_error(err_t err_code, const char *extra_info = NULL);
void gd_ass_register_label(const char *label, u16 lval);
void gd_ass_clear_labels();
s32 strtoval(const char *str);
char *find_brackets(char *src, char *dst);
u32 parse_exp(const char *ptr);
u32 parse_exp_f(const char *ptr);
u32 get_params(char *parstr, param_t *par);
const opc_t *find_opcode(const char *opcode, u32 par_count, const opc_t * const opcod, int opcod_size);
bool verify_params(const opc_t *opc, param_t *par, int count, bool ext = false);
void build_code(const opc_t *opc, param_t *par, u32 par_count, u16 *outbuf);
char *include_dir;
label_t labels[10000];
int labels_count;
char cur_line[4096];
u32 cur_addr;
u8 cur_pass;
fass_t *cur_fa;
typedef std::map<std::string, std::string> AliasMap;
AliasMap aliases;
segment_t cur_segment;
u32 segment_addr[SEGMENT_MAX];
int current_param;
std::string include_dir;
std::vector<label_t> labels;
std::string cur_line;
u32 cur_addr;
u8 cur_pass;
FILE *fsrc;
u32 code_line;
bool failed;
typedef std::map<std::string, std::string> AliasMap;
AliasMap aliases;
segment_t cur_segment;
u32 segment_addr[SEGMENT_MAX];
int current_param;
const AssemblerSettings settings_;
};
#endif // _DSP_ASSEMBLE_H

View File

@ -34,25 +34,23 @@
#pragma warning(disable:4996)
#endif
u32 unk_opcodes[0x10000];
extern void nop(const UDSPInstruction& opc);
DSPDisassembler::DSPDisassembler()
DSPDisassembler::DSPDisassembler(const AssemblerSettings &settings)
: settings_(settings)
{
memset(unk_opcodes, 0, sizeof(unk_opcodes));
}
char* DSPDisassembler::gd_dis_params(gd_globals_t* gdg, const DSPOPCTemplate* opc,
u16 op1, u16 op2, char* strbuf)
char *DSPDisassembler::gd_dis_params(const DSPOPCTemplate* opc, u16 op1, u16 op2, char *strbuf)
{
char* buf = strbuf;
u32 val;
char *buf = strbuf;
for (int j = 0; j < opc->param_count; j++)
{
if (j > 0)
buf += sprintf(buf, ", ");
u32 val;
if (opc->params[j].loc >= 1)
val = op2;
else
@ -83,21 +81,21 @@ char* DSPDisassembler::gd_dis_params(gd_globals_t* gdg, const DSPOPCTemplate* op
switch (type)
{
case P_REG:
if (gdg->decode_registers)
if (settings_.decode_registers)
sprintf(buf, "$%s", pdregname(val));
else
sprintf(buf, "$%d", val);
break;
case P_PRG:
if (gdg->decode_registers)
if (settings_.decode_registers)
sprintf(buf, "@$%s", pdregname(val));
else
sprintf(buf, "@$%d", val);
break;
case P_VAL:
if (gdg->decode_names)
if (settings_.decode_names)
sprintf(buf, "%s", pdname(val));
else
sprintf(buf, "0x%04x", val);
@ -119,7 +117,7 @@ char* DSPDisassembler::gd_dis_params(gd_globals_t* gdg, const DSPOPCTemplate* op
if (opc->params[j].size != 2)
val = (u16)(s8)val;
if (gdg->decode_names)
if (settings_.decode_names)
sprintf(buf, "@%s", pdname(val));
else
sprintf(buf, "@0x%04x", val);
@ -127,7 +125,6 @@ char* DSPDisassembler::gd_dis_params(gd_globals_t* gdg, const DSPOPCTemplate* op
default:
ERROR_LOG(DSPLLE, "Unknown parameter type: %x", opc->params[j].type);
// exit(-1);
break;
}
@ -137,6 +134,7 @@ char* DSPDisassembler::gd_dis_params(gd_globals_t* gdg, const DSPOPCTemplate* op
return strbuf;
}
#if 0
u16 gd_dis_get_opcode_size(gd_globals_t* gdg)
{
const DSPOPCTemplate* opc = 0;
@ -168,7 +166,6 @@ u16 gd_dis_get_opcode_size(gd_globals_t* gdg)
if (!opc)
{
ERROR_LOG(DSPLLE, "get_opcode_size ARGH");
exit(0);
}
if (opc->size & P_EXT && op1 & 0x00ff)
@ -197,28 +194,27 @@ u16 gd_dis_get_opcode_size(gd_globals_t* gdg)
return opc->size & ~P_EXT;
}
#endif
char* DSPDisassembler::gd_dis_opcode(gd_globals_t* gdg)
void DSPDisassembler::gd_dis_opcode(const u16 *binbuf, u16 *pc, std::string *dest)
{
u32 op2;
char *buf = gdg->buffer;
u16 pc = gdg->pc;
char buffer[256];
char *buf = buffer;
// Start with a space.
buf[0] = ' ';
buf[1] = '\0';
buf++;
if ((pc & 0x7fff) >= 0x1000)
if ((*pc & 0x7fff) >= 0x1000)
{
gdg->pc++;
return gdg->buffer;
*pc++;
return;
}
pc &= 0x0fff;
u32 op1 = gdg->binbuf[pc];
*pc &= 0x0fff;
const u32 op1 = binbuf[*pc];
const DSPOPCTemplate *opc = NULL;
const DSPOPCTemplate *opc_ext = NULL;
@ -239,7 +235,6 @@ char* DSPDisassembler::gd_dis_opcode(gd_globals_t* gdg)
}
}
const DSPOPCTemplate fake_op = {"CW", 0x0000, 0x0000, nop, nop, 1, 1, {{P_VAL, 2, 0, 0, 0xffff}}, NULL, NULL,};
if (!opc)
opc = &fake_op;
@ -266,23 +261,22 @@ char* DSPDisassembler::gd_dis_opcode(gd_globals_t* gdg)
// printing
if (gdg->show_pc)
sprintf(buf, "%04x ", gdg->pc);
if (settings_.show_pc)
sprintf(buf, "%04x ", *pc);
buf += strlen(buf);
if ((opc->size & ~P_EXT) == 2)
{
op2 = gdg->binbuf[pc + 1];
if (gdg->show_hex)
op2 = binbuf[*pc + 1];
if (settings_.show_hex)
sprintf(buf, "%04x %04x ", op1, op2);
}
else
{
op2 = 0;
if (gdg->show_hex)
if (settings_.show_hex)
sprintf(buf, "%04x ", op1);
}
@ -291,11 +285,11 @@ char* DSPDisassembler::gd_dis_opcode(gd_globals_t* gdg)
char tmpbuf[20];
if (extended)
sprintf(tmpbuf, "%s%c%s", opc->name, gdg->ext_separator, opc_ext->name);
sprintf(tmpbuf, "%s%c%s", opc->name, settings_.ext_separator, opc_ext->name);
else
sprintf(tmpbuf, "%s", opc->name);
if (gdg->print_tabs)
if (settings_.print_tabs)
sprintf(buf, "%s\t", tmpbuf);
else
sprintf(buf, "%-12s", tmpbuf);
@ -303,7 +297,7 @@ char* DSPDisassembler::gd_dis_opcode(gd_globals_t* gdg)
buf += strlen(buf);
if (opc->param_count > 0)
gd_dis_params(gdg, opc, op1, op2, buf);
gd_dis_params(opc, op1, op2, buf);
buf += strlen(buf);
@ -318,7 +312,7 @@ char* DSPDisassembler::gd_dis_opcode(gd_globals_t* gdg)
buf += strlen(buf);
if (opc_ext->param_count > 0)
gd_dis_params(gdg, opc_ext, op1, op2, buf);
gd_dis_params(opc_ext, op1, op2, buf);
buf += strlen(buf);
}
@ -331,14 +325,14 @@ char* DSPDisassembler::gd_dis_opcode(gd_globals_t* gdg)
}
if (extended)
gdg->pc += opc_ext->size;
*pc += opc_ext->size;
else
gdg->pc += opc->size & ~P_EXT;
*pc += opc->size & ~P_EXT;
return gdg->buffer;
dest->append(buffer);
}
bool DSPDisassembler::gd_dis_file(gd_globals_t* gdg, const char* name, FILE* output)
bool DSPDisassembler::gd_dis_file(const char* name, FILE* output)
{
gd_dis_open_unkop();
@ -354,23 +348,20 @@ bool DSPDisassembler::gd_dis_file(gd_globals_t* gdg, const char* name, FILE* out
fseek(in, 0, SEEK_END);
size = (int)ftell(in);
fseek(in, 0, SEEK_SET);
gdg->binbuf = (u16*)malloc(size);
fread(gdg->binbuf, 1, size, in);
gdg->buffer = (char*)malloc(256);
gdg->buffer_size = 256;
u16 *binbuf = (u16*)malloc(size);
fread(binbuf, 1, size, in);
for (gdg->pc = 0; gdg->pc < (size / 2);)
fprintf(output, "%s\n", gd_dis_opcode(gdg));
for (u16 pc = 0; pc < (size / 2);)
{
std::string str;
gd_dis_opcode(binbuf, &pc, &str);
fprintf(output, "%s\n", str.c_str());
}
fclose(in);
free(gdg->binbuf);
gdg->binbuf = NULL;
free(gdg->buffer);
gdg->buffer = NULL;
gdg->buffer_size = 0;
free(binbuf);
gd_dis_close_unkop();

View File

@ -28,40 +28,55 @@
#include "Common.h"
#include "DSPTables.h"
struct gd_globals_t
struct AssemblerSettings
{
AssemblerSettings()
: print_tabs(false),
show_hex(false),
show_pc(false),
decode_names(true),
decode_registers(true),
ext_separator('\'')
{
}
bool print_tabs;
bool show_hex;
bool show_pc;
bool decode_names;
bool decode_registers;
bool lower_case_ops;
char ext_separator;
u16* binbuf;
u16 *binbuf;
u16 pc;
char* buffer;
u16 buffer_size;
char ext_separator;
};
class DSPDisassembler
{
public:
DSPDisassembler();
DSPDisassembler(const AssemblerSettings &settings);
~DSPDisassembler() {}
char* gd_dis_opcode(gd_globals_t* gdg);
bool gd_dis_file(gd_globals_t* gdg, const char* name, FILE* output);
// Moves PC forward and writes the result to dest.
void gd_dis_opcode(const u16 *binbuf, u16 *pc, std::string *dest);
bool gd_dis_file(const char* name, FILE *output);
void gd_dis_close_unkop();
void gd_dis_open_unkop();
const char* gd_dis_get_reg_name(u16 reg);
private:
char* gd_dis_params(gd_globals_t* gdg, const DSPOPCTemplate* opc, u16 op1, u16 op2, char* strbuf);
char* gd_dis_params(const DSPOPCTemplate* opc, u16 op1, u16 op2, char* strbuf);
u32 unk_opcodes[0x10000];
const AssemblerSettings settings_;
};
const char *gd_get_reg_name(u16 reg);
u16 gd_dis_get_opcode_size(gd_globals_t* gdg);
//u16 gd_dis_get_opcode_size(gd_globals_t* gdg);
#endif // _DSP_DISASSEMBLE_H

View File

@ -88,7 +88,6 @@ void RunAsmTests()
#define CHK(a) if (!SuperTrip(a)) printf("FAIL\n%s\n", a), fail = true;
// Let's start out easy - a trivial instruction..
#if 0
CHK(" NOP\n");
// Now let's do several.
@ -114,25 +113,29 @@ void RunAsmTests()
" si @0xfffd, #0xbeef\n"
" si @DIRQ, #0x0001\n");
// Let's try some messy extended instructions.
//CHK(" MULMV'SN $AX0.L, $AX0.H, $ACC0 : @$AR2, $AC1.M\n");
//" ADDAXL'MV $ACC1, $AX1.L : $AX1.H, $AC1.M\n");
// Let's get brutal. We generate random code bytes and make sure that they can
// be roundtripped. We don't expect it to always succeed but it'll be sure to generate
// interesting test cases.
/*
puts("Insane Random Code Test\n");
std::vector<u16> rand_code;
GenRandomCode(21, &rand_code);
GenRandomCode(31, &rand_code);
std::string rand_code_text;
Disassemble(rand_code, &rand_code_text);
Disassemble(rand_code, true, &rand_code_text);
printf("%s", rand_code_text.c_str());
RoundTrip(rand_code);
#endif
*/
std::string dsp_test;
//File::ReadStringFromFile(true, "C:/devkitPro/examples/wii/asndlib/dsptest/dsp_test.ds", &dsp_test);
File::ReadFileToString(true, "C:/devkitPro/trunk/libogc/libasnd/dsp_mixer/dsp_mixer.s", &dsp_test);
if (File::ReadFileToString(true, "C:/devkitPro/examples/wii/asndlib/dsptest/dsp_test.ds", &dsp_test))
SuperTrip(dsp_test.c_str());
//.File::ReadFileToString(true, "C:/devkitPro/trunk/libogc/libasnd/dsp_mixer/dsp_mixer.s", &dsp_test);
// This is CLOSE to working. Sorry about the local path btw. This is preliminary code.
SuperTrip(dsp_test.c_str());
if (!fail)
printf("All passed!\n");

View File

@ -190,26 +190,27 @@ void DSPDebuggerLLE::RebuildDisAsmListView()
m_Disasm->DeleteAllItems();
char Buffer[256];
gd_globals_t gdg;
AssemblerSettings settings;
const u16 *binbuf;
if (g_dsp.pc & 0x8000)
gdg.binbuf = g_dsp.irom;
binbuf = g_dsp.irom;
else
gdg.binbuf = g_dsp.iram;
binbuf = g_dsp.iram;
gdg.buffer = Buffer;
gdg.buffer_size = 256;
gdg.ext_separator = (char)0xff;
settings.buffer = Buffer;
settings.buffer_size = 256;
settings.ext_separator = (char)0xff;
gdg.show_pc = false;
gdg.show_hex = false;
gdg.print_tabs = true;
gdg.decode_names = true;
gdg.decode_registers = true;
settings.show_pc = false;
settings.show_hex = false;
settings.print_tabs = true;
settings.decode_names = true;
settings.decode_registers = true;
for (gdg.pc = 0; gdg.pc < DSP_IROM_SIZE;)
for (settings.pc = 0; settings.pc < DSP_IROM_SIZE;)
{
u16 CurrentPC = gdg.pc;
u16 CurrentPC = settings.pc;
if (g_dsp.pc & 0x8000)
CurrentPC |= 0x8000;
@ -220,13 +221,16 @@ void DSPDebuggerLLE::RebuildDisAsmListView()
char Temp2[256];
sprintf(Temp2, "0x%04x", dsp_imem_read(CurrentPC));
DSPDisassembler disasm;
char* pOpcode = disasm.gd_dis_opcode(&gdg);
AssemblerSettings settings;
DSPDisassembler disasm(settings);
std::string op_str;
disasm.gd_dis_opcode(binbuf,&settings.pc, &op_str);
const char* pParameter = NULL;
const char* pExtension = NULL;
size_t WholeString = strlen(pOpcode);
size_t WholeString = op_str.size();
/*
for (size_t i = 0; i < WholeString; i++)
{
if (pOpcode[i] == (char)0xff)
@ -240,7 +244,7 @@ void DSPDebuggerLLE::RebuildDisAsmListView()
pOpcode[i] = 0x00;
pParameter = &pOpcode[i + 1];
}
}
}*/
const char* pFunctionName = NULL;
@ -249,15 +253,15 @@ void DSPDebuggerLLE::RebuildDisAsmListView()
pFunctionName = m_SymbolMap[CurrentPC].Name.c_str();
}
int Item = m_Disasm->InsertItem(gdg.pc, wxEmptyString);
int Item = m_Disasm->InsertItem(settings.pc, wxEmptyString);
m_Disasm->SetItem(Item, COLUMN_BP, wxEmptyString);
m_Disasm->SetItem(Item, COLUMN_FUNCTION, wxString::FromAscii(pFunctionName));
m_Disasm->SetItem(Item, COLUMN_ADDRESS, wxString::FromAscii(Temp));
m_Disasm->SetItem(Item, COLUMN_MNEMONIC, wxString::FromAscii(Temp2));
m_Disasm->SetItem(Item, COLUMN_OPCODE, wxString::FromAscii(pOpcode));
m_Disasm->SetItem(Item, COLUMN_OPCODE, wxString::FromAscii(op_str.c_str()));
m_Disasm->SetItem(Item, COLUMN_EXT, wxString::FromAscii(pExtension));
if (!strcasecmp(pOpcode, "CALL"))
if (!strcasecmp(op_str.c_str(), "CALL"))
{
u32 FunctionAddress = -1;
sscanf(pParameter, "0x%04x", &FunctionAddress);

View File

@ -60,15 +60,15 @@ bool DisasmUCodeDump(u32 crc)
FILE* t = fopen(txtFile, "wb");
if (t != NULL)
{
gd_globals_t gdg;
memset(&gdg, 0, sizeof(gdg));
gdg.show_hex = true;
gdg.show_pc = true;
gdg.ext_separator = '\t';
gdg.decode_names = true;
gdg.decode_registers = true;
DSPDisassembler disasm;
disasm.gd_dis_file(&gdg, binFile, t);
AssemblerSettings settings;
memset(&settings, 0, sizeof(settings));
settings.show_hex = true;
settings.show_pc = true;
settings.ext_separator = '\t';
settings.decode_names = true;
settings.decode_registers = true;
DSPDisassembler disasm(settings);
disasm.gd_dis_file(binFile, t);
fclose(t);
return true;
}