OpenCores
URL https://opencores.org/ocsvn/yifive/yifive/trunk

Subversion Repositories yifive

[/] [yifive/] [trunk/] [caravel_yifive/] [verilog/] [rtl/] [syntacore/] [scr1/] [src/] [core/] [pipeline/] [scr1_pipe_ialu.sv] - Blame information for rev 21

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 11 dinesha
/// Copyright by Syntacore LLC © 2016-2020. See LICENSE for details
2
/// @file       
3
/// @brief      Integer Arithmetic Logic Unit (IALU)
4
///
5
 
6
//-------------------------------------------------------------------------------
7
 //
8
 // Functionality:
9
 // - Performs addition/subtraction and arithmetic and branch comparisons
10
 // - Performs logical operations (AND(I), OR(I), XOR(I))
11
 // - Performs address calculation for branch, jump, DMEM load and store and AUIPC
12
 //   instructions
13
 // - Performs shift operations
14
 // - Performs MUL/DIV operations
15
 //
16
 // Structure:
17
 // - Main adder
18
 // - Address adder
19
 // - Shift logic
20
 // - MUL/DIV logic
21
 // - Output result multiplexer
22
 //
23
//-------------------------------------------------------------------------------
24
 
25
`include "scr1_arch_description.svh"
26
`include "scr1_riscv_isa_decoding.svh"
27
`include "scr1_search_ms1.svh"
28
 
29
 
30
module scr1_pipe_ialu (
31
`ifdef SCR1_RVM_EXT
32
    // Common
33
    input   logic                           clk,                        // IALU clock
34
    input   logic                           rst_n,                      // IALU reset
35
    input   logic                           exu2ialu_rvm_cmd_vd_i,      // MUL/DIV command valid
36
    output  logic                           ialu2exu_rvm_res_rdy_o,     // MUL/DIV result ready
37
`endif // SCR1_RVM_EXT
38
 
39
    // Main adder
40
    input   logic [`SCR1_XLEN-1:0]          exu2ialu_main_op1_i,        // main ALU 1st operand
41
    input   logic [`SCR1_XLEN-1:0]          exu2ialu_main_op2_i,        // main ALU 2nd operand
42
    input   type_scr1_ialu_cmd_sel_e        exu2ialu_cmd_i,             // IALU command
43
    output  logic [`SCR1_XLEN-1:0]          ialu2exu_main_res_o,        // main ALU result
44
    output  logic                           ialu2exu_cmp_res_o,         // IALU comparison result
45
 
46
    // Address adder
47
    input   logic [`SCR1_XLEN-1:0]          exu2ialu_addr_op1_i,        // Address adder 1st operand
48
    input   logic [`SCR1_XLEN-1:0]          exu2ialu_addr_op2_i,        // Address adder 2nd operand
49
    output  logic [`SCR1_XLEN-1:0]          ialu2exu_addr_res_o         // Address adder result
50
);
51
 
52
//-------------------------------------------------------------------------------
53
// Local parameters declaration
54
//-------------------------------------------------------------------------------
55
 
56
`ifdef SCR1_RVM_EXT
57
 `ifdef SCR1_FAST_MUL
58
localparam SCR1_MUL_WIDTH     = `SCR1_XLEN;
59
localparam SCR1_MUL_RES_WIDTH = 2 * `SCR1_XLEN;
60
localparam SCR1_MDU_SUM_WIDTH = `SCR1_XLEN + 1;
61
 `else
62
localparam SCR1_MUL_STG_NUM   = 32;
63
localparam SCR1_MUL_WIDTH     = 32 / SCR1_MUL_STG_NUM;
64
localparam SCR1_MUL_CNT_INIT  = 32'b1 << (`SCR1_XLEN/SCR1_MUL_WIDTH - 2);
65
localparam SCR1_MDU_SUM_WIDTH = `SCR1_XLEN + SCR1_MUL_WIDTH;
66
 `endif // ~SCR1_FAST_MUL
67
localparam SCR1_DIV_WIDTH     = 1;
68
localparam SCR1_DIV_CNT_INIT  = 32'b1 << (`SCR1_XLEN/SCR1_DIV_WIDTH - 2);
69
`endif // SCR1_RVM_EXT
70
 
71
//-------------------------------------------------------------------------------
72
// Local types declaration
73
//-------------------------------------------------------------------------------
74
 
75
typedef struct packed {
76
    logic       z;      // Zero
77
    logic       s;      // Sign
78
    logic       o;      // Overflow
79
    logic       c;      // Carry
80
} type_scr1_ialu_flags_s;
81
 
82
 `ifdef SCR1_RVM_EXT
83 21 dinesha
//typedef enum logic [1:0] {
84
parameter    SCR1_IALU_MDU_FSM_IDLE  = 2'b00;
85
parameter    SCR1_IALU_MDU_FSM_ITER  = 2'b01;
86
parameter    SCR1_IALU_MDU_FSM_CORR  = 2'b10;
87
//} type_scr1_ialu_fsm_state;
88 11 dinesha
 
89 21 dinesha
//typedef enum logic [1:0] {
90
parameter   SCR1_IALU_MDU_NONE       = 2'b00;
91
parameter   SCR1_IALU_MDU_MUL        = 2'b01;
92
parameter   SCR1_IALU_MDU_DIV        = 2'b10;
93
//} type_scr1_ialu_mdu_cmd;
94 11 dinesha
 `endif // SCR1_RVM_EXT
95
 
96
//-------------------------------------------------------------------------------
97
// Local signals declaration
98
//-------------------------------------------------------------------------------
99
 
100
// Main adder signals
101
logic        [`SCR1_XLEN:0]                 main_sum_res;       // Main adder result
102
type_scr1_ialu_flags_s                      main_sum_flags;     // Main adder flags
103
logic                                       main_sum_pos_ovflw; // Main adder positive overflow
104
logic                                       main_sum_neg_ovflw; // Main adder negative overflow
105
logic                                       main_ops_diff_sgn;  // Main adder operands have different signs
106
logic                                       main_ops_non_zero;  // Both main adder operands are NOT 0
107
 
108
// Shifter signals
109
logic                                       ialu_cmd_shft;      // IALU command is shift
110
logic signed [`SCR1_XLEN-1:0]               shft_op1;           // SHIFT operand 1
111
logic        [4:0]                          shft_op2;           // SHIFT operand 2
112
logic        [1:0]                          shft_cmd;           // SHIFT command: 00 - logical left, 10 - logical right, 11 - arithmetical right
113
logic        [`SCR1_XLEN-1:0]               shft_res;           // SHIFT result
114
 
115
// MUL/DIV signals
116
`ifdef SCR1_RVM_EXT
117
// MUL/DIV FSM control signals
118
logic                                       mdu_cmd_is_iter;    // MDU Command is iterative
119
logic                                       mdu_iter_req;       // Request iterative stage
120
logic                                       mdu_iter_rdy;       // Iteration is ready
121
logic                                       mdu_corr_req;       // DIV/REM(U) correction request
122
logic                                       div_corr_req;       // Correction request for DIV operation
123
logic                                       rem_corr_req;       // Correction request for REM(U) operations
124
 
125
// MUL/DIV FSM signals
126 21 dinesha
logic [1:0]                                 mdu_fsm_ff;         // Current FSM state
127
logic [1:0]                                 mdu_fsm_next;       // Next FSM state
128 11 dinesha
logic                                       mdu_fsm_idle;       // MDU FSM is in IDLE state
129
`ifdef SCR1_TRGT_SIMULATION
130
logic                                       mdu_fsm_iter;       // MDU FSM is in ITER state
131
`endif // SCR1_TRGT_SIMULATION
132
logic                                       mdu_fsm_corr;       // MDU FSM is in CORR state
133
 
134
// MDU command signals
135 21 dinesha
logic [1:0]                                 mdu_cmd;            // MDU command: 00 - NONE, 01 - MUL,  10 - DIV
136 11 dinesha
logic                                       mdu_cmd_mul;        // MDU command is MUL(HSU)
137
logic                                       mdu_cmd_div;        // MDU command is DIV(U)/REM(U)
138
logic        [1:0]                          mul_cmd;            // MUL command: 00 - MUL,  01 - MULH, 10 - MULHSU, 11 - MULHU
139
logic                                       mul_cmd_hi;         // High part of MUL result is requested
140
logic        [1:0]                          div_cmd;            // DIV command: 00 - DIV,  01 - DIVU, 10 - REM,    11 - REMU
141
logic                                       div_cmd_div;        // DIV command is DIV
142
logic                                       div_cmd_rem;        // DIV command is REM(U)
143
 
144
// Multiplier signals
145
logic                                       mul_op1_is_sgn;     // First MUL operand is signed
146
logic                                       mul_op2_is_sgn;     // Second MUL operand is signed
147
logic                                       mul_op1_sgn;        // First MUL operand is negative
148
logic                                       mul_op2_sgn;        // Second MUL operand is negative
149
logic signed [`SCR1_XLEN:0]                 mul_op1;            // MUL operand 1
150
logic signed [SCR1_MUL_WIDTH:0]             mul_op2;            // MUL operand 1
151
 `ifdef SCR1_FAST_MUL
152
logic signed [SCR1_MUL_RES_WIDTH-1:0]       mul_res;            // MUL result
153
 `else // ~SCR1_FAST_MUL
154
logic signed [SCR1_MDU_SUM_WIDTH:0]         mul_part_prod;
155
logic        [`SCR1_XLEN-1:0]               mul_res_hi;
156
logic        [`SCR1_XLEN-1:0]               mul_res_lo;
157
 `endif // ~SCR1_FAST_MUL
158
 
159
// Divisor signals
160
logic                                       div_ops_are_sgn;
161
logic                                       div_op1_is_neg;
162
logic                                       div_op2_is_neg;
163
logic                                       div_res_rem_c;
164
logic        [`SCR1_XLEN-1:0]               div_res_rem;
165
logic        [`SCR1_XLEN-1:0]               div_res_quo;
166
logic                                       div_quo_bit;
167
logic                                       div_dvdnd_lo_upd;
168
logic        [`SCR1_XLEN-1:0]               div_dvdnd_lo_ff;
169
logic        [`SCR1_XLEN-1:0]               div_dvdnd_lo_next;
170
 
171
// MDU adder signals
172
logic                                       mdu_sum_sub;        // MDU adder operation: 0 - add, 1 - sub
173
logic signed [SCR1_MDU_SUM_WIDTH-1:0]       mdu_sum_op1;        // MDU adder operand 1
174
logic signed [SCR1_MDU_SUM_WIDTH-1:0]       mdu_sum_op2;        // MDU adder operand 2
175
logic signed [SCR1_MDU_SUM_WIDTH-1:0]       mdu_sum_res;        // MDU adder result
176
 
177
// MDU iteration counter signals
178
logic                                       mdu_iter_cnt_en;
179
logic        [`SCR1_XLEN-1:0]               mdu_iter_cnt;
180
logic        [`SCR1_XLEN-1:0]               mdu_iter_cnt_next;
181
 
182
// Intermediate results registers
183
logic                                       mdu_res_upd;
184
logic                                       mdu_res_c_ff;
185
logic                                       mdu_res_c_next;
186
logic        [`SCR1_XLEN-1:0]               mdu_res_hi_ff;
187
logic        [`SCR1_XLEN-1:0]               mdu_res_hi_next;
188
logic        [`SCR1_XLEN-1:0]               mdu_res_lo_ff;
189
logic        [`SCR1_XLEN-1:0]               mdu_res_lo_next;
190
`endif // SCR1_RVM_EXT
191
 
192
//-------------------------------------------------------------------------------
193
// Main adder
194
//-------------------------------------------------------------------------------
195
//
196
 // Main adder is used for the following types of operations:
197
 // - Addition/subtraction          (ADD/ADDI/SUB)
198
 // - Branch comparisons            (BEQ/BNE/BLT(U)/BGE(U))
199
 // - Arithmetic comparisons        (SLT(U)/SLTI(U))
200
//
201
 
202
// Carry out (MSB of main_sum_res) is evaluated correctly because the result
203
// width equals to the maximum width of both the right-hand and left-hand side variables
204
always_comb begin
205
    main_sum_res = (exu2ialu_cmd_i != SCR1_IALU_CMD_ADD)
206
                 ? (exu2ialu_main_op1_i - exu2ialu_main_op2_i)   // Subtraction and comparison
207
                 : (exu2ialu_main_op1_i + exu2ialu_main_op2_i);  // Addition
208
 
209
    main_sum_pos_ovflw = ~exu2ialu_main_op1_i[`SCR1_XLEN-1]
210
                       &  exu2ialu_main_op2_i[`SCR1_XLEN-1]
211
                       &  main_sum_res[`SCR1_XLEN-1];
212
    main_sum_neg_ovflw =  exu2ialu_main_op1_i[`SCR1_XLEN-1]
213
                       & ~exu2ialu_main_op2_i[`SCR1_XLEN-1]
214
                       & ~main_sum_res[`SCR1_XLEN-1];
215
 
216
    // FLAGS1 - flags for comparison (result of subtraction)
217
    main_sum_flags.c = main_sum_res[`SCR1_XLEN];
218
    main_sum_flags.z = ~|main_sum_res[`SCR1_XLEN-1:0];
219
    main_sum_flags.s = main_sum_res[`SCR1_XLEN-1];
220
    main_sum_flags.o = main_sum_pos_ovflw | main_sum_neg_ovflw;
221
end
222
 
223
//-------------------------------------------------------------------------------
224
// Address adder
225
//-------------------------------------------------------------------------------
226
//
227
 // Additional adder is used for the following types of operations:
228
 // - PC-based address calculation          (AUIPC)
229
 // - IMEM branch address calculation       (BEQ/BNE/BLT(U)/BGE(U))
230
 // - IMEM jump address calculation         (JAL/JALR)
231
 // - DMEM load address calculation         (LB(U)/LH(U)/LW)
232
 // - DMEM store address calculation        (SB/SH/SW)
233
//
234
 
235
assign ialu2exu_addr_res_o = exu2ialu_addr_op1_i + exu2ialu_addr_op2_i;
236
 
237
//-------------------------------------------------------------------------------
238
// Shift logic
239
//-------------------------------------------------------------------------------
240
 //
241
 // Shift logic supports the following types of shift operations:
242
 // - Logical left shift      (SLLI/SLL)
243
 // - Logical right shift     (SRLI/SRL)
244
 // - Arithmetic right shift  (SRAI/SRA)
245
//
246
 
247
assign ialu_cmd_shft = (exu2ialu_cmd_i == SCR1_IALU_CMD_SLL)
248
                     | (exu2ialu_cmd_i == SCR1_IALU_CMD_SRL)
249
                     | (exu2ialu_cmd_i == SCR1_IALU_CMD_SRA);
250
assign shft_cmd      = ialu_cmd_shft
251
                     ? {(exu2ialu_cmd_i != SCR1_IALU_CMD_SLL),
252
                        (exu2ialu_cmd_i == SCR1_IALU_CMD_SRA)}
253
                     : 2'b00;
254
 
255
always_comb begin
256
    shft_op1 = exu2ialu_main_op1_i;
257
    shft_op2 = exu2ialu_main_op2_i[4:0];
258
    case (shft_cmd)
259
        2'b10   : shft_res = shft_op1  >> shft_op2;
260
        2'b11   : shft_res = shft_op1 >>> shft_op2;
261
        default : shft_res = shft_op1  << shft_op2;
262
    endcase
263
end
264
 
265
`ifdef SCR1_RVM_EXT
266
//-------------------------------------------------------------------------------
267
// MUL/DIV logic
268
//-------------------------------------------------------------------------------
269
//
270
 // MUL/DIV instructions use the following functional units:
271
 // - MUL/DIV FSM control logic, including iteration number counter
272
 // - MUL/DIV FSM
273
 // - MUL logic
274
 // - DIV logic
275
 // - MDU adder to produce an intermediate result
276
 // - 2 registers to save the intermediate result (shared between MUL and DIV
277
 //   operations)
278
//
279
 
280
//-------------------------------------------------------------------------------
281
// MUL/DIV FSM Control logic
282
//-------------------------------------------------------------------------------
283
 
284
assign mdu_cmd_div = (exu2ialu_cmd_i == SCR1_IALU_CMD_DIV)
285
                   | (exu2ialu_cmd_i == SCR1_IALU_CMD_DIVU)
286
                   | (exu2ialu_cmd_i == SCR1_IALU_CMD_REM)
287
                   | (exu2ialu_cmd_i == SCR1_IALU_CMD_REMU);
288
assign mdu_cmd_mul = (exu2ialu_cmd_i == SCR1_IALU_CMD_MUL)
289
                   | (exu2ialu_cmd_i == SCR1_IALU_CMD_MULH)
290
                   | (exu2ialu_cmd_i == SCR1_IALU_CMD_MULHU)
291
                   | (exu2ialu_cmd_i == SCR1_IALU_CMD_MULHSU);
292
 
293
assign mdu_cmd     = mdu_cmd_div ? SCR1_IALU_MDU_DIV
294
                   : mdu_cmd_mul ? SCR1_IALU_MDU_MUL
295
                                 : SCR1_IALU_MDU_NONE;
296
 
297
assign main_ops_non_zero = |exu2ialu_main_op1_i & |exu2ialu_main_op2_i;
298
assign main_ops_diff_sgn = exu2ialu_main_op1_i[`SCR1_XLEN-1]
299
                         ^ exu2ialu_main_op2_i[`SCR1_XLEN-1];
300
 
301
 `ifdef SCR1_FAST_MUL
302
    assign mdu_cmd_is_iter = mdu_cmd_div;
303
 `else // ~SCR1_FAST_MUL
304
    assign mdu_cmd_is_iter = mdu_cmd_mul | mdu_cmd_div;
305
 `endif // ~SCR1_FAST_MUL
306
 
307
assign mdu_iter_req = mdu_cmd_is_iter ? (main_ops_non_zero & mdu_fsm_idle) : 1'b0;
308
assign mdu_iter_rdy = mdu_iter_cnt[0];
309
 
310
assign div_cmd_div = (div_cmd == 2'b00);
311
assign div_cmd_rem = div_cmd[1];
312
 
313
// Correction request signals
314
assign div_corr_req = div_cmd_div & main_ops_diff_sgn;
315
assign rem_corr_req = div_cmd_rem & |div_res_rem & (div_op1_is_neg ^ div_res_rem_c);
316
assign mdu_corr_req = mdu_cmd_div & (div_corr_req | rem_corr_req);
317
 
318
// MDU iteration counter
319
//------------------------------------------------------------------------------
320
 
321
assign mdu_iter_cnt_en = exu2ialu_rvm_cmd_vd_i & ~ialu2exu_rvm_res_rdy_o;
322
 
323
always_ff @(posedge clk) begin
324
    if (mdu_iter_cnt_en) begin
325
        mdu_iter_cnt <= mdu_iter_cnt_next;
326
    end
327
end
328
 
329
assign mdu_iter_cnt_next = ~mdu_fsm_idle ? mdu_iter_cnt >> 1
330
                         : mdu_cmd_div   ? SCR1_DIV_CNT_INIT
331
 `ifndef SCR1_FAST_MUL
332
                         : mdu_cmd_mul   ? SCR1_MUL_CNT_INIT
333
 `endif // ~SCR1_FAST_MUL
334
                                         : mdu_iter_cnt;
335
 
336
//-------------------------------------------------------------------------------
337
// MUL/DIV FSM
338
//-------------------------------------------------------------------------------
339
 
340
always_ff @(posedge clk, negedge rst_n) begin
341
    if (~rst_n) begin
342
        mdu_fsm_ff <= SCR1_IALU_MDU_FSM_IDLE;
343
    end else begin
344
        mdu_fsm_ff <= mdu_fsm_next;
345
    end
346
end
347
 
348
always_comb begin
349
    mdu_fsm_next = SCR1_IALU_MDU_FSM_IDLE;
350
 
351
    if (exu2ialu_rvm_cmd_vd_i) begin
352
        case (mdu_fsm_ff)
353
            SCR1_IALU_MDU_FSM_IDLE : begin
354
                mdu_fsm_next = mdu_iter_req  ? SCR1_IALU_MDU_FSM_ITER
355
                                             : SCR1_IALU_MDU_FSM_IDLE;
356
            end
357
            SCR1_IALU_MDU_FSM_ITER : begin
358
                mdu_fsm_next = ~mdu_iter_rdy ? SCR1_IALU_MDU_FSM_ITER
359
                             : mdu_corr_req  ? SCR1_IALU_MDU_FSM_CORR
360
                                             : SCR1_IALU_MDU_FSM_IDLE;
361
            end
362
            SCR1_IALU_MDU_FSM_CORR : begin
363
                mdu_fsm_next = SCR1_IALU_MDU_FSM_IDLE;
364
            end
365
        endcase
366
    end
367
end
368
 
369
assign mdu_fsm_idle = (mdu_fsm_ff == SCR1_IALU_MDU_FSM_IDLE);
370
`ifdef SCR1_TRGT_SIMULATION
371
assign mdu_fsm_iter = (mdu_fsm_ff == SCR1_IALU_MDU_FSM_ITER);
372
`endif // SCR1_TRGT_SIMULATION
373
assign mdu_fsm_corr = (mdu_fsm_ff == SCR1_IALU_MDU_FSM_CORR);
374
 
375
//-------------------------------------------------------------------------------
376
// Multiplier logic
377
//-------------------------------------------------------------------------------
378
//
379
 // Multiplication has 2 options: fast (1 cycle) and Radix-2 (32 cycles) multiplication.
380
 //
381
 // 1. Fast multiplication uses the straightforward approach when 2 operands are
382
 // multiplied in one cycle
383
 //
384
 // 2. Radix-2 multiplication uses 2 registers (high and low part of multiplication)
385
 //
386
 // Radix-2 algorithm:
387
 // 1. Initialize registers
388
 // 2. Create a partial product by multiplying multiplicand by the LSB of multiplier
389
 // 3. Add the partial product to the previous (intermediate) value of multiplication
390
 //    result (stored into high and low parts of multiplication result register)
391
 // 4. Shift the low part of multiplication result register right
392
 // 4. Store the addition result into the high part of multiplication result register
393
 // 6. If iteration is not ready, go to step 2. Otherwise multiplication is done
394
 //
395
//
396
 
397
assign mul_cmd  = {((exu2ialu_cmd_i == SCR1_IALU_CMD_MULHU) | (exu2ialu_cmd_i == SCR1_IALU_CMD_MULHSU)),
398
                   ((exu2ialu_cmd_i == SCR1_IALU_CMD_MULHU) | (exu2ialu_cmd_i == SCR1_IALU_CMD_MULH))};
399
 
400
assign mul_cmd_hi     = |mul_cmd;
401
assign mul_op1_is_sgn = ~&mul_cmd;
402
assign mul_op2_is_sgn = ~mul_cmd[1];
403
assign mul_op1_sgn    = mul_op1_is_sgn & exu2ialu_main_op1_i[`SCR1_XLEN-1];
404
assign mul_op2_sgn    = mul_op2_is_sgn & exu2ialu_main_op2_i[`SCR1_XLEN-1];
405
 
406
`ifdef SCR1_FAST_MUL
407
assign mul_op1 = mdu_cmd_mul ? $signed({mul_op1_sgn, exu2ialu_main_op1_i}) : '0;
408
assign mul_op2 = mdu_cmd_mul ? $signed({mul_op2_sgn, exu2ialu_main_op2_i}) : '0;
409
assign mul_res = mdu_cmd_mul ? mul_op1 * mul_op2                           : 'sb0;
410
`else // ~SCR1_FAST_MUL
411
assign mul_op1 = mdu_cmd_mul  ? $signed({mul_op1_sgn, exu2ialu_main_op1_i}) : '0;
412
assign mul_op2 = ~mdu_cmd_mul ? '0
413
               : mdu_fsm_idle ? $signed({1'b0, exu2ialu_main_op2_i[SCR1_MUL_WIDTH-1:0]})
414
                              : $signed({(mdu_iter_cnt[0] & mul_op2_is_sgn & mdu_res_lo_ff[SCR1_MUL_WIDTH-1]),
415
                                          mdu_res_lo_ff[SCR1_MUL_WIDTH-1:0]});
416
 
417
assign mul_part_prod            = mdu_cmd_mul  ? mul_op1 * mul_op2 : 'sb0;
418
assign {mul_res_hi, mul_res_lo} = ~mdu_cmd_mul ? '0
419
                                : mdu_fsm_idle ? ({mdu_sum_res, exu2ialu_main_op2_i[`SCR1_XLEN-1:SCR1_MUL_WIDTH]})
420
                                               : ({mdu_sum_res, mdu_res_lo_ff[`SCR1_XLEN-1:SCR1_MUL_WIDTH]});
421
`endif // ~SCR1_FAST_MUL
422
 
423
//-------------------------------------------------------------------------------
424
// Divider logic
425
//-------------------------------------------------------------------------------
426
//
427
 // Division uses a non-restoring algorithm. 3 registers are used:
428
 // - Remainder register
429
 // - Quotient register
430
 // - Dividend low part register (for corner case quotient bit calculation)
431
 //
432
 // Algorithm:
433
 // 1. Initialize registers
434
 // 2. Shift remainder and dividend low part registers left
435
 // 3. Compare remainder register with the divisor (taking previous quotient bit
436
 //    and operands signs into account) and calculate quotient bit based on the
437
 //    comparison results
438
 // 4. Shift quotient register left, append quotient bit to the quotient register
439
 // 5. If iteration is not ready, go to step 2. Otherwise go to step 6
440
 // 6. Do correction if necessary, otherwise division is done
441
 //
442
 // Quotient bit calculation has a corner case:
443
 // When dividend is negative result carry bit check takes into account only
444
 // the case of remainder register been greater than divisor. To handle
445
 // equality case we should check if both the comparison result and the
446
 // lower part of dividend are zero
447
//
448
 
449
assign div_cmd  = {((exu2ialu_cmd_i == SCR1_IALU_CMD_REM)   | (exu2ialu_cmd_i == SCR1_IALU_CMD_REMU)),
450
                   ((exu2ialu_cmd_i == SCR1_IALU_CMD_REMU)  | (exu2ialu_cmd_i == SCR1_IALU_CMD_DIVU))};
451
 
452
assign div_ops_are_sgn = ~div_cmd[0];
453
assign div_op1_is_neg  = div_ops_are_sgn & exu2ialu_main_op1_i[`SCR1_XLEN-1];
454
assign div_op2_is_neg  = div_ops_are_sgn & exu2ialu_main_op2_i[`SCR1_XLEN-1];
455
 
456
always_comb begin
457
    div_res_rem_c = '0;
458
    div_res_rem   = '0;
459
    div_res_quo   = '0;
460
    div_quo_bit   = 1'b0;
461
    if (mdu_cmd_div & ~mdu_fsm_corr) begin
462
        div_res_rem_c = mdu_sum_res[SCR1_MDU_SUM_WIDTH-1];
463
        div_res_rem   = mdu_sum_res[SCR1_MDU_SUM_WIDTH-2:0];
464
        div_quo_bit   = ~(div_op1_is_neg ^ div_res_rem_c)
465
                      | (div_op1_is_neg & ({mdu_sum_res, div_dvdnd_lo_next} == '0));
466
        div_res_quo   = mdu_fsm_idle
467
                      ? {'0, div_quo_bit}
468
                      : {mdu_res_lo_ff[`SCR1_XLEN-2:0], div_quo_bit};
469
    end
470
end
471
 
472
// Dividend low part register
473
//------------------------------------------------------------------------------
474
 
475
assign div_dvdnd_lo_upd = exu2ialu_rvm_cmd_vd_i & ~ialu2exu_rvm_res_rdy_o;
476
 
477
always_ff @(posedge clk) begin
478
    if (div_dvdnd_lo_upd) begin
479
        div_dvdnd_lo_ff <= div_dvdnd_lo_next;
480
    end
481
end
482
 
483
assign div_dvdnd_lo_next = (~mdu_cmd_div | mdu_fsm_corr) ? '0
484
                         : mdu_fsm_idle                  ? exu2ialu_main_op1_i << 1
485
                                                         : div_dvdnd_lo_ff     << 1;
486
 
487
//-------------------------------------------------------------------------------
488
// MDU adder
489
//-------------------------------------------------------------------------------
490
logic           sgn;
491
logic           inv;
492
 
493
always_comb begin
494
    mdu_sum_sub    = 1'b0;
495
    mdu_sum_op1    = '0;
496
    mdu_sum_op2    = '0;
497
    sgn            = '0; // yosys - latch fix
498
    inv            = '0; // yosys - latch fix
499
    case (mdu_cmd)
500
        SCR1_IALU_MDU_DIV : begin
501
            sgn         = mdu_fsm_corr ? div_op1_is_neg ^ mdu_res_c_ff
502
                        : mdu_fsm_idle ? 1'b0
503
                                       : ~mdu_res_lo_ff[0];
504
            inv         = div_ops_are_sgn & main_ops_diff_sgn;
505
            mdu_sum_sub = ~inv ^ sgn;
506
            mdu_sum_op1 = mdu_fsm_corr ? $signed({1'b0, mdu_res_hi_ff})
507
                        : mdu_fsm_idle ? $signed({div_op1_is_neg, exu2ialu_main_op1_i[`SCR1_XLEN-1]})
508
                                       : $signed({mdu_res_hi_ff, div_dvdnd_lo_ff[`SCR1_XLEN-1]});
509
            mdu_sum_op2 = $signed({div_op2_is_neg, exu2ialu_main_op2_i});
510
        end
511
`ifndef SCR1_FAST_MUL
512
        SCR1_IALU_MDU_MUL : begin
513
            mdu_sum_op1 = mdu_fsm_idle
514
                        ? '0
515
                        : $signed({(mul_op1_is_sgn & mdu_res_hi_ff[`SCR1_XLEN-1]), mdu_res_hi_ff});
516
            mdu_sum_op2 = mul_part_prod;
517
        end
518
`endif // SCR1_FAST_MUL
519
        default : begin end
520
    endcase
521
    mdu_sum_res = mdu_sum_sub
522
                ? (mdu_sum_op1 - mdu_sum_op2)
523
                : (mdu_sum_op1 + mdu_sum_op2);
524
end
525
 
526
//-------------------------------------------------------------------------------
527
// MUL/DIV intermediate results registers
528
//-------------------------------------------------------------------------------
529
 
530
assign mdu_res_upd = exu2ialu_rvm_cmd_vd_i & ~ialu2exu_rvm_res_rdy_o;
531
 
532
always_ff @(posedge clk) begin
533
    if (mdu_res_upd) begin
534
        mdu_res_c_ff  <= mdu_res_c_next;
535
        mdu_res_hi_ff <= mdu_res_hi_next;
536
        mdu_res_lo_ff <= mdu_res_lo_next;
537
    end
538
end
539
 
540
assign mdu_res_c_next  = mdu_cmd_div ? div_res_rem_c : mdu_res_c_ff;
541
assign mdu_res_hi_next = mdu_cmd_div ? div_res_rem
542
 `ifndef SCR1_FAST_MUL
543
                       : mdu_cmd_mul ? mul_res_hi
544
 `endif // SCR1_FAST_MUL
545
                                     : mdu_res_hi_ff;
546
assign mdu_res_lo_next = mdu_cmd_div ? div_res_quo
547
 `ifndef SCR1_FAST_MUL
548
                       : mdu_cmd_mul ? mul_res_lo
549
 `endif // SCR1_FAST_MUL
550
                                     : mdu_res_lo_ff;
551
`endif // SCR1_RVM_EXT
552
 
553
//-------------------------------------------------------------------------------
554
// Operation result forming
555
//-------------------------------------------------------------------------------
556
 
557
always_comb begin
558
    ialu2exu_main_res_o    = '0;
559
    ialu2exu_cmp_res_o     = 1'b0;
560
`ifdef SCR1_RVM_EXT
561
    ialu2exu_rvm_res_rdy_o = 1'b1;
562
`endif // SCR1_RVM_EXT
563
 
564
    case (exu2ialu_cmd_i)
565
        SCR1_IALU_CMD_AND : begin
566
            ialu2exu_main_res_o = exu2ialu_main_op1_i & exu2ialu_main_op2_i;
567
        end
568
        SCR1_IALU_CMD_OR : begin
569
            ialu2exu_main_res_o = exu2ialu_main_op1_i | exu2ialu_main_op2_i;
570
        end
571
        SCR1_IALU_CMD_XOR : begin
572
            ialu2exu_main_res_o = exu2ialu_main_op1_i ^ exu2ialu_main_op2_i;
573
        end
574
        SCR1_IALU_CMD_ADD : begin
575
            ialu2exu_main_res_o = main_sum_res[`SCR1_XLEN-1:0];
576
        end
577
        SCR1_IALU_CMD_SUB : begin
578
            ialu2exu_main_res_o = main_sum_res[`SCR1_XLEN-1:0];
579
        end
580
        SCR1_IALU_CMD_SUB_LT : begin
581
            ialu2exu_main_res_o = `SCR1_XLEN'(main_sum_flags.s ^ main_sum_flags.o);
582
            ialu2exu_cmp_res_o  = main_sum_flags.s ^ main_sum_flags.o;
583
        end
584
        SCR1_IALU_CMD_SUB_LTU : begin
585
            ialu2exu_main_res_o = `SCR1_XLEN'(main_sum_flags.c);
586
            ialu2exu_cmp_res_o  = main_sum_flags.c;
587
        end
588
        SCR1_IALU_CMD_SUB_EQ : begin
589
            ialu2exu_main_res_o = `SCR1_XLEN'(main_sum_flags.z);
590
            ialu2exu_cmp_res_o  = main_sum_flags.z;
591
        end
592
        SCR1_IALU_CMD_SUB_NE : begin
593
            ialu2exu_main_res_o = `SCR1_XLEN'(~main_sum_flags.z);
594
            ialu2exu_cmp_res_o  = ~main_sum_flags.z;
595
        end
596
        SCR1_IALU_CMD_SUB_GE : begin
597
            ialu2exu_main_res_o = `SCR1_XLEN'(~(main_sum_flags.s ^ main_sum_flags.o));
598
            ialu2exu_cmp_res_o  = ~(main_sum_flags.s ^ main_sum_flags.o);
599
        end
600
        SCR1_IALU_CMD_SUB_GEU : begin
601
            ialu2exu_main_res_o = `SCR1_XLEN'(~main_sum_flags.c);
602
            ialu2exu_cmp_res_o  = ~main_sum_flags.c;
603
        end
604
        SCR1_IALU_CMD_SLL,
605
        SCR1_IALU_CMD_SRL,
606
        SCR1_IALU_CMD_SRA: begin
607
            ialu2exu_main_res_o = shft_res;
608
        end
609
`ifdef SCR1_RVM_EXT
610
        SCR1_IALU_CMD_MUL,
611
        SCR1_IALU_CMD_MULHU,
612
        SCR1_IALU_CMD_MULHSU,
613
        SCR1_IALU_CMD_MULH : begin
614
 `ifdef SCR1_FAST_MUL
615
            ialu2exu_main_res_o = mul_cmd_hi
616
                                ? mul_res[SCR1_MUL_RES_WIDTH-1:`SCR1_XLEN]
617
                                : mul_res[`SCR1_XLEN-1:0];
618
 `else // ~SCR1_FAST_MUL
619
            case (mdu_fsm_ff)
620
                SCR1_IALU_MDU_FSM_IDLE : begin
621
                    ialu2exu_main_res_o    = '0;
622
                    ialu2exu_rvm_res_rdy_o = ~mdu_iter_req;
623
                end
624
                SCR1_IALU_MDU_FSM_ITER : begin
625
                    ialu2exu_main_res_o    = mul_cmd_hi ? mul_res_hi : mul_res_lo;
626
                    ialu2exu_rvm_res_rdy_o = mdu_iter_rdy;
627
                end
628
            endcase
629
 `endif // ~SCR1_FAST_MUL
630
        end
631
        SCR1_IALU_CMD_DIV,
632
        SCR1_IALU_CMD_DIVU,
633
        SCR1_IALU_CMD_REM,
634
        SCR1_IALU_CMD_REMU : begin
635
            case (mdu_fsm_ff)
636
                SCR1_IALU_MDU_FSM_IDLE : begin
637
                    ialu2exu_main_res_o    = (|exu2ialu_main_op2_i | div_cmd_rem)
638
                                           ? exu2ialu_main_op1_i
639
                                           : '1;
640
                    ialu2exu_rvm_res_rdy_o = ~mdu_iter_req;
641
                end
642
                SCR1_IALU_MDU_FSM_ITER : begin
643
                    ialu2exu_main_res_o    = div_cmd_rem ? div_res_rem : div_res_quo;
644
                    ialu2exu_rvm_res_rdy_o = mdu_iter_rdy & ~mdu_corr_req;
645
                end
646
                SCR1_IALU_MDU_FSM_CORR : begin
647
                    ialu2exu_main_res_o    = div_cmd_rem
648
                                           ? mdu_sum_res[`SCR1_XLEN-1:0]
649
                                           : -mdu_res_lo_ff[`SCR1_XLEN-1:0];
650
                    ialu2exu_rvm_res_rdy_o = 1'b1;
651
                end
652
            endcase
653
        end
654
`endif // SCR1_RVM_EXT
655
        default : begin end
656
    endcase
657
end
658
 
659
 
660
`ifdef SCR1_TRGT_SIMULATION
661
//-------------------------------------------------------------------------------
662
// Assertion
663
//-------------------------------------------------------------------------------
664
 
665
`ifdef SCR1_RVM_EXT
666
 
667
// X checks
668
 
669
SCR1_SVA_IALU_XCHECK : assert property (
670
    @(negedge clk) disable iff (~rst_n)
671
    !$isunknown({exu2ialu_rvm_cmd_vd_i, mdu_fsm_ff})
672
    ) else $error("IALU Error: unknown values");
673
 
674
SCR1_SVA_IALU_XCHECK_QUEUE : assert property (
675
    @(negedge clk) disable iff (~rst_n)
676
    exu2ialu_rvm_cmd_vd_i |->
677
    !$isunknown({exu2ialu_main_op1_i, exu2ialu_main_op2_i, exu2ialu_cmd_i})
678
    ) else $error("IALU Error: unknown values in queue");
679
 
680
// Behavior checks
681
 
682
SCR1_SVA_IALU_ILL_STATE : assert property (
683
    @(negedge clk) disable iff (~rst_n)
684
    $onehot0({~exu2ialu_rvm_cmd_vd_i, mdu_fsm_iter, mdu_fsm_corr})
685
    ) else $error("IALU Error: illegal state");
686
 
687
`ifndef VERILATOR
688
SCR1_SVA_IALU_JUMP_FROM_IDLE : assert property (
689
    @(negedge clk) disable iff (~rst_n)
690
    (mdu_fsm_idle & (~exu2ialu_rvm_cmd_vd_i | ~mdu_iter_req)) |=> mdu_fsm_idle
691
    ) else $error("EXU Error: illegal jump from IDLE state");
692
 
693
SCR1_SVA_IALU_IDLE_TO_ITER : assert property (
694
    @(negedge clk) disable iff (~rst_n)
695
    (mdu_fsm_idle & exu2ialu_rvm_cmd_vd_i & mdu_iter_req) |=> mdu_fsm_iter
696
    ) else $error("EXU Error: illegal change state form IDLE to ITER");
697
 
698
SCR1_SVA_IALU_JUMP_FROM_ITER : assert property (
699
    @(negedge clk) disable iff (~rst_n)
700
    (mdu_fsm_iter & ~mdu_iter_rdy) |=> mdu_fsm_iter
701
    ) else $error("EXU Error: illegal jump from ITER state");
702
 
703
SCR1_SVA_IALU_ITER_TO_IDLE : assert property (
704
    @(negedge clk) disable iff (~rst_n)
705
    (mdu_fsm_iter & mdu_iter_rdy & ~mdu_corr_req) |=> mdu_fsm_idle
706
    ) else $error("EXU Error: illegal state change ITER to IDLE");
707
 
708
SCR1_SVA_IALU_ITER_TO_CORR : assert property (
709
    @(negedge clk) disable iff (~rst_n)
710
    (mdu_fsm_iter & mdu_iter_rdy & mdu_corr_req) |=> mdu_fsm_corr
711
    ) else $error("EXU Error: illegal state change ITER to CORR");
712
 
713
SCR1_SVA_IALU_CORR_TO_IDLE : assert property (
714
    @(negedge clk) disable iff (~rst_n)
715
    mdu_fsm_corr |=> mdu_fsm_idle
716
    ) else $error("EXU Error: illegal state stay in CORR");
717
`endif // VERILATOR
718
 
719
`endif // SCR1_RVM_EXT
720
 
721
`endif // SCR1_TRGT_SIMULATION
722
 
723
endmodule : scr1_pipe_ialu

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.