summaryrefslogtreecommitdiff
path: root/msim/ins.c
diff options
context:
space:
mode:
authorFreya Murphy <freya@freyacat.org>2024-09-30 18:52:25 -0400
committerFreya Murphy <freya@freyacat.org>2024-09-30 18:52:25 -0400
commit4af200b00188e02b2c6207dfe494a3dd12556c5f (patch)
tree25d993117e6306907d1d3821ef4fca729390d221 /msim/ins.c
parentupdate runtime to return exit code from main (diff)
downloadmips-4af200b00188e02b2c6207dfe494a3dd12556c5f.tar.gz
mips-4af200b00188e02b2c6207dfe494a3dd12556c5f.tar.bz2
mips-4af200b00188e02b2c6207dfe494a3dd12556c5f.zip
msim done (ish)
Diffstat (limited to '')
-rw-r--r--msim/ins.c373
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);
+ }
+}
+