diff --git a/Source/Core/Core/DSP/DSPAssembler.cpp b/Source/Core/Core/DSP/DSPAssembler.cpp index 1a9d9aece5..25686013e0 100644 --- a/Source/Core/Core/DSP/DSPAssembler.cpp +++ b/Source/Core/Core/DSP/DSPAssembler.cpp @@ -429,33 +429,33 @@ u32 DSPAssembler::GetParams(char* parstr, param_t* par) return count; } -const opc_t* DSPAssembler::FindOpcode(const char* name, u32 par_count, const opc_t* const opcodes, - size_t opcodes_size) +const opc_t* DSPAssembler::FindOpcode(std::string name, size_t par_count, OpcodeType type) { if (name[0] == 'C' && name[1] == 'W') return &cw; const auto alias_iter = aliases.find(name); if (alias_iter != aliases.end()) - name = alias_iter->second.c_str(); - for (size_t i = 0; i < opcodes_size; i++) + name = alias_iter->second; + + const DSPOPCTemplate* const info = + type == OpcodeType::Primary ? FindOpInfoByName(name) : FindExtOpInfoByName(name); + if (!info) { - const opc_t* opcode = &opcodes[i]; - if (strcmp(opcode->name, name) == 0) - { - if (par_count < opcode->param_count) - { - ShowError(ERR_NOT_ENOUGH_PARAMETERS); - } - else if (par_count > opcode->param_count) - { - ShowError(ERR_TOO_MANY_PARAMETERS); - } - return opcode; - } + ShowError(ERR_UNKNOWN_OPCODE); + return nullptr; } - ShowError(ERR_UNKNOWN_OPCODE); - return nullptr; + + if (par_count < info->param_count) + { + ShowError(ERR_NOT_ENOUGH_PARAMETERS); + } + else if (par_count > info->param_count) + { + ShowError(ERR_TOO_MANY_PARAMETERS); + } + + return info; } // weird... @@ -466,7 +466,7 @@ static u16 get_mask_shifted_down(u16 mask) return mask; } -bool DSPAssembler::VerifyParams(const opc_t* opc, param_t* par, size_t count, bool ext) +bool DSPAssembler::VerifyParams(const opc_t* opc, param_t* par, size_t count, OpcodeType type) { for (size_t i = 0; i < count; i++) { @@ -495,7 +495,7 @@ bool DSPAssembler::VerifyParams(const opc_t* opc, param_t* par, size_t count, bo if ((int)par[i].val < value || (int)par[i].val > value + get_mask_shifted_down(opc->params[i].mask)) { - if (ext) + if (type == OpcodeType::Extension) fprintf(stderr, "(ext) "); fprintf(stderr, "%s (param %zu)", cur_line.c_str(), current_param); @@ -505,7 +505,7 @@ bool DSPAssembler::VerifyParams(const opc_t* opc, param_t* par, size_t count, bo case P_PRG: if ((int)par[i].val < 0 || (int)par[i].val > 0x3) { - if (ext) + if (type == OpcodeType::Extension) fprintf(stderr, "(ext) "); fprintf(stderr, "%s (param %zu)", cur_line.c_str(), current_param); @@ -515,7 +515,7 @@ bool DSPAssembler::VerifyParams(const opc_t* opc, param_t* par, size_t count, bo case P_ACC: if ((int)par[i].val < 0x20 || (int)par[i].val > 0x21) { - if (ext) + if (type == OpcodeType::Extension) fprintf(stderr, "(ext) "); if (par[i].val >= 0x1e && par[i].val <= 0x1f) @@ -523,7 +523,8 @@ bool DSPAssembler::VerifyParams(const opc_t* opc, param_t* par, size_t count, bo 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: %zu Ext: %d\n", - (par[i].val & 1), (par[i].val & 1), code_line, current_param, ext); + (par[i].val & 1), (par[i].val & 1), code_line, current_param, + static_cast(type)); } else if (par[i].val >= 0x1c && par[i].val <= 0x1d) { @@ -541,7 +542,7 @@ bool DSPAssembler::VerifyParams(const opc_t* opc, param_t* par, size_t count, bo case P_ACCM: if ((int)par[i].val < 0x1e || (int)par[i].val > 0x1f) { - if (ext) + if (type == OpcodeType::Extension) fprintf(stderr, "(ext) "); if (par[i].val >= 0x1c && par[i].val <= 0x1d) @@ -568,7 +569,7 @@ bool DSPAssembler::VerifyParams(const opc_t* opc, param_t* par, size_t count, bo case P_ACCL: if ((int)par[i].val < 0x1c || (int)par[i].val > 0x1d) { - if (ext) + if (type == OpcodeType::Extension) fprintf(stderr, "(ext) "); if (par[i].val >= 0x1e && par[i].val <= 0x1f) @@ -606,22 +607,22 @@ bool DSPAssembler::VerifyParams(const opc_t* opc, param_t* par, size_t count, bo switch (par[i].type & (P_REG | 7)) { case P_REG: - if (ext) + if (type == OpcodeType::Extension) fprintf(stderr, "(ext) "); ShowError(ERR_EXPECTED_PARAM_REG); break; case P_MEM: - if (ext) + if (type == OpcodeType::Extension) fprintf(stderr, "(ext) "); ShowError(ERR_EXPECTED_PARAM_MEM); break; case P_VAL: - if (ext) + if (type == OpcodeType::Extension) fprintf(stderr, "(ext) "); ShowError(ERR_EXPECTED_PARAM_VAL); break; case P_IMM: - if (ext) + if (type == OpcodeType::Extension) fprintf(stderr, "(ext) "); ShowError(ERR_EXPECTED_PARAM_IMM); break; @@ -973,13 +974,13 @@ bool DSPAssembler::AssembleFile(const std::string& file_path, int pass) continue; } - const opc_t* opc = FindOpcode(opcode, params_count, opcodes.data(), opcodes.size()); + const opc_t* opc = FindOpcode(opcode, params_count, OpcodeType::Primary); if (!opc) opc = &cw; opcode_size = opc->size; - VerifyParams(opc, params, params_count); + VerifyParams(opc, params, params_count, OpcodeType::Primary); const opc_t* opc_ext = nullptr; // Check for opcode extensions. @@ -987,11 +988,13 @@ bool DSPAssembler::AssembleFile(const std::string& file_path, int pass) { if (opcode_ext) { - opc_ext = FindOpcode(opcode_ext, params_count_ext, opcodes_ext.data(), opcodes_ext.size()); - VerifyParams(opc_ext, params_ext, params_count_ext, true); + opc_ext = FindOpcode(opcode_ext, params_count_ext, OpcodeType::Extension); + VerifyParams(opc_ext, params_ext, params_count_ext, OpcodeType::Extension); } else if (params_count_ext) + { ShowError(ERR_EXT_PAR_NOT_EXT); + } } else { diff --git a/Source/Core/Core/DSP/DSPAssembler.h b/Source/Core/Core/DSP/DSPAssembler.h index 85c46afdbe..183a4ef7ae 100644 --- a/Source/Core/Core/DSP/DSPAssembler.h +++ b/Source/Core/Core/DSP/DSPAssembler.h @@ -78,6 +78,12 @@ private: SEGMENT_MAX }; + enum class OpcodeType + { + Primary, + Extension + }; + // Utility functions s32 ParseValue(const char* str); u32 ParseExpression(const char* ptr); @@ -91,9 +97,8 @@ private: // void ShowWarning(err_t err_code, const char *extra_info = nullptr); char* FindBrackets(char* src, char* dst); - const opc_t* FindOpcode(const char* name, u32 par_count, const opc_t* opcodes, - size_t opcodes_size); - bool VerifyParams(const opc_t* opc, param_t* par, size_t count, bool ext = false); + const opc_t* FindOpcode(std::string name, size_t par_count, OpcodeType type); + bool VerifyParams(const opc_t* opc, param_t* par, size_t count, OpcodeType type); void BuildCode(const opc_t* opc, param_t* par, u32 par_count, u16* outbuf); std::vector m_output_buffer; diff --git a/Source/Core/Core/DSP/DSPDisassembler.cpp b/Source/Core/Core/DSP/DSPDisassembler.cpp index 4dc82dd30e..972db90ec4 100644 --- a/Source/Core/Core/DSP/DSPDisassembler.cpp +++ b/Source/Core/Core/DSP/DSPDisassembler.cpp @@ -180,22 +180,10 @@ bool DSPDisassembler::DisassembleOpcode(const u16* binbuf, int base_addr, int pa return false; } - const u32 op1 = binbuf[*pc & 0x0fff]; + const u16 op1 = binbuf[*pc & 0x0fff]; - const DSPOPCTemplate* opc = nullptr; - const DSPOPCTemplate* opc_ext = nullptr; - - // find opcode - for (const auto& opcode : opcodes) - { - u16 mask = opcode.opcode_mask; - - if ((op1 & mask) == opcode.opcode) - { - opc = &opcode; - break; - } - } + // Find main opcode + const DSPOPCTemplate* opc = FindOpInfoByOpcode(op1); const DSPOPCTemplate fake_op = {"CW", 0x0000, 0x0000, DSP::Interpreter::nop, nullptr, 1, 1, {{P_VAL, 2, 0, 0, 0xffff}}, false, false, false, false, @@ -203,42 +191,25 @@ bool DSPDisassembler::DisassembleOpcode(const u16* binbuf, int base_addr, int pa if (!opc) opc = &fake_op; - bool extended = false; - bool only7bitext = false; + bool is_extended = false; + bool is_only_7_bit_ext = false; if (((opc->opcode >> 12) == 0x3) && (op1 & 0x007f)) { - extended = true; - only7bitext = true; + is_extended = true; + is_only_7_bit_ext = true; } else if (((opc->opcode >> 12) > 0x3) && (op1 & 0x00ff)) { - extended = true; + is_extended = true; } - if (extended) + const DSPOPCTemplate* opc_ext = nullptr; + if (is_extended) { // opcode has an extension - // find opcode - for (const auto& opcode_ext : opcodes_ext) - { - if (only7bitext) - { - if (((op1 & 0x7f) & opcode_ext.opcode_mask) == opcode_ext.opcode) - { - opc_ext = &opcode_ext; - break; - } - } - else - { - if ((op1 & opcode_ext.opcode_mask) == opcode_ext.opcode) - { - opc_ext = &opcode_ext; - break; - } - } - } + const u16 extended_opcode = is_only_7_bit_ext ? op1 & 0x7F : op1; + opc_ext = FindExtOpInfoByOpcode(extended_opcode); } // printing @@ -246,7 +217,7 @@ bool DSPDisassembler::DisassembleOpcode(const u16* binbuf, int base_addr, int pa if (settings_.show_pc) buf += StringFromFormat("%04x ", *pc); - u32 op2; + u16 op2; // Size 2 - the op has a large immediate. if (opc->size == 2) @@ -267,7 +238,7 @@ bool DSPDisassembler::DisassembleOpcode(const u16* binbuf, int base_addr, int pa opname = MakeLowerCase(opname); std::string ext_buf; - if (extended) + if (is_extended) ext_buf = StringFromFormat("%s%c%s", opname.c_str(), settings_.ext_separator, opc_ext->name); else ext_buf = opname; @@ -283,7 +254,7 @@ bool DSPDisassembler::DisassembleOpcode(const u16* binbuf, int base_addr, int pa buf += DisassembleParameters(*opc, op1, op2); // Handle opcode extension. - if (extended) + if (is_extended) { if (opc->param_count > 0) buf += " "; @@ -301,7 +272,7 @@ bool DSPDisassembler::DisassembleOpcode(const u16* binbuf, int base_addr, int pa buf += "\t\t; *** UNKNOWN OPCODE ***"; } - if (extended) + if (is_extended) *pc += opc_ext->size; else *pc += opc->size; diff --git a/Source/Core/Core/DSP/DSPTables.cpp b/Source/Core/Core/DSP/DSPTables.cpp index f0bfee47cb..e8bf9d19f4 100644 --- a/Source/Core/Core/DSP/DSPTables.cpp +++ b/Source/Core/Core/DSP/DSPTables.cpp @@ -6,6 +6,7 @@ #include "Core/DSP/DSPTables.h" +#include #include #include @@ -20,7 +21,7 @@ namespace DSP using JIT::x86::DSPEmitter; // clang-format off -const std::array opcodes = +const std::array s_opcodes = {{ // # of parameters----+ {type, size, loc, lshift, mask} branch reads PC // instruction approximation // name opcode mask interpreter function JIT function size-V V param 1 param 2 param 3 extendable uncond. updates SR @@ -296,7 +297,7 @@ const DSPOPCTemplate cw = // extended opcodes -const std::array opcodes_ext = +const std::array s_opcodes_ext = {{ {"XXX", 0x0000, 0x00fc, Interpreter::Ext::nop, &DSPEmitter::nop, 1, 1, {{P_VAL, 1, 0, 0, 0x00ff}}, false, false, false, false, false}, // no operation @@ -512,8 +513,59 @@ constexpr size_t OPTABLE_SIZE = 0xffff + 1; constexpr size_t EXT_OPTABLE_SIZE = 0xff + 1; std::array s_op_table; std::array s_ext_op_table; + +template +auto FindByOpcode(UDSPInstruction opcode, const std::array& data) +{ + return std::find_if(data.cbegin(), data.cend(), [opcode](const auto& info) { + return (opcode & info.opcode_mask) == info.opcode; + }); +} + +template +auto FindByName(const std::string& name, const std::array& data) +{ + return std::find_if(data.cbegin(), data.cend(), + [&name](const auto& info) { return name == info.name; }); +} } // Anonymous namespace +const DSPOPCTemplate* FindOpInfoByOpcode(UDSPInstruction opcode) +{ + const auto iter = FindByOpcode(opcode, s_opcodes); + if (iter == s_opcodes.cend()) + return nullptr; + + return &*iter; +} + +const DSPOPCTemplate* FindOpInfoByName(const std::string& name) +{ + const auto iter = FindByName(name, s_opcodes); + if (iter == s_opcodes.cend()) + return nullptr; + + return &*iter; +} + +const DSPOPCTemplate* FindExtOpInfoByOpcode(UDSPInstruction opcode) +{ + const auto iter = FindByOpcode(opcode, s_opcodes_ext); + if (iter == s_opcodes_ext.cend()) + return nullptr; + + return &*iter; +} + +const DSPOPCTemplate* FindExtOpInfoByName(const std::string& name) +{ + const auto iter = FindByName(name, s_opcodes_ext); + if (iter == s_opcodes_ext.cend()) + return nullptr; + + return &*iter; +} + const DSPOPCTemplate* GetOpTemplate(UDSPInstruction inst) { return s_op_table[inst]; @@ -538,25 +590,21 @@ void InitInstructionTable() { s_ext_op_table[i] = &cw; - for (const DSPOPCTemplate& ext : opcodes_ext) + const auto iter = FindByOpcode(static_cast(i), s_opcodes_ext); + if (iter == s_opcodes_ext.cend()) + continue; + + if (s_ext_op_table[i] == &cw) { - u16 mask = ext.opcode_mask; - if ((mask & i) == ext.opcode) + s_ext_op_table[i] = &*iter; + } + else + { + // If the entry already in the table is a strict subset, allow it + if ((s_ext_op_table[i]->opcode_mask | iter->opcode_mask) != s_ext_op_table[i]->opcode_mask) { - if (s_ext_op_table[i] == &cw) - { - s_ext_op_table[i] = &ext; - } - else - { - // if the entry already in the table - // is a strict subset, allow it - if ((s_ext_op_table[i]->opcode_mask | ext.opcode_mask) != s_ext_op_table[i]->opcode_mask) - { - ERROR_LOG(DSPLLE, "opcode ext table place %zu already in use by %s when inserting %s", - i, s_ext_op_table[i]->name, ext.name); - } - } + ERROR_LOG(DSPLLE, "opcode ext table place %zu already in use by %s when inserting %s", i, + s_ext_op_table[i]->name, iter->name); } } } @@ -566,17 +614,14 @@ void InitInstructionTable() for (size_t i = 0; i < s_op_table.size(); i++) { - for (const DSPOPCTemplate& opcode : opcodes) - { - u16 mask = opcode.opcode_mask; - if ((mask & i) == opcode.opcode) - { - if (s_op_table[i] == &cw) - s_op_table[i] = &opcode; - else - ERROR_LOG(DSPLLE, "opcode table place %zu already in use for %s", i, opcode.name); - } - } + const auto iter = FindByOpcode(static_cast(i), s_opcodes); + if (iter == s_opcodes.cend()) + continue; + + if (s_op_table[i] == &cw) + s_op_table[i] = &*iter; + else + ERROR_LOG(DSPLLE, "opcode table place %zu already in use for %s", i, iter->name); } writeBackLogIdx.fill(-1); diff --git a/Source/Core/Core/DSP/DSPTables.h b/Source/Core/Core/DSP/DSPTables.h index 194c7cb0bb..869a4a780c 100644 --- a/Source/Core/Core/DSP/DSPTables.h +++ b/Source/Core/Core/DSP/DSPTables.h @@ -8,6 +8,7 @@ #include #include +#include #include "Core/DSP/DSPCommon.h" #include "Core/DSP/Jit/DSPEmitter.h" @@ -90,8 +91,6 @@ struct DSPOPCTemplate typedef DSPOPCTemplate opc_t; // Opcodes -extern const std::array opcodes; -extern const std::array opcodes_ext; extern const DSPOPCTemplate cw; constexpr size_t WRITEBACK_LOG_SIZE = 5; @@ -118,6 +117,14 @@ void applyWriteBackLog(); void zeroWriteBackLog(); void zeroWriteBackLogPreserveAcc(u8 acc); +// Used by the assembler and disassembler for info retrieval. +const DSPOPCTemplate* FindOpInfoByOpcode(UDSPInstruction opcode); +const DSPOPCTemplate* FindOpInfoByName(const std::string& name); + +const DSPOPCTemplate* FindExtOpInfoByOpcode(UDSPInstruction opcode); +const DSPOPCTemplate* FindExtOpInfoByName(const std::string& name); + +// Used by the interpreter and JIT for instruction emulation const DSPOPCTemplate* GetOpTemplate(UDSPInstruction inst); const DSPOPCTemplate* GetExtOpTemplate(UDSPInstruction inst); } // namespace DSP