diff --git a/Source/Core/Common/Src/FileUtil.cpp b/Source/Core/Common/Src/FileUtil.cpp index 11fd035ad9..bfc3188a67 100644 --- a/Source/Core/Common/Src/FileUtil.cpp +++ b/Source/Core/Common/Src/FileUtil.cpp @@ -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() diff --git a/Source/Core/DSPCore/DSPCore.vcproj b/Source/Core/DSPCore/DSPCore.vcproj index 1c524c77a8..f7a0fc90f6 100644 --- a/Source/Core/DSPCore/DSPCore.vcproj +++ b/Source/Core/DSPCore/DSPCore.vcproj @@ -522,6 +522,14 @@ RelativePath=".\Src\gdsp_registers.h" > + + + + diff --git a/Source/Core/DSPCore/Src/DSPCodeUtil.cpp b/Source/Core/DSPCore/Src/DSPCodeUtil.cpp index 9ddf2c9405..370e945a12 100644 --- a/Source/Core/DSPCore/Src/DSPCodeUtil.cpp +++ b/Source/Core/DSPCore/Src/DSPCodeUtil.cpp @@ -71,7 +71,7 @@ bool Compare(const std::vector &code1, const std::vector &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 *code) } } -void CodeToHeader(std::vector *code, const char *name, std::string *header) +void CodeToHeader(const std::vector &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 *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 "); diff --git a/Source/Core/DSPCore/Src/DSPCodeUtil.h b/Source/Core/DSPCore/Src/DSPCodeUtil.h index 7701a3432c..02105dc52c 100644 --- a/Source/Core/DSPCore/Src/DSPCodeUtil.h +++ b/Source/Core/DSPCore/Src/DSPCodeUtil.h @@ -27,7 +27,7 @@ bool Assemble(const char *text, std::vector *code); bool Disassemble(const std::vector &code, bool line_numbers, std::string *text); bool Compare(const std::vector &code1, const std::vector &code2); void GenRandomCode(int size, std::vector *code); -void CodeToHeader(std::vector *code, const char *name, std::string *header); +void CodeToHeader(const std::vector &code, const char *name, std::string *header); // Big-endian, for writing straight to file using File::WriteStringToFile. void CodeToBinaryStringBE(const std::vector &code, std::string *str); diff --git a/Source/Core/DSPCore/Src/DSPInterpreter.cpp b/Source/Core/DSPCore/Src/DSPInterpreter.cpp index 9392d555f1..e801e4e1b9 100644 --- a/Source/Core/DSPCore/Src/DSPInterpreter.cpp +++ b/Source/Core/DSPCore/Src/DSPInterpreter.cpp @@ -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; diff --git a/Source/Core/DSPCore/Src/DSPTables.cpp b/Source/Core/DSPCore/Src/DSPTables.cpp index d3f015921d..e57c886fe2 100644 --- a/Source/Core/DSPCore/Src/DSPTables.cpp +++ b/Source/Core/DSPCore/Src/DSPTables.cpp @@ -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}, diff --git a/Source/Core/DSPCore/Src/DSPTables.h b/Source/Core/DSPCore/Src/DSPTables.h index 4a5990a53e..8e0f66207c 100644 --- a/Source/Core/DSPCore/Src/DSPTables.h +++ b/Source/Core/DSPCore/Src/DSPTables.h @@ -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 diff --git a/Source/Core/DSPCore/Src/LabelMap.cpp b/Source/Core/DSPCore/Src/LabelMap.cpp new file mode 100644 index 0000000000..836fef98f9 --- /dev/null +++ b/Source/Core/DSPCore/Src/LabelMap.cpp @@ -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::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(); +} diff --git a/Source/Core/DSPCore/Src/LabelMap.h b/Source/Core/DSPCore/Src/LabelMap.h new file mode 100644 index 0000000000..66d442e49c --- /dev/null +++ b/Source/Core/DSPCore/Src/LabelMap.h @@ -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 +#include + +#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 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 diff --git a/Source/Core/DSPCore/Src/assemble.cpp b/Source/Core/DSPCore/Src/assemble.cpp index 59ca640ee6..729578f5b7 100644 --- a/Source/Core/DSPCore/Src/assemble.cpp +++ b/Source/Core/DSPCore/Src/assemble.cpp @@ -115,12 +115,12 @@ bool DSPAssembler::Assemble(const char *text, std::vector *code, std::vecto return true; } -void DSPAssembler::parse_error(err_t err_code, const char *extra_info) +void DSPAssembler::ShowError(err_t err_code, const char *extra_info) { failed = true; char error_buffer[1024]; char *buf_ptr = error_buffer; - buf_ptr += sprintf(buf_ptr, "%i : %s\n", code_line, cur_line); + buf_ptr += sprintf(buf_ptr, "%i : %s", code_line, cur_line.c_str()); if (!extra_info) extra_info = "-"; if (fsrc) @@ -151,18 +151,8 @@ const char *skip_spaces(const char *ptr) return ptr; } -void DSPAssembler::gd_ass_register_label(const char *label, u16 lval) -{ - labels.push_back(label_t(label, lval)); -} - -void DSPAssembler::gd_ass_clear_labels() -{ - labels.clear(); -} - // Parse a standalone value - it can be a number in one of several formats or a label. -s32 DSPAssembler::strtoval(const char *str) +s32 DSPAssembler::ParseValue(const char *str) { bool negative = false; s32 val = 0; @@ -188,7 +178,7 @@ s32 DSPAssembler::strtoval(const char *str) if (ptr[i] >= '0' && ptr[i] <= '9') val += ptr[i] - '0'; else - parse_error(ERR_INCORRECT_DEC, str); + ShowError(ERR_INCORRECT_DEC, str); } } else @@ -206,7 +196,7 @@ s32 DSPAssembler::strtoval(const char *str) else if (ptr[i] >= '0' && ptr[i] <= '9') val += (ptr[i] - '0'); else - parse_error(ERR_INCORRECT_HEX, str); + ShowError(ERR_INCORRECT_HEX, str); } break; case '\'': // binary @@ -216,7 +206,7 @@ s32 DSPAssembler::strtoval(const char *str) if(ptr[i] >= '0' && ptr[i] <= '1') val += ptr[i] - '0'; else - parse_error(ERR_INCORRECT_BIN, str); + ShowError(ERR_INCORRECT_BIN, str); } break; default: @@ -237,19 +227,17 @@ s32 DSPAssembler::strtoval(const char *str) if (ptr[i] >= '0' && ptr[i] <= '9') val += ptr[i] - '0'; else - parse_error(ERR_INCORRECT_DEC, str); + ShowError(ERR_INCORRECT_DEC, str); } } else // Everything else is a label. { // Lookup label - for (int i = 0; i < labels.size(); i++) - { - if (strcmp(labels[i].label.c_str(), ptr) == 0) - return labels[i].addr; - } + u16 value; + if (labels.GetLabelValue(ptr, &value)) + return value; if (cur_pass == 2) - parse_error(ERR_UNKNOWN_LABEL, str); + ShowError(ERR_UNKNOWN_LABEL, str); } } if (negative) @@ -257,10 +245,9 @@ s32 DSPAssembler::strtoval(const char *str) return val; } - // Modifies both src and dst! // What does it do, really?? -char *DSPAssembler::find_brackets(char *src, char *dst) +char *DSPAssembler::FindBrackets(char *src, char *dst) { s32 len = (s32) strlen(src); s32 first = -1; @@ -302,12 +289,12 @@ char *DSPAssembler::find_brackets(char *src, char *dst) } } if (count) - parse_error(ERR_NO_MATCHING_BRACKETS); + ShowError(ERR_NO_MATCHING_BRACKETS); return NULL; } // Bizarre in-place expression evaluator. -u32 DSPAssembler::parse_exp(const char *ptr) +u32 DSPAssembler::ParseExpression(const char *ptr) { char *pbuf; s32 val = 0; @@ -316,9 +303,9 @@ u32 DSPAssembler::parse_exp(const char *ptr) char *s_buffer = (char *)malloc(1024); strcpy(s_buffer, ptr); - while ((pbuf = find_brackets(s_buffer, d_buffer)) != NULL) + while ((pbuf = FindBrackets(s_buffer, d_buffer)) != NULL) { - val = parse_exp(d_buffer); + val = ParseExpression(d_buffer); sprintf(d_buffer, "%s%d%s", s_buffer, val, pbuf); strcpy(s_buffer, d_buffer); } @@ -351,17 +338,18 @@ u32 DSPAssembler::parse_exp(const char *ptr) } d_buffer[i] = c; } + while ((pbuf = strstr(d_buffer, "+")) != NULL) { *pbuf = 0x0; - val = parse_exp(d_buffer) + parse_exp(pbuf+1); + val = ParseExpression(d_buffer) + ParseExpression(pbuf+1); sprintf(d_buffer, "%d", val); } while ((pbuf = strstr(d_buffer, "-")) != NULL) { *pbuf = 0x0; - val = parse_exp(d_buffer) - parse_exp(pbuf+1); + val = ParseExpression(d_buffer) - ParseExpression(pbuf+1); if (val < 0) { val = 0x10000 + (val & 0xffff); // ATTENTION: avoid a terrible bug!!! number cannot write with '-' in sprintf @@ -373,44 +361,39 @@ u32 DSPAssembler::parse_exp(const char *ptr) while ((pbuf = strstr(d_buffer, "*")) != NULL) { *pbuf = 0x0; - val = parse_exp(d_buffer) * parse_exp(pbuf+1); + val = ParseExpression(d_buffer) * ParseExpression(pbuf+1); sprintf(d_buffer, "%d", val); } while ((pbuf = strstr(d_buffer, "/")) != NULL) { *pbuf = 0x0; - val = parse_exp(d_buffer) / parse_exp(pbuf+1); + val = ParseExpression(d_buffer) / ParseExpression(pbuf+1); sprintf(d_buffer, "%d", val); } while ((pbuf = strstr(d_buffer, "|")) != NULL) { *pbuf = 0x0; - val = parse_exp(d_buffer) | parse_exp(pbuf+1); + val = ParseExpression(d_buffer) | ParseExpression(pbuf+1); sprintf(d_buffer, "%d", val); } while ((pbuf = strstr(d_buffer, "&")) != NULL) { *pbuf = 0x0; - val = parse_exp(d_buffer) & parse_exp(pbuf+1); + val = ParseExpression(d_buffer) & ParseExpression(pbuf+1); sprintf(d_buffer, "%d", val); } - val = strtoval(d_buffer); + val = ParseValue(d_buffer); free(d_buffer); free(s_buffer); return val; } -u32 DSPAssembler::parse_exp_f(const char *ptr) -{ - return parse_exp(ptr); -} - // Destroys parstr -u32 DSPAssembler::get_params(char *parstr, param_t *par) +u32 DSPAssembler::GetParams(char *parstr, param_t *par) { u32 count = 0; char *tmpstr = skip_spaces(parstr); @@ -435,27 +418,28 @@ u32 DSPAssembler::get_params(char *parstr, param_t *par) par[i].type = P_STR; break; case '#': - par[i].val = parse_exp_f(tmpstr + 1); + par[i].val = ParseExpression(tmpstr + 1); par[i].type = P_IMM; break; case '@': if (tmpstr[1] == '$') { - par[i].val = parse_exp_f(tmpstr + 2); + par[i].val = ParseExpression(tmpstr + 2); par[i].type = P_PRG; } else { - par[i].val = parse_exp_f(tmpstr + 1); + par[i].val = ParseExpression(tmpstr + 1); par[i].type = P_MEM; } break; case '$': - par[i].val = parse_exp_f(tmpstr + 1); + par[i].val = ParseExpression(tmpstr + 1); par[i].type = P_REG; break; + default: - par[i].val = parse_exp_f(tmpstr); + par[i].val = ParseExpression(tmpstr); par[i].type = P_VAL; break; } @@ -464,7 +448,7 @@ u32 DSPAssembler::get_params(char *parstr, param_t *par) return count; } -const opc_t *DSPAssembler::find_opcode(const char *opcode, u32 par_count, const opc_t * const opcod, int opcod_size) +const opc_t *DSPAssembler::FindOpcode(const char *opcode, u32 par_count, const opc_t * const opcod, int opcod_size) { if (opcode[0] == 'C' && opcode[1] == 'W') return &cw; @@ -479,16 +463,16 @@ const opc_t *DSPAssembler::find_opcode(const char *opcode, u32 par_count, const { if (par_count < opc->param_count) { - parse_error(ERR_NOT_ENOUGH_PARAMETERS); + ShowError(ERR_NOT_ENOUGH_PARAMETERS); } if (par_count > opc->param_count) { - parse_error(ERR_TOO_MANY_PARAMETERS); + ShowError(ERR_TOO_MANY_PARAMETERS); } return opc; } } - parse_error(ERR_UNKNOWN_OPCODE); + ShowError(ERR_UNKNOWN_OPCODE); return NULL; } @@ -500,13 +484,20 @@ u16 get_mask_shifted_down(u16 mask) return mask; } -bool DSPAssembler::verify_params(const opc_t *opc, param_t *par, int count, bool ext) +bool DSPAssembler::VerifyParams(const opc_t *opc, param_t *par, int count, bool ext) { for (int i = 0; i < count; i++) { const int current_param = i + 1; // just for display. if (opc->params[i].type != par[i].type || (par[i].type & P_REG)) { + if (par[i].type == P_VAL && + (opc->params[i].type == P_ADDR_I || opc->params[i].type == P_ADDR_D)) + { + // Data and instruction addresses are valid as VAL values. + continue; + } + if ((opc->params[i].type & P_REG) && (par[i].type & P_REG)) { // Just a temp. Should be replaced with more purposeful vars. @@ -524,7 +515,7 @@ bool DSPAssembler::verify_params(const opc_t *opc, param_t *par, int count, bool { if (ext) fprintf(stderr, "(ext) "); fprintf(stderr, "%s (param %i)", cur_line.c_str(), current_param); - parse_error(ERR_INVALID_REGISTER); + ShowError(ERR_INVALID_REGISTER); } break; case P_PRG: @@ -532,21 +523,24 @@ bool DSPAssembler::verify_params(const opc_t *opc, param_t *par, int count, bool { if (ext) fprintf(stderr, "(ext) "); fprintf(stderr, "%s (param %i)", cur_line.c_str(), current_param); - parse_error(ERR_INVALID_REGISTER); + ShowError(ERR_INVALID_REGISTER); } break; case P_ACC: if ((int)par[i].val < 0x20 || (int)par[i].val > 0x21) { if (ext) fprintf(stderr, "(ext) "); - if (par[i].val >= 0x1e && par[i].val <= 0x1f) + if (par[i].val >= 0x1e && par[i].val <= 0x1f) { + fprintf(stderr, "%i : %s", code_line, cur_line.c_str()); fprintf(stderr, "WARNING: $ACM%d register used instead of $ACC%d register Line: %d Param: %d\n", (par[i].val & 1), (par[i].val & 1), code_line, current_param, ext); - else if (par[i].val >= 0x1c && par[i].val <= 0x1d) + } + else if (par[i].val >= 0x1c && par[i].val <= 0x1d) { fprintf(stderr, "WARNING: $ACL%d register used instead of $ACC%d register Line: %d Param: %d\n", (par[i].val & 1), (par[i].val & 1), code_line, current_param); + } else - parse_error(ERR_WRONG_PARAMETER_ACC); + ShowError(ERR_WRONG_PARAMETER_ACC); } break; case P_ACCM: @@ -560,7 +554,7 @@ bool DSPAssembler::verify_params(const opc_t *opc, param_t *par, int count, bool fprintf(stderr, "WARNING: $ACC%d register used instead of $ACM%d register Line: %d Param: %d\n", (par[i].val & 1), (par[i].val & 1), code_line, current_param); else - parse_error(ERR_WRONG_PARAMETER_ACC); + ShowError(ERR_WRONG_PARAMETER_ACC); } break; @@ -580,39 +574,39 @@ bool DSPAssembler::verify_params(const opc_t *opc, param_t *par, int count, bool (par[i].val & 1), (par[i].val & 1), code_line, current_param); } else - parse_error(ERR_WRONG_PARAMETER_ACC); + ShowError(ERR_WRONG_PARAMETER_ACC); } break; /* case P_ACCM_D: //P_ACC_MID: if ((int)par[i].val < 0x1e || (int)par[i].val > 0x1f) { - parse_error(ERR_WRONG_PARAMETER_MID_ACC); + ShowError(ERR_WRONG_PARAMETER_MID_ACC); } break;*/ } continue; } - switch (par[i].type & (P_REG | P_VAL | P_MEM | P_IMM)) + switch (par[i].type & (P_REG | 7)) { case P_REG: if (ext) fprintf(stderr, "(ext) "); - parse_error(ERR_EXPECTED_PARAM_REG); + ShowError(ERR_EXPECTED_PARAM_REG); break; case P_MEM: if (ext) fprintf(stderr, "(ext) "); - parse_error(ERR_EXPECTED_PARAM_MEM); + ShowError(ERR_EXPECTED_PARAM_MEM); break; case P_VAL: if (ext) fprintf(stderr, "(ext) "); - parse_error(ERR_EXPECTED_PARAM_VAL); + ShowError(ERR_EXPECTED_PARAM_VAL); break; case P_IMM: if (ext) fprintf(stderr, "(ext) "); - parse_error(ERR_EXPECTED_PARAM_IMM); + ShowError(ERR_EXPECTED_PARAM_IMM); break; } - parse_error(ERR_WRONG_PARAMETER); + ShowError(ERR_WRONG_PARAMETER); break; } else if ((opc->params[i].type & 3) != 0 && (par[i].type & 3) != 0) @@ -625,7 +619,7 @@ bool DSPAssembler::verify_params(const opc_t *opc, param_t *par, int count, bool if (value == 7) // value 7 por sbclr/sbset { fprintf(stderr,"Value must be from 0x0 to 0x%x\n", value); - parse_error(ERR_OUT_RANGE_NUMBER); + ShowError(ERR_OUT_RANGE_NUMBER); } else if (opc->params[i].type == P_MEM) { @@ -634,7 +628,7 @@ bool DSPAssembler::verify_params(const opc_t *opc, param_t *par, int count, bool else fprintf(stderr, "Address value must be from 0x0 to 0x%x\n", value); - parse_error(ERR_OUT_RANGE_NUMBER); + ShowError(ERR_OUT_RANGE_NUMBER); } else if ((int)par[i].val < -((value >> 1) + 1)) { @@ -645,7 +639,7 @@ bool DSPAssembler::verify_params(const opc_t *opc, param_t *par, int count, bool fprintf(stderr, "Value must be from -0x%x to 0x%x or 0x0 to 0x%x, is %i\n", (value >> 1) + 1, value >> 1, value, par[i].val); - parse_error(ERR_OUT_RANGE_NUMBER); + ShowError(ERR_OUT_RANGE_NUMBER); } } else @@ -655,7 +649,7 @@ bool DSPAssembler::verify_params(const opc_t *opc, param_t *par, int count, bool if (par[i].val > (unsigned)value) { fprintf(stderr,"Value must be from 0x%x to 0x%x, is %i\n",valueu, value, par[i].val); - parse_error(ERR_OUT_RANGE_NUMBER); + ShowError(ERR_OUT_RANGE_NUMBER); } } else if (opc->params[i].type == P_MEM) @@ -669,7 +663,7 @@ bool DSPAssembler::verify_params(const opc_t *opc, param_t *par, int count, bool fprintf(stderr,"Address value must be from 0x%x to 0x%x, is %04x\n", valueu, value, par[i].val); else fprintf(stderr,"Address value must be minor of 0x%x\n", value+1); - parse_error(ERR_OUT_RANGE_NUMBER); + ShowError(ERR_OUT_RANGE_NUMBER); } } else @@ -682,7 +676,7 @@ bool DSPAssembler::verify_params(const opc_t *opc, param_t *par, int count, bool fprintf(stderr,"Value must be from -0x%x to 0x%x, is %i\n", (value + 1), value, par[i].val); else fprintf(stderr,"Value must be minor of 0x%x, is %i\n", value + 1, par[i].val); - parse_error(ERR_OUT_RANGE_NUMBER); + ShowError(ERR_OUT_RANGE_NUMBER); } } } @@ -695,7 +689,7 @@ bool DSPAssembler::verify_params(const opc_t *opc, param_t *par, int count, bool // Merge opcode with params. -void DSPAssembler::build_code(const opc_t *opc, param_t *par, u32 par_count, u16 *outbuf) +void DSPAssembler::BuildCode(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++) @@ -721,15 +715,8 @@ void DSPAssembler::InitPass(int pass) if (pass == 1) { // Reset label table. Pre-populate with hw addresses and registers. - gd_ass_clear_labels(); - for (int i = 0; i < 0x24; i++) - { - gd_ass_register_label(regnames[i].name, regnames[i].addr); - } - for (int i = 0; i < (int)pdlabels_size; i++) - { - gd_ass_register_label(pdlabels[i].name, pdlabels[i].addr); - } + labels.Clear(); + labels.RegisterDefaults(); aliases.clear(); aliases["S15"] = "SET15"; aliases["S16"] = "SET16"; @@ -875,9 +862,9 @@ bool DSPAssembler::AssembleFile(const char *fname, int pass) } if (paramstr) - params_count = get_params(paramstr, params); + params_count = GetParams(paramstr, params); if (paramstr_ext) - params_count_ext = get_params(paramstr_ext, params_ext); + params_count_ext = GetParams(paramstr_ext, params_ext); } if (label) @@ -893,7 +880,7 @@ bool DSPAssembler::AssembleFile(const char *fname, int pass) } } if (pass == 1) - gd_ass_register_label(label, lval); + labels.RegisterLabel(label, lval); } if (opcode == NULL) @@ -919,7 +906,7 @@ bool DSPAssembler::AssembleFile(const char *fname, int pass) free(tmpstr); } else - parse_error(ERR_EXPECTED_PARAM_STR); + ShowError(ERR_EXPECTED_PARAM_STR); continue; } @@ -928,7 +915,7 @@ bool DSPAssembler::AssembleFile(const char *fname, int pass) if (params[0].type == P_STR) include_dir = params[0].str; else - parse_error(ERR_EXPECTED_PARAM_STR); + ShowError(ERR_EXPECTED_PARAM_STR); continue; } @@ -937,7 +924,7 @@ bool DSPAssembler::AssembleFile(const char *fname, int pass) if (params[0].type == P_VAL) cur_addr = params[0].val; else - parse_error(ERR_EXPECTED_PARAM_VAL); + ShowError(ERR_EXPECTED_PARAM_VAL); continue; } @@ -953,17 +940,17 @@ bool DSPAssembler::AssembleFile(const char *fname, int pass) cur_addr = segment_addr[cur_segment]; } else - parse_error(ERR_EXPECTED_PARAM_STR); + ShowError(ERR_EXPECTED_PARAM_STR); continue; } - const opc_t *opc = find_opcode(opcode, params_count, opcodes, opcodes_size); + const opc_t *opc = FindOpcode(opcode, params_count, opcodes, opcodes_size); if (!opc) opc = &cw; opcode_size = opc->size & ~P_EXT; - verify_params(opc, params, params_count); + VerifyParams(opc, params, params_count); const opc_t *opc_ext = NULL; // Check for opcode extensions. @@ -971,27 +958,27 @@ bool DSPAssembler::AssembleFile(const char *fname, int pass) { if (opcode_ext) { - opc_ext = find_opcode(opcode_ext, params_count_ext, opcodes_ext, opcodes_ext_size); - verify_params(opc_ext, params_ext, params_count_ext, true); + opc_ext = FindOpcode(opcode_ext, params_count_ext, opcodes_ext, opcodes_ext_size); + VerifyParams(opc_ext, params_ext, params_count_ext, true); } else if (params_count_ext) - parse_error(ERR_EXT_PAR_NOT_EXT); + ShowError(ERR_EXT_PAR_NOT_EXT); } else { if (opcode_ext) - parse_error(ERR_EXT_CANT_EXTEND_OPCODE); + ShowError(ERR_EXT_CANT_EXTEND_OPCODE); if (params_count_ext) - parse_error(ERR_EXT_PAR_NOT_EXT); + ShowError(ERR_EXT_PAR_NOT_EXT); } if (pass == 2) { // generate binary ((u16 *)gdg_buffer)[cur_addr] = 0x0000; - build_code(opc, params, params_count, (u16 *)gdg_buffer); + BuildCode(opc, params, params_count, (u16 *)gdg_buffer); if (opc_ext) - build_code(opc_ext, params_ext, params_count_ext, (u16 *)gdg_buffer); + BuildCode(opc_ext, params_ext, params_count_ext, (u16 *)gdg_buffer); } cur_addr += opcode_size; diff --git a/Source/Core/DSPCore/Src/assemble.h b/Source/Core/DSPCore/Src/assemble.h index 3d3800d343..4b698e7e6e 100644 --- a/Source/Core/DSPCore/Src/assemble.h +++ b/Source/Core/DSPCore/Src/assemble.h @@ -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 labels; std::string cur_line; u32 cur_addr; u8 cur_pass; + + LabelMap labels; FILE *fsrc; u32 code_line; diff --git a/Source/Core/DSPCore/Src/disassemble.cpp b/Source/Core/DSPCore/Src/disassemble.cpp index 8accae2ecf..4840517fbb 100644 --- a/Source/Core/DSPCore/Src/disassemble.cpp +++ b/Source/Core/DSPCore/Src/disassemble.cpp @@ -82,15 +82,8 @@ bool DSPDisassembler::Disassemble(int start_pc, const std::vector &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; -} diff --git a/Source/Core/DSPCore/Src/disassemble.h b/Source/Core/DSPCore/Src/disassemble.h index 610755407a..e131450ef5 100644 --- a/Source/Core/DSPCore/Src/disassemble.h +++ b/Source/Core/DSPCore/Src/disassemble.h @@ -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 &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 unk_opcodes; const AssemblerSettings settings_; -}; -const char *gd_get_reg_name(u16 reg); + LabelMap labels; +}; #endif // _DSP_DISASSEMBLE_H diff --git a/Source/Core/DSPCore/Src/gdsp_opcodes_helper.h b/Source/Core/DSPCore/Src/gdsp_opcodes_helper.h index 7bfdadd2b8..ee6b02d552 100644 --- a/Source/Core/DSPCore/Src/gdsp_opcodes_helper.h +++ b/Source/Core/DSPCore/Src/gdsp_opcodes_helper.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 diff --git a/Source/DSPTool/Src/main.cpp b/Source/DSPTool/Src/main.cpp index 42bfc0774e..d355fc31d5 100644 --- a/Source/DSPTool/Src/main.cpp +++ b/Source/DSPTool/Src/main.cpp @@ -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 &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 hermes; + if (!LoadBinary("testdata/hermes.bin", &hermes)) + PanicAlert("Failed to load hermes rom"); + RoundTrip(hermes); + */ + /* + std::vector 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 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 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 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 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; } \ No newline at end of file diff --git a/Source/DSPTool/Testdata/dsp_test.S b/Source/DSPTool/Testdata/dsp_test.S new file mode 100644 index 0000000000..11de8ff33e --- /dev/null +++ b/Source/DSPTool/Testdata/dsp_test.S @@ -0,0 +1,639 @@ + +DSCR: equ 0xffc9 ; DSP DMA Control Reg +DSBL: equ 0xffcb ; DSP DMA Block Length +DSPA: equ 0xffcd ; DSP DMA DMEM Address +DSMAH: equ 0xffce ; DSP DMA Mem Address H +DSMAL: equ 0xffcf ; DSP DMA Mem Address L + +ACSAH: equ 0xffd4 +ACSAL: equ 0xffd5 +ACEAH: equ 0xffd6 +ACEAL: equ 0xffd7 +ACCAH: equ 0xffd8 +ACCAL: equ 0xffd9 +AMDM: equ 0xffef ; ARAM DMA Request Mask + +DIRQ: equ 0xfffb ; DSP Irq Request +DMBH: equ 0xfffc ; DSP Mailbox H +DMBL: equ 0xfffd ; DSP Mailbox L +CMBH: equ 0xfffe ; CPU Mailbox H +CMBL: equ 0xffff ; CPU Mailbox L + +R00: equ 0x00 +R01: equ 0x01 +R02: equ 0x02 +R03: equ 0x03 +R04: equ 0x04 +R05: equ 0x05 +R06: equ 0x06 +R07: equ 0x07 +R08: equ 0x08 +R09: equ 0x09 +R0A: equ 0x0a +R0B: equ 0x0b +R0C: equ 0x0c +R0D: equ 0x0d +R0E: equ 0x0e +R0F: equ 0x0f +R10: equ 0x10 +R11: equ 0x11 +R12: equ 0x12 +R13: equ 0x13 +R14: equ 0x14 +R15: equ 0x15 +R16: equ 0x16 +R17: equ 0x17 +R18: equ 0x18 +R19: equ 0x19 +R1A: equ 0x1a +R1B: equ 0x1b +R1C: equ 0x1c +R1D: equ 0x1d +R1E: equ 0x1e +R1F: equ 0x1f + +ACH0: equ 0x10 +ACH1: equ 0x11 +ACL0: equ 0x1e +ACL1: equ 0x1f + +DSP_CR_IMEM: equ 2 +DSP_CR_TO_CPU: equ 1 + + +REGS_BASE: equ 0x0f80 +MEM_HI: equ 0x0f7E +MEM_LO: equ 0x0f7F + + +; Interrupt vectors 8 vectors, 2 opcodes each + + jmp irq0 + jmp irq1 + jmp irq2 + jmp irq3 + jmp irq4 + jmp irq5 + jmp irq6 + jmp irq7 + +; Main code at 0x10 + CW 0x1302 + CW 0x1303 + CW 0x1204 + CW 0x1305 + CW 0x1306 + + s40 + lri $r12, #0x00ff + +main: + + cw 0x8900 + cw 0x8100 + +; get address of memory dump and copy it + + call wait_for_dsp_mbox + si @DMBH, #0x8888 + si @DMBL, #0xdead + si @DIRQ, #0x0001 + + call wait_for_cpu_mbox + lrs $ACL0, @CMBL + andi $acl1, #0x7fff + + sr @MEM_HI, $ACL1 + sr @MEM_LO, $ACL0 + + lri $r18, #0 + lri $r19, #0 ;(DSP_CR_IMEM | DSP_CR_TO_CPU) + lri $r1a, #0x2000 + lr $r1c, @MEM_HI + lr $r1e, @MEM_LO + call do_dma + + +; get address of registers and DMA them to memory + + call wait_for_dsp_mbox + si @DMBH, #0x8888 + si @DMBL, #0xbeef + si @DIRQ, #0x0001 + + call wait_for_cpu_mbox + lrs $ACL0, @CMBL + andi $acl1, #0x7fff + + sr @MEM_HI, $ACL1 + sr @MEM_LO, $ACL0 + + lri $r18, #REGS_BASE + lri $r19, #0 ;(DSP_CR_IMEM | DSP_CR_TO_CPU) + lri $r1a, #0x80 + lr $r1c, @MEM_HI + lr $r1e, @MEM_LO + call do_dma + + + + lri $r00, #REGS_BASE+1 + lrri $r01, @$r00 + lrri $r02, @$r00 + lrri $r03, @$r00 + lrri $r04, @$r00 + lrri $r05, @$r00 + lrri $r06, @$r00 + lrri $r07, @$r00 + lrri $r08, @$r00 + lrri $r09, @$r00 + lrri $r0a, @$r00 + lrri $r0b, @$r00 + lrri $r0c, @$r00 + lrri $r0d, @$r00 + lrri $r0e, @$r00 + lrri $r0f, @$r00 + lrri $r10, @$r00 + lrri $r11, @$r00 + lrri $r12, @$r00 + lrri $r13, @$r00 + lrri $r14, @$r00 + lrri $r15, @$r00 + lrri $r16, @$r00 + lrri $r17, @$r00 + lrri $r18, @$r00 + lrri $r19, @$r00 + lrri $r1a, @$r00 + lrri $r1b, @$r00 + lrri $r1c, @$r00 + lrri $r1d, @$r00 + lrri $r1e, @$r00 + lrri $r1f, @$r00 + lr $r00, @REGS_BASE + + nop + nop + nop + nop + + + + + cw 0x8600 + + call send_back + + JMP ende + + +; call dump_memory +; call send_back + + +; 0x041e +; + + cw 0x00de + cw 0x03f1 + call send_back + + cw 0x0200 + cw 0x0a60 + call send_back + + cw 0x1c7e + call send_back + + cw 0x8100 + call send_back + + cw 0x8900 + call send_back + + cw 0x009f + cw 0x00a0 + call send_back + + cw 0x00de + cw 0x03f1 + call send_back + + cw 0x5d00 + call send_back + + cw 0x0e50 + call send_back + + cw 0x0750 + call send_back + + cw 0x0270 + call send_back + + cw 0x5d00 + call send_back + + cw 0x00da + cw 0x03f2 + call send_back + + cw 0x8600 + call send_back + + JNS g_0c4d +; cw 0x0290 +; cw 0x0c4d +; call send_back JX0 + + cw 0x00de + cw 0x03f3 + call send_back + + cw 0x5c00 + call send_back + + JLE g_0c38 +; cw 0x0293 +; cw 0x0c38 JX3 +; call send_back + + JMP g_0c52 + +; cw 0x029f +; cw 0x0c52 +; call send_back + +g_0c38: + cw 0x00db + cw 0x03f7 + call send_back + + cw 0x009e + cw 0x8000 + call send_back + + cw 0x4600 + call send_back + + JMP g_0c44 +; cw 0x029f +; cw 0x0c44 +; call send_back + +g_0c3f: + cw 0x00db + cw 0x03f7 + call send_back + + cw 0x009e + cw 0x8000 + call send_back + + cw 0x5600 + call send_back + +g_0c44: + cw 0x00fe + cw 0x03f5 + call send_back + + cw 0x1fda + call send_back + + cw 0x7c00 + call send_back + + cw 0x1f5e + call send_back + + cw 0x00fe + cw 0x03f2 + call send_back + + JMP g_0c52 +; cw 0x029f +; cw 0x0c52 +; call send_back + +g_0c4d: + + cw 0x00de + cw 0x03f4 + call send_back + + cw 0x5d00 + call send_back + + JLE g_0c3f +; cw 0x0293 +; cw 0x0c3f +; call send_back + +g_0c52: + cw 0x8900 + call send_back + + cw 0x00dd + cw 0x03f5 + call send_back + + cw 0x1501 + call send_back + + cw 0x8100 + call send_back + + cw 0x00dc + cw 0x03f6 + call send_back + + cw 0x008b + cw 0x009f + call send_back + + cw 0x0080 + cw 0x0a00 + call send_back + + cw 0x0900 + call send_back + + BLOOPI #0x50, g_0c65 +; cw 0x1150 +; cw 0x0c65 +; call send_back + + + cw 0x1878 + call send_back + + cw 0x4c00 + call send_back + + cw 0x1cfe + call send_back + + cw 0x001f + call send_back + + cw 0x1fd9 + call send_back +g_0c65: + cw 0x1b18 + call send_back + + cw 0x009f + cw 0x0a60 + call send_back + + cw 0x1fc3 + call send_back + + cw 0x5c00 + call send_back + + cw 0x00fe + cw 0x03f1 + call send_back + + cw 0x00fc + cw 0x03f6 + call send_back + + cw 0x008b + cw 0xffff + call send_back + + + +ende: + + nop + nop + nop + nop + nop + nop + nop + + + +dead_loop: + jmp dead_loop + +do_dma: + sr @DSMAH, $r1c + sr @DSMAL, $r1e + sr @DSPA, $r18 + sr @DSCR, $r19 + sr @DSBL, $r1a +wait_dma: + LRS $ACL1, @DSCR + andf $acl1, #0x0004 + JNZ wait_dma + RET + + +wait_for_dsp_mbox: + lrs $ACL1, @DMBH + andf $acl1, #0x8000 + jnz wait_for_dsp_mbox + ret + +wait_for_cpu_mbox: + lrs $ACL1, @cmbh + andcf $acl1, #0x8000 + jlnz wait_for_cpu_mbox + ret + +irq0: + lri $acl0, #0x0000 + jmp irq +irq1: + lri $acl0, #0x0001 + jmp irq +irq2: + lri $acl0, #0x0002 + jmp irq + +irq3: + lri $acl0, #0x0003 + jmp irq +irq4: + lri $acl0, #0x0004 + jmp irq +irq5: +; jmp finale + s40 + mrr $r0d, $r1c + mrr $r0d, $r1e + clr $acc0 + mrr $r1e, $r0d + mrr $r1c, $r0d + nop + nop + nop + nop + nop + nop + rti + + lri $acl0, #0x0005 + jmp irq +irq6: + lri $acl0, #0x0006 + jmp irq +irq7: + lri $acl0, #0x0007 + jmp irq + +irq: + lrs $ACL1, @DMBH + andf $acl1, #0x8000 + jnz irq + si @DMBH, #0x8BAD + sr @DMBL, $r0b +;sr @DMBL, $acl0 + si @DIRQ, #0x0001 + halt + + + + +send_back: + + ; store registers to reg table + sr @REGS_BASE, $r00 + lri $r00, #(REGS_BASE + 1) + srri @$r00, $r01 + srri @$r00, $r02 + srri @$r00, $r03 + srri @$r00, $r04 + srri @$r00, $r05 + srri @$r00, $r06 + srri @$r00, $r07 + srri @$r00, $r08 + srri @$r00, $r09 + srri @$r00, $r0a + srri @$r00, $r0b + srri @$r00, $r0c + srri @$r00, $r0d + srri @$r00, $r0e + srri @$r00, $r0f + srri @$r00, $r10 + srri @$r00, $r11 + srri @$r00, $r12 + srri @$r00, $r13 + srri @$r00, $r14 + srri @$r00, $r15 + srri @$r00, $r16 + srri @$r00, $r17 + srri @$r00, $r18 + srri @$r00, $r19 + srri @$r00, $r1a + srri @$r00, $r1b + srri @$r00, $r1c + srri @$r00, $r1d + srri @$r00, $r1e + srri @$r00, $r1f + + + lri $r18, #0x0000 + lri $r19, #1 ;(DSP_CR_IMEM | DSP_CR_TO_CPU) + lri $r1a, #0x200 + lr $r1c, @MEM_HI + lr $r1e, @MEM_LO + + lri $r01, #8+8 + + bloop $r01, dma_copy + call do_dma + addi $r1e, #0x200 + mrr $r1f, $r18 + addi $r1f, #0x100 + mrr $r18, $r1f + nop +dma_copy: + nop + + call wait_for_dsp_mbox + si @DMBH, #0x8888 + si @DMBL, #0xfeeb + si @DIRQ, #0x0001 + +; wait for answer before we execute the next op + call wait_for_cpu_mbox + lrs $ACL0, @CMBL + andi $acl1, #0x7fff + + + + lri $r00, #REGS_BASE+1 + lrri $r01, @$r00 + lrri $r02, @$r00 + lrri $r03, @$r00 + lrri $r04, @$r00 + lrri $r05, @$r00 + lrri $r06, @$r00 + lrri $r07, @$r00 + lrri $r08, @$r00 + lrri $r09, @$r00 + lrri $r0a, @$r00 + lrri $r0b, @$r00 + lrri $r0c, @$r00 + lrri $r0d, @$r00 + lrri $r0e, @$r00 + lrri $r0f, @$r00 + lrri $r10, @$r00 + lrri $r11, @$r00 + lrri $r12, @$r00 + lrri $r13, @$r00 + lrri $r14, @$r00 + lrri $r15, @$r00 + lrri $r16, @$r00 + lrri $r17, @$r00 + lrri $r18, @$r00 + lrri $r19, @$r00 + lrri $r1a, @$r00 + lrri $r1b, @$r00 + lrri $r1c, @$r00 + lrri $r1d, @$r00 + lrri $r1e, @$r00 + lrri $r1f, @$r00 + lr $r00, @REGS_BASE + + ret + +send_back_16: + + cw 0x8e00 + call send_back + cw 0x8f00 + + ret + + +dump_memory: + + lri $r02, #0x0000 + lri $acl0, #0x1000 + + lri $r01, #0x1000 + bloop $r01, _fill_loop2 + + mrr $r03, $acl0 + cw 0x80f0 + + mrr $r1f, $r00 + mrr $r00, $r02 + srri @$r00, $r1b + mrr $r02, $r00 + mrr $r00, $r1f + + addis $acc0, #0x1 + +_fill_loop2: + nop + + +ret diff --git a/Source/DSPTool/Testdata/dsp_test.bin b/Source/DSPTool/Testdata/dsp_test.bin new file mode 100644 index 0000000000..4726300d23 Binary files /dev/null and b/Source/DSPTool/Testdata/dsp_test.bin differ diff --git a/Source/DSPTool/Testdata/hermes.bin b/Source/DSPTool/Testdata/hermes.bin new file mode 100644 index 0000000000..0f6f9dd42a Binary files /dev/null and b/Source/DSPTool/Testdata/hermes.bin differ diff --git a/Source/DSPTool/Testdata/hermes.s b/Source/DSPTool/Testdata/hermes.s new file mode 100644 index 0000000000..5bef82eb8c --- /dev/null +++ b/Source/DSPTool/Testdata/hermes.s @@ -0,0 +1,1099 @@ +/* DSP_MIXER -> PCM VOICE SOFTWARE PROCESSOR (8-16 Bits Mono/Stereo Voices) + +// Thanks to Duddie for you hard work and documentation + +Copyright (c) 2008 Hermes +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are +permitted provided that the following conditions are met: + +- Redistributions of source code must retain the above copyright notice, this list of + conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright notice, this list + of conditions and the following disclaimer in the documentation and/or other + materials provided with the distribution. +- The names of the contributors may not be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + + +/********************************/ +/** REGISTER NAMES **/ +/********************************/ + +AR0: equ 0x00 ; address registers +AR1: equ 0x01 +AR2: equ 0x02 +AR3: equ 0x03 // used as jump function selector + +IX0: equ 0x04 // LEFT_VOLUME accel +IX1: equ 0x05 // RIGHT_VOLUME accel +IX2: equ 0x06 // ADDRH_SMP accel +IX3: equ 0x07 // ADDRL_SMP accel + +R08: equ 0x08 // fixed to 48000 value +R09: equ 0x09 // problems using this +R0A: equ 0x0a // ADDREH_SMP accel +R0B: equ 0x0b // ADDREL_SMP accel + +ST0: equ 0x0c +ST1: equ 0x0d +ST2: equ 0x0e +ST3: equ 0x0f + +CONFIG: equ 0x12 +SR: equ 0x13 + +PRODL: equ 0x14 +PRODM: equ 0x15 +PRODH: equ 0x16 +PRODM2: equ 0x17 + +AXL0: equ 0x18 +AXL1: equ 0x19 +AXH0: equ 0x1A // SMP_R accel +AXH1: equ 0x1b // SMP_L accel + +ACC0: equ 0x1c // accumulator (global) +ACC1: equ 0x1d + +ACL0: equ 0x1c // Low accumulator +ACL1: equ 0x1d +ACM0: equ 0x1e // Mid accumulator +ACM1: equ 0x1f +ACH0: equ 0x10 // Sign extended 8 bit register 0 +ACH1: equ 0x11 // Sign extended 8 bit register 1 + +/********************************/ +/** HARDWARE REGISTER ADDRESS **/ +/********************************/ + +DSCR: equ 0xffc9 ; DSP DMA Control Reg +DSBL: equ 0xffcb ; DSP DMA Block Length +DSPA: equ 0xffcd ; DSP DMA DMEM Address +DSMAH: equ 0xffce ; DSP DMA Mem Address H +DSMAL: equ 0xffcf ; DSP DMA Mem Address L + +DIRQ: equ 0xfffb ; DSP Irq Request +DMBH: equ 0xfffc ; DSP Mailbox H +DMBL: equ 0xfffd ; DSP Mailbox L +CMBH: equ 0xfffe ; CPU Mailbox H +CMBL: equ 0xffff ; CPU Mailbox L + +DMA_TO_DSP: equ 0 +DMA_TO_CPU: equ 1 + +/**************************************************************/ +/* NUM_SAMPLES SLICE */ +/**************************************************************/ + +NUM_SAMPLES: equ 1024 ; 1024 stereo samples 16 bits + + +/**************************************************************/ +/* SOUND CHANNEL REGS */ +/**************************************************************/ + +MEM_REG2: equ 0x0 +MEM_VECTH: equ MEM_REG2 +MEM_VECTL: equ MEM_REG2+1 +RETURN: equ MEM_REG2+2 + +/**************************************************************/ +/* CHANNEL DATAS */ +/**************************************************************/ + +MEM_REG: equ MEM_REG2+0x10 + +ADDRH_SND: equ MEM_REG // Output buffer +ADDRL_SND: equ MEM_REG+1 + +DELAYH_SND: equ MEM_REG+2 // Delay samples High word +DELAYL_SND: equ MEM_REG+3 // Delay samples Low word + +CHAN_REGS: equ MEM_REG+4 // specific regs for the channel + +FLAGSH_SMP: equ CHAN_REGS+0 // countain number of bytes for step (1-> Mono 8 bits, 2-> Stereo 8 bits and Mono 16 bits, 4-> Stereo 16 bits) +FLAGSL_SMP: equ CHAN_REGS+1 // 0->Mono 8 bits, 1->Stereo 8 bits, 2->Mono 16 bits 3 -> Stereo 16 bits + +ADDRH_SMP: equ CHAN_REGS+2 // start address +ADDRL_SMP: equ CHAN_REGS+3 + +ADDREH_SMP: equ CHAN_REGS+4 // end address +ADDREL_SMP: equ CHAN_REGS+5 + +FREQH_SMP: equ CHAN_REGS+6 // Freq in Hz to play +FREQL_SMP: equ CHAN_REGS+7 + +SMP_L: equ CHAN_REGS+8 // last sample for left (used to joint various buffers) +SMP_R: equ CHAN_REGS+9 // last sample for right (used to joint various buffers) + +COUNTERH_SMP: equ CHAN_REGS+10 // pitch counter +COUNTERL_SMP: equ CHAN_REGS+11 + +LEFT_VOLUME: equ CHAN_REGS+12 // volume (0 to 255) +RIGHT_VOLUME: equ CHAN_REGS+13 + +ADDR2H_SMP: equ CHAN_REGS+14 // start address of buffer two (to joint) +ADDR2L_SMP: equ CHAN_REGS+15 + +ADDR2EH_SMP: equ CHAN_REGS+16 // end address of buffer two (to joint) +ADDR2EL_SMP: equ CHAN_REGS+17 + +LEFT_VOLUME2: equ CHAN_REGS+18 // volume (0 to 255) for buffer two +RIGHT_VOLUME2: equ CHAN_REGS+19 + +BACKUPH_SMP: equ CHAN_REGS+20 // start address backup +BACKUPL_SMP: equ CHAN_REGS+21 + +/**************************************************************/ +/* VOICE SAMPLE BUFFER DATAS */ +/**************************************************************/ + +MEM_SAMP: equ CHAN_REGS+0x20 + + +data_end: equ MEM_SAMP+0x20 + +/**************************************************************/ +/* SND OUTPUT DATAS */ +/**************************************************************/ + +MEM_SND: equ data_end ; it need 2048 words (4096 bytes) + + + +/*** START CODE ***/ + +/**************************************************************/ +/* EXCEPTION TABLE */ +/**************************************************************/ + + jmp exception0 + jmp exception1 + jmp exception2 + jmp exception3 + jmp exception4 + jmp exception5 + jmp exception6 + jmp exception7 + + lri $CONFIG, #0xff + lri $SR,#0 + s40 + clr15 + m0 + +/**************************************************************/ +/* main */ +/**************************************************************/ + +main: + +// send init token to CPU + + si @DMBH, #0xdcd1 + si @DMBL, #0x0000 + si @DIRQ, #1 + +recv_cmd: +// check if previous mail is received from the CPU + + call wait_for_dsp_mail + +// wait a mail from CPU + + call wait_for_cpu_mail + + si @DMBH, #0xdcd1 + + clr $ACC0 + lri $ACM0,#0xcdd1 + cmp + jz sys_command + + clr $ACC1 + lrs $ACM1, @CMBL + + cmpi $ACM1, #0x111 // fill the internal sample buffer and process the voice internally + jz input_samples + + cmpi $ACM1, #0x112 // get samples from the external buffer to the internal buffer and process the voice mixing the samples internally + jz input_samples2 + + cmpi $ACM1, #0x123 // get the address of the voice datas buffer (CHANNEL DATAS) + jz get_data_addr + + cmpi $ACM1, #0x222 // process the voice mixing the samples internally + jz input_next_samples + + cmpi $ACM1, #0x666 // send the samples for the internal buffer to the external buffer + jz send_samples + + cmpi $ACM1, #0x777 // special: to dump the IROM Datas (remember disable others functions from the interrupt vector to use) + jz rom_dump_word // (CMBH+0x8000) countain the address of IROM + + cmpi $ACM1, #0x888 // Used for test + jz polla_loca + + cmpi $ACM1, #0x999 + jz task_terminate + + si @DMBL, #0x0004 // return 0 as ignore command + si @DIRQ, #0x1 // set the interrupt + jmp recv_cmd + +task_terminate: + si @DMBL, #0x0003 + si @DIRQ, #0x1 + jmp recv_cmd + +sys_command: + clr $ACC1 + lrs $ACM1, @CMBL + + cmpi $ACM1,#0x0001 + jz run_nexttask + + cmpi $ACM1,#0x0002 + jz 0x8000 + + jmp recv_cmd + +run_nexttask: + s40 + call wait_for_cpu_mail + lrs $29,@CMBL + call wait_for_cpu_mail + lrs $29,@CMBL + call wait_for_cpu_mail + lrs $29,@CMBL + call wait_for_cpu_mail + lr $5,@CMBL + andi $31,#0x0fff + mrr $4,$31 + call wait_for_cpu_mail + lr $7,@CMBL + call wait_for_cpu_mail + lr $6,@CMBL + call wait_for_cpu_mail + lr $0,@CMBL + call wait_for_cpu_mail + lrs $24,@CMBL + andi $31,#0x0fff + mrr $26,$31 + call wait_for_cpu_mail + lrs $25,@CMBL + call wait_for_cpu_mail + lrs $27,@CMBL + sbclr #0x05 + sbclr #0x06 + jmp 0x80b5 + halt + +/**************************************************************************************************************************************/ +// send the samples for the internal buffer to the external buffer + +send_samples: + + lri $AR0, #MEM_SND + lris $AXL1, #DMA_TO_CPU; + lri $AXL0, #NUM_SAMPLES*4 ; len + lr $ACM0, @ADDRH_SND + lr $ACL0, @ADDRL_SND + + call do_dma + si @DMBL, #0x0004 + si @DIRQ, #0x1 // set the interrupt + jmp recv_cmd + +/**************************************************************************************************************************************/ +// get the address of the voice datas buffer (CHANNEL DATAS) + +get_data_addr: + call wait_for_cpu_mail + + lrs $ACM0, @CMBH + lr $ACL0, @CMBL + + sr @MEM_VECTH, $ACM0 + sr @MEM_VECTL, $ACL0 + + si @DIRQ, #0x0 // clear the interrupt + jmp recv_cmd + +/**************************************************************************************************************************************/ +// fill the internal sample buffer and process the voice internally + +input_samples: + + clr $ACC0 + lr $ACM0, @MEM_VECTH + lr $ACL0, @MEM_VECTL + + lris $AXL0, #0x0004 + sr @RETURN, $AXL0 + si @DIRQ, #0x0000 + + // program DMA to get datas + + lri $AR0, #MEM_REG + lris $AXL1, #DMA_TO_DSP + lris $AXL0, #64 ; len + + call do_dma + + lri $AR1, #MEM_SND + lri $ACL1, #0; + + lri $AXL0, #NUM_SAMPLES + bloop $AXL0, loop_get1 + + srri @$AR1, $ACL1 + srri @$AR1, $ACL1 + +loop_get1: + nop + + lr $ACM0, @ADDRH_SND + lr $ACL0, @ADDRL_SND + jmp start_main + +/**************************************************************************************************************************************/ +// get samples from the external buffer to the internal buffer and process the voice mixing the samples internally + +input_samples2: + + clr $ACC0 + lr $ACM0, @MEM_VECTH + lr $ACL0, @MEM_VECTL + + lris $AXL0, #0x0004 + sr @RETURN, $AXL0 + si @DIRQ, #0x0000 + + // program DMA to get datas + + lri $AR0, #MEM_REG + lri $AXL1, #DMA_TO_DSP + lris $AXL0, #64 ; len + + call do_dma + + lr $ACM0, @ADDRH_SND + lr $ACL0, @ADDRL_SND + + lri $AR0, #MEM_SND + lris $AXL1, #DMA_TO_DSP; + lri $AXL0, #NUM_SAMPLES*4; len + + call do_dma + + jmp start_main + +/**************************************************************************************************************************************/ +// process the voice mixing the samples internally + +input_next_samples: + + clr $ACC0 + lr $ACM0, @MEM_VECTH + lr $ACL0, @MEM_VECTL + + lris $AXL0, #0x0004 + sr @RETURN, $AXL0 + si @DIRQ, #0x0000 + + // program DMA to get datas + + lri $AR0, #MEM_REG + lris $AXL1, #DMA_TO_DSP + lris $AXL0, #64 ; len + + call do_dma + +/**************************************************************************************************************************************/ +// mixing and control pitch to create 1024 Stereo Samples at 16 bits from here + +start_main: + + lri $R08, #48000 + + // load the previous samples used + + lr $AXH0, @SMP_R + lr $AXH1, @SMP_L + +// optimize the jump function to get MONO/STEREO 8/16 bits samples + + lr $ACM1, @FLAGSL_SMP + andi $ACM1, #0x3 + addi $ACM1, #sample_selector + mrr $AR3, $ACM1 + ilrr $ACM1, @$AR3 + mrr $AR3, $ACM1 // AR3 countain the jump loaded from sample selector + + clr $ACC0 + +// test for channel paused + + lr $ACM0, @FLAGSL_SMP + andcf $ACM0, #0x20 + jlz end_main + +// load the sample address + + lr $ACM0, @ADDRH_SMP + lr $ACL0, @ADDRL_SMP + +// test if ADDR_SMP & ADDR2H_SMP are zero + + tst $ACC0 + jnz do_not_change1 + +// set return as "change of buffer" + + lris $AXL0, #0x0004 + sr @RETURN, $AXL0 + +// change to buffer 2 if it is possible + + call change_buffer + +// stops if again 0 address + + tst $ACC0 + jz save_datas_end + +do_not_change1: + + +// backup the external sample address + + mrr $IX2, $ACM0 + mrr $IX3, $ACL0 + + +// load the counter pitch + + //lr $r08, @COUNTERH_SMP + //lr $r09, @COUNTERL_SMP + +// load the end address of the samples + + lr $r0a, @ADDREH_SMP + lr $r0b, @ADDREL_SMP + +// load AR1 with internal buffer address + + lri $AR1, #MEM_SND + +///////////////////////////////////// +// delay time section +///////////////////////////////////// + +// load AXL0 with the samples to be processed + + lri $AXL0, #NUM_SAMPLES + +// test if DELAY == 0 and skip or not + + clr $ACC0 + clr $ACC1 + lr $ACH0, @DELAYH_SND + lr $ACM0, @DELAYL_SND + tst $ACC0 + jz no_delay + +// samples left and right to 0 + + lris $AXH0, #0 + lris $AXH1, #0 + +// load the samples to be processed in ACM1 + + mrr $ACM1, $AXL0 +l_delay: + iar $AR1 // skip two samples + iar $AR1 + decm $ACM1 + jz exit_delay1 // exit1 if samples to be processed == 0 + + decm $ACM0 + jz exit_delay2 // exit2 if delay time == 0 + jmp l_delay + +// store the remanent delay and ends + +exit_delay1: + decm $ACM0 + + sr @DELAYH_SND, $ACH0 + sr @DELAYL_SND, $ACM0 + + lris $AXL0,#0 ; exit from loop + + jmp no_delay + + +exit_delay2: + + // store delay=0 and continue + + sr @DELAYH_SND, $ACH0 + sr @DELAYL_SND, $ACM0 + mrr $AXL0, $ACL1 // load remanent samples to be processed in AXL0 + +no_delay: + +///////////////////////////////////// +// end of delay time section +///////////////////////////////////// + +/* bucle de generacion de samples */ + + +// load the sample buffer with address aligned to 32 bytes blocks (first time) + + si @DSCR, #DMA_TO_DSP // very important!: load_smp_addr_align and jump_load_smp_addr need fix this DMA Register (I gain some cycles so) + +// load_smp_addr_align input: $IX2:$IX3 + + call load_smp_addr_align + +// load the volume registers + + lr $IX0, @LEFT_VOLUME + lr $IX1, @RIGHT_VOLUME + +// test the freq value + + clr $ACL0 + lr $ACH0, @FREQH_SMP + lr $ACM0, @FREQL_SMP + + clr $ACC1 + ;lri $ACM1,#48000 + mrr $ACM1, $R08 + cmp + +// select the output of the routine to process stereo-mono 8/16bits samples + + lri $AR0, #get_sample // fast method <=48000 + +// if number is greater freq>48000 fix different routine + + ifg + lri $AR0, #get_sample2 // slow method >48000 + +// loops for samples to be processed + + bloop $AXL0, loop_end + + //srri @$AR1, $AXH0 // put sample R + //srri @$AR1, $AXH1 // put sample L + +// Mix right sample section + + lrr $ACL0, @$AR1 // load in ACL0 the right sample from the internal buffer + movax $ACC1, $AXL1 // big trick :) load the current sample <<16 and sign extended + + asl $ACC0,#24 // convert sample from buffer to 24 bit number with sign extended (ACH0:ACM0) + asr $ACC0,#-8 + + add $ACC0,$ACC1 // current_sample+buffer sample + + cmpi $ACM0,#32767 // limit to 32767 + jle right_skip + + lri $ACM0, #32767 + jmp right_skip2 + +right_skip: + + cmpi $ACM0,#-32768 // limit to -32768 + ifle + lri $ACM0, #-32768 + +right_skip2: + + srri @$AR1, $ACM0 // store the right sample mixed to the internal buffer and increment AR1 + +// Mix left sample section + + lrr $ACL0, @$AR1 // load in ACL0 the left sample from the internal buffer + + movax $ACC1, $AXL0 // big trick :) load the current sample <<16 and sign extended + + asl $ACC0, #24 // convert sample from buffer to 24 bit number with sign extended (ACH0:ACM0) + asr $ACC0, #-8 + + add $ACC0, $ACC1 // current_sample+buffer sample + + cmpi $ACM0,#32767 // limit to 32767 + jle left_skip + + lri $ACM0, #32767 + jmp left_skip2 + +left_skip: + + cmpi $ACM0,#-32768 // limit to -32768 + ifle + lri $ACM0, #-32768 + +left_skip2: + + srri @$AR1, $ACM0 // store the left sample mixed to the internal buffer and increment AR1 + +// adds the counter with the voice frequency and test if it >=48000 to get the next sample + + clr $ACL1 + lr $ACH1, @COUNTERH_SMP + lr $ACM1, @COUNTERL_SMP + clr $ACL0 + lr $ACH0, @FREQH_SMP + lr $ACM0, @FREQL_SMP + + add $ACC1,$ACC0 + clr $ACC0 + //lri $ACM0,#48000 + mrr $ACM0, $R08 + + cmp + + jrl $AR0 //get_sample or get_sample2 method + + sr @COUNTERH_SMP, $ACH1 + sr @COUNTERL_SMP, $ACM1 + + jmp loop_end + +// get a new sample for freq > 48000 Hz + +get_sample2: // slow method + + sub $ACC1,$ACC0 // restore the counter + +// restore the external sample buffer address + + clr $ACC0 + mrr $ACM0, $IX2 // load ADDRH_SMP + mrr $ACL0, $IX3 // load ADDRL_SMP + + lr $AXL1, @FLAGSH_SMP // add the step to get the next samples + addaxl $ACC0, $AXL1 + + mrr $IX2, $ACM0 // store ADDRH_SMP + mrr $IX3, $ACL0 // store ADDRL_SMP + + mrr $ACM0, $ACL0 + andf $ACM0, #0x1f + +// load_smp_addr_align input: $IX2:$IX3 call if (ACM0 & 0x1f)==0 + + calllz load_smp_addr_align + + clr $ACC0 + //lri $ACM0,#48000 + mrr $ACM0, $R08 + + cmp + + jle get_sample2 + + sr @COUNTERH_SMP, $ACH1 + sr @COUNTERL_SMP, $ACM1 + + mrr $ACM0, $IX2 // load ADDRH_SMP + mrr $ACL0, $IX3 // load ADDRL_SMP + + clr $ACC1 + mrr $ACM1, $r0a // load ADDREH_SMP + mrr $ACL1, $r0b // load ADDREL_SMP + +// compares if the current address is >= end address to change the buffer or stops + + cmp + +// if addr>addr end get a new buffer (if you uses double buffer) + + jge get_new_buffer + +// load samples from dma, return $ar2 with the addr to get the samples and return using $ar0 to the routine to process 8-16bits Mono/Stereo + + jmp jump_load_smp_addr + +// get a new sample for freq <= 48000 Hz + +get_sample: // fast method + + sub $ACC1,$ACC0 // restore the counter + sr @COUNTERH_SMP, $ACH1 + sr @COUNTERL_SMP, $ACM1 + +// restore the external sample buffer address + + clr $ACC0 + mrr $ACM0, $IX2 // load ADDRH_SMP + mrr $ACL0, $IX3 // load ADDRL_SMP + + lr $AXL1, @FLAGSH_SMP // add the step to get the next samples + addaxl $ACC0, $AXL1 + + clr $ACC1 + mrr $ACM1, $r0a // load ADDREH_SMP + mrr $ACL1, $r0b // load ADDREL_SMP + +// compares if the current address is >= end address to change the buffer or stops + + cmp + jge get_new_buffer + +// load the new sample from the buffer + + mrr $IX2, $ACM0 // store ADDRH_SMP + mrr $IX3, $ACL0 // store ADDRL_SMP + +// load samples from dma, return $ar2 with the addr and return using $ar0 to the routine to process 8-16bits Mono/Stereo or addr_get_sample_again + + jmp jump_load_smp_addr + +sample_selector: + cw mono_8bits + cw mono_16bits + cw stereo_8bits + cw stereo_16bits + +get_new_buffer: + +// set return as "change of buffer": it need to change the sample address + + lris $AXL0, #0x0004 + sr @RETURN, $AXL0 + + call change_buffer // load add from addr2 + +// addr is 0 ? go to zero_samples and exit + + tst $acc0 + jz zero_samples + +// load_smp_addr_align input: $IX2:$IX3 + + call load_smp_addr_align // force the load the samples cached (address aligned) + +// jump_load_smp_addr: $IX2:$IX3 +// load samples from dma, return $ar2 with the addr to get the samples and return using $ar0 to the routine to process 8-16bits Mono/Stereo + + jmp jump_load_smp_addr + +// set to 0 the current samples + +zero_samples: + + lris $AXH0, #0 + lris $AXH1, #0 + jmp out_samp + +mono_8bits: + +// 8 bits mono + mrr $ACM1, $IX3 + lrri $ACL0, @$AR2 + andf $ACM1, #0x1 + + iflz // obtain sample0-sample1 from 8bits packet + asr $ACL0, #-8 + asl $ACL0, #8 + + mrr $AXH1,$ACL0 + mrr $AXH0,$ACL0 + jmp out_samp + +stereo_8bits: + +// 8 bits stereo + + lrri $ACL0, @$AR2 + mrr $ACM0, $ACL0 + andi $ACM0, #0xff00 + mrr $AXH1, $ACM0 + lsl $ACL0, #8 + mrr $AXH0, $ACL0 + + jmp out_samp + +mono_16bits: + +// 16 bits mono + + lrri $AXH1, @$AR2 + mrr $AXH0,$AXH1 + jmp out_samp + +stereo_16bits: + +// 16 bits stereo + + lrri $AXH1, @$AR2 + lrri $AXH0, @$AR2 + +out_samp: + +// multiply sample x volume + + // LEFT_VOLUME + mrr $AXL0,$IX0 + mul $AXL0,$AXH0 + movp $ACL0 + asr $ACL0,#-8 + mrr $AXH0, $ACL0 + + // RIGHT VOLUME + mrr $AXL1,$IX1 + mul $AXL1,$AXH1 + movp $ACL0 + asr $ACL0,#-8 + mrr $AXH1, $ACL0 + +loop_end: + nop + +end_process: + + // load the sample address + + clr $ACC0 + mrr $ACM0, $IX2 + mrr $ACL0, $IX3 + + tst $ACC0 + jnz save_datas_end + +// set return as "change of buffer" + + lris $AXL0, #0x0004 + sr @RETURN, $AXL0 + +// change to buffer 2 if it is possible + + call change_buffer + +save_datas_end: + + sr @ADDRH_SMP, $IX2 + sr @ADDRL_SMP, $IX3 + sr @SMP_R, $AXH0 + sr @SMP_L, $AXH1 + +end_main: + +// program DMA to send the CHANNEL DATAS changed + + clr $ACC0 + lr $ACM0, @MEM_VECTH + lr $ACL0, @MEM_VECTL + + lri $AR0, #MEM_REG + lris $AXL1, #DMA_TO_CPU + lris $AXL0, #64 ; len + + call do_dma + + si @DMBH, #0xdcd1 + lr $ACL0, @RETURN + + sr @DMBL, $ACL0 + si @DIRQ, #0x1 // set the interrupt + + jmp recv_cmd + +change_buffer: + + clr $ACC0 + lr $ACM0, @LEFT_VOLUME2 + lr $ACL0, @RIGHT_VOLUME2 + sr @LEFT_VOLUME, $ACM0 + sr @RIGHT_VOLUME, $ACL0 + mrr $IX0, $ACM0 + mrr $IX1, $ACL0 + + lr $ACM0, @ADDR2EH_SMP + lr $ACL0, @ADDR2EL_SMP + sr @ADDREH_SMP, $ACM0 + sr @ADDREL_SMP, $ACL0 + mrr $r0a, $ACM0 + mrr $r0b, $ACL0 + + lr $ACM0, @ADDR2H_SMP + lr $ACL0, @ADDR2L_SMP + sr @ADDRH_SMP, $ACM0 + sr @ADDRL_SMP, $ACL0 + sr @BACKUPH_SMP, $ACM0 + sr @BACKUPL_SMP, $ACL0 + mrr $IX2, $ACM0 + mrr $IX3, $ACL0 + + lr $ACM1, @FLAGSL_SMP + andcf $ACM1, #0x4 + retlz + + sr @ADDR2H_SMP, $ACH0 + sr @ADDR2L_SMP, $ACH0 + sr @ADDR2EH_SMP, $ACH0 + sr @ADDR2EL_SMP, $ACH0 + ret + +/**************************************************************/ +/* DMA ROUTINE */ +/**************************************************************/ + +do_dma: + + sr @DSMAH, $ACM0 + sr @DSMAL, $ACL0 + sr @DSPA, $AR0 + sr @DSCR, $AXL1 + sr @DSBL, $AXL0 + +wait_dma: + + lrs $ACM1, @DSCR + andcf $ACM1, #0x4 + jlz wait_dma + ret + + +wait_for_dsp_mail: + + lrs $ACM1, @DMBH + andf $ACM1, #0x8000 + jnz wait_for_dsp_mail + ret + +wait_for_cpu_mail: + + lrs $ACM1, @cmbh + andcf $ACM1, #0x8000 + jlnz wait_for_cpu_mail + ret + +load_smp_addr_align: + + mrr $ACL0, $IX3 // load ADDRL_SMP + + lsr $ACC0, #-5 + lsl $ACC0, #5 + sr @DSMAH, $IX2 + sr @DSMAL, $ACL0 + si @DSPA, #MEM_SAMP + ;si @DSCR, #DMA_TO_DSP + si @DSBL, #0x20 + +wait_dma1: + lrs $ACM0, @DSCR + andcf $ACM0, #0x4 + jlz wait_dma1 + + lri $AR2, #MEM_SAMP + ret + + +////////////////////////////////////////// + +jump_load_smp_addr: + + mrr $ACM0, $IX3 // load ADDRL_SMP + asr $ACC0, #-1 + andi $ACM0, #0xf + jz jump_load_smp_dma + + addi $ACM0, #MEM_SAMP + mrr $AR2, $ACM0 + jmpr $AR3 + +jump_load_smp_dma: + + sr @DSMAH, $IX2 + sr @DSMAL, $IX3 + si @DSPA, #MEM_SAMP + ;si @DSCR, #DMA_TO_DSP // to gain some cycles + si @DSBL, #0x20 + +wait_dma2: + lrs $ACM0, @DSCR + andcf $ACM0, #0x4 + jlz wait_dma2 + + lri $AR2, #MEM_SAMP + jmpr $AR3 + +// exception table + +exception0: // RESET + rti + +exception1: // STACK OVERFLOW + rti + +exception2: + rti + +exception3: + rti + +exception4: + rti + +exception5: // ACCELERATOR ADDRESS OVERFLOW + rti + +exception6: + rti + +exception7: + rti + +// routine to read a word of the IROM space + +rom_dump_word: + + clr $ACC0 + + lr $ACM0, @CMBH + ori $ACM0, #0x8000 + mrr $AR0, $ACM0 + clr $ACC0 + ilrr $ACM0, @$AR0 + sr @DMBH, $ACL0 + sr @DMBL, $ACM0 + ;si @DIRQ, #0x1 // set the interrupt + clr $ACC0 + jmp recv_cmd + +polla_loca: + + clr $ACC0 + lri $acm0, #0x0 + andf $acm0,#0x1 + + sr @DMBH, $sr + sr @DMBL, $acm0 + ;si @DIRQ, #0x1 // set the interrupt + clr $ACC0 + jmp recv_cmd + + diff --git a/Source/Plugins/Plugin_DSP_LLE/Src/Debugger/DSPRegisterView.cpp b/Source/Plugins/Plugin_DSP_LLE/Src/Debugger/DSPRegisterView.cpp index 711ba5cfe3..6fef8b8937 100644 --- a/Source/Plugins/Plugin_DSP_LLE/Src/Debugger/DSPRegisterView.cpp +++ b/Source/Plugins/Plugin_DSP_LLE/Src/Debugger/DSPRegisterView.cpp @@ -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(""); } diff --git a/Source/Plugins/Plugin_DSP_LLE/Src/Debugger/Debugger.cpp b/Source/Plugins/Plugin_DSP_LLE/Src/Debugger/Debugger.cpp index c036f15db4..79b72288f5 100644 --- a/Source/Plugins/Plugin_DSP_LLE/Src/Debugger/Debugger.cpp +++ b/Source/Plugins/Plugin_DSP_LLE/Src/Debugger/Debugger.cpp @@ -221,7 +221,7 @@ void DSPDebuggerLLE::RebuildDisAsmListView() AssemblerSettings settings; DSPDisassembler disasm(settings); std::string op_str; - disasm.DisOpcode(binbuf, &settings.pc, &op_str); + disasm.DisOpcode(binbuf, 2, &settings.pc, &op_str); const char* pParameter = NULL; const char* pExtension = NULL; diff --git a/Source/Plugins/Plugin_DSP_LLE/Src/Tools.cpp b/Source/Plugins/Plugin_DSP_LLE/Src/Tools.cpp index 0d1cb2ea2a..a60a25b195 100644 --- a/Source/Plugins/Plugin_DSP_LLE/Src/Tools.cpp +++ b/Source/Plugins/Plugin_DSP_LLE/Src/Tools.cpp @@ -53,7 +53,7 @@ bool DumpDSPCode(const u8 *code_be, int size_in_bytes, u32 crc) AssemblerSettings settings; settings.show_hex = true; settings.show_pc = true; - settings.ext_separator = '\t'; + settings.ext_separator = '\''; settings.decode_names = true; settings.decode_registers = true;