summaryrefslogtreecommitdiff
path: root/msim/ins.c
diff options
context:
space:
mode:
Diffstat (limited to 'msim/ins.c')
-rw-r--r--msim/ins.c177
1 files changed, 116 insertions, 61 deletions
diff --git a/msim/ins.c b/msim/ins.c
index 6a98e92..209f613 100644
--- a/msim/ins.c
+++ b/msim/ins.c
@@ -1,25 +1,74 @@
#include <mips.h>
#include <melf.h>
#include <stdint.h>
-#include <stdio.h>
#include <unistd.h>
-
+#include <merror.h>
#include "sim.h"
-#define I16(n) ((int32_t)(uint16_t)(n))
+/* sign extension */
+#define SE(n) ((uint32_t)(int16_t)(n))
+/* sign extension 64bit */
+#define SE64(n) ((uint64_t)(int32_t)(n))
+/* signed sign extension 64bit */
+#define SSE64(n) ((int64_t)(int32_t)(n))
+/* shifted sign extention */
+#define SSE(n, s) (SE(n) << (s))
+/* zero extension */
+#define ZE(n) ((uint32_t)(uint16_t)(n))
+/* get vaddr from offset and base */
+#define VADDR(sim, ins) \
+ ((sim->reg[ins.rs] /* base */) + \
+ (SE(ins.offset) /* offset */))
+/* gets the low 32 bits of a 64 bit value */
+#define LO(n) (((1ULL << 32) - 1) & (n))
+/* gets the hi 32 bits of a 64 bit value */
+#define HI(n) ((n) >> 32)
+
+/* convert to a pointer */
+#define PTR(ptr, type) ((type *)(uintptr_t)(ptr))
+
+static void sim_delay_slot(struct simulator *sim)
+{
+ if (sim->args->jdelay == false)
+ return;
+
+ uint32_t ins = * (uint32_t *) (uintptr_t) sim->pc;
+ union mips_instruction_data data = { .raw = B32(ins) };
+ sim->pc += 4;
+
+ switch (data.op) {
+ case MIPS_OP_REGIMM:
+ case MIPS_OP_J:
+ case MIPS_OP_JAL:
+ case MIPS_OP_JALX:
+ case MIPS_OP_BEQ:
+ case MIPS_OP_BEQL:
+ case MIPS_OP_BNE:
+ case MIPS_OP_BNEL:
+ case MIPS_OP_BGTZ:
+ case MIPS_OP_BGTZL:
+ case MIPS_OP_BLEZ:
+ case MIPS_OP_BLEZL:
+ sim_dump(sim, "attempted to execute jump instruction in delay"
+ "slot (0b%05b)", data.op);
+ default:
+ }
+
+ sim_ins(sim, ins);
+}
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;
+ sim->reg[ins.rd] = (SSE64(sim->reg[ins.rs]) *
+ SSE64(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;
+ sim->reg[ins.rd] = (SSE64(sim->reg[ins.rs]) *
+ SSE64(sim->reg[ins.rt])) >> 32;
break;
default:
@@ -32,13 +81,13 @@ static void sim_ins_special_sop31(struct simulator *sim,
{
switch (ins.shamt) {
case MIPS_SOP31_MULU:
- sim->reg[ins.rd] = ((uint64_t)sim->reg[ins.rs] /
- (uint64_t)sim->reg[ins.rt]) >> 0;
+ sim->reg[ins.rd] = (SE64(sim->reg[ins.rs]) *
+ SE64(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;
+ sim->reg[ins.rd] = (SE64(sim->reg[ins.rs]) *
+ SE64(sim->reg[ins.rt])) >> 32;
break;
default:
@@ -51,13 +100,13 @@ static void sim_ins_special_sop32(struct simulator *sim,
{
switch (ins.shamt) {
case MIPS_SOP32_DIV:
- sim->reg[ins.rd] = (int32_t)sim->reg[ins.rs] /
- (int32_t)sim->reg[ins.rt];
+ sim->reg[ins.rd] = (signed) sim->reg[ins.rs] /
+ (signed) 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];
+ sim->reg[ins.rd] = (signed) sim->reg[ins.rs] %
+ (signed) sim->reg[ins.rt];
break;
default:
@@ -87,8 +136,8 @@ static void sim_ins_special(struct simulator *sim,
{
switch (ins.funct) {
case MIPS_FUNCT_ADD:
- sim->reg[ins.rd] = (int32_t)sim->reg[ins.rs] +
- (int32_t)sim->reg[ins.rt];
+ // TODO: trap on overflow
+ sim->reg[ins.rd] = sim->reg[ins.rs] + sim->reg[ins.rt];
break;
case MIPS_FUNCT_ADDU:
@@ -116,9 +165,10 @@ static void sim_ins_special(struct simulator *sim,
break;
case MIPS_FUNCT_JALR:
- sim->reg[MIPS_REG_RA] = sim->pc;
+ sim->reg[ins.rd] = sim->pc + 4;
/* fall through */
case MIPS_FUNCT_JR:
+ sim_delay_slot(sim);
sim->pc = sim->reg[ins.rs];
break;
@@ -147,7 +197,8 @@ static void sim_ins_special(struct simulator *sim,
break;
case MIPS_FUNCT_SLT:
- sim->reg[ins.rd] = (int32_t)sim->reg[ins.rs] < (int32_t)sim->reg[ins.rt] ? 1 : 0;
+ sim->reg[ins.rd] = (signed) sim->reg[ins.rs] <
+ (signed) sim->reg[ins.rt] ? 1 : 0;
break;
case MIPS_FUNCT_SLTU:
@@ -155,11 +206,12 @@ static void sim_ins_special(struct simulator *sim,
break;
case MIPS_FUNCT_SRA:
- sim->reg[ins.rd] = (int32_t)sim->reg[ins.rt] >> ins.shamt;
+ sim->reg[ins.rd] = (signed) 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];
+ sim->reg[ins.rd] = (signed) sim->reg[ins.rt] >>
+ sim->reg[ins.rs];
break;
case MIPS_FUNCT_SRL:
@@ -171,8 +223,8 @@ static void sim_ins_special(struct simulator *sim,
break;
case MIPS_FUNCT_SUB:
- sim->reg[ins.rd] = (int32_t)sim->reg[ins.rs] -
- (int32_t)sim->reg[ins.rt];
+ // TODO: trap on overflow
+ sim->reg[ins.rd] = sim->reg[ins.rs] - sim->reg[ins.rt];
break;
case MIPS_FUNCT_SUBU:
@@ -209,29 +261,33 @@ static void sim_ins_special(struct simulator *sim,
static void sim_ins_regimm(struct simulator *sim,
union mips_instruction_data ins)
{
+ uint32_t pc = sim->pc;
+
switch (ins.bfunct) {
case MIPS_FUNCT_BGEZAL:
case MIPS_FUNCT_BGEZALL:
- sim->reg[MIPS_REG_RA] = sim->pc;
+ sim->reg[MIPS_REG_RA] = sim->pc + 4;
/* fall through */
case MIPS_FUNCT_BGEZ:
case MIPS_FUNCT_BGEZL:
- if ((int32_t)sim->reg[ins.rs] >= 0)
- sim->pc += ins.offset << 2;
+ sim_delay_slot(sim);
+ if ((signed) sim->reg[ins.rs] >= 0)
+ sim->pc = pc + SSE(ins.offset, 2);
break;
case MIPS_FUNCT_BLTZAL:
case MIPS_FUNCT_BLTZALL:
- sim->reg[MIPS_REG_RA] = sim->pc;
+ sim->reg[MIPS_REG_RA] = sim->pc + 4;
/* fall through */
case MIPS_FUNCT_BLTZ:
case MIPS_FUNCT_BLTZL:
- if ((int32_t)sim->reg[ins.rs] < 0)
- sim->pc += ins.offset << 2;
+ sim_delay_slot(sim);
+ if ((signed) sim->reg[ins.rs] < 0)
+ sim->pc = pc + SSE(ins.offset, 2);
break;
default:
- sim_dump(sim, "unknown bfunct (0b%06b)", ins.bfunct);
+ sim_dump(sim, "unknown branch funct (0b%06b)", ins.bfunct);
}
}
@@ -241,6 +297,7 @@ void sim_ins(struct simulator *sim, uint32_t raw)
union mips_instruction_data ins = {
.raw = B32(raw)
};
+ uint32_t pc = sim->pc;
// reset zero reg
sim->reg[MIPS_REG_ZERO] = 0;
@@ -256,73 +313,75 @@ void sim_ins(struct simulator *sim, uint32_t raw)
case MIPS_OP_ADDI:
sim->reg[ins.rt] = (int32_t)sim->reg[ins.rs] +
- (int16_t) ins.immd;
+ SE(ins.immd);
break;
case MIPS_OP_ADDIU:
- sim->reg[ins.rt] = sim->reg[ins.rs] + ins.immd;
+ sim->reg[ins.rt] = sim->reg[ins.rs] + SE(ins.immd);
break;
case MIPS_OP_ANDI:
- sim->reg[ins.rt] = sim->reg[ins.rs] & ins.immd;
+ sim->reg[ins.rt] = sim->reg[ins.rs] & ZE(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;
+ sim->pc += SSE(ins.offs26, 2);
break;
case MIPS_OP_BEQ:
case MIPS_OP_BEQL:
+ sim_delay_slot(sim);
if (sim->reg[ins.rs] == sim->reg[ins.rt])
- sim->pc += ins.offset << 2;
+ sim->pc = pc + SSE(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;
+ sim_delay_slot(sim);
+ if ((signed) sim->reg[ins.rs] <= 0)
+ sim->pc = pc + SSE(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;
+ sim_delay_slot(sim);
+ if ((signed) sim->reg[ins.rs] <= 0)
+ sim->pc = pc + SSE(ins.offset, 2);
break;
case MIPS_OP_BNE:
case MIPS_OP_BNEL:
+ sim_delay_slot(sim);
if (sim->reg[ins.rs] != sim->reg[ins.rt])
- sim->pc += ins.offset << 2;
+ sim->pc = pc + SSE(ins.offset, 2);
break;
case MIPS_OP_JAL:
- sim->reg[MIPS_REG_RA] = sim->pc;
+ sim->reg[MIPS_REG_RA] = sim->pc + 4;
/* fall through */
case MIPS_OP_J:
- sim->pc = ins.target << 2;
+ sim_delay_slot(sim);
+ sim->pc &= 0xF0000000;
+ sim->pc |= ins.target << 2;
break;
case MIPS_OP_LB:
- sim->reg[ins.rt] = * (int8_t *) (uintptr_t) (sim->reg[ins.rs]
- + ins.offset);
+ sim->reg[ins.rt] = *PTR(VADDR(sim, ins), int8_t);
break;
case MIPS_OP_LBU:
- sim->reg[ins.rt] = * (uint8_t *) (uintptr_t) (sim->reg[ins.rs]
- + ins.offset);
+ sim->reg[ins.rt] = *PTR(VADDR(sim, ins), uint8_t);
break;
case MIPS_OP_LH:
- sim->reg[ins.rt] = * (int16_t *) (uintptr_t) (sim->reg[ins.rs]
- + ins.offset);
+ sim->reg[ins.rt] = *PTR(VADDR(sim, ins), int16_t);
break;
case MIPS_OP_LHU:
- sim->reg[ins.rt] = * (uint16_t *) (uintptr_t) (sim->reg[ins.rs]
- + ins.offset);
+ sim->reg[ins.rt] = *PTR(VADDR(sim, ins), uint16_t);
break;
case MIPS_OP_LUI:
@@ -330,32 +389,28 @@ void sim_ins(struct simulator *sim, uint32_t raw)
break;
case MIPS_OP_LW:
- sim->reg[ins.rt] = * (uint32_t *) (uintptr_t) (sim->reg[ins.rs]
- + ins.offset);
+ sim->reg[ins.rt] = *PTR(VADDR(sim, ins), uint32_t);
break;
case MIPS_OP_SB:
- * (uint8_t *) (uintptr_t) (sim->reg[ins.rs] +
- + ins.offset) = sim->reg[ins.rt];
+ *PTR(VADDR(sim, ins), uint8_t) = sim->reg[ins.rt];
break;
case MIPS_OP_SH:
- * (uint16_t *) (uintptr_t) (sim->reg[ins.rs] +
- ins.offset) = sim->reg[ins.rt];
+ *PTR(VADDR(sim, ins), uint16_t) = sim->reg[ins.rt];
break;
case MIPS_OP_SW:
- * (uint32_t *) (uintptr_t) (sim->reg[ins.rs] +
- ins.offset) = sim->reg[ins.rt];
+ *PTR(VADDR(sim, ins), uint32_t) = 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;
+ sim->reg[ins.rt] = (signed) sim->reg[ins.rs] <
+ (signed) SE(ins.immd) ? 1 : 0;
break;
case MIPS_OP_SLTIU:
- sim->reg[ins.rt] = sim->reg[ins.rs] < ins.immd ? 1 : 0;
+ sim->reg[ins.rt] = sim->reg[ins.rs] < SE(ins.immd) ? 1 : 0;
break;
case MIPS_OP_ORI: