Added optional SR[CY]. Added define to enable additional (compare) flag modifiers...
[or1200.git] / rtl / verilog / or1200_alu.v
blob5aa9de5410c337bcfeefa32071757d24a52d5e3d
1 //////////////////////////////////////////////////////////////////////
2 //// ////
3 //// OR1200's ALU ////
4 //// ////
5 //// This file is part of the OpenRISC 1200 project ////
6 //// http://www.opencores.org/cores/or1k/ ////
7 //// ////
8 //// Description ////
9 //// ALU ////
10 //// ////
11 //// To Do: ////
12 //// - make it smaller and faster ////
13 //// ////
14 //// Author(s): ////
15 //// - Damjan Lampret, lampret@opencores.org ////
16 //// ////
17 //////////////////////////////////////////////////////////////////////
18 //// ////
19 //// Copyright (C) 2000 Authors and OPENCORES.ORG ////
20 //// ////
21 //// This source file may be used and distributed without ////
22 //// restriction provided that this copyright statement is not ////
23 //// removed from the file and that any derivative work contains ////
24 //// the original copyright notice and the associated disclaimer. ////
25 //// ////
26 //// This source file is free software; you can redistribute it ////
27 //// and/or modify it under the terms of the GNU Lesser General ////
28 //// Public License as published by the Free Software Foundation; ////
29 //// either version 2.1 of the License, or (at your option) any ////
30 //// later version. ////
31 //// ////
32 //// This source is distributed in the hope that it will be ////
33 //// useful, but WITHOUT ANY WARRANTY; without even the implied ////
34 //// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ////
35 //// PURPOSE. See the GNU Lesser General Public License for more ////
36 //// details. ////
37 //// ////
38 //// You should have received a copy of the GNU Lesser General ////
39 //// Public License along with this source; if not, download it ////
40 //// from http://www.opencores.org/lgpl.shtml ////
41 //// ////
42 //////////////////////////////////////////////////////////////////////
44 // CVS Revision History
46 // $Log$
47 // Revision 1.8 2002/09/07 05:42:02 lampret
48 // Added optional SR[CY]. Added define to enable additional (compare) flag modifiers. Defines are OR1200_IMPL_ADDC and OR1200_ADDITIONAL_FLAG_MODIFIERS.
50 // Revision 1.7 2002/09/03 22:28:21 lampret
51 // As per Taylor Su suggestion all case blocks are full case by default and optionally (OR1200_CASE_DEFAULT) can be disabled to increase clock frequncy.
53 // Revision 1.6 2002/03/29 16:40:10 lampret
54 // Added a directive to ignore signed division variables that are only used in simulation.
56 // Revision 1.5 2002/03/29 16:33:59 lampret
57 // Added again just recently removed full_case directive
59 // Revision 1.4 2002/03/29 15:16:53 lampret
60 // Some of the warnings fixed.
62 // Revision 1.3 2002/01/28 01:15:59 lampret
63 // Changed 'void' nop-ops instead of insn[0] to use insn[16]. Debug unit stalls the tick timer. Prepared new flag generation for add and and insns. Blocked DC/IC while they are turned off. Fixed I/D MMU SPRs layout except WAYs. TODO: smart IC invalidate, l.j 2 and TLB ways.
65 // Revision 1.2 2002/01/14 06:18:22 lampret
66 // Fixed mem2reg bug in FAST implementation. Updated debug unit to work with new genpc/if.
68 // Revision 1.1 2002/01/03 08:16:15 lampret
69 // New prefixes for RTL files, prefixed module names. Updated cache controllers and MMUs.
71 // Revision 1.10 2001/11/12 01:45:40 lampret
72 // Moved flag bit into SR. Changed RF enable from constant enable to dynamic enable for read ports.
74 // Revision 1.9 2001/10/21 17:57:16 lampret
75 // Removed params from generic_XX.v. Added translate_off/on in sprs.v and id.v. Removed spr_addr from dc.v and ic.v. Fixed CR+LF.
77 // Revision 1.8 2001/10/19 23:28:45 lampret
78 // Fixed some synthesis warnings. Configured with caches and MMUs.
80 // Revision 1.7 2001/10/14 13:12:09 lampret
81 // MP3 version.
83 // Revision 1.1.1.1 2001/10/06 10:18:35 igorm
84 // no message
86 // Revision 1.2 2001/08/09 13:39:33 lampret
87 // Major clean-up.
89 // Revision 1.1 2001/07/20 00:46:03 lampret
90 // Development version of RTL. Libraries are missing.
94 // synopsys translate_off
95 `include "timescale.v"
96 // synopsys translate_on
97 `include "or1200_defines.v"
99 module or1200_alu(
100 a, b, mult_mac_result, macrc_op,
101 alu_op, shrot_op, comp_op,
102 result, flagforw, flag_we,
103 cyforw, cy_we, carry
106 parameter width = `OR1200_OPERAND_WIDTH;
109 // I/O
111 input [width-1:0] a;
112 input [width-1:0] b;
113 input [width-1:0] mult_mac_result;
114 input macrc_op;
115 input [`OR1200_ALUOP_WIDTH-1:0] alu_op;
116 input [`OR1200_SHROTOP_WIDTH-1:0] shrot_op;
117 input [`OR1200_COMPOP_WIDTH-1:0] comp_op;
118 output [width-1:0] result;
119 output flagforw;
120 output flag_we;
121 output cyforw;
122 output cy_we;
123 input carry;
126 // Internal wires and regs
128 reg [width-1:0] result;
129 reg [width-1:0] shifted_rotated;
130 reg flagforw;
131 reg flagcomp;
132 reg flag_we;
133 reg cy_we;
134 // synopsys translate_off
135 `ifdef OR1200_SIM_ALU_DIV
136 integer d1;
137 integer d2;
138 `endif
139 // synopsys translate_on
140 wire [width-1:0] comp_a;
141 wire [width-1:0] comp_b;
142 `ifdef OR1200_IMPL_ALU_COMP1
143 wire a_eq_b;
144 wire a_lt_b;
145 `endif
146 wire [width-1:0] result_sum;
147 `ifdef OR1200_IMPL_ADDC
148 wire [width-1:0] result_csum;
149 `endif
150 wire [width-1:0] result_and;
151 wire cyforw;
154 // Combinatorial logic
156 assign comp_a = {a[width-1] ^ comp_op[3] , a[width-2:0]};
157 assign comp_b = {b[width-1] ^ comp_op[3] , b[width-2:0]};
158 `ifdef OR1200_IMPL_ALU_COMP1
159 assign a_eq_b = (comp_a == comp_b);
160 assign a_lt_b = (comp_a < comp_b);
161 `endif
162 assign {cyforw, result_sum} = a + b;
163 `ifdef OR1200_IMPL_ADDC
164 assign {cyforw, result_csum} = a + b + carry;
165 `endif
166 assign result_and = a & b;
169 // Simulation check for bad ALU behavior
171 `ifdef OR1200_WARNINGS
172 // synopsys translate_off
173 always @(result) begin
174 if (result === 32'bx)
175 $display("%t: WARNING: 32'bx detected on ALU result bus. Please check !", $time);
177 // synopsys translate_on
178 `endif
181 // Central part of the ALU
183 always @(alu_op or a or b or result_sum or result_and or macrc_op or shifted_rotated or mult_mac_result) begin
184 `ifdef OR1200_CASE_DEFAULT
185 casex (alu_op) // synopsys parallel_case
186 `else
187 casex (alu_op) // synopsys full_case parallel_case
188 `endif
189 `OR1200_ALUOP_SHROT : begin
190 result = shifted_rotated;
192 `OR1200_ALUOP_ADD : begin
193 result = result_sum;
195 `ifdef OR1200_IMPL_ADDC
196 `OR1200_ALUOP_ADDC : begin
197 result = result_csum;
199 `endif
200 `OR1200_ALUOP_SUB : begin
201 result = a - b;
203 `OR1200_ALUOP_XOR : begin
204 result = a ^ b;
206 `OR1200_ALUOP_OR : begin
207 result = a | b;
209 `OR1200_ALUOP_IMM : begin
210 result = b;
212 `OR1200_ALUOP_MOVHI : begin
213 if (macrc_op) begin
214 result = mult_mac_result;
216 else begin
217 result = b << 16;
220 `OR1200_ALUOP_MUL : begin
221 result = mult_mac_result;
222 `ifdef OR1200_VERBOSE
223 // synopsys translate_off
224 $display("%t: MUL operation: %h * %h = %h", $time, a, b, mult_mac_result);
225 // synopsys translate_on
226 `endif
228 // synopsys translate_off
229 `ifdef OR1200_SIM_ALU_DIV
230 `OR1200_ALUOP_DIV : begin
231 d1 = a;
232 d2 = b;
233 $display("DIV operation: %d / %d = %d", d1, d2, d1/d2);
234 if (d2)
235 result = d1 / d2;
236 else
237 result = 32'h00000000;
239 `endif
240 `ifdef OR1200_SIM_ALU_DIVU
241 `OR1200_ALUOP_DIVU : begin
242 if (b)
243 result = a / b;
244 else
245 result = 32'h00000000;
247 `endif
248 // synopsys translate_on
249 `ifdef OR1200_CASE_DEFAULT
250 default: begin
251 `else
252 `OR1200_ALUOP_COMP, `OR1200_ALUOP_AND
253 `endif
254 result = result_and;
256 endcase
260 // Generate flag and flag write enable
262 always @(alu_op or result_sum or result_and or flagcomp) begin
263 casex (alu_op) // synopsys parallel_case
264 `ifdef OR1200_ADDITIONAL_FLAG_MODIFIERS
265 `OR1200_ALUOP_ADD : begin
266 flagforw = (result_sum == 32'h0000_0000);
267 flag_we = 1'b1;
269 `ifdef OR1200_IMPL_ADDC
270 `OR1200_ALUOP_ADDC : begin
271 flagforw = (result_csum == 32'h0000_0000);
272 flag_we = 1'b1;
274 `endif
275 `OR1200_ALUOP_AND: begin
276 flagforw = (result_and == 32'h0000_0000);
277 flag_we = 1'b1;
279 `endif
280 `OR1200_ALUOP_COMP: begin
281 flagforw = flagcomp;
282 flag_we = 1'b1;
284 default: begin
285 flagforw = 1'b0;
286 flag_we = 1'b0;
288 endcase
292 // Generate SR[CY] write enable
294 always @(alu_op) begin
295 casex (alu_op) // synopsys parallel_case
296 `ifdef OR1200_IMPL_ADDC
297 `OR1200_ALUOP_ADDC : begin
298 cy_we = 1'b1;
300 `endif
301 default: begin
302 cy_we = 1'b0;
304 endcase
308 // Shifts and rotation
310 always @(shrot_op or a or b) begin
311 case (shrot_op) // synopsys parallel_case
312 `OR1200_SHROTOP_SLL :
313 shifted_rotated = (a << b[4:0]);
314 `OR1200_SHROTOP_SRL :
315 shifted_rotated = (a >> b[4:0]);
317 `ifdef OR1200_IMPL_ALU_ROTATE
318 `OR1200_SHROTOP_ROR :
319 shifted_rotated = (a << (6'd32-{1'b0, b[4:0]})) | (a >> b[4:0]);
320 `endif
321 default:
322 shifted_rotated = ({32{a[31]}} << (6'd32-{1'b0, b[4:0]})) | a >> b[4:0];
323 endcase
327 // First type of compare implementation
329 `ifdef OR1200_IMPL_ALU_COMP1
330 always @(comp_op or a_eq_b or a_lt_b) begin
331 case(comp_op[2:0]) // synopsys parallel_case
332 `OR1200_COP_SFEQ:
333 flagcomp = a_eq_b;
334 `OR1200_COP_SFNE:
335 flagcomp = ~a_eq_b;
336 `OR1200_COP_SFGT:
337 flagcomp = ~(a_eq_b | a_lt_b);
338 `OR1200_COP_SFGE:
339 flagcomp = ~a_lt_b;
340 `OR1200_COP_SFLT:
341 flagcomp = a_lt_b;
342 `OR1200_COP_SFLE:
343 flagcomp = a_eq_b | a_lt_b;
344 default:
345 flagcomp = 1'b0;
346 endcase
348 `endif
351 // Second type of compare implementation
353 `ifdef OR1200_IMPL_ALU_COMP2
354 always @(comp_op or comp_a or comp_b) begin
355 case(comp_op[2:0]) // synopsys parallel_case
356 `OR1200_COP_SFEQ:
357 flagcomp = (comp_a == comp_b);
358 `OR1200_COP_SFNE:
359 flagcomp = (comp_a != comp_b);
360 `OR1200_COP_SFGT:
361 flagcomp = (comp_a > comp_b);
362 `OR1200_COP_SFGE:
363 flagcomp = (comp_a >= comp_b);
364 `OR1200_COP_SFLT:
365 flagcomp = (comp_a < comp_b);
366 `OR1200_COP_SFLE:
367 flagcomp = (comp_a <= comp_b);
368 default:
369 flagcomp = 1'b0;
370 endcase
372 `endif
374 endmodule