1 |
2 |
smjoshua |
//////////////////////////////////////////////////////////////////
|
2 |
|
|
// //
|
3 |
|
|
// OoOPs Core Instruction Fetch module //
|
4 |
|
|
// //
|
5 |
|
|
// This file is part of the OoOPs project //
|
6 |
|
|
// http://www.opencores.org/project,oops //
|
7 |
|
|
// //
|
8 |
|
|
// Description: //
|
9 |
|
|
// Handles updating Program Counter and fetching instructions //
|
10 |
|
|
// from the Instruction Cache. //
|
11 |
|
|
// //
|
12 |
|
|
// Author(s): //
|
13 |
|
|
// - Joshua Smith, smjoshua@umich.edu //
|
14 |
|
|
// //
|
15 |
|
|
//////////////////////////////////////////////////////////////////
|
16 |
|
|
// //
|
17 |
|
|
// Copyright (C) 2012 Authors and OPENCORES.ORG //
|
18 |
|
|
// //
|
19 |
|
|
// This source file may be used and distributed without //
|
20 |
|
|
// restriction provided that this copyright statement is not //
|
21 |
|
|
// removed from the file and that any derivative work contains //
|
22 |
|
|
// the original copyright notice and the associated disclaimer. //
|
23 |
|
|
// //
|
24 |
|
|
// This source file is free software; you can redistribute it //
|
25 |
|
|
// and/or modify it under the terms of the GNU Lesser General //
|
26 |
|
|
// Public License as published by the Free Software Foundation; //
|
27 |
|
|
// either version 2.1 of the License, or (at your option) any //
|
28 |
|
|
// later version. //
|
29 |
|
|
// //
|
30 |
|
|
// This source is distributed in the hope that it will be //
|
31 |
|
|
// useful, but WITHOUT ANY WARRANTY; without even the implied //
|
32 |
|
|
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //
|
33 |
|
|
// PURPOSE. See the GNU Lesser General Public License for more //
|
34 |
|
|
// details. //
|
35 |
|
|
// //
|
36 |
|
|
// You should have received a copy of the GNU Lesser General //
|
37 |
|
|
// Public License along with this source; if not, download it //
|
38 |
|
|
// from http://www.opencores.org/lgpl.shtml //
|
39 |
|
|
// //
|
40 |
|
|
//////////////////////////////////////////////////////////////////
|
41 |
|
|
`include "ooops_defs.v"
|
42 |
|
|
|
43 |
|
|
module if_stage (
|
44 |
|
|
input wire clk,
|
45 |
|
|
input wire rst,
|
46 |
|
|
|
47 |
|
|
// Flush/stall interfaces
|
48 |
|
|
input wire rob_pipe_flush,
|
49 |
|
|
input wire [`ADDR_SZ-1:0] rob_flush_target,
|
50 |
|
|
input wire ds_stall,
|
51 |
|
|
|
52 |
|
|
// Instruction cache interface
|
53 |
|
|
output wire if_ic_req,
|
54 |
|
|
output wire [`ADDR_SZ-1:0] if_ic_fpc,
|
55 |
|
|
output wire [`ADDR_SZ-1:0] r_if_ic_fpc,
|
56 |
|
|
input wire [`INSTR_SZ-1:0] ic_if_data,
|
57 |
|
|
input wire ic_if_data_valid,
|
58 |
|
|
input wire ic_if_ready,
|
59 |
|
|
|
60 |
|
|
// Interface to ID stage
|
61 |
|
|
output wire if_id_valid,
|
62 |
|
|
output wire [`INSTR_SZ-1:0] if_id_instr,
|
63 |
|
|
output wire [`ADDR_SZ-1:0] if_id_fpc,
|
64 |
|
|
output wire [`BP_SZ-1:0] if_id_bprd_info
|
65 |
|
|
);
|
66 |
|
|
|
67 |
|
|
// Internal wires/regs
|
68 |
|
|
wire if_stall;
|
69 |
|
|
wire if_valid;
|
70 |
|
|
wire [`ADDR_SZ-1:0] if_fpc; // Current fetch pc
|
71 |
|
|
wire [`ADDR_SZ-1:0] r_if_fpc; // flopped FPC
|
72 |
|
|
wire [`ADDR_SZ-1:0] r_if_fpc_in;
|
73 |
|
|
wire [`INSTR_SZ-1:0] if_instr;
|
74 |
|
|
wire [`BP_SZ-1:0] if_bprd_info;
|
75 |
|
|
wire if_br_predict_valid;
|
76 |
|
|
wire if_br_predict_taken;
|
77 |
|
|
wire [`ADDR_SZ-1:0] if_br_predict_target;
|
78 |
|
|
|
79 |
|
|
// Note that Icache will have 1 cycle latency, so we won't know if it's a miss until
|
80 |
|
|
// one cycle later. Since we don't want to have to wait to figure out if it's a hit
|
81 |
|
|
// before we increment the FPC (want to be optimistic), we'll have to be able to reset
|
82 |
|
|
// the FPC if it's a miss.
|
83 |
|
|
assign if_ic_req = !if_stall;
|
84 |
|
|
assign if_ic_fpc = if_fpc;
|
85 |
|
|
assign r_if_ic_fpc = r_if_fpc;
|
86 |
|
|
assign if_valid = ic_if_data_valid & !rob_pipe_flush;
|
87 |
|
|
assign if_instr = ic_if_data;
|
88 |
|
|
|
89 |
|
|
// Handle the FPC generation
|
90 |
|
|
wire [`ADDR_SZ-1:0] if_fpc_p4 = if_fpc + `ADDR_SZ'h4;
|
91 |
|
|
reg [`ADDR_SZ-1:0] if_fpc_in;
|
92 |
|
|
always @* begin
|
93 |
|
|
casez({rob_pipe_flush, if_br_predict_taken, !ic_if_ready})
|
94 |
|
|
3'b1??: if_fpc_in = rob_flush_target; // Flush target
|
95 |
|
|
3'b01?: if_fpc_in = if_br_predict_target; // Taken branch target
|
96 |
|
|
3'b001: if_fpc_in = r_if_fpc; // Previous FPC
|
97 |
|
|
default: if_fpc_in = if_fpc_p4; // Next incrmented FPC
|
98 |
|
|
endcase
|
99 |
|
|
end
|
100 |
|
|
|
101 |
|
|
MDFFLR #(`ADDR_SZ) if_fpc_ff (clk, rst, if_ic_req, `RESET_ADDR, if_fpc_in, if_fpc);
|
102 |
|
|
|
103 |
|
|
// Flop Icache request signals so we can re-request if it ends up being a miss
|
104 |
|
|
assign r_if_fpc_in = rob_pipe_flush ? rob_flush_target : if_ic_fpc;
|
105 |
|
|
MDFFR #(`ADDR_SZ) r_if_fpc_ff (clk, rst, `RESET_ADDR, if_fpc, r_if_fpc);
|
106 |
|
|
|
107 |
|
|
// Handle branch prediction
|
108 |
|
|
// TODO: throw in branch prediction
|
109 |
|
|
// Note: Try to identify jumps and other unconditional branches here, for quick recovery
|
110 |
|
|
`ifdef DYN_BPRD
|
111 |
|
|
assign if_br_predict_valid = 1'b0;
|
112 |
|
|
assign if_br_predict_taken = 1'b0;
|
113 |
|
|
assign if_br_predict_target = {`ADDR_SZ{1'b0}};
|
114 |
|
|
assign if_bprd_info = {if_br_predict_target, if_br_predict_taken, if_br_predict_valid};
|
115 |
|
|
`else
|
116 |
|
|
// tie-offs should optimize logic away
|
117 |
|
|
assign if_br_predict_valid = 1'b0;
|
118 |
|
|
assign if_br_predict_taken = 1'b0;
|
119 |
|
|
assign if_br_predict_target = {`ADDR_SZ{1'b0}};
|
120 |
|
|
assign if_bprd_info = {if_br_predict_target, if_br_predict_taken, if_br_predict_valid};
|
121 |
|
|
`endif
|
122 |
|
|
|
123 |
|
|
`ifdef USE_IFB
|
124 |
|
|
wire ifb_full;
|
125 |
|
|
if_buffer ifb (
|
126 |
|
|
.clk(clk),
|
127 |
|
|
.rst(rst),
|
128 |
|
|
.flush(rob_pipe_flush),
|
129 |
|
|
.if_valid(if_valid),
|
130 |
|
|
.if_instr(if_instr),
|
131 |
|
|
.if_fpc(if_fpc),
|
132 |
|
|
.if_bprd_info(if_bprd_info),
|
133 |
|
|
.if_ifb_pop_en(!ds_stall),
|
134 |
|
|
.ifb_full(ifb_full),
|
135 |
|
|
.if_id_valid(if_id_valid),
|
136 |
|
|
.if_id_instr(if_id_instr),
|
137 |
|
|
.if_id_fpc(if_id_fpc),
|
138 |
|
|
.if_id_bprd_info(if_id_bprd_info)
|
139 |
|
|
);
|
140 |
|
|
|
141 |
|
|
assign if_stall = ifb_full; // Only stall if IFB is full
|
142 |
|
|
`else
|
143 |
|
|
|
144 |
|
|
MDFFLR #(1) if_id_valid_ff (clk, rst, !if_stall, 1'b0, if_valid, if_id_valid);
|
145 |
|
|
MDFFL #(`INSTR_SZ) if_id_instr_ff (clk, !if_stall, if_instr, if_id_instr);
|
146 |
|
|
MDFFL #(`ADDR_SZ) if_id_fpc_ff (clk, !if_stall, if_ic_fpc_q, if_id_fpc);
|
147 |
|
|
MDFFL #(`BP_SZ) if_id_bprd_info_ff (clk, if_valid, if_bprd_info, if_id_bprd_info);
|
148 |
|
|
|
149 |
|
|
assign if_stall = if_id_valid & ds_stall; // Stall if we have a valid instruction going to ID and DS stalling
|
150 |
|
|
|
151 |
|
|
`endif // USE_IFB
|
152 |
|
|
endmodule
|