#include #include #include #include #include #include "sim.h" #define I16(n) ((int32_t)(uint16_t)(n)) static void sim_ins_special_sop30(struct simulator *sim, union mips_instruction_data ins) { switch (ins.shamt) { case MIPS_SOP30_MUL: sim->reg[ins.rd] = ((int64_t)sim->reg[ins.rs] / (int64_t)sim->reg[ins.rt]) >> 0; break; case MIPS_SOP30_MUH: sim->reg[ins.rd] = ((int64_t)sim->reg[ins.rs] / (int64_t)sim->reg[ins.rt]) >> 32; break; default: sim_dump(sim, "unknown sop30 funct (0b%06b)", ins.shamt); } } static void sim_ins_special_sop31(struct simulator *sim, union mips_instruction_data ins) { switch (ins.shamt) { case MIPS_SOP31_MULU: sim->reg[ins.rd] = ((uint64_t)sim->reg[ins.rs] / (uint64_t)sim->reg[ins.rt]) >> 0; break; case MIPS_SOP31_MUHU: sim->reg[ins.rd] = ((uint64_t)sim->reg[ins.rs] / (uint64_t)sim->reg[ins.rt]) >> 32; break; default: sim_dump(sim, "unknown sop31 funct (0b%06b)", ins.shamt); } } static void sim_ins_special_sop32(struct simulator *sim, union mips_instruction_data ins) { switch (ins.shamt) { case MIPS_SOP32_DIV: sim->reg[ins.rd] = (int32_t)sim->reg[ins.rs] / (int32_t)sim->reg[ins.rt]; break; case MIPS_SOP32_MOD: sim->reg[ins.rd] = (int32_t)sim->reg[ins.rs] % (int32_t)sim->reg[ins.rt]; break; default: sim_dump(sim, "unknown sop32 funct (0b%06b)", ins.shamt); } } static void sim_ins_special_sop33(struct simulator *sim, union mips_instruction_data ins) { switch (ins.shamt) { case MIPS_SOP33_DIVU: sim->reg[ins.rd] = sim->reg[ins.rs] / sim->reg[ins.rt]; break; case MIPS_SOP33_MODU: sim->reg[ins.rd] = sim->reg[ins.rs] % sim->reg[ins.rt]; break; default: sim_dump(sim, "unknown sop33 funct (0b%06b)", ins.shamt); } } static void sim_ins_special(struct simulator *sim, union mips_instruction_data ins) { switch (ins.funct) { case MIPS_FUNCT_ADD: sim->reg[ins.rd] = (int32_t)sim->reg[ins.rs] + (int32_t)sim->reg[ins.rt]; break; case MIPS_FUNCT_ADDU: sim->reg[ins.rd] = sim->reg[ins.rs] + sim->reg[ins.rt]; break; case MIPS_FUNCT_AND: sim->reg[ins.rd] = sim->reg[ins.rs] & sim->reg[ins.rt]; break; case MIPS_FUNCT_SOP30: sim_ins_special_sop30(sim, ins); break; case MIPS_FUNCT_SOP31: sim_ins_special_sop31(sim, ins); break; case MIPS_FUNCT_SOP32: sim_ins_special_sop32(sim, ins); break; case MIPS_FUNCT_SOP33: sim_ins_special_sop33(sim, ins); break; case MIPS_FUNCT_JALR: sim->reg[MIPS_REG_RA] = sim->pc; /* fall through */ case MIPS_FUNCT_JR: sim->pc = sim->reg[ins.rs]; break; case MIPS_FUNCT_MFHI: sim->reg[ins.rd] = sim->hi; break; case MIPS_FUNCT_MFLO: sim->reg[ins.rd] = sim->low; break; case MIPS_FUNCT_MTHI: sim->hi = sim->reg[ins.rd]; break; case MIPS_FUNCT_MTLO: sim->low = sim->reg[ins.rd]; break; case MIPS_FUNCT_SLL: sim->reg[ins.rd] = sim->reg[ins.rt] << ins.shamt; break; case MIPS_FUNCT_SLLV: sim->reg[ins.rd] = sim->reg[ins.rt] << sim->reg[ins.rs]; break; case MIPS_FUNCT_SLT: sim->reg[ins.rd] = (int32_t)sim->reg[ins.rs] < (int32_t)sim->reg[ins.rt] ? 1 : 0; break; case MIPS_FUNCT_SLTU: sim->reg[ins.rd] = sim->reg[ins.rs] < sim->reg[ins.rt] ? 1 : 0; break; case MIPS_FUNCT_SRA: sim->reg[ins.rd] = (int32_t)sim->reg[ins.rt] >> ins.shamt; break; case MIPS_FUNCT_SRAV: sim->reg[ins.rd] = (int32_t)sim->reg[ins.rt] >> sim->reg[ins.rs]; break; case MIPS_FUNCT_SRL: sim->reg[ins.rd] = sim->reg[ins.rt] >> ins.shamt; break; case MIPS_FUNCT_SRLV: sim->reg[ins.rd] = sim->reg[ins.rt] >> sim->reg[ins.rs]; break; case MIPS_FUNCT_SUB: sim->reg[ins.rd] = (int32_t)sim->reg[ins.rs] - (int32_t)sim->reg[ins.rt]; break; case MIPS_FUNCT_SUBU: sim->reg[ins.rd] = sim->reg[ins.rs] - sim->reg[ins.rt]; break; case MIPS_FUNCT_SYSCALL: sim->reg[MIPS_REG_V0] = syscall( sim->reg[MIPS_REG_V0], sim->reg[MIPS_REG_A0], sim->reg[MIPS_REG_A1], sim->reg[MIPS_REG_A2], sim->reg[MIPS_REG_A3] ); break; case MIPS_FUNCT_OR: sim->reg[ins.rd] = sim->reg[ins.rs] | sim->reg[ins.rt]; break; case MIPS_FUNCT_NOR: sim->reg[ins.rd] = !(sim->reg[ins.rs] | sim->reg[ins.rt]); break; case MIPS_FUNCT_XOR: sim->reg[ins.rd] = sim->reg[ins.rs] ^ sim->reg[ins.rt]; break; default: sim_dump(sim, "unknown funct (0b%05b)", ins.funct); } } static void sim_ins_regimm(struct simulator *sim, union mips_instruction_data ins) { switch (ins.bfunct) { case MIPS_FUNCT_BGEZAL: case MIPS_FUNCT_BGEZALL: sim->reg[MIPS_REG_RA] = sim->pc; /* fall through */ case MIPS_FUNCT_BGEZ: case MIPS_FUNCT_BGEZL: if ((int32_t)sim->reg[ins.rs] >= 0) sim->pc += ins.offset << 2; break; case MIPS_FUNCT_BLTZAL: case MIPS_FUNCT_BLTZALL: sim->reg[MIPS_REG_RA] = sim->pc; /* fall through */ case MIPS_FUNCT_BLTZ: case MIPS_FUNCT_BLTZL: if ((int32_t)sim->reg[ins.rs] < 0) sim->pc += ins.offset << 2; break; default: sim_dump(sim, "unknown bfunct (0b%06b)", ins.bfunct); } } void sim_ins(struct simulator *sim, uint32_t raw) { // get ins parts union mips_instruction_data ins = { .raw = B32(raw) }; // reset zero reg sim->reg[MIPS_REG_ZERO] = 0; switch (ins.op) { case MIPS_OP_SPECIAL: sim_ins_special(sim, ins); break; case MIPS_OP_REGIMM: sim_ins_regimm(sim, ins); break; case MIPS_OP_ADDI: sim->reg[ins.rt] = (int32_t)sim->reg[ins.rs] + (int16_t) ins.immd; break; case MIPS_OP_ADDIU: sim->reg[ins.rt] = sim->reg[ins.rs] + ins.immd; break; case MIPS_OP_ANDI: sim->reg[ins.rt] = sim->reg[ins.rs] & ins.immd; break; case MIPS_OP_BALC: sim->reg[MIPS_REG_RA] = sim->pc; /* fall through */ case MIPS_OP_BC: sim->pc += ins.offs26 << 2; break; case MIPS_OP_BEQ: case MIPS_OP_BEQL: if (sim->reg[ins.rs] == sim->reg[ins.rt]) sim->pc += ins.offset << 2; break; case MIPS_OP_BGTZ: case MIPS_OP_BGTZL: if ((int32_t)sim->reg[ins.rs] <= 0) sim->pc += ins.offset << 2; break; case MIPS_OP_BLEZ: case MIPS_OP_BLEZL: if ((int32_t)sim->reg[ins.rs] <= 0) sim->pc += ins.offset << 2; break; case MIPS_OP_BNE: case MIPS_OP_BNEL: if (sim->reg[ins.rs] != sim->reg[ins.rt]) sim->pc += ins.offset << 2; break; case MIPS_OP_JAL: sim->reg[MIPS_REG_RA] = sim->pc; /* fall through */ case MIPS_OP_J: sim->pc = ins.target << 2; break; case MIPS_OP_LB: sim->reg[ins.rt] = * (int8_t *) (uintptr_t) (sim->reg[ins.rs] + ins.offset); break; case MIPS_OP_LBU: sim->reg[ins.rt] = * (uint8_t *) (uintptr_t) (sim->reg[ins.rs] + ins.offset); break; case MIPS_OP_LH: sim->reg[ins.rt] = * (int16_t *) (uintptr_t) (sim->reg[ins.rs] + ins.offset); break; case MIPS_OP_LHU: sim->reg[ins.rt] = * (uint16_t *) (uintptr_t) (sim->reg[ins.rs] + ins.offset); break; case MIPS_OP_LUI: sim->reg[ins.rt] = ins.immd << 16; break; case MIPS_OP_LW: sim->reg[ins.rt] = * (uint32_t *) (uintptr_t) (sim->reg[ins.rs] + ins.offset); break; case MIPS_OP_SB: * (uint8_t *) (uintptr_t) (sim->reg[ins.rs] + + ins.offset) = sim->reg[ins.rt]; break; case MIPS_OP_SH: * (uint16_t *) (uintptr_t) (sim->reg[ins.rs] + ins.offset) = sim->reg[ins.rt]; break; case MIPS_OP_SW: * (uint32_t *) (uintptr_t) (sim->reg[ins.rs] + ins.offset) = sim->reg[ins.rt]; break; case MIPS_OP_SLTI: sim->reg[ins.rt] = (int32_t)sim->reg[ins.rs] < (int16_t)ins.immd ? 1 : 0; break; case MIPS_OP_SLTIU: sim->reg[ins.rt] = sim->reg[ins.rs] < ins.immd ? 1 : 0; break; case MIPS_OP_ORI: sim->reg[ins.rt] = sim->reg[ins.rs] | ins.immd; break; case MIPS_OP_XORI: sim->reg[ins.rt] = sim->reg[ins.rs] ^ ins.immd; break; default: sim_dump(sim, "unknown op code (0b%05b)", ins.op); } }