summaryrefslogtreecommitdiff
path: root/tools/spasm/opcode.c
diff options
context:
space:
mode:
authorXavi Del Campo <xavi.dcr@tutanota.com>2020-01-31 10:32:23 +0100
committerXavi Del Campo <xavi.dcr@tutanota.com>2020-01-31 10:32:23 +0100
commit7c24e9a9b02b04dcaf9507acb94091ea70a2c02d (patch)
treec28d0748652ad4b4222309e46e6cfc82c0906220 /tools/spasm/opcode.c
parenta2b7b6bb1cc2f4a3258b7b2dbc92399d151f864d (diff)
downloadpsxsdk-7c24e9a9b02b04dcaf9507acb94091ea70a2c02d.tar.gz
Imported pristine psxsdk-20190410 from official repo
Diffstat (limited to 'tools/spasm/opcode.c')
-rw-r--r--tools/spasm/opcode.c2214
1 files changed, 2214 insertions, 0 deletions
diff --git a/tools/spasm/opcode.c b/tools/spasm/opcode.c
new file mode 100644
index 0000000..a09c119
--- /dev/null
+++ b/tools/spasm/opcode.c
@@ -0,0 +1,2214 @@
+#include "spasm.h"
+
+struct
+{
+ char *name;
+ void (*func)();
+}instruction_table[] =
+{
+ {"add" ,INS_ADD},
+ {"addi" ,INS_ADDI},
+ {"addiu" ,INS_ADDIU},
+ {"addu" ,INS_ADDU},
+ {"and" ,INS_AND},
+ {"andi" ,INS_ANDI},
+ {"beq" ,INS_BEQ},
+ {"bgez" ,INS_BGEZ},
+ {"bgezal" ,INS_BGEZAL},
+ {"bgtz" ,INS_BGTZ},
+ {"blez" ,INS_BLEZ},
+ {"bltz" ,INS_BLTZ},
+ {"bltzal" ,INS_BLTZAL},
+ {"bne" ,INS_BNE},
+ {"break" ,INS_BREAK},
+ {"cfc0" ,INS_CFC },
+ {"cfc1" ,INS_CFC },
+ {"cfc2" ,INS_CFC },
+ {"cfc3" ,INS_CFC },
+ {"cop0" ,INS_COP },
+ {"cop1" ,INS_COP },
+ {"cop2" ,INS_COP },
+ {"cop3" ,INS_COP },
+ {"ctc0" ,INS_CTC },
+ {"ctc1" ,INS_CTC },
+ {"ctc2" ,INS_CTC },
+ {"ctc3" ,INS_CTC },
+ {"div" ,INS_DIV},
+ {"divu" ,INS_DIVU},
+ {"j" ,INS_J},
+ {"jal" ,INS_JAL},
+ {"jalr" ,INS_JALR},
+ {"jr" ,INS_JR},
+ {"lb" ,INS_LB},
+ {"lbu" ,INS_LBU},
+ {"lh" ,INS_LH},
+ {"lhu" ,INS_LHU},
+ {"lui" ,INS_LUI},
+ {"lw" ,INS_LW},
+ {"lwc0" ,INS_LWC },
+ {"lwc1" ,INS_LWC },
+ {"lwc2" ,INS_LWC },
+ {"lwc3" ,INS_LWC },
+ {"lwl" ,INS_LWL},
+ {"lwr" ,INS_LWR},
+ {"mfc0" ,INS_MFC},
+ {"mfc1" ,INS_MFC},
+ {"mfc2" ,INS_MFC},
+ {"mfc3" ,INS_MFC},
+ {"mfhi" ,INS_MFHI},
+ {"mflo" ,INS_MFLO},
+ {"mtc0" ,INS_MTC },
+ {"mtc1" ,INS_MTC },
+ {"mtc2" ,INS_MTC },
+ {"mtc3" ,INS_MTC },
+ {"mthi" ,INS_MTHI},
+ {"mtlo" ,INS_MTLO},
+ {"mult" ,INS_MULT},
+ {"multu" ,INS_MULTU},
+ {"nor" ,INS_NOR},
+ {"or" ,INS_OR},
+ {"ori" ,INS_ORI},
+ {"sb" ,INS_SB},
+ {"sh" ,INS_SH},
+ {"sll" ,INS_SLL},
+ {"sllv" ,INS_SLLV},
+ {"slt" ,INS_SLT},
+ {"slti" ,INS_SLTI},
+ {"sltiu" ,INS_SLTIU},
+ {"sltu" ,INS_SLTU},
+ {"sra" ,INS_SRA},
+ {"srav" ,INS_SRAV},
+ {"srl" ,INS_SRL},
+ {"srlv" ,INS_SRLV},
+ {"sub" ,INS_SUB},
+ {"subu" ,INS_SUBU},
+ {"sw" ,INS_SW},
+ {"swc0" ,INS_SWC},
+ {"swc1" ,INS_SWC},
+ {"swc2" ,INS_SWC},
+ {"swc3" ,INS_SWC},
+ {"swl" ,INS_SWL},
+ {"swr" ,INS_SWR},
+ {"syscall" ,INS_SYSCALL},
+ {"xor" ,INS_XOR},
+ {"xori" ,INS_XORI},
+
+ {"b" ,INS_B},
+ {"la" ,INS_LA},
+ {"li" ,INS_LI},
+ {"nop" ,INS_NOP},
+ {"move" ,INS_MOVE},
+ {"subi" ,INS_SUBI},
+ {"subiu" ,INS_SUBIU},
+ {"beqz" ,INS_BEQZ},
+ {"bnez" ,INS_BNEZ},
+ {"bal" ,INS_BAL},
+ {"org" ,INS_ORG},
+ {"include" ,INS_INCLUDE},
+ {"incbin" ,INS_INCBIN},
+ {"dcb" ,INS_DCB},
+ {"db" ,INS_DB},
+ {"dh" ,INS_DH},
+ {"dw" ,INS_DW},
+ {"align" ,INS_ALIGN},
+
+ {NULL},
+};
+
+#define I_TYPE(op, rs, rt, imm) \
+ ( (((op) & 63) << 26) | (((rs) & 31) << 21) | (((rt) & 31) << 16) | \
+ ((imm) & 0xFFFF) )
+
+#define J_TYPE(op, target) \
+ ( (((op) & 63) << 26) | ((target) & 0x3FFFFFF) )
+
+#define R_TYPE(op, rs, rt, rd, shamt, funct) \
+ ( (((op) & 63) << 26) | (((rs) & 31) << 21) | (((rt) & 31) << 16) | \
+ (((rd) & 31) << 11) | (((shamt) & 31) << 6) | \
+ ((funct) & 63))
+
+// copn = coprocessor number
+// SET_DIS_CHECK()
+
+#define SET_DIS_CHECK() /* Argument type check. Placeholder, contains nothing for now. */
+
+int set_delay_slot = 0;
+
+void OUTSEEK(unsigned int position)
+{
+ fseek(asmOut, position, SEEK_SET);
+}
+
+void OUTBYTE(unsigned char b)
+{
+ if(curPass>0)
+ fputc(b, asmOut);
+
+ curPc++;
+}
+
+void OUTHALF(unsigned short h)
+{
+ if(curPass>0)
+ {
+ fputc(h&0xff, asmOut);
+ fputc(h>>8, asmOut);
+ }
+
+ curPc += 2;
+}
+
+void OUTWORD(unsigned int w)
+{
+ if(curPass>0)
+ {
+ fputc(w&0xff, asmOut);
+ fputc((w>>8)&0xff, asmOut);
+ fputc((w>>16)&0xff, asmOut);
+ fputc(w>>24, asmOut);
+ }
+
+ curPc += 4;
+}
+
+void OUTINS(unsigned int instruction)
+{
+ OUTWORD(instruction);
+
+ if(set_delay_slot)
+ {
+ OUTWORD(0);
+
+ set_delay_slot = 0;
+ }
+}
+
+
+void OUTSTRING(char *string)
+{
+ int stringt;
+ int esc=0;
+
+ if(*string == '"')
+ stringt = 0;
+ else if(*string == '\'')
+ stringt = 1;
+ else
+ instruction_error("OUTSTRING <INTERNAL ERROR>. Not a string!");
+
+ string++;
+
+ while(*string)
+ {
+ if(*string == '"')
+ {
+ if(stringt == 0 && !esc)
+ break;
+
+ OUTBYTE('"');
+ esc = 0;
+ }
+ else if(*string == '\'')
+ {
+ if(stringt == 1 && !esc)
+ break;
+
+ OUTBYTE('\'');
+ esc = 0;
+ }
+ else if(*string == 'n')
+ {
+ if(esc)
+ OUTBYTE('\n');
+ else
+ OUTBYTE('n');
+
+ esc = 0;
+ }
+ else if(*string == 't')
+ {
+ if(esc)
+ OUTBYTE('\t');
+ else
+ OUTBYTE('t');
+
+ esc = 0;
+ }
+ else if(*string == 'r')
+ {
+ if(esc)
+ OUTBYTE('\r');
+ else
+ OUTBYTE('r');
+
+ esc = 0;
+ }
+ else if(*string == '\\')
+ {
+ if(esc)
+ {
+ OUTBYTE('\\');
+ esc = 0;
+ }
+ else
+ esc = 1;
+ }
+ else
+ {
+ if(esc)
+ instruction_error("Invalid escape sequence \\%c in string", *string);
+
+ OUTBYTE(*string);
+ }
+
+ string++;
+ }
+}
+
+unsigned int OUTSIZE(void)
+{
+ int r;
+ int pos = ftell(asmOut);
+ fseek(asmOut, 0, SEEK_END);
+ r = ftell(asmOut);
+ fseek(asmOut, pos, SEEK_SET);
+ return r;
+}
+
+unsigned short compute_branch(unsigned int imm)
+{
+ unsigned int off = imm - (curPc + 4);
+ //off >>= 2;
+
+ if(curPass <= 0)
+ return 0;
+
+ if(off >= 0x20000 && off < -0x20000)
+ instruction_error("Branch out of range. %04x", off);
+
+ return (off>>2) & 0xFFFF;
+}
+
+unsigned int compute_jump(unsigned int imm)
+{
+ if(curPass <= 0)
+ return 0;
+
+ return (imm >> 2);
+}
+
+struct
+{
+ int size;
+ int pos;
+ unsigned int *el;
+}cannotPredict = {0, 0, NULL};
+
+unsigned int compute_real_offset(unsigned int imm, unsigned int base,
+ unsigned int rt)
+{
+ int i, unpredictable=0;
+ unsigned short hipart;
+ unsigned short lopart;
+
+ if(!find_label_ok())
+ {
+ if(cannotPredict.size == cannotPredict.pos)
+ {
+ cannotPredict.size += 128;
+ cannotPredict.el = realloc(cannotPredict.el, cannotPredict.size * sizeof(int));
+ }
+
+ cannotPredict.el[cannotPredict.pos++] = curPc;
+ }
+
+ for(i = 0; i < cannotPredict.pos; i++)
+ {
+ if(curPc == cannotPredict.el[i])
+ {
+ unpredictable = 1;
+ break;
+ }
+ }
+
+ if(!unpredictable && ((imm <= 0xFFFF) || (imm >= 0xFFFF8000 && imm <= 0xFFFFFFFF)))
+ return I_TYPE(0, base, rt, imm);
+
+//compute_real_offset_output_wide:
+ // li at, offset
+ // add at, at, base
+ // lw rt, 0(at)
+ hipart = (imm >> 16);
+ lopart = imm & 0xFFFF;
+ int t=(*curIns == 'l') ? rt : 1;
+
+ // lw at, $CAFEBABE(zero) -> lui at, $CAFE, ori at, at, $BABE, lw at, 0(at)
+ // lw at, $CAFEBABE(v0) -> lui at, $CAFE, ori at, at, $BABE, lw at, 0(v0)
+ // sw at, $CAFEBABE ->
+
+ if(base)
+ {
+ /*OUTINS( I_TYPE(15, 0, t, hipart)); // lui $t, (offset > 16)
+
+ if(lopart || unpredictable)
+ OUTINS( I_TYPE (13, t, t, lopart)); // ori $t, $t, offset & 0xffff
+
+ OUTINS( R_TYPE (0, t, base, t, 0, 33) ); // add $t, $t, base
+ return I_TYPE(0, t, rt, 0);*/
+
+// SPASM is seriously broken regarding this..
+ return I_TYPE(0, base, rt, imm);
+ }
+
+ if(lopart >= 0x8000)
+ hipart++;
+
+ OUTINS( I_TYPE(15, 0, t, hipart)); // lui $t, (offset > 16)
+
+ return I_TYPE(0, t, rt, lopart); // XX rt, lopart(rt)
+}
+
+void INS_ADD(void)
+{
+ unsigned int rd, rs, rt;
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ // ADD rd, rs, rt -> rd = rs + rt
+
+ if(insArgc == 2)
+ {
+ if(atoiT[1] == T_INTEGER)
+ return INS_ADDI();
+
+ rd = insArgv[0];
+ rs = insArgv[0];
+ rt = insArgv[1];
+ }
+ else
+ {
+ if(atoiT[2] == T_INTEGER)
+ return INS_ADDI();
+
+ rd = insArgv[0];
+ rs = insArgv[1];
+ rt = insArgv[2];
+ }
+
+ OUTINS( R_TYPE (0, rs, rt, rd, 0, 32) );
+}
+
+void INS_ADDI(void)
+{
+ unsigned int rt, rs, imm;
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ // ADDI rt, rs, imm -> rt = rs + imm;
+
+ if(insArgc == 2)
+ {
+ rt = insArgv[0];
+ rs = insArgv[0];
+ imm = insArgv[1];
+ }
+ else
+ {
+ rt = insArgv[0];
+ rs = insArgv[1];
+ imm = insArgv[2];
+ }
+
+ if(imm > 0x7FFF && imm < 0xFFFF0000)
+ instruction_warning("Immediate is possibly out of range.");
+
+ OUTINS( I_TYPE (8, rs, rt, imm) );
+}
+
+void INS_ADDIU(void)
+{
+ unsigned int rt, rs, imm;
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ // ADDIU rt, rs, imm -> rt = rs + imm;
+
+ if(insArgc == 2)
+ {
+ rt = insArgv[0];
+ rs = insArgv[0];
+ imm = insArgv[1];
+ }
+ else
+ {
+ rt = insArgv[0];
+ rs = insArgv[1];
+ imm = insArgv[2];
+ }
+
+ if(imm > 0x7FFF && imm < 0xFFFF0000)
+ instruction_warning("Immediate is possibly out of range.");
+
+ OUTINS( I_TYPE (9, rs, rt, imm) );
+}
+
+void INS_ADDU(void)
+{
+ unsigned int rd, rs, rt;
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ // ADDU rd, rs, rt -> rd = rs + rt
+
+ if(insArgc == 2)
+ {
+ if(atoiT[1] == T_INTEGER)
+ return INS_ADDIU();
+
+ rd = insArgv[0];
+ rs = insArgv[0];
+ rt = insArgv[1];
+ }
+ else
+ {
+ if(atoiT[2] == T_INTEGER)
+ return INS_ADDIU();
+
+ rd = insArgv[0];
+ rs = insArgv[1];
+ rt = insArgv[2];
+ }
+
+ OUTINS( R_TYPE (0, rs, rt, rd, 0, 33) );
+}
+
+void INS_AND(void)
+{
+ unsigned int rd, rs, rt;
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ // AND rd, rs, rt -> rd = rs + rt
+
+ if(insArgc == 2)
+ {
+ if(atoiT[1] == T_INTEGER)
+ return INS_ANDI();
+
+ rd = insArgv[0];
+ rs = insArgv[0];
+ rt = insArgv[1];
+ }
+ else
+ {
+ if(atoiT[2] == T_INTEGER)
+ return INS_ANDI();
+
+ rd = insArgv[0];
+ rs = insArgv[1];
+ rt = insArgv[2];
+ }
+
+ OUTINS( R_TYPE (0, rs, rt, rd, 0, 36) );
+}
+
+void INS_ANDI(void)
+{
+ unsigned int rt, rs, imm;
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ // ANDI rt, rs, imm -> rt = rs + imm;
+
+ if(insArgc == 2)
+ {
+ rt = insArgv[0];
+ rs = insArgv[0];
+ imm = insArgv[1];
+ }
+ else
+ {
+ rt = insArgv[0];
+ rs = insArgv[1];
+ imm = insArgv[2];
+ }
+
+ if(imm > 0xFFFF)
+ instruction_warning("Immediate is possibly out of range");
+
+ OUTINS( I_TYPE (12, rs, rt, imm) );
+}
+
+void INS_BEQ(void)
+{
+ unsigned int rt, rs, imm;
+
+ if(insArgc != 3)
+ instruction_error("Wrong number of arguments");
+
+ rs = insArgv[0];
+ rt = insArgv[1];
+ imm = insArgv[2];
+
+ OUTINS( I_TYPE(4, rs, rt, compute_branch(imm)) );
+}
+
+void INS_BGEZ(void)
+{
+ unsigned int rs, imm;
+
+ if(insArgc != 2)
+ instruction_error("Wrong number of arguments");
+
+ rs = insArgv[0];
+ imm = insArgv[1];
+
+ OUTINS( I_TYPE(1, rs, 1, compute_branch(imm)) );
+}
+
+void INS_BGEZAL(void)
+{
+ unsigned int rs, imm;
+
+ if(insArgc != 2)
+ instruction_error("Wrong number of arguments");
+
+ rs = insArgv[0];
+ imm = insArgv[1];
+
+ OUTINS( I_TYPE(1, rs, 17, compute_branch(imm)) );
+}
+
+void INS_BGTZ(void)
+{
+ unsigned int rs, imm;
+
+ if(insArgc != 2)
+ instruction_error("Wrong number of arguments");
+
+ rs = insArgv[0];
+ imm = insArgv[1];
+
+ OUTINS( I_TYPE(7, rs, 0, compute_branch(imm)) );
+}
+
+void INS_BLEZ(void)
+{
+ unsigned int rs, imm;
+
+ if(insArgc != 2)
+ instruction_error("Wrong number of arguments");
+
+ rs = insArgv[0];
+ imm = insArgv[1];
+
+ OUTINS( I_TYPE(6, rs, 0, compute_branch(imm)) );
+}
+
+void INS_BLTZ(void)
+{
+ unsigned int rs, imm;
+
+ if(insArgc != 2)
+ instruction_error("Wrong number of arguments");
+
+ rs = insArgv[0];
+ imm = insArgv[1];
+
+ OUTINS( I_TYPE(1, rs, 0, compute_branch(imm)) );
+}
+
+void INS_BLTZAL(void)
+{
+ unsigned int rs, imm;
+
+ if(insArgc != 2)
+ instruction_error("Wrong number of arguments");
+
+ rs = insArgv[0];
+ imm = insArgv[1];
+
+ OUTINS( I_TYPE(1, rs, 16, compute_branch(imm)) );
+}
+
+void INS_BNE(void)
+{
+ unsigned int rt, rs, imm;
+
+ if(insArgc != 3)
+ instruction_error("Wrong number of arguments");
+
+ rs = insArgv[0];
+ rt = insArgv[1];
+ imm = insArgv[2];
+
+ OUTINS( I_TYPE(5, rs, rt, compute_branch(imm)) );
+}
+
+void INS_BREAK(void)
+{
+ unsigned int imm = 0;
+
+ if(insArgc > 1)
+ instruction_error("Too many arguments");
+
+ if(insArgc == 1)
+ imm = insArgv[0];
+
+ imm &= 0xFFFFF;
+
+ OUTINS( (imm << 6) | 13 );
+}
+
+void INS_CFC(void)
+{
+ unsigned int rt, rd;
+
+ if(insArgc != 2)
+ instruction_error("Wrong number of arguments");
+
+ rt = insArgv[0];
+ rd = insArgv[1];
+
+ OUTINS ( R_TYPE(16 | copn, 2, rt, rd, 0, 0) );
+}
+
+void INS_COP(void)
+{
+ unsigned int cofun;
+
+ if(insArgc != 1)
+ instruction_error("Wrong number of arguments");
+
+ cofun = insArgv[0];
+
+ OUTINS( ( (16 | copn) << 26) | (1<<25) | (cofun & 0x1FFFFFF));
+}
+
+void INS_CTC(void)
+{
+ unsigned int rt, rd;
+
+ if(insArgc != 2)
+ instruction_error("Wrong number of arguments");
+
+ rt = insArgv[0];
+ rd = insArgv[1];
+
+ OUTINS ( R_TYPE(16 | copn, 6, rt, rd, 0, 0) );
+}
+
+void INS_DIV(void)
+{
+ unsigned int rs, rt;
+
+ if(insArgc != 2)
+ instruction_error("Wrong number of arguments");
+
+ rs = insArgv[0];
+ rt = insArgv[1];
+
+ OUTINS ( R_TYPE(0, rs, rt, 0, 0, 26));
+}
+
+void INS_DIVU(void)
+{
+ unsigned int rs, rt;
+
+ if(insArgc != 2)
+ instruction_error("Wrong number of arguments");
+
+ rs = insArgv[0];
+ rt = insArgv[1];
+
+ OUTINS ( R_TYPE(0, rs, rt, 0, 0, 27));
+}
+
+void INS_J(void)
+{
+ if(insArgc != 1)
+ instruction_error("Wrong number of arguments");
+
+ OUTINS ( J_TYPE(2, compute_jump(insArgv[0])));
+}
+
+void INS_JAL(void)
+{
+ if(insArgc != 1)
+ instruction_error("Wrong number of arguments");
+
+ OUTINS ( J_TYPE(3, compute_jump(insArgv[0])));
+}
+
+void INS_JALR(void)
+{
+ unsigned int rd, rs;
+
+ if(insArgc < 1)
+ instruction_error("Not enough arguments");
+ if(insArgc > 2)
+ instruction_error("Too many arguments");
+
+ if(insArgc == 1)
+ {
+ rd = 31; // register ra
+ rs = insArgv[0];
+ }
+ else
+ {
+ rd = insArgv[0];
+ rs = insArgv[1];
+ }
+
+ OUTINS ( R_TYPE(0, rs, 0, rd, 0, 9));
+}
+
+void INS_JR(void)
+{
+ if(insArgc != 1)
+ instruction_error("Wrong number of arguments");
+
+ OUTINS ( R_TYPE(0, insArgv[0], 0, 0, 0, 8));
+}
+
+void INS_LB(void)
+{
+ unsigned int base, rt, offset;
+
+ SET_DIS_CHECK();
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ if(insArgc == 2)
+ {
+ rt = insArgv[0];
+ offset = insArgv[1];
+ base = 0;
+ }
+ else
+ {
+ rt = insArgv[0];
+ offset = insArgv[1];
+ base = insArgv[2];
+ }
+
+ OUTINS(R_TYPE(32, 0, 0, 0, 0, 0) | compute_real_offset(offset, base, rt));
+}
+
+void INS_LBU(void)
+{
+ unsigned int base, rt, offset;
+
+ SET_DIS_CHECK();
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ if(insArgc == 2)
+ {
+ rt = insArgv[0];
+ offset = insArgv[1];
+ base = 0;
+ }
+ else
+ {
+ rt = insArgv[0];
+ offset = insArgv[1];
+ base = insArgv[2];
+ }
+
+ OUTINS(R_TYPE(36, 0, 0, 0, 0, 0) | compute_real_offset(offset, base, rt));
+}
+
+void INS_LH(void)
+{
+ unsigned int base, rt, offset;
+
+ SET_DIS_CHECK();
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ if(insArgc == 2)
+ {
+ rt = insArgv[0];
+ offset = insArgv[1];
+ base = 0;
+ }
+ else
+ {
+ rt = insArgv[0];
+ offset = insArgv[1];
+ base = insArgv[2];
+ }
+
+ OUTINS(R_TYPE(33, 0, 0, 0, 0, 0) | compute_real_offset(offset, base, rt));
+}
+
+void INS_LHU(void)
+{
+ unsigned int base, rt, offset;
+
+ SET_DIS_CHECK();
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ if(insArgc == 2)
+ {
+ rt = insArgv[0];
+ offset = insArgv[1];
+ base = 0;
+ }
+ else
+ {
+ rt = insArgv[0];
+ offset = insArgv[1];
+ base = insArgv[2];
+ }
+
+ OUTINS(R_TYPE(37, 0, 0, 0, 0, 0) | compute_real_offset(offset, base, rt));
+}
+
+void INS_LUI(void)
+{
+ if(insArgc != 2)
+ instruction_error("Wrong number of arguments");
+
+ OUTINS(I_TYPE(15, 0, insArgv[0], insArgv[1]));
+}
+
+void INS_LW(void)
+{
+ unsigned int base, rt, offset;
+
+ SET_DIS_CHECK();
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ if(insArgc == 2)
+ {
+ rt = insArgv[0];
+ offset = insArgv[1];
+ base = 0;
+ }
+ else
+ {
+ rt = insArgv[0];
+ offset = insArgv[1];
+ base = insArgv[2];
+ }
+
+ OUTINS(R_TYPE(35, 0, 0, 0, 0, 0) | compute_real_offset(offset, base, rt));
+}
+
+void INS_LWC(void)
+{
+ unsigned int base, rt, offset;
+
+ SET_DIS_CHECK();
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ if(insArgc == 2)
+ {
+ rt = insArgv[0];
+ offset = insArgv[1];
+ base = 0;
+ }
+ else
+ {
+ rt = insArgv[0];
+ offset = insArgv[1];
+ base = insArgv[2];
+ }
+
+ OUTINS(R_TYPE(48 | copn, 0, 0, 0, 0, 0) | compute_real_offset(offset, base, rt));
+}
+
+void INS_LWL(void)
+{
+ unsigned int base, rt, offset;
+
+ SET_DIS_CHECK();
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ if(insArgc == 2)
+ {
+ rt = insArgv[0];
+ offset = insArgv[1];
+ base = 0;
+ }
+ else
+ {
+ rt = insArgv[0];
+ offset = insArgv[1];
+ base = insArgv[2];
+ }
+
+ OUTINS(R_TYPE(34, 0, 0, 0, 0, 0) | compute_real_offset(offset, base, rt));
+}
+
+void INS_LWR(void)
+{
+ unsigned int base, rt, offset;
+
+ SET_DIS_CHECK();
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ if(insArgc == 2)
+ {
+ rt = insArgv[0];
+ offset = insArgv[1];
+ base = 0;
+ }
+ else
+ {
+ rt = insArgv[0];
+ offset = insArgv[1];
+ base = insArgv[2];
+ }
+
+ OUTINS(R_TYPE(38, 0, 0, 0, 0, 0) | compute_real_offset(offset, base, rt));
+}
+
+void INS_MFC(void)
+{
+ if(insArgc != 2)
+ instruction_error("Wrong number of arguments");
+
+ OUTINS(R_TYPE (16 | copn, 0, insArgv[0], insArgv[1], 0, 0));
+}
+
+void INS_MFHI(void)
+{
+ if(insArgc != 1)
+ instruction_error("Wrong number of arguments");
+
+ OUTINS(R_TYPE(0, 0, 0, insArgv[0], 0, 16));
+}
+
+void INS_MFLO(void)
+{
+ if(insArgc != 1)
+ instruction_error("Wrong number of arguments");
+
+ OUTINS(R_TYPE(0, 0, 0, insArgv[0], 0, 18));
+}
+
+void INS_MTC(void)
+{
+ if(insArgc != 2)
+ instruction_error("Wrong number of arguments");
+
+ OUTINS(R_TYPE (16 | copn, 4, insArgv[0], insArgv[1], 0, 0));
+}
+
+void INS_MTHI(void)
+{
+ if(insArgc != 1)
+ instruction_error("Wrong number of arguments");
+
+ OUTINS(R_TYPE(0, insArgv[0], 0, 0, 0, 17));
+}
+
+void INS_MTLO(void)
+{
+ if(insArgc != 1)
+ instruction_error("Wrong number of arguments");
+
+ OUTINS(R_TYPE(0, insArgv[0], 0, 0, 0, 19));
+}
+
+void INS_MULT(void)
+{
+ unsigned int rs, rt;
+
+ if(insArgc != 2)
+ instruction_error("Wrong number of arguments");
+
+ rs = insArgv[0];
+ rt = insArgv[1];
+
+ OUTINS(R_TYPE(0, rs, rt, 0, 0, 24));
+}
+
+void INS_MULTU(void)
+{
+ unsigned int rs, rt;
+
+ if(insArgc != 2)
+ instruction_error("Wrong number of arguments");
+
+ rs = insArgv[0];
+ rt = insArgv[1];
+
+ OUTINS(R_TYPE(0, rs, rt, 0, 0, 25));
+}
+
+void INS_NOR(void)
+{
+ unsigned int rd, rs, rt;
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ if(insArgc == 2)
+ {
+ rd = insArgv[0];
+ rs = insArgv[0];
+ rt = insArgv[1];
+ }
+ else
+ {
+ rd = insArgv[0];
+ rs = insArgv[1];
+ rt = insArgv[2];
+ }
+
+ OUTINS( R_TYPE (0, rs, rt, rd, 0, 39) );
+}
+
+void INS_OR(void)
+{
+ unsigned int rd, rs, rt;
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ if(insArgc == 2)
+ {
+ if(atoiT[1] == T_INTEGER)
+ return INS_ORI();
+
+ rd = insArgv[0];
+ rs = insArgv[0];
+ rt = insArgv[1];
+ }
+ else
+ {
+ if(atoiT[2] == T_INTEGER)
+ return INS_ORI();
+
+ rd = insArgv[0];
+ rs = insArgv[1];
+ rt = insArgv[2];
+ }
+
+ OUTINS( R_TYPE (0, rs, rt, rd, 0, 37) );
+}
+
+void INS_ORI(void)
+{
+ unsigned int rt, rs, imm;
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ // ANDI rt, rs, imm -> rt = rs + imm;
+
+ if(insArgc == 2)
+ {
+ rt = insArgv[0];
+ rs = insArgv[0];
+ imm = insArgv[1];
+ }
+ else
+ {
+ rt = insArgv[0];
+ rs = insArgv[1];
+ imm = insArgv[2];
+ }
+
+ if(imm > 0xFFFF)
+ instruction_warning("Immediate is possibly out of range");
+
+ OUTINS( I_TYPE (13, rs, rt, imm) );
+}
+
+void INS_SB(void)
+{
+ unsigned int base, rt, offset;
+
+ SET_DIS_CHECK();
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ if(insArgc == 2)
+ {
+ rt = insArgv[0];
+ offset = insArgv[1];
+ base = 0;
+ }
+ else
+ {
+ rt = insArgv[0];
+ offset = insArgv[1];
+ base = insArgv[2];
+ }
+
+ OUTINS(R_TYPE(40, 0, 0, 0, 0, 0) | compute_real_offset(offset, base, rt));
+}
+
+void INS_SH(void)
+{
+ unsigned int base, rt, offset;
+
+ SET_DIS_CHECK();
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ if(insArgc == 2)
+ {
+ rt = insArgv[0];
+ offset = insArgv[1];
+ base = 0;
+ }
+ else
+ {
+ rt = insArgv[0];
+ offset = insArgv[1];
+ base = insArgv[2];
+ }
+
+ OUTINS(R_TYPE(41, 0, 0, 0, 0, 0) | compute_real_offset(offset, base, rt));
+}
+
+void INS_SLL(void)
+{
+ unsigned int rd, rt, sa;
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ if(insArgc == 2)
+ {
+ rd = insArgv[0];
+ rt = insArgv[0];
+ sa = insArgv[1];
+ }
+ else
+ {
+ rd = insArgv[0];
+ rt = insArgv[1];
+ sa = insArgv[2];
+ }
+
+ OUTINS(R_TYPE(0, 0, rt, rd, sa, 0));
+}
+
+void INS_SLLV(void)
+{
+ unsigned int rd, rs, rt;
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ if(insArgc == 2)
+ {
+ rd = insArgv[0];
+ rt = insArgv[0];
+ rs = insArgv[1];
+ }
+ else
+ {
+ rd = insArgv[0];
+ rt = insArgv[1];
+ rs = insArgv[2];
+ }
+
+ OUTINS( R_TYPE (0, rs, rt, rd, 0, 4) );
+}
+
+void INS_SLT(void)
+{
+ unsigned int rd, rs, rt;
+
+ if(insArgc != 3)
+ instruction_error("Wrong number of arguments");
+
+ if(atoiT[2] == T_INTEGER)
+ return INS_SLTI();
+
+ rd = insArgv[0];
+ rs = insArgv[1];
+ rt = insArgv[2];
+
+ OUTINS( R_TYPE (0, rs, rt, rd, 0, 42) );
+}
+
+void INS_SLTI(void)
+{
+ unsigned int imm, rs, rt;
+
+ if(insArgc != 3)
+ instruction_error("Wrong number of arguments");
+
+ rt = insArgv[0];
+ rs = insArgv[1];
+ imm = insArgv[2];
+
+ if(imm > 0x7FFF && imm < 0xFFFF8000)
+ instruction_error("Immediate out of range.");
+
+ OUTINS( I_TYPE (10, rs, rt, imm) );
+}
+
+void INS_SLTIU(void)
+{
+ unsigned int imm, rs, rt;
+
+ if(insArgc != 3)
+ instruction_error("Wrong number of arguments");
+
+ rt = insArgv[0];
+ rs = insArgv[1];
+ imm = insArgv[2];
+
+ if(imm > 0x7FFF && imm < 0xFFFF8000)
+ instruction_error("Immediate out of range.");
+
+ OUTINS( I_TYPE (11, rs, rt, imm) );
+}
+
+void INS_SLTU(void)
+{
+ unsigned int rd, rs, rt;
+
+ if(insArgc != 3)
+ instruction_error("Wrong number of arguments");
+
+ if(atoiT[2] == T_INTEGER)
+ return INS_SLTIU();
+
+ rd = insArgv[0];
+ rs = insArgv[1];
+ rt = insArgv[2];
+
+ OUTINS( R_TYPE (0, rs, rt, rd, 0, 43) );
+}
+
+void INS_SRA(void)
+{
+ unsigned int rd, rt, sa;
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ if(insArgc == 2)
+ {
+ rd = insArgv[0];
+ rt = insArgv[0];
+ sa = insArgv[1];
+ }
+ else
+ {
+ rd = insArgv[0];
+ rt = insArgv[1];
+ sa = insArgv[2];
+ }
+
+ OUTINS(R_TYPE(0, 0, rt, rd, sa, 3));
+}
+
+void INS_SRAV(void)
+{
+ unsigned int rd, rs, rt;
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ if(insArgc == 2)
+ {
+ rd = insArgv[0];
+ rt = insArgv[0];
+ rs = insArgv[1];
+ }
+ else
+ {
+ rd = insArgv[0];
+ rt = insArgv[1];
+ rs = insArgv[2];
+ }
+
+ OUTINS( R_TYPE (0, rs, rt, rd, 0, 7) );
+}
+
+void INS_SRL(void)
+{
+ unsigned int rd, rt, sa;
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ if(insArgc == 2)
+ {
+ rd = insArgv[0];
+ rt = insArgv[0];
+ sa = insArgv[1];
+ }
+ else
+ {
+ rd = insArgv[0];
+ rt = insArgv[1];
+ sa = insArgv[2];
+ }
+
+ OUTINS(R_TYPE(0, 0, rt, rd, sa, 2));
+}
+
+void INS_SRLV(void)
+{
+ unsigned int rd, rs, rt;
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ if(insArgc == 2)
+ {
+ rd = insArgv[0];
+ rt = insArgv[0];
+ rs = insArgv[1];
+ }
+ else
+ {
+ rd = insArgv[0];
+ rt = insArgv[1];
+ rs = insArgv[2];
+ }
+
+ OUTINS( R_TYPE (0, rs, rt, rd, 0, 6) );
+}
+
+void INS_SUB(void)
+{
+ unsigned int rd, rs, rt;
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+
+ if(insArgc == 2)
+ {
+ if(atoiT[1] == T_INTEGER)
+ return INS_SUBI();
+
+ rd = insArgv[0];
+ rs = insArgv[0];
+ rt = insArgv[1];
+ }
+ else
+ {
+ if(atoiT[2] == T_INTEGER)
+ return INS_SUBI();
+
+ rd = insArgv[0];
+ rs = insArgv[1];
+ rt = insArgv[2];
+ }
+
+ OUTINS( R_TYPE (0, rs, rt, rd, 0, 34) );
+}
+
+void INS_SUBU(void)
+{
+ unsigned int rd, rs, rt;
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ // ADD rd, rs, rt -> rd = rs + rt
+
+ if(insArgc == 2)
+ {
+ if(atoiT[1] == T_INTEGER)
+ return INS_SUBIU();
+
+ rd = insArgv[0];
+ rs = insArgv[0];
+ rt = insArgv[1];
+ }
+ else
+ {
+ if(atoiT[2] == T_INTEGER)
+ return INS_SUBIU();
+
+ rd = insArgv[0];
+ rs = insArgv[1];
+ rt = insArgv[2];
+ }
+
+ OUTINS( R_TYPE (0, rs, rt, rd, 0, 35) );
+}
+
+void INS_SW(void)
+{
+ unsigned int base, rt, offset;
+
+ SET_DIS_CHECK();
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ if(insArgc == 2)
+ {
+ rt = insArgv[0];
+ offset = insArgv[1];
+ base = 0;
+ }
+ else
+ {
+ rt = insArgv[0];
+ offset = insArgv[1];
+ base = insArgv[2];
+ }
+
+ OUTINS(R_TYPE(43, 0, 0, 0, 0, 0) | compute_real_offset(offset, base, rt));
+}
+
+void INS_SWC(void)
+{
+ unsigned int base, rt, offset;
+
+ SET_DIS_CHECK();
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ if(insArgc == 2)
+ {
+ rt = insArgv[0];
+ offset = insArgv[1];
+ base = 0;
+ }
+ else
+ {
+ rt = insArgv[0];
+ offset = insArgv[1];
+ base = insArgv[2];
+ }
+
+ OUTINS(R_TYPE(56 | copn, 0, 0, 0, 0, 0) | compute_real_offset(offset, base, rt));
+}
+
+void INS_SWL(void)
+{
+ unsigned int base, rt, offset;
+
+ SET_DIS_CHECK();
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ if(insArgc == 2)
+ {
+ rt = insArgv[0];
+ offset = insArgv[1];
+ base = 0;
+ }
+ else
+ {
+ rt = insArgv[0];
+ offset = insArgv[1];
+ base = insArgv[2];
+ }
+
+ OUTINS(R_TYPE(42, 0, 0, 0, 0, 0) | compute_real_offset(offset, base, rt));
+}
+
+void INS_SWR(void)
+{
+ unsigned int base, rt, offset;
+
+ SET_DIS_CHECK();
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ if(insArgc == 2)
+ {
+ rt = insArgv[0];
+ offset = insArgv[1];
+ base = 0;
+ }
+ else
+ {
+ rt = insArgv[0];
+ offset = insArgv[1];
+ base = insArgv[2];
+ }
+
+ OUTINS(R_TYPE(46, 0, 0, 0, 0, 0) | compute_real_offset(offset, base, rt));
+}
+
+void INS_SYSCALL(void)
+{
+ unsigned int imm = 0;
+
+ if(insArgc > 1)
+ instruction_error("Too many arguments");
+
+ if(insArgc == 1)
+ imm = insArgv[0];
+
+ imm &= 0xFFFFF;
+
+ OUTINS( (imm << 6) | 12 );
+}
+
+void INS_XOR(void)
+{
+ unsigned int rd, rs, rt;
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ if(insArgc == 2)
+ {
+ if(atoiT[1] == T_INTEGER)
+ return INS_XORI();
+
+ rd = insArgv[0];
+ rs = insArgv[0];
+ rt = insArgv[1];
+ }
+ else
+ {
+ if(atoiT[2] == T_INTEGER)
+ return INS_XORI();
+
+ rd = insArgv[0];
+ rs = insArgv[1];
+ rt = insArgv[2];
+ }
+
+ OUTINS( R_TYPE (0, rs, rt, rd, 0, 38) );
+}
+
+void INS_XORI(void)
+{
+ unsigned int rt, rs, imm;
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ if(insArgc == 2)
+ {
+ rt = insArgv[0];
+ rs = insArgv[0];
+ imm = insArgv[1];
+ }
+ else
+ {
+ rt = insArgv[0];
+ rs = insArgv[1];
+ imm = insArgv[2];
+ }
+
+ if(imm > 0xFFFF)
+ instruction_warning("Immediate is possibly out of range");
+
+ OUTINS( I_TYPE (14, rs, rt, imm) );
+}
+
+// ***** PSEUDO INSTRUCTIONS *****
+
+void INS_B(void)
+{
+ unsigned int imm;
+
+ if(insArgc != 1)
+ instruction_error("Wrong number of arguments");
+
+ imm = insArgv[0];
+
+ OUTINS( I_TYPE(4, 0, 0, compute_branch(imm)) ); // <- beq zero, zero, imm
+}
+
+/*void INS_LI(void)
+{
+ unsigned int rd, imm;
+ unsigned short lopart, hipart;
+
+ if(insArgc != 2)
+ instruction_error("Wrong number of arguments");
+
+ rd = insArgv[0];
+ imm = insArgv[1];
+
+ hipart = imm >> 16;
+ lopart = imm & 0xFFFF;
+
+ if(atoiT[1] == T_INTEGER && imm >= 0 && imm <= 0xFFFF)
+ OUTINS(I_TYPE(13, 0, rd, lopart)); // ori $rd, $zero, imm
+ else
+ {
+ if(lopart >= 0x8000)
+ hipart++;
+
+ OUTINS( I_TYPE(15, 0, rd, hipart)); // lui $rd, (imm > 16)
+ OUTINS( I_TYPE (9, rd, rd, lopart)); // addiu $rd, $rd, imm & 0xffff
+ }
+}*/
+
+void INS_LI(void)
+{
+ int i;
+ unsigned int rd, imm;
+ unsigned short lopart, hipart;
+ int unpredictable=0;
+
+ if(insArgc != 2)
+ instruction_error("Wrong number of arguments");
+
+ rd = insArgv[0];
+ imm = insArgv[1];
+
+ hipart = imm >> 16;
+ lopart = imm & 0xFFFF;
+
+ if(!find_label_ok())
+ {
+ if(cannotPredict.size == cannotPredict.pos)
+ {
+ cannotPredict.size += 128;
+ cannotPredict.el = realloc(cannotPredict.el, cannotPredict.size * sizeof(int));
+ }
+
+ cannotPredict.el[cannotPredict.pos++] = curPc;
+ }
+
+ for(i = 0; i < cannotPredict.pos; i++)
+ {
+ if(curPc == cannotPredict.el[i])
+ {
+ unpredictable = 1;
+ break;
+ }
+ }
+
+ if(/*atoiT[1] == T_INTEGER &&*/ !unpredictable && imm >= 0 && imm <= 0xFFFF)
+ OUTINS(I_TYPE(13, 0, rd, lopart)); // ori $rd, $zero, imm
+ else if(!unpredictable && !lopart)
+ OUTINS(I_TYPE(15, 0, rd, hipart));
+ else
+ {
+ // if(lopart >= 0x8000)
+ // hipart++;
+
+ OUTINS( I_TYPE(15, 0, rd, hipart)); // lui $rd, (imm > 16)
+
+ // OUTINS( I_TYPE(9, rd, rd, lopart)); // addiu $rd, $rd, imm & 0xffff
+ OUTINS( I_TYPE (13, rd, rd, lopart)); // ori $rd, $rd, imm & 0xffff
+ }
+
+}
+
+void INS_LA(void)
+{
+ int i;
+ unsigned int rd, imm;
+ unsigned short lopart, hipart;
+ int unpredictable=0;
+
+ if(insArgc != 2)
+ instruction_error("Wrong number of arguments");
+
+ rd = insArgv[0];
+ imm = insArgv[1];
+
+ hipart = imm >> 16;
+ lopart = imm & 0xFFFF;
+
+ if(!find_label_ok())
+ {
+ if(cannotPredict.size == cannotPredict.pos)
+ {
+ cannotPredict.size += 128;
+ cannotPredict.el = realloc(cannotPredict.el, cannotPredict.size * sizeof(int));
+ }
+
+ cannotPredict.el[cannotPredict.pos++] = curPc;
+ }
+
+ for(i = 0; i < cannotPredict.pos; i++)
+ {
+ if(curPc == cannotPredict.el[i])
+ {
+ unpredictable = 1;
+ break;
+ }
+ }
+
+ if(/*atoiT[1] == T_INTEGER &&*/ !unpredictable && imm >= 0 && imm <= 0xFFFF)
+ OUTINS(I_TYPE(13, 0, rd, lopart)); // ori $rd, $zero, imm
+ //else if(!unpredictable && !lopart)
+ // OUTINS(I_TYPE(15, 0, rd, hipart));
+ else
+ {
+ if(lopart >= 0x8000)
+ hipart++;
+
+ OUTINS( I_TYPE(15, 0, rd, hipart)); // lui $rd, (imm > 16)
+
+ OUTINS( I_TYPE(9, rd, rd, lopart)); // addiu $rd, $rd, imm & 0xffff
+// OUTINS( I_TYPE (13, rd, rd, lopart)); // ori $rd, $rd, imm & 0xffff
+ }
+
+}
+
+/*void INS_LA(void)
+{
+ INS_LI(); // The LI and LA pseudo-instructions are the same thing in SPASM
+}*/
+
+void INS_NOP(void)
+{
+ OUTINS(0);
+}
+
+void INS_MOVE(void)
+{
+ unsigned int rd, rs;
+
+ if(insArgc != 2)
+ instruction_error("Wrong number of arguments");
+
+ rd = insArgv[0];
+ rs = insArgv[1];
+
+ OUTINS( R_TYPE (0, rs, 0, rd, 0, 33) ); // addu $rd, $rs, $zero
+}
+
+void INS_SUBI(void)
+{
+// just like ADDI, but switches the sign of the immediate
+
+ unsigned int rt, rs, imm;
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+
+ if(insArgc == 2)
+ {
+ rt = insArgv[0];
+ rs = insArgv[0];
+ imm = -insArgv[1];
+ }
+ else
+ {
+ rt = insArgv[0];
+ rs = insArgv[1];
+ imm = -insArgv[2];
+ }
+
+ if(imm > 0x7FFF && imm < 0xFFFF0000)
+ instruction_warning("Immediate is possibly out of range");
+
+ OUTINS( I_TYPE (8, rs, rt, imm) );
+}
+
+void INS_SUBIU(void)
+{
+ unsigned int rt, rs, imm;
+
+ if(insArgc < 2)
+ instruction_error("Not enough arguments");
+ if(insArgc > 3)
+ instruction_error("Too many arguments");
+
+ if(insArgc == 2)
+ {
+ rt = insArgv[0];
+ rs = insArgv[0];
+ imm = -insArgv[1];
+ }
+ else
+ {
+ rt = insArgv[0];
+ rs = insArgv[1];
+ imm = -insArgv[2];
+ }
+
+ if(imm > 0x7FFF && imm < 0xFFFF0000)
+ instruction_warning("Immediate is possibly out of range");
+
+ OUTINS( I_TYPE (9, rs, rt, imm) );
+}
+
+void INS_BEQZ(void)
+{
+ unsigned int rt, imm;
+
+ if(insArgc != 2)
+ instruction_error("Wrong number of arguments");
+
+ rt = insArgv[0];
+ imm = insArgv[1];
+
+ OUTINS( I_TYPE(4, rt, 0, compute_branch(imm)) ); // <- beq zero, rt, imm
+// OUTINS( I_TYPE(4, rs, rt, compute_branch(imm)) );
+
+}
+
+void INS_BNEZ(void)
+{
+ unsigned int rt, imm;
+
+ if(insArgc != 2)
+ instruction_error("Wrong number of arguments");
+
+ rt = insArgv[0];
+ imm = insArgv[1];
+
+ OUTINS( I_TYPE(5,rt, 0, compute_branch(imm)) ); // <- bne zero, rt, imm
+}
+
+void INS_BAL(void)
+{
+ unsigned int imm;
+
+ if(insArgc != 1)
+ instruction_error("Wrong number of arguments");
+
+ imm = insArgv[0];
+
+ OUTINS( I_TYPE(1, 0, 17, compute_branch(imm)) ); //bgezal $zero, imm
+}
+
+void INS_ORG(void)
+{
+ if(insArgc != 1)
+ instruction_error("Wrong number of arguments");
+
+ //if(!first_instruction)
+ // instruction_error("ORG is not the first instruction");
+
+ curPc = insArgv[0];
+ startAddress = insArgv[0];
+ org_found = 1;
+}
+
+void INS_INCBIN(void)
+{
+ FILE *f;
+ char *path, *cp;
+ int sz;
+
+
+ if(insArgc != 1)
+ instruction_error("Wrong number of arguments");
+
+ path = rawArgv[0];
+
+ if(*path == '"')
+ {
+ path++;
+ if((cp = strrchr(path, '"')))
+ *cp = '\0';
+ }
+ else if(*path == '\'')
+ {
+ path++;
+ if((cp = strrchr(path, '\'')))
+ *cp = '\0';
+ }
+
+ //printf("DEBUG(INCBIN): including %s\n", path);
+
+ f = spasm_fopen(path, "rb");
+
+ if(!f)
+ instruction_error("Could not open \"%s\"", path);
+
+ fseek(f, 0, SEEK_END);
+ sz = ftell(f);
+ fseek(f, 0, SEEK_SET);
+
+ if(curPass <= 0)
+ curPc += sz;
+ else
+ {
+ for(;sz;sz--)
+ OUTBYTE(fgetc(f));
+ }
+
+ fclose(f);
+}
+
+void INS_DCB(void)
+{
+ unsigned int num, value;
+
+ if(insArgc != 2)
+ instruction_error("Wrong number of arguments");
+
+ num = insArgv[0];
+ value = insArgv[1];
+
+ if(num & (1<<31))
+ {
+ instruction_warning("Negative number of values, ignoring instruction");
+
+ return;
+ }
+
+ if(curPass <= 0)
+ curPc += num;
+ else
+ {
+ for(;num;num--)
+ OUTBYTE(value);
+ }
+}
+
+void INS_DB(void)
+{
+ int i;
+
+ for(i = 0; i < insArgc; i++)
+ {
+ if(rawArgv[i][0] == '"' || rawArgv[i][0] == '\'')
+ OUTSTRING(rawArgv[i]);
+ else
+ OUTBYTE(insArgv[i] & 0xFF);
+ }
+}
+
+void INS_DH(void)
+{
+ int i;
+
+ for(i = 0; i < insArgc; i++)
+ {
+ if(rawArgv[i][0] == '"' || rawArgv[i][0] == '\'')
+ OUTSTRING(rawArgv[i]);
+ else
+ OUTHALF(insArgv[i] & 0xFFFF);
+ }
+}
+
+void INS_DW(void)
+{
+ int i;
+
+ for(i = 0; i < insArgc; i++)
+ {
+ if(rawArgv[i][0] == '"' || rawArgv[i][0] == '\'')
+ OUTSTRING(rawArgv[i]);
+ else
+ OUTWORD(insArgv[i]);
+ }
+}
+
+void INS_ALIGN(void)
+{
+ unsigned int unit;
+ unsigned int delta;
+
+ if(insArgc != 1)
+ instruction_error("Wrong number of arguments");
+
+ unit = insArgv[0];
+
+ if(unit <= 0)
+ instruction_error("Alignment unit cannot be equal to zero or negative");
+
+ if((curPc % unit))
+ {
+ delta = (unit - (curPc % unit)) % unit;
+
+ if(curPass <= 0)
+ curPc += delta;
+ else
+ {
+ for(;delta;delta--)
+ OUTBYTE(0);
+ }
+ }
+}
+
+void INS_INCLUDE(void)
+{
+ int i, l, o;
+ int sz;
+ int tsz;
+ FILE *f;
+ char *path;
+ char *cp;
+ char *newtext;
+
+ if(insArgc != 1)
+ instruction_error("Wrong number of arguments");
+
+ if(curPass <= 0)
+ {
+
+ path = rawArgv[0];
+
+ if(*path == '"')
+ {
+ path++;
+ if((cp = strrchr(path, '"')))
+ *cp = '\0';
+ }
+ else if(*path == '\'')
+ {
+ path++;
+ if((cp = strrchr(path, '\'')))
+ *cp = '\0';
+ }
+
+ f = spasm_fopen(path, "rb");
+
+ if(!f)
+ instruction_error("Could not open %s", path);
+
+ //printf("DEBUG(INCLUDE): Including %s, line %d\n", path, line_number);
+
+ fseek(f, 0, SEEK_END);
+ sz = ftell(f);
+ fseek(f, 0, SEEK_SET);
+
+ tsz = strlen(curText);
+
+ newtext = malloc(sz + tsz + 1);
+
+ for(i = 0, l = 1; l < line_number; i++)
+ {
+ if(curText[i] == '\n')
+ l++;
+
+ newtext[i] = curText[i];
+ }
+
+ fread(&newtext[i], sizeof(char), sz, f);
+
+ o = i+sz;
+
+ if(newtext[i+sz-1] != '\n')
+ {
+ instruction_warning("No newline found at end of file %s", path);
+ newtext[o++] = '\n';
+ }
+
+
+ for(; curText[i] != '\n'; i++);
+
+ i++;
+ newtext[o] = '\0';
+
+ strcat(newtext, &curText[i]);
+
+ free(curText);
+ curText = newtext;
+ }
+}
+
+void INS_BLANK(void)
+{
+
+}
+
+void *get_instruction(char *name)
+{
+ int i;
+
+
+ for(i = 0; instruction_table[i].name; i++)
+ {
+ //printf("name = ^%s$, iname = ^%s$\n", name, instruction_table[i].name);
+
+ if(strcasecmp(name, instruction_table[i].name) == 0)
+ {
+ // printf("di sranron\n");
+ return instruction_table[i].func;
+ }
+ }
+
+ return NULL;
+}