DSP: Give the assembler and disassembler saner public APIs. Fix bug in fileutil ReadFileToString. More cleanup.
git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@2970 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
parent
f9903f2054
commit
d973a9e001
|
@ -626,7 +626,7 @@ bool ReadFileToString(bool text_file, const char *filename, std::string *str)
|
||||||
fseek(f, 0, SEEK_SET);
|
fseek(f, 0, SEEK_SET);
|
||||||
char *buf = new char[len + 1];
|
char *buf = new char[len + 1];
|
||||||
buf[fread(buf, 1, len, f)] = 0;
|
buf[fread(buf, 1, len, f)] = 0;
|
||||||
*str = std::string(buf);
|
*str = std::string(buf, len);
|
||||||
fclose(f);
|
fclose(f);
|
||||||
delete [] buf;
|
delete [] buf;
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -26,7 +26,6 @@
|
||||||
|
|
||||||
bool Assemble(const char *text, std::vector<u16> *code)
|
bool Assemble(const char *text, std::vector<u16> *code)
|
||||||
{
|
{
|
||||||
const char *fname = "tmp.asm";
|
|
||||||
AssemblerSettings settings;
|
AssemblerSettings settings;
|
||||||
settings.pc = 0;
|
settings.pc = 0;
|
||||||
// settings.decode_registers = false;
|
// settings.decode_registers = false;
|
||||||
|
@ -34,22 +33,11 @@ bool Assemble(const char *text, std::vector<u16> *code)
|
||||||
settings.print_tabs = false;
|
settings.print_tabs = false;
|
||||||
settings.ext_separator = '\'';
|
settings.ext_separator = '\'';
|
||||||
|
|
||||||
if (!File::WriteStringToFile(true, text, fname))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// TODO: fix the terrible api of the assembler.
|
// TODO: fix the terrible api of the assembler.
|
||||||
DSPAssembler assembler(settings);
|
DSPAssembler assembler(settings);
|
||||||
assembler.gd_ass_init_pass(1);
|
if (!assembler.Assemble(text, code))
|
||||||
if (!assembler.gd_ass_file(fname, 1))
|
printf("%s", assembler.GetErrorString().c_str());
|
||||||
return false;
|
|
||||||
assembler.gd_ass_init_pass(2);
|
|
||||||
if (!assembler.gd_ass_file(fname, 2))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,34 +45,19 @@ bool Disassemble(const std::vector<u16> &code, bool line_numbers, std::string *t
|
||||||
{
|
{
|
||||||
if (code.empty())
|
if (code.empty())
|
||||||
return false;
|
return false;
|
||||||
const char *tmp1 = "tmp1.bin";
|
|
||||||
const char *tmp2 = "tmp.txt";
|
|
||||||
|
|
||||||
// First we have to dump the code to a bin file.
|
AssemblerSettings settings;
|
||||||
FILE *f = fopen(tmp1, "wb");
|
|
||||||
fwrite(&code[0], 1, code.size() * 2, f);
|
|
||||||
fclose(f);
|
|
||||||
|
|
||||||
FILE* t = fopen(tmp2, "w");
|
// These two prevent roundtripping.
|
||||||
if (t != NULL)
|
settings.show_hex = false;
|
||||||
{
|
settings.show_pc = line_numbers;
|
||||||
AssemblerSettings settings;
|
settings.ext_separator = '\'';
|
||||||
|
settings.decode_names = false;
|
||||||
|
settings.decode_registers = true;
|
||||||
|
|
||||||
// These two prevent roundtripping.
|
DSPDisassembler disasm(settings);
|
||||||
settings.show_hex = false;
|
bool success = disasm.Disassemble(0, code, text);
|
||||||
settings.show_pc = line_numbers;
|
return success;
|
||||||
settings.ext_separator = '\'';
|
|
||||||
settings.decode_names = false;
|
|
||||||
settings.decode_registers = true;
|
|
||||||
|
|
||||||
DSPDisassembler disasm(settings);
|
|
||||||
bool success = disasm.gd_dis_file(tmp1, t);
|
|
||||||
fclose(t);
|
|
||||||
|
|
||||||
File::ReadFileToString(true, tmp2, text);
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Compare(const std::vector<u16> &code1, const std::vector<u16> &code2)
|
bool Compare(const std::vector<u16> &code1, const std::vector<u16> &code2)
|
||||||
|
@ -92,7 +65,7 @@ bool Compare(const std::vector<u16> &code1, const std::vector<u16> &code2)
|
||||||
if (code1.size() != code2.size())
|
if (code1.size() != code2.size())
|
||||||
printf("Size difference! 1=%i 2=%i\n", (int)code1.size(), (int)code2.size());
|
printf("Size difference! 1=%i 2=%i\n", (int)code1.size(), (int)code2.size());
|
||||||
int count_equal = 0;
|
int count_equal = 0;
|
||||||
const int min_size = std::min(code1.size(), code2.size());
|
const int min_size = (int)std::min(code1.size(), code2.size());
|
||||||
for (int i = 0; i < min_size; i++)
|
for (int i = 0; i < min_size; i++)
|
||||||
{
|
{
|
||||||
if (code1[i] == code2[i])
|
if (code1[i] == code2[i])
|
||||||
|
@ -150,7 +123,7 @@ void BinaryStringBEToCode(const std::string &str, std::vector<u16> *code)
|
||||||
code->resize(str.size() / 2);
|
code->resize(str.size() / 2);
|
||||||
for (int i = 0; i < code->size(); i++)
|
for (int i = 0; i < code->size(); i++)
|
||||||
{
|
{
|
||||||
(*code)[i] = (str[i * 2 + 0] << 8) | (str[i * 2 + 1]);
|
(*code)[i] = ((u16)(u8)str[i * 2 + 0] << 8) | ((u16)(u8)str[i * 2 + 1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,6 +132,7 @@ bool LoadBinary(const char *filename, std::vector<u16> *code)
|
||||||
std::string buffer;
|
std::string buffer;
|
||||||
if (!File::ReadFileToString(false, filename, &buffer))
|
if (!File::ReadFileToString(false, filename, &buffer))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
BinaryStringBEToCode(buffer, code);
|
BinaryStringBEToCode(buffer, code);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -352,8 +352,8 @@ const DSPOPCTemplate opcodes_ext[] =
|
||||||
{"XXX", 0x0000, 0x0000, nop, nop, 1, 1, {{P_VAL, 1, 0, 0, 0x00ff}}, NULL, NULL,},
|
{"XXX", 0x0000, 0x0000, nop, nop, 1, 1, {{P_VAL, 1, 0, 0, 0x00ff}}, NULL, NULL,},
|
||||||
};
|
};
|
||||||
|
|
||||||
const u32 opcodes_size = sizeof(opcodes) / sizeof(DSPOPCTemplate);
|
const int opcodes_size = sizeof(opcodes) / sizeof(DSPOPCTemplate);
|
||||||
const u32 opcodes_ext_size = sizeof(opcodes_ext) / sizeof(DSPOPCTemplate);
|
const int opcodes_ext_size = sizeof(opcodes_ext) / sizeof(DSPOPCTemplate);
|
||||||
|
|
||||||
const pdlabel_t pdlabels[] =
|
const pdlabel_t pdlabels[] =
|
||||||
{
|
{
|
||||||
|
|
|
@ -120,9 +120,9 @@ typedef DSPOPCTemplate opc_t;
|
||||||
|
|
||||||
// Opcodes
|
// Opcodes
|
||||||
extern const DSPOPCTemplate opcodes[];
|
extern const DSPOPCTemplate opcodes[];
|
||||||
extern const u32 opcodes_size;
|
extern const int opcodes_size;
|
||||||
extern const DSPOPCTemplate opcodes_ext[];
|
extern const DSPOPCTemplate opcodes_ext[];
|
||||||
extern const u32 opcodes_ext_size;
|
extern const int opcodes_ext_size;
|
||||||
extern u8 opSize[OPTABLE_SIZE];
|
extern u8 opSize[OPTABLE_SIZE];
|
||||||
extern const DSPOPCTemplate cw;
|
extern const DSPOPCTemplate cw;
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,7 @@ Initial import
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
|
#include "FileUtil.h"
|
||||||
#include "DSPInterpreter.h"
|
#include "DSPInterpreter.h"
|
||||||
#include "DSPTables.h"
|
#include "DSPTables.h"
|
||||||
#include "disassemble.h"
|
#include "disassemble.h"
|
||||||
|
@ -80,38 +81,60 @@ DSPAssembler::DSPAssembler(const AssemblerSettings &settings)
|
||||||
: current_param(0),
|
: current_param(0),
|
||||||
cur_addr(0),
|
cur_addr(0),
|
||||||
cur_pass(0),
|
cur_pass(0),
|
||||||
settings_(settings)
|
settings_(settings)
|
||||||
{
|
{
|
||||||
gdg_buffer = NULL;
|
gdg_buffer = NULL;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DSPAssembler::~DSPAssembler()
|
DSPAssembler::~DSPAssembler()
|
||||||
{
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DSPAssembler::Assemble(const char *text, std::vector<u16> *code, std::vector<int> *line_numbers)
|
||||||
|
{
|
||||||
|
if (line_numbers)
|
||||||
|
line_numbers->clear();
|
||||||
|
const char *fname = "tmp.asm";
|
||||||
|
if (!File::WriteStringToFile(true, text, fname))
|
||||||
|
return false;
|
||||||
|
InitPass(1);
|
||||||
|
if (!AssembleFile(fname, 1))
|
||||||
|
return false;
|
||||||
|
InitPass(2);
|
||||||
|
if (!AssembleFile(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);
|
||||||
|
}
|
||||||
|
|
||||||
|
last_error_str = "(no errors)";
|
||||||
|
last_error = ERR_OK;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DSPAssembler::parse_error(err_t err_code, const char *extra_info)
|
void DSPAssembler::parse_error(err_t err_code, const char *extra_info)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "%i : %s\n", code_line, cur_line);
|
|
||||||
failed = true;
|
failed = true;
|
||||||
|
char error_buffer[1024];
|
||||||
|
char *buf_ptr = error_buffer;
|
||||||
|
buf_ptr += sprintf(buf_ptr, "%i : %s\n", code_line, cur_line);
|
||||||
if (!extra_info)
|
if (!extra_info)
|
||||||
extra_info = "-";
|
extra_info = "-";
|
||||||
if (fsrc)
|
if (fsrc)
|
||||||
fclose(fsrc);
|
fclose(fsrc);
|
||||||
else
|
else
|
||||||
{
|
buf_ptr += sprintf(buf_ptr, "ERROR: %s : %s\n", err_string[err_code], extra_info);
|
||||||
fprintf(stderr, "ERROR: %s : %s\n", err_string[err_code], extra_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
// modified by Hermes
|
|
||||||
|
|
||||||
if (current_param == 0)
|
if (current_param == 0)
|
||||||
fprintf(stderr, "ERROR: %s Line: %d : %s\n", err_string[err_code], code_line, extra_info);
|
buf_ptr += sprintf(buf_ptr, "ERROR: %s Line: %d : %s\n", err_string[err_code], code_line, extra_info);
|
||||||
else
|
else
|
||||||
fprintf(stderr, "ERROR: %s Line: %d Param: %d : %s\n",
|
buf_ptr += sprintf(buf_ptr, "ERROR: %s Line: %d Param: %d : %s\n",
|
||||||
err_string[err_code], code_line, current_param, extra_info);
|
err_string[err_code], code_line, current_param, extra_info);
|
||||||
|
last_error_str = error_buffer;
|
||||||
|
last_error = err_code;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *skip_spaces(char *ptr)
|
char *skip_spaces(char *ptr)
|
||||||
|
@ -692,7 +715,7 @@ void DSPAssembler::build_code(const opc_t *opc, param_t *par, u32 par_count, u16
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DSPAssembler::gd_ass_init_pass(int pass)
|
void DSPAssembler::InitPass(int pass)
|
||||||
{
|
{
|
||||||
failed = false;
|
failed = false;
|
||||||
if (pass == 1)
|
if (pass == 1)
|
||||||
|
@ -719,7 +742,7 @@ void DSPAssembler::gd_ass_init_pass(int pass)
|
||||||
segment_addr[SEGMENT_OVERLAY] = 0;
|
segment_addr[SEGMENT_OVERLAY] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DSPAssembler::gd_ass_file(const char *fname, int pass)
|
bool DSPAssembler::AssembleFile(const char *fname, int pass)
|
||||||
{
|
{
|
||||||
int disable_text = 0; // modified by Hermes
|
int disable_text = 0; // modified by Hermes
|
||||||
|
|
||||||
|
@ -892,7 +915,7 @@ bool DSPAssembler::gd_ass_file(const char *fname, int pass)
|
||||||
tmpstr = (char *)malloc(strlen(params[0].str) + 1);
|
tmpstr = (char *)malloc(strlen(params[0].str) + 1);
|
||||||
strcpy(tmpstr, params[0].str);
|
strcpy(tmpstr, params[0].str);
|
||||||
}
|
}
|
||||||
gd_ass_file(tmpstr, pass);
|
AssembleFile(tmpstr, pass);
|
||||||
free(tmpstr);
|
free(tmpstr);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -67,8 +67,16 @@ public:
|
||||||
DSPAssembler(const AssemblerSettings &settings);
|
DSPAssembler(const AssemblerSettings &settings);
|
||||||
~DSPAssembler();
|
~DSPAssembler();
|
||||||
|
|
||||||
void Assemble(const char *text, std::vector<u16> *code);
|
// line_numbers is optional (and not yet implemented). It'll receieve a list of ints,
|
||||||
|
// one for each word of code, indicating the source assembler code line number it came from.
|
||||||
|
|
||||||
|
// If returns false, call GetErrorString to get some text to present to the user.
|
||||||
|
bool Assemble(const char *text, std::vector<u16> *code, std::vector<int> *line_numbers = NULL);
|
||||||
|
|
||||||
|
std::string GetErrorString() const { return last_error_str; }
|
||||||
|
err_t GetError() const { return last_error; }
|
||||||
|
|
||||||
|
private:
|
||||||
struct label_t
|
struct label_t
|
||||||
{
|
{
|
||||||
label_t(const char *lbl, s32 address) : label(lbl), addr(address) {}
|
label_t(const char *lbl, s32 address) : label(lbl), addr(address) {}
|
||||||
|
@ -90,13 +98,13 @@ public:
|
||||||
SEGMENT_OVERLAY,
|
SEGMENT_OVERLAY,
|
||||||
SEGMENT_MAX
|
SEGMENT_MAX
|
||||||
};
|
};
|
||||||
void gd_ass_init_pass(int pass);
|
|
||||||
bool gd_ass_file(const char *fname, int pass);
|
void InitPass(int pass);
|
||||||
|
bool AssembleFile(const char *fname, int pass);
|
||||||
|
|
||||||
char *gdg_buffer;
|
char *gdg_buffer;
|
||||||
int gdg_buffer_size;
|
int gdg_buffer_size;
|
||||||
|
|
||||||
private:
|
|
||||||
void parse_error(err_t err_code, const char *extra_info = NULL);
|
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_register_label(const char *label, u16 lval);
|
||||||
void gd_ass_clear_labels();
|
void gd_ass_clear_labels();
|
||||||
|
@ -119,6 +127,8 @@ private:
|
||||||
FILE *fsrc;
|
FILE *fsrc;
|
||||||
u32 code_line;
|
u32 code_line;
|
||||||
bool failed;
|
bool failed;
|
||||||
|
std::string last_error_str;
|
||||||
|
err_t last_error;
|
||||||
|
|
||||||
typedef std::map<std::string, std::string> AliasMap;
|
typedef std::map<std::string, std::string> AliasMap;
|
||||||
AliasMap aliases;
|
AliasMap aliases;
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "FileUtil.h"
|
||||||
#include "disassemble.h"
|
#include "disassemble.h"
|
||||||
#include "DSPTables.h"
|
#include "DSPTables.h"
|
||||||
|
|
||||||
|
@ -39,31 +40,81 @@ extern void nop(const UDSPInstruction& opc);
|
||||||
DSPDisassembler::DSPDisassembler(const AssemblerSettings &settings)
|
DSPDisassembler::DSPDisassembler(const AssemblerSettings &settings)
|
||||||
: settings_(settings)
|
: settings_(settings)
|
||||||
{
|
{
|
||||||
memset(unk_opcodes, 0, sizeof(unk_opcodes));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char *DSPDisassembler::gd_dis_params(const DSPOPCTemplate* opc, u16 op1, u16 op2, char *strbuf)
|
DSPDisassembler::~DSPDisassembler()
|
||||||
|
{
|
||||||
|
// Some old code for logging unknown ops.
|
||||||
|
char filename[MAX_PATH];
|
||||||
|
sprintf(filename, "%sUnkOps.txt", FULL_DSP_DUMP_DIR);
|
||||||
|
FILE *uo = fopen(filename, "w");
|
||||||
|
if (!uo)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
for (std::map<u16, int>::const_iterator iter = unk_opcodes.begin();
|
||||||
|
iter != unk_opcodes.end(); ++iter)
|
||||||
|
{
|
||||||
|
if (iter->second > 0)
|
||||||
|
{
|
||||||
|
count++;
|
||||||
|
fprintf(uo, "OP%04x\t%d", iter->first, iter->second);
|
||||||
|
for (int j = 15; j >= 0; j--) // print op bits
|
||||||
|
{
|
||||||
|
if ((j & 0x3) == 3)
|
||||||
|
fprintf(uo, "\tb");
|
||||||
|
fprintf(uo, "%d", (iter->first >> j) & 0x1);
|
||||||
|
}
|
||||||
|
fprintf(uo, "\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fprintf(uo, "Unknown opcodes count: %d\n", count);
|
||||||
|
fclose(uo);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DSPDisassembler::Disassemble(int start_pc, const std::vector<u16> &code, std::string *text)
|
||||||
|
{
|
||||||
|
const char *tmp1 = "tmp1.bin";
|
||||||
|
const char *tmp2 = "tmp.txt";
|
||||||
|
|
||||||
|
// First we have to dump the code to a bin file.
|
||||||
|
FILE *f = fopen(tmp1, "wb");
|
||||||
|
fwrite(&code[0], 1, code.size() * 2, f);
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
FILE* t = fopen(tmp2, "w");
|
||||||
|
if (!t)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bool success = DisFile(tmp1, t);
|
||||||
|
fclose(t);
|
||||||
|
|
||||||
|
File::ReadFileToString(true, tmp2, text);
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *DSPDisassembler::DisParams(const DSPOPCTemplate& opc, u16 op1, u16 op2, char *strbuf)
|
||||||
{
|
{
|
||||||
char *buf = strbuf;
|
char *buf = strbuf;
|
||||||
for (int j = 0; j < opc->param_count; j++)
|
for (int j = 0; j < opc.param_count; j++)
|
||||||
{
|
{
|
||||||
if (j > 0)
|
if (j > 0)
|
||||||
buf += sprintf(buf, ", ");
|
buf += sprintf(buf, ", ");
|
||||||
|
|
||||||
u32 val;
|
u32 val;
|
||||||
if (opc->params[j].loc >= 1)
|
if (opc.params[j].loc >= 1)
|
||||||
val = op2;
|
val = op2;
|
||||||
else
|
else
|
||||||
val = op1;
|
val = op1;
|
||||||
|
|
||||||
val &= opc->params[j].mask;
|
val &= opc.params[j].mask;
|
||||||
|
|
||||||
if (opc->params[j].lshift < 0)
|
if (opc.params[j].lshift < 0)
|
||||||
val = val << (-opc->params[j].lshift);
|
val = val << (-opc.params[j].lshift);
|
||||||
else
|
else
|
||||||
val = val >> opc->params[j].lshift;
|
val = val >> opc.params[j].lshift;
|
||||||
|
|
||||||
u32 type = opc->params[j].type;
|
u32 type = opc.params[j].type;
|
||||||
|
|
||||||
if ((type & 0xff) == 0x10)
|
if ((type & 0xff) == 0x10)
|
||||||
type &= 0xff00;
|
type &= 0xff00;
|
||||||
|
@ -102,9 +153,9 @@ char *DSPDisassembler::gd_dis_params(const DSPOPCTemplate* opc, u16 op1, u16 op2
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case P_IMM:
|
case P_IMM:
|
||||||
if (opc->params[j].size != 2)
|
if (opc.params[j].size != 2)
|
||||||
{
|
{
|
||||||
if (opc->params[j].mask == 0x003f) // LSL, LSR, ASL, ASR
|
if (opc.params[j].mask == 0x003f) // LSL, LSR, ASL, ASR
|
||||||
sprintf(buf, "#%d", (val & 0x20) ? (val | 0xFFFFFFC0) : val);
|
sprintf(buf, "#%d", (val & 0x20) ? (val | 0xFFFFFFC0) : val);
|
||||||
else
|
else
|
||||||
sprintf(buf, "#0x%02x", val);
|
sprintf(buf, "#0x%02x", val);
|
||||||
|
@ -114,7 +165,7 @@ char *DSPDisassembler::gd_dis_params(const DSPOPCTemplate* opc, u16 op1, u16 op2
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case P_MEM:
|
case P_MEM:
|
||||||
if (opc->params[j].size != 2)
|
if (opc.params[j].size != 2)
|
||||||
val = (u16)(s8)val;
|
val = (u16)(s8)val;
|
||||||
|
|
||||||
if (settings_.decode_names)
|
if (settings_.decode_names)
|
||||||
|
@ -124,7 +175,7 @@ char *DSPDisassembler::gd_dis_params(const DSPOPCTemplate* opc, u16 op1, u16 op2
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
ERROR_LOG(DSPLLE, "Unknown parameter type: %x", opc->params[j].type);
|
ERROR_LOG(DSPLLE, "Unknown parameter type: %x", opc.params[j].type);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,70 +185,7 @@ char *DSPDisassembler::gd_dis_params(const DSPOPCTemplate* opc, u16 op1, u16 op2
|
||||||
return strbuf;
|
return strbuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
void DSPDisassembler::DisOpcode(const u16 *binbuf, u16 *pc, std::string *dest)
|
||||||
u16 gd_dis_get_opcode_size(gd_globals_t* gdg)
|
|
||||||
{
|
|
||||||
const DSPOPCTemplate* opc = 0;
|
|
||||||
const DSPOPCTemplate* opc_ext = 0;
|
|
||||||
bool extended;
|
|
||||||
|
|
||||||
// Undefined memory.
|
|
||||||
if ((gdg->pc & 0x7fff) >= 0x1000)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
u32 op1 = gdg->binbuf[gdg->pc & 0x0fff];
|
|
||||||
|
|
||||||
for (u32 j = 0; j < opcodes_size; j++)
|
|
||||||
{
|
|
||||||
u16 mask;
|
|
||||||
|
|
||||||
if (opcodes[j].size & P_EXT)
|
|
||||||
mask = opcodes[j].opcode_mask & 0xff00;
|
|
||||||
else
|
|
||||||
mask = opcodes[j].opcode_mask;
|
|
||||||
|
|
||||||
if ((op1 & mask) == opcodes[j].opcode)
|
|
||||||
{
|
|
||||||
opc = &opcodes[j];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!opc)
|
|
||||||
{
|
|
||||||
ERROR_LOG(DSPLLE, "get_opcode_size ARGH");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opc->size & P_EXT && op1 & 0x00ff)
|
|
||||||
extended = true;
|
|
||||||
else
|
|
||||||
extended = false;
|
|
||||||
|
|
||||||
if (extended)
|
|
||||||
{
|
|
||||||
// opcode has an extension
|
|
||||||
// find opcode
|
|
||||||
for (u32 j = 0; j < opcodes_ext_size; j++)
|
|
||||||
{
|
|
||||||
if ((op1 & opcodes_ext[j].opcode_mask) == opcodes_ext[j].opcode)
|
|
||||||
{
|
|
||||||
opc_ext = &opcodes_ext[j];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!opc_ext)
|
|
||||||
{
|
|
||||||
ERROR_LOG(DSPLLE, "get_opcode_size ext ARGH");
|
|
||||||
}
|
|
||||||
return opc_ext->size;
|
|
||||||
}
|
|
||||||
|
|
||||||
return opc->size & ~P_EXT;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
void DSPDisassembler::gd_dis_opcode(const u16 *binbuf, u16 *pc, std::string *dest)
|
|
||||||
{
|
{
|
||||||
u32 op2;
|
u32 op2;
|
||||||
char buffer[256];
|
char buffer[256];
|
||||||
|
@ -297,22 +285,19 @@ void DSPDisassembler::gd_dis_opcode(const u16 *binbuf, u16 *pc, std::string *des
|
||||||
buf += strlen(buf);
|
buf += strlen(buf);
|
||||||
|
|
||||||
if (opc->param_count > 0)
|
if (opc->param_count > 0)
|
||||||
gd_dis_params(opc, op1, op2, buf);
|
DisParams(*opc, op1, op2, buf);
|
||||||
|
|
||||||
buf += strlen(buf);
|
buf += strlen(buf);
|
||||||
|
|
||||||
if (extended)
|
if (extended)
|
||||||
{
|
{
|
||||||
if (opc->param_count > 0)
|
if (opc->param_count > 0)
|
||||||
sprintf(buf, " ");
|
buf += sprintf(buf, " ");
|
||||||
|
|
||||||
buf += strlen(buf);
|
buf += sprintf(buf, ": ");
|
||||||
|
|
||||||
sprintf(buf, ": ");
|
|
||||||
buf += strlen(buf);
|
|
||||||
|
|
||||||
if (opc_ext->param_count > 0)
|
if (opc_ext->param_count > 0)
|
||||||
gd_dis_params(opc_ext, op1, op2, buf);
|
DisParams(*opc_ext, op1, op2, buf);
|
||||||
|
|
||||||
buf += strlen(buf);
|
buf += strlen(buf);
|
||||||
}
|
}
|
||||||
|
@ -332,10 +317,8 @@ void DSPDisassembler::gd_dis_opcode(const u16 *binbuf, u16 *pc, std::string *des
|
||||||
dest->append(buffer);
|
dest->append(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DSPDisassembler::gd_dis_file(const char* name, FILE* output)
|
bool DSPDisassembler::DisFile(const char* name, FILE* output)
|
||||||
{
|
{
|
||||||
gd_dis_open_unkop();
|
|
||||||
|
|
||||||
FILE* in;
|
FILE* in;
|
||||||
u32 size;
|
u32 size;
|
||||||
|
|
||||||
|
@ -346,95 +329,24 @@ bool DSPDisassembler::gd_dis_file(const char* name, FILE* output)
|
||||||
}
|
}
|
||||||
|
|
||||||
fseek(in, 0, SEEK_END);
|
fseek(in, 0, SEEK_END);
|
||||||
size = (int)ftell(in);
|
size = (int)ftell(in) & ~1;
|
||||||
fseek(in, 0, SEEK_SET);
|
fseek(in, 0, SEEK_SET);
|
||||||
|
|
||||||
u16 *binbuf = (u16*)malloc(size);
|
u16 *binbuf = new u16[size / 2];
|
||||||
fread(binbuf, 1, size, in);
|
fread(binbuf, 1, size, in);
|
||||||
|
|
||||||
for (u16 pc = 0; pc < (size / 2);)
|
for (u16 pc = 0; pc < (size / 2);)
|
||||||
{
|
{
|
||||||
std::string str;
|
std::string str;
|
||||||
gd_dis_opcode(binbuf, &pc, &str);
|
DisOpcode(binbuf, &pc, &str);
|
||||||
fprintf(output, "%s\n", str.c_str());
|
fprintf(output, "%s\n", str.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(in);
|
fclose(in);
|
||||||
|
delete [] binbuf;
|
||||||
free(binbuf);
|
|
||||||
|
|
||||||
gd_dis_close_unkop();
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DSPDisassembler::gd_dis_close_unkop()
|
|
||||||
{
|
|
||||||
FILE* uo;
|
|
||||||
int i, j;
|
|
||||||
u32 count = 0;
|
|
||||||
|
|
||||||
char filename[MAX_PATH];
|
|
||||||
sprintf(filename, "%sUnkOps.bin", FULL_DSP_DUMP_DIR);
|
|
||||||
|
|
||||||
uo = fopen(filename, "wb");
|
|
||||||
|
|
||||||
if (uo)
|
|
||||||
{
|
|
||||||
fwrite(unk_opcodes, 1, sizeof(unk_opcodes), uo);
|
|
||||||
fclose(uo);
|
|
||||||
}
|
|
||||||
|
|
||||||
sprintf(filename, "%sUnkOps.txt", FULL_DSP_DUMP_DIR);
|
|
||||||
uo = fopen(filename, "w");
|
|
||||||
|
|
||||||
if (uo)
|
|
||||||
{
|
|
||||||
for (i = 0; i < 0x10000; i++)
|
|
||||||
{
|
|
||||||
if (unk_opcodes[i])
|
|
||||||
{
|
|
||||||
count++;
|
|
||||||
fprintf(uo, "OP%04x\t%d", i, unk_opcodes[i]);
|
|
||||||
|
|
||||||
for (j = 15; j >= 0; j--)
|
|
||||||
{
|
|
||||||
if ((j & 0x3) == 3)
|
|
||||||
fprintf(uo, "\tb");
|
|
||||||
|
|
||||||
fprintf(uo, "%d", (i >> j) & 0x1);
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(uo, "\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(uo, "Unknown opcodes count: %d\n", count);
|
|
||||||
fclose(uo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void DSPDisassembler::gd_dis_open_unkop()
|
|
||||||
{
|
|
||||||
FILE* uo;
|
|
||||||
char filename[MAX_PATH];
|
|
||||||
sprintf(filename, "%sUnkOps.bin", FULL_DSP_DUMP_DIR);
|
|
||||||
uo = fopen(filename, "rb");
|
|
||||||
|
|
||||||
if (uo)
|
|
||||||
{
|
|
||||||
fread(unk_opcodes, 1, sizeof(unk_opcodes), uo);
|
|
||||||
fclose(uo);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (int i = 0; i < 0x10000; i++)
|
|
||||||
{
|
|
||||||
unk_opcodes[i] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *gd_get_reg_name(u16 reg)
|
const char *gd_get_reg_name(u16 reg)
|
||||||
{
|
{
|
||||||
return regnames[reg].name;
|
return regnames[reg].name;
|
||||||
|
|
|
@ -25,6 +25,9 @@
|
||||||
#ifndef _DSP_DISASSEMBLE_H
|
#ifndef _DSP_DISASSEMBLE_H
|
||||||
#define _DSP_DISASSEMBLE_H
|
#define _DSP_DISASSEMBLE_H
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "DSPTables.h"
|
#include "DSPTables.h"
|
||||||
|
|
||||||
|
@ -55,25 +58,24 @@ class DSPDisassembler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DSPDisassembler(const AssemblerSettings &settings);
|
DSPDisassembler(const AssemblerSettings &settings);
|
||||||
~DSPDisassembler() {}
|
~DSPDisassembler();
|
||||||
|
|
||||||
// Moves PC forward and writes the result to dest.
|
bool Disassemble(int start_pc, const std::vector<u16> &code, std::string *text);
|
||||||
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();
|
// Warning - this one is trickier to use right.
|
||||||
void gd_dis_open_unkop();
|
void DisOpcode(const u16 *binbuf, u16 *pc, std::string *dest);
|
||||||
const char* gd_dis_get_reg_name(u16 reg);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
char* gd_dis_params(const DSPOPCTemplate* opc, u16 op1, u16 op2, char* strbuf);
|
// Moves PC forward and writes the result to dest.
|
||||||
u32 unk_opcodes[0x10000];
|
bool DisFile(const char* name, FILE *output);
|
||||||
|
|
||||||
|
char* DisParams(const DSPOPCTemplate& opc, u16 op1, u16 op2, char* strbuf);
|
||||||
|
std::map<u16, int> unk_opcodes;
|
||||||
|
|
||||||
const AssemblerSettings settings_;
|
const AssemblerSettings settings_;
|
||||||
};
|
};
|
||||||
|
|
||||||
const char *gd_get_reg_name(u16 reg);
|
const char *gd_get_reg_name(u16 reg);
|
||||||
//u16 gd_dis_get_opcode_size(gd_globals_t* gdg);
|
|
||||||
|
|
||||||
#endif // _DSP_DISASSEMBLE_H
|
#endif // _DSP_DISASSEMBLE_H
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,7 @@ volatile u32 gdsp_running;
|
||||||
static bool cr_halt = true;
|
static bool cr_halt = true;
|
||||||
static bool cr_external_int = false;
|
static bool cr_external_int = false;
|
||||||
|
|
||||||
|
|
||||||
void UpdateCachedCR()
|
void UpdateCachedCR()
|
||||||
{
|
{
|
||||||
cr_halt = (g_dsp.cr & 0x4) != 0;
|
cr_halt = (g_dsp.cr & 0x4) != 0;
|
||||||
|
|
|
@ -116,12 +116,7 @@ void gdsp_run_cycles(int cycles);
|
||||||
void gdsp_stop();
|
void gdsp_stop();
|
||||||
|
|
||||||
void gdsp_write_cr(u16 val);
|
void gdsp_write_cr(u16 val);
|
||||||
u16 gdsp_read_cr(void);
|
u16 gdsp_read_cr();
|
||||||
|
|
||||||
u16* gdsp_get_iram(void);
|
|
||||||
u16* gdsp_get_irom(void);
|
|
||||||
u16* gdsp_get_dram(void);
|
|
||||||
u16* gdsp_get_drom(void);
|
|
||||||
|
|
||||||
// sets a flag in the pending exception register.
|
// sets a flag in the pending exception register.
|
||||||
void gdsp_generate_exception(u8 level);
|
void gdsp_generate_exception(u8 level);
|
||||||
|
|
|
@ -120,15 +120,15 @@ void RunAsmTests()
|
||||||
// Let's get brutal. We generate random code bytes and make sure that they can
|
// 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
|
// be roundtripped. We don't expect it to always succeed but it'll be sure to generate
|
||||||
// interesting test cases.
|
// interesting test cases.
|
||||||
/*
|
|
||||||
puts("Insane Random Code Test\n");
|
puts("Insane Random Code Test\n");
|
||||||
std::vector<u16> rand_code;
|
std::vector<u16> rand_code;
|
||||||
GenRandomCode(31, &rand_code);
|
GenRandomCode(30, &rand_code);
|
||||||
std::string rand_code_text;
|
std::string rand_code_text;
|
||||||
Disassemble(rand_code, true, &rand_code_text);
|
Disassemble(rand_code, true, &rand_code_text);
|
||||||
printf("%s", rand_code_text.c_str());
|
printf("%s", rand_code_text.c_str());
|
||||||
RoundTrip(rand_code);
|
RoundTrip(rand_code);
|
||||||
*/
|
|
||||||
std::string dsp_test;
|
std::string dsp_test;
|
||||||
|
|
||||||
if (File::ReadFileToString(true, "C:/devkitPro/examples/wii/asndlib/dsptest/dsp_test.ds", &dsp_test))
|
if (File::ReadFileToString(true, "C:/devkitPro/examples/wii/asndlib/dsptest/dsp_test.ds", &dsp_test))
|
||||||
|
|
|
@ -45,7 +45,6 @@ bool DSPHost_Running()
|
||||||
u32 DSPHost_CodeLoaded(const u8 *ptr, int size)
|
u32 DSPHost_CodeLoaded(const u8 *ptr, int size)
|
||||||
{
|
{
|
||||||
u32 crc = GenerateCRC(ptr, size);
|
u32 crc = GenerateCRC(ptr, size);
|
||||||
|
|
||||||
DumpDSPCode(ptr, size, crc);
|
DumpDSPCode(ptr, size, crc);
|
||||||
return crc;
|
return crc;
|
||||||
}
|
}
|
|
@ -221,7 +221,7 @@ void DSPDebuggerLLE::RebuildDisAsmListView()
|
||||||
AssemblerSettings settings;
|
AssemblerSettings settings;
|
||||||
DSPDisassembler disasm(settings);
|
DSPDisassembler disasm(settings);
|
||||||
std::string op_str;
|
std::string op_str;
|
||||||
disasm.gd_dis_opcode(binbuf,&settings.pc, &op_str);
|
disasm.DisOpcode(binbuf, &settings.pc, &op_str);
|
||||||
const char* pParameter = NULL;
|
const char* pParameter = NULL;
|
||||||
const char* pExtension = NULL;
|
const char* pExtension = NULL;
|
||||||
|
|
||||||
|
|
|
@ -21,58 +21,48 @@
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "Globals.h"
|
#include "Globals.h"
|
||||||
|
|
||||||
|
#include "FileUtil.h"
|
||||||
|
#include "DSPCodeUtil.h"
|
||||||
#include "Tools.h"
|
#include "Tools.h"
|
||||||
#include "disassemble.h"
|
#include "disassemble.h"
|
||||||
#include "gdsp_interpreter.h"
|
#include "gdsp_interpreter.h"
|
||||||
|
|
||||||
bool DumpDSPCode(const u8 *data, u32 _Length, u32 crc)
|
bool DumpDSPCode(const u8 *code_be, int size_in_bytes, u32 crc)
|
||||||
{
|
|
||||||
char szFilename[MAX_PATH];
|
|
||||||
sprintf(szFilename, "%sDSP_UC_%08X.bin", FULL_DSP_DUMP_DIR, crc);
|
|
||||||
FILE* pFile = fopen(szFilename, "wb");
|
|
||||||
|
|
||||||
if (pFile)
|
|
||||||
{
|
|
||||||
fwrite(data, _Length, 1, pFile);
|
|
||||||
fclose(pFile);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
PanicAlert("Cant open file (%s) to dump UCode!!", szFilename);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!DisasmUCodeDump(crc))
|
|
||||||
{
|
|
||||||
PanicAlert("Failed to disasm UCode!!", szFilename);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DisasmUCodeDump(u32 crc)
|
|
||||||
{
|
{
|
||||||
char binFile[MAX_PATH];
|
char binFile[MAX_PATH];
|
||||||
char txtFile[MAX_PATH];
|
char txtFile[MAX_PATH];
|
||||||
sprintf(binFile, "%sDSP_UC_%08X.bin", FULL_DSP_DUMP_DIR, crc);
|
sprintf(binFile, "%sDSP_UC_%08X.bin", FULL_DSP_DUMP_DIR, crc);
|
||||||
sprintf(txtFile, "%sDSP_UC_%08X.txt", FULL_DSP_DUMP_DIR, crc);
|
sprintf(txtFile, "%sDSP_UC_%08X.txt", FULL_DSP_DUMP_DIR, crc);
|
||||||
FILE* t = fopen(txtFile, "wb");
|
|
||||||
if (t != NULL)
|
FILE* pFile = fopen(binFile, "wb");
|
||||||
|
if (pFile)
|
||||||
{
|
{
|
||||||
AssemblerSettings settings;
|
fwrite(code_be, size_in_bytes, 1, pFile);
|
||||||
settings.show_hex = true;
|
fclose(pFile);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
PanicAlert("Cant open file (%s) to dump UCode!!", binFile);
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load the binary back in.
|
||||||
|
std::vector<u16> code;
|
||||||
|
LoadBinary(binFile, &code);
|
||||||
|
|
||||||
|
AssemblerSettings settings;
|
||||||
|
settings.show_hex = true;
|
||||||
|
settings.show_pc = true;
|
||||||
|
settings.ext_separator = '\t';
|
||||||
|
settings.decode_names = true;
|
||||||
|
settings.decode_registers = true;
|
||||||
|
|
||||||
|
std::string text;
|
||||||
|
DSPDisassembler disasm(settings);
|
||||||
|
if (!disasm.Disassemble(0, code, &text))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return File::WriteStringToFile(true, text, txtFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 GenerateCRC(const unsigned char* _pBuffer, int _pLength)
|
u32 GenerateCRC(const unsigned char* _pBuffer, int _pLength)
|
||||||
|
|
|
@ -18,8 +18,7 @@
|
||||||
#ifndef _DSPLLE_TOOLS_H
|
#ifndef _DSPLLE_TOOLS_H
|
||||||
#define _DSPLLE_TOOLS_H
|
#define _DSPLLE_TOOLS_H
|
||||||
|
|
||||||
bool DumpDSPCode(const u8 *data, u32 _Length, u32 crc);
|
bool DumpDSPCode(const u8 *code_be, int size_in_bytes, u32 crc);
|
||||||
bool DisasmUCodeDump(u32 crc);
|
|
||||||
u32 GenerateCRC(const unsigned char* _pBuffer, int _pLength);
|
u32 GenerateCRC(const unsigned char* _pBuffer, int _pLength);
|
||||||
bool DumpCWCode(u32 _Address, u32 _Length);
|
bool DumpCWCode(u32 _Address, u32 _Length);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue