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 #include #include -#include #include - +#include #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: diff --git a/msim/load.c b/msim/load.c index 77b62ed..a4029cf 100644 --- a/msim/load.c +++ b/msim/load.c @@ -52,12 +52,15 @@ static int load_ehdr(struct simulator *sim, struct load_state *state) res |= assert_ehdr(&baseline.e_##name, \ &ehdr.e_##name, size) \ + // ignore abi ver + ehdr.e_ident[EI_ABIVERSION] = 0x00; + int res = 0; EHDR_ASSERT(ident, EI_NIDENT); EHDR_ASSERT(type, sizeof(Elf32_Half)); EHDR_ASSERT(machine, sizeof(Elf32_Half)); EHDR_ASSERT(version, sizeof(Elf32_Word)); - EHDR_ASSERT(flags, sizeof(Elf32_Word)); + // EHDR_ASSERT(flags, sizeof(Elf32_Word)); EHDR_ASSERT(ehsize, sizeof(Elf32_Half)); EHDR_ASSERT(phentsize, sizeof(Elf32_Half)); EHDR_ASSERT(shentsize, sizeof(Elf32_Half)); diff --git a/msim/main.c b/msim/main.c index f8a0999..13f6383 100644 --- a/msim/main.c +++ b/msim/main.c @@ -2,7 +2,6 @@ #include #include #include -#include #include "fault.h" #include "sim.h" @@ -11,7 +10,7 @@ static void help(void) { printf("usage: msim [options] executable\n\n"); printf("options:\n"); printf("\t-h\t\tprints this help messaage\n"); - printf("\t-c\t\tdisable runtime memory checks (allows segfault)\n"); + printf("\t-j\t\tdisable jump delay slot\n"); printf("\t-d\t\truns the debugger\n"); } @@ -21,18 +20,18 @@ int main(int argc, char **argv) { struct simulator_args args = { .executable = NULL, .debug = false, - .memchk = true, + .jdelay = true, }; int c; - while ((c = getopt(argc, argv, "hcd")) != 1) { + while ((c = getopt(argc, argv, "hjd")) != 1) { switch (c) { case 'h': help(); return M_SUCCESS; - case 'c': - args.memchk = false; + case 'j': + args.jdelay = false; break; case 'd': args.debug = true; diff --git a/msim/sim.h b/msim/sim.h index 517babd..6913792 100644 --- a/msim/sim.h +++ b/msim/sim.h @@ -9,7 +9,7 @@ /// arguments struct simulator_args { char *executable; - bool memchk; + bool jdelay; bool debug; };