project64/Source/Project64/UserInterface/Debugger/Assembler.cpp

684 lines
22 KiB
C++

#include "stdafx.h"
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "Assembler.h"
#include "Project64-core/N64System/Mips/R4300iOpcode.h"
ASM_PARSE_ERROR CAssembler::m_ParseError = ERR_NONE;
uint32_t CAssembler::m_Address = 0;
char * CAssembler::m_TokContext = nullptr;
const ASM_SYNTAX_FN CAssembler::syn_jump[] = {arg_jump, nullptr};
const ASM_SYNTAX_FN CAssembler::syn_loadstore[] = {arg_reg_t, arg_imm16, arg_reg_s, nullptr};
const ASM_SYNTAX_FN CAssembler::syn_arith[] = {arg_reg_d, arg_reg_s, arg_reg_t, nullptr};
const ASM_SYNTAX_FN CAssembler::syn_arith2[] = {arg_reg_s, arg_reg_t, nullptr};
const ASM_SYNTAX_FN CAssembler::syn_shiftv[] = {arg_reg_d, arg_reg_t, arg_reg_s, nullptr};
const ASM_SYNTAX_FN CAssembler::syn_arith_i[] = {arg_reg_t, arg_reg_s, arg_imm16, nullptr};
const ASM_SYNTAX_FN CAssembler::syn_load_i[] = {arg_reg_t, arg_imm16, nullptr};
const ASM_SYNTAX_FN CAssembler::syn_branch_z[] = {arg_reg_s, arg_bra_target, nullptr};
const ASM_SYNTAX_FN CAssembler::syn_branch[] = {arg_reg_s, arg_reg_t, arg_bra_target, nullptr};
const ASM_SYNTAX_FN CAssembler::syn_branch_unc[] = {arg_bra_target, nullptr};
const ASM_SYNTAX_FN CAssembler::syn_trap_i[] = {arg_reg_s, arg_imm16, nullptr};
const ASM_SYNTAX_FN CAssembler::syn_shift[] = {arg_reg_d, arg_reg_t, arg_shamt, nullptr};
const ASM_SYNTAX_FN CAssembler::syn_mf[] = {arg_reg_d, nullptr};
const ASM_SYNTAX_FN CAssembler::syn_jr[] = {arg_reg_s, nullptr};
const ASM_SYNTAX_FN CAssembler::syn_jalr[] = {arg_reg_d, arg_reg_s, nullptr};
const ASM_SYNTAX_FN CAssembler::syn_cop1_arith[] = {arg_reg_fd, arg_reg_fs, arg_reg_ft, nullptr};
const ASM_SYNTAX_FN CAssembler::syn_cop1[] = {arg_reg_fd, arg_reg_fs, nullptr};
const ASM_SYNTAX_FN CAssembler::syn_cop1_cmp[] = {arg_reg_fs, arg_reg_ft, nullptr};
const ASM_SYNTAX_FN CAssembler::syn_cop_mv[] = {arg_reg_t, arg_reg_d, nullptr};
const ASM_SYNTAX_FN CAssembler::syn_cache[] = {arg_cache_op, arg_imm16, arg_reg_s, nullptr};
const ASM_SYNTAX_FN CAssembler::syn_syscall[] = {arg_syscall_code, nullptr};
const ASM_INSTRUCTION CAssembler::m_Instructions[] = {
{"j", R4300i_J, base_op, syn_jump},
{"jal", R4300i_JAL, base_op, syn_jump},
{"beq", R4300i_BEQ, base_op, syn_branch},
{"beqz", R4300i_BEQ, base_op, syn_branch_z},
{"b", R4300i_BEQ, base_op, syn_branch_unc},
{"bne", R4300i_BNE, base_op, syn_branch},
{"bnez", R4300i_BNE, base_op, syn_branch_z},
{"blez", R4300i_BLEZ, base_op, syn_branch_z},
{"bgtz", R4300i_BGTZ, base_op, syn_branch_z},
{"addi", R4300i_ADDI, base_op, syn_arith_i},
{"addiu", R4300i_ADDIU, base_op, syn_arith_i},
{"slti", R4300i_SLTI, base_op, syn_arith_i},
{"sltiu", R4300i_SLTIU, base_op, syn_arith_i},
{"andi", R4300i_ANDI, base_op, syn_arith_i},
{"ori", R4300i_ORI, base_op, syn_arith_i},
{"xori", R4300i_XORI, base_op, syn_arith_i},
{"lui", R4300i_LUI, base_op, syn_load_i},
{"beql", R4300i_BEQL, base_op, syn_branch},
{"beqzl", R4300i_BEQL, base_op, syn_branch_z},
{"bnel", R4300i_BNEL, base_op, syn_branch},
{"bnezl", R4300i_BNEL, base_op, syn_branch_z},
{"blezl", R4300i_BLEZL, base_op, syn_branch_z},
{"bgtzl", R4300i_BGTZL, base_op, syn_branch_z},
{"daddi", R4300i_DADDI, base_op, syn_arith_i},
{"daddiu", R4300i_DADDIU, base_op, syn_arith_i},
{"ldl", R4300i_LDL, base_op, syn_loadstore},
{"ldr", R4300i_LDR, base_op, syn_loadstore},
{"lb", R4300i_LB, base_op, syn_loadstore},
{"lh", R4300i_LH, base_op, syn_loadstore},
{"lwl", R4300i_LWL, base_op, syn_loadstore},
{"lw", R4300i_LW, base_op, syn_loadstore},
{"lbu", R4300i_LBU, base_op, syn_loadstore},
{"lhu", R4300i_LHU, base_op, syn_loadstore},
{"lwr", R4300i_LWR, base_op, syn_loadstore},
{"lwu", R4300i_LWU, base_op, syn_loadstore},
{"sb", R4300i_SB, base_op, syn_loadstore},
{"sh", R4300i_SH, base_op, syn_loadstore},
{"swl", R4300i_SWL, base_op, syn_loadstore},
{"sw", R4300i_SW, base_op, syn_loadstore},
{"sdl", R4300i_SDL, base_op, syn_loadstore},
{"sdr", R4300i_SDR, base_op, syn_loadstore},
{"swr", R4300i_SWR, base_op, syn_loadstore},
{"cache", R4300i_CACHE, base_op, syn_cache},
{"ll", R4300i_LL, base_op, syn_loadstore},
{"lwc1", R4300i_LWC1, base_op, syn_loadstore},
{"ldc1", R4300i_LDC1, base_op, syn_loadstore},
{"ld", R4300i_LD, base_op, syn_loadstore},
{"sc", R4300i_SC, base_op, syn_loadstore},
{"swc1", R4300i_SWC1, base_op, syn_loadstore},
{"sdc1", R4300i_SDC1, base_op, syn_loadstore},
{"sdc2", R4300i_SDC2, base_op, syn_loadstore},
{"sd", R4300i_SD, base_op, syn_loadstore},
{"sll", R4300i_SPECIAL_SLL, base_spec, syn_shift},
{"nop", R4300i_SPECIAL_SLL, base_spec, nullptr},
{"srl", R4300i_SPECIAL_SRL, base_spec, syn_shift},
{"sra", R4300i_SPECIAL_SRA, base_spec, syn_shift},
{"sllv", R4300i_SPECIAL_SLLV, base_spec, syn_shiftv},
{"srlv", R4300i_SPECIAL_SRLV, base_spec, syn_shiftv},
{"srav", R4300i_SPECIAL_SRAV, base_spec, syn_shiftv},
{"jr", R4300i_SPECIAL_JR, base_spec, syn_jr},
{"jalr", R4300i_SPECIAL_JALR, base_spec, syn_jalr},
{"jalr", R4300i_SPECIAL_JALR, base_spec_jalr_ra, syn_jr},
{"syscall", R4300i_SPECIAL_SYSCALL, base_spec, syn_syscall},
{"break", R4300i_SPECIAL_BREAK, base_spec, syn_syscall},
{"sync", R4300i_SPECIAL_SYNC, base_spec, nullptr},
{"mfhi", R4300i_SPECIAL_MFHI, base_spec, syn_mf},
{"mthi", R4300i_SPECIAL_MTHI, base_spec, syn_mf},
{"mflo", R4300i_SPECIAL_MFLO, base_spec, syn_mf},
{"mtlo", R4300i_SPECIAL_MTLO, base_spec, syn_mf},
{"dsllv", R4300i_SPECIAL_DSLLV, base_spec, syn_shiftv},
{"dsrlv", R4300i_SPECIAL_DSRLV, base_spec, syn_shiftv},
{"dsrav", R4300i_SPECIAL_DSRAV, base_spec, syn_shiftv},
{"mult", R4300i_SPECIAL_MULT, base_spec, syn_arith2},
{"multu", R4300i_SPECIAL_MULTU, base_spec, syn_arith2},
{"div", R4300i_SPECIAL_DIV, base_spec, syn_arith2},
{"divu", R4300i_SPECIAL_DIVU, base_spec, syn_arith2},
{"dmult", R4300i_SPECIAL_DMULT, base_spec, syn_arith2},
{"dmultu", R4300i_SPECIAL_DMULTU, base_spec, syn_arith2},
{"ddiv", R4300i_SPECIAL_DDIV, base_spec, syn_arith2},
{"ddivu", R4300i_SPECIAL_DDIVU, base_spec, syn_arith2},
{"add", R4300i_SPECIAL_ADD, base_spec, syn_arith},
{"addu", R4300i_SPECIAL_ADDU, base_spec, syn_arith},
{"sub", R4300i_SPECIAL_SUB, base_spec, syn_arith},
{"subu", R4300i_SPECIAL_SUBU, base_spec, syn_arith},
{"and", R4300i_SPECIAL_AND, base_spec, syn_arith},
{"or", R4300i_SPECIAL_OR, base_spec, syn_arith},
{"xor", R4300i_SPECIAL_XOR, base_spec, syn_arith},
{"nor", R4300i_SPECIAL_NOR, base_spec, syn_arith},
{"slt", R4300i_SPECIAL_SLT, base_spec, syn_arith},
{"sltu", R4300i_SPECIAL_SLTU, base_spec, syn_arith},
{"dadd", R4300i_SPECIAL_DADD, base_spec, syn_arith},
{"daddu", R4300i_SPECIAL_DADDU, base_spec, syn_arith},
{"dsub", R4300i_SPECIAL_DSUB, base_spec, syn_arith},
{"dsubu", R4300i_SPECIAL_DSUBU, base_spec, syn_arith},
{"tge", R4300i_SPECIAL_TGE, base_spec, syn_arith2}, // Note: no code field
{"tgeu", R4300i_SPECIAL_TGEU, base_spec, syn_arith2}, //
{"tlt", R4300i_SPECIAL_TLT, base_spec, syn_arith2}, //
{"tltu", R4300i_SPECIAL_TLTU, base_spec, syn_arith2}, //
{"teq", R4300i_SPECIAL_TEQ, base_spec, syn_arith2}, //
{"tne", R4300i_SPECIAL_TNE, base_spec, syn_arith2}, //
{"dsll", R4300i_SPECIAL_DSLL, base_spec, syn_shift},
{"dsrl", R4300i_SPECIAL_DSRL, base_spec, syn_shift},
{"dsra", R4300i_SPECIAL_DSRA, base_spec, syn_shift},
{"dsll32", R4300i_SPECIAL_DSLL32, base_spec, syn_shift},
{"dsrl32", R4300i_SPECIAL_DSRL32, base_spec, syn_shift},
{"dsra32", R4300i_SPECIAL_DSRA32, base_spec, syn_shift},
{"bltz", R4300i_REGIMM_BLTZ, base_regimm, syn_branch_z},
{"bgez", R4300i_REGIMM_BGEZ, base_regimm, syn_branch_z},
{"bltzl", R4300i_REGIMM_BLTZL, base_regimm, syn_branch_z},
{"bgezl", R4300i_REGIMM_BGEZL, base_regimm, syn_branch_z},
{"tgei", R4300i_REGIMM_TGEI, base_regimm, syn_trap_i},
{"tgeiu", R4300i_REGIMM_TGEIU, base_regimm, syn_trap_i},
{"tlti", R4300i_REGIMM_TLTI, base_regimm, syn_trap_i},
{"tltiu", R4300i_REGIMM_TLTIU, base_regimm, syn_trap_i},
{"teqi", R4300i_REGIMM_TEQI, base_regimm, syn_trap_i},
{"tnei", R4300i_REGIMM_TNEI, base_regimm, syn_trap_i},
{"bltzal", R4300i_REGIMM_BLTZAL, base_regimm, syn_branch_z},
{"bgezal", R4300i_REGIMM_BGEZAL, base_regimm, syn_branch_z},
{"bal", R4300i_REGIMM_BGEZAL, base_regimm, syn_branch_unc},
{"bltzall", R4300i_REGIMM_BLTZALL, base_regimm, syn_branch_z},
{"bgezall", R4300i_REGIMM_BGEZALL, base_regimm, syn_branch_z},
{"mfc0", R4300i_COP0_MF, base_cop0_mv, syn_cop_mv},
{"mtc0", R4300i_COP0_MT, base_cop0_mv, syn_cop_mv},
{"tlbr", R4300i_COP0_CO_TLBR, base_cop0_co, nullptr},
{"tlbwi", R4300i_COP0_CO_TLBWI, base_cop0_co, nullptr},
{"tlbwr", R4300i_COP0_CO_TLBWR, base_cop0_co, nullptr},
{"tlbp", R4300i_COP0_CO_TLBP, base_cop0_co, nullptr},
{"eret", R4300i_COP0_CO_ERET, base_cop0_co, nullptr},
{"mfc1", R4300i_COP1_MF, base_cop1_mv, syn_cop_mv},
{"dmfc1", R4300i_COP1_DMF, base_cop1_mv, syn_cop_mv},
{"cfc1", R4300i_COP1_CF, base_cop1_mv, syn_cop_mv},
{"mtc1", R4300i_COP1_MT, base_cop1_mv, syn_cop_mv},
{"dmtc1", R4300i_COP1_DMT, base_cop1_mv, syn_cop_mv},
{"ctc1", R4300i_COP1_CT, base_cop1_mv, syn_cop_mv},
{"bc1f", R4300i_COP1_BC_BCF, base_cop1_bc, syn_branch_unc},
{"bc1t", R4300i_COP1_BC_BCT, base_cop1_bc, syn_branch_unc},
{"bc1fl", R4300i_COP1_BC_BCFL, base_cop1_bc, syn_branch_unc},
{"bc1tl", R4300i_COP1_BC_BCTL, base_cop1_bc, syn_branch_unc},
{"add.s", R4300i_COP1_FUNCT_ADD, base_cop1_s, syn_cop1_arith},
{"sub.s", R4300i_COP1_FUNCT_SUB, base_cop1_s, syn_cop1_arith},
{"mul.s", R4300i_COP1_FUNCT_MUL, base_cop1_s, syn_cop1_arith},
{"div.s", R4300i_COP1_FUNCT_DIV, base_cop1_s, syn_cop1_arith},
{"sqrt.s", R4300i_COP1_FUNCT_SQRT, base_cop1_s, syn_cop1},
{"abs.s", R4300i_COP1_FUNCT_ABS, base_cop1_s, syn_cop1},
{"mov.s", R4300i_COP1_FUNCT_MOV, base_cop1_s, syn_cop1},
{"neg.s", R4300i_COP1_FUNCT_NEG, base_cop1_s, syn_cop1},
{"round.l.s", R4300i_COP1_FUNCT_ROUND_L, base_cop1_s, syn_cop1},
{"trunc.l.s", R4300i_COP1_FUNCT_TRUNC_L, base_cop1_s, syn_cop1},
{"ceil.l.s", R4300i_COP1_FUNCT_CEIL_L, base_cop1_s, syn_cop1},
{"floor.l.s", R4300i_COP1_FUNCT_FLOOR_L, base_cop1_s, syn_cop1},
{"round.w.s", R4300i_COP1_FUNCT_ROUND_W, base_cop1_s, syn_cop1},
{"trunc.w.s", R4300i_COP1_FUNCT_TRUNC_W, base_cop1_s, syn_cop1},
{"ceil.w.s", R4300i_COP1_FUNCT_CEIL_W, base_cop1_s, syn_cop1},
{"floor.w.s", R4300i_COP1_FUNCT_FLOOR_W, base_cop1_s, syn_cop1},
{"cvt.s.s", R4300i_COP1_FUNCT_CVT_S, base_cop1_s, syn_cop1},
{"cvt.d.s", R4300i_COP1_FUNCT_CVT_D, base_cop1_s, syn_cop1},
{"cvt.w.s", R4300i_COP1_FUNCT_CVT_W, base_cop1_s, syn_cop1},
{"cvt.l.s", R4300i_COP1_FUNCT_CVT_L, base_cop1_s, syn_cop1},
{"c.f.s", R4300i_COP1_FUNCT_C_F, base_cop1_s, syn_cop1_cmp},
{"c.un.s", R4300i_COP1_FUNCT_C_UN, base_cop1_s, syn_cop1_cmp},
{"c.eq.s", R4300i_COP1_FUNCT_C_EQ, base_cop1_s, syn_cop1_cmp},
{"c.ueq.s", R4300i_COP1_FUNCT_C_UEQ, base_cop1_s, syn_cop1_cmp},
{"c.olt.s", R4300i_COP1_FUNCT_C_OLT, base_cop1_s, syn_cop1_cmp},
{"c.ult.s", R4300i_COP1_FUNCT_C_ULT, base_cop1_s, syn_cop1_cmp},
{"c.ole.s", R4300i_COP1_FUNCT_C_OLE, base_cop1_s, syn_cop1_cmp},
{"c.ule.s", R4300i_COP1_FUNCT_C_ULE, base_cop1_s, syn_cop1_cmp},
{"c.sf.s", R4300i_COP1_FUNCT_C_SF, base_cop1_s, syn_cop1_cmp},
{"c.ngle.s", R4300i_COP1_FUNCT_C_NGLE, base_cop1_s, syn_cop1_cmp},
{"c.seq.s", R4300i_COP1_FUNCT_C_SEQ, base_cop1_s, syn_cop1_cmp},
{"c.ngl.s", R4300i_COP1_FUNCT_C_NGL, base_cop1_s, syn_cop1_cmp},
{"c.lt.s", R4300i_COP1_FUNCT_C_LT, base_cop1_s, syn_cop1_cmp},
{"c.nge.s", R4300i_COP1_FUNCT_C_NGE, base_cop1_s, syn_cop1_cmp},
{"c.le.s", R4300i_COP1_FUNCT_C_LE, base_cop1_s, syn_cop1_cmp},
{"c.ngt.s", R4300i_COP1_FUNCT_C_NGT, base_cop1_s, syn_cop1_cmp},
{"add.d", R4300i_COP1_FUNCT_ADD, base_cop1_d, syn_cop1_arith},
{"sub.d", R4300i_COP1_FUNCT_SUB, base_cop1_d, syn_cop1_arith},
{"mul.d", R4300i_COP1_FUNCT_MUL, base_cop1_d, syn_cop1_arith},
{"div.d", R4300i_COP1_FUNCT_DIV, base_cop1_d, syn_cop1_arith},
{"sqrt.d", R4300i_COP1_FUNCT_SQRT, base_cop1_d, syn_cop1},
{"abs.d", R4300i_COP1_FUNCT_ABS, base_cop1_d, syn_cop1},
{"mov.d", R4300i_COP1_FUNCT_MOV, base_cop1_d, syn_cop1},
{"neg.d", R4300i_COP1_FUNCT_NEG, base_cop1_d, syn_cop1},
{"round.l.d", R4300i_COP1_FUNCT_ROUND_L, base_cop1_d, syn_cop1},
{"trunc.l.d", R4300i_COP1_FUNCT_TRUNC_L, base_cop1_d, syn_cop1},
{"ceil.l.d", R4300i_COP1_FUNCT_CEIL_L, base_cop1_d, syn_cop1},
{"floor.l.d", R4300i_COP1_FUNCT_FLOOR_L, base_cop1_d, syn_cop1},
{"round.w.d", R4300i_COP1_FUNCT_ROUND_W, base_cop1_d, syn_cop1},
{"trunc.w.d", R4300i_COP1_FUNCT_TRUNC_W, base_cop1_d, syn_cop1},
{"ceil.w.d", R4300i_COP1_FUNCT_CEIL_W, base_cop1_d, syn_cop1},
{"floor.w.d", R4300i_COP1_FUNCT_FLOOR_W, base_cop1_d, syn_cop1},
{"cvt.s.d", R4300i_COP1_FUNCT_CVT_S, base_cop1_d, syn_cop1},
{"cvt.d.d", R4300i_COP1_FUNCT_CVT_D, base_cop1_d, syn_cop1},
{"cvt.w.d", R4300i_COP1_FUNCT_CVT_W, base_cop1_d, syn_cop1},
{"cvt.l.d", R4300i_COP1_FUNCT_CVT_L, base_cop1_d, syn_cop1},
{"c.f.d", R4300i_COP1_FUNCT_C_F, base_cop1_d, syn_cop1_cmp},
{"c.un.d", R4300i_COP1_FUNCT_C_UN, base_cop1_d, syn_cop1_cmp},
{"c.eq.d", R4300i_COP1_FUNCT_C_EQ, base_cop1_d, syn_cop1_cmp},
{"c.ueq.d", R4300i_COP1_FUNCT_C_UEQ, base_cop1_d, syn_cop1_cmp},
{"c.olt.d", R4300i_COP1_FUNCT_C_OLT, base_cop1_d, syn_cop1_cmp},
{"c.ult.d", R4300i_COP1_FUNCT_C_ULT, base_cop1_d, syn_cop1_cmp},
{"c.ole.d", R4300i_COP1_FUNCT_C_OLE, base_cop1_d, syn_cop1_cmp},
{"c.ule.d", R4300i_COP1_FUNCT_C_ULE, base_cop1_d, syn_cop1_cmp},
{"c.sf.d", R4300i_COP1_FUNCT_C_SF, base_cop1_d, syn_cop1_cmp},
{"c.ngle.d", R4300i_COP1_FUNCT_C_NGLE, base_cop1_d, syn_cop1_cmp},
{"c.seq.d", R4300i_COP1_FUNCT_C_SEQ, base_cop1_d, syn_cop1_cmp},
{"c.ngl.d", R4300i_COP1_FUNCT_C_NGL, base_cop1_d, syn_cop1_cmp},
{"c.lt.d", R4300i_COP1_FUNCT_C_LT, base_cop1_d, syn_cop1_cmp},
{"c.nge.d", R4300i_COP1_FUNCT_C_NGE, base_cop1_d, syn_cop1_cmp},
{"c.le.d", R4300i_COP1_FUNCT_C_LE, base_cop1_d, syn_cop1_cmp},
{"c.ngt.d", R4300i_COP1_FUNCT_C_NGT, base_cop1_d, syn_cop1_cmp},
{"cvt.s.w", R4300i_COP1_FUNCT_CVT_S, base_cop1_w, syn_cop1},
{"cvt.d.w", R4300i_COP1_FUNCT_CVT_D, base_cop1_w, syn_cop1},
{"cvt.s.l", R4300i_COP1_FUNCT_CVT_S, base_cop1_l, syn_cop1},
{"cvt.d.l", R4300i_COP1_FUNCT_CVT_D, base_cop1_l, syn_cop1},
{nullptr},
};
const ASM_REGISTER CAssembler::m_Registers[] = {
{"r0", 0},
{"at", 1},
{"v0", 2},
{"v1", 3},
{"a0", 4},
{"a1", 5},
{"a2", 6},
{"a3", 7},
{"t0", 8},
{"t1", 9},
{"t2", 10},
{"t3", 11},
{"t4", 12},
{"t5", 13},
{"t6", 14},
{"t7", 15},
{"s0", 16},
{"s1", 17},
{"s2", 18},
{"s3", 19},
{"s4", 20},
{"s5", 21},
{"s6", 22},
{"s7", 23},
{"t8", 24},
{"t9", 25},
{"k0", 26},
{"k1", 27},
{"gp", 28},
{"sp", 29},
{"s8", 30},
{"ra", 31},
{"fp", 30},
{"r0", 0},
{"r1", 1},
{"r2", 2},
{"r3", 3},
{"r4", 4},
{"r5", 5},
{"r6", 6},
{"r7", 7},
{"r8", 8},
{"r9", 9},
{"r10", 10},
{"r11", 11},
{"r12", 12},
{"r13", 13},
{"r14", 14},
{"r15", 15},
{"r16", 16},
{"r17", 17},
{"r18", 18},
{"r19", 19},
{"r20", 20},
{"r21", 21},
{"r22", 22},
{"r23", 23},
{"r24", 24},
{"r25", 25},
{"r26", 26},
{"r27", 27},
{"r28", 28},
{"r29", 29},
{"r30", 30},
{"r31", 31},
{"f0", 0},
{"f1", 1},
{"f2", 2},
{"f3", 3},
{"f4", 4},
{"f5", 5},
{"f6", 6},
{"f7", 7},
{"f8", 8},
{"f9", 9},
{"f10", 10},
{"f11", 11},
{"f12", 12},
{"f13", 13},
{"f14", 14},
{"f15", 15},
{"f16", 16},
{"f17", 17},
{"f18", 18},
{"f19", 19},
{"f20", 20},
{"f21", 21},
{"f22", 22},
{"f23", 23},
{"f24", 24},
{"f25", 25},
{"f26", 26},
{"f27", 27},
{"f28", 28},
{"f29", 29},
{"f30", 30},
{"f31", 31},
{"revision", 0},
{"fcsr", 31},
{"fcs", 31},
{"index", 0},
{"random", 1},
{"entrylo0", 2},
{"entrylo1", 3},
{"context", 4},
{"pagemask", 5},
{"wired", 6},
{"badvaddr", 8},
{"count", 9},
{"entryhi", 10},
{"compare", 11},
{"status", 12},
{"cause", 13},
{"epc", 14},
{"prid", 15},
{"config", 16},
{"lladdr", 17},
{"watchlo", 18},
{"watchhi", 19},
{"xcontext", 20},
{"ecc", 26},
{"cacheerr", 27},
{"taglo", 28},
{"taghi", 29},
{"errepc", 30},
{nullptr},
};
bool CAssembler::AssembleLine(const char * line, uint32_t * opcode, uint32_t address)
{
m_ParseError = ERR_NONE;
m_Address = address;
char line_c[128];
strncpy(line_c, line, 128);
StrToLower(line_c);
if (line_c[0] == '\0')
{
*opcode = 0;
return true;
}
char * name = strtok_s(line_c, " \t", &m_TokContext);
// Attempt to assemble the line
// If a syntax error occurs, check if the command has alternative syntax forms and retry
for (int nFallback = 0;; nFallback++)
{
const ASM_INSTRUCTION * instruction = LookupInstruction(name, nFallback);
if (instruction == nullptr)
{
m_ParseError = ERR_UNKNOWN_CMD;
return false;
}
m_ParseError = ERR_NONE;
if (nFallback > 0)
{
// Prepare for re-tokenization
strncpy(line_c, line, 128);
StrToLower(line_c);
name = strtok_s(line_c, " \t", &m_TokContext);
}
*opcode = instruction->base(instruction->val);
if (instruction->syntax == nullptr)
{
// No parameters
return true;
}
for (int i = 0; instruction->syntax[i]; i++)
{
instruction->syntax[i](opcode);
if (m_ParseError != ERR_NONE)
{
goto next_fallback;
}
}
// Assembled without errors
return true;
next_fallback:;
}
}
const ASM_INSTRUCTION * CAssembler::LookupInstruction(char * name, int nFallback)
{
for (int i = 0; m_Instructions[i].name != nullptr; i++)
{
if (strcmp(name, m_Instructions[i].name) == 0)
{
if (nFallback != 0)
{
nFallback--;
continue;
}
return &m_Instructions[i];
}
}
return nullptr;
}
const ASM_REGISTER * CAssembler::LookupRegister(char * name)
{
for (int i = 0; m_Registers[i].name != nullptr; i++)
{
if (strcmp(name, m_Registers[i].name) == 0)
{
return &m_Registers[i];
}
}
return nullptr;
}
void CAssembler::StrToLower(char * str)
{
while (*str)
{
if (*str >= 'A' && *str <= 'Z')
{
*str |= 0x20;
}
str++;
}
}
uint32_t CAssembler::pop_reg()
{
char * r = strtok_s(nullptr, " \t,()", &m_TokContext);
if (r == nullptr)
{
m_ParseError = ERR_EXPECTED_REG;
return 0;
}
const ASM_REGISTER * reg = LookupRegister(r);
if (reg == nullptr)
{
m_ParseError = ERR_INVALID_REG;
return 0;
}
return reg->val;
}
uint32_t CAssembler::pop_val()
{
char * v = strtok_s(nullptr, " \t,()", &m_TokContext);
if (v == nullptr)
{
m_ParseError = ERR_EXPECTED_VAL;
return 0;
}
//if (isalpha(*v))
//{
// // TODO: lookup label value
// return 0;
//}
int base = 0; // Hexadecimal or decimal
if (*v == '$')
{
base = 16; // Hexadecimal
v++;
}
char * endptr;
uint32_t val = strtoul(v, &endptr, base);
if (*endptr != '\0')
{
m_ParseError = ERR_EXPECTED_VAL;
return 0;
}
return val;
}
uint32_t CAssembler::base_op(uint32_t val)
{
return val << 26;
}
uint32_t CAssembler::base_spec(uint32_t val)
{
return val;
}
uint32_t CAssembler::base_spec_jalr_ra(uint32_t val)
{
return (31 << 11) | val;
}
uint32_t CAssembler::base_regimm(uint32_t val)
{
return (R4300i_REGIMM << 26) | (val << 16);
}
uint32_t CAssembler::base_cop0_co(uint32_t val)
{
return (R4300i_CP0 << 26) | (1 << 25) | val;
}
uint32_t CAssembler::base_cop0_mv(uint32_t val)
{
return (R4300i_CP0 << 26) | (val << 21);
}
uint32_t CAssembler::base_cop1_mv(uint32_t val)
{
return (R4300i_CP1 << 26) | (val << 21);
}
uint32_t CAssembler::base_cop1_s(uint32_t val)
{
return (R4300i_CP1 << 26) | (R4300i_COP1_S << 21) | val;
}
uint32_t CAssembler::base_cop1_d(uint32_t val)
{
return (R4300i_CP1 << 26) | (R4300i_COP1_D << 21) | val;
}
uint32_t CAssembler::base_cop1_w(uint32_t val)
{
return (R4300i_CP1 << 26) | (R4300i_COP1_W << 21) | val;
}
uint32_t CAssembler::base_cop1_l(uint32_t val)
{
return (R4300i_CP1 << 26) | (R4300i_COP1_L << 21) | val;
}
uint32_t CAssembler::base_cop1_bc(uint32_t val)
{
return (R4300i_CP1 << 26) | (R4300i_COP1_BC << 21) | (val << 16);
}
void CAssembler::arg_reg_t(uint32_t * opcode)
{
*opcode |= pop_reg() << 16;
}
void CAssembler::arg_reg_s(uint32_t * opcode)
{
*opcode |= pop_reg() << 21;
}
void CAssembler::arg_reg_d(uint32_t * opcode)
{
*opcode |= pop_reg() << 11;
}
void CAssembler::arg_reg_ft(uint32_t * opcode)
{
*opcode |= pop_reg() << 16;
}
void CAssembler::arg_reg_fs(uint32_t * opcode)
{
*opcode |= pop_reg() << 11;
}
void CAssembler::arg_reg_fd(uint32_t * opcode)
{
*opcode |= pop_reg() << 6;
}
void CAssembler::arg_jump(uint32_t * opcode)
{
*opcode |= (pop_val() / 4) & 0x3FFFFFF;
}
void CAssembler::arg_imm16(uint32_t * opcode)
{
*opcode |= (pop_val() & 0xFFFF);
}
void CAssembler::arg_bra_target(uint32_t * opcode)
{
uint16_t relTarget = (((pop_val() - m_Address) / 4) & 0xFFFF) - 1;
*opcode |= relTarget;
}
void CAssembler::arg_shamt(uint32_t * opcode)
{
*opcode |= (pop_val() & 0x1F) << 6;
}
void CAssembler::arg_cache_op(uint32_t * opcode)
{
*opcode |= (pop_val() & 0x1F) << 16;
}
void CAssembler::arg_syscall_code(uint32_t * opcode)
{
*opcode |= (pop_val() & 0xFFFFF) << 6;
}