tdc_divider.vhd 3.05 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
-------------------------------------------------------------------------------
-- TDC Core / CERN
-------------------------------------------------------------------------------
--
-- unit name: tdc_divider
--
-- author: Sebastien Bourdeauducq, sebastien@milkymist.org
--
-- description: Multi-cycle unsigned integer divider
--
-- references: http://www.ohwr.org/projects/tdc-core
--
-------------------------------------------------------------------------------
-- last changes:
-- 2011-08-17 SB Created file
-------------------------------------------------------------------------------

-- Copyright (C) 2011 Sebastien Bourdeauducq

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

Sebastien Bourdeauducq's avatar
Sebastien Bourdeauducq committed
24 25 26
library work;
use work.tdc_package.all;

27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
entity tdc_divider is
    generic(
        -- Number of bits of the operands and results.
        g_WIDTH: positive
    );
    port(
        clk_i       : in std_logic;
        reset_i     : in std_logic;
        
        start_i     : in std_logic;
        dividend_i  : in std_logic_vector(g_WIDTH-1 downto 0);
        divisor_i   : in std_logic_vector(g_WIDTH-1 downto 0);
        
        ready_o     : out std_logic;
        quotient_o  : out std_logic_vector(g_WIDTH-1 downto 0);
        remainder_o : out std_logic_vector(g_WIDTH-1 downto 0)
    );
end entity;

architecture rtl of tdc_divider is

function f_log2_size(a : natural) return natural is
begin
    for i in 1 to 64 loop               -- Works for up to 64 bits
        if 2**i >= a then
            return i;
        end if;
    end loop;
    return 63;
end function;

signal qr        : std_logic_vector(2*g_WIDTH-1 downto 0);
59
signal counter   : std_logic_vector(f_log2_size(g_WIDTH+1)-1 downto 0);
60 61 62 63 64
signal divisor_r : std_logic_vector(g_WIDTH-1 downto 0);
signal diff      : std_logic_vector(g_WIDTH downto 0);
signal ready     : std_logic;

begin
65 66
    quotient_o <= qr(g_WIDTH-1 downto 0);
    remainder_o <= qr(2*g_WIDTH-1 downto g_WIDTH);
67 68
    
    ready <= '1' when (counter = (counter'range => '0')) else '0';
69
    ready_o <= ready;
70 71 72 73 74 75 76 77 78 79 80 81 82
    diff <= std_logic_vector(unsigned(qr(2*g_WIDTH-1 downto g_WIDTH-1))
        - unsigned("0" & divisor_r));
    
    process(clk_i)
    begin
        if rising_edge(clk_i) then
            if reset_i = '1' then
                qr <= (qr'range => '0');
                counter <= (counter'range => '0');
                divisor_r <= (divisor_r'range => '0');
            else
                if start_i = '1' then
                    counter <= std_logic_vector(to_unsigned(g_WIDTH, counter'length));
83 84
                    qr <= (g_WIDTH-1 downto 0 => '0') & dividend_i;
                    divisor_r <= divisor_i;
85 86 87 88 89
                elsif ready = '0' then
                    if diff(g_WIDTH) = '1' then
                        qr <= qr(2*g_WIDTH-2 downto 0) & "0";
                    else
                        qr <= diff(g_WIDTH-1 downto 0) & qr(g_WIDTH-2 downto 0) & "1";
90
                    end if;
91 92 93 94 95 96
                    counter <= std_logic_vector(unsigned(counter) - 1);
                end if;
            end if;
        end if;
    end process;
end architecture;