DSP: I seem to have forgotten assemble.h? Killed the globals in assemble.cpp by putting the entire thing in a class, which will make more improvements easier. Same with disasm. More tweaking of the shift ops.

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@2958 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
hrydgard 2009-04-12 14:48:55 +00:00
parent d4055b971b
commit 6369b48538
11 changed files with 233 additions and 125 deletions

View File

@ -23,6 +23,22 @@
#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)
{
@ -40,11 +56,12 @@ bool Assemble(const char *text, std::vector<u16> *code)
return false;
// TODO: fix the terrible api of the assembler.
gd_ass_init_pass(1);
if (!gd_ass_file(&gdg, fname, 1))
DSPAssembler assembler;
assembler.gd_ass_init_pass(1);
if (!assembler.gd_ass_file(&gdg, fname, 1))
return false;
gd_ass_init_pass(2);
if (!gd_ass_file(&gdg, fname, 2))
assembler.gd_ass_init_pass(2);
if (!assembler.gd_ass_file(&gdg, fname, 2))
return false;
code->resize(gdg.buffer_size);
@ -54,7 +71,7 @@ bool Assemble(const char *text, std::vector<u16> *code)
return true;
}
bool Disassemble(const std::vector<u16> &code, std::string *text)
bool Disassemble(const std::vector<u16> &code, bool line_numbers, std::string *text)
{
if (code.empty())
return false;
@ -74,11 +91,13 @@ bool Disassemble(const std::vector<u16> &code, std::string *text)
// These two prevent roundtripping.
gdg.show_hex = false;
gdg.show_pc = false;
gdg.show_pc = line_numbers;
gdg.ext_separator = '\'';
gdg.decode_names = false;
gdg.decode_registers = true;
bool success = gd_dis_file(&gdg, tmp1, t);
DSPDisassembler disasm;
bool success = disasm.gd_dis_file(&gdg, tmp1, t);
fclose(t);
File::ReadFileToString(true, tmp2, text);
@ -87,7 +106,7 @@ bool Disassemble(const std::vector<u16> &code, std::string *text)
return false;
}
void Compare(const std::vector<u16> &code1, const std::vector<u16> &code2)
bool Compare(const std::vector<u16> &code1, const std::vector<u16> &code2)
{
if (code1.size() != code2.size())
printf("Size difference! 1=%i 2=%i\n", (int)code1.size(), (int)code2.size());
@ -98,15 +117,16 @@ void Compare(const std::vector<u16> &code1, const std::vector<u16> &code2)
if (code1[i] == code2[i])
count_equal++;
else
printf("!! %04x : %04x vs %04x\n", i, code1[i], code2[i]);
printf("!! %i : %04x vs %04x\n", i, code1[i], code2[i]);
}
printf("Equal instruction words: %i / %i\n", count_equal, min_size);
return code1.size() == code2.size() && code1.size() == count_equal;
}
void GenRandomCode(int size, std::vector<u16> *code)
{
code->resize(size);
for (int i = 0; i < size; i++)
for (int i = 0; i < size; i++)
{
(*code)[i] = rand() ^ (rand() << 8);
}

View File

@ -24,8 +24,8 @@
#include "Common.h"
bool Assemble(const char *text, std::vector<u16> *code);
bool Disassemble(const std::vector<u16> &code, std::string *text);
void Compare(const std::vector<u16> &code1, const std::vector<u16> &code2);
bool Disassemble(const std::vector<u16> &code, bool line_numbers, std::string *text);
bool Compare(const std::vector<u16> &code1, const std::vector<u16> &code2);
void GenRandomCode(int size, std::vector<u16> *code);
void CodeToHeader(std::vector<u16> *code, const char *name, std::string *header);

View File

@ -154,10 +154,11 @@ const DSPOPCTemplate opcodes[] =
{"SBCLR", 0x1200, 0xfff8, DSPInterpreter::sbclr, nop, 1, 1, {{P_IMM, 1, 0, 0, 0x0007}}, NULL, NULL},
{"SBSET", 0x1300, 0xfff8, DSPInterpreter::sbset, nop, 1, 1, {{P_IMM, 1, 0, 0, 0x0007}}, NULL, NULL},
{"LSL", 0x1400, 0xfec0, DSPInterpreter::lsl, nop, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x007f}}, NULL, NULL}, // 0x007f?
{"LSR", 0x1440, 0xfec0, DSPInterpreter::lsr, nop, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x007f}}, NULL, NULL}, // 0x007f?
{"ASL", 0x1480, 0xfec0, DSPInterpreter::asl, nop, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x007f}}, NULL, NULL},
{"ASR", 0x14c0, 0xfec0, DSPInterpreter::asr, nop, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x007f}}, NULL, NULL},
// actually, given the masks these should probably be 0x3f. need investigation.
{"LSL", 0x1400, 0xfec0, DSPInterpreter::lsl, nop, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x003f}}, NULL, NULL},
{"LSR", 0x1440, 0xfec0, DSPInterpreter::lsr, nop, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x003f}}, NULL, NULL},
{"ASL", 0x1480, 0xfec0, DSPInterpreter::asl, nop, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x003f}}, NULL, NULL},
{"ASR", 0x14c0, 0xfec0, DSPInterpreter::asr, nop, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x003f}}, NULL, NULL},
{"LRI", 0x0080, 0xffe0, DSPInterpreter::lri, nop, 2, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_IMM, 2, 1, 0, 0xffff}}, NULL, NULL},
{"LR", 0x00c0, 0xffe0, DSPInterpreter::lr, nop, 2, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_MEM, 2, 1, 0, 0xffff}}, NULL, NULL},

View File

@ -47,83 +47,9 @@ Initial import
#include "DSPInterpreter.h"
#include "DSPTables.h"
#include "disassemble.h"
//#include "gdsp_tool.h"
#include "assemble.h"
char *include_dir = NULL;
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
};
typedef struct fass_t
{
FILE *fsrc;
u32 code_line;
bool failed;
} fass_t;
label_t labels[10000];
int labels_count = 0;
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 = 0;
typedef 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
};
char *err_string[] =
static const char *err_string[] =
{
"",
"Unknown Error",
@ -150,7 +76,7 @@ char *err_string[] =
"Number out of range"
};
void parse_error(err_t err_code, fass_t *fa, const char *extra_info = NULL)
void DSPAssembler::parse_error(err_t err_code, fass_t *fa, const char *extra_info)
{
fprintf(stderr, "%i : %s\n", fa->code_line, cur_line);
fa->failed = true;
@ -186,7 +112,7 @@ const char *skip_spaces(const char *ptr)
return ptr;
}
void gd_ass_register_label(const char *label, u16 lval)
void DSPAssembler::gd_ass_register_label(const char *label, u16 lval)
{
labels[labels_count].label = (char *)malloc(strlen(label) + 1);
strcpy(labels[labels_count].label, label);
@ -194,7 +120,7 @@ void gd_ass_register_label(const char *label, u16 lval)
labels_count++;
}
void gd_ass_clear_labels()
void DSPAssembler::gd_ass_clear_labels()
{
for (int i = 0; i < labels_count; i++)
{
@ -204,7 +130,7 @@ void gd_ass_clear_labels()
}
// Parse a standalone value - it can be a number in one of several formats or a label.
s32 strtoval(const char *str)
s32 DSPAssembler::strtoval(const char *str)
{
bool negative = false;
s32 val = 0;
@ -302,7 +228,7 @@ s32 strtoval(const char *str)
// Modifies both src and dst!
// What does it do, really??
char *find_brackets(char *src, char *dst)
char *DSPAssembler::find_brackets(char *src, char *dst)
{
s32 len = (s32) strlen(src);
s32 first = -1;
@ -349,7 +275,7 @@ char *find_brackets(char *src, char *dst)
}
// Bizarre in-place expression evaluator.
u32 parse_exp(const char *ptr)
u32 DSPAssembler::parse_exp(const char *ptr)
{
char *pbuf;
s32 val = 0;
@ -447,14 +373,14 @@ u32 parse_exp(const char *ptr)
return val;
}
u32 parse_exp_f(const char *ptr, fass_t *fa)
u32 DSPAssembler::parse_exp_f(const char *ptr, fass_t *fa)
{
cur_fa = fa;
return parse_exp(ptr);
}
// Destroys parstr
u32 get_params(char *parstr, param_t *par, fass_t *fa)
u32 DSPAssembler::get_params(char *parstr, param_t *par, fass_t *fa)
{
u32 count = 0;
char *tmpstr = skip_spaces(parstr);
@ -508,7 +434,7 @@ u32 get_params(char *parstr, param_t *par, fass_t *fa)
return count;
}
const opc_t *find_opcode(const char *opcode, u32 par_count, const opc_t * const opcod, u32 opcod_size, fass_t *fa)
const opc_t *DSPAssembler::find_opcode(const char *opcode, u32 par_count, const opc_t * const opcod, u32 opcod_size, DSPAssembler::fass_t *fa)
{
if (opcode[0] == 'C' && opcode[1] == 'W')
return &cw;
@ -544,7 +470,7 @@ u16 get_mask_shifted_down(u16 mask)
return mask;
}
bool verify_params(const opc_t *opc, param_t *par, u32 count, fass_t *fa)
bool DSPAssembler::verify_params(const opc_t *opc, param_t *par, u32 count, fass_t *fa)
{
int value;
unsigned int valueu;
@ -724,7 +650,7 @@ bool verify_params(const opc_t *opc, param_t *par, u32 count, fass_t *fa)
// Merge opcode with params.
void build_code(const opc_t *opc, param_t *par, u32 par_count, u16 *outbuf)
void DSPAssembler::build_code(const opc_t *opc, param_t *par, u32 par_count, u16 *outbuf)
{
outbuf[cur_addr] |= opc->opcode;
for (u32 i = 0; i < par_count; i++)
@ -744,7 +670,7 @@ void build_code(const opc_t *opc, param_t *par, u32 par_count, u16 *outbuf)
}
}
void gd_ass_init_pass(int pass)
void DSPAssembler::gd_ass_init_pass(int pass)
{
if (pass == 1)
{
@ -770,7 +696,7 @@ void gd_ass_init_pass(int pass)
segment_addr[SEGMENT_OVERLAY] = 0;
}
bool gd_ass_file(gd_globals_t *gdg, const char *fname, int pass)
bool DSPAssembler::gd_ass_file(gd_globals_t *gdg, const char *fname, int pass)
{
fass_t fa;
int disable_text = 0; // modified by Hermes

View File

@ -0,0 +1,135 @@
/*====================================================================
project: GameCube DSP Tool (gcdsp)
created: 2005.03.04
mail: duddie@walla.com
Copyright (c) 2005 Duddie
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
====================================================================*/
#ifndef _DSP_ASSEMBLE_H
#define _DSP_ASSEMBLE_H
#include <string>
#include <map>
#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
};
// Unless you want labels to carry over between files, you probably
// want to create a new DSPAssembler for every file you assemble.
class DSPAssembler
{
public:
DSPAssembler();
~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
};
void gd_ass_init_pass(int pass);
bool gd_ass_file(gd_globals_t *gdg, const char *fname, int pass);
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);
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;
};
#endif // _DSP_ASSEMBLE_H

View File

@ -38,7 +38,12 @@ u32 unk_opcodes[0x10000];
extern void nop(const UDSPInstruction& opc);
char* gd_dis_params(gd_globals_t* gdg, const DSPOPCTemplate* opc, u16 op1, u16 op2, char* strbuf)
DSPDisassembler::DSPDisassembler()
{
}
char* DSPDisassembler::gd_dis_params(gd_globals_t* gdg, const DSPOPCTemplate* opc,
u16 op1, u16 op2, char* strbuf)
{
char* buf = strbuf;
u32 val;
@ -101,8 +106,8 @@ char* gd_dis_params(gd_globals_t* gdg, const DSPOPCTemplate* opc, u16 op1, u16 o
case P_IMM:
if (opc->params[j].size != 2)
{
if (opc->params[j].mask == 0x007f) // LSL, LSR, ASL, ASR
sprintf(buf, "#%d", (val & 0x40) ? (val | 0xFFFFFFC0) : val);
if (opc->params[j].mask == 0x003f) // LSL, LSR, ASL, ASR
sprintf(buf, "#%d", (val & 0x20) ? (val | 0xFFFFFFC0) : val);
else
sprintf(buf, "#0x%02x", val);
}
@ -194,7 +199,7 @@ u16 gd_dis_get_opcode_size(gd_globals_t* gdg)
}
char* gd_dis_opcode(gd_globals_t* gdg)
char* DSPDisassembler::gd_dis_opcode(gd_globals_t* gdg)
{
u32 op2;
char *buf = gdg->buffer;
@ -333,7 +338,7 @@ char* gd_dis_opcode(gd_globals_t* gdg)
return gdg->buffer;
}
bool gd_dis_file(gd_globals_t* gdg, const char* name, FILE* output)
bool DSPDisassembler::gd_dis_file(gd_globals_t* gdg, const char* name, FILE* output)
{
gd_dis_open_unkop();
@ -372,7 +377,7 @@ bool gd_dis_file(gd_globals_t* gdg, const char* name, FILE* output)
return true;
}
void gd_dis_close_unkop()
void DSPDisassembler::gd_dis_close_unkop()
{
FILE* uo;
int i, j;
@ -418,7 +423,7 @@ void gd_dis_close_unkop()
}
}
void gd_dis_open_unkop()
void DSPDisassembler::gd_dis_open_unkop()
{
FILE* uo;
char filename[MAX_PATH];
@ -439,7 +444,7 @@ void gd_dis_open_unkop()
}
}
const char *gd_dis_get_reg_name(u16 reg)
const char *gd_get_reg_name(u16 reg)
{
return regnames[reg].name;
}

View File

@ -26,6 +26,7 @@
#define _DSP_DISASSEMBLE_H
#include "Common.h"
#include "DSPTables.h"
struct gd_globals_t
{
@ -42,12 +43,25 @@ struct gd_globals_t
char ext_separator;
};
class DSPDisassembler
{
public:
DSPDisassembler();
~DSPDisassembler() {}
char* gd_dis_opcode(gd_globals_t* gdg);
bool gd_dis_file(gd_globals_t* gdg, const char* name, FILE* output);
char* gd_dis_opcode(gd_globals_t* gdg);
bool gd_dis_file(gd_globals_t* gdg, const char* name, FILE* output);
void gd_dis_close_unkop();
void gd_dis_open_unkop();
const char* gd_dis_get_reg_name(u16 reg);
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);
};
const char *gd_get_reg_name(u16 reg);
u16 gd_dis_get_opcode_size(gd_globals_t* gdg);
#endif // _DSP_DISASSEMBLE_H

View File

@ -31,7 +31,7 @@ bool RoundTrip(const std::vector<u16> &code1)
{
std::vector<u16> code2;
std::string text;
if (!Disassemble(code1, &text))
if (!Disassemble(code1, false, &text))
{
printf("RoundTrip: Disassembly failed.\n");
return false;
@ -57,7 +57,7 @@ bool SuperTrip(const char *asm_code)
return false;
}
printf("First assembly: %i words\n", (int)code1.size());
if (!Disassemble(code1, &text))
if (!Disassemble(code1, false, &text))
{
printf("SuperTrip: Disassembly failed\n");
return false;
@ -72,7 +72,13 @@ bool SuperTrip(const char *asm_code)
printf("SuperTrip: Second assembly failed\n");
return false;
}
Compare(code1, code2);
/*
std::string text2;
Disassemble(code1, true, &text1);
Disassemble(code2, true, &text2);
File::WriteStringToFile(true, text1, "code1.txt");
File::WriteStringToFile(true, text2, "code2.txt");
*/
return true;
}

View File

@ -25,7 +25,7 @@ wxString CRegTable::GetValue(int row, int col)
{
switch (col)
{
case 0: return wxString::FromAscii(gd_dis_get_reg_name(row));
case 0: return wxString::FromAscii(gd_get_reg_name(row));
case 1: return wxString::Format(wxT("0x%04x"), g_dsp.r[row]);
default: return wxString::FromAscii("");
}

View File

@ -220,7 +220,8 @@ void DSPDebuggerLLE::RebuildDisAsmListView()
char Temp2[256];
sprintf(Temp2, "0x%04x", dsp_imem_read(CurrentPC));
char* pOpcode = gd_dis_opcode(&gdg);
DSPDisassembler disasm;
char* pOpcode = disasm.gd_dis_opcode(&gdg);
const char* pParameter = NULL;
const char* pExtension = NULL;
@ -241,7 +242,6 @@ void DSPDebuggerLLE::RebuildDisAsmListView()
}
}
const char* pFunctionName = NULL;
if (m_SymbolMap.find(CurrentPC) != m_SymbolMap.end())

View File

@ -67,7 +67,8 @@ bool DisasmUCodeDump(u32 crc)
gdg.ext_separator = '\t';
gdg.decode_names = true;
gdg.decode_registers = true;
gd_dis_file(&gdg, binFile, t);
DSPDisassembler disasm;
disasm.gd_dis_file(&gdg, binFile, t);
fclose(t);
return true;
}