URL
https://opencores.org/ocsvn/serial_div_uu/serial_div_uu/trunk
Subversion Repositories serial_div_uu
Compare Revisions
- This comparison shows the changes necessary to convert path
/
- from Rev 6 to Rev 7
- ↔ Reverse comparison
Rev 6 → Rev 7
/serial_div_uu/trunk/testbench.vhd
0,0 → 1,149
------------------------------------------------------------------------------- |
-- |
-- Filename: testbench.vhd |
-- Author: David Sala |
-- Description: Divider Testbench |
-- Comment: |
-- |
-- Version history: |
------------------------------------------------------------------------------- |
|
LIBRARY IEEE; |
USE IEEE.std_logic_1164.ALL; |
USE IEEE.std_logic_signed.ALL; |
|
------------------------------------------------------------------------------- |
-- ENTITY |
------------------------------------------------------------------------------- |
entity testbench is |
end testbench; |
|
------------------------------------------------------------------------------- |
-- ARCHITECTURE |
------------------------------------------------------------------------------- |
architecture behavioral of testbench is |
|
|
|
component serial_divide_uu |
generic ( M_PP : integer := 16; -- Size of dividend |
N_PP : integer := 8; -- Size of divisor |
R_PP : integer := 0; -- Size of remainder |
S_PP : integer := 0; -- Skip this many bits (known leading zeros) |
HELD_OUTPUT_PP : integer := 0); -- Set to 1 if stable output should be held |
-- from previous operation, during current |
-- operation. Using this option will increase |
-- the resource utilization (costs extra |
-- d-flip-flops.) |
port( clk_i : in std_logic; |
clk_en_i : in std_logic; |
rst_i : in std_logic; |
divide_i : in std_logic; |
dividend_i : in std_logic_vector(M_PP-1 downto 0); |
divisor_i : in std_logic_vector(N_PP-1 downto 0); |
quotient_o : out std_logic_vector(M_PP+R_PP-S_PP-1 downto 0); |
done_o : out std_logic |
); |
end component; |
|
|
|
signal clk_i : std_logic; |
signal clk_en_i : std_logic; |
signal rst_i : std_logic; |
signal divide_i : std_logic; |
signal dividend_i : std_logic_vector(20 downto 0); |
signal divisor_i : std_logic_vector(20 downto 0); |
signal quotient_o : std_logic_vector(20 downto 0); |
signal done_o : std_logic; |
|
signal expected : std_logic_vector(20 downto 0); |
|
|
|
begin |
|
I_serial_divide_uu: serial_divide_uu |
generic map ( M_PP => 21, |
N_PP => 21, |
R_PP => 0, |
S_PP => 0, |
HELD_OUTPUT_PP => 1) |
port map ( clk_i => clk_i, |
clk_en_i => clk_en_i, |
rst_i => rst_i, |
divide_i => divide_i, |
dividend_i => dividend_i, |
divisor_i => divisor_i, |
quotient_o => quotient_o, |
done_o => done_o ); |
|
clk_en_i <='1'; |
|
stim_gen: process |
begin |
|
dividend_i <= "000000011100000110100"; -- 14388; |
divisor_i <= "000000000000000000000"; -- 64 |
expected <= "000000000000011100000"; -- 224; |
wait for 10000 ns; |
dividend_i <= "000000010111111101111"; -- 12271; |
divisor_i <= "000000000000001111101"; -- 125; |
expected <= "000000000000001100010"; -- 98; |
wait for 10000 ns; |
dividend_i <= "000000011100000110100"; -- 14388; |
divisor_i <= "000000000000010111010"; -- 186; |
expected <= "000000000000001001101"; -- 77; |
wait for 10000 ns; |
dividend_i <= "101100100010001111100"; -- 1459324; |
divisor_i <= "000010100111001110101"; -- 85621; |
expected <= "000000000000000010001"; -- 17; |
wait for 10000 ns; |
dividend_i <= "000000011100000110100"; -- 14388; |
divisor_i <= "000000000000010111010"; -- 186; |
expected <= "000000000000001001101"; -- 77; |
wait for 100 ns; |
wait; |
end process; |
|
|
stim_gen2: process |
begin |
divide_i <= '0'; |
wait for 100 ns; |
divide_i <= '1'; |
wait for 100 ns; |
divide_i <= '0'; |
wait for 10000 ns; |
divide_i <= '1'; |
wait for 100 ns; |
divide_i <= '0'; |
wait for 10000 ns; |
divide_i <= '1'; |
wait for 100 ns; |
divide_i <= '0'; |
wait for 10000 ns; |
divide_i <= '1'; |
wait for 100 ns; |
divide_i <= '0'; |
wait; |
end process; |
|
|
res_gen: process |
begin |
rst_i <= '1'; |
wait for 10 ns; |
rst_i <= '0'; |
wait; |
end process res_gen; |
|
clk_gen: process |
begin |
clk_i <= '0'; |
wait for 50 ns; |
clk_i <= '1'; |
wait for 50 ns; |
end process; |
|
end behavioral; |
/serial_div_uu/trunk/serial_divide_uu.vhd
0,0 → 1,207
----------------------------------------------------------------------------- |
-- serial_divide_uu.v -- Serial division module |
-- |
-- |
-- Description: See description below (which suffices for IP core |
-- specification document.) |
-- |
-- Copyright (C) 2002 John Clayton and OPENCORES.ORG (this Verilog version) |
-- |
-- This source file may be used and distributed without restriction provided |
-- that this copyright statement is not removed from the file and that any |
-- derivative work contains the original copyright notice and the associated |
-- disclaimer. |
-- |
-- This source file is free software; you can redistribute it and/or modify |
-- it under the terms of the GNU Lesser General Public License as published |
-- by the Free Software Foundation; either version 2.1 of the License, or |
-- (at your option) any later version. |
-- |
-- This source is distributed in the hope that it will be useful, but WITHOUT |
-- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
-- FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public |
-- License for more details. |
-- |
-- You should have received a copy of the GNU Lesser General Public License |
-- along with this source. |
-- If not, download it from http:--www.opencores.org/lgpl.shtml |
-- |
------------------------------------------------------------------------------- |
-- |
-- Author: John Clayton |
-- Date : Jan. 30, 2003 |
-- Update: Jan. 30, 2003 Copied this file from "vga_crosshair.v" |
-- Stripped out extraneous stuff. |
-- Update: Mar. 14, 2003 Added S_PP parameter, made some simple changes to |
-- implement quotient leading zero "skip" feature. |
-- Update: Mar. 24, 2003 Updated comments to improve readability. |
-- Update: Jul. 29, 2009 Verilog to VHDL translation (by David Sala) |
-- |
------------------------------------------------------------------------------- |
-- Description: |
-- |
-- This module performs a division operation serially, producing one bit of the |
-- answer per clock cycle. The dividend and the divisor are both taken to be |
-- unsigned quantities. The divider is conceived as an integer divider (as |
-- opposed to a divider for fractional quantities) but the user can configure |
-- the divider to divide fractional quantities as long as the position of the |
-- binary point is carefully monitored. |
-- |
-- The widths of the signals are configurable by parameters, as follows: |
-- |
-- M_PP = Bit width of the dividend |
-- N_PP = Bit width of the divisor |
-- R_PP = Remainder bits desired |
-- S_PP = Skipped quotient bits |
-- |
-- The skipped quotient bits parameter provides a way to prevent the divider |
-- from calculating the full M_PP+R_PP output bits, in case some of the leading |
-- bits are already known to be zero. This is the case, for example, when |
-- dividing two quantities to obtain a result that is a fraction between 0 and 1 |
-- (as when measuring PWM signals). In that case the integer portion of the |
-- quotient is always zero, and therefore it need not be calculated. |
-- |
-- The divide operation is begun by providing a pulse on the divide_i input. |
-- The quotient is provided (M_PP+R_PP-S_PP) clock cycles later. |
-- The divide_i pulse stores the input parameters in registers, so they do |
-- not need to be maintained at the inputs throughout the operation of the module. |
-- If a divide_i pulse is given to the serial_divide_uu module during the time |
-- when it is already working on a previous divide operation, it will abort the |
-- operation it was doing, and begin working on the new one. |
-- |
-- The user is responsible for treating the results correctly. The position |
-- of the binary point is not given, but it is understood that the integer part |
-- of the result is the M_PP most significant bits of the quotient output. |
-- The remaining R_PP least significant bits are the fractional part. |
-- |
-- This is illustrated graphically: |
-- |
-- [ M_PP bits ][ R_PP bits] |
-- [ S_PP bits ][quotient_o] |
-- |
-- The quotient will consist of whatever bits are left after removing the S_PP |
-- most significant bits from the (M_PP+R_PP) result bits. |
-- |
-- Attempting to divide by zero will simply produce a result of all ones. |
-- This core is so simple, that no checking for this condition is provided. |
-- If the user is concerned about a possible divide by zero condition, he should |
-- compare the divisor to zero and flag that condition himself! |
-- |
-- The COUNT_WIDTH_PP parameter must be sized so that 2^COUNT_WIDTH_PP-1 is >= |
-- M_PP+R_PP-S_PP-1. The unit terminates the divide operation when the count |
-- is equal to M_PP+R_PP-S_PP-1. |
-- |
-- The HELD_OUTPUT_PP parameter causes the unit to keep its output result in |
-- a register other than the one which it uses to compute the quotient. This |
-- is useful for applications where the divider is used repeatedly and the |
-- previous divide result (quotient) must be stable during the computation of the |
-- next divide result. Using the additional output register does incur some |
-- additional utilization of resources. |
-- |
------------------------------------------------------------------------------- |
library ieee; |
|
use ieee.std_logic_1164.all; |
use ieee.std_logic_signed.all; |
use ieee.numeric_std.all; |
use ieee.math_real.log; |
use ieee.math_real.ceil; |
|
|
entity serial_divide_uu is |
generic ( M_PP : integer := 16; -- Size of dividend |
N_PP : integer := 8; -- Size of divisor |
R_PP : integer := 0; -- Size of remainder |
S_PP : integer := 0; -- Skip this many bits (known leading zeros) |
-- COUNT_WIDTH_PP : integer := 5; -- 2^COUNT_WIDTH_PP-1 >= (M_PP+R_PP-S_PP-1) |
HELD_OUTPUT_PP : integer := 0); -- Set to 1 if stable output should be held |
-- from previous operation, during current |
-- operation. Using this option will increase |
-- the resource utilization (costs extra d-flip-flops.) |
port( clk_i : in std_logic; |
clk_en_i : in std_logic; |
rst_i : in std_logic; |
divide_i : in std_logic; |
dividend_i : in std_logic_vector(M_PP-1 downto 0); |
divisor_i : in std_logic_vector(N_PP-1 downto 0); |
quotient_o : out std_logic_vector(M_PP+R_PP-S_PP-1 downto 0); |
done_o : out std_logic |
); |
end serial_divide_uu; |
|
|
architecture behavior of serial_divide_uu is |
|
constant COUNT_WIDTH_PP : integer := integer(ceil(log(real(M_PP+R_PP-S_PP),2.0))); |
|
signal done_s : std_logic; |
|
-- Internal signal declarations |
signal grand_dividend : std_logic_vector(M_PP+R_PP-1 downto 0) ; |
signal grand_divisor : std_logic_vector(M_PP+N_PP+R_PP-2 downto 0); |
signal quotient : std_logic_vector(M_PP+R_PP-S_PP-1 downto 0); |
signal quotient_reg : std_logic_vector(M_PP+R_PP-1 downto 0) ; |
signal divide_count : std_logic_vector(COUNT_WIDTH_PP-1 downto 0); |
|
signal subtract_node : std_logic_vector(M_PP+N_PP+R_PP-1 downto 0); -- Subtract node has extra "sign" bit |
signal quotient_node : std_logic_vector(M_PP+R_PP-1 downto 0) ; -- Shifted version of quotient |
signal divisor_node : std_logic_vector(M_PP+N_PP+R_PP-2 downto 0); -- Shifted version of grand divisor |
|
begin |
|
done_o <= done_s; |
|
---------------------------------------------------------------------------- |
-- Module code |
|
P_SERIAL_DIVIDING_MODULE: process (clk_i) |
begin |
if rising_edge(clk_i) then |
if rst_i='1' then |
grand_dividend <= (others=>'0'); |
grand_divisor <= (others=>'0'); |
divide_count <= (others=>'0'); |
quotient <= (others=>'0'); |
done_s <= '0'; |
elsif clk_en_i='1' then |
done_s <= '0'; |
if divide_i='1' then -- Start a new division |
quotient <= (others=>'0'); |
divide_count <= (others=>'0'); |
-- dividend placed initially so that remainder bits are zero... |
grand_dividend <= (others=>'0'); |
grand_dividend (M_PP+R_PP-1 downto R_PP)<= dividend_i; |
-- divisor placed initially for a 1 bit overlap with dividend... |
-- But adjust it back by S_PP, to account for bits that are known |
-- to be leading zeros in the quotient. |
grand_divisor <= (others=>'0'); |
grand_divisor (M_PP+N_PP+R_PP-2 downto M_PP+R_PP-1) <= divisor_i; |
elsif (divide_count = M_PP+R_PP-S_PP-1) then |
done_s <= '1'; -- Indicate done, just sit |
if done_s='0' then |
quotient <= quotient_node; -- final shift... |
quotient_reg <= quotient_node; -- final shift (held output) |
end if; |
else -- Division in progress |
-- If the subtraction yields a positive result, then store that result |
if subtract_node(M_PP+N_PP+R_PP-1)='0' then |
grand_dividend <= subtract_node(M_PP+R_PP-1 downto 0); |
end if; |
-- If the subtraction yields a positive result, then a 1 bit goes into |
-- the quotient, via a shift register |
quotient <= quotient_node; |
-- shift the grand divisor to the right, to cut it in half next clock cycle |
grand_divisor <= divisor_node; |
-- Advance the counter |
divide_count <= divide_count + 1; |
end if; |
end if; |
end if; |
end process; |
|
subtract_node <= ('0' & grand_dividend) - ('0' & grand_divisor); |
quotient_node <= quotient(M_PP+R_PP-S_PP-2 downto 0) & not(subtract_node(M_PP+N_PP+R_PP-1)); |
divisor_node <= '0' & grand_divisor(M_PP+N_PP+R_PP-2 downto 1); |
quotient_o <= quotient when HELD_OUTPUT_PP = 0 else quotient_reg; |
|
end behavior; |