684 lines
22 KiB
C++
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;
|
|
}
|