1 //////////////////////////////////////////////////////////////////////
5 //// This file is part of the OpenRISC 1200 project ////
6 //// http://www.opencores.org/cores/or1k/ ////
12 //// - make it smaller and faster ////
15 //// - Damjan Lampret, lampret@opencores.org ////
17 //////////////////////////////////////////////////////////////////////
19 //// Copyright (C) 2000 Authors and OPENCORES.ORG ////
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. ////
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. ////
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 ////
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 ////
42 //////////////////////////////////////////////////////////////////////
44 // CVS Revision History
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
83 // Revision 1.1.1.1 2001/10/06 10:18:35 igorm
86 // Revision 1.2 2001/08/09 13:39:33 lampret
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"
100 a
, b
, mult_mac_result
, macrc_op
,
101 alu_op
, shrot_op
, comp_op
,
102 result
, flagforw
, flag_we
,
106 parameter width
= `OR1200_OPERAND_WIDTH;
113 input [width
-1:0] mult_mac_result
;
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
;
126 // Internal wires and regs
128 reg [width
-1:0] result
;
129 reg [width
-1:0] shifted_rotated
;
134 // synopsys translate_off
135 `ifdef OR1200_SIM_ALU_DIV
139 // synopsys translate_on
140 wire [width
-1:0] comp_a
;
141 wire [width
-1:0] comp_b
;
142 `ifdef OR1200_IMPL_ALU_COMP1
146 wire [width
-1:0] result_sum
;
147 `ifdef OR1200_IMPL_ADDC
148 wire [width
-1:0] result_csum
;
150 wire [width
-1:0] result_and
;
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
);
162 assign {cyforw
, result_sum
} = a
+ b
;
163 `ifdef OR1200_IMPL_ADDC
164 assign {cyforw
, result_csum
} = a
+ b
+ carry
;
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
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
187 casex (alu_op
) // synopsys full_case parallel_case
189 `OR1200_ALUOP_SHROT : begin
190 result
= shifted_rotated
;
192 `OR1200_ALUOP_ADD : begin
195 `ifdef OR1200_IMPL_ADDC
196 `OR1200_ALUOP_ADDC : begin
197 result
= result_csum
;
200 `OR1200_ALUOP_SUB : begin
203 `OR1200_ALUOP_XOR : begin
206 `OR1200_ALUOP_OR : begin
209 `OR1200_ALUOP_IMM : begin
212 `OR1200_ALUOP_MOVHI : begin
214 result
= mult_mac_result
;
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
228 // synopsys translate_off
229 `ifdef OR1200_SIM_ALU_DIV
230 `OR1200_ALUOP_DIV : begin
233 $display("DIV operation: %d / %d = %d", d1
, d2
, d1
/d2
);
237 result
= 32'h00000000
;
240 `ifdef OR1200_SIM_ALU_DIVU
241 `OR1200_ALUOP_DIVU : begin
245 result
= 32'h00000000
;
248 // synopsys translate_on
249 `ifdef OR1200_CASE_DEFAULT
252 `OR1200_ALUOP_COMP, `OR1200_ALUOP_AND
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
);
269 `ifdef OR1200_IMPL_ADDC
270 `OR1200_ALUOP_ADDC : begin
271 flagforw
= (result_csum
== 32'h0000_0000
);
275 `OR1200_ALUOP_AND: begin
276 flagforw
= (result_and
== 32'h0000_0000
);
280 `OR1200_ALUOP_COMP: begin
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
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]);
322 shifted_rotated
= ({32{a
[31]}} << (6'd32-{1'b0, b
[4:0]})) | a
>> b
[4:0];
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
337 flagcomp
= ~(a_eq_b | a_lt_b
);
343 flagcomp
= a_eq_b | a_lt_b
;
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
357 flagcomp
= (comp_a
== comp_b
);
359 flagcomp
= (comp_a
!= comp_b
);
361 flagcomp
= (comp_a
> comp_b
);
363 flagcomp
= (comp_a
>= comp_b
);
365 flagcomp
= (comp_a
< comp_b
);
367 flagcomp
= (comp_a
<= comp_b
);