DSP: More work on dsptool. Minor bugfixes. Add some testdata for dsptool.

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@2993 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
hrydgard
2009-04-18 11:31:37 +00:00
parent c395b93590
commit e7e4ef4481
22 changed files with 2224 additions and 232 deletions
+1 -1
View File
@@ -579,8 +579,8 @@ std::string GetSysDirectory()
sysDir += DIR_SEP;
INFO_LOG(COMMON, "GetSysDirectory: Setting to %s:", sysDir.c_str());
return sysDir;
}
// Returns a pointer to a string with a Dolphin data dir in the user's home
// directory. To be used in "multi-user" mode (that is, installed).
const char *GetUserDirectory()
+8
View File
@@ -522,6 +522,14 @@
RelativePath=".\Src\gdsp_registers.h"
>
</File>
<File
RelativePath=".\Src\LabelMap.cpp"
>
</File>
<File
RelativePath=".\Src\LabelMap.h"
>
</File>
<File
RelativePath=".\Src\SConscript"
>
+4 -4
View File
@@ -71,7 +71,7 @@ bool Compare(const std::vector<u16> &code1, const std::vector<u16> &code2)
if (code1[i] == code2[i])
count_equal++;
else
printf("!! %i : %04x vs %04x\n", i, code1[i], code2[i]);
printf("!! %04x : %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;
@@ -86,11 +86,11 @@ void GenRandomCode(int size, std::vector<u16> *code)
}
}
void CodeToHeader(std::vector<u16> *code, const char *name, std::string *header)
void CodeToHeader(const std::vector<u16> &code, const char *name, std::string *header)
{
char buffer[1024];
header->clear();
header->reserve(code->size() * 4);
header->reserve(code.size() * 4);
header->append("#ifndef _MSCVER\n");
sprintf(buffer, "const __declspec(align:64) unsigned short %s = {\n");
header->append(buffer);
@@ -98,7 +98,7 @@ void CodeToHeader(std::vector<u16> *code, const char *name, std::string *header)
sprintf(buffer, "const unsigned short %s __attribute__(aligned:64) = {\n");
header->append(buffer);
header->append("#endif\n\n ");
for (int i = 0; i < code->size(); i++)
for (int i = 0; i < code.size(); i++)
{
if (((i + 1) & 15) == 0)
header->append("\n ");
+1 -1
View File
@@ -27,7 +27,7 @@ bool Assemble(const char *text, std::vector<u16> *code);
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);
void CodeToHeader(const std::vector<u16> &code, const char *name, std::string *header);
// Big-endian, for writing straight to file using File::WriteStringToFile.
void CodeToBinaryStringBE(const std::vector<u16> &code, std::string *str);
+1 -1
View File
@@ -1214,7 +1214,7 @@ void addis(const UDSPInstruction& opc)
{
u8 areg = (opc.hex >> 8) & 0x1;
s64 Imm = (s8)opc.hex;
s64 Imm = (s8)(u8)opc.hex;
Imm <<= 16;
s64 acc = dsp_get_long_acc(areg);
acc += Imm;
+27 -28
View File
@@ -66,7 +66,6 @@ void nop(const UDSPInstruction& opc)
// All AX games: a100
// Zelda Four Swords: 02ca
// TODO: Fill up the tables with the corresponding instructions
const DSPOPCTemplate opcodes[] =
{
@@ -90,17 +89,17 @@ const DSPOPCTemplate opcodes[] =
{"RET", 0x02df, 0xffff, DSPInterpreter::ret, nop, 1, 0, {}, NULL, NULL},
{"RTI", 0x02ff, 0xffff, DSPInterpreter::rti, nop, 1, 0, {}, NULL, NULL},
{"CALLNS", 0x02b0, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
{"CALLS", 0x02b1, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
{"CALLG", 0x02b2, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
{"CALLLE", 0x02b3, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
{"CALLNE", 0x02b4, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
{"CALLZ", 0x02b5, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
{"CALLL", 0x02b6, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
{"CALLGE", 0x02b7, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
{"CALLLNZ", 0x02bc, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
{"CALLLZ", 0x02bd, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
{"CALL", 0x02bf, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
{"CALLNS", 0x02b0, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
{"CALLS", 0x02b1, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
{"CALLG", 0x02b2, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
{"CALLLE", 0x02b3, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
{"CALLNE", 0x02b4, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
{"CALLZ", 0x02b5, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
{"CALLL", 0x02b6, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
{"CALLGE", 0x02b7, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
{"CALLLNZ", 0x02bc, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
{"CALLLZ", 0x02bd, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
{"CALL", 0x02bf, 0xffff, DSPInterpreter::call, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
{"IFNS", 0x0270, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL},
{"IFS", 0x0271, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL},
@@ -114,17 +113,17 @@ const DSPOPCTemplate opcodes[] =
{"IFLZ", 0x027d, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL},
{"IF", 0x027f, 0xffff, DSPInterpreter::ifcc, nop, 1, 0, {}, NULL, NULL}, // Hermes doesn't list this
{"JNS", 0x0290, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
{"JS", 0x0291, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
{"JG", 0x0292, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
{"JLE", 0x0293, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
{"JNZ", 0x0294, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
{"JZ", 0x0295, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
{"JL", 0x0296, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
{"JGE", 0x0297, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
{"JLNZ", 0x029c, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
{"JLZ", 0x029d, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
{"JMP", 0x029f, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
{"JNS", 0x0290, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
{"JS", 0x0291, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
{"JG", 0x0292, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
{"JLE", 0x0293, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
{"JNZ", 0x0294, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
{"JZ", 0x0295, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
{"JL", 0x0296, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
{"JGE", 0x0297, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
{"JLNZ", 0x029c, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
{"JLZ", 0x029d, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
{"JMP", 0x029f, 0xffff, DSPInterpreter::jcc, nop, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
{"JRNS", 0x1700, 0xff1f, DSPInterpreter::jmprcc, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, NULL, NULL},
@@ -205,11 +204,11 @@ const DSPOPCTemplate opcodes[] =
// LOOPS
{"LOOP", 0x0040, 0xffe0, DSPInterpreter::loop, nop, 1, 1, {{P_REG, 1, 0, 0, 0x001f}}, NULL, NULL},
{"BLOOP", 0x0060, 0xffe0, DSPInterpreter::bloop, nop, 2, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
{"BLOOP", 0x0060, 0xffe0, DSPInterpreter::bloop, nop, 2, 2, {{P_REG, 1, 0, 0, 0x001f}, {P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
{"LOOPI", 0x1000, 0xff00, DSPInterpreter::loopi, nop, 1, 1, {{P_IMM, 1, 0, 0, 0x00ff}}, NULL, NULL},
{"BLOOPI", 0x1100, 0xff00, DSPInterpreter::bloopi, nop, 2, 2, {{P_IMM, 1, 0, 0, 0x00ff}, {P_VAL, 2, 1, 0, 0xffff}}, NULL, NULL},
{"BLOOPI", 0x1100, 0xff00, DSPInterpreter::bloopi, nop, 2, 2, {{P_IMM, 1, 0, 0, 0x00ff}, {P_ADDR_I, 2, 1, 0, 0xffff}}, NULL, NULL},
{"ADDARN", 0x0010, 0xfff0, DSPInterpreter::addarn, nop, 2, 2, {{P_REG, 1, 0, 0, 0x00c0}, {P_REG04, 2, 1, 0, 0x0003}}, NULL, NULL},
{"ADDARN", 0x0010, 0xfff0, DSPInterpreter::addarn, nop, 1, 2, {{P_REG, 1, 0, 0, 0x0003}, {P_REG04, 1, 0, 2, 0x000c}}, NULL, NULL},
// opcodes that can be extended
@@ -292,12 +291,12 @@ const DSPOPCTemplate opcodes[] =
{"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},
{"ADD", 0x4c00, 0xfeff, DSPInterpreter::add, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
{"ADD", 0x4c00, 0xfeff, DSPInterpreter::add, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_ACC_D, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
{"ADDAXL", 0x7000, 0xfcff, DSPInterpreter::addaxl, 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},
{"SUBR", 0x5000, 0xf8ff, DSPInterpreter::subr, 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},
{"SUBAX", 0x5800, 0xfcff, DSPInterpreter::subax, 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},
{"SUB", 0x5c00, 0xfeff, DSPInterpreter::sub, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
{"SUB", 0x5c00, 0xfeff, DSPInterpreter::sub, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_ACC_D, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
{"SUBP", 0x5e00, 0xfeff, DSPInterpreter::subp, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
{"MADD", 0xf200, 0xfeff, DSPInterpreter::madd, nop, 1 | P_EXT, 2, {{P_REG18, 1, 0, 8, 0x0100}, {P_REG1A, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi},
+4 -3
View File
@@ -22,7 +22,7 @@
#include "Common.h"
// The ones that end with _D are the opposite one - if the bit specify
// The non-ADDR 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.
@@ -32,10 +32,12 @@
enum partype_t
{
P_NONE = 0x0000,
P_VAL = 0x0001,
P_VAL = 0x0001,
P_IMM = 0x0002,
P_MEM = 0x0003,
P_STR = 0x0004,
P_ADDR_I = 0x0005,
P_ADDR_D = 0x0006,
P_REG = 0x8000,
P_REG04 = P_REG | 0x0400, // IX
P_REG08 = P_REG | 0x0800,
@@ -60,7 +62,6 @@ enum partype_t
// The following seem like junk:
// P_REG10 = P_REG | 0x1000,
// P_AX_D = P_REG | 0x2280,
};
#define P_EXT 0x80
+83
View File
@@ -0,0 +1,83 @@
// Copyright (C) 2003-2009 Dolphin Project.
// 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, version 2.0.
// 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "LabelMap.h"
#include "DSPTables.h"
LabelMap::LabelMap()
{
}
void LabelMap::RegisterDefaults()
{
for (int i = 0; i < 0x24; i++)
{
RegisterLabel(regnames[i].name, regnames[i].addr);
}
for (int i = 0; i < (int)pdlabels_size; i++)
{
RegisterLabel(pdlabels[i].name, pdlabels[i].addr);
}
}
void LabelMap::RegisterLabel(const char *label, u16 lval, LabelType type)
{
u16 old_value;
if (GetLabelValue(label, &old_value) && old_value != lval)
{
printf("WARNING: Redefined label %s to %04x - old value %04x\n",
label, lval, old_value);
DeleteLabel(label);
}
labels.push_back(label_t(label, lval, type));
}
void LabelMap::DeleteLabel(const char *label)
{
for (std::vector<label_t>::iterator iter = labels.begin();
iter != labels.end(); ++iter)
{
if (!strcmp(label, iter->name.c_str()))
{
labels.erase(iter);
return;
}
}
}
bool LabelMap::GetLabelValue(const char *label, u16 *value, LabelType type) const
{
for (int i = 0; i < labels.size(); i++)
{
if (!strcmp(labels[i].name.c_str(), label))
{
if (type & labels[i].type) {
*value = labels[i].addr;
return true;
} else {
printf("WARNING: Wrong label type requested. %s\n", label);
}
}
}
return false;
}
void LabelMap::Clear()
{
labels.clear();
}
+54
View File
@@ -0,0 +1,54 @@
// Copyright (C) 2003-2009 Dolphin Project.
// 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, version 2.0.
// 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _LABELMAP_H
#define _LABELMAP_H
#include <string>
#include <vector>
#include "Common.h"
enum LabelType
{
LABEL_IADDR = 1, // Jump addresses, etc
LABEL_DADDR = 2, // Data addresses, etc
LABEL_VALUE = 4,
LABEL_ANY = 0xFF,
};
class LabelMap
{
struct label_t
{
label_t(const char *lbl, s32 address, LabelType ltype) : name(lbl), addr(address), type(ltype) {}
std::string name;
s32 addr;
LabelType type;
};
std::vector<label_t> labels;
public:
LabelMap();
void RegisterDefaults();
void RegisterLabel(const char *label, u16 lval, LabelType type = LABEL_VALUE);
void DeleteLabel(const char *label);
bool GetLabelValue(const char *label, u16 *value, LabelType type = LABEL_ANY) const;
void Clear();
};
#endif // _LABELMAP_H
File diff suppressed because it is too large Load Diff
+18 -20
View File
@@ -31,6 +31,7 @@
#include "Common.h"
#include "disassemble.h"
#include "DSPTables.h"
#include "LabelMap.h"
enum err_t
{
@@ -59,6 +60,7 @@ enum err_t
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
@@ -77,13 +79,6 @@ public:
err_t GetError() const { return last_error; }
private:
struct label_t
{
label_t(const char *lbl, s32 address) : label(lbl), addr(address) {}
std::string label;
s32 addr;
};
struct param_t
{
u32 val;
@@ -99,30 +94,33 @@ private:
SEGMENT_MAX
};
// Utility functions
s32 ParseValue(const char *str);
u32 ParseExpression(const char *ptr);
u32 GetParams(char *parstr, param_t *par);
void InitPass(int pass);
bool AssembleFile(const char *fname, int pass);
void ShowError(err_t err_code, const char *extra_info = NULL);
// void ShowWarning(err_t err_code, const char *extra_info = NULL);
char *FindBrackets(char *src, char *dst);
const opc_t *FindOpcode(const char *opcode, u32 par_count, const opc_t * const opcod, int opcod_size);
bool VerifyParams(const opc_t *opc, param_t *par, int count, bool ext = false);
void BuildCode(const opc_t *opc, param_t *par, u32 par_count, u16 *outbuf);
char *gdg_buffer;
int gdg_buffer_size;
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);
std::string include_dir;
std::vector<label_t> labels;
std::string cur_line;
u32 cur_addr;
u8 cur_pass;
LabelMap labels;
FILE *fsrc;
u32 code_line;
+56 -61
View File
@@ -82,15 +82,8 @@ bool DSPDisassembler::Disassemble(int start_pc, const std::vector<u16> &code, st
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;
// Run the two passes.
return DisFile(tmp1, 1, text) && DisFile(tmp1, 2, text);
}
char *DSPDisassembler::DisParams(const DSPOPCTemplate& opc, u16 op1, u16 op2, char *strbuf)
@@ -101,31 +94,24 @@ char *DSPDisassembler::DisParams(const DSPOPCTemplate& opc, u16 op1, u16 op2, ch
if (j > 0)
buf += sprintf(buf, ", ");
u32 val;
if (opc.params[j].loc >= 1)
val = op2;
else
val = op1;
u32 val = (opc.params[j].loc >= 1) ? val = op2 : val = op1;
val &= opc.params[j].mask;
if (opc.params[j].lshift < 0)
val = val << (-opc.params[j].lshift);
else
val = val >> opc.params[j].lshift;
u32 type = opc.params[j].type;
if ((type & 0xff) == 0x10)
type &= 0xff00;
if (type & P_REG)
{
// Check for _D parameter - if so flip.
if (type == P_ACC_D) // Used to be P_ACCM_D TODO verify
val = (~val & 0x1) | ((type & P_REGS_MASK) >> 8);
else
val |= (type & P_REGS_MASK) >> 8;
type &= ~P_REGS_MASK;
}
@@ -146,8 +132,12 @@ char *DSPDisassembler::DisParams(const DSPOPCTemplate& opc, u16 op1, u16 op2, ch
break;
case P_VAL:
case P_ADDR_I:
case P_ADDR_D:
if (settings_.decode_names)
{
sprintf(buf, "%s", pdname(val));
}
else
sprintf(buf, "0x%04x", val);
break;
@@ -156,17 +146,19 @@ char *DSPDisassembler::DisParams(const DSPOPCTemplate& opc, u16 op1, u16 op2, ch
if (opc.params[j].size != 2)
{
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); // 6-bit sign extension
else
sprintf(buf, "#0x%02x", val);
}
else
{
sprintf(buf, "#0x%04x", val);
}
break;
case P_MEM:
if (opc.params[j].size != 2)
val = (u16)(s8)val;
val = (u16)(s16)(s8)val;
if (settings_.decode_names)
sprintf(buf, "@%s", pdname(val));
@@ -185,12 +177,22 @@ char *DSPDisassembler::DisParams(const DSPOPCTemplate& opc, u16 op1, u16 op2, ch
return strbuf;
}
void DSPDisassembler::DisOpcode(const u16 *binbuf, u16 *pc, std::string *dest)
static void MakeLowerCase(char *ptr)
{
int i = 0;
while (ptr[i])
{
ptr[i] = tolower(ptr[i]);
i++;
}
}
void DSPDisassembler::DisOpcode(const u16 *binbuf, int pass, u16 *pc, std::string *dest)
{
u32 op2;
char buffer[256];
char *buf = buffer;
// Start with a space.
// Start with 8 spaces, if there's no label.
buf[0] = ' ';
buf[1] = '\0';
buf++;
@@ -206,6 +208,7 @@ void DSPDisassembler::DisOpcode(const u16 *binbuf, u16 *pc, std::string *dest)
const DSPOPCTemplate *opc = NULL;
const DSPOPCTemplate *opc_ext = NULL;
// find opcode
for (int j = 0; j < opcodes_size; j++)
{
@@ -222,13 +225,12 @@ void DSPDisassembler::DisOpcode(const u16 *binbuf, u16 *pc, std::string *dest)
break;
}
}
const DSPOPCTemplate fake_op = {"CW", 0x0000, 0x0000, nop, nop, 1, 1, {{P_VAL, 2, 0, 0, 0xffff}}, NULL, NULL,};
if (!opc)
opc = &fake_op;
bool extended;
if (opc->size & P_EXT && op1 & 0x00ff)
if ((opc->size & P_EXT) && (op1 & 0x00ff))
extended = true;
else
extended = false;
@@ -250,52 +252,52 @@ void DSPDisassembler::DisOpcode(const u16 *binbuf, u16 *pc, std::string *dest)
// printing
if (settings_.show_pc)
sprintf(buf, "%04x ", *pc);
buf += sprintf(buf, "%04x ", *pc);
buf += strlen(buf);
u32 op2;
// Size 2 - the op has a large immediate.
if ((opc->size & ~P_EXT) == 2)
{
op2 = binbuf[*pc + 1];
if (settings_.show_hex)
sprintf(buf, "%04x %04x ", op1, op2);
buf += sprintf(buf, "%04x %04x ", op1, op2);
}
else
{
op2 = 0;
if (settings_.show_hex)
sprintf(buf, "%04x ", op1);
buf += sprintf(buf, "%04x ", op1);
}
buf += strlen(buf);
char tmpbuf[20];
char opname[20];
strcpy(opname, opc->name);
if (settings_.lower_case_ops)
MakeLowerCase(opname);
char ext_buf[20];
if (extended)
sprintf(tmpbuf, "%s%c%s", opc->name, settings_.ext_separator, opc_ext->name);
sprintf(ext_buf, "%s%c%s", opname, settings_.ext_separator, opc_ext->name);
else
sprintf(tmpbuf, "%s", opc->name);
sprintf(ext_buf, "%s", opname);
if (settings_.lower_case_ops)
MakeLowerCase(ext_buf);
if (settings_.print_tabs)
sprintf(buf, "%s\t", tmpbuf);
buf += sprintf(buf, "%s\t", ext_buf);
else
sprintf(buf, "%-12s", tmpbuf);
buf += strlen(buf);
buf += sprintf(buf, "%-12s", ext_buf);
if (opc->param_count > 0)
DisParams(*opc, op1, op2, buf);
buf += strlen(buf);
// Handle opcode extension.
if (extended)
{
if (opc->param_count > 0)
buf += sprintf(buf, " ");
buf += sprintf(buf, ": ");
if (opc_ext->param_count > 0)
DisParams(*opc_ext, op1, op2, buf);
@@ -314,40 +316,33 @@ void DSPDisassembler::DisOpcode(const u16 *binbuf, u16 *pc, std::string *dest)
else
*pc += opc->size & ~P_EXT;
dest->append(buffer);
if (pass == 2)
dest->append(buffer);
}
bool DSPDisassembler::DisFile(const char* name, FILE* output)
bool DSPDisassembler::DisFile(const char* name, int pass, std::string *output)
{
FILE* in;
u32 size;
in = fopen(name, "rb");
if (in == NULL) {
FILE* in = fopen(name, "rb");
if (in == NULL)
{
printf("gd_dis_file: No input\n");
return false;
}
fseek(in, 0, SEEK_END);
size = (int)ftell(in) & ~1;
int size = (int)ftell(in) & ~1;
fseek(in, 0, SEEK_SET);
u16 *binbuf = new u16[size / 2];
fread(binbuf, 1, size, in);
fclose(in);
// Actually do the disassembly.
for (u16 pc = 0; pc < (size / 2);)
{
std::string str;
DisOpcode(binbuf, &pc, &str);
fprintf(output, "%s\n", str.c_str());
DisOpcode(binbuf, pass, &pc, output);
if (pass == 2)
output->append("\n");
}
fclose(in);
delete [] binbuf;
return true;
}
const char *gd_get_reg_name(u16 reg)
{
return regnames[reg].name;
}
+8 -4
View File
@@ -30,6 +30,7 @@
#include "Common.h"
#include "DSPTables.h"
#include "LabelMap.h"
struct AssemblerSettings
{
@@ -40,6 +41,7 @@ struct AssemblerSettings
decode_names(true),
decode_registers(true),
ext_separator('\''),
lower_case_ops(true),
pc(0)
{
}
@@ -50,6 +52,7 @@ struct AssemblerSettings
bool decode_names;
bool decode_registers;
char ext_separator;
bool lower_case_ops;
u16 pc;
};
@@ -63,19 +66,20 @@ public:
bool Disassemble(int start_pc, const std::vector<u16> &code, std::string *text);
// Warning - this one is trickier to use right.
void DisOpcode(const u16 *binbuf, u16 *pc, std::string *dest);
// Use pass == 2 if you're just using it by itself.
void DisOpcode(const u16 *binbuf, int pass, u16 *pc, std::string *dest);
private:
// Moves PC forward and writes the result to dest.
bool DisFile(const char* name, FILE *output);
bool DisFile(const char* name, int pass, std::string *output);
char* DisParams(const DSPOPCTemplate& opc, u16 op1, u16 op2, char* strbuf);
std::map<u16, int> unk_opcodes;
const AssemblerSettings settings_;
};
const char *gd_get_reg_name(u16 reg);
LabelMap labels;
};
#endif // _DSP_DISASSEMBLE_H
@@ -123,7 +123,9 @@ inline s64 dsp_get_long_prod()
return val;
}
// For accurate emulation, this is wrong - it should take the two multiplicands
// as input and set the two mid stages accordingly. most likely it's doing something
// pretty simple.
inline void dsp_set_long_prod(s64 val)
{
#if PROFILE
+130 -7
View File
@@ -19,6 +19,8 @@
#include "FileUtil.h"
#include "DSPCodeUtil.h"
#include "dsp_test.h"
// Stub out the dsplib host stuff, since this is just a simple cmdline tools.
u8 DSPHost_ReadHostMemory(u32 addr) { return 0; }
bool DSPHost_OnThread() { return false; }
@@ -41,7 +43,11 @@ bool RoundTrip(const std::vector<u16> &code1)
printf("RoundTrip: Assembly failed.\n");
return false;
}
Compare(code1, code2);
if (!Compare(code1, code2))
{
Disassemble(code1, true, &text);
printf("%s", text.c_str());
}
return true;
}
@@ -64,8 +70,8 @@ bool SuperTrip(const char *asm_code)
}
else
{
//printf("Disass:\n");
//printf("%s", text.c_str());
printf("Disass:\n");
printf("%s", text.c_str());
}
if (!Assemble(text.c_str(), &code2))
{
@@ -119,8 +125,47 @@ void RunAsmTests()
//" 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.
// interesting test cases.
/*
std::vector<u16> hermes;
if (!LoadBinary("testdata/hermes.bin", &hermes))
PanicAlert("Failed to load hermes rom");
RoundTrip(hermes);
*/
/*
std::vector<u16> code;
std::string text_orig;
File::ReadFileToString(false, "testdata/dsp_test.S", &text_orig);
if (!Assemble(text_orig.c_str(), &code))
{
printf("SuperTrip: First assembly failed\n");
return;
}*/
/*
code.clear();
for (int i = 0; i < sizeof(dsp_test)/4; i++)
{
code.push_back(dsp_test[i] >> 16);
code.push_back(dsp_test[i] & 0xFFFF);
}
SaveBinary(code, "dsp_test.bin");
RoundTrip(code);*/
//if (Compare(code, hermes))
// printf("Successs\n");
/*
{
std::vector<u16> code;
std::string text;
LoadBinary("testdata/dsp_test.bin", &code);
Disassemble(code, true, &text);
Assemble(text.c_str(), &code);
Disassemble(code, true, &text);
printf("%s", text.c_str());
}*/
/*
puts("Insane Random Code Test\n");
std::vector<u16> rand_code;
GenRandomCode(30, &rand_code);
@@ -129,24 +174,102 @@ void RunAsmTests()
printf("%s", rand_code_text.c_str());
RoundTrip(rand_code);
std::string 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.
*/
std::string dsp_test;
if (File::ReadFileToString(true, "Testdata/dsp_test.s", &dsp_test))
fail = fail || !SuperTrip(dsp_test.c_str());
if (!fail)
printf("All passed!\n");
}
// Usage:
// Run internal tests:
// dsptool test
// Disassemble a file:
// dsptool -d -o asdf.txt asdf.bin
// Disassemble a file, output to standard output:
// dsptool -d asdf.bin
// Assemble a file:
// dsptool -o asdf.bin asdf.txt
// Assemble a file, output header:
// dsptool -h asdf.h asdf.txt
// So far, all this binary can do is test partially that itself works correctly.
int main(int argc, const char *argv[])
{
if (argc == 2 && !strcmp(argv[1], "test"))
{
RunAsmTests();
RunAsmTests();
return 0;
}
std::string input_name;
std::string output_header_name;
std::string output_name;
bool disassemble = false;
for (int i = 1; i < argc; i++)
{
if (!strcmp(argv[i], "-d"))
disassemble = true;
else if (!strcmp(argv[i], "-o"))
output_name = argv[++i];
else if (!strcmp(argv[i], "-h"))
output_header_name = argv[++i];
else
{
if (!input_name.empty())
{
printf("Can only take one input file.\n");
return 1;
}
input_name = argv[i];
}
}
if (disassemble)
{
if (input_name.empty())
{
printf("Must specify input.\n");
return 1;
}
std::string binary_code;
std::vector<u16> code;
File::ReadFileToString(false, input_name.c_str(), &binary_code);
BinaryStringBEToCode(binary_code, &code);
std::string text;
Disassemble(code, true, &text);
File::WriteStringToFile(true, text, output_name.c_str());
}
else
{
std::string source;
if (File::ReadFileToString(true, input_name.c_str(), &source))
{
std::vector<u16> code;
Assemble(source.c_str(), &code);
if (!output_name.empty())
{
std::string binary_code;
CodeToBinaryStringBE(code, &binary_code);
File::WriteStringToFile(false, binary_code, output_name.c_str());
}
if (!output_header_name.empty())
{
std::string header;
CodeToHeader(code, output_header_name.c_str(), &header);
File::WriteStringToFile(true, header, (output_header_name + ".h").c_str());
}
}
}
return 0;
}
File diff suppressed because it is too large Load Diff
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large Load Diff
@@ -25,7 +25,7 @@ wxString CRegTable::GetValue(int row, int col)
{
switch (col)
{
case 0: return wxString::FromAscii(gd_get_reg_name(row));
case 0: return wxString::FromAscii(pdregname(row));
case 1: return wxString::Format(wxT("0x%04x"), g_dsp.r[row]);
default: return wxString::FromAscii("");
}

Some files were not shown because too many files have changed in this diff Show More