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