psxsdk/tools/spasm/opcode.c

2215 lines
35 KiB
C

#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 <= 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 <= 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;
}