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;
|