1 |
2 |
dmitryr |
// ========== Copyright Header Begin ==========================================
|
2 |
|
|
//
|
3 |
|
|
// OpenSPARC T1 Processor File: sparc_exu_ecl_mdqctl.v
|
4 |
|
|
// Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
|
5 |
|
|
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
|
6 |
|
|
//
|
7 |
|
|
// The above named program is free software; you can redistribute it and/or
|
8 |
|
|
// modify it under the terms of the GNU General Public
|
9 |
|
|
// License version 2 as published by the Free Software Foundation.
|
10 |
|
|
//
|
11 |
|
|
// The above named program is distributed in the hope that it will be
|
12 |
|
|
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 |
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
14 |
|
|
// General Public License for more details.
|
15 |
|
|
//
|
16 |
|
|
// You should have received a copy of the GNU General Public
|
17 |
|
|
// License along with this work; if not, write to the Free Software
|
18 |
|
|
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
19 |
|
|
//
|
20 |
|
|
// ========== Copyright Header End ============================================
|
21 |
|
|
////////////////////////////////////////////////////////////////////////
|
22 |
|
|
/*
|
23 |
|
|
// Module Name: sparc_exu_ecl_mdqctl
|
24 |
|
|
// Description: This block is the control logic for the multiply/divide
|
25 |
|
|
// input buffer. It generates the select lines for both the output
|
26 |
|
|
// to mul and div, as well as for moving the data within the buffer.
|
27 |
|
|
// There are 4 slots in the buffer, which is a modified FIFO.
|
28 |
|
|
// It will output 1 MUL and 1 DIV every cycle, as well as whether those
|
29 |
|
|
// outputs are valid. If none of the slots contain a valid entry, it
|
30 |
|
|
// will pass through the input to the output. If a kill comes through
|
31 |
|
|
// and invalidates an entry, it will show up on the valid bit coming out
|
32 |
|
|
// of the mdq, but may cause a lost cycle as the kill won't affect the logic
|
33 |
|
|
// which chooses the output until the next cycle. The block also
|
34 |
|
|
// stores the thr, rd, setcc and other control bits for each entry.
|
35 |
|
|
*/
|
36 |
|
|
|
37 |
|
|
`define MULS 10
|
38 |
|
|
`define IS64 9
|
39 |
|
|
`define SIGNED 8
|
40 |
|
|
`define SET_CC 7
|
41 |
|
|
|
42 |
|
|
module sparc_exu_ecl_mdqctl (/*AUTOARG*/
|
43 |
|
|
// Outputs
|
44 |
|
|
mdqctl_divcntl_input_vld, mdqctl_divcntl_reset_div,
|
45 |
|
|
mdqctl_divcntl_muldone, ecl_div_div64, ecl_div_signed_div,
|
46 |
|
|
ecl_div_muls, mdqctl_wb_divthr_g, mdqctl_wb_divrd_g,
|
47 |
|
|
mdqctl_wb_multhr_g, mdqctl_wb_mulrd_g, mdqctl_wb_divsetcc_g,
|
48 |
|
|
mdqctl_wb_mulsetcc_g, mdqctl_wb_yreg_shift_g, exu_mul_input_vld,
|
49 |
|
|
mdqctl_wb_yreg_wen_g, ecl_div_mul_sext_rs1_e,
|
50 |
|
|
ecl_div_mul_sext_rs2_e, ecl_div_mul_get_new_data,
|
51 |
|
|
ecl_div_mul_keep_data, ecl_div_mul_get_32bit_data,
|
52 |
|
|
ecl_div_mul_wen, div_zero_m,
|
53 |
|
|
// Inputs
|
54 |
|
|
clk, se, reset, ifu_exu_muldivop_d, tid_d, ifu_exu_rd_d, tid_w1,
|
55 |
|
|
flush_w1, ifu_exu_inst_vld_w, wb_divcntl_ack_g, divcntl_wb_req_g,
|
56 |
|
|
byp_alu_rs1_data_31_e, byp_alu_rs2_data_31_e, mul_exu_ack,
|
57 |
|
|
ecl_div_sel_div, ifu_exu_muls_d, div_ecl_detect_zero_high,
|
58 |
|
|
div_ecl_detect_zero_low, ifu_tlu_flush_w, early_flush_w
|
59 |
|
|
) ;
|
60 |
|
|
input clk;
|
61 |
|
|
input se;
|
62 |
|
|
input reset;
|
63 |
|
|
input [4:0] ifu_exu_muldivop_d;
|
64 |
|
|
input [1:0] tid_d;
|
65 |
|
|
input [4:0] ifu_exu_rd_d;
|
66 |
|
|
input [1:0] tid_w1;
|
67 |
|
|
input flush_w1;
|
68 |
|
|
input ifu_exu_inst_vld_w;
|
69 |
|
|
input wb_divcntl_ack_g;
|
70 |
|
|
input divcntl_wb_req_g;
|
71 |
|
|
input byp_alu_rs1_data_31_e;
|
72 |
|
|
input byp_alu_rs2_data_31_e;
|
73 |
|
|
input mul_exu_ack;
|
74 |
|
|
input ecl_div_sel_div;
|
75 |
|
|
input ifu_exu_muls_d;
|
76 |
|
|
input div_ecl_detect_zero_high;
|
77 |
|
|
input div_ecl_detect_zero_low;
|
78 |
|
|
input ifu_tlu_flush_w;
|
79 |
|
|
input early_flush_w;
|
80 |
|
|
|
81 |
|
|
|
82 |
|
|
output mdqctl_divcntl_input_vld;
|
83 |
|
|
output mdqctl_divcntl_reset_div;
|
84 |
|
|
output mdqctl_divcntl_muldone;
|
85 |
|
|
output ecl_div_div64;
|
86 |
|
|
output ecl_div_signed_div;
|
87 |
|
|
output ecl_div_muls;
|
88 |
|
|
output [1:0] mdqctl_wb_divthr_g;
|
89 |
|
|
output [4:0] mdqctl_wb_divrd_g;
|
90 |
|
|
output [1:0] mdqctl_wb_multhr_g;
|
91 |
|
|
output [4:0] mdqctl_wb_mulrd_g;
|
92 |
|
|
output mdqctl_wb_divsetcc_g;
|
93 |
|
|
output mdqctl_wb_mulsetcc_g;
|
94 |
|
|
output mdqctl_wb_yreg_shift_g;
|
95 |
|
|
|
96 |
|
|
|
97 |
|
|
output exu_mul_input_vld;
|
98 |
|
|
output mdqctl_wb_yreg_wen_g;
|
99 |
|
|
output ecl_div_mul_sext_rs1_e;
|
100 |
|
|
output ecl_div_mul_sext_rs2_e;
|
101 |
|
|
output ecl_div_mul_get_new_data;
|
102 |
|
|
output ecl_div_mul_keep_data;
|
103 |
|
|
output ecl_div_mul_get_32bit_data;
|
104 |
|
|
output ecl_div_mul_wen;
|
105 |
|
|
output div_zero_m;
|
106 |
|
|
|
107 |
|
|
wire [11:0] div_data_next;
|
108 |
|
|
wire [11:0] div_data;
|
109 |
|
|
wire new_div_vld;
|
110 |
|
|
wire curr_div_vld;
|
111 |
|
|
wire [11:0] div_input_data_d;
|
112 |
|
|
wire [9:0] mul_input_data_d;
|
113 |
|
|
wire [9:0] mul_data;
|
114 |
|
|
wire [9:0] mul_data_next;
|
115 |
|
|
wire new_mul_d;
|
116 |
|
|
wire kill_thr_mul;
|
117 |
|
|
wire mul_kill;
|
118 |
|
|
wire invalid_mul_w;
|
119 |
|
|
wire div_kill;
|
120 |
|
|
wire kill_thr_div;
|
121 |
|
|
|
122 |
|
|
wire mul_ready_next;
|
123 |
|
|
wire mul_ready;
|
124 |
|
|
wire mul_done_valid_c0;
|
125 |
|
|
wire mul_done_valid_c1;
|
126 |
|
|
wire mul_done_ack;
|
127 |
|
|
wire mul_done_c0;
|
128 |
|
|
wire mul_done_c1;
|
129 |
|
|
wire mul_done_c2;
|
130 |
|
|
wire mul_done_c3;
|
131 |
|
|
|
132 |
|
|
wire isdiv_e_valid;
|
133 |
|
|
wire isdiv_m_valid;
|
134 |
|
|
wire ismul_e_valid;
|
135 |
|
|
wire ismul_m_valid;
|
136 |
|
|
wire isdiv_e;
|
137 |
|
|
wire isdiv_m;
|
138 |
|
|
wire isdiv_w;
|
139 |
|
|
wire ismul_e;
|
140 |
|
|
wire ismul_m;
|
141 |
|
|
wire ismul_w;
|
142 |
|
|
|
143 |
|
|
wire div_used;
|
144 |
|
|
wire invalid_div_w;
|
145 |
|
|
wire div_zero_e;
|
146 |
|
|
|
147 |
|
|
// Mul result state wires
|
148 |
|
|
wire go_mul_done;
|
149 |
|
|
wire stay_mul_done;
|
150 |
|
|
wire mul_done;
|
151 |
|
|
wire next_mul_done;
|
152 |
|
|
|
153 |
|
|
|
154 |
|
|
////////////////////////
|
155 |
|
|
// Divide output DATAPATH
|
156 |
|
|
////////////////////////
|
157 |
|
|
// store control signals
|
158 |
|
|
assign div_used = divcntl_wb_req_g & wb_divcntl_ack_g & ecl_div_sel_div;
|
159 |
|
|
|
160 |
|
|
assign new_div_vld = ifu_exu_muls_d | ifu_exu_muldivop_d[3];
|
161 |
|
|
|
162 |
|
|
assign div_input_data_d[11:0] = {1'b1, // isdiv
|
163 |
|
|
ifu_exu_muls_d,
|
164 |
|
|
ifu_exu_muldivop_d[2], // 64bit
|
165 |
|
|
ifu_exu_muldivop_d[1], // signed
|
166 |
|
|
ifu_exu_muldivop_d[0], // setcc
|
167 |
|
|
ifu_exu_rd_d[4:0],
|
168 |
|
|
tid_d[1:0]};
|
169 |
|
|
mux2ds #(12) div_data_mux(.dout(div_data_next[11:0]),
|
170 |
|
|
.in0({curr_div_vld, div_data[10:0]}),
|
171 |
|
|
.in1(div_input_data_d[11:0]),
|
172 |
|
|
.sel0(~new_div_vld),
|
173 |
|
|
.sel1(new_div_vld));
|
174 |
|
|
|
175 |
|
|
dffr_s #(12) div_data_dff(.din(div_data_next[11:0]), .clk(clk), .q(div_data[11:0]),
|
176 |
|
|
.se(se), .si(), .so(), .rst(reset));
|
177 |
|
|
|
178 |
|
|
//div kill logic (kills on div by zero exception or if there isn't an outstanding div)
|
179 |
|
|
assign div_zero_e = isdiv_e & div_ecl_detect_zero_high & div_ecl_detect_zero_low & ~div_data[`MULS];
|
180 |
|
|
assign invalid_div_w = isdiv_w & (~ifu_exu_inst_vld_w | ifu_tlu_flush_w | early_flush_w);
|
181 |
|
|
assign kill_thr_div = ~(div_data[1] ^ tid_w1[1]) & ~(div_data[0] ^ tid_w1[0]);
|
182 |
|
|
assign div_kill = (flush_w1 & kill_thr_div) | invalid_div_w | new_div_vld;
|
183 |
|
|
assign curr_div_vld = div_data[11] & ~div_zero_m & ~div_kill & ~div_used;
|
184 |
|
|
|
185 |
|
|
wire div_zero_unqual_m;
|
186 |
|
|
assign div_zero_m = div_zero_unqual_m & isdiv_m;
|
187 |
|
|
dff_s div_zero_e2m(.din(div_zero_e), .clk(clk), .q(div_zero_unqual_m), .se(se), .si(), .so());
|
188 |
|
|
|
189 |
|
|
// pipeling for divide valid signal (for inst_vld checking)
|
190 |
|
|
dff_s isdiv_d2e(.din(new_div_vld), .clk(clk), .q(isdiv_e),
|
191 |
|
|
.se(se), .si(), .so());
|
192 |
|
|
dff_s isdiv_e2m(.din(isdiv_e_valid), .clk(clk), .q(isdiv_m),
|
193 |
|
|
.se(se), .si(), .so());
|
194 |
|
|
dff_s isdiv_m2w(.din(isdiv_m_valid), .clk(clk), .q(isdiv_w),
|
195 |
|
|
.se(se), .si(), .so());
|
196 |
|
|
assign isdiv_e_valid = isdiv_e & ~div_kill;
|
197 |
|
|
assign isdiv_m_valid = isdiv_m & ~div_kill;
|
198 |
|
|
|
199 |
|
|
// control for div state machine
|
200 |
|
|
assign mdqctl_divcntl_reset_div = (~div_data[11] | div_kill);
|
201 |
|
|
assign mdqctl_divcntl_input_vld = isdiv_e;
|
202 |
|
|
|
203 |
|
|
// control signals for div
|
204 |
|
|
assign ecl_div_div64 = div_data[`IS64];
|
205 |
|
|
assign ecl_div_signed_div = div_data[`SIGNED];
|
206 |
|
|
assign ecl_div_muls = div_data[`MULS];
|
207 |
|
|
|
208 |
|
|
// control for writeback on completion
|
209 |
|
|
assign mdqctl_wb_divrd_g[4:0] = div_data[6:2];
|
210 |
|
|
assign mdqctl_wb_divthr_g[1:0] = div_data[1:0];
|
211 |
|
|
assign mdqctl_wb_divsetcc_g = div_data[`SET_CC] | div_data[`MULS];
|
212 |
|
|
assign mdqctl_wb_yreg_shift_g = div_used & div_data[`MULS];
|
213 |
|
|
|
214 |
|
|
|
215 |
|
|
////////////////////////////////////////////////////////////////////////////
|
216 |
|
|
// Multiply control
|
217 |
|
|
//----------------------
|
218 |
|
|
// The multiply will drop the current operation if a new request is issued.
|
219 |
|
|
// This requires addition checking to make sure that the kills are for the
|
220 |
|
|
// proper operation.
|
221 |
|
|
////////////////////////////////////////////////////////////////////////////
|
222 |
|
|
dff_s ismul_d2e(.din(ifu_exu_muldivop_d[4]), .clk(clk), .q(ismul_e),
|
223 |
|
|
.se(se), .si(), .so());
|
224 |
|
|
dff_s ismul_e2m(.din(ismul_e_valid), .clk(clk), .q(ismul_m),
|
225 |
|
|
.se(se), .si(), .so());
|
226 |
|
|
dff_s ismul_m2w(.din(ismul_m_valid), .clk(clk), .q(ismul_w),
|
227 |
|
|
.se(se), .si(), .so());
|
228 |
|
|
assign ismul_e_valid = ismul_e & ~mul_kill;
|
229 |
|
|
assign ismul_m_valid = ismul_m & ~mul_kill & ~ismul_e;
|
230 |
|
|
|
231 |
|
|
// store control signals
|
232 |
|
|
// assign mul_used = divcntl_wb_req_g & wb_divcntl_ack_g & ~ecl_div_sel_div;
|
233 |
|
|
assign new_mul_d = ifu_exu_muldivop_d[4];
|
234 |
|
|
|
235 |
|
|
assign mul_input_data_d[9:0] = {ifu_exu_muldivop_d[2], // 64bit
|
236 |
|
|
ifu_exu_muldivop_d[1], // signed
|
237 |
|
|
ifu_exu_muldivop_d[0], // setcc
|
238 |
|
|
ifu_exu_rd_d[4:0],
|
239 |
|
|
tid_d[1:0]};
|
240 |
|
|
assign mul_data_next[9:0] = (new_mul_d)? mul_input_data_d[9:0]: mul_data[9:0];
|
241 |
|
|
|
242 |
|
|
dff_s #(10) mul_data_dff(.din(mul_data_next[9:0]), .clk(clk), .q(mul_data[9:0]),
|
243 |
|
|
.se(se), .si(), .so());
|
244 |
|
|
|
245 |
|
|
// mul kill logic
|
246 |
|
|
assign kill_thr_mul = ~(mul_data[1] ^ tid_w1[1]) & ~(mul_data[0] ^ tid_w1[0]);
|
247 |
|
|
assign mul_kill = (flush_w1 & kill_thr_mul) | reset;
|
248 |
|
|
assign invalid_mul_w = ismul_w & ~ifu_exu_inst_vld_w;
|
249 |
|
|
|
250 |
|
|
// control signals for mul data in div unit
|
251 |
|
|
assign ecl_div_mul_keep_data = ~ismul_e;
|
252 |
|
|
assign ecl_div_mul_get_new_data = ismul_e & mul_data[`IS64];
|
253 |
|
|
assign ecl_div_mul_get_32bit_data = ismul_e & ~mul_data[`IS64];
|
254 |
|
|
assign ecl_div_mul_sext_rs1_e = byp_alu_rs1_data_31_e & mul_data[`SIGNED];
|
255 |
|
|
assign ecl_div_mul_sext_rs2_e = byp_alu_rs2_data_31_e & mul_data[`SIGNED];
|
256 |
|
|
|
257 |
|
|
// control for writeback on completion
|
258 |
|
|
assign mdqctl_wb_yreg_wen_g = ~mul_data[`IS64] & ecl_div_mul_wen;
|
259 |
|
|
assign mdqctl_wb_multhr_g[1:0] = mul_data[1:0];
|
260 |
|
|
assign mdqctl_wb_mulsetcc_g = mul_data[`SET_CC];
|
261 |
|
|
assign mdqctl_wb_mulrd_g[4:0] = mul_data[6:2];
|
262 |
|
|
|
263 |
|
|
// interface with mul and state of pending mul
|
264 |
|
|
assign mul_ready_next = ismul_e_valid | (mul_ready & ~mul_exu_ack & ~mul_kill & ~ismul_e & ~invalid_mul_w);
|
265 |
|
|
dff_s mul_ready_dff(.din(mul_ready_next), .clk(clk), .q(mul_ready), .se(se), .si(), .so());
|
266 |
|
|
|
267 |
|
|
assign exu_mul_input_vld = mul_ready;
|
268 |
|
|
|
269 |
|
|
// If there was a valid request and an ack then start passing down pipe
|
270 |
|
|
assign mul_done_ack = mul_ready & ~mul_kill & ~ismul_e & mul_exu_ack & ~invalid_mul_w;
|
271 |
|
|
dff_s dff_done_ack2c0(.din(mul_done_ack), .clk(clk), .q(mul_done_c0),
|
272 |
|
|
.se(se), .si(), .so());
|
273 |
|
|
// need to check here cause this could be w
|
274 |
|
|
assign mul_done_valid_c0 = mul_done_c0 & ~mul_kill & ~invalid_mul_w & ~ismul_e;
|
275 |
|
|
dff_s dff_done_c02c1(.din(mul_done_valid_c0), .clk(clk), .q(mul_done_c1),
|
276 |
|
|
.se(se), .si(), .so());
|
277 |
|
|
// need to check here cause this could be w1
|
278 |
|
|
assign mul_done_valid_c1 = mul_done_c1 & ~mul_kill & ~ismul_e;
|
279 |
|
|
dff_s dff_done_c1c2(.din(mul_done_valid_c1), .clk(clk), .q(mul_done_c2),
|
280 |
|
|
.se(se), .si(), .so());
|
281 |
|
|
dff_s dff_done_c22c3(.din(mul_done_c2), .clk(clk), .q(mul_done_c3),
|
282 |
|
|
.se(se), .si(), .so());
|
283 |
|
|
dff_s dff_done_c32c4(.din(mul_done_c3), .clk(clk), .q(ecl_div_mul_wen),
|
284 |
|
|
.se(se), .si(), .so());
|
285 |
|
|
|
286 |
|
|
// Mul result state machine
|
287 |
|
|
assign go_mul_done = ~mul_done & ecl_div_mul_wen;
|
288 |
|
|
assign stay_mul_done = mul_done & (~wb_divcntl_ack_g | ecl_div_sel_div);
|
289 |
|
|
assign next_mul_done = ~reset & (go_mul_done | stay_mul_done);
|
290 |
|
|
|
291 |
|
|
assign mdqctl_divcntl_muldone = mul_done;
|
292 |
|
|
|
293 |
|
|
// mul state flop
|
294 |
|
|
dff_s mulstate_dff(.din(next_mul_done), .clk(clk), .q(mul_done), .se(se), .si(),
|
295 |
|
|
.so());
|
296 |
|
|
|
297 |
|
|
/////////////////////////////////////////
|
298 |
|
|
// Pipeline registers for control signals
|
299 |
|
|
/////////////////////////////////////////
|
300 |
|
|
|
301 |
|
|
|
302 |
|
|
endmodule // sparc_exu_ecl_mdqctl
|