1 |
2 |
smjoshua |
//////////////////////////////////////////////////////////////////
|
2 |
|
|
// //
|
3 |
|
|
// OoOPs Core Instruction Cache Control module //
|
4 |
|
|
// //
|
5 |
|
|
// This file is part of the OoOPs project //
|
6 |
|
|
// http://www.opencores.org/project,oops //
|
7 |
|
|
// //
|
8 |
|
|
// Description: //
|
9 |
|
|
// Controller for Instruction Cache. Block takes requests from//
|
10 |
|
|
// the IF stage, handles the inputs to the cache RAMs, detects //
|
11 |
|
|
// cache hits, and generates bus requests if the cache misses. //
|
12 |
|
|
// The controller is only capable of handling one outstanding //
|
13 |
|
|
// miss and does no prefetching. //
|
14 |
|
|
// //
|
15 |
|
|
// Author(s): //
|
16 |
|
|
// - Joshua Smith, smjoshua@umich.edu //
|
17 |
|
|
// //
|
18 |
|
|
//////////////////////////////////////////////////////////////////
|
19 |
|
|
// //
|
20 |
|
|
// Copyright (C) 2012 Authors and OPENCORES.ORG //
|
21 |
|
|
// //
|
22 |
|
|
// This source file may be used and distributed without //
|
23 |
|
|
// restriction provided that this copyright statement is not //
|
24 |
|
|
// removed from the file and that any derivative work contains //
|
25 |
|
|
// the original copyright notice and the associated disclaimer. //
|
26 |
|
|
// //
|
27 |
|
|
// This source file is free software; you can redistribute it //
|
28 |
|
|
// and/or modify it under the terms of the GNU Lesser General //
|
29 |
|
|
// Public License as published by the Free Software Foundation; //
|
30 |
|
|
// either version 2.1 of the License, or (at your option) any //
|
31 |
|
|
// later version. //
|
32 |
|
|
// //
|
33 |
|
|
// This source is distributed in the hope that it will be //
|
34 |
|
|
// useful, but WITHOUT ANY WARRANTY; without even the implied //
|
35 |
|
|
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //
|
36 |
|
|
// PURPOSE. See the GNU Lesser General Public License for more //
|
37 |
|
|
// details. //
|
38 |
|
|
// //
|
39 |
|
|
// You should have received a copy of the GNU Lesser General //
|
40 |
|
|
// Public License along with this source; if not, download it //
|
41 |
|
|
// from http://www.opencores.org/lgpl.shtml //
|
42 |
|
|
// //
|
43 |
|
|
//////////////////////////////////////////////////////////////////
|
44 |
|
|
`include "ooops_defs.v"
|
45 |
|
|
|
46 |
|
|
module icache_ctl (
|
47 |
|
|
input wire clk,
|
48 |
|
|
input wire rst,
|
49 |
|
|
input wire rob_pipe_flush,
|
50 |
|
|
|
51 |
|
|
// Coprocessor interface (for IC enable)
|
52 |
|
|
input wire cp0_ic_enable,
|
53 |
|
|
|
54 |
|
|
// IF interface
|
55 |
|
|
input wire if_ic_req,
|
56 |
|
|
input wire [`ADDR_SZ-1:0] if_ic_fpc,
|
57 |
|
|
input wire [`ADDR_SZ-1:0] r_if_ic_fpc,
|
58 |
|
|
output wire [`INSTR_SZ-1:0] ic_if_data,
|
59 |
|
|
output wire ic_if_data_valid,
|
60 |
|
|
output wire ic_if_ready,
|
61 |
|
|
|
62 |
|
|
// Interface to cache memories
|
63 |
|
|
input wire [`IC_TAGRAM_SZ-1:0] ic_tagram_data,
|
64 |
|
|
input wire [`IC_LINE_SZ-1:0] ic_dataram_data,
|
65 |
|
|
output wire [`IC_LINE_SZ-1:0] ic_dataram_wr_data,
|
66 |
|
|
output wire [`IC_SI_SZ-1:0] ic_dataram_addr,
|
67 |
|
|
output wire ic_dataram_wren,
|
68 |
|
|
output wire [`IC_TAGRAM_SZ-1:0] ic_tagram_wr_data,
|
69 |
|
|
output wire [`IC_SI_SZ-1:0] ic_tagram_addr,
|
70 |
|
|
output wire ic_tagram_wren,
|
71 |
|
|
|
72 |
|
|
// Memory interface
|
73 |
|
|
output wire ic2bus_req,
|
74 |
|
|
output wire [`ADDR_SZ-1:0] ic2bus_fpc,
|
75 |
|
|
input wire bus2ic_valid,
|
76 |
|
|
input wire [`SYS_BUS_SZ-1:0] bus2ic_data
|
77 |
|
|
);
|
78 |
|
|
|
79 |
|
|
parameter IC_STATE_IDLE = 3'h0,
|
80 |
|
|
IC_STATE_REQ = 3'h1,
|
81 |
|
|
IC_STATE_WAIT = 3'h2,
|
82 |
|
|
IC_STATE_WR_RAM = 3'h3,
|
83 |
|
|
IC_STATE_INIT = 3'h4;
|
84 |
|
|
|
85 |
|
|
// Internal wires/regs
|
86 |
|
|
wire ic_cache_hit;
|
87 |
|
|
wire ic_tag_match;
|
88 |
|
|
wire ic_tag_valid;
|
89 |
|
|
wire [`IC_TAG_SZ-1:0] ic_tag;
|
90 |
|
|
wire r_if_ic_req;
|
91 |
|
|
|
92 |
|
|
wire [2:0] ic_state;
|
93 |
|
|
reg [2:0] ic_nstate;
|
94 |
|
|
wire [`IC_SI] ic_init_ctr;
|
95 |
|
|
wire [`IC_SI] ic_init_nctr;
|
96 |
|
|
wire ic_do_init;
|
97 |
|
|
wire ic_init_done;
|
98 |
|
|
wire ic_initialized;
|
99 |
|
|
wire ic_initialized_ld;
|
100 |
|
|
|
101 |
|
|
// Latch req signal so we can correctly assert "hit" and also request to memory
|
102 |
|
|
// on a cache miss.
|
103 |
|
|
MDFFR #(1) r_if_ic_req_ff (clk, rst, 1'b0, if_ic_req, r_if_ic_req);
|
104 |
|
|
|
105 |
|
|
// If we get a cache miss and then a flush happens, need to make sure that instruction
|
106 |
|
|
// coming back isn't sent down the pipe.
|
107 |
|
|
wire rob_pipe_flush_seen, rob_pipe_flush_seen_in;
|
108 |
|
|
assign rob_pipe_flush_seen_in = rob_pipe_flush_seen ? ~bus2ic_valid : rob_pipe_flush & (ic_state != IC_STATE_IDLE);
|
109 |
|
|
MDFFR #(1) rob_pipe_flush_seen_ff (clk, rst, 1'b0, rob_pipe_flush_seen_in, rob_pipe_flush_seen);
|
110 |
|
|
|
111 |
|
|
// Handle interface to Data and Tag SRAMs
|
112 |
|
|
`ifdef USE_IC
|
113 |
|
|
assign ic_do_init = (ic_state == IC_STATE_INIT);
|
114 |
|
|
assign ic_dataram_wren = ic_do_init || (bus2ic_valid & !rob_pipe_flush_seen);
|
115 |
|
|
assign ic_dataram_wr_data = ic_do_init ? {`IC_LINE_SZ{1'b0}} : bus2ic_data;
|
116 |
|
|
assign ic_dataram_addr = (ic_state == IC_STATE_INIT) ? ic_init_ctr[`IC_SI] :
|
117 |
|
|
(ic_state == IC_STATE_WAIT) ? ic2bus_fpc[`IC_SI] :
|
118 |
|
|
if_ic_fpc[`IC_SI];
|
119 |
|
|
|
120 |
|
|
assign ic_tagram_wren = ic_do_init || (bus2ic_valid & !rob_pipe_flush_seen);
|
121 |
|
|
assign ic_tagram_wr_data = ic_do_init ? {`IC_TAGRAM_SZ{1'b0}} : {1'b1, 1'b0, ic2bus_fpc[`IC_TAG]};
|
122 |
|
|
assign ic_tagram_addr = (ic_state == IC_STATE_INIT) ? ic_init_ctr[`IC_SI] :
|
123 |
|
|
(ic_state == IC_STATE_WAIT) ? ic2bus_fpc[`IC_SI] :
|
124 |
|
|
if_ic_fpc[`IC_SI];
|
125 |
|
|
`else
|
126 |
|
|
// If not including Icache, then just zero cache inputs out
|
127 |
|
|
assign ic_do_init = 1'b0;
|
128 |
|
|
assign ic_dataram_wren = 1'b0;
|
129 |
|
|
assign ic_dataram_wr_data = {`IC_LINE_SZ{1'b0}};
|
130 |
|
|
assign ic_dataram_addr = {`IC_SI_SZ{1'b0}};
|
131 |
|
|
|
132 |
|
|
assign ic_tagram_wren = 1'b0;
|
133 |
|
|
assign ic_tagram_wr_data = {`IC_LINE_SZ{1'b0}};
|
134 |
|
|
assign ic_tagram_addr = {`IC_SI_SZ{1'b0}};
|
135 |
|
|
`endif
|
136 |
|
|
|
137 |
|
|
// Handle tag comparison and IF interface
|
138 |
|
|
// Note: ic_if_ready just means we've initialized SRAMs. This will block
|
139 |
|
|
// IF requests and stall the pipeline on startup.
|
140 |
|
|
`ifdef USE_IC
|
141 |
|
|
assign ic_tag = ic_tagram_data[`IC_TAGRAM_TAG];
|
142 |
|
|
assign ic_tag_valid = ic_tagram_data[`IC_TAGRAM_VLD];
|
143 |
|
|
assign ic_tag_match = (ic_tag == r_if_ic_fpc[`IC_TAG]);
|
144 |
|
|
assign ic_cache_hit = ic_tag_match & (r_if_ic_req & ic_tag_valid & cp0_ic_enable & ic_initialized & !rob_pipe_flush_seen);
|
145 |
|
|
assign ic_if_ready = ic_initialized & (ic_nstate == IC_STATE_IDLE);
|
146 |
|
|
assign ic_if_data = r_if_ic_fpc[2] ? ic_dataram_data[63:32] : ic_dataram_data[31:0];
|
147 |
|
|
assign ic_if_data_valid = ic_cache_hit;
|
148 |
|
|
`else
|
149 |
|
|
// If not including Icache, then need to force everything as a cache miss and only return bus2ic_data
|
150 |
|
|
assign ic_tag = {`IC_TAG_SZ{1'b0}};
|
151 |
|
|
assign ic_tag_valid = 1'b0;
|
152 |
|
|
assign ic_tag_match = 1'b0;
|
153 |
|
|
assign ic_cache_hit = bus2ic_valid & !rob_pipe_flush_seen;
|
154 |
|
|
assign ic_if_ready = 1'b1; // No need to initialize cache
|
155 |
|
|
assign ic_if_data = r_if_ic_fpc[2] ? bus2ic_data[63:32] : bus2ic_data[31:0];
|
156 |
|
|
assign ic_if_data_valid = ic_cache_hit;
|
157 |
|
|
|
158 |
|
|
`endif
|
159 |
|
|
|
160 |
|
|
|
161 |
|
|
// Icache state machine
|
162 |
|
|
always @*
|
163 |
|
|
case (ic_state)
|
164 |
|
|
// From the IDLE state
|
165 |
|
|
// + move to req if we detect a miss
|
166 |
|
|
IC_STATE_IDLE: begin
|
167 |
|
|
if (r_if_ic_req & !ic_cache_hit)
|
168 |
|
|
ic_nstate = IC_STATE_REQ;
|
169 |
|
|
else
|
170 |
|
|
ic_nstate = IC_STATE_IDLE;
|
171 |
|
|
end
|
172 |
|
|
|
173 |
|
|
// In the REQ state we send the request to memory for the needed data.
|
174 |
|
|
// Then transition to WAIT state to wait for memory response
|
175 |
|
|
// TODO: Need to stall here if arbiter doesn't accept our request
|
176 |
|
|
IC_STATE_REQ: begin
|
177 |
|
|
ic_nstate = IC_STATE_WAIT;
|
178 |
|
|
end
|
179 |
|
|
|
180 |
|
|
// In the WAIT state we wait for memory response, then transition to
|
181 |
|
|
// WR_RAM state to write the data.
|
182 |
|
|
IC_STATE_WAIT: begin
|
183 |
|
|
if (bus2ic_valid) ic_nstate = IC_STATE_IDLE;
|
184 |
|
|
else ic_nstate = IC_STATE_WAIT;
|
185 |
|
|
end
|
186 |
|
|
|
187 |
|
|
// From the INIT state, we initialize each line of the cache to invalid
|
188 |
|
|
// and transition to IDLE after writing each line.
|
189 |
|
|
IC_STATE_INIT: begin
|
190 |
|
|
if (ic_init_ctr == `IC_NUM_LINES-1)
|
191 |
|
|
ic_nstate = IC_STATE_IDLE;
|
192 |
|
|
else
|
193 |
|
|
ic_nstate = IC_STATE_INIT;
|
194 |
|
|
end
|
195 |
|
|
|
196 |
|
|
default: ic_nstate = IC_STATE_IDLE;
|
197 |
|
|
endcase
|
198 |
|
|
|
199 |
|
|
// For the initialization, just loop through every set in cache and write it as invalid. When done
|
200 |
|
|
// set ic_initialized.
|
201 |
|
|
`ifdef USE_IC
|
202 |
|
|
assign ic_init_done = (ic_state == IC_STATE_INIT) & (ic_init_ctr == `IC_NUM_LINES-1);
|
203 |
|
|
assign ic_initialized_ld = ic_init_done;
|
204 |
|
|
assign ic_init_nctr = ic_init_ctr + `IC_SI_SZ'h1;
|
205 |
|
|
`else
|
206 |
|
|
assign ic_init_done = 1'b1;
|
207 |
|
|
assign ic_initialized_ld = 1'b0;
|
208 |
|
|
assign ic_init_nctr = {`IC_SI_SZ{1'b0}};
|
209 |
|
|
`endif
|
210 |
|
|
|
211 |
|
|
MDFFR #(3) ic_state_ff (clk, rst, IC_STATE_INIT, ic_nstate, ic_state);
|
212 |
|
|
MDFFLR #(`IC_SI_SZ) ic_init_ctr_ff (clk, rst, (ic_state == IC_STATE_INIT), `IC_SI_SZ'h0, ic_init_nctr, ic_init_ctr);
|
213 |
|
|
MDFFLR #(1) ic_initialized_ff (clk, rst, ic_initialized_ld, 1'b0, 1'b1, ic_initialized);
|
214 |
|
|
|
215 |
|
|
// Handle memory request outputs
|
216 |
|
|
// Note that we request from the bus the cycle after detecting a hit, so if_ic_fpc should be corrected from miss already.
|
217 |
|
|
assign ic2bus_fpc = if_ic_fpc;
|
218 |
|
|
assign ic2bus_req = (ic_state == IC_STATE_REQ);
|
219 |
|
|
|
220 |
|
|
endmodule
|