summaryrefslogtreecommitdiff
path: root/rtl/core/core_fetch.sv
diff options
context:
space:
mode:
Diffstat (limited to 'rtl/core/core_fetch.sv')
-rw-r--r--rtl/core/core_fetch.sv74
1 files changed, 74 insertions, 0 deletions
diff --git a/rtl/core/core_fetch.sv b/rtl/core/core_fetch.sv
new file mode 100644
index 0000000..279d2c2
--- /dev/null
+++ b/rtl/core/core_fetch.sv
@@ -0,0 +1,74 @@
+`include "core/uarch.sv"
+
+module core_fetch
+#(parameter PREFETCH_ORDER=2)
+(
+ input logic clk,
+ rst_n,
+ stall,
+ fault,
+ fetched,
+ explicit_branch /*verilator public*/ /*verilator forceable*/,
+ wr_pc,
+ prefetch_flush,
+ input ptr branch_target,
+ porch_insn_pc,
+ input word wr_current,
+ fetch_data,
+
+ output logic fetch,
+ flush,
+ nop,
+ output word insn,
+ output ptr insn_pc,
+ addr,
+ fetch_head,
+ output logic insn_abort
+);
+
+ ptr target /*verilator public*/ /*verilator forceable*/, hold_addr;
+ logic branch, prefetch_ready, fetched_valid, discard, pending, next_pending;
+
+ assign fetch = prefetch_ready && !discard;
+ assign flush = branch || prefetch_flush;
+ assign branch = explicit_branch || wr_pc;
+ assign target = wr_pc ? wr_current[31:2] : branch_target; //TODO: alignment exception
+ assign next_pending = fetch || (pending && !fetched);
+ assign fetched_valid = fetched && !discard;
+
+ core_prefetch #(.ORDER(PREFETCH_ORDER)) prefetch
+ (
+ .head(fetch_head),
+ .fetched(fetched_valid),
+ .fetch(prefetch_ready),
+ .*
+ );
+
+ always_comb begin
+ if(branch)
+ fetch_head = target;
+ else if(prefetch_flush)
+ fetch_head = porch_insn_pc;
+ else
+ fetch_head = {30{1'bx}};
+
+ if(flush)
+ addr = fetch_head;
+ else if(fetch && fetched_valid)
+ addr = hold_addr + 1;
+ else
+ addr = hold_addr;
+ end
+
+ always_ff @(posedge clk or negedge rst_n)
+ if(!rst_n) begin
+ pending <= 0;
+ discard <= 0;
+ hold_addr <= 0;
+ end else begin
+ pending <= next_pending;
+ discard <= next_pending && (discard || flush);
+ hold_addr <= addr;
+ end
+
+endmodule