From ce8be82f047a15edd86f5844492ed63705e99914 Mon Sep 17 00:00:00 2001 From: Julian Blake Kongslie Date: Thu, 22 Sep 2022 13:31:06 -0700 Subject: Add a trivial indirect jump predictor and matching test --- backend/regfile.h | 1 + frontend/decode.h | 15 ++++++++++++--- inst.h | 1 + tests/loop-indirect.hex | 1 + 4 files changed, 15 insertions(+), 3 deletions(-) create mode 100644 tests/loop-indirect.hex diff --git a/backend/regfile.h b/backend/regfile.h index 276504c..4cf328a 100644 --- a/backend/regfile.h +++ b/backend/regfile.h @@ -33,6 +33,7 @@ namespace backend { auto i = writebackp.read(); if (i.generation == generation_down) { pte(i.transaction, "W", fmt::format("writeback gen={} pc={:x}", generation_down, pc)); + assert(pc == i.init_pc); auto old_pc = pc; pc = i.linear_next_pc; switch (i.field[OPCODE]) { diff --git a/frontend/decode.h b/frontend/decode.h index 717d0f6..cb7bedd 100644 --- a/frontend/decode.h +++ b/frontend/decode.h @@ -24,15 +24,20 @@ namespace frontend { unsigned int generation_down = 0; std::uint64_t pc = 0; + std::uint64_t indirect_jump_origin = ~(std::uint64_t)0; + std::uint64_t indirect_jump_destination = ~(std::uint64_t)0; + static constexpr unsigned int MAX_INST_SIZE = 64; - static constexpr unsigned int BYTES_PER_CYCLE = 4; + static constexpr unsigned int BYTES_PER_CYCLE = 1; void clock() { if (restartp.can_read()) { auto r = restartp.read(); generation_down = r.new_generation; - pc = r.new_pc; + next_inst.init_pc = pc = r.new_pc; next_inst.size = 0; + indirect_jump_origin = r.from_pc; + indirect_jump_destination = r.new_pc; for (auto &f : next_inst.field) f = 0; fetch::restart fr; @@ -95,7 +100,10 @@ namespace frontend { redirect = target; } } else if (!taken.has_value() || taken.value()) { - unpredictable = true; + if (next_inst.init_pc == indirect_jump_origin) + redirect = indirect_jump_destination; + else + unpredictable = true; } } if (redirect.has_value()) { @@ -106,6 +114,7 @@ namespace frontend { next_inst.predicted_next_pc.reset(); } instp->write(std::move(next_inst)); + next_inst.init_pc = pc; next_inst.size = unpredictable ? MAX_INST_SIZE : 0; for (auto &f : next_inst.field) f = 0; diff --git a/inst.h b/inst.h index 15ae9d7..5f96fe3 100644 --- a/inst.h +++ b/inst.h @@ -8,6 +8,7 @@ struct inst { infra::transaction transaction; unsigned int generation; unsigned int size = 0; + std::uint64_t init_pc = 0; std::uint64_t linear_next_pc; std::optional predicted_next_pc; std::uint64_t field[4] = {}; diff --git a/tests/loop-indirect.hex b/tests/loop-indirect.hex new file mode 100644 index 0000000..c8b07f7 --- /dev/null +++ b/tests/loop-indirect.hex @@ -0,0 +1 @@ +00 # 0: jmp r0 if r0 == 0 -- cgit v1.2.3