forked from openhwgroup/cv32e40p
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathalu_div.sv
216 lines (177 loc) · 6.96 KB
/
alu_div.sv
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
// Copyright 2016 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the “License”); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this 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.
///////////////////////////////////////////////////////////////////////////////
// File : Simple Serial Divider
// Ver : 1.0
// Date : 15.03.2016
///////////////////////////////////////////////////////////////////////////////
//
// Description: this is a simple serial divider for signed integers (int32).
//
///////////////////////////////////////////////////////////////////////////////
//
// Authors : Michael Schaffner (schaffner@iis.ee.ethz.ch)
// Andreas Traber (atraber@iis.ee.ethz.ch)
//
///////////////////////////////////////////////////////////////////////////////
module riscv_alu_div
#(
parameter C_WIDTH = 32,
parameter C_LOG_WIDTH = 6
)
(
input logic Clk_CI,
input logic Rst_RBI,
// input IF
input logic [C_WIDTH-1:0] OpA_DI,
input logic [C_WIDTH-1:0] OpB_DI,
input logic [C_LOG_WIDTH-1:0] OpBShift_DI,
input logic OpBIsZero_SI,
//
input logic OpBSign_SI, // gate this to 0 in case of unsigned ops
input logic [1:0] OpCode_SI, // 0: udiv, 2: urem, 1: div, 3: rem
// handshake
input logic InVld_SI,
// output IF
input logic OutRdy_SI,
output logic OutVld_SO,
output logic [C_WIDTH-1:0] Res_DO
);
///////////////////////////////////////////////////////////////////////////////
// signal declarations
///////////////////////////////////////////////////////////////////////////////
logic [C_WIDTH-1:0] ResReg_DP, ResReg_DN;
logic [C_WIDTH-1:0] ResReg_DP_rev;
logic [C_WIDTH-1:0] AReg_DP, AReg_DN;
logic [C_WIDTH-1:0] BReg_DP, BReg_DN;
logic RemSel_SN, RemSel_SP;
logic CompInv_SN, CompInv_SP;
logic ResInv_SN, ResInv_SP;
logic [C_WIDTH-1:0] AddMux_D;
logic [C_WIDTH-1:0] AddOut_D;
logic [C_WIDTH-1:0] AddTmp_D;
logic [C_WIDTH-1:0] BMux_D;
logic [C_WIDTH-1:0] OutMux_D;
logic [C_LOG_WIDTH-1:0] Cnt_DP, Cnt_DN;
logic CntZero_S;
logic ARegEn_S, BRegEn_S, ResRegEn_S, ABComp_S, PmSel_S, LoadEn_S;
enum logic [1:0] {IDLE, DIVIDE, FINISH} State_SN, State_SP;
///////////////////////////////////////////////////////////////////////////////
// datapath
///////////////////////////////////////////////////////////////////////////////
assign PmSel_S = LoadEn_S & ~(OpCode_SI[0] & (OpA_DI[$high(OpA_DI)] ^ OpBSign_SI));
// muxes
assign AddMux_D = (LoadEn_S) ? OpA_DI : BReg_DP;
// attention: logical shift in case of negative operand B!
assign BMux_D = (LoadEn_S) ? OpB_DI : {CompInv_SP, (BReg_DP[$high(BReg_DP):1])};
assign ResReg_DP_rev = {<<{ResReg_DP}};
assign OutMux_D = (RemSel_SP) ? AReg_DP : ResReg_DP_rev;
// invert if necessary
assign Res_DO = (ResInv_SP) ? -$signed(OutMux_D) : OutMux_D;
// main comparator
assign ABComp_S = ((AReg_DP == BReg_DP) | ((AReg_DP > BReg_DP) ^ CompInv_SP)) & ((|AReg_DP) | OpBIsZero_SI);
// main adder
assign AddTmp_D = (LoadEn_S) ? 0 : AReg_DP;
assign AddOut_D = (PmSel_S) ? AddTmp_D + AddMux_D : AddTmp_D - $signed(AddMux_D);
///////////////////////////////////////////////////////////////////////////////
// counter
///////////////////////////////////////////////////////////////////////////////
assign Cnt_DN = (LoadEn_S) ? OpBShift_DI :
(~CntZero_S) ? Cnt_DP - 1 : Cnt_DP;
assign CntZero_S = ~(|Cnt_DP);
///////////////////////////////////////////////////////////////////////////////
// FSM
///////////////////////////////////////////////////////////////////////////////
always_comb
begin : p_fsm
// default
State_SN = State_SP;
OutVld_SO = 1'b0;
LoadEn_S = 1'b0;
ARegEn_S = 1'b0;
BRegEn_S = 1'b0;
ResRegEn_S = 1'b0;
case (State_SP)
/////////////////////////////////
IDLE: begin
OutVld_SO = 1'b1;
if(InVld_SI) begin
OutVld_SO = 1'b0;
ARegEn_S = 1'b1;
BRegEn_S = 1'b1;
LoadEn_S = 1'b1;
State_SN = DIVIDE;
end
end
/////////////////////////////////
DIVIDE: begin
ARegEn_S = ABComp_S;
BRegEn_S = 1'b1;
ResRegEn_S = 1'b1;
// calculation finished
// one more divide cycle (32nd divide cycle)
if (CntZero_S) begin
State_SN = FINISH;
end
end
/////////////////////////////////
FINISH: begin
OutVld_SO = 1'b1;
if(OutRdy_SI) begin
State_SN = IDLE;
end
end
/////////////////////////////////
default : /* default */ ;
/////////////////////////////////
endcase
end
///////////////////////////////////////////////////////////////////////////////
// regs
///////////////////////////////////////////////////////////////////////////////
// get flags
assign RemSel_SN = (LoadEn_S) ? OpCode_SI[1] : RemSel_SP;
assign CompInv_SN = (LoadEn_S) ? OpBSign_SI : CompInv_SP;
assign ResInv_SN = (LoadEn_S) ? (~OpBIsZero_SI | OpCode_SI[1]) & OpCode_SI[0] & (OpA_DI[$high(OpA_DI)] ^ OpBSign_SI) : ResInv_SP;
assign AReg_DN = (ARegEn_S) ? AddOut_D : AReg_DP;
assign BReg_DN = (BRegEn_S) ? BMux_D : BReg_DP;
assign ResReg_DN = (LoadEn_S) ? '0 :
(ResRegEn_S) ? {ABComp_S, ResReg_DP[$high(ResReg_DP):1]} : ResReg_DP;
always_ff @(posedge Clk_CI or negedge Rst_RBI) begin : p_regs
if(~Rst_RBI) begin
State_SP <= IDLE;
AReg_DP <= '0;
BReg_DP <= '0;
ResReg_DP <= '0;
Cnt_DP <= '0;
RemSel_SP <= 1'b0;
CompInv_SP <= 1'b0;
ResInv_SP <= 1'b0;
end else begin
State_SP <= State_SN;
AReg_DP <= AReg_DN;
BReg_DP <= BReg_DN;
ResReg_DP <= ResReg_DN;
Cnt_DP <= Cnt_DN;
RemSel_SP <= RemSel_SN;
CompInv_SP <= CompInv_SN;
ResInv_SP <= ResInv_SN;
end
end
///////////////////////////////////////////////////////////////////////////////
// assertions
///////////////////////////////////////////////////////////////////////////////
`ifndef SYNTHESIS
initial
begin : p_assertions
assert (C_LOG_WIDTH == $clog2(C_WIDTH+1)) else $error("C_LOG_WIDTH must be $clog2(C_WIDTH+1)");
end
`endif
endmodule // serDiv