forked from lowRISC/ibex
-
Notifications
You must be signed in to change notification settings - Fork 2
/
zeroriscy_prefetch_buffer.sv
252 lines (198 loc) · 7.25 KB
/
zeroriscy_prefetch_buffer.sv
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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
////////////////////////////////////////////////////////////////////////////////
// Engineer: Andreas Traber - [email protected] //
// //
// Design Name: Prefetcher Buffer for 32 bit memory interface //
// Project Name: zero-riscy //
// Language: SystemVerilog //
// //
// Description: Prefetch Buffer that caches instructions. This cuts overly //
// long critical paths to the instruction cache //
// //
////////////////////////////////////////////////////////////////////////////////
module zeroriscy_prefetch_buffer
(
input logic clk,
input logic rst_n,
input logic req_i,
input logic branch_i,
input logic [31:0] addr_i,
input logic ready_i,
output logic valid_o,
output logic [31:0] rdata_o,
output logic [31:0] addr_o,
// goes to instruction memory / instruction cache
output logic instr_req_o,
input logic instr_gnt_i,
output logic [31:0] instr_addr_o,
input logic [31:0] instr_rdata_i,
input logic instr_rvalid_i,
// Prefetch Buffer Status
output logic busy_o
);
enum logic [1:0] {IDLE, WAIT_GNT, WAIT_RVALID, WAIT_ABORTED } CS, NS;
logic [31:0] instr_addr_q, fetch_addr;
logic addr_valid;
logic fifo_valid;
logic fifo_ready;
logic fifo_clear;
logic valid_stored;
//////////////////////////////////////////////////////////////////////////////
// prefetch buffer status
//////////////////////////////////////////////////////////////////////////////
assign busy_o = (CS != IDLE) || instr_req_o;
//////////////////////////////////////////////////////////////////////////////
// fetch fifo
// consumes addresses and rdata
//////////////////////////////////////////////////////////////////////////////
zeroriscy_fetch_fifo fifo_i
(
.clk ( clk ),
.rst_n ( rst_n ),
.clear_i ( fifo_clear ),
.in_addr_i ( instr_addr_q ),
.in_rdata_i ( instr_rdata_i ),
.in_valid_i ( fifo_valid ),
.in_ready_o ( fifo_ready ),
.out_valid_o ( valid_o ),
.out_ready_i ( ready_i ),
.out_rdata_o ( rdata_o ),
.out_addr_o ( addr_o ),
.out_valid_stored_o ( valid_stored )
);
//////////////////////////////////////////////////////////////////////////////
// fetch addr
//////////////////////////////////////////////////////////////////////////////
assign fetch_addr = {instr_addr_q[31:2], 2'b00} + 32'd4;
always_comb
begin
fifo_clear = branch_i;
end
//////////////////////////////////////////////////////////////////////////////
// instruction fetch FSM
// deals with instruction memory / instruction cache
//////////////////////////////////////////////////////////////////////////////
always_comb
begin
instr_req_o = 1'b0;
instr_addr_o = fetch_addr;
fifo_valid = 1'b0;
addr_valid = 1'b0;
NS = CS;
unique case(CS)
// default state, not waiting for requested data
IDLE:
begin
instr_addr_o = fetch_addr;
instr_req_o = 1'b0;
if (branch_i)
instr_addr_o = addr_i;
if (req_i & (fifo_ready | branch_i )) begin
instr_req_o = 1'b1;
addr_valid = 1'b1;
if(instr_gnt_i) //~> granted request
NS = WAIT_RVALID;
else begin //~> got a request but no grant
NS = WAIT_GNT;
end
end
end // case: IDLE
// we sent a request but did not yet get a grant
WAIT_GNT:
begin
instr_addr_o = instr_addr_q;
instr_req_o = 1'b1;
if (branch_i) begin
instr_addr_o = addr_i;
addr_valid = 1'b1;
end
if(instr_gnt_i)
NS = WAIT_RVALID;
else
NS = WAIT_GNT;
end // case: WAIT_GNT
// we wait for rvalid, after that we are ready to serve a new request
WAIT_RVALID: begin
instr_addr_o = fetch_addr;
if (branch_i)
instr_addr_o = addr_i;
if (req_i & (fifo_ready | branch_i)) begin
// prepare for next request
if (instr_rvalid_i) begin
instr_req_o = 1'b1;
fifo_valid = 1'b1;
addr_valid = 1'b1;
if (instr_gnt_i) begin
NS = WAIT_RVALID;
end else begin
NS = WAIT_GNT;
end
end else begin
// we are requested to abort our current request
// we didn't get an rvalid yet, so wait for it
if (branch_i) begin
addr_valid = 1'b1;
NS = WAIT_ABORTED;
end
end
end else begin
// just wait for rvalid and go back to IDLE, no new request
if (instr_rvalid_i) begin
fifo_valid = 1'b1;
NS = IDLE;
end
end
end // case: WAIT_RVALID
// our last request was aborted, but we didn't yet get a rvalid and
// there was no new request sent yet
// we assume that req_i is set to high
WAIT_ABORTED: begin
instr_addr_o = instr_addr_q;
if (branch_i) begin
instr_addr_o = addr_i;
addr_valid = 1'b1;
end
if (instr_rvalid_i) begin
instr_req_o = 1'b1;
// no need to send address, already done in WAIT_RVALID
if (instr_gnt_i) begin
NS = WAIT_RVALID;
end else begin
NS = WAIT_GNT;
end
end
end
default:
begin
NS = IDLE;
instr_req_o = 1'b0;
end
endcase
end
//////////////////////////////////////////////////////////////////////////////
// registers
//////////////////////////////////////////////////////////////////////////////
always_ff @(posedge clk, negedge rst_n)
begin
if(rst_n == 1'b0)
begin
CS <= IDLE;
instr_addr_q <= '0;
end
else
begin
CS <= NS;
if (addr_valid) begin
instr_addr_q <= instr_addr_o;
end
end
end
endmodule