diff --git a/sim/simx/execute.cpp b/sim/simx/execute.cpp index ba36bca151..c24e8d2c85 100644 --- a/sim/simx/execute.cpp +++ b/sim/simx/execute.cpp @@ -466,7 +466,7 @@ instr_trace_t* Emulator::execute(const Instr &instr, uint32_t wid) { continue; rd_data[t].i = next_pc; } - next_pc = rs1_data[thread_last].i + offset; + next_pc = (rs1_data[thread_last].u + offset) & ~Word(1); trace->fetch_stall = true; rd_write = true; } break; @@ -1562,4 +1562,4 @@ instr_trace_t* Emulator::execute(const Instr &instr, uint32_t wid) { } return trace; -} \ No newline at end of file +} diff --git a/tests/kernel/conform/main.cpp b/tests/kernel/conform/main.cpp index 0efa00cab5..908754776c 100644 --- a/tests/kernel/conform/main.cpp +++ b/tests/kernel/conform/main.cpp @@ -28,6 +28,8 @@ int main() { errors += test_shfl(); + errors += test_jalr(); + if (0 == errors) { PRINTF("Passed!\n"); } else { @@ -35,4 +37,4 @@ int main() { } return errors; -} \ No newline at end of file +} diff --git a/tests/kernel/conform/tests.cpp b/tests/kernel/conform/tests.cpp index c1b19575de..9af5b87435 100644 --- a/tests/kernel/conform/tests.cpp +++ b/tests/kernel/conform/tests.cpp @@ -401,4 +401,61 @@ int test_shfl() { do_shfl(); vx_tmc_one(); // back to thread0 return check_error(shfl_buffer, 0, num_threads); -} \ No newline at end of file +} + +/////////////////////////////////////////////////////////////////////////////// + +#define JALR_PASS_VALUE 0x13579bdf + +uint32_t __attribute__((noinline)) do_jalr_misaligned() { + uint32_t value = 0; + asm volatile( + // x1 is prepared so that the misaligned decode path can immediately + // execute a valid JALR to label 3 and produce a deterministic failure + // value instead of aborting in the decoder. + "la x1, 3f\n" + // 1744 is chosen to match the immediate embedded in the overlapped + // misaligned instruction below: jalr x0, -1744(x1). + "addi x1, x1, 1744\n" + "la t0, 1f\n" + // Add 1 on purpose. A correct JALR implementation must clear bit 0 and + // land at 1f. An incorrect implementation enters at 1f + 1 instead. + "addi t0, t0, 1\n" + "jalr x0, t0, 0\n" + ".balign 4\n" + "1:\n" + // 0x00806713 is a hand-picked overlapped instruction word: + // - from the aligned entry at 1f it decodes as: ori x14, x0, 8 + // - from the misaligned entry at 1f + 1 it decodes as: + // jalr x0, -1744(x1) + // + // That lets both fixed and unfixed builds decode valid instructions + // while still producing different results. + ".4byte 0x00806713\n" + // This is the next aligned instruction after the pass-path overlap word. + ".4byte 0x00000093\n" + "j 4f\n" + "3:\n" + // Fail signature used when JALR does not clear bit 0. + "li %[value], 0x2468ace0\n" + "j 5f\n" + "4:\n" + // Pass signature used when JALR correctly clears bit 0. + "li %[value], 0x13579bdf\n" + "5:\n" + : [value] "=r" (value) + : + : "x1", "t0", "x14"); + return value; +} + +int test_jalr() { + PRINTF("JALR Test\n"); + vx_tmc_one(); + uint32_t value = do_jalr_misaligned(); + if (value != JALR_PASS_VALUE) { + PRINTF("*** error: jalr value=0x%x, expected=0x%x\n", value, JALR_PASS_VALUE); + return 1; + } + return 0; +} diff --git a/tests/kernel/conform/tests.h b/tests/kernel/conform/tests.h index 52e7df68b3..06576930b5 100644 --- a/tests/kernel/conform/tests.h +++ b/tests/kernel/conform/tests.h @@ -27,4 +27,6 @@ int test_vote(); int test_shfl(); +int test_jalr(); + #endif