// ================================================================== // >>>>>>>>>>>>>>>>>>>>>>> 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