diff options
author | Freya Murphy <freya@freyacat.org> | 2024-09-30 18:52:25 -0400 |
---|---|---|
committer | Freya Murphy <freya@freyacat.org> | 2024-09-30 18:52:25 -0400 |
commit | 4af200b00188e02b2c6207dfe494a3dd12556c5f (patch) | |
tree | 25d993117e6306907d1d3821ef4fca729390d221 /msim/ins.c | |
parent | update runtime to return exit code from main (diff) | |
download | mips-4af200b00188e02b2c6207dfe494a3dd12556c5f.tar.gz mips-4af200b00188e02b2c6207dfe494a3dd12556c5f.tar.bz2 mips-4af200b00188e02b2c6207dfe494a3dd12556c5f.zip |
msim done (ish)
Diffstat (limited to '')
-rw-r--r-- | msim/ins.c | 373 |
1 files changed, 373 insertions, 0 deletions
diff --git a/msim/ins.c b/msim/ins.c new file mode 100644 index 0000000..6a98e92 --- /dev/null +++ b/msim/ins.c @@ -0,0 +1,373 @@ +#include <mips.h> +#include <melf.h> +#include <stdint.h> +#include <stdio.h> +#include <unistd.h> + +#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); + } +} + |