Commit 0f81de17 authored by Tomasz Wlostowski's avatar Tomasz Wlostowski

dsp/gc_cordic: make saturated math optional through a generic

parent 52d3800a
......@@ -25,8 +25,9 @@ use work.gc_cordic_pkg.all;
entity cordic_modulo_360 is
generic(
g_M : positive := 16;
g_ANGLE_FORMAT : integer
g_M : positive;
g_ANGLE_FORMAT : integer;
g_USE_SATURATED_MATH : boolean
);
port (
cor_submode_i : in t_CORDIC_SUBMODE;
......@@ -84,14 +85,14 @@ begin
begin
if cor_submode_i = c_SUBMODE_CIRCULAR then
if(lt = '1' and gt = '0') then
f_limit_add(signed(angle_i), c_OFFS_P360D, angle_out, lim_out);
f_limit_add(g_USE_SATURATED_MATH, signed(angle_i), c_OFFS_P360D, angle_out, lim_out);
elsif (lt = '0' and gt = '1') then
f_limit_add(signed(angle_i), c_OFFS_N360D, angle_out, lim_out);
f_limit_add(g_USE_SATURATED_MATH, signed(angle_i), c_OFFS_N360D, angle_out, lim_out);
else
f_limit_add(signed(angle_i), c_OFFS_ZERO, angle_out, lim_out);
f_limit_add(g_USE_SATURATED_MATH, signed(angle_i), c_OFFS_ZERO, angle_out, lim_out);
end if;
else
f_limit_add(signed(angle_i), to_signed(0, g_M), angle_out, lim_out);
f_limit_add(g_USE_SATURATED_MATH, signed(angle_i), to_signed(0, g_M), angle_out, lim_out);
end if;
angle_o <= std_logic_vector(angle_out(g_M-1 downto 0));
......
......@@ -7,8 +7,9 @@ use work.gc_cordic_pkg.all;
entity cordic_xy_logic_hd is
generic(
g_M : positive := 16;
g_J : integer := 0
g_M : positive;
g_J : integer;
g_USE_SATURATED_MATH : boolean
);
port (
clk_i : in std_logic;
......@@ -107,23 +108,23 @@ begin
-- scntrl = 1, updmode = 1
when c_SUBMODE_CIRCULAR =>
yi_muxed := f_limit_negate(yi_shifted, not d_i);
yi_muxed := f_limit_negate(g_USE_SATURATED_MATH, yi_shifted, not d_i);
-- scntrl = 0, updmode = 1
when c_SUBMODE_HYPERBOLIC =>
yi_muxed := f_limit_negate(yi_shifted, d_i);
yi_muxed := f_limit_negate(g_USE_SATURATED_MATH, yi_shifted, d_i);
when others =>
yi_muxed := (others => '0');
end case;
xi_muxed := f_limit_negate(xi_shifted, not d_i);
xi_muxed := f_limit_negate(g_USE_SATURATED_MATH, xi_shifted, not d_i);
f_limit_subtract(signed(xi_i), yi_muxed, xj_comb, xj_limit);
f_limit_add(signed(yi_i), xi_muxed, yj_comb, yj_limit);
f_limit_subtract(g_USE_SATURATED_MATH, signed(xi_i), yi_muxed, xj_comb, xj_limit);
f_limit_add(g_USE_SATURATED_MATH, signed(yi_i), xi_muxed, yj_comb, yj_limit);
fi_inv := f_limit_negate( signed(fi_i), not d_i );
fi_inv := f_limit_negate(g_USE_SATURATED_MATH, signed(fi_i), not d_i );
zj_comb := signed(zi_i) - fi_inv;
......
......@@ -7,10 +7,11 @@ use work.gc_cordic_pkg.all;
entity cordic_xy_logic_nhd is
generic(
g_M : positive := 16;
g_J : integer := 0;
g_I : integer := 0;
g_ANGLE_FORMAT : integer
g_M : positive;
g_J : integer;
g_I : integer;
g_ANGLE_FORMAT : integer;
g_USE_SATURATED_MATH : boolean
);
port (
clk_i : in std_logic;
......@@ -120,25 +121,25 @@ begin
when c_SUBMODE_CIRCULAR =>
-- scntrl = 1, updmode = 1
yi_muxed := f_limit_negate(yi_shifted, not di_int);
yi_muxed := f_limit_negate(g_USE_SATURATED_MATH, yi_shifted, not di_int);
when c_SUBMODE_HYPERBOLIC =>
-- scntrl = 0, updmode = 1
yi_muxed := f_limit_negate(yi_shifted, di_int);
yi_muxed := f_limit_negate(g_USE_SATURATED_MATH, yi_shifted, di_int);
when others =>
yi_muxed := (others => '0');
end case;
xi_muxed := f_limit_negate(xi_shifted, not di_int);
xi_muxed := f_limit_negate(g_USE_SATURATED_MATH, xi_shifted, not di_int);
xi_muxed_s <= xi_muxed;
yi_muxed_s <= yi_muxed;
f_limit_subtract(signed(xi_i), yi_muxed, xj_comb, xj_limit);
f_limit_add(signed(yi_i), xi_muxed, yj_comb, yj_limit);
f_limit_subtract(g_USE_SATURATED_MATH, signed(xi_i), yi_muxed, xj_comb, xj_limit);
f_limit_add(g_USE_SATURATED_MATH, signed(yi_i), xi_muxed, yj_comb, yj_limit);
fi_inv := f_limit_negate( signed(fi), not di_int );
fi_inv := f_limit_negate(g_USE_SATURATED_MATH, signed(fi), not di_int );
zj_comb := signed(zi_i) - fi_inv;
......
......@@ -8,13 +8,15 @@ use work.gc_cordic_pkg.all;
entity cordic_xy_logic_nmhd is
generic(
-- Number of XYlogicNHD cells instantiated
g_N : positive := 12;
g_N : positive;
--M = Word-width (maximum = 32)
g_M : positive := 16;
g_M : positive;
--AngleMode = Default angle format S8.7 otherwise FS = 180 deg.
g_ANGLE_FORMAT : integer
g_ANGLE_FORMAT : integer;
g_USE_SATURATED_MATH : boolean
);
port (
clk_i : in std_logic;
......@@ -64,8 +66,9 @@ begin
B_Cell0 : entity work.cordic_xy_logic_hd
generic map(
g_M => g_M,
g_J => 0)
g_M => g_M,
g_J => 0,
g_USE_SATURATED_MATH => g_USE_SATURATED_MATH)
port map(
clk_i => clk_i,
rst_i => rst_i,
......@@ -90,10 +93,11 @@ begin
B_CellN_1 : entity work.cordic_xy_logic_nhd
generic map(
g_M => g_M,
g_J => g_N - 1,
g_I => g_N - 1,
g_ANGLE_FORMAT => g_ANGLE_FORMAT)
g_M => g_M,
g_J => g_N - 1,
g_I => g_N - 1,
g_ANGLE_FORMAT => g_ANGLE_FORMAT,
g_USE_SATURATED_MATH => g_USE_SATURATED_MATH)
port map(
clk_i => clk_i,
rst_i => loc_Rst(g_N-2),
......@@ -117,10 +121,11 @@ begin
GXYlogic : for K in 1 to g_N-2 generate
B_CellN : entity work.cordic_xy_logic_nhd
generic map(
g_M => g_M,
g_J => K,
g_ANGLE_FORMAT => g_ANGLE_FORMAT,
g_I => K)
g_M => g_M,
g_J => K,
g_ANGLE_FORMAT => g_ANGLE_FORMAT,
g_I => K,
g_USE_SATURATED_MATH => g_USE_SATURATED_MATH)
port map(
clk_i => clk_i,
rst_i => loc_Rst(K-1),
......
--------------------------------------------------------------------------------
-- CERN BE-CO-HT
-- General Cores Library
-- https://www.ohwr.org/projects/general-cores
--------------------------------------------------------------------------------
--
-- unit name: gc_cordic
--
-- authors: fixme
--
-- description: Fully pipelined multifunction CORDIC code. FIXME.
--
--
--------------------------------------------------------------------------------
-- Copyright CERN 2020
--------------------------------------------------------------------------------
-- Copyright and related rights are licensed under the Solderpad Hardware
-- License, Version 2.0 (the "License"); you may not use this file except
-- in compliance with the License. You may obtain a copy of the License at
-- http://solderpad.org/licenses/SHL-2.0.
-- Unless required by applicable law or agreed to in writing, software,
-- hardware and materials distributed under this License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
-- or implied. See the License for the specific language governing permissions
-- and limitations under the License.
--------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
......@@ -7,31 +34,46 @@ use work.gc_cordic_pkg.all;
entity gc_cordic is
generic(
-- Number of XYlogicNHD cells instantiated
-- Number of pipeline stages
g_N : positive := 12;
--M = Word-width (maximum = 32)
g_M : positive := 16;
--AngleMode = Default angle format S8.7 otherwise FS = 180 deg.
g_ANGLE_FORMAT : integer := c_ANGLE_FORMAT_FULL_SCALE_180
g_ANGLE_FORMAT : integer := c_ANGLE_FORMAT_FULL_SCALE_180;
-- when true, all addition/subtraction operations are performed with saturation.
-- Limit inputs/outputs are only supported if the parameter is TRUE.
g_USE_SATURATED_MATH : boolean := false
);
port (
clk_i : in std_logic;
rst_i : in std_logic;
-- Mode of operation. Two have been tested/are supported:
-- MODE = ROTATE, SUBMODE = CIRCULAR: mag/phase -> sin/cos
-- MODE = VECTOR, SUBMODE = CIRCULAR: sin/cos -> mag/phase
-- The other mode combinations may work, but have not been tested.
cor_mode_i : in t_CORDIC_MODE;
cor_submode_i : in t_CORDIC_SUBMODE;
lim_x_i : in std_logic;
lim_y_i : in std_logic;
-- cos input
x0_i : in std_logic_vector(g_M-1 downto 0);
-- sin input
y0_i : in std_logic_vector(g_M-1 downto 0);
-- phase input
z0_i : in std_logic_vector(g_M-1 downto 0);
-- cos output
xn_o : out std_logic_vector(g_M-1 downto 0);
-- sin output
yn_o : out std_logic_vector(g_M-1 downto 0);
-- phase output
zn_o : out std_logic_vector(g_M-1 downto 0);
lim_x_o : out std_logic;
......@@ -43,13 +85,13 @@ entity gc_cordic is
end entity;
architecture rtl of gc_cordic is
signal r_lim_x, r_lim_y : std_logic;
signal z0_int : std_logic_vector(g_M downto 0);
signal x1, y1 : std_logic_vector(g_M-1 downto 0);
signal z1 : std_logic_vector(g_M downto 0);
signal d1 : std_logic;
signal fi1 : std_logic_vector(31 downto 0);
signal zj_int : std_logic_vector(g_M downto 0);
signal r_lim_x, r_lim_y : std_logic;
signal z0_int : std_logic_vector(g_M downto 0);
signal x1, y1 : std_logic_vector(g_M-1 downto 0);
signal z1 : std_logic_vector(g_M downto 0);
signal d1 : std_logic;
signal fi1 : std_logic_vector(31 downto 0);
signal zj_int : std_logic_vector(g_M downto 0);
signal rst_o_int, rst_o_int_d : std_logic;
begin
......@@ -72,7 +114,7 @@ begin
U_Cordic_Init : entity work.cordic_init
generic map (
g_M => g_M,
g_M => g_M,
g_ANGLE_FORMAT => g_ANGLE_FORMAT)
port map (
clk_i => clk_i,
......@@ -87,20 +129,21 @@ begin
z1_o => z1,
d1_o => d1);
U_Cordic_Core: entity work.cordic_xy_logic_nmhd
U_Cordic_Core : entity work.cordic_xy_logic_nmhd
generic map (
g_N => g_N-1,
g_M => g_M,
g_ANGLE_FORMAT => g_ANGLE_FORMAT)
g_N => g_N-1,
g_M => g_M,
g_ANGLE_FORMAT => g_ANGLE_FORMAT,
g_USE_SATURATED_MATH => g_USE_SATURATED_MATH)
port map (
clk_i => clk_i,
rst_i => rst_i,
cor_mode_i => cor_mode_i,
cor_submode_i => cor_submode_i,
d_i => d1,
fi1_i => fi1(31 downto 31 - (g_M - 1) ),
fi1_i => fi1(31 downto 31 - (g_M - 1)),
lim_x_i => r_lim_x,
lim_y_i => r_lim_y,
xi_i => x1,
......@@ -115,8 +158,9 @@ begin
U_Fixup_Angle : entity work.cordic_modulo_360
generic map (
g_M => g_M,
g_ANGLE_FORMAT => g_ANGLE_FORMAT)
g_M => g_M,
g_ANGLE_FORMAT => g_ANGLE_FORMAT,
g_USE_SATURATED_MATH => g_USE_SATURATED_MATH)
port map (
cor_submode_i => cor_submode_i,
angle_i => zj_int,
......@@ -131,5 +175,5 @@ begin
end process;
rst_o <= rst_o_int_d or rst_o_int;
end rtl;
......@@ -11,19 +11,19 @@ use ieee.numeric_std.all;
package gc_cordic_pkg is
subtype t_CORDIC_MODE is Std_logic_vector(0 downto 0);
subtype t_CORDIC_SUBMODE is Std_logic_vector(1 downto 0);
subtype t_CORDIC_MODE is std_logic_vector(0 downto 0);
subtype t_CORDIC_SUBMODE is std_logic_vector(1 downto 0);
constant c_ANGLE_FORMAT_S8_7 : integer := 0;
constant c_ANGLE_FORMAT_S8_7 : integer := 0;
constant c_ANGLE_FORMAT_FULL_SCALE_180 : integer := 1;
constant c_MODE_VECTOR : t_CORDIC_MODE := "0";
constant c_MODE_ROTATE : t_CORDIC_MODE := "1";
constant c_SUBMODE_CIRCULAR : t_CORDIC_SUBMODE := "00";
constant c_SUBMODE_LINEAR : t_CORDIC_SUBMODE := "01";
constant c_SUBMODE_CIRCULAR : t_CORDIC_SUBMODE := "00";
constant c_SUBMODE_LINEAR : t_CORDIC_SUBMODE := "01";
constant c_SUBMODE_HYPERBOLIC : t_CORDIC_SUBMODE := "11";
-- Used by CORDIC algo and init
-- Constant GHHfFReg : Std_logic_vector(19 downto 1) := X"0000"&"000";
constant c_DegPlus90 : signed(15 downto 0) := X"2D00";
......@@ -88,7 +88,7 @@ package gc_cordic_pkg is
constant c_FSDegZeroHD : signed(31 downto 0) := X"00000000";
-- Cordic Sequencer Iteration Constants
constant c_CirIter : Std_logic_vector(4 downto 0) := '0'&X"D";
constant c_CirIter : std_logic_vector(4 downto 0) := '0'&X"D";
constant c_LinIter : std_logic_vector(4 downto 0) := '0'&X"F";
-- Cordic Sequencer Iteration Constants for FS Angle format
constant c_FSCirIter : std_logic_vector(4 downto 0) := '0'&X"F";
......@@ -105,23 +105,26 @@ package gc_cordic_pkg is
procedure f_limit_subtract
(a, b : in signed;
o : out signed;
lim : out std_logic);
(use_limiter : boolean;
a, b : in signed;
o : out signed;
lim : out std_logic);
procedure f_limit_add
(a, b : in signed;
o : out signed;
lim : out std_logic);
(use_limiter : boolean;
a, b : in signed;
o : out signed;
lim : out std_logic);
function f_limit_negate(
x : in signed;
neg : in std_logic) return signed;
use_limiter : boolean;
x : in signed;
neg : in std_logic) return signed;
function f_phi_lookup (
stage : integer;
submode : t_CORDIC_SUBMODE;
angle_format : integer
stage : integer;
submode : t_CORDIC_SUBMODE;
angle_format : integer
)
return signed;
......@@ -134,17 +137,21 @@ end package;
package body gc_cordic_pkg is
procedure f_limit_subtract
(a, b : in signed;
o : out signed;
lim : out std_logic) is
(use_limiter : boolean;
a, b : in signed;
o : out signed;
lim : out std_logic) is
constant c_max_val : signed(o'range) := ('0', others => '1');
constant c_min_val : signed(o'range) := ('1', others => '0');
variable l_sum : signed(O'length downto 0) := (others => '0');
begin
l_sum := resize(a, o'length+1) - resize(b, o'length-1);
if not use_limiter then
o := l_sum(o'range);
lim := '0';
-- value above maximum
if l_sum(o'length) = '0' and l_sum(o'length-1) = '1' then
elsif l_sum(o'length) = '0' and l_sum(o'length-1) = '1' then
o := c_max_val;
lim := '1';
-- value below minimum
......@@ -158,17 +165,22 @@ package body gc_cordic_pkg is
end procedure;
procedure f_limit_add
(a, b : in signed;
o : out signed;
lim : out std_logic) is
(
use_limiter : boolean;
a, b : in signed;
o : out signed;
lim : out std_logic) is
constant c_max_val : signed(o'range) := ('0', others => '1');
constant c_min_val : signed(o'range) := ('1', others => '0');
variable l_sum : signed(O'length downto 0) := (others => '0');
begin
l_sum := resize(a, o'length+1) + resize(b, o'length-1);
if not use_limiter then
o := l_sum(o'range);
lim := '0';
-- value above maximum
if l_sum(o'length) = '0' and l_sum(o'length-1) = '1' then
elsif l_sum(o'length) = '0' and l_sum(o'length-1) = '1' then
o := c_max_val;
lim := '1';
-- value below minimum
......@@ -182,13 +194,14 @@ package body gc_cordic_pkg is
end procedure;
function f_limit_negate(
x : in signed;
neg : in std_logic) return signed is
use_limiter : boolean;
x : in signed;
neg : in std_logic) return signed is
constant c_max_val : signed(x'range) := ('0', others => '1');
constant c_min_val : signed(x'range) := ('1', others => '0');
begin
if neg = '1' then
if x = c_min_val then
if x = c_min_val and use_limiter then
return c_max_val;
else
return not x (x'length-1 downto 0) + 1;
......@@ -201,9 +214,9 @@ package body gc_cordic_pkg is
function f_phi_lookup (
stage : integer;
submode : t_CORDIC_SUBMODE;
angle_format : integer
stage : integer;
submode : t_CORDIC_SUBMODE;
angle_format : integer
) return signed is
type t_LUT is array(integer range<>) of signed(31 downto 0);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment