@@ -60,14 +60,14 @@ architecture neorv32_cpu_cp_muldiv_rtl of neorv32_cpu_cp_muldiv is
60
60
rs1_is_signed : std_ulogic ;
61
61
rs2_is_signed : std_ulogic ;
62
62
out_en : std_ulogic ;
63
- rs2_abs : std_ulogic_vector (XLEN- 1 downto 0 );
64
63
end record ;
65
64
signal ctrl : ctrl_t;
66
65
67
66
-- divider core --
68
67
type div_t is record
69
68
start : std_ulogic ; -- start new division
70
69
sign_mod : std_ulogic ; -- result sign correction
70
+ rs2_abs : std_ulogic_vector (XLEN- 1 downto 0 );
71
71
remainder : std_ulogic_vector (XLEN- 1 downto 0 );
72
72
quotient : std_ulogic_vector (XLEN- 1 downto 0 );
73
73
sub : std_ulogic_vector (XLEN downto 0 ); -- try subtraction (and restore if underflow)
@@ -95,58 +95,39 @@ begin
95
95
control : process (rstn_i, clk_i)
96
96
begin
97
97
if (rstn_i = '0' ) then
98
- ctrl.state <= S_IDLE;
99
- ctrl.rs2_abs <= (others => '0' );
100
- ctrl.cnt <= (others => '0' );
101
- ctrl.out_en <= '0' ;
102
- div.sign_mod <= '0' ;
98
+ ctrl.state <= S_IDLE;
99
+ ctrl.cnt <= (others => '0' );
100
+ ctrl.out_en <= '0' ;
103
101
elsif rising_edge (clk_i) then
104
102
-- defaults --
105
103
ctrl.out_en <= '0' ;
104
+ ctrl.cnt <= std_ulogic_vector (to_unsigned (XLEN- 2 , index_size_f(XLEN))); -- cycle counter initialization
106
105
107
- -- FSM --
106
+ -- fsm --
108
107
case ctrl.state is
109
108
110
109
when S_IDLE => -- wait for start signal
111
- ctrl.cnt <= std_ulogic_vector ( to_unsigned (XLEN - 2 , index_size_f(XLEN))); -- iterative cycle counter
110
+ -- ------------------------------------------------------------
112
111
if (start_i = '1' ) then -- trigger new operation
113
- if DIVISION_EN then
114
- -- DIV: check relevant input signs for result sign compensation --
115
- if (ctrl_i.ir_funct3(1 downto 0 ) = op_div_c(1 downto 0 )) then -- signed div operation
116
- div.sign_mod <= (rs1_i(rs1_i'left ) xor rs2_i(rs2_i'left )) and or_reduce_f(rs2_i); -- different signs AND divisor not zero
117
- elsif (ctrl_i.ir_funct3(1 downto 0 ) = op_rem_c(1 downto 0 )) then -- signed rem operation
118
- div.sign_mod <= rs1_i(rs1_i'left );
119
- else
120
- div.sign_mod <= '0' ;
121
- end if ;
122
- -- DIV: abs(rs2) --
123
- if ((rs2_i(rs2_i'left ) and ctrl.rs2_is_signed) = '1' ) then -- signed division?
124
- ctrl.rs2_abs <= std_ulogic_vector (0 - unsigned (rs2_i)); -- make positive
125
- else
126
- ctrl.rs2_abs <= rs2_i;
127
- end if ;
128
- end if ;
129
- -- is fast multiplication? --
130
- if (ctrl_i.ir_funct3(2 ) = '0' ) and FAST_MUL_EN then
112
+ if (ctrl_i.ir_funct3(2 ) = '0' ) and FAST_MUL_EN then -- is fast multiplication?
131
113
ctrl.state <= S_DONE;
132
114
else -- serial division or serial multiplication
133
115
ctrl.state <= S_BUSY;
134
116
end if ;
135
117
end if ;
136
118
137
119
when S_BUSY => -- processing
120
+ -- ------------------------------------------------------------
138
121
ctrl.cnt <= std_ulogic_vector (unsigned (ctrl.cnt) - 1 );
139
122
if (or_reduce_f(ctrl.cnt) = '0' ) or (ctrl_i.cpu_trap = '1' ) then -- abort on trap
140
123
ctrl.state <= S_DONE;
141
124
end if ;
142
125
143
- when S_DONE => -- final step / enable output for one cycle
126
+ when others => -- S_DONE: final step / enable output for one cycle
127
+ -- ------------------------------------------------------------
144
128
ctrl.out_en <= '1' ;
145
129
ctrl.state <= S_IDLE;
146
130
147
- when others => -- undefined
148
- ctrl.state <= S_IDLE;
149
-
150
131
end case ;
151
132
end if ;
152
133
end process control ;
@@ -160,7 +141,7 @@ begin
160
141
ctrl.rs2_is_signed <= '1' when (ctrl_i.ir_funct3 = op_mulh_c) or
161
142
(ctrl_i.ir_funct3 = op_div_c) or (ctrl_i.ir_funct3 = op_rem_c) else '0' ;
162
143
163
- -- start operation (do it fast!) --
144
+ -- operation trigger --
164
145
mul.start <= '1' when (start_i = '1' ) and (ctrl_i.ir_funct3(2 ) = '0' ) else '0' ;
165
146
div.start <= '1' when (start_i = '1' ) and (ctrl_i.ir_funct3(2 ) = '1' ) else '0' ;
166
147
@@ -214,14 +195,14 @@ begin
214
195
if (mul.start = '1' ) then -- start new multiplication
215
196
mul.prod(63 downto 32 ) <= (others => '0' );
216
197
mul.prod(31 downto 0 ) <= rs1_i;
217
- elsif (ctrl.state = S_BUSY) or (ctrl.state = S_DONE) then -- processing step or sign-finalization step
198
+ elsif (ctrl.state /= S_IDLE) then -- processing steps or sign-finalization step
218
199
mul.prod(63 downto 31 ) <= mul.add(32 downto 0 );
219
200
mul.prod(30 downto 0 ) <= mul.prod(31 downto 1 );
220
201
end if ;
221
202
end if ;
222
203
end process multiplier_core ;
223
204
224
- -- multiply with 0/1 via addition --
205
+ -- multiply with 0/-1/+1 via shift and subtraction/ addition --
225
206
mul_update : process (mul, ctrl, rs2_i)
226
207
begin
227
208
if (mul.prod(0 ) = '1' ) then -- multiply with 1
@@ -258,14 +239,32 @@ begin
258
239
begin
259
240
if (rstn_i = '0' ) then
260
241
div.quotient <= (others => '0' );
242
+ div.rs2_abs <= (others => '0' );
243
+ div.sign_mod <= '0' ;
261
244
div.remainder <= (others => '0' );
262
245
elsif rising_edge (clk_i) then
263
246
if (div.start = '1' ) then -- start new division
247
+ -- abs(rs1) --
264
248
if ((rs1_i(rs1_i'left ) and ctrl.rs1_is_signed) = '1' ) then -- signed division?
265
249
div.quotient <= std_ulogic_vector (0 - unsigned (rs1_i)); -- make positive
266
250
else
267
251
div.quotient <= rs1_i;
268
252
end if ;
253
+ -- abs(rs2) --
254
+ if ((rs2_i(rs2_i'left ) and ctrl.rs2_is_signed) = '1' ) then -- signed division?
255
+ div.rs2_abs <= std_ulogic_vector (0 - unsigned (rs2_i)); -- make positive
256
+ else
257
+ div.rs2_abs <= rs2_i;
258
+ end if ;
259
+ -- check relevant input signs for result sign compensation --
260
+ if (ctrl_i.ir_funct3(1 downto 0 ) = op_div_c(1 downto 0 )) then -- signed div operation
261
+ div.sign_mod <= (rs1_i(rs1_i'left ) xor rs2_i(rs2_i'left )) and or_reduce_f(rs2_i); -- different signs AND divisor not zero
262
+ elsif (ctrl_i.ir_funct3(1 downto 0 ) = op_rem_c(1 downto 0 )) then -- signed rem operation
263
+ div.sign_mod <= rs1_i(rs1_i'left );
264
+ else
265
+ div.sign_mod <= '0' ;
266
+ end if ;
267
+ --
269
268
div.remainder <= (others => '0' );
270
269
elsif (ctrl.state = S_BUSY) or (ctrl.state = S_DONE) then -- running?
271
270
div.quotient <= div.quotient(30 downto 0 ) & (not div.sub(32 ));
@@ -279,10 +278,10 @@ begin
279
278
end process divider_core ;
280
279
281
280
-- try another subtraction (and shift) --
282
- div.sub <= std_ulogic_vector (unsigned ('0' & div.remainder(30 downto 0 ) & div.quotient(31 )) - unsigned ('0' & ctrl .rs2_abs));
281
+ div.sub <= std_ulogic_vector (unsigned ('0' & div.remainder(30 downto 0 ) & div.quotient(31 )) - unsigned ('0' & div .rs2_abs));
283
282
284
283
-- result and sign compensation --
285
- div.res_u <= div.quotient when (ctrl_i.ir_funct3 = op_div_c) or (ctrl_i.ir_funct3 = op_divu_c) else div.remainder;
284
+ div.res_u <= div.quotient when (ctrl_i.ir_funct3( 2 downto 1 ) = op_div_c( 2 downto 1 )) else div.remainder; -- division only
286
285
div.res <= std_ulogic_vector (0 - unsigned (div.res_u)) when (div.sign_mod = '1' ) else div.res_u;
287
286
288
287
end generate ; -- /divider_core_serial
@@ -291,6 +290,8 @@ begin
291
290
divider_core_serial_none:
292
291
if not DIVISION_EN generate
293
292
div.quotient <= (others => '0' );
293
+ div.sign_mod <= '0' ;
294
+ div.rs2_abs <= (others => '0' );
294
295
div.remainder <= (others => '0' );
295
296
div.sub <= (others => '0' );
296
297
div.res_u <= (others => '0' );
0 commit comments