| // ================================================================== |
| // >>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<< |
| // ------------------------------------------------------------------ |
| // Copyright (c) 2006-2011 by Lattice Semiconductor Corporation |
| // ALL RIGHTS RESERVED |
| // ------------------------------------------------------------------ |
| // |
| // IMPORTANT: THIS FILE IS AUTO-GENERATED BY THE LATTICEMICO SYSTEM. |
| // |
| // Permission: |
| // |
| // Lattice Semiconductor grants permission to use this code |
| // pursuant to the terms of the Lattice Semiconductor Corporation |
| // Open Source License Agreement. |
| // |
| // Disclaimer: |
| // |
| // Lattice Semiconductor provides no warranty regarding the use or |
| // functionality of this code. It is the user's responsibility to |
| // verify the user's design for consistency and functionality through |
| // the use of formal verification methods. |
| // |
| // -------------------------------------------------------------------- |
| // |
| // Lattice Semiconductor Corporation |
| // 5555 NE Moore Court |
| // Hillsboro, OR 97214 |
| // U.S.A |
| // |
| // TEL: 1-800-Lattice (USA and Canada) |
| // 503-286-8001 (other locations) |
| // |
| // web: http://www.latticesemi.com/ |
| // email: techsupport@latticesemi.com |
| // |
| // -------------------------------------------------------------------- |
| // FILE DETAILS |
| // Project : LatticeMico32 |
| // File : lm_mc_arithmetic.v |
| // Title : Multi-cycle arithmetic unit. |
| // Dependencies : lm32_include.v |
| // Version : 6.1.17 |
| // : Initial Release |
| // Version : 7.0SP2, 3.0 |
| // : No Change |
| // Version : 3.1 |
| // : No Change |
| // ============================================================================= |
| |
| `include "lm32_include.v" |
| |
| `define LM32_MC_STATE_RNG 2:0 |
| `define LM32_MC_STATE_IDLE 3'b000 |
| `define LM32_MC_STATE_MULTIPLY 3'b001 |
| `define LM32_MC_STATE_MODULUS 3'b010 |
| `define LM32_MC_STATE_DIVIDE 3'b011 |
| `define LM32_MC_STATE_SHIFT_LEFT 3'b100 |
| `define LM32_MC_STATE_SHIFT_RIGHT 3'b101 |
| |
| ///////////////////////////////////////////////////// |
| // Module interface |
| ///////////////////////////////////////////////////// |
| |
| module lm32_mc_arithmetic ( |
| // ----- Inputs ----- |
| clk_i, |
| rst_i, |
| stall_d, |
| kill_x, |
| `ifdef CFG_MC_DIVIDE_ENABLED |
| divide_d, |
| modulus_d, |
| `endif |
| `ifdef CFG_MC_MULTIPLY_ENABLED |
| multiply_d, |
| `endif |
| `ifdef CFG_MC_BARREL_SHIFT_ENABLED |
| shift_left_d, |
| shift_right_d, |
| sign_extend_d, |
| `endif |
| operand_0_d, |
| operand_1_d, |
| // ----- Ouputs ----- |
| result_x, |
| `ifdef CFG_MC_DIVIDE_ENABLED |
| divide_by_zero_x, |
| `endif |
| stall_request_x |
| ); |
| |
| ///////////////////////////////////////////////////// |
| // Inputs |
| ///////////////////////////////////////////////////// |
| |
| input clk_i; // Clock |
| input rst_i; // Reset |
| input stall_d; // Stall instruction in D stage |
| input kill_x; // Kill instruction in X stage |
| `ifdef CFG_MC_DIVIDE_ENABLED |
| input divide_d; // Perform divide |
| input modulus_d; // Perform modulus |
| `endif |
| `ifdef CFG_MC_MULTIPLY_ENABLED |
| input multiply_d; // Perform multiply |
| `endif |
| `ifdef CFG_MC_BARREL_SHIFT_ENABLED |
| input shift_left_d; // Perform left shift |
| input shift_right_d; // Perform right shift |
| input sign_extend_d; // Whether to sign-extend (arithmetic) or zero-extend (logical) |
| `endif |
| input [`LM32_WORD_RNG] operand_0_d; |
| input [`LM32_WORD_RNG] operand_1_d; |
| |
| ///////////////////////////////////////////////////// |
| // Outputs |
| ///////////////////////////////////////////////////// |
| |
| output [`LM32_WORD_RNG] result_x; // Result of operation |
| reg [`LM32_WORD_RNG] result_x; |
| `ifdef CFG_MC_DIVIDE_ENABLED |
| output divide_by_zero_x; // A divide by zero was attempted |
| reg divide_by_zero_x; |
| `endif |
| output stall_request_x; // Request to stall pipeline from X stage back |
| wire stall_request_x; |
| |
| ///////////////////////////////////////////////////// |
| // Internal nets and registers |
| ///////////////////////////////////////////////////// |
| |
| reg [`LM32_WORD_RNG] p; // Temporary registers |
| reg [`LM32_WORD_RNG] a; |
| reg [`LM32_WORD_RNG] b; |
| `ifdef CFG_MC_DIVIDE_ENABLED |
| wire [32:0] t; |
| `endif |
| |
| reg [`LM32_MC_STATE_RNG] state; // Current state of FSM |
| reg [5:0] cycles; // Number of cycles remaining in the operation |
| |
| `ifdef CFG_MC_BARREL_SHIFT_ENABLED |
| reg sign_extend_x; // Whether to sign extend of zero extend right shifts |
| wire fill_value; // Value to fill with for right barrel-shifts |
| `endif |
| |
| ///////////////////////////////////////////////////// |
| // Combinational logic |
| ///////////////////////////////////////////////////// |
| |
| // Stall pipeline while any operation is being performed |
| assign stall_request_x = state != `LM32_MC_STATE_IDLE; |
| |
| `ifdef CFG_MC_DIVIDE_ENABLED |
| // Subtraction |
| assign t = {p[`LM32_WORD_WIDTH-2:0], a[`LM32_WORD_WIDTH-1]} - b; |
| `endif |
| |
| `ifdef CFG_MC_BARREL_SHIFT_ENABLED |
| // Determine fill value for right shift - Sign bit for arithmetic shift, or zero for logical shift |
| assign fill_value = (sign_extend_x == `TRUE) & b[`LM32_WORD_WIDTH-1]; |
| `endif |
| |
| ///////////////////////////////////////////////////// |
| // Sequential logic |
| ///////////////////////////////////////////////////// |
| |
| // Perform right shift |
| always @(posedge clk_i `CFG_RESET_SENSITIVITY) |
| begin |
| if (rst_i == `TRUE) |
| begin |
| cycles <= {6{1'b0}}; |
| p <= {`LM32_WORD_WIDTH{1'b0}}; |
| a <= {`LM32_WORD_WIDTH{1'b0}}; |
| b <= {`LM32_WORD_WIDTH{1'b0}}; |
| `ifdef CFG_MC_BARREL_SHIFT_ENABLED |
| sign_extend_x <= 1'b0; |
| `endif |
| `ifdef CFG_MC_DIVIDE_ENABLED |
| divide_by_zero_x <= `FALSE; |
| `endif |
| result_x <= {`LM32_WORD_WIDTH{1'b0}}; |
| state <= `LM32_MC_STATE_IDLE; |
| end |
| else |
| begin |
| `ifdef CFG_MC_DIVIDE_ENABLED |
| divide_by_zero_x <= `FALSE; |
| `endif |
| case (state) |
| `LM32_MC_STATE_IDLE: |
| begin |
| if (stall_d == `FALSE) |
| begin |
| cycles <= `LM32_WORD_WIDTH; |
| p <= 32'b0; |
| a <= operand_0_d; |
| b <= operand_1_d; |
| `ifdef CFG_MC_DIVIDE_ENABLED |
| if (divide_d == `TRUE) |
| state <= `LM32_MC_STATE_DIVIDE; |
| if (modulus_d == `TRUE) |
| state <= `LM32_MC_STATE_MODULUS; |
| `endif |
| `ifdef CFG_MC_MULTIPLY_ENABLED |
| if (multiply_d == `TRUE) |
| state <= `LM32_MC_STATE_MULTIPLY; |
| `endif |
| `ifdef CFG_MC_BARREL_SHIFT_ENABLED |
| if (shift_left_d == `TRUE) |
| begin |
| state <= `LM32_MC_STATE_SHIFT_LEFT; |
| sign_extend_x <= sign_extend_d; |
| cycles <= operand_1_d[4:0]; |
| a <= operand_0_d; |
| b <= operand_0_d; |
| end |
| if (shift_right_d == `TRUE) |
| begin |
| state <= `LM32_MC_STATE_SHIFT_RIGHT; |
| sign_extend_x <= sign_extend_d; |
| cycles <= operand_1_d[4:0]; |
| a <= operand_0_d; |
| b <= operand_0_d; |
| end |
| `endif |
| end |
| end |
| `ifdef CFG_MC_DIVIDE_ENABLED |
| `LM32_MC_STATE_DIVIDE: |
| begin |
| if (t[32] == 1'b0) |
| begin |
| p <= t[31:0]; |
| a <= {a[`LM32_WORD_WIDTH-2:0], 1'b1}; |
| end |
| else |
| begin |
| p <= {p[`LM32_WORD_WIDTH-2:0], a[`LM32_WORD_WIDTH-1]}; |
| a <= {a[`LM32_WORD_WIDTH-2:0], 1'b0}; |
| end |
| result_x <= a; |
| if ((cycles == `LM32_WORD_WIDTH'd0) || (kill_x == `TRUE)) |
| begin |
| // Check for divide by zero |
| divide_by_zero_x <= b == {`LM32_WORD_WIDTH{1'b0}}; |
| state <= `LM32_MC_STATE_IDLE; |
| end |
| cycles <= cycles - 1'b1; |
| end |
| `LM32_MC_STATE_MODULUS: |
| begin |
| if (t[32] == 1'b0) |
| begin |
| p <= t[31:0]; |
| a <= {a[`LM32_WORD_WIDTH-2:0], 1'b1}; |
| end |
| else |
| begin |
| p <= {p[`LM32_WORD_WIDTH-2:0], a[`LM32_WORD_WIDTH-1]}; |
| a <= {a[`LM32_WORD_WIDTH-2:0], 1'b0}; |
| end |
| result_x <= p; |
| if ((cycles == `LM32_WORD_WIDTH'd0) || (kill_x == `TRUE)) |
| begin |
| // Check for divide by zero |
| divide_by_zero_x <= b == {`LM32_WORD_WIDTH{1'b0}}; |
| state <= `LM32_MC_STATE_IDLE; |
| end |
| cycles <= cycles - 1'b1; |
| end |
| `endif |
| `ifdef CFG_MC_MULTIPLY_ENABLED |
| `LM32_MC_STATE_MULTIPLY: |
| begin |
| if (b[0] == 1'b1) |
| p <= p + a; |
| b <= {1'b0, b[`LM32_WORD_WIDTH-1:1]}; |
| a <= {a[`LM32_WORD_WIDTH-2:0], 1'b0}; |
| result_x <= p; |
| if ((cycles == `LM32_WORD_WIDTH'd0) || (kill_x == `TRUE)) |
| state <= `LM32_MC_STATE_IDLE; |
| cycles <= cycles - 1'b1; |
| end |
| `endif |
| `ifdef CFG_MC_BARREL_SHIFT_ENABLED |
| `LM32_MC_STATE_SHIFT_LEFT: |
| begin |
| a <= {a[`LM32_WORD_WIDTH-2:0], 1'b0}; |
| result_x <= a; |
| if ((cycles == `LM32_WORD_WIDTH'd0) || (kill_x == `TRUE)) |
| state <= `LM32_MC_STATE_IDLE; |
| cycles <= cycles - 1'b1; |
| end |
| `LM32_MC_STATE_SHIFT_RIGHT: |
| begin |
| b <= {fill_value, b[`LM32_WORD_WIDTH-1:1]}; |
| result_x <= b; |
| if ((cycles == `LM32_WORD_WIDTH'd0) || (kill_x == `TRUE)) |
| state <= `LM32_MC_STATE_IDLE; |
| cycles <= cycles - 1'b1; |
| end |
| `endif |
| endcase |
| end |
| end |
| |
| endmodule |