summaryrefslogtreecommitdiff
path: root/rtl/core/fetch/fetch.sv
blob: acc8e9d8cdaa4edfe4a42bf5afe63e9452a1039b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
`include "core/uarch.sv"

module core_fetch
#(parameter PREFETCH_ORDER=2)
(
	input  logic clk,
	             rst_n,
	             stall,
	             fetched,
	             explicit_branch,
	             wr_pc,
	             prefetch_flush,
	input  ptr   branch_target,
	input  word  wr_current,
	             fetch_data,

	output logic fetch,
	             flush,
	output word  insn,
	output ptr   insn_pc,
	             addr,
	             fetch_head
);

	ptr next_pc, hold_addr, target;
	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 = next_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