diff --git a/Source/Core/DSPCore/Src/DSPCodeUtil.cpp b/Source/Core/DSPCore/Src/DSPCodeUtil.cpp index 79c07af743..4ccb17aa7a 100644 --- a/Source/Core/DSPCore/Src/DSPCodeUtil.cpp +++ b/Source/Core/DSPCore/Src/DSPCodeUtil.cpp @@ -23,50 +23,34 @@ #include "assemble.h" #include "disassemble.h" -DSPAssembler::DSPAssembler() -: include_dir(0), - current_param(0), - cur_addr(0), - labels_count(0), - cur_pass(0) -{ - include_dir = 0; - current_param = 0; -} - -DSPAssembler::~DSPAssembler() -{ - -} - bool Assemble(const char *text, std::vector *code) { const char *fname = "tmp.asm"; - gd_globals_t gdg; - memset(&gdg, 0, sizeof(gdg)); - gdg.pc = 0; - // gdg.decode_registers = false; - // gdg.decode_names = false; - gdg.print_tabs = false; - gdg.ext_separator = '\''; - gdg.buffer = 0; + AssemblerSettings settings; + memset(&settings, 0, sizeof(settings)); + settings.pc = 0; + // settings.decode_registers = false; + // settings.decode_names = false; + settings.print_tabs = false; + settings.ext_separator = '\''; + settings.buffer = 0; if (!File::WriteStringToFile(true, text, fname)) return false; // TODO: fix the terrible api of the assembler. - DSPAssembler assembler; + DSPAssembler assembler(settings); assembler.gd_ass_init_pass(1); - if (!assembler.gd_ass_file(&gdg, fname, 1)) + if (!assembler.gd_ass_file(fname, 1)) return false; assembler.gd_ass_init_pass(2); - if (!assembler.gd_ass_file(&gdg, fname, 2)) + if (!assembler.gd_ass_file(fname, 2)) return false; - code->resize(gdg.buffer_size); - for (int i = 0; i < gdg.buffer_size; i++) { - (*code)[i] = *(u16 *)(gdg.buffer + i * 2); + code->resize(assembler.gdg_buffer_size); + for (int i = 0; i < assembler.gdg_buffer_size; i++) { + (*code)[i] = *(u16 *)(assembler.gdg_buffer + i * 2); } return true; } @@ -86,18 +70,17 @@ bool Disassemble(const std::vector &code, bool line_numbers, std::string *t FILE* t = fopen(tmp2, "w"); if (t != NULL) { - gd_globals_t gdg; - memset(&gdg, 0, sizeof(gdg)); + AssemblerSettings settings; // These two prevent roundtripping. - gdg.show_hex = false; - gdg.show_pc = line_numbers; - gdg.ext_separator = '\''; - gdg.decode_names = false; - gdg.decode_registers = true; + settings.show_hex = false; + settings.show_pc = line_numbers; + settings.ext_separator = '\''; + settings.decode_names = false; + settings.decode_registers = true; - DSPDisassembler disasm; - bool success = disasm.gd_dis_file(&gdg, tmp1, t); + DSPDisassembler disasm(settings); + bool success = disasm.gd_dis_file(tmp1, t); fclose(t); File::ReadFileToString(true, tmp2, text); diff --git a/Source/Core/DSPCore/Src/DSPTables.cpp b/Source/Core/DSPCore/Src/DSPTables.cpp index 6b65f8a631..025a018bba 100644 --- a/Source/Core/DSPCore/Src/DSPTables.cpp +++ b/Source/Core/DSPCore/Src/DSPTables.cpp @@ -234,11 +234,11 @@ const DSPOPCTemplate opcodes[] = {"INCM", 0x7400, 0xfeff, DSPInterpreter::incm, nop, 1 | P_EXT, 1, {{P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, - {"INC", 0x7600, 0xfeff, DSPInterpreter::inc, nop, 1 | P_EXT, 1, {{P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"INC", 0x7600, 0xfeff, DSPInterpreter::inc, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, {"DECM", 0x7800, 0xfeff, DSPInterpreter::decm, nop, 1 | P_EXT, 1, {{P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, - {"DEC", 0x7a00, 0xfeff, DSPInterpreter::dec, nop, 1 | P_EXT, 1, {{P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, - {"NEG", 0x7c00, 0xfeff, DSPInterpreter::neg, nop, 1 | P_EXT, 1, {{P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, - {"MOVNP", 0x7e00, 0xfeff, DSPInterpreter::movnp, nop, 1 | P_EXT, 1, {{P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"DEC", 0x7a00, 0xfeff, DSPInterpreter::dec, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"NEG", 0x7c00, 0xfeff, DSPInterpreter::neg, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"MOVNP", 0x7e00, 0xfeff, DSPInterpreter::movnp, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, {"TST", 0xb100, 0xf7ff, DSPInterpreter::tst, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, @@ -278,19 +278,19 @@ const DSPOPCTemplate opcodes[] = {"ORC", 0x3E00, 0xfeff, DSPInterpreter::orc, nop, 1 | P_EXT, 1, {{P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, // Hermes doesn't list this {"MULX", 0xa000, 0xe7ff, DSPInterpreter::mulx, nop, 1 | P_EXT, 2, {{P_REGM18, 1, 0, 11, 0x1000}, {P_REGM19, 1, 0, 10, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, - {"MULXMVZ", 0xa200, 0xe6ff, DSPInterpreter::mulxmvz, nop, 1 | P_EXT, 3, {{P_REGM18, 1, 0, 11, 0x1000}, {P_REGM19, 1, 0, 10, 0x0800}, {P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, - {"MULXAC", 0xa400, 0xe6ff, DSPInterpreter::mulxac, nop, 1 | P_EXT, 3, {{P_REGM18, 1, 0, 11, 0x1000}, {P_REGM19, 1, 0, 10, 0x0800}, {P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, - {"MULXMV", 0xa600, 0xe6ff, DSPInterpreter::mulxmv, nop, 1 | P_EXT, 3, {{P_REGM18, 1, 0, 11, 0x1000}, {P_REGM19, 1, 0, 10, 0x0800}, {P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"MULXMVZ", 0xa200, 0xe6ff, DSPInterpreter::mulxmvz, nop, 1 | P_EXT, 3, {{P_REGM18, 1, 0, 11, 0x1000}, {P_REGM19, 1, 0, 10, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"MULXAC", 0xa400, 0xe6ff, DSPInterpreter::mulxac, nop, 1 | P_EXT, 3, {{P_REGM18, 1, 0, 11, 0x1000}, {P_REGM19, 1, 0, 10, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"MULXMV", 0xa600, 0xe6ff, DSPInterpreter::mulxmv, nop, 1 | P_EXT, 3, {{P_REGM18, 1, 0, 11, 0x1000}, {P_REGM19, 1, 0, 10, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, {"MUL", 0x9000, 0xf7ff, DSPInterpreter::mul, nop, 1 | P_EXT, 2, {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, - {"MULMVZ", 0x9200, 0xf6ff, DSPInterpreter::mulmvz, nop, 1 | P_EXT, 3, {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, - {"MULAC", 0x9400, 0xf6ff, DSPInterpreter::mulac, nop, 1 | P_EXT, 3, {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, - {"MULMV", 0x9600, 0xf6ff, DSPInterpreter::mulmv, nop, 1 | P_EXT, 3, {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"MULMVZ", 0x9200, 0xf6ff, DSPInterpreter::mulmvz, nop, 1 | P_EXT, 3, {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"MULAC", 0x9400, 0xf6ff, DSPInterpreter::mulac, nop, 1 | P_EXT, 3, {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"MULMV", 0x9600, 0xf6ff, DSPInterpreter::mulmv, nop, 1 | P_EXT, 3, {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, {"MULC", 0xc000, 0xe7ff, DSPInterpreter::mulc, nop, 1 | P_EXT, 2, {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, - {"MULCMVZ", 0xc200, 0xe6ff, DSPInterpreter::mulcmvz, nop, 1 | P_EXT, 3, {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, - {"MULCAC", 0xc400, 0xe6ff, DSPInterpreter::mulcac, nop, 1 | P_EXT, 3, {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, - {"MULCMV", 0xc600, 0xe6ff, DSPInterpreter::mulcmv, nop, 1 | P_EXT, 3, {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACCM, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"MULCMVZ", 0xc200, 0xe6ff, DSPInterpreter::mulcmvz, nop, 1 | P_EXT, 3, {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"MULCAC", 0xc400, 0xe6ff, DSPInterpreter::mulcac, nop, 1 | P_EXT, 3, {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"MULCMV", 0xc600, 0xe6ff, DSPInterpreter::mulcmv, nop, 1 | P_EXT, 3, {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, {"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}, @@ -315,8 +315,7 @@ const DSPOPCTemplate cw = const DSPOPCTemplate opcodes_ext[] = -{ - +{ // FIXME: guessing this is cr need checking {"CR", 0x0000, 0x00fc, DSPInterpreter::Ext::cr, nop, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, NULL, NULL,}, {"DR", 0x0004, 0x00fc, DSPInterpreter::Ext::dr, nop, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, NULL, NULL,}, @@ -410,10 +409,10 @@ const pdlabel_t regnames[] = {0x01, "AR1", "Addr Reg 01",}, {0x02, "AR2", "Addr Reg 02",}, {0x03, "AR3", "Addr Reg 03",}, - {0x04, "IX0", "Index Reg 1(04)",}, - {0x05, "IX1", "Index Reg 2(05)",}, - {0x06, "IX2", "Index Reg 3(06)",}, - {0x07, "IX3", "Indec Reg 4(07)",}, + {0x04, "IX0", "Index Reg 0(04)",}, + {0x05, "IX1", "Index Reg 1(05)",}, + {0x06, "IX2", "Index Reg 2(06)",}, + {0x07, "IX3", "Indec Reg 3(07)",}, {0x08, "R08", "Register 08",}, {0x09, "R09", "Register 09",}, {0x0a, "R10", "Register 10",}, @@ -422,7 +421,7 @@ const pdlabel_t regnames[] = {0x0d, "ST1", "Data stack",}, {0x0e, "ST2", "Loop addr stack",}, {0x0f, "ST3", "Loop counter",}, - {0x00, "AC0.H", "Accu High 0",}, + {0x10, "AC0.H", "Accu High 0",}, {0x11, "AC1.H", "Accu High 1",}, {0x12, "CR", "Config Register",}, {0x13, "SR", "Special Register",}, @@ -439,7 +438,7 @@ const pdlabel_t regnames[] = {0x1e, "AC0.M", "Accu Mid 0",}, {0x1f, "AC1.M", "Accu Mid 1",}, - // To resolve special names. + // To resolve combined register names. {0x20, "ACC0", "Accu Full 0",}, {0x21, "ACC1", "Accu Full 1",}, {0x22, "AX0", "Extra Accu 0",}, @@ -451,7 +450,6 @@ dspInstFunc opTable[OPTABLE_SIZE]; dspInstFunc prologueTable[OPTABLE_SIZE]; dspInstFunc epilogueTable[OPTABLE_SIZE]; - const char* pdname(u16 val) { static char tmpstr[12]; // nasty diff --git a/Source/Core/DSPCore/Src/DSPTables.h b/Source/Core/DSPCore/Src/DSPTables.h index 64ffef51d0..650953abfd 100644 --- a/Source/Core/DSPCore/Src/DSPTables.h +++ b/Source/Core/DSPCore/Src/DSPTables.h @@ -24,6 +24,11 @@ // The 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. +// For the reg ones, the value >> 8 is the base register. +// & 0x80 means it's a "D". + enum partype_t { P_NONE = 0x0000, @@ -37,15 +42,15 @@ enum partype_t P_REGM18 = P_REG | 0x1810, // used in multiply instructions P_REG19 = P_REG | 0x1900, P_REGM19 = P_REG | 0x1910, // used in multiply instructions - P_REG1A = P_REG | 0x1a00, + P_REG1A = P_REG | 0x1a80, P_REG1C = P_REG | 0x1c00, // P_ACC = P_REG | 0x1c10, // used for global accum (gcdsptool's value) P_ACC_D = P_REG | 0x1c80, - P_ACCL = P_REG | 0x1c00, // used for mid accum - P_ACCM = P_REG | 0x1e00, // used for mid accum + P_ACCL = P_REG | 0x1c00, // used for low part of accum + P_ACCM = P_REG | 0x1e00, // used for mid part of accum // The following are not in gcdsptool P_ACCM_D = P_REG | 0x1e80, - P_ACC = P_REG | 0x2000, // used for global accum. + P_ACC = P_REG | 0x2000, // used for full accum. P_AX = P_REG | 0x2200, P_REGS_MASK = 0x03f80, // gcdsptool's value = 0x01f80 P_REF = P_REG | 0x4000, diff --git a/Source/Core/DSPCore/Src/assemble.cpp b/Source/Core/DSPCore/Src/assemble.cpp index 8e1c94c77f..c7a6267a47 100644 --- a/Source/Core/DSPCore/Src/assemble.cpp +++ b/Source/Core/DSPCore/Src/assemble.cpp @@ -1,972 +1,984 @@ -/*==================================================================== - -$Id: assemble.cpp,v 1.3 2008-11-11 01:04:26 wntrmute Exp $ - -project: GameCube DSP Tool (gcdsp) -mail: duddie@walla.com - -Copyright (c) 2005 Duddie - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -Revision 1.4 2008/10/04 10:30:00 Hermes -added function to export the code to .h file -added support for '/ *' '* /' and '//' for comentaries -added some sintax detection when use registers - -$Log: not supported by cvs2svn $ -Revision 1.2 2005/09/14 02:19:29 wntrmute -added header guards -use standard main function - -Revision 1.1 2005/08/24 22:13:34 wntrmute -Initial import - - -====================================================================*/ - -#include -#include -#include - -#include - -#include "Common.h" -#include "DSPInterpreter.h" -#include "DSPTables.h" -#include "disassemble.h" -#include "assemble.h" - -static const char *err_string[] = -{ - "", - "Unknown Error", - "Unknown opcode", - "Not enough parameters", - "Too many parameters", - "Wrong parameter", - "Expected parameter of type 'string'", - "Expected parameter of type 'value'", - "Expected parameter of type 'register'", - "Expected parameter of type 'memory pointer'", - "Expected parameter of type 'immediate'", - "Incorrect binary value", - "Incorrect hexadecimal value", - "Incorrect decimal value", - "Label already exists", - "Label not defined", - "No matching brackets", - "This opcode cannot be extended", - "Given extending params for non extensible opcode", - "Wrong parameter: must be accumulator register", - "Wrong parameter: must be mid accumulator register", - "Invalid register", - "Number out of range" -}; - -void DSPAssembler::parse_error(err_t err_code, fass_t *fa, const char *extra_info) -{ - fprintf(stderr, "%i : %s\n", fa->code_line, cur_line); - fa->failed = true; - if (!extra_info) - extra_info = "-"; - if (fa->fsrc) - fclose(fa->fsrc); - else - { - fprintf(stderr, "ERROR: %s : %s\n", err_string[err_code], extra_info); - } - - // modified by Hermes - - if (current_param == 0) - fprintf(stderr, "ERROR: %s Line: %d : %s\n", err_string[err_code], fa->code_line, extra_info); - else - fprintf(stderr, "ERROR: %s Line: %d Param: %d : %s\n", - err_string[err_code], fa->code_line, current_param, extra_info); -} - -char *skip_spaces(char *ptr) -{ - while (*ptr == ' ') - ptr++; - return ptr; -} - -const char *skip_spaces(const char *ptr) -{ - while (*ptr == ' ') - ptr++; - return ptr; -} - -void DSPAssembler::gd_ass_register_label(const char *label, u16 lval) -{ - labels[labels_count].label = (char *)malloc(strlen(label) + 1); - strcpy(labels[labels_count].label, label); - labels[labels_count].addr = lval; - labels_count++; -} - -void DSPAssembler::gd_ass_clear_labels() -{ - for (int i = 0; i < labels_count; i++) - { - free(labels[i].label); - } - labels_count = 0; -} - -// Parse a standalone value - it can be a number in one of several formats or a label. -s32 DSPAssembler::strtoval(const char *str) -{ - bool negative = false; - s32 val = 0; - const char *ptr = str; - - if (ptr[0] == '#') - { - ptr++; - negative = true; // Wow! Double # (needed one to get in here) negates??? - } - if (ptr[0] == '-') - { - ptr++; - negative = true; - } - if (ptr[0] == '0') - { - if (ptr[1] >= '0' && ptr[1] <= '9') - { - for (int i = 0; ptr[i] != 0; i++) - { - val *= 10; - if (ptr[i] >= '0' && ptr[i] <= '9') - val += ptr[i] - '0'; - else - parse_error(ERR_INCORRECT_DEC, cur_fa, str); - } - } - else - { - switch (ptr[1]) - { - case 'X': // hex - for (int i = 2 ; ptr[i] != 0 ; i++) - { - val <<= 4; - if (ptr[i] >= 'a' && ptr[i] <= 'f') - val += (ptr[i]-'a'+10); - else if (ptr[i] >= 'A' && ptr[i] <= 'F') - val += (ptr[i]-'A'+10); - else if (ptr[i] >= '0' && ptr[i] <= '9') - val += (ptr[i]-'0'); - else - parse_error(ERR_INCORRECT_HEX, cur_fa, str); - } - break; - case '\'': // binary - for (int i = 2; ptr[i] != 0; i++) - { - val *=2; - if(ptr[i] >= '0' && ptr[i] <= '1') - val += ptr[i] - '0'; - else - parse_error(ERR_INCORRECT_BIN, cur_fa, str); - } - break; - default: - // value is 0 or error - val = 0; - break; - } - } - } - else - { - // Symbol starts with a digit - it's a dec number. - if (ptr[0] >= '0' && ptr[0] <= '9') - { - for (int i = 0; ptr[i] != 0; i++) - { - val *= 10; - if (ptr[i] >= '0' && ptr[i] <= '9') - val += ptr[i] - '0'; - else - parse_error(ERR_INCORRECT_DEC, cur_fa, str); - } - } - else // Everything else is a label. - { - // Lookup label - for (int i = 0; i < labels_count; i++) - { - if (strcmp(labels[i].label, ptr) == 0) - return labels[i].addr; - } - if (cur_pass == 2) - parse_error(ERR_UNKNOWN_LABEL, cur_fa, str); - } - } - if (negative) - return -val; - return val; -} - - -// Modifies both src and dst! -// What does it do, really?? -char *DSPAssembler::find_brackets(char *src, char *dst) -{ - s32 len = (s32) strlen(src); - s32 first = -1; - s32 count = 0; - s32 i, j; - j = 0; - for (i = 0 ; i < len ; i++) - { - if (src[i] == '(') - { - if (first < 0) - { - count = 1; - src[i] = 0x0; - first = i; - } - else - { - count++; - dst[j++] = src[i]; - } - } - else if (src[i] == ')') - { - if (--count == 0) - { - dst[j] = 0; - return &src[i+1]; - } - else - { - dst[j++] = src[i]; - } - } - else - { - if (first >= 0) - dst[j++] = src[i]; - } - } - if (count) - parse_error(ERR_NO_MATCHING_BRACKETS, cur_fa); - return NULL; -} - -// Bizarre in-place expression evaluator. -u32 DSPAssembler::parse_exp(const char *ptr) -{ - char *pbuf; - s32 val = 0; - - char *d_buffer = (char *)malloc(1024); - char *s_buffer = (char *)malloc(1024); - strcpy(s_buffer, ptr); - - while ((pbuf = find_brackets(s_buffer, d_buffer)) != NULL) - { - val = parse_exp(d_buffer); - sprintf(d_buffer, "%s%d%s", s_buffer, val, pbuf); - strcpy(s_buffer, d_buffer); - } - - int j = 0; - for (int i = 0; i < ((s32)strlen(s_buffer) + 1) ; i++) - { - char c = s_buffer[i]; - if (c != ' ') - d_buffer[j++] = c; - } - - for (int i = 0; i < ((s32)strlen(d_buffer) + 1) ; i++) - { - char c = d_buffer[i]; - if (c == '-') - { - if (i == 0) - c = '#'; - else - { - switch (d_buffer[i - 1]) - { - case '/': - case '%': - case '*': - c = '#'; - } - } - } - d_buffer[i] = c; - } - while ((pbuf = strstr(d_buffer, "+")) != NULL) - { - *pbuf = 0x0; - val = parse_exp(d_buffer) + parse_exp(pbuf+1); - sprintf(d_buffer, "%d", val); - } - - while ((pbuf = strstr(d_buffer, "-")) != NULL) - { - *pbuf = 0x0; - val = parse_exp(d_buffer) - parse_exp(pbuf+1); - if (val < 0) - { - val = 0x10000 + (val & 0xffff); // ATTENTION: avoid a terrible bug!!! number cannot write with '-' in sprintf - if(cur_fa) - fprintf(stderr, "WARNING: Number Underflow at Line: %d \n", cur_fa->code_line); - } - sprintf(d_buffer, "%d", val); - } - - while ((pbuf = strstr(d_buffer, "*")) != NULL) - { - *pbuf = 0x0; - val = parse_exp(d_buffer) * parse_exp(pbuf+1); - sprintf(d_buffer, "%d", val); - } - - while ((pbuf = strstr(d_buffer, "/")) != NULL) - { - *pbuf = 0x0; - val = parse_exp(d_buffer) / parse_exp(pbuf+1); - sprintf(d_buffer, "%d", val); - } - - while ((pbuf = strstr(d_buffer, "|")) != NULL) - { - *pbuf = 0x0; - val = parse_exp(d_buffer) | parse_exp(pbuf+1); - sprintf(d_buffer, "%d", val); - } - - while ((pbuf = strstr(d_buffer, "&")) != NULL) - { - *pbuf = 0x0; - val = parse_exp(d_buffer) & parse_exp(pbuf+1); - sprintf(d_buffer, "%d", val); - } - - val = strtoval(d_buffer); - free(d_buffer); - free(s_buffer); - return val; -} - -u32 DSPAssembler::parse_exp_f(const char *ptr, fass_t *fa) -{ - cur_fa = fa; - return parse_exp(ptr); -} - -// Destroys parstr -u32 DSPAssembler::get_params(char *parstr, param_t *par, fass_t *fa) -{ - u32 count = 0; - char *tmpstr = skip_spaces(parstr); - tmpstr = strtok(tmpstr, ",\x00"); - for (int i = 0; i < 10; i++) - { - if (tmpstr == NULL) - break; - tmpstr = skip_spaces(tmpstr); - if (strlen(tmpstr) == 0) - break; - if (tmpstr) - count++; - else - break; - - par[i].type = P_NONE; - switch (tmpstr[0]) - { - case '"': - par[i].str = strtok(tmpstr, "\""); - par[i].type = P_STR; - break; - case '#': - par[i].val = parse_exp_f(tmpstr + 1, fa); - par[i].type = P_IMM; - break; - case '@': - if (tmpstr[1] == '$') - { - par[i].val = parse_exp_f(tmpstr + 2, fa); - par[i].type = P_PRG; - } - else - { - par[i].val = parse_exp_f(tmpstr + 1, fa); - par[i].type = P_MEM; - } - break; - case '$': - par[i].val = parse_exp_f(tmpstr + 1, fa); - par[i].type = P_REG; - break; - default: - par[i].val = parse_exp_f(tmpstr, fa); - par[i].type = P_VAL; - break; - } - tmpstr = strtok(NULL, ",\x00"); - } - return count; -} - -const opc_t *DSPAssembler::find_opcode(const char *opcode, u32 par_count, const opc_t * const opcod, u32 opcod_size, DSPAssembler::fass_t *fa) -{ - if (opcode[0] == 'C' && opcode[1] == 'W') - return &cw; - - AliasMap::const_iterator alias_iter = aliases.find(opcode); - if (alias_iter != aliases.end()) - opcode = alias_iter->second.c_str(); - for (int i = 0; i < opcod_size; i++) - { - const opc_t *opc = &opcod[i]; - if (strcmp(opc->name, opcode) == 0) - { - if (par_count < opc->param_count) - { - parse_error(ERR_NOT_ENOUGH_PARAMETERS, fa); - } - if (par_count > opc->param_count) - { - parse_error(ERR_TOO_MANY_PARAMETERS, fa); - } - return opc; - } - } - parse_error(ERR_UNKNOWN_OPCODE, fa); - return NULL; -} - -// weird... -u16 get_mask_shifted_down(u16 mask) -{ - while (!(mask & 1)) - mask >>= 1; - return mask; -} - -bool DSPAssembler::verify_params(const opc_t *opc, param_t *par, u32 count, fass_t *fa) -{ - int value; - unsigned int valueu; - for (u32 i = 0; i < count; i++) - { - current_param = i+1; - if (opc->params[i].type != par[i].type || (par[i].type & P_REG)) - { - if ((opc->params[i].type & P_REG) && (par[i].type & P_REG)) - { - // modified by Hermes: test the register range - switch ((unsigned)opc->params[i].type) - { - case P_REG18: - case P_REG19: - case P_REG1A: - //case P_REG1C: - value = (opc->params[i].type >> 8) & 31; - if ((int)par[i].val < value || - (int)par[i].val > value + get_mask_shifted_down(opc->params[i].mask)) - { - parse_error(ERR_INVALID_REGISTER, fa); - } - break; - case P_PRG: - if ((int)par[i].val < 0 || (int)par[i].val > 0x3) - { - parse_error(ERR_INVALID_REGISTER, fa); - } - break; - case P_ACC: - if ((int)par[i].val < 0x20 || (int)par[i].val > 0x21) - { - if (par[i].val >= 0x1e && par[i].val <= 0x1f) - fprintf(stderr, "WARNING: $ACM%d register used instead $ACC%d register Line: %d Param: %d\n", - (par[i].val & 1), (par[i].val & 1), fa->code_line, current_param); - else if (par[i].val >= 0x1c && par[i].val <= 0x1d) - fprintf(stderr, "WARNING: $ACL%d register used instead $ACC%d register Line: %d Param: %d\n", - (par[i].val & 1), (par[i].val & 1), fa->code_line, current_param); - else - parse_error(ERR_WRONG_PARAMETER_ACC, fa); - } - break; - case P_ACCM: - if ((int)par[i].val < 0x1e || (int)par[i].val > 0x1f) - { - if (par[i].val >= 0x1c && par[i].val <= 0x1d) - fprintf(stderr, "WARNING: $ACL%d register used instead $ACM%d register Line: %d Param: %d\n", - (par[i].val & 1), (par[i].val & 1), fa->code_line, current_param); - else if (par[i].val >= 0x20 && par[i].val <= 0x21) - fprintf(stderr, "WARNING: $ACC%d register used instead $ACM%d register Line: %d Param: %d\n", - (par[i].val & 1), (par[i].val & 1), fa->code_line, current_param); - else - parse_error(ERR_WRONG_PARAMETER_ACC, fa); - } - break; - - case P_ACCL: - if ((int)par[i].val < 0x1c || (int)par[i].val > 0x1d) - { - if (par[i].val >= 0x1e && par[i].val <= 0x1f) - fprintf(stderr, "WARNING: $ACM%d register used instead $ACL%d register Line: %d Param: %d\n", - (par[i].val & 1), (par[i].val & 1), fa->code_line, current_param); - else if (par[i].val >= 0x20 && par[i].val <= 0x21) - fprintf(stderr, "WARNING: $ACC%d register used instead $ACL%d register Line: %d Param: %d\n", - (par[i].val & 1), (par[i].val & 1), fa->code_line, current_param); - else - parse_error(ERR_WRONG_PARAMETER_ACC, fa); - } - 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, fa); - } - break;*/ - } - continue; - } - - switch (par[i].type & (P_REG | P_VAL | P_MEM | P_IMM)) - { - case P_REG: - parse_error(ERR_EXPECTED_PARAM_REG, fa); - break; - case P_MEM: - parse_error(ERR_EXPECTED_PARAM_MEM, fa); - break; - case P_VAL: - parse_error(ERR_EXPECTED_PARAM_VAL, fa); - break; - case P_IMM: - parse_error(ERR_EXPECTED_PARAM_IMM, fa); - break; - } - parse_error(ERR_WRONG_PARAMETER, fa); - break; - } - else if ((opc->params[i].type & 3) != 0 && (par[i].type & 3) != 0) - { - // modified by Hermes: test NUMBER range - value = get_mask_shifted_down(opc->params[i].mask); - - valueu = 0xffff & ~(value >> 1); - if ((int)par[i].val < 0) - { - 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, fa); - } - else if (opc->params[i].type == P_MEM) - { - if (value < 256) - fprintf(stderr,"Address value must be from 0x%x to 0x%x\n",valueu, (value>>1)); - else - fprintf(stderr,"Address value must be from 0x0 to 0x%x\n", value); - - parse_error(ERR_OUT_RANGE_NUMBER, fa); - } - else if ((int)par[i].val < -((value >> 1) + 1)) - { - if (value < 128) - fprintf(stderr, "Value must be from -0x%x to 0x%x, is %i\n", - (value >> 1) + 1, value >> 1, par[i].val); - else - 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, fa); - } - } - else - { - if (value == 7) // value 7 por sbclr/sbset - { - 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, fa); - } - } - else if (opc->params[i].type == P_MEM) - { - if (value < 256) - value >>= 1; // addressing 8 bit with sign - if (par[i].val > (unsigned)value && - (par[i].val < valueu || par[i].val > (unsigned)0xffff)) - { - if (value < 256) - 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, fa); - } - } - else - { - if (value < 128) - value >>= 1; // special case ASL/ASR/LSL/LSR - if (par[i].val > (unsigned)value) - { - if (value < 64) - 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, fa); - } - } - } - continue; - } - } - current_param = 0; - return true; -} - - -// Merge opcode with params. -void DSPAssembler::build_code(const opc_t *opc, param_t *par, u32 par_count, u16 *outbuf) -{ - outbuf[cur_addr] |= opc->opcode; - for (u32 i = 0; i < par_count; i++) - { - // Ignore the "reverse" parameters since they are implicit. - if (opc->params[i].type != P_ACC_D && opc->params[i].type != P_ACCM_D) - { - u16 t16 = outbuf[cur_addr + opc->params[i].loc]; - u16 v16 = par[i].val; - if (opc->params[i].lshift > 0) - v16 <<= opc->params[i].lshift; - else - v16 >>= -opc->params[i].lshift; - v16 &= opc->params[i].mask; - outbuf[cur_addr + opc->params[i].loc] = t16 | v16; - } - } -} - -void DSPAssembler::gd_ass_init_pass(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 < pdlabels_size; i++) - { - gd_ass_register_label(pdlabels[i].name, pdlabels[i].addr); - } - aliases.clear(); - aliases["S15"] = "SET15"; - aliases["S16"] = "SET16"; - aliases["S40"] = "SET40"; - } - cur_addr = 0; - cur_segment = SEGMENT_CODE; - segment_addr[SEGMENT_CODE] = 0; - segment_addr[SEGMENT_DATA] = 0; - segment_addr[SEGMENT_OVERLAY] = 0; -} - -bool DSPAssembler::gd_ass_file(gd_globals_t *gdg, const char *fname, int pass) -{ - fass_t fa; - int disable_text = 0; // modified by Hermes - - param_t params[10] = {0}; - param_t params_ext[10] = {0}; - u32 params_count = 0; - u32 params_count_ext = 0; - - fa.failed = false; - fa.fsrc = fopen(fname, "r"); - if (fa.fsrc == NULL) - { - fprintf(stderr, "Cannot open %s file\n", fname); - return false; - } - - fseek(fa.fsrc, 0, SEEK_SET); - printf("Pass %d\n", pass); - fa.code_line = 0; - cur_pass = pass; - -#define LINEBUF_SIZE 4096 - char linebuffer[LINEBUF_SIZE]; - while (!feof(fa.fsrc) && !fa.failed) - { - int opcode_size = 0; - memset(linebuffer, 0, LINEBUF_SIZE); - if (!fgets(linebuffer, LINEBUF_SIZE, fa.fsrc)) - break; - strcpy(cur_line, linebuffer); - //printf("A: %s", linebuffer); - fa.code_line++; - - for (int i = 0; i < LINEBUF_SIZE; i++) - { - char c = linebuffer[i]; - // This stuff handles /**/ and // comments. - // modified by Hermes : added // and /* */ for long comentaries - if (c == '/') - { - if (i < 1023) - { - if (linebuffer[i+1] == '/') - c = 0x00; - else if (linebuffer[i+1] == '*') - { - // wtf is this? - disable_text = !disable_text; - } - } - } - else if (c == '*') - { - if (i < 1023 && linebuffer[i+1] == '/' && disable_text) - { - disable_text = 0; - c = 32; - linebuffer[i + 1] = 32; - } - } - - - if(disable_text && ((unsigned char )c)>32) c=32; - - if (c == 0x0a || c == 0x0d || c == ';') - c = 0x00; - if (c == 0x09) // tabs to spaces - c = ' '; - if (c >= 'a' && c <= 'z') // convert to uppercase - c = c - 'a' + 'A'; - linebuffer[i] = c; - if (c == 0) - break; // modified by Hermes - } - char *ptr = linebuffer; - - char *opcode = NULL; - char *label = NULL; - char *col_ptr; - if ((col_ptr = strstr(ptr, ":")) != NULL) - { - int j; - bool valid; - j = 0; - valid = true; - while ((ptr+j) < col_ptr) - { - if (j == 0) - if (!((ptr[j] >= 'A' && ptr[j] <= 'Z') || (ptr[j] == '_'))) - valid = false; - if (!((ptr[j] >= '0' && ptr[j] <= '9') || (ptr[j] >= 'A' && ptr[j] <= 'Z') || (ptr[j] == '_'))) - valid = false; - j++; - } - if (valid) - { - label = strtok(ptr, ":\x20"); - ptr = col_ptr + 1; - } - } - - opcode = strtok(ptr, " "); - char *opcode_ext = NULL; - - char *paramstr; - char *paramstr_ext; - - if (opcode) - { - if ((opcode_ext = strstr(opcode, "'")) != NULL) - { - opcode_ext[0] = '\0'; - opcode_ext++; - if (strlen(opcode_ext) == 0) - opcode_ext = NULL; - } - // now we have opcode and label - - params_count = 0; - params_count_ext = 0; - - paramstr = paramstr_ext = 0; - // there is valid opcode so probably we have parameters - - paramstr = strtok(NULL, "\0"); - - if (paramstr) - { - if ((paramstr_ext = strstr(paramstr, ":")) != NULL) - { - paramstr_ext[0] = '\0'; - paramstr_ext++; - } - } - - if (paramstr) - params_count = get_params(paramstr, params, &fa); - if (paramstr_ext) - params_count_ext = get_params(paramstr_ext, params_ext, &fa); - } - - if (label) - { - // there is a valid label so lets store it in labels table - u32 lval = cur_addr; - if (opcode) - { - if (strcmp(opcode, "EQU") == 0) - { - lval = params[0].val; - opcode = NULL; - } - } - if (pass == 1) - { - gd_ass_register_label(label, lval); - } - } - - if (opcode == NULL) - continue; - - // check if opcode is reserved compiler word - if (strcmp("INCLUDE", opcode) == 0) - { - if (params[0].type == P_STR) - { - char *tmpstr; - if (include_dir) - { - tmpstr = (char *)malloc(strlen(include_dir) + strlen(params[0].str) + 2); - sprintf(tmpstr, "%s/%s", include_dir, params[0].str); - } - else - { - tmpstr = (char *)malloc(strlen(params[0].str) + 1); - strcpy(tmpstr, params[0].str); - } - gd_ass_file(gdg, tmpstr, pass); - free(tmpstr); - } - else - parse_error(ERR_EXPECTED_PARAM_STR, &fa); - continue; - } - - if (strcmp("INCDIR", opcode) == 0) - { - if (params[0].type == P_STR) - { - if (include_dir) free(include_dir); - include_dir = (char *)malloc(strlen(params[0].str) + 1); - strcpy(include_dir, params[0].str); - } - else - parse_error(ERR_EXPECTED_PARAM_STR, &fa); - continue; - } - - if (strcmp("ORG", opcode) == 0) - { - if (params[0].type == P_VAL) - cur_addr = params[0].val; - else - parse_error(ERR_EXPECTED_PARAM_VAL, &fa); - continue; - } - - if (strcmp("SEGMENT", opcode) == 0) - { - if(params[0].type == P_STR) - { - segment_addr[cur_segment] = cur_addr; - if (strcmp("DATA", params[0].str) == 0) - cur_segment = SEGMENT_DATA; - if (strcmp("CODE", params[0].str) == 0) - cur_segment = SEGMENT_CODE; - cur_addr = segment_addr[cur_segment]; - } - else - parse_error(ERR_EXPECTED_PARAM_STR, &fa); - continue; - } - - const opc_t *opc = find_opcode(opcode, params_count, opcodes, opcodes_size, &fa); - if (!opc) - opc = &cw; - - opcode_size = opc->size & ~P_EXT; - - verify_params(opc, params, params_count, &fa); - - const opc_t *opc_ext = NULL; - // Check for opcode extensions. - if (opc->size & P_EXT) - { - if (opcode_ext) - { - opc_ext = find_opcode(opcode_ext, params_count_ext, opcodes_ext, opcodes_ext_size, &fa); - verify_params(opc_ext, params_ext, params_count_ext, &fa); - } - else if (params_count_ext) - parse_error(ERR_EXT_PAR_NOT_EXT, &fa); - } - else - { - if (opcode_ext) - parse_error(ERR_EXT_CANT_EXTEND_OPCODE, &fa); - if (params_count_ext) - parse_error(ERR_EXT_PAR_NOT_EXT, &fa); - } - - if (pass == 2) - { - // generate binary - ((u16 *)gdg->buffer)[cur_addr] = 0x0000; - build_code(opc, params, params_count, (u16 *)gdg->buffer); - if (opc_ext) - build_code(opc_ext, params_ext, params_count_ext, (u16 *)gdg->buffer); - } - - cur_addr += opcode_size; - }; - if (gdg->buffer == NULL) - { - gdg->buffer_size = cur_addr; - gdg->buffer = (char *)malloc(gdg->buffer_size * sizeof(u16) + 4); - memset(gdg->buffer, 0, gdg->buffer_size * sizeof(u16)); - } - fclose(fa.fsrc); - return !fa.failed; -} +/*==================================================================== + +$Id: assemble.cpp,v 1.3 2008-11-11 01:04:26 wntrmute Exp $ + +project: GameCube DSP Tool (gcdsp) +mail: duddie@walla.com + +Copyright (c) 2005 Duddie + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +Revision 1.4 2008/10/04 10:30:00 Hermes +added function to export the code to .h file +added support for '/ *' '* /' and '//' for comentaries +added some sintax detection when use registers + +$Log: not supported by cvs2svn $ +Revision 1.2 2005/09/14 02:19:29 wntrmute +added header guards +use standard main function + +Revision 1.1 2005/08/24 22:13:34 wntrmute +Initial import + + +====================================================================*/ + +#include +#include +#include + +#include + +#include "Common.h" +#include "DSPInterpreter.h" +#include "DSPTables.h" +#include "disassemble.h" +#include "assemble.h" + +static const char *err_string[] = +{ + "", + "Unknown Error", + "Unknown opcode", + "Not enough parameters", + "Too many parameters", + "Wrong parameter", + "Expected parameter of type 'string'", + "Expected parameter of type 'value'", + "Expected parameter of type 'register'", + "Expected parameter of type 'memory pointer'", + "Expected parameter of type 'immediate'", + "Incorrect binary value", + "Incorrect hexadecimal value", + "Incorrect decimal value", + "Label already exists", + "Label not defined", + "No matching brackets", + "This opcode cannot be extended", + "Given extending params for non extensible opcode", + "Wrong parameter: must be accumulator register", + "Wrong parameter: must be mid accumulator register", + "Invalid register", + "Number out of range" +}; + +DSPAssembler::DSPAssembler(const AssemblerSettings &settings) +: current_param(0), + cur_addr(0), + cur_pass(0), + settings_(settings) +{ + gdg_buffer = NULL; + +} + + +DSPAssembler::~DSPAssembler() +{ + +} + +void DSPAssembler::parse_error(err_t err_code, const char *extra_info) +{ + fprintf(stderr, "%i : %s\n", code_line, cur_line); + failed = true; + if (!extra_info) + extra_info = "-"; + if (fsrc) + fclose(fsrc); + else + { + fprintf(stderr, "ERROR: %s : %s\n", err_string[err_code], extra_info); + } + + // modified by Hermes + + if (current_param == 0) + fprintf(stderr, "ERROR: %s Line: %d : %s\n", err_string[err_code], code_line, extra_info); + else + fprintf(stderr, "ERROR: %s Line: %d Param: %d : %s\n", + err_string[err_code], code_line, current_param, extra_info); +} + +char *skip_spaces(char *ptr) +{ + while (*ptr == ' ') + ptr++; + return ptr; +} + +const char *skip_spaces(const char *ptr) +{ + while (*ptr == ' ') + 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) +{ + bool negative = false; + s32 val = 0; + const char *ptr = str; + + if (ptr[0] == '#') + { + ptr++; + negative = true; // Wow! Double # (needed one to get in here) negates??? + } + if (ptr[0] == '-') + { + ptr++; + negative = true; + } + if (ptr[0] == '0') + { + if (ptr[1] >= '0' && ptr[1] <= '9') + { + for (int i = 0; ptr[i] != 0; i++) + { + val *= 10; + if (ptr[i] >= '0' && ptr[i] <= '9') + val += ptr[i] - '0'; + else + parse_error(ERR_INCORRECT_DEC, str); + } + } + else + { + switch (ptr[1]) + { + case 'X': // hex + for (int i = 2 ; ptr[i] != 0 ; i++) + { + val <<= 4; + if (ptr[i] >= 'a' && ptr[i] <= 'f') + val += (ptr[i]-'a'+10); + else if (ptr[i] >= 'A' && ptr[i] <= 'F') + val += (ptr[i]-'A'+10); + else if (ptr[i] >= '0' && ptr[i] <= '9') + val += (ptr[i] - '0'); + else + parse_error(ERR_INCORRECT_HEX, str); + } + break; + case '\'': // binary + for (int i = 2; ptr[i] != 0; i++) + { + val *=2; + if(ptr[i] >= '0' && ptr[i] <= '1') + val += ptr[i] - '0'; + else + parse_error(ERR_INCORRECT_BIN, str); + } + break; + default: + // value is 0 or error + val = 0; + break; + } + } + } + else + { + // Symbol starts with a digit - it's a dec number. + if (ptr[0] >= '0' && ptr[0] <= '9') + { + for (int i = 0; ptr[i] != 0; i++) + { + val *= 10; + if (ptr[i] >= '0' && ptr[i] <= '9') + val += ptr[i] - '0'; + else + parse_error(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; + } + if (cur_pass == 2) + parse_error(ERR_UNKNOWN_LABEL, str); + } + } + if (negative) + return -val; + return val; +} + + +// Modifies both src and dst! +// What does it do, really?? +char *DSPAssembler::find_brackets(char *src, char *dst) +{ + s32 len = (s32) strlen(src); + s32 first = -1; + s32 count = 0; + s32 i, j; + j = 0; + for (i = 0 ; i < len ; i++) + { + if (src[i] == '(') + { + if (first < 0) + { + count = 1; + src[i] = 0x0; + first = i; + } + else + { + count++; + dst[j++] = src[i]; + } + } + else if (src[i] == ')') + { + if (--count == 0) + { + dst[j] = 0; + return &src[i+1]; + } + else + { + dst[j++] = src[i]; + } + } + else + { + if (first >= 0) + dst[j++] = src[i]; + } + } + if (count) + parse_error(ERR_NO_MATCHING_BRACKETS); + return NULL; +} + +// Bizarre in-place expression evaluator. +u32 DSPAssembler::parse_exp(const char *ptr) +{ + char *pbuf; + s32 val = 0; + + char *d_buffer = (char *)malloc(1024); + char *s_buffer = (char *)malloc(1024); + strcpy(s_buffer, ptr); + + while ((pbuf = find_brackets(s_buffer, d_buffer)) != NULL) + { + val = parse_exp(d_buffer); + sprintf(d_buffer, "%s%d%s", s_buffer, val, pbuf); + strcpy(s_buffer, d_buffer); + } + + int j = 0; + for (int i = 0; i < ((s32)strlen(s_buffer) + 1) ; i++) + { + char c = s_buffer[i]; + if (c != ' ') + d_buffer[j++] = c; + } + + for (int i = 0; i < ((s32)strlen(d_buffer) + 1) ; i++) + { + char c = d_buffer[i]; + if (c == '-') + { + if (i == 0) + c = '#'; + else + { + switch (d_buffer[i - 1]) + { + case '/': + case '%': + case '*': + c = '#'; + } + } + } + d_buffer[i] = c; + } + while ((pbuf = strstr(d_buffer, "+")) != NULL) + { + *pbuf = 0x0; + val = parse_exp(d_buffer) + parse_exp(pbuf+1); + sprintf(d_buffer, "%d", val); + } + + while ((pbuf = strstr(d_buffer, "-")) != NULL) + { + *pbuf = 0x0; + val = parse_exp(d_buffer) - parse_exp(pbuf+1); + if (val < 0) + { + val = 0x10000 + (val & 0xffff); // ATTENTION: avoid a terrible bug!!! number cannot write with '-' in sprintf + fprintf(stderr, "WARNING: Number Underflow at Line: %d \n", code_line); + } + sprintf(d_buffer, "%d", val); + } + + while ((pbuf = strstr(d_buffer, "*")) != NULL) + { + *pbuf = 0x0; + val = parse_exp(d_buffer) * parse_exp(pbuf+1); + sprintf(d_buffer, "%d", val); + } + + while ((pbuf = strstr(d_buffer, "/")) != NULL) + { + *pbuf = 0x0; + val = parse_exp(d_buffer) / parse_exp(pbuf+1); + sprintf(d_buffer, "%d", val); + } + + while ((pbuf = strstr(d_buffer, "|")) != NULL) + { + *pbuf = 0x0; + val = parse_exp(d_buffer) | parse_exp(pbuf+1); + sprintf(d_buffer, "%d", val); + } + + while ((pbuf = strstr(d_buffer, "&")) != NULL) + { + *pbuf = 0x0; + val = parse_exp(d_buffer) & parse_exp(pbuf+1); + sprintf(d_buffer, "%d", val); + } + + val = strtoval(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 count = 0; + char *tmpstr = skip_spaces(parstr); + tmpstr = strtok(tmpstr, ",\x00"); + for (int i = 0; i < 10; i++) + { + if (tmpstr == NULL) + break; + tmpstr = skip_spaces(tmpstr); + if (strlen(tmpstr) == 0) + break; + if (tmpstr) + count++; + else + break; + + par[i].type = P_NONE; + switch (tmpstr[0]) + { + case '"': + par[i].str = strtok(tmpstr, "\""); + par[i].type = P_STR; + break; + case '#': + par[i].val = parse_exp_f(tmpstr + 1); + par[i].type = P_IMM; + break; + case '@': + if (tmpstr[1] == '$') + { + par[i].val = parse_exp_f(tmpstr + 2); + par[i].type = P_PRG; + } + else + { + par[i].val = parse_exp_f(tmpstr + 1); + par[i].type = P_MEM; + } + break; + case '$': + par[i].val = parse_exp_f(tmpstr + 1); + par[i].type = P_REG; + break; + default: + par[i].val = parse_exp_f(tmpstr); + par[i].type = P_VAL; + break; + } + tmpstr = strtok(NULL, ",\x00"); + } + return count; +} + +const opc_t *DSPAssembler::find_opcode(const char *opcode, u32 par_count, const opc_t * const opcod, int opcod_size) +{ + if (opcode[0] == 'C' && opcode[1] == 'W') + return &cw; + + AliasMap::const_iterator alias_iter = aliases.find(opcode); + if (alias_iter != aliases.end()) + opcode = alias_iter->second.c_str(); + for (int i = 0; i < opcod_size; i++) + { + const opc_t *opc = &opcod[i]; + if (strcmp(opc->name, opcode) == 0) + { + if (par_count < opc->param_count) + { + parse_error(ERR_NOT_ENOUGH_PARAMETERS); + } + if (par_count > opc->param_count) + { + parse_error(ERR_TOO_MANY_PARAMETERS); + } + return opc; + } + } + parse_error(ERR_UNKNOWN_OPCODE); + return NULL; +} + +// weird... +u16 get_mask_shifted_down(u16 mask) +{ + while (!(mask & 1)) + mask >>= 1; + return mask; +} + +bool DSPAssembler::verify_params(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 ((opc->params[i].type & P_REG) && (par[i].type & P_REG)) + { + // Just a temp. Should be replaced with more purposeful vars. + int value; + + // modified by Hermes: test the register range + switch ((unsigned)opc->params[i].type) + { + case P_REG18: + case P_REG19: + case P_REG1A: + value = (opc->params[i].type >> 8) & 31; + if ((int)par[i].val < value || + (int)par[i].val > value + get_mask_shifted_down(opc->params[i].mask)) + { + if (ext) fprintf(stderr, "(ext) "); + fprintf(stderr, "%s (param %i)", cur_line.c_str(), current_param); + parse_error(ERR_INVALID_REGISTER); + } + break; + case P_PRG: + if ((int)par[i].val < 0 || (int)par[i].val > 0x3) + { + if (ext) fprintf(stderr, "(ext) "); + fprintf(stderr, "%s (param %i)", cur_line.c_str(), current_param); + parse_error(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) + 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) + 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); + } + break; + case P_ACCM: + if ((int)par[i].val < 0x1e || (int)par[i].val > 0x1f) + { + if (ext) fprintf(stderr, "(ext) "); + if (par[i].val >= 0x1c && par[i].val <= 0x1d) + fprintf(stderr, "WARNING: $ACL%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 if (par[i].val >= 0x20 && par[i].val <= 0x21) + 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); + } + break; + + case P_ACCL: + if ((int)par[i].val < 0x1c || (int)par[i].val > 0x1d) + { + if (ext) fprintf(stderr, "(ext) "); + if (par[i].val >= 0x1e && par[i].val <= 0x1f) + { + fprintf(stderr, "%s", cur_line.c_str()); + fprintf(stderr, "WARNING: $ACM%d register used instead of $ACL%d register Line: %d Param: %d\n", + (par[i].val & 1), (par[i].val & 1), code_line, current_param); + } + else if (par[i].val >= 0x20 && par[i].val <= 0x21) { + fprintf(stderr, "%s", cur_line.c_str()); + fprintf(stderr, "WARNING: $ACC%d register used instead of $ACL%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); + } + 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); + } + break;*/ + } + continue; + } + + switch (par[i].type & (P_REG | P_VAL | P_MEM | P_IMM)) + { + case P_REG: + if (ext) fprintf(stderr, "(ext) "); + parse_error(ERR_EXPECTED_PARAM_REG); + break; + case P_MEM: + if (ext) fprintf(stderr, "(ext) "); + parse_error(ERR_EXPECTED_PARAM_MEM); + break; + case P_VAL: + if (ext) fprintf(stderr, "(ext) "); + parse_error(ERR_EXPECTED_PARAM_VAL); + break; + case P_IMM: + if (ext) fprintf(stderr, "(ext) "); + parse_error(ERR_EXPECTED_PARAM_IMM); + break; + } + parse_error(ERR_WRONG_PARAMETER); + break; + } + else if ((opc->params[i].type & 3) != 0 && (par[i].type & 3) != 0) + { + // modified by Hermes: test NUMBER range + int value = get_mask_shifted_down(opc->params[i].mask); + unsigned int valueu = 0xffff & ~(value >> 1); + if ((int)par[i].val < 0) + { + 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); + } + else if (opc->params[i].type == P_MEM) + { + if (value < 256) + fprintf(stderr, "Address value must be from 0x%x to 0x%x\n",valueu, (value>>1)); + else + fprintf(stderr, "Address value must be from 0x0 to 0x%x\n", value); + + parse_error(ERR_OUT_RANGE_NUMBER); + } + else if ((int)par[i].val < -((value >> 1) + 1)) + { + if (value < 128) + fprintf(stderr, "Value must be from -0x%x to 0x%x, is %i\n", + (value >> 1) + 1, value >> 1, par[i].val); + else + 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); + } + } + else + { + if (value == 7) // value 7 por sbclr/sbset + { + 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); + } + } + else if (opc->params[i].type == P_MEM) + { + if (value < 256) + value >>= 1; // addressing 8 bit with sign + if (par[i].val > (unsigned)value && + (par[i].val < valueu || par[i].val > (unsigned)0xffff)) + { + if (value < 256) + 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); + } + } + else + { + if (value < 128) + value >>= 1; // special case ASL/ASR/LSL/LSR + if (par[i].val > (unsigned)value) + { + if (value < 64) + 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); + } + } + } + continue; + } + } + current_param = 0; + return true; +} + + +// Merge opcode with params. +void DSPAssembler::build_code(const opc_t *opc, param_t *par, u32 par_count, u16 *outbuf) +{ + outbuf[cur_addr] |= opc->opcode; + for (u32 i = 0; i < par_count; i++) + { + // Ignore the "reverse" parameters since they are implicit. + if (opc->params[i].type != P_ACC_D && opc->params[i].type != P_ACCM_D) + { + u16 t16 = outbuf[cur_addr + opc->params[i].loc]; + u16 v16 = par[i].val; + if (opc->params[i].lshift > 0) + v16 <<= opc->params[i].lshift; + else + v16 >>= -opc->params[i].lshift; + v16 &= opc->params[i].mask; + outbuf[cur_addr + opc->params[i].loc] = t16 | v16; + } + } +} + +void DSPAssembler::gd_ass_init_pass(int pass) +{ + failed = false; + 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); + } + aliases.clear(); + aliases["S15"] = "SET15"; + aliases["S16"] = "SET16"; + aliases["S40"] = "SET40"; + } + cur_addr = 0; + cur_segment = SEGMENT_CODE; + segment_addr[SEGMENT_CODE] = 0; + segment_addr[SEGMENT_DATA] = 0; + segment_addr[SEGMENT_OVERLAY] = 0; +} + +bool DSPAssembler::gd_ass_file(const char *fname, int pass) +{ + int disable_text = 0; // modified by Hermes + + fsrc = fopen(fname, "r"); + if (fsrc == NULL) + { + fprintf(stderr, "Cannot open %s file\n", fname); + return false; + } + + fseek(fsrc, 0, SEEK_SET); + + printf("Pass %d\n", pass); + code_line = 0; + cur_pass = pass; + +#define LINEBUF_SIZE 1024 + char linebuffer[LINEBUF_SIZE]; + while (!feof(fsrc) && !failed) + { + int opcode_size = 0; + memset(linebuffer, 0, LINEBUF_SIZE); + if (!fgets(linebuffer, LINEBUF_SIZE, fsrc)) + break; + cur_line = linebuffer; + //printf("A: %s", linebuffer); + code_line++; + + param_t params[10] = {0}; + param_t params_ext[10] = {0}; + + for (int i = 0; i < LINEBUF_SIZE; i++) + { + char c = linebuffer[i]; + // This stuff handles /**/ and // comments. + // modified by Hermes : added // and /* */ for long comentaries + if (c == '/') + { + if (i < 1023) + { + if (linebuffer[i+1] == '/') + c = 0x00; + else if (linebuffer[i+1] == '*') + { + // toggle comment mode. + disable_text = !disable_text; + } + } + } + else if (c == '*') + { + if (i < 1023 && linebuffer[i+1] == '/' && disable_text) + { + disable_text = 0; + c = 32; + linebuffer[i + 1] = 32; + } + } + + // turn text into spaces if disable_text is on (in a comment). + if (disable_text && ((unsigned char)c) > 32) c = 32; + + if (c == 0x0a || c == 0x0d || c == ';') + c = 0x00; + if (c == 0x09) // tabs to spaces + c = ' '; + if (c >= 'a' && c <= 'z') // convert to uppercase + c = c - 'a' + 'A'; + linebuffer[i] = c; + if (c == 0) + break; // modified by Hermes + } + char *ptr = linebuffer; + + char *opcode = NULL; + char *label = NULL; + char *col_ptr; + if ((col_ptr = strstr(ptr, ":")) != NULL) + { + int j; + bool valid; + j = 0; + valid = true; + while ((ptr+j) < col_ptr) + { + if (j == 0) + if (!((ptr[j] >= 'A' && ptr[j] <= 'Z') || (ptr[j] == '_'))) + valid = false; + if (!((ptr[j] >= '0' && ptr[j] <= '9') || (ptr[j] >= 'A' && ptr[j] <= 'Z') || (ptr[j] == '_'))) + valid = false; + j++; + } + if (valid) + { + label = strtok(ptr, ":\x20"); + ptr = col_ptr + 1; + } + } + + opcode = strtok(ptr, " "); + char *opcode_ext = NULL; + + u32 params_count = 0; + u32 params_count_ext = 0; + if (opcode) + { + if ((opcode_ext = strstr(opcode, "'")) != NULL) + { + opcode_ext[0] = '\0'; + opcode_ext++; + if (strlen(opcode_ext) == 0) + opcode_ext = NULL; + } + // now we have opcode and label + + params_count = 0; + params_count_ext = 0; + + char *paramstr = strtok(NULL, "\0"); + char *paramstr_ext = 0; + // there is valid opcode so probably we have parameters + + if (paramstr) + { + if ((paramstr_ext = strstr(paramstr, ":")) != NULL) + { + paramstr_ext[0] = '\0'; + paramstr_ext++; + } + } + + if (paramstr) + params_count = get_params(paramstr, params); + if (paramstr_ext) + params_count_ext = get_params(paramstr_ext, params_ext); + } + + if (label) + { + // there is a valid label so lets store it in labels table + u32 lval = cur_addr; + if (opcode) + { + if (strcmp(opcode, "EQU") == 0) + { + lval = params[0].val; + opcode = NULL; + } + } + if (pass == 1) + gd_ass_register_label(label, lval); + } + + if (opcode == NULL) + continue; + + // check if opcode is reserved compiler word + if (strcmp("INCLUDE", opcode) == 0) + { + if (params[0].type == P_STR) + { + char *tmpstr; + if (include_dir.size()) + { + tmpstr = (char *)malloc(include_dir.size() + strlen(params[0].str) + 2); + sprintf(tmpstr, "%s/%s", include_dir.c_str(), params[0].str); + } + else + { + tmpstr = (char *)malloc(strlen(params[0].str) + 1); + strcpy(tmpstr, params[0].str); + } + gd_ass_file(tmpstr, pass); + free(tmpstr); + } + else + parse_error(ERR_EXPECTED_PARAM_STR); + continue; + } + + if (strcmp("INCDIR", opcode) == 0) + { + if (params[0].type == P_STR) + include_dir = params[0].str; + else + parse_error(ERR_EXPECTED_PARAM_STR); + continue; + } + + if (strcmp("ORG", opcode) == 0) + { + if (params[0].type == P_VAL) + cur_addr = params[0].val; + else + parse_error(ERR_EXPECTED_PARAM_VAL); + continue; + } + + if (strcmp("SEGMENT", opcode) == 0) + { + if (params[0].type == P_STR) + { + segment_addr[cur_segment] = cur_addr; + if (strcmp("DATA", params[0].str) == 0) + cur_segment = SEGMENT_DATA; + if (strcmp("CODE", params[0].str) == 0) + cur_segment = SEGMENT_CODE; + cur_addr = segment_addr[cur_segment]; + } + else + parse_error(ERR_EXPECTED_PARAM_STR); + continue; + } + + const opc_t *opc = find_opcode(opcode, params_count, opcodes, opcodes_size); + if (!opc) + opc = &cw; + + opcode_size = opc->size & ~P_EXT; + + verify_params(opc, params, params_count); + + const opc_t *opc_ext = NULL; + // Check for opcode extensions. + if (opc->size & P_EXT) + { + 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); + } + else if (params_count_ext) + parse_error(ERR_EXT_PAR_NOT_EXT); + } + else + { + if (opcode_ext) + parse_error(ERR_EXT_CANT_EXTEND_OPCODE); + if (params_count_ext) + parse_error(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); + if (opc_ext) + build_code(opc_ext, params_ext, params_count_ext, (u16 *)gdg_buffer); + } + + cur_addr += opcode_size; + }; + if (gdg_buffer == NULL) + { + gdg_buffer_size = cur_addr; + gdg_buffer = (char *)malloc(gdg_buffer_size * sizeof(u16) + 4); + memset(gdg_buffer, 0, gdg_buffer_size * sizeof(u16)); + } + fclose(fsrc); + return !failed; +} diff --git a/Source/Core/DSPCore/Src/assemble.h b/Source/Core/DSPCore/Src/assemble.h index 55f930e6de..af3db5dca1 100644 --- a/Source/Core/DSPCore/Src/assemble.h +++ b/Source/Core/DSPCore/Src/assemble.h @@ -31,32 +31,32 @@ #include "Common.h" #include "disassemble.h" #include "DSPTables.h" - -enum err_t -{ - ERR_OK = 0, - ERR_UNKNOWN, - ERR_UNKNOWN_OPCODE, - ERR_NOT_ENOUGH_PARAMETERS, - ERR_TOO_MANY_PARAMETERS, - ERR_WRONG_PARAMETER, - ERR_EXPECTED_PARAM_STR, - ERR_EXPECTED_PARAM_VAL, - ERR_EXPECTED_PARAM_REG, - ERR_EXPECTED_PARAM_MEM, - ERR_EXPECTED_PARAM_IMM, - ERR_INCORRECT_BIN, - ERR_INCORRECT_HEX, - ERR_INCORRECT_DEC, - ERR_LABEL_EXISTS, - ERR_UNKNOWN_LABEL, - ERR_NO_MATCHING_BRACKETS, - ERR_EXT_CANT_EXTEND_OPCODE, - ERR_EXT_PAR_NOT_EXT, - ERR_WRONG_PARAMETER_ACC, - ERR_WRONG_PARAMETER_MID_ACC, - ERR_INVALID_REGISTER, - ERR_OUT_RANGE_NUMBER + +enum err_t +{ + ERR_OK = 0, + ERR_UNKNOWN, + ERR_UNKNOWN_OPCODE, + ERR_NOT_ENOUGH_PARAMETERS, + ERR_TOO_MANY_PARAMETERS, + ERR_WRONG_PARAMETER, + ERR_EXPECTED_PARAM_STR, + ERR_EXPECTED_PARAM_VAL, + ERR_EXPECTED_PARAM_REG, + ERR_EXPECTED_PARAM_MEM, + ERR_EXPECTED_PARAM_IMM, + ERR_INCORRECT_BIN, + ERR_INCORRECT_HEX, + ERR_INCORRECT_DEC, + ERR_LABEL_EXISTS, + ERR_UNKNOWN_LABEL, + ERR_NO_MATCHING_BRACKETS, + ERR_EXT_CANT_EXTEND_OPCODE, + ERR_EXT_PAR_NOT_EXT, + ERR_WRONG_PARAMETER_ACC, + ERR_WRONG_PARAMETER_MID_ACC, + ERR_INVALID_REGISTER, + ERR_OUT_RANGE_NUMBER }; // Unless you want labels to carry over between files, you probably @@ -64,72 +64,69 @@ enum err_t class DSPAssembler { public: - DSPAssembler(); + DSPAssembler(const AssemblerSettings &settings); ~DSPAssembler(); void Assemble(const char *text, std::vector *code); - - typedef struct fass_t - { - FILE *fsrc; - u32 code_line; - bool failed; - } fass_t; - - struct label_t - { - char *label; - s32 addr; - }; - - struct param_t - { - u32 val; - partype_t type; - char *str; - }; - - enum segment_t - { - SEGMENT_CODE = 0, - SEGMENT_DATA, - SEGMENT_OVERLAY, - SEGMENT_MAX + + struct label_t + { + label_t(const char *lbl, s32 address) : label(lbl), addr(address) {} + std::string label; + s32 addr; }; - void gd_ass_init_pass(int pass); - bool gd_ass_file(gd_globals_t *gdg, const char *fname, int pass); + + struct param_t + { + u32 val; + partype_t type; + char *str; + }; + + enum segment_t + { + SEGMENT_CODE = 0, + SEGMENT_DATA, + SEGMENT_OVERLAY, + SEGMENT_MAX + }; + void gd_ass_init_pass(int pass); + bool gd_ass_file(const char *fname, int pass); + + char *gdg_buffer; + int gdg_buffer_size; private: - void parse_error(err_t err_code, fass_t *fa, const char *extra_info = NULL); - void gd_ass_register_label(const char *label, u16 lval); - void gd_ass_clear_labels(); - s32 strtoval(const char *str); - char *find_brackets(char *src, char *dst); - u32 parse_exp(const char *ptr); - u32 parse_exp_f(const char *ptr, fass_t *fa); - u32 get_params(char *parstr, param_t *par, fass_t *fa); - const opc_t *find_opcode(const char *opcode, u32 par_count, const opc_t * const opcod, u32 opcod_size, fass_t *fa); - bool verify_params(const opc_t *opc, param_t *par, u32 count, fass_t *fa); - void build_code(const opc_t *opc, param_t *par, u32 par_count, u16 *outbuf); + 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); - char *include_dir; - - label_t labels[10000]; - int labels_count; - - char cur_line[4096]; - - u32 cur_addr; - u8 cur_pass; - fass_t *cur_fa; - - typedef std::map AliasMap; - AliasMap aliases; - - segment_t cur_segment; - u32 segment_addr[SEGMENT_MAX]; - - int current_param; + std::string include_dir; + std::vector labels; + std::string cur_line; + + u32 cur_addr; + u8 cur_pass; + + FILE *fsrc; + u32 code_line; + bool failed; + + typedef std::map AliasMap; + AliasMap aliases; + + segment_t cur_segment; + u32 segment_addr[SEGMENT_MAX]; + int current_param; + const AssemblerSettings settings_; }; #endif // _DSP_ASSEMBLE_H \ No newline at end of file diff --git a/Source/Core/DSPCore/Src/disassemble.cpp b/Source/Core/DSPCore/Src/disassemble.cpp index d22a8c6451..32fb1d0817 100644 --- a/Source/Core/DSPCore/Src/disassemble.cpp +++ b/Source/Core/DSPCore/Src/disassemble.cpp @@ -34,25 +34,23 @@ #pragma warning(disable:4996) #endif -u32 unk_opcodes[0x10000]; - extern void nop(const UDSPInstruction& opc); -DSPDisassembler::DSPDisassembler() +DSPDisassembler::DSPDisassembler(const AssemblerSettings &settings) + : settings_(settings) { + memset(unk_opcodes, 0, sizeof(unk_opcodes)); } -char* DSPDisassembler::gd_dis_params(gd_globals_t* gdg, const DSPOPCTemplate* opc, - u16 op1, u16 op2, char* strbuf) +char *DSPDisassembler::gd_dis_params(const DSPOPCTemplate* opc, u16 op1, u16 op2, char *strbuf) { - char* buf = strbuf; - u32 val; - + char *buf = strbuf; for (int j = 0; j < opc->param_count; j++) { if (j > 0) buf += sprintf(buf, ", "); + u32 val; if (opc->params[j].loc >= 1) val = op2; else @@ -83,21 +81,21 @@ char* DSPDisassembler::gd_dis_params(gd_globals_t* gdg, const DSPOPCTemplate* op switch (type) { case P_REG: - if (gdg->decode_registers) + if (settings_.decode_registers) sprintf(buf, "$%s", pdregname(val)); else sprintf(buf, "$%d", val); break; case P_PRG: - if (gdg->decode_registers) + if (settings_.decode_registers) sprintf(buf, "@$%s", pdregname(val)); else sprintf(buf, "@$%d", val); break; case P_VAL: - if (gdg->decode_names) + if (settings_.decode_names) sprintf(buf, "%s", pdname(val)); else sprintf(buf, "0x%04x", val); @@ -119,7 +117,7 @@ char* DSPDisassembler::gd_dis_params(gd_globals_t* gdg, const DSPOPCTemplate* op if (opc->params[j].size != 2) val = (u16)(s8)val; - if (gdg->decode_names) + if (settings_.decode_names) sprintf(buf, "@%s", pdname(val)); else sprintf(buf, "@0x%04x", val); @@ -127,7 +125,6 @@ char* DSPDisassembler::gd_dis_params(gd_globals_t* gdg, const DSPOPCTemplate* op default: ERROR_LOG(DSPLLE, "Unknown parameter type: %x", opc->params[j].type); -// exit(-1); break; } @@ -137,6 +134,7 @@ char* DSPDisassembler::gd_dis_params(gd_globals_t* gdg, const DSPOPCTemplate* op return strbuf; } +#if 0 u16 gd_dis_get_opcode_size(gd_globals_t* gdg) { const DSPOPCTemplate* opc = 0; @@ -168,7 +166,6 @@ u16 gd_dis_get_opcode_size(gd_globals_t* gdg) if (!opc) { ERROR_LOG(DSPLLE, "get_opcode_size ARGH"); - exit(0); } if (opc->size & P_EXT && op1 & 0x00ff) @@ -197,28 +194,27 @@ u16 gd_dis_get_opcode_size(gd_globals_t* gdg) return opc->size & ~P_EXT; } +#endif -char* DSPDisassembler::gd_dis_opcode(gd_globals_t* gdg) +void DSPDisassembler::gd_dis_opcode(const u16 *binbuf, u16 *pc, std::string *dest) { u32 op2; - char *buf = gdg->buffer; - - u16 pc = gdg->pc; - + char buffer[256]; + char *buf = buffer; // Start with a space. buf[0] = ' '; buf[1] = '\0'; buf++; - if ((pc & 0x7fff) >= 0x1000) + if ((*pc & 0x7fff) >= 0x1000) { - gdg->pc++; - return gdg->buffer; + *pc++; + return; } - pc &= 0x0fff; - u32 op1 = gdg->binbuf[pc]; + *pc &= 0x0fff; + const u32 op1 = binbuf[*pc]; const DSPOPCTemplate *opc = NULL; const DSPOPCTemplate *opc_ext = NULL; @@ -239,7 +235,6 @@ char* DSPDisassembler::gd_dis_opcode(gd_globals_t* gdg) } } - const DSPOPCTemplate fake_op = {"CW", 0x0000, 0x0000, nop, nop, 1, 1, {{P_VAL, 2, 0, 0, 0xffff}}, NULL, NULL,}; if (!opc) opc = &fake_op; @@ -266,23 +261,22 @@ char* DSPDisassembler::gd_dis_opcode(gd_globals_t* gdg) // printing - if (gdg->show_pc) - sprintf(buf, "%04x ", gdg->pc); + if (settings_.show_pc) + sprintf(buf, "%04x ", *pc); buf += strlen(buf); if ((opc->size & ~P_EXT) == 2) { - op2 = gdg->binbuf[pc + 1]; - - if (gdg->show_hex) + op2 = binbuf[*pc + 1]; + if (settings_.show_hex) sprintf(buf, "%04x %04x ", op1, op2); } else { op2 = 0; - if (gdg->show_hex) + if (settings_.show_hex) sprintf(buf, "%04x ", op1); } @@ -291,11 +285,11 @@ char* DSPDisassembler::gd_dis_opcode(gd_globals_t* gdg) char tmpbuf[20]; if (extended) - sprintf(tmpbuf, "%s%c%s", opc->name, gdg->ext_separator, opc_ext->name); + sprintf(tmpbuf, "%s%c%s", opc->name, settings_.ext_separator, opc_ext->name); else sprintf(tmpbuf, "%s", opc->name); - if (gdg->print_tabs) + if (settings_.print_tabs) sprintf(buf, "%s\t", tmpbuf); else sprintf(buf, "%-12s", tmpbuf); @@ -303,7 +297,7 @@ char* DSPDisassembler::gd_dis_opcode(gd_globals_t* gdg) buf += strlen(buf); if (opc->param_count > 0) - gd_dis_params(gdg, opc, op1, op2, buf); + gd_dis_params(opc, op1, op2, buf); buf += strlen(buf); @@ -318,7 +312,7 @@ char* DSPDisassembler::gd_dis_opcode(gd_globals_t* gdg) buf += strlen(buf); if (opc_ext->param_count > 0) - gd_dis_params(gdg, opc_ext, op1, op2, buf); + gd_dis_params(opc_ext, op1, op2, buf); buf += strlen(buf); } @@ -331,14 +325,14 @@ char* DSPDisassembler::gd_dis_opcode(gd_globals_t* gdg) } if (extended) - gdg->pc += opc_ext->size; + *pc += opc_ext->size; else - gdg->pc += opc->size & ~P_EXT; + *pc += opc->size & ~P_EXT; - return gdg->buffer; + dest->append(buffer); } -bool DSPDisassembler::gd_dis_file(gd_globals_t* gdg, const char* name, FILE* output) +bool DSPDisassembler::gd_dis_file(const char* name, FILE* output) { gd_dis_open_unkop(); @@ -354,23 +348,20 @@ bool DSPDisassembler::gd_dis_file(gd_globals_t* gdg, const char* name, FILE* out fseek(in, 0, SEEK_END); size = (int)ftell(in); fseek(in, 0, SEEK_SET); - gdg->binbuf = (u16*)malloc(size); - fread(gdg->binbuf, 1, size, in); - gdg->buffer = (char*)malloc(256); - gdg->buffer_size = 256; + u16 *binbuf = (u16*)malloc(size); + fread(binbuf, 1, size, in); - for (gdg->pc = 0; gdg->pc < (size / 2);) - fprintf(output, "%s\n", gd_dis_opcode(gdg)); + for (u16 pc = 0; pc < (size / 2);) + { + std::string str; + gd_dis_opcode(binbuf, &pc, &str); + fprintf(output, "%s\n", str.c_str()); + } fclose(in); - free(gdg->binbuf); - gdg->binbuf = NULL; - - free(gdg->buffer); - gdg->buffer = NULL; - gdg->buffer_size = 0; + free(binbuf); gd_dis_close_unkop(); diff --git a/Source/Core/DSPCore/Src/disassemble.h b/Source/Core/DSPCore/Src/disassemble.h index 886e8bb637..c59361a5bf 100644 --- a/Source/Core/DSPCore/Src/disassemble.h +++ b/Source/Core/DSPCore/Src/disassemble.h @@ -28,40 +28,55 @@ #include "Common.h" #include "DSPTables.h" -struct gd_globals_t +struct AssemblerSettings { + AssemblerSettings() + : print_tabs(false), + show_hex(false), + show_pc(false), + decode_names(true), + decode_registers(true), + ext_separator('\'') + { + } + bool print_tabs; bool show_hex; bool show_pc; bool decode_names; bool decode_registers; + bool lower_case_ops; + char ext_separator; - u16* binbuf; + u16 *binbuf; u16 pc; char* buffer; u16 buffer_size; - char ext_separator; }; class DSPDisassembler { public: - DSPDisassembler(); + DSPDisassembler(const AssemblerSettings &settings); ~DSPDisassembler() {} - char* gd_dis_opcode(gd_globals_t* gdg); - bool gd_dis_file(gd_globals_t* gdg, const char* name, FILE* output); + // Moves PC forward and writes the result to dest. + void gd_dis_opcode(const u16 *binbuf, u16 *pc, std::string *dest); + bool gd_dis_file(const char* name, FILE *output); void gd_dis_close_unkop(); void gd_dis_open_unkop(); const char* gd_dis_get_reg_name(u16 reg); private: - char* gd_dis_params(gd_globals_t* gdg, const DSPOPCTemplate* opc, u16 op1, u16 op2, char* strbuf); + char* gd_dis_params(const DSPOPCTemplate* opc, u16 op1, u16 op2, char* strbuf); + u32 unk_opcodes[0x10000]; + + const AssemblerSettings settings_; }; const char *gd_get_reg_name(u16 reg); -u16 gd_dis_get_opcode_size(gd_globals_t* gdg); +//u16 gd_dis_get_opcode_size(gd_globals_t* gdg); #endif // _DSP_DISASSEMBLE_H diff --git a/Source/DSPTool/Src/main.cpp b/Source/DSPTool/Src/main.cpp index 5333dcca33..d049447dc0 100644 --- a/Source/DSPTool/Src/main.cpp +++ b/Source/DSPTool/Src/main.cpp @@ -88,7 +88,6 @@ void RunAsmTests() #define CHK(a) if (!SuperTrip(a)) printf("FAIL\n%s\n", a), fail = true; // Let's start out easy - a trivial instruction.. -#if 0 CHK(" NOP\n"); // Now let's do several. @@ -114,25 +113,29 @@ void RunAsmTests() " si @0xfffd, #0xbeef\n" " si @DIRQ, #0x0001\n"); + // Let's try some messy extended instructions. + //CHK(" MULMV'SN $AX0.L, $AX0.H, $ACC0 : @$AR2, $AC1.M\n"); + + //" 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. - +/* puts("Insane Random Code Test\n"); std::vector rand_code; - GenRandomCode(21, &rand_code); + GenRandomCode(31, &rand_code); std::string rand_code_text; - Disassemble(rand_code, &rand_code_text); + Disassemble(rand_code, true, &rand_code_text); printf("%s", rand_code_text.c_str()); RoundTrip(rand_code); -#endif - +*/ std::string dsp_test; - //File::ReadStringFromFile(true, "C:/devkitPro/examples/wii/asndlib/dsptest/dsp_test.ds", &dsp_test); - File::ReadFileToString(true, "C:/devkitPro/trunk/libogc/libasnd/dsp_mixer/dsp_mixer.s", &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. - SuperTrip(dsp_test.c_str()); if (!fail) printf("All passed!\n"); diff --git a/Source/Plugins/Plugin_DSP_LLE/Src/Debugger/Debugger.cpp b/Source/Plugins/Plugin_DSP_LLE/Src/Debugger/Debugger.cpp index 78b20731c0..0e6b9f34ef 100644 --- a/Source/Plugins/Plugin_DSP_LLE/Src/Debugger/Debugger.cpp +++ b/Source/Plugins/Plugin_DSP_LLE/Src/Debugger/Debugger.cpp @@ -190,26 +190,27 @@ void DSPDebuggerLLE::RebuildDisAsmListView() m_Disasm->DeleteAllItems(); char Buffer[256]; - gd_globals_t gdg; + AssemblerSettings settings; + const u16 *binbuf; if (g_dsp.pc & 0x8000) - gdg.binbuf = g_dsp.irom; + binbuf = g_dsp.irom; else - gdg.binbuf = g_dsp.iram; + binbuf = g_dsp.iram; - gdg.buffer = Buffer; - gdg.buffer_size = 256; - gdg.ext_separator = (char)0xff; + settings.buffer = Buffer; + settings.buffer_size = 256; + settings.ext_separator = (char)0xff; - gdg.show_pc = false; - gdg.show_hex = false; - gdg.print_tabs = true; - gdg.decode_names = true; - gdg.decode_registers = true; + settings.show_pc = false; + settings.show_hex = false; + settings.print_tabs = true; + settings.decode_names = true; + settings.decode_registers = true; - for (gdg.pc = 0; gdg.pc < DSP_IROM_SIZE;) + for (settings.pc = 0; settings.pc < DSP_IROM_SIZE;) { - u16 CurrentPC = gdg.pc; + u16 CurrentPC = settings.pc; if (g_dsp.pc & 0x8000) CurrentPC |= 0x8000; @@ -220,13 +221,16 @@ void DSPDebuggerLLE::RebuildDisAsmListView() char Temp2[256]; sprintf(Temp2, "0x%04x", dsp_imem_read(CurrentPC)); - DSPDisassembler disasm; - char* pOpcode = disasm.gd_dis_opcode(&gdg); + AssemblerSettings settings; + DSPDisassembler disasm(settings); + std::string op_str; + disasm.gd_dis_opcode(binbuf,&settings.pc, &op_str); const char* pParameter = NULL; const char* pExtension = NULL; - size_t WholeString = strlen(pOpcode); + size_t WholeString = op_str.size(); + /* for (size_t i = 0; i < WholeString; i++) { if (pOpcode[i] == (char)0xff) @@ -240,7 +244,7 @@ void DSPDebuggerLLE::RebuildDisAsmListView() pOpcode[i] = 0x00; pParameter = &pOpcode[i + 1]; } - } + }*/ const char* pFunctionName = NULL; @@ -249,15 +253,15 @@ void DSPDebuggerLLE::RebuildDisAsmListView() pFunctionName = m_SymbolMap[CurrentPC].Name.c_str(); } - int Item = m_Disasm->InsertItem(gdg.pc, wxEmptyString); + int Item = m_Disasm->InsertItem(settings.pc, wxEmptyString); m_Disasm->SetItem(Item, COLUMN_BP, wxEmptyString); m_Disasm->SetItem(Item, COLUMN_FUNCTION, wxString::FromAscii(pFunctionName)); m_Disasm->SetItem(Item, COLUMN_ADDRESS, wxString::FromAscii(Temp)); m_Disasm->SetItem(Item, COLUMN_MNEMONIC, wxString::FromAscii(Temp2)); - m_Disasm->SetItem(Item, COLUMN_OPCODE, wxString::FromAscii(pOpcode)); + m_Disasm->SetItem(Item, COLUMN_OPCODE, wxString::FromAscii(op_str.c_str())); m_Disasm->SetItem(Item, COLUMN_EXT, wxString::FromAscii(pExtension)); - if (!strcasecmp(pOpcode, "CALL")) + if (!strcasecmp(op_str.c_str(), "CALL")) { u32 FunctionAddress = -1; sscanf(pParameter, "0x%04x", &FunctionAddress); diff --git a/Source/Plugins/Plugin_DSP_LLE/Src/Tools.cpp b/Source/Plugins/Plugin_DSP_LLE/Src/Tools.cpp index 639bad939d..2304655b7a 100644 --- a/Source/Plugins/Plugin_DSP_LLE/Src/Tools.cpp +++ b/Source/Plugins/Plugin_DSP_LLE/Src/Tools.cpp @@ -60,15 +60,15 @@ bool DisasmUCodeDump(u32 crc) FILE* t = fopen(txtFile, "wb"); if (t != NULL) { - gd_globals_t gdg; - memset(&gdg, 0, sizeof(gdg)); - gdg.show_hex = true; - gdg.show_pc = true; - gdg.ext_separator = '\t'; - gdg.decode_names = true; - gdg.decode_registers = true; - DSPDisassembler disasm; - disasm.gd_dis_file(&gdg, binFile, t); + AssemblerSettings settings; + memset(&settings, 0, sizeof(settings)); + settings.show_hex = true; + settings.show_pc = true; + settings.ext_separator = '\t'; + settings.decode_names = true; + settings.decode_registers = true; + DSPDisassembler disasm(settings); + disasm.gd_dis_file(binFile, t); fclose(t); return true; }