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

Subversion Repositories serial_div_uu

[/] [serial_div_uu/] [trunk/] [serial_divide_uu.vhd] - Blame information for rev 7

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 7 jclaytons
-----------------------------------------------------------------------------
2
-- serial_divide_uu.v  -- Serial division module
3
--
4
--
5
-- Description: See description below (which suffices for IP core
6
--                                     specification document.)
7
--
8
-- Copyright (C) 2002 John Clayton and OPENCORES.ORG (this Verilog version)
9
--
10
-- This source file may be used and distributed without restriction provided
11
-- that this copyright statement is not removed from the file and that any
12
-- derivative work contains the original copyright notice and the associated
13
-- disclaimer.
14
--
15
-- This source file is free software; you can redistribute it and/or modify
16
-- it under the terms of the GNU Lesser General Public License as published
17
-- by the Free Software Foundation;  either version 2.1 of the License, or
18
-- (at your option) any later version.
19
--
20
-- This source is distributed in the hope that it will be useful, but WITHOUT
21
-- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
22
-- FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
23
-- License for more details.
24
--
25
-- You should have received a copy of the GNU Lesser General Public License
26
-- along with this source.
27
-- If not, download it from http:--www.opencores.org/lgpl.shtml
28
--
29
-------------------------------------------------------------------------------
30
--
31
-- Author: John Clayton
32
-- Date  : Jan. 30, 2003
33
-- Update: Jan. 30, 2003  Copied this file from "vga_crosshair.v"
34
--                        Stripped out extraneous stuff.
35
-- Update: Mar. 14, 2003  Added S_PP parameter, made some simple changes to
36
--                        implement quotient leading zero "skip" feature.
37
-- Update: Mar. 24, 2003  Updated comments to improve readability.
38
-- Update: Jul. 29, 2009  Verilog to VHDL translation (by David Sala)
39
--
40
-------------------------------------------------------------------------------
41
-- Description:
42
--
43
-- This module performs a division operation serially, producing one bit of the
44
-- answer per clock cycle.  The dividend and the divisor are both taken to be
45
-- unsigned quantities.  The divider is conceived as an integer divider (as
46
-- opposed to a divider for fractional quantities) but the user can configure
47
-- the divider to divide fractional quantities as long as the position of the
48
-- binary point is carefully monitored.
49
--
50
-- The widths of the signals are configurable by parameters, as follows:
51
--
52
-- M_PP = Bit width of the dividend
53
-- N_PP = Bit width of the divisor
54
-- R_PP = Remainder bits desired
55
-- S_PP = Skipped quotient bits
56
--
57
-- The skipped quotient bits parameter provides a way to prevent the divider
58
-- from calculating the full M_PP+R_PP output bits, in case some of the leading
59
-- bits are already known to be zero.  This is the case, for example, when
60
-- dividing two quantities to obtain a result that is a fraction between 0 and 1
61
-- (as when measuring PWM signals).  In that case the integer portion of the
62
-- quotient is always zero, and therefore it need not be calculated.
63
--
64
-- The divide operation is begun by providing a pulse on the divide_i input.
65
-- The quotient is provided (M_PP+R_PP-S_PP) clock cycles later.
66
-- The divide_i pulse stores the input parameters in registers, so they do
67
-- not need to be maintained at the inputs throughout the operation of the module.
68
-- If a divide_i pulse is given to the serial_divide_uu module during the time
69
-- when it is already working on a previous divide operation, it will abort the
70
-- operation it was doing, and begin working on the new one.
71
--
72
-- The user is responsible for treating the results correctly.  The position
73
-- of the binary point is not given, but it is understood that the integer part
74
-- of the result is the M_PP most significant bits of the quotient output.
75
-- The remaining R_PP least significant bits are the fractional part.
76
--
77
-- This is illustrated graphically:
78
--
79
--     [ M_PP bits ][    R_PP bits]
80
--     [ S_PP bits    ][quotient_o]
81
--
82
-- The quotient will consist of whatever bits are left after removing the S_PP
83
-- most significant bits from the (M_PP+R_PP) result bits.
84
--
85
-- Attempting to divide by zero will simply produce a result of all ones.
86
-- This core is so simple, that no checking for this condition is provided.
87
-- If the user is concerned about a possible divide by zero condition, he should
88
-- compare the divisor to zero and flag that condition himself!
89
--
90
-- The COUNT_WIDTH_PP parameter must be sized so that 2^COUNT_WIDTH_PP-1 is >=
91
-- M_PP+R_PP-S_PP-1.  The unit terminates the divide operation when the count
92
-- is equal to M_PP+R_PP-S_PP-1.
93
--
94
-- The HELD_OUTPUT_PP parameter causes the unit to keep its output result in
95
-- a register other than the one which it uses to compute the quotient.  This
96
-- is useful for applications where the divider is used repeatedly and the
97
-- previous divide result (quotient) must be stable during the computation of the
98
-- next divide result.  Using the additional output register does incur some
99
-- additional utilization of resources.
100
--
101
-------------------------------------------------------------------------------
102
library ieee;
103
 
104
use ieee.std_logic_1164.all;
105
use ieee.std_logic_signed.all;
106
use ieee.numeric_std.all;
107
use ieee.math_real.log;
108
use ieee.math_real.ceil;
109
 
110
 
111
entity serial_divide_uu is
112
  generic ( M_PP : integer := 16;           -- Size of dividend
113
            N_PP : integer := 8;            -- Size of divisor
114
            R_PP : integer := 0;            -- Size of remainder
115
            S_PP : integer := 0;            -- Skip this many bits (known leading zeros)
116
--            COUNT_WIDTH_PP : integer := 5;  -- 2^COUNT_WIDTH_PP-1 >= (M_PP+R_PP-S_PP-1)
117
            HELD_OUTPUT_PP : integer := 0); -- Set to 1 if stable output should be held
118
                                            -- from previous operation, during current
119
                                            -- operation.  Using this option will increase
120
                                            -- the resource utilization (costs extra d-flip-flops.)
121
    port(   clk_i      : in  std_logic;
122
            clk_en_i   : in  std_logic;
123
            rst_i      : in  std_logic;
124
            divide_i   : in  std_logic;
125
            dividend_i : in  std_logic_vector(M_PP-1 downto 0);
126
            divisor_i  : in  std_logic_vector(N_PP-1 downto 0);
127
            quotient_o : out std_logic_vector(M_PP+R_PP-S_PP-1 downto 0);
128
            done_o     : out std_logic
129
    );
130
end serial_divide_uu;
131
 
132
 
133
architecture behavior of serial_divide_uu is
134
 
135
   constant COUNT_WIDTH_PP    : integer := integer(ceil(log(real(M_PP+R_PP-S_PP),2.0)));
136
 
137
   signal done_s         : std_logic;
138
 
139
-- Internal signal declarations
140
   signal grand_dividend : std_logic_vector(M_PP+R_PP-1 downto 0)     ;
141
   signal grand_divisor  : std_logic_vector(M_PP+N_PP+R_PP-2 downto 0);
142
   signal quotient       : std_logic_vector(M_PP+R_PP-S_PP-1 downto 0);
143
   signal quotient_reg   : std_logic_vector(M_PP+R_PP-1 downto 0)     ;
144
   signal divide_count   : std_logic_vector(COUNT_WIDTH_PP-1 downto 0);
145
 
146
   signal subtract_node  : std_logic_vector(M_PP+N_PP+R_PP-1 downto 0); -- Subtract node has extra "sign" bit
147
   signal quotient_node  : std_logic_vector(M_PP+R_PP-1 downto 0)     ; -- Shifted version of quotient
148
   signal divisor_node   : std_logic_vector(M_PP+N_PP+R_PP-2 downto 0); -- Shifted version of grand divisor
149
 
150
begin
151
 
152
   done_o <= done_s;
153
 
154
----------------------------------------------------------------------------
155
-- Module code
156
 
157
   P_SERIAL_DIVIDING_MODULE: process (clk_i)
158
      begin
159
         if rising_edge(clk_i) then
160
            if rst_i='1' then
161
                grand_dividend <= (others=>'0');
162
                grand_divisor <= (others=>'0');
163
                divide_count <= (others=>'0');
164
                quotient <= (others=>'0');
165
                done_s <= '0';
166
            elsif clk_en_i='1' then
167
                done_s <= '0';
168
                if divide_i='1' then       -- Start a new division
169
                    quotient <= (others=>'0');
170
                    divide_count <= (others=>'0');
171
                    -- dividend placed initially so that remainder bits are zero...
172
                    grand_dividend <= (others=>'0');
173
                    grand_dividend (M_PP+R_PP-1 downto R_PP)<= dividend_i;
174
                    -- divisor placed initially for a 1 bit overlap with dividend...
175
                    -- But adjust it back by S_PP, to account for bits that are known
176
                    -- to be leading zeros in the quotient.
177
                    grand_divisor <= (others=>'0');
178
                    grand_divisor (M_PP+N_PP+R_PP-2 downto M_PP+R_PP-1) <= divisor_i;
179
                elsif (divide_count = M_PP+R_PP-S_PP-1) then
180
                    done_s <= '1';                    -- Indicate done, just sit
181
                    if done_s='0' then
182
                        quotient <= quotient_node;      -- final shift...
183
                        quotient_reg <= quotient_node;  -- final shift (held output)
184
                    end if;
185
                else                -- Division in progress
186
                    -- If the subtraction yields a positive result, then store that result
187
                    if subtract_node(M_PP+N_PP+R_PP-1)='0' then
188
                        grand_dividend <= subtract_node(M_PP+R_PP-1 downto 0);
189
                    end if;
190
                    -- If the subtraction yields a positive result, then a 1 bit goes into
191
                    -- the quotient, via a shift register
192
                    quotient <= quotient_node;
193
                    -- shift the grand divisor to the right, to cut it in half next clock cycle
194
                    grand_divisor <= divisor_node;
195
                    -- Advance the counter
196
                    divide_count <= divide_count + 1;
197
                end if;
198
            end if;
199
         end if;
200
     end process;
201
 
202
    subtract_node <= ('0' & grand_dividend) - ('0' & grand_divisor);
203
    quotient_node <= quotient(M_PP+R_PP-S_PP-2 downto 0) & not(subtract_node(M_PP+N_PP+R_PP-1));
204
    divisor_node  <= '0' & grand_divisor(M_PP+N_PP+R_PP-2 downto 1);
205
    quotient_o    <= quotient when HELD_OUTPUT_PP = 0 else quotient_reg;
206
 
207
end behavior;

powered by: WebSVN 2.1.0

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