SHOW:
|
|
- or go back to the newest paste.
1 | `timescale 1ns / 1ps | |
2 | module div #( | |
3 | parameter int unsigned DATA_WIDTH = 32 | |
4 | ) ( | |
5 | input logic clk, | |
6 | input logic rst_n, | |
7 | input logic [DATA_WIDTH-1:0] dividend, | |
8 | input logic [DATA_WIDTH-1:0] divisor, | |
9 | input logic signed_ope, | |
10 | input logic start, | |
11 | input logic flush, | |
12 | output logic [DATA_WIDTH-1:0] quotient, | |
13 | output logic [DATA_WIDTH-1:0] remainder, | |
14 | output logic ready | |
15 | ); | |
16 | localparam int unsigned D1 = 1; | |
17 | localparam int unsigned COUNT_WIDTH = $clog2(DATA_WIDTH + 1); | |
18 | ||
19 | logic r_ready; | |
20 | logic r_signed_ope; | |
21 | logic [COUNT_WIDTH-1:0] r_count; | |
22 | logic [DATA_WIDTH-1:0] r_quotient; | |
23 | logic w_dividend_sign; | |
24 | logic r_dividend_sign; | |
25 | logic remainder_sign; | |
26 | logic [DATA_WIDTH:0] r_remainder; | |
27 | logic [DATA_WIDTH-1:0] r_divisor; | |
28 | logic [DATA_WIDTH:0] divisor_ext; | |
29 | logic divisor_sign; | |
30 | logic [DATA_WIDTH:0] rem_quo; | |
31 | logic diff_sign; | |
32 | logic [DATA_WIDTH:0] sub_add; | |
33 | ||
34 | assign ready = r_ready; | |
35 | ||
36 | assign divisor_sign = r_divisor[DATA_WIDTH-1] & r_signed_ope; | |
37 | assign divisor_ext = {divisor_sign, r_divisor}; | |
38 | assign remainder_sign = r_remainder[DATA_WIDTH]; | |
39 | ||
40 | assign rem_quo = {r_remainder[DATA_WIDTH-1:0], r_quotient[DATA_WIDTH-1]}; | |
41 | assign diff_sign = remainder_sign ^ divisor_sign; | |
42 | assign sub_add = diff_sign ? rem_quo + divisor_ext : | |
43 | rem_quo - divisor_ext; | |
44 | ||
45 | // after process | |
46 | always_comb begin | |
47 | quotient = (r_quotient << 1) | 1; | |
48 | remainder = r_remainder[DATA_WIDTH-1:0]; | |
49 | ||
50 | if (r_remainder == 0) begin | |
51 | // do nothing | |
52 | end else if (r_remainder == divisor_ext) begin | |
53 | quotient = quotient + 1; | |
54 | remainder = remainder - r_divisor; | |
55 | end else if (r_remainder == -divisor_ext) begin | |
56 | quotient = quotient - 1; | |
57 | remainder = remainder + r_divisor; | |
58 | end else if (remainder_sign ^ r_dividend_sign) begin | |
59 | if (diff_sign) begin | |
60 | quotient = quotient - 1; | |
61 | remainder = remainder + r_divisor; | |
62 | end else begin | |
63 | quotient = quotient + 1; | |
64 | remainder = remainder - r_divisor; | |
65 | end | |
66 | end | |
67 | end | |
68 | ||
69 | assign w_dividend_sign = dividend[DATA_WIDTH-1] & signed_ope; | |
70 | ||
71 | always @(posedge clk or negedge rst_n) begin | |
72 | if (~rst_n) begin | |
73 | r_quotient <= #D1 '0; | |
74 | r_dividend_sign <= #D1 '0; | |
75 | r_remainder <= #D1 '0; | |
76 | r_divisor <= #D1 '0; | |
77 | r_count <= #D1 '0; | |
78 | r_ready <= #D1 1'b1; | |
79 | r_signed_ope <= #D1 1'b0; | |
80 | end else begin | |
81 | if (flush) begin | |
82 | r_count <= #D1 '0; | |
83 | r_ready <= #D1 1'b1; | |
84 | end else if (start) begin | |
85 | // RISC-V's div by 0 spec | |
86 | if (divisor == '0) begin | |
87 | r_quotient <= #D1 '1; | |
88 | r_remainder <= #D1 {w_dividend_sign, dividend}; | |
89 | end else begin | |
90 | r_quotient <= #D1 dividend; | |
91 | r_remainder <= #D1 {(DATA_WIDTH+1){w_dividend_sign}}; | |
92 | r_ready <= #D1 1'b0; | |
93 | end | |
94 | r_count <= #D1 '0; | |
95 | r_dividend_sign <= #D1 w_dividend_sign; | |
96 | r_divisor <= #D1 divisor; | |
97 | r_signed_ope <= #D1 signed_ope; | |
98 | end else if (~ready) begin | |
99 | r_quotient <= #D1 {r_quotient[DATA_WIDTH-2:0], ~diff_sign}; | |
100 | r_remainder <= #D1 sub_add[DATA_WIDTH:0]; | |
101 | r_count <= #D1 r_count + 1; | |
102 | if (r_count == DATA_WIDTH - 1) begin | |
103 | r_ready <= #D1 1'b1; | |
104 | end | |
105 | end | |
106 | end | |
107 | end | |
108 | endmodule | |
109 | ||
110 |