LibreVNA/FPGA/Generator/RationalApproximation.vhd
2022-06-08 02:06:08 +02:00

161 lines
4.1 KiB
VHDL

----------------------------------------------------------------------------------
-- Company:
-- Engineer:
--
-- Create Date: 00:02:23 05/10/2022
-- Design Name:
-- Module Name: RationalApproximation - Behavioral
-- Project Name:
-- Target Devices:
-- Tool versions:
-- Description:
--
-- Dependencies:
--
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
use IEEE.NUMERIC_STD.ALL;
-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
entity RationalApproximation is
Port ( CLK : in STD_LOGIC;
RESET : in STD_LOGIC;
NUM : out STD_LOGIC_VECTOR (11 downto 0);
DENOM : out STD_LOGIC_VECTOR (11 downto 0);
RATIO : in STD_LOGIC_VECTOR (26 downto 0);
START : in STD_LOGIC;
READY : out STD_LOGIC);
end RationalApproximation;
architecture Behavioral of RationalApproximation is
COMPONENT wide_mult
PORT (
clk : IN STD_LOGIC;
a : IN STD_LOGIC_VECTOR(12 DOWNTO 0);
b : IN STD_LOGIC_VECTOR(26 DOWNTO 0);
ce : IN STD_LOGIC;
p : OUT STD_LOGIC_VECTOR(39 DOWNTO 0)
);
END COMPONENT;
signal a : integer range 0 to 8192;
signal b : integer range 0 to 8192;
signal c : integer range 0 to 8192;
signal d : integer range 0 to 8192;
signal compare_ratio : unsigned(39 downto 0);
signal compare_median : unsigned(39 downto 0);
signal mult_a : std_logic_vector(12 downto 0);
signal mult_p : std_logic_vector(39 downto 0);
signal mult_ce : std_logic;
signal mult_pipe : integer range 0 to 5;
type States is (Idle, StartMultiplier, WaitMultiplier, CheckResult, Done);
signal state : States;
begin
Mult : wide_mult
PORT MAP (
clk => CLK,
a => mult_a,
b => RATIO,
ce => mult_ce,
p => mult_p
);
compare_ratio <= unsigned(mult_p);
READY <= '1' when state = Done else '0';
process(CLK, RESET)
begin
if(rising_edge(CLK)) then
if(RESET = '1') then
a <= 0;
b <= 1;
c <= 1;
d <= 1;
NUM <= (others => '0');
DENOM <= (others => '0');
state <= Idle;
mult_ce <= '0';
else
if start = '0' then
state <= Idle;
mult_ce <= '0';
else
-- start is active
case state is
when Idle =>
a <= 0;
b <= 1;
c <= 1;
d <= 1;
state <= StartMultiplier;
when StartMultiplier =>
mult_a <= std_logic_vector(to_unsigned(b + d, 13));
compare_median <= unsigned(std_logic_vector(to_unsigned(a + c, 13)) & b"000_0000_0000_0000_0000_0000_0000");
mult_ce <= '1';
mult_pipe <= 5;
state <= WaitMultiplier;
when WaitMultiplier =>
if unsigned(mult_a) < 4096 then
if mult_pipe = 0 then
state <= CheckResult;
mult_ce <= '0';
else
mult_pipe <= mult_pipe - 1;
end if;
else
-- got too far, return best approximation
NUM <= std_logic_vector(to_unsigned(a, 12));
DENOM <= std_logic_vector(to_unsigned(b, 12));
state <= Done;
mult_ce <= '0';
end if;
when CheckResult =>
if compare_ratio = compare_median then
-- mult_a still contains b + d
if unsigned(mult_a) < 4096 then
NUM <= std_logic_vector(to_unsigned(a + c, 12));
DENOM <= mult_a(11 downto 0);
elsif d > b then
NUM <= std_logic_vector(to_unsigned(c, 12));
DENOM <= std_logic_vector(to_unsigned(d, 12));
else
NUM <= std_logic_vector(to_unsigned(a, 12));
DENOM <= std_logic_vector(to_unsigned(b, 12));
end if;
state <= Done;
else
if compare_ratio > compare_median then
a <= a + c;
b <= b + d;
else
c <= a + c;
d <= b + d;
end if;
state <= StartMultiplier;
end if;
when others =>
end case;
end if;
end if;
end if;
end process;
end Behavioral;