2023-03-20 23:22:06 +00:00
///////////////////////////////////////////
// intdivrestoring.sv
//
// Written: David_Harris@hmc.edu 12 September 2021
// Modified:
//
// Purpose: Restoring integer division using a shift register and subtractor
//
// Documentation: RISC-V System on Chip Design Chapter 12 (Figure 12.19)
//
// A component of the CORE-V-WALLY configurable RISC-V project.
2024-01-29 13:38:11 +00:00
// https://github.com/openhwgroup/cvw
2023-03-20 23:22:06 +00:00
//
// Copyright (C) 2021-23 Harvey Mudd College & Oklahoma State University
//
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
//
// Licensed under the Solderpad Hardware License v 2.1 (the “License”); you may not use this file
// except in compliance with the License, or, at your option, the Apache License version 2.0. You
// may obtain a copy of the License at
//
// https://solderpad.org/licenses/SHL-2.1/
//
// Unless required by applicable law or agreed to in writing, any work distributed under the
// License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
// either express or implied. See the License for the specific language governing permissions
// and limitations under the License.
////////////////////////////////////////////////////////////////////////////////////////////////
2023-05-24 20:01:35 +00:00
module div import cvw : : * ; # ( parameter cvw_t P ) (
2023-06-12 20:47:09 +00:00
input logic clk ,
input logic reset ,
input logic StallM ,
input logic FlushE ,
input logic IntDivE , // integer division/remainder instruction of any type
input logic DivSignedE , // signed division
input logic W64E , // W-type instructions (divw, divuw, remw, remuw)
input logic [ P . XLEN - 1 : 0 ] ForwardedSrcAE , ForwardedSrcBE , // Forwarding mux outputs for Source A and B
output logic DivBusyE , // Divide is busy - stall pipeline
output logic [ P . XLEN - 1 : 0 ] QuotM , RemM // Quotient and remainder outputs
2023-03-20 23:22:06 +00:00
) ;
2023-05-24 20:01:35 +00:00
localparam STEPBITS = $clog2 ( P . XLEN / P . IDIV_BITSPERCYCLE ) ; // Number of steps
2023-03-20 23:22:06 +00:00
2023-06-12 20:47:09 +00:00
typedef enum logic [ 1 : 0 ] { IDLE , BUSY , DONE } statetype ; // division FSM state
2023-03-20 23:22:06 +00:00
statetype state ;
2023-05-24 20:01:35 +00:00
logic [ P . XLEN - 1 : 0 ] W [ P . IDIV_BITSPERCYCLE: 0 ] ; // Residual for each of k steps
logic [ P . XLEN - 1 : 0 ] XQ [ P . IDIV_BITSPERCYCLE: 0 ] ; // dividend/quotient for each of k steps
2023-06-12 20:47:09 +00:00
logic [ P . XLEN - 1 : 0 ] WNext , XQNext ; // initialized W and XQ going into registers
logic [ P . XLEN - 1 : 0 ] DinE , XinE ; // divisor & dividend, possibly truncated to 32 bits
logic [ P . XLEN - 1 : 0 ] DnE ; // DnE = ~DinE
logic [ P . XLEN - 1 : 0 ] DAbsBE ; // absolute value of D
logic [ P . XLEN - 1 : 0 ] DAbsB ; // registered absolute value of D, constant during division
logic [ P . XLEN - 1 : 0 ] XnE ; // DXnE = ~XinE
logic [ P . XLEN - 1 : 0 ] XInitE ; // |X|, or original X for divide by 0
logic [ P . XLEN - 1 : 0 ] WnM , XQnM ; // negated residual W and quotient XQ for postprocessing sign correction
logic [ STEPBITS: 0 ] step ; // division step
logic Div0E , Div0M ; // divide by 0
logic DivStartE ; // start integer division
logic SignXE , SignDE ; // sign of dividend and divisor
logic NegQE , NegWM , NegQM ; // negate quotient or residual during postprocessing
2023-03-20 23:22:06 +00:00
//////////////////////////////
// Execute Stage: prepare for division calculation with control logic, W logic and absolute values, initialize W and XQ
//////////////////////////////
// Divider control signals
assign DivStartE = IntDivE & ( state = = IDLE ) & ~ StallM ;
assign DivBusyE = ( state = = BUSY ) | DivStartE ;
// Handle sign extension for W-type instructions
2023-05-24 20:01:35 +00:00
if ( P . XLEN = = 64 ) begin : rv64 // RV64 has W-type instructions
mux2 # ( P . XLEN ) xinmux ( ForwardedSrcAE , { ForwardedSrcAE [ 31 : 0 ] , 32 'b0 } , W64E , XinE ) ;
mux2 # ( P . XLEN ) dinmux ( ForwardedSrcBE , { { 32 { ForwardedSrcBE [ 31 ] & DivSignedE } } , ForwardedSrcBE [ 31 : 0 ] } , W64E , DinE ) ;
2023-03-20 23:22:06 +00:00
end else begin // RV32 has no W-type instructions
assign XinE = ForwardedSrcAE ;
2023-03-24 22:32:25 +00:00
assign DinE = ForwardedSrcBE ;
2023-03-20 23:22:06 +00:00
end
// Extract sign bits and check fo division by zero
2023-05-24 20:01:35 +00:00
assign SignDE = DivSignedE & DinE [ P . XLEN - 1 ] ;
assign SignXE = DivSignedE & XinE [ P . XLEN - 1 ] ;
2023-03-20 23:22:06 +00:00
assign NegQE = SignDE ^ SignXE ;
assign Div0E = ( DinE = = 0 ) ;
// Take absolute value for signed operations, and negate D to handle subtraction in divider stages
2023-05-24 20:01:35 +00:00
neg # ( P . XLEN ) negd ( DinE , DnE ) ;
mux2 # ( P . XLEN ) dabsmux ( DnE , DinE , SignDE , DAbsBE ) ; // take absolute value for signed operations, and negate for subtraction setp
neg # ( P . XLEN ) negx ( XinE , XnE ) ;
mux3 # ( P . XLEN ) xabsmux ( XinE , XnE , ForwardedSrcAE , { Div0E , SignXE } , XInitE ) ; // take absolute value for signed operations, or keep original value for divide by 0
2023-03-20 23:22:06 +00:00
//////////////////////////////
// Division Iterations (effectively stalled execute stage, no suffix)
//////////////////////////////
// initialization multiplexers on first cycle of operation
2023-05-24 20:01:35 +00:00
mux2 # ( P . XLEN ) wmux ( W [ P . IDIV_BITSPERCYCLE ] , { P . XLEN { 1 'b0 } } , DivStartE , WNext ) ;
mux2 # ( P . XLEN ) xmux ( XQ [ P . IDIV_BITSPERCYCLE ] , XInitE , DivStartE , XQNext ) ;
2023-03-20 23:22:06 +00:00
// registers before division steps
2023-05-24 20:01:35 +00:00
flopen # ( P . XLEN ) wreg ( clk , DivBusyE , WNext , W [ 0 ] ) ;
flopen # ( P . XLEN ) xreg ( clk , DivBusyE , XQNext , XQ [ 0 ] ) ;
flopen # ( P . XLEN ) dabsreg ( clk , DivStartE , DAbsBE , DAbsB ) ;
2023-03-20 23:22:06 +00:00
// one copy of divstep for each bit produced per cycle
genvar i ;
2023-05-24 20:01:35 +00:00
for ( i = 0 ; i < P . IDIV_BITSPERCYCLE ; i = i + 1 )
2023-06-15 18:09:07 +00:00
divstep # ( P . XLEN ) divstep ( W [ i ] , XQ [ i ] , DAbsB , W [ i + 1 ] , XQ [ i + 1 ] ) ;
2023-03-20 23:22:06 +00:00
//////////////////////////////
// Memory Stage: output sign correction and special cases
//////////////////////////////
flopen # ( 3 ) Div0eMReg ( clk , DivStartE , { Div0E , NegQE , SignXE } , { Div0M , NegQM , NegWM } ) ;
// On final setp of signed operations, negate outputs as needed to get correct sign
2023-05-24 20:01:35 +00:00
neg # ( P . XLEN ) qneg ( XQ [ 0 ] , XQnM ) ;
neg # ( P . XLEN ) wneg ( W [ 0 ] , WnM ) ;
2023-03-20 23:22:06 +00:00
// Select appropriate output: normal, negated, or for divide by zero
2023-05-24 20:01:35 +00:00
mux3 # ( P . XLEN ) qmux ( XQ [ 0 ] , XQnM , { P . XLEN { 1 'b1 } } , { Div0M , NegQM } , QuotM ) ; // Q taken from XQ register, negated if necessary, or all 1s when dividing by zero
mux3 # ( P . XLEN ) remmux ( W [ 0 ] , WnM , XQ [ 0 ] , { Div0M , NegWM } , RemM ) ; // REM taken from W register, negated if necessary, or from X when dividing by zero
2023-03-20 23:22:06 +00:00
//////////////////////////////
// Divider FSM to sequence Busy and Done
//////////////////////////////
always_ff @ ( posedge clk )
if ( reset | FlushE ) begin
state < = IDLE ;
end else if ( DivStartE ) begin
step < = 1 ;
if ( Div0E ) state < = DONE ;
else state < = BUSY ;
2023-06-12 20:47:09 +00:00
end else if ( state = = BUSY ) begin // pause one cycle at beginning of signed operations for absolute value
2023-05-24 20:01:35 +00:00
if ( step [ STEPBITS ] | ( P . XLEN = = 64 ) & W64E & step [ STEPBITS - 1 ] ) begin // complete in half the time for W-type instructions
2023-03-20 23:22:06 +00:00
state < = DONE ;
end
step < = step + 1 ;
end else if ( state = = DONE ) begin
if ( StallM ) state < = DONE ;
else state < = IDLE ;
end
endmodule