OpenCores
URL https://opencores.org/ocsvn/cordic/cordic/trunk

Subversion Repositories cordic

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /
    from Rev 5 to Rev 6
    Reverse comparison

Rev 5 → Rev 6

/trunk/rect2polar/r2p_CordicPipe.vhd
0,0 → 1,142
--
-- file: r2p_CordicPipe.vhd
-- author: Richard Herveille
-- rev. 1.0 initial release
-- rev. 1.1 March 19th, 2001. Richard Herveille. Changed function Delta, it is compatible with Xilinx WebPack software now
-- rev. 1.2 May 18th, 2001. Richard Herveille. Added documentation to function ATAN (by popular request).
-- rev. 1.3 June 4th, 2001. Richard Herveille. Revised design (made it simpler and easier to understand).
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
 
entity r2p_CordicPipe is
generic(
WIDTH : natural := 16;
PIPEID : natural := 1
);
port(
clk : in std_logic;
ena : in std_logic;
 
Xi : in signed(WIDTH -1 downto 0);
Yi : in signed(WIDTH -1 downto 0);
Zi : in signed(19 downto 0);
Xo : out signed(WIDTH -1 downto 0);
Yo : out signed(WIDTH -1 downto 0);
Zo : out signed(19 downto 0)
);
end entity r2p_CordicPipe;
 
architecture dataflow of r2p_CordicPipe is
 
--
-- functions
--
 
-- Function CATAN (constante arc-tangent).
-- This is a lookup table containing pre-calculated arc-tangents.
-- 'n' is the number of the pipe, returned is a 20bit arc-tangent value.
-- The numbers are calculated as follows: Z(n) = atan(1/2^n)
-- examples:
-- 20bit values => 2^20 = 2pi(rad)
-- 1(rad) = 2^20/2pi = 166886.053....
-- n:1, atan(1/2) = 0.4636...(rad)
-- 0.4636... * 166886.053... = 77376.32(dec) = 12E40(hex)
-- n:2, atan(1/4) = 0.2449...(rad)
-- 0.2449... * 166886.053... = 40883.52(dec) = 9FB3(hex)
-- n:3, atan(1/8) = 0.1243...(rad)
-- 0.1243... * 166886.053... = 20753.11(dec) = 5111(hex)
--
function CATAN(n :natural) return integer is
variable result :integer;
begin
case n is
when 0 => result := 16#020000#;
when 1 => result := 16#012E40#;
when 2 => result := 16#09FB4#;
when 3 => result := 16#05111#;
when 4 => result := 16#028B1#;
when 5 => result := 16#0145D#;
when 6 => result := 16#0A2F#;
when 7 => result := 16#0518#;
when 8 => result := 16#028C#;
when 9 => result := 16#0146#;
when 10 => result := 16#0A3#;
when 11 => result := 16#051#;
when 12 => result := 16#029#;
when 13 => result := 16#014#;
when 14 => result := 16#0A#;
when 15 => result := 16#05#;
when 16 => result := 16#03#;
when 17 => result := 16#01#;
when others => result := 16#0#;
end case;
return result;
end CATAN;
 
-- function Delta is actually an arithmatic shift right
-- This strange construction is needed for compatibility with Xilinx WebPack
function Delta(Arg : signed; Cnt : natural) return signed is
variable tmp : signed(Arg'range);
constant lo : integer := Arg'high -cnt +1;
begin
for n in Arg'high downto lo loop
tmp(n) := Arg(Arg'high);
end loop;
for n in Arg'high -cnt downto 0 loop
tmp(n) := Arg(n +cnt);
end loop;
return tmp;
end function Delta;
 
function AddSub(dataa, datab : in signed; add_sub : in std_logic) return signed is
begin
if (add_sub = '1') then
return dataa + datab;
else
return dataa - datab;
end if;
end;
 
--
-- ARCHITECTURE BODY
--
signal dX, Xresult : signed(WIDTH -1 downto 0);
signal dY, Yresult : signed(WIDTH -1 downto 0);
signal atan, Zresult : signed(19 downto 0);
 
signal Yneg, Ypos : std_logic;
begin
 
dX <= Delta(Xi, PIPEID);
dY <= Delta(Yi, PIPEID);
atan <= conv_signed( catan(PIPEID), 20); -- Angle can not be negative, catan never returns a negative value, so conv_signed can be used
 
-- generate adder structures
Yneg <= Yi(WIDTH -1);
Ypos <= not Yi(WIDTH -1);
 
-- xadd
Xresult <= AddSub(Xi, dY, YPos);
 
-- yadd
Yresult <= AddSub(Yi, dX, Yneg);
 
-- zadd
Zresult <= AddSub(Zi, atan, Ypos);
 
gen_regs: process(clk)
begin
if(clk'event and clk='1') then
if (ena = '1') then
Xo <= Xresult;
Yo <= Yresult;
Zo <= Zresult;
end if;
end if;
end process;
 
end architecture dataflow;
 
/trunk/rect2polar/r2p_cordic.vhd
0,0 → 1,100
--
-- VHDL implementation of cordic algorithm
--
-- File: cordic.vhd
-- author: Richard Herveille
-- rev. 1.0 initial release
-- rev. 1.1 changed CordicPipe component declaration, Xilinx WebPack issue
-- rev. 1.2 Revised entire core. Made is simpler and easier to understand.
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
 
entity r2p_cordic is
generic(
PIPELINE : integer := 15;
WIDTH : integer := 16;
EXT_PRECISION : integer := 4
);
port(
clk : in std_logic;
ena : in std_logic;
 
Xi : in signed(WIDTH-1 downto 0);
Yi : in signed(WIDTH-1 downto 0);
Zi : in signed(19 downto 0) := (others => '0');
Xo : out signed(WIDTH + EXT_PRECISION -1 downto 0);
Zo : out signed(19 downto 0)
);
end r2p_cordic;
 
 
architecture dataflow of r2p_cordic is
 
--
-- TYPE defenitions
--
type XYVector is array(PIPELINE downto 0) of signed(WIDTH + EXT_PRECISION -1 downto 0);
type ZVector is array(PIPELINE downto 0) of signed(19 downto 0);
 
--
-- COMPONENT declarations
--
component r2p_CordicPipe
generic(
WIDTH : natural := 16;
PIPEID : natural := 1
);
port(
clk : in std_logic;
ena : in std_logic;
 
Xi : in signed(WIDTH -1 downto 0);
Yi : in signed(WIDTH -1 downto 0);
Zi : in signed(19 downto 0);
 
Xo : out signed(WIDTH -1 downto 0);
Yo : out signed(WIDTH -1 downto 0);
Zo : out signed(19 downto 0)
);
end component r2p_CordicPipe;
 
--
-- SIGNALS
--
signal X, Y : XYVector;
signal Z : ZVector;
 
--
-- ACHITECTURE BODY
--
begin
-- fill first nodes
 
X(0)(WIDTH + EXT_PRECISION -1 downto EXT_PRECISION) <= Xi; -- fill MSBs with input data
X(0)(EXT_PRECISION -1 downto 0) <= (others => '0'); -- fill LSBs with '0'
 
Y(0)(WIDTH + EXT_PRECISION -1 downto EXT_PRECISION) <= Yi; -- fill MSBs with input data
Y(0)(EXT_PRECISION -1 downto 0) <= (others => '0'); -- fill LSBs with '0'
 
Z(0) <= Zi;
 
--
-- generate pipeline
--
gen_pipe:
for n in 1 to PIPELINE generate
Pipe: r2p_CordicPipe
generic map(WIDTH => WIDTH+EXT_PRECISION, PIPEID => n -1)
port map ( clk, ena, X(n-1), Y(n-1), Z(n-1), X(n), Y(n), Z(n) );
end generate gen_pipe;
 
--
-- assign outputs
--
Xo <= X(PIPELINE);
Zo <= Z(PIPELINE);
end dataflow;
 
/trunk/rect2polar/r2p_post.vhd
0,0 → 1,150
--
-- post.vhd
--
-- Cordic post-processing block
--
-- Compensate cordic algorithm K-factor; divide Radius by 1.6467, or multiply by 0.60725.
-- Approximation: Ra = Ri/2 + Ri/8 - Ri/64 - Ri/512
-- Radius = Ra - Ra/4096 = Ri * 0.60727. This is a 0.0034% error.
-- Implementation: Ra = (Ri/2 + Ri/8) - (Ri/64 + Ri/512)
-- Radius = Ra - Ra/4096
-- Position calculated angle in correct quadrant.
--
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
 
entity r2p_post is
port(
clk : in std_logic;
ena : in std_logic;
 
Ai : in signed(19 downto 0);
Ri : in unsigned(19 downto 0);
Q : in std_logic_vector(2 downto 0);
 
Ao : out signed(19 downto 0);
Ro : out unsigned(19 downto 0));
end entity r2p_post;
 
architecture dataflow of r2p_post is
begin
radius: block
signal RadA, RadB, RadC : unsigned(19 downto 0);
begin
process(clk)
begin
if (clk'event and clk = '1') then
if (ena = '1') then
RadA <= ('0' & Ri(19 downto 1)) + ("000" & Ri(19 downto 3));
RadB <= ("000000" & Ri(19 downto 6)) + ("000000000" & Ri(19 downto 9));
RadC <= RadA - RadB;
 
Ro <= RadC - RadC(19 downto 12);
end if;
end if;
end process;
end block radius;
 
angle: block
constant const_PI2 : signed(19 downto 0) := conv_signed(16#40000#, 20); -- PI / 2
constant const_PI : signed(19 downto 0) := conv_signed(16#80000#, 20); -- PI
constant const_2PI : signed(19 downto 0) := (others => '0'); -- 2PI
 
signal dQ : std_logic_vector(2 downto 1);
signal ddQ : std_logic;
signal AngStep1 : signed(19 downto 0);
signal AngStep2 : signed(19 downto 0);
begin
angle_step1: process(clk, Ai, Q)
variable overflow : std_logic;
variable AngA, AngB, Ang : signed(19 downto 0);
begin
-- check if angle is negative, if so set it to zero
overflow := Ai(19); --and Ai(18);
 
if (overflow = '1') then
AngA := (others => '0');
else
AngA := Ai;
end if;
 
-- step 1: Xabs and Yabs are swapped
-- Calculated angle is the angle between vector and Y-axis.
-- ActualAngle = PI/2 - CalculatedAngle
AngB := const_PI2 - AngA;
 
if (Q(0) = '1') then
Ang := AngB;
else
Ang := AngA;
end if;
 
if (clk'event and clk = '1') then
if (ena = '1') then
AngStep1 <= Ang;
dQ <= q(2 downto 1);
end if;
end if;
end process angle_step1;
 
 
angle_step2: process(clk, AngStep1, dQ)
variable AngA, AngB, Ang : signed(19 downto 0);
begin
AngA := AngStep1;
 
-- step 2: Xvalue is negative
-- Actual angle is in the second or third quadrant
-- ActualAngle = PI - CalculatedAngle
AngB := const_PI - AngA;
 
if (dQ(1) = '1') then
Ang := AngB;
else
Ang := AngA;
end if;
 
if (clk'event and clk = '1') then
if (ena = '1') then
AngStep2 <= Ang;
ddQ <= dQ(2);
end if;
end if;
end process angle_step2;
 
 
angle_step3: process(clk, AngStep2, ddQ)
variable AngA, AngB, Ang : signed(19 downto 0);
begin
AngA := AngStep2;
 
-- step 3: Yvalue is negative
-- Actual angle is in the third or fourth quadrant
-- ActualAngle = 2PI - CalculatedAngle
AngB := const_2PI - AngA;
 
if (ddQ = '1') then
Ang := AngB;
else
Ang := AngA;
end if;
if (clk'event and clk = '1') then
if (ena = '1') then
Ao <= Ang;
end if;
end if;
end process angle_step3;
end block angle;
end;
 
 
 
 
 
 
 
 
 
/trunk/rect2polar/r2p_pre.vhd
0,0 → 1,83
--
-- r2p_pre.vhd
--
-- Cordic pre-processing block
--
--
-- step 1: determine quadrant and generate absolute value of X and Y
-- Q1: Xnegative
-- Q2: Ynegative
--
-- step 2: swap X and Y values if Y>X
-- Q3: swapped (Y > X)
--
-- Rev. 1.1 June 4th, 2001. Richard Herveille. Revised entire core.
--
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
 
entity r2p_pre is
port(
clk : in std_logic;
ena : in std_logic;
 
Xi : in signed(15 downto 0);
Yi : in signed(15 downto 0);
 
Xo : out unsigned(14 downto 0);
Yo : out unsigned(14 downto 0);
Q : out std_logic_vector(2 downto 0));
end entity r2p_pre;
 
architecture dataflow of r2p_pre is
signal Xint1, Yint1 : unsigned(14 downto 0);
signal Xneg, Yneg, swap : std_logic;
 
begin
--
-- step 1: Determine absolute value of X and Y, set Xneg and Yneg
-- Loose the sign-bit.
Step1: process(clk, Xi, Yi)
begin
if (clk'event and clk = '1') then
if (ena = '1') then
Xint1 <= conv_unsigned(abs(Xi), 15);
Xneg <= Xi(Xi'left);
 
Yint1 <= conv_unsigned(abs(Yi), 15);
Yneg <= Yi(Yi'left);
end if;
end if;
end process Step1;
 
--
-- step 2: Swap X and Y if Y>X
--
Step2: process(clk, Xint1, Yint1)
variable Xint2, Yint2 : unsigned(14 downto 0);
begin
if (Yint1 > Xint1) then
swap <= '1';
Xint2 := Yint1;
Yint2 := Xint1;
else
swap <= '0';
Xint2 := Xint1;
Yint2 := Yint1;
end if;
if(clk'event and clk = '1') then
if (ena = '1') then
Xo <= Xint2;
Yo <= Yint2;
 
Q <= (Yneg, Xneg, swap);
end if;
end if;
end process Step2;
 
end architecture dataflow;
 
 
/trunk/rect2polar/r2p_corproc.vhd
0,0 → 1,107
--
-- file: r2p_corproc.vhd
--
-- XY to RA coordinate / rectangular to polar coordinates processor
--
-- uses: r2p_pre.vhd, r2p_cordic.vhd, r2p_post.vhd
--
-- rev. 1.1 June 4th, 2001. Richard Herveille. Completely revised core.
--
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
 
entity r2p_corproc is
port(
clk : in std_logic;
ena : in std_logic;
Xin : in signed(15 downto 0);
Yin : in signed(15 downto 0);
Rout : out unsigned(19 downto 0);
Aout : out signed(19 downto 0)
);
end entity r2p_corproc;
 
architecture dataflow of r2p_corproc is
constant PipeLength : natural := 15;
 
component r2p_pre is
port(
clk : in std_logic;
ena : in std_logic;
Xi : in signed(15 downto 0);
Yi : in signed(15 downto 0);
 
Xo : out unsigned(14 downto 0);
Yo : out unsigned(14 downto 0);
Q : out std_logic_vector(2 downto 0)
);
end component r2p_pre;
 
component r2p_cordic is
generic(
PIPELINE : integer;
WIDTH : integer;
EXT_PRECISION : integer
);
port(
clk : in std_logic;
ena : in std_logic;
Xi : in signed(WIDTH-1 downto 0);
Yi : in signed(WIDTH-1 downto 0);
Zi : in signed(19 downto 0) := (others => '0');
 
Xo : out signed(WIDTH + EXT_PRECISION -1 downto 0);
Zo : out signed(19 downto 0));
end component r2p_cordic;
 
component r2p_post is
port(
clk : in std_logic;
ena : in std_logic;
 
Ai : in signed(19 downto 0);
Ri : in unsigned(19 downto 0);
Q : in std_logic_vector(2 downto 0);
 
Ao : out signed(19 downto 0);
Ro : out unsigned(19 downto 0));
end component r2p_post;
 
signal Xpre, Ypre : unsigned(15 downto 0);
signal Acor, Rcor : signed(19 downto 0);
signal Q, dQ : std_logic_vector(2 downto 0);
 
begin
 
-- instantiate components
u1: r2p_pre port map(clk => clk, ena => ena, Xi => Xin, Yi => Yin, Xo => Xpre(14 downto 0), Yo => Ypre(14 downto 0), Q => Q);
Xpre(15) <= '0';
Ypre(15) <= '0';
 
u2: r2p_cordic
generic map(PIPELINE => PipeLength, WIDTH => 16, EXT_PRECISION => 4)
port map(clk => clk, ena => ena, Xi => signed(Xpre), Yi => signed(Ypre), Xo => Rcor, Zo => Acor);
 
delay: block
type delay_type is array(PipeLength -1 downto 0) of std_logic_vector(2 downto 0);
signal delay_pipe :delay_type;
begin
process(clk, Q)
begin
if (clk'event and clk = '1') then
if (ena = '1') then
delay_pipe(0) <= Q;
for n in 1 to PipeLength -1 loop
delay_pipe(n) <= delay_pipe(n -1);
end loop;
end if;
end if;
end process;
dQ <= delay_pipe(PipeLength -1);
end block delay;
 
u3: r2p_post port map(clk => clk, ena => ena, Ri => unsigned(Rcor), Ai => Acor, Q => dQ, Ao => Aout, Ro => Rout);
end architecture dataflow;

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.