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

Subversion Repositories zipcpu

[/] [zipcpu/] [trunk/] [rtl/] [core/] [div.v] - Blame information for rev 160

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 69 dgisselq
///////////////////////////////////////////////////////////////////////////////
2
//
3
// Filename:    div.v
4
//
5
// Project:     Zip CPU -- a small, lightweight, RISC CPU soft core
6
//
7
// Purpose:     Provide an Integer divide capability to the Zip CPU.
8
//
9
//
10
// Creator:     Dan Gisselquist, Ph.D.
11
//              Gisselquist Technology, LLC
12
//
13
///////////////////////////////////////////////////////////////////////////////
14
//
15 160 dgisselq
// Copyright (C) 2015-2016, Gisselquist Technology, LLC
16 69 dgisselq
//
17
// This program is free software (firmware): you can redistribute it and/or
18
// modify it under the terms of  the GNU General Public License as published
19
// by the Free Software Foundation, either version 3 of the License, or (at
20
// your option) any later version.
21
//
22
// This program is distributed in the hope that it will be useful, but WITHOUT
23
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
24
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
25
// for more details.
26
//
27
// License:     GPL, v3, as defined and found on www.gnu.org,
28
//              http://www.gnu.org/licenses/gpl.html
29
//
30
//
31
///////////////////////////////////////////////////////////////////////////////
32
//
33
// `include "cpudefs.v"
34
//
35
module  div(i_clk, i_rst, i_wr, i_signed, i_numerator, i_denominator,
36
                o_busy, o_valid, o_err, o_quotient, o_flags);
37
        parameter       BW=32, LGBW = 5;
38
        input           i_clk, i_rst;
39
        // Input parameters
40
        input                   i_wr, i_signed;
41
        input   [(BW-1):0]       i_numerator, i_denominator;
42
        // Output parameters
43
        output  reg             o_busy, o_valid, o_err;
44
        output  reg [(BW-1):0]   o_quotient;
45
        output  wire    [3:0]    o_flags;
46
 
47 160 dgisselq
        // r_busy is an internal busy register.  It will clear one clock
48
        // before we are valid, so it can't be o_busy ...
49
        //
50
        reg                     r_busy;
51 69 dgisselq
        reg     [(2*BW-2):0]     r_divisor;
52
        reg     [(BW-1):0]       r_dividend;
53
        wire    [(BW):0] diff; // , xdiff[(BW-1):0];
54
        assign  diff = r_dividend - r_divisor[(BW-1):0];
55
        // assign       xdiff= r_dividend - { 1'b0, r_divisor[(BW-1):1] };
56
 
57 160 dgisselq
        reg             r_sign, pre_sign, r_z, r_c, last_bit;
58
        reg     [(LGBW-1):0]     r_bit;
59 69 dgisselq
 
60 160 dgisselq
        initial r_busy = 1'b0;
61 69 dgisselq
        always @(posedge i_clk)
62
                if (i_rst)
63 160 dgisselq
                        r_busy <= 1'b0;
64
                else if (i_wr)
65
                        r_busy <= 1'b1;
66
                else if ((last_bit)||(o_err))
67
                        r_busy <= 1'b0;
68
 
69
        initial o_busy = 1'b0;
70
        always @(posedge i_clk)
71
                if (i_rst)
72 69 dgisselq
                        o_busy <= 1'b0;
73 160 dgisselq
                else if (i_wr)
74 69 dgisselq
                        o_busy <= 1'b1;
75 160 dgisselq
                else if (((last_bit)||(o_err))&&(~r_sign))
76 88 dgisselq
                        o_busy <= 1'b0;
77 160 dgisselq
                else if (~r_busy)
78
                        o_busy <= 1'b0;
79 88 dgisselq
 
80
        always @(posedge i_clk)
81
                if ((i_rst)||(i_wr))
82 69 dgisselq
                        o_valid <= 1'b0;
83 160 dgisselq
                else if (r_busy)
84 69 dgisselq
                begin
85 160 dgisselq
                        if ((last_bit)||(o_err))
86 69 dgisselq
                                o_valid <= (o_err)||(~r_sign);
87
                end else if (r_sign)
88
                begin
89
                        // if (o_err), o_valid is already one.
90
                        //      if not, o_valid has not yet become one.
91
                        o_valid <= (~o_err); // 1'b1;
92 88 dgisselq
                end else
93 69 dgisselq
                        o_valid <= 1'b0;
94
 
95
        always @(posedge i_clk)
96
                if((i_rst)||(o_valid))
97
                        o_err <= 1'b0;
98
                else if (o_busy)
99
                        o_err <= (r_divisor == 0);
100
 
101 160 dgisselq
        initial last_bit = 1'b0;
102 69 dgisselq
        always @(posedge i_clk)
103 160 dgisselq
                if ((i_wr)||(pre_sign)||(i_rst))
104
                        last_bit <= 1'b0;
105
                else if (r_busy)
106
                        last_bit <= (r_bit == {{(LGBW-1){1'b0}},1'b1});
107
 
108
        always @(posedge i_clk)
109
                // if (i_rst) r_busy <= 1'b0;
110
                // else
111 69 dgisselq
                if (i_wr)
112
                begin
113 160 dgisselq
                        //
114
                        // Set our values upon an initial command.  Here's
115
                        // where we come in and start.
116
                        //
117
                        // r_busy <= 1'b1;
118
                        //
119 69 dgisselq
                        o_quotient <= 0;
120 160 dgisselq
                        r_bit <= {(LGBW){1'b1}};
121 69 dgisselq
                        r_divisor <= {  i_denominator, {(BW-1){1'b0}} };
122
                        r_dividend <=  i_numerator;
123
                        r_sign <= 1'b0;
124
                        pre_sign <= i_signed;
125
                        r_z <= 1'b1;
126
                end else if (pre_sign)
127
                begin
128 160 dgisselq
                        //
129
                        // Note that we only come in here, for one clock, if
130
                        // our initial value may have been signed.  If we are
131
                        // doing an unsigned divide, we then skip this step.
132
                        //
133
                        r_sign <= ((r_divisor[(2*BW-2)])^(r_dividend[(BW-1)]));
134
                        // Negate our dividend if necessary so that it becomes
135
                        // a magnitude only value
136 69 dgisselq
                        if (r_dividend[BW-1])
137
                                r_dividend <= -r_dividend;
138 160 dgisselq
                        // Do the same with the divisor--rendering it into
139
                        // a magnitude only.
140 69 dgisselq
                        if (r_divisor[(2*BW-2)])
141
                                r_divisor[(2*BW-2):(BW-1)] <= -r_divisor[(2*BW-2):(BW-1)];
142 160 dgisselq
                        //
143
                        // We only do this stage for a single clock, so go on
144
                        // with the rest of the divide otherwise.
145 69 dgisselq
                        pre_sign <= 1'b0;
146 160 dgisselq
                end else if (r_busy)
147 69 dgisselq
                begin
148 160 dgisselq
                        // While the divide is taking place, we examine each bit
149
                        // in turn here.
150
                        //
151
                        r_bit <= r_bit + {(LGBW){1'b1}}; // r_bit = r_bit - 1;
152 69 dgisselq
                        r_divisor <= { 1'b0, r_divisor[(2*BW-2):1] };
153
                        if (|r_divisor[(2*BW-2):(BW)])
154
                        begin
155
                        end else if (diff[BW])
156
                        begin
157 160 dgisselq
                                // 
158
                                // diff = r_dividend - r_divisor[(BW-1):0];
159
                                //
160
                                // If this value was negative, there wasn't
161
                                // enough value in the dividend to support
162
                                // pulling off a bit.  We'll move down a bit
163
                                // therefore and try again.
164
                                //
165 69 dgisselq
                        end else begin
166 160 dgisselq
                                //
167
                                // Put a '1' into our output accumulator.
168
                                // Subtract the divisor from the dividend,
169
                                // and then move on to the next bit
170
                                //
171 69 dgisselq
                                r_dividend <= diff[(BW-1):0];
172
                                o_quotient[r_bit[(LGBW-1):0]] <= 1'b1;
173
                                r_z <= 1'b0;
174
                        end
175
                end else if (r_sign)
176
                begin
177
                        r_sign <= 1'b0;
178
                        o_quotient <= -o_quotient;
179
                end
180
 
181
        // Set Carry on an exact divide
182
        wire    w_n;
183
        always @(posedge i_clk)
184 160 dgisselq
                r_c <= (r_busy)&&((diff == 0)||(r_dividend == 0));
185 69 dgisselq
        assign w_n = o_quotient[(BW-1)];
186
 
187
        assign o_flags = { 1'b0, w_n, r_c, r_z };
188
endmodule

powered by: WebSVN 2.1.0

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