cordic

extras/cordic.vhdl

Dependencies

pipelining

Description

This package provides components and procedures used to implement the CORDIC algorithm for rotations. A variety of implementations are provided to meet different design requirements. These implementations are flexible in all parameters and are not constrained by a fixed arctan table.

A pair of procedures provide pure combinational CORDIC implementations:

  • rotate procedure - Combinational CORDIC in rotation mode
  • vector procedure - Combinational CORDIC in vectoring mode

The CORDIC components provide both rotation or vectoring mode based on a Mode input:

  • cordic_sequential - Iterative algorithm with minimal hardware
  • cordic_pipelined - One pipeline stage per iteration
  • cordic_flex_pipelined - Selectable pipeline stages independent of
    the number of iterations

A set of wrapper components are provided to conveniently generate sin and cos:

  • sincos_sequential - Iterative algorithm with minimal hardware
  • sincos_pipelined - One pipeline stage per iteration

These CORDIC implementations take a common set of parameters. There are X, Y, and Z inputs defining the initial vector and angle value. The result is produced in a set of X, Y, and Z outputs. Depending on which CORDIC operation you are using, some inputs may be constants and some outputs may be ignored.

The CORDIC algorithm performs pseudo-rotations that cause an unwanted growth in the length of the result vector. This growth is a gain parameter that approaches 1.647 but is dependent on the number of iterations performed. The cordic_gain() function produces a real-valued gain for a specified number of iterations. This can be converted to a synthesizable integer constant with the following:

gain := integer(cordic_gain(ITERATIONS) * 2.0 ** FRAC_BITS)

With some operations you can adjust the input vector by dividing by the gain ahead of time. In other cases you have to correct for the gain after the CORDIC operation. The gain from pseudo-rotation never affects the Z parameter.

The following are some of the operations that can be performed with the CORDIC algorithm:

sin and cos:

X0 = 1/gain, Y0 = 0, Z0 = angle; rotate → sin(Z0) in Y, cos(Z0) in X

polar to rectangular:

X0 = magnitude, Y0 = 0, Z0 = angle; rotate → gain*X in X, gain*Y in Y

arctan:

Y0 = y, X0 = x, Z0 = 0; vector → arctan(Y0/X0) in Z

rectangular to polar:

Y0 = y, X0 = x, Z0 = 0; vector → gain*magnitude in X, angle in Z

The X and Y parameters are represented as unconstrained signed vectors. You establish the precision of a CORDIC implementation by selecting the width of these vectors. The interpretation of these numbers does not affect the internal CORDIC implementation but most implementations will need them to be fixed point integers with the maximum number of fractional bits possible. When calculating sin and cos, the output is constrained to the range +/-1.0. Thus we only need to reserve two bits for the sign and integral portion of the numbers. The remaining bits can be fractional. Operations that work on larger vectors outside of the unit circle need to ensure that a sufficient number of integer bits are present to prevent overflow of X and Y.

The angle parameter Z should be provided in units of binary-radians or brads. \(2\pi \text{ radians} = 2^\text{size} \text{ brads}\) for “size” number of bits. This maps the entire binary range of Z to the unit circle. The Z parameter is represented by the signed type in all of these CORDIC implementations but it can be viewed as an unsigned value. Because of the circular mapping, signed and unsigned angles are equivalent. It is easiest to think of the angle Z as an integer without fractional bits like X and Y. There is no risk of overflowing Z becuase of the circular mapping.

The circular CORDIC algorithm only converges between angles of +/- 99.7 degrees. If you want to use angles covering all four quadrants you must condition the inputs to the CORDIC algorithm using the adjust_angle() procedure. This will perform conditional negation on X and Y and flip the sign bit on Z to bring vectors in quadrants 2 and 3 (1-based) into quadrants 1 and 4.

Example usage

You can use the two functions rotate() and vector() to perform a single iteration cycle of CORDIC. This can be used for simulation purposes or wrapped in a registered process for specialized synthesis implementations. The entire CORDIC core will be synthesized as a combinational blob. You can use register retiming techniques to improve the performance.

signal X, Y, Z, Xr, Yr, Zr : signed(9 downto 0);
constant ITERATIONS : integer : 5;
...

reg: process(clock, reset) is
begin
  if reset = '1' then
    Xr <= (others => '0');
    Yr <= (others => '0');
    Zr <= (others => '0');
  elsif rising_edge(clock) then
    rotate(ITERATIONS, X, Y, Z, Xr, Yr, Zr);
  end if;
end process;

The components implemented in this package offer a number of different synthesizable CORDIC implementations and wrappers to generate Sine and Cosine waveforms.

constant ITERATIONS : positive := 8;

-- 1 sign bit + 1 integer bit + 8 fraction bits
signal X, Y, Z, Xr, Yr, Zr : signed(9 downto 0);

-- Sequential implementation
cs: cordic_sequential
  generic map (
    SIZE       => X'length,
    ITERATIONS => ITERATIONS
  )
  port map (
    Clock => clock,
    Reset => reset,

    Data_valid   => data_valid,
    Busy         => busy,
    Result_valid => result_valid,
    Mode         => cordic_rotate,

    X => X,
    Y => Y,
    Z => Z,

    X_result => Xr,
    Y_result => Yr,
    Z_result => Zr
  );

Types

cordic.cordic_mode

Rotation or vector mode selection.

Components

cordic_pipelined

component cordic_pipelined is generic ( SIZE : positive; ITERATIONS : positive; RESET_ACTIVE_LEVEL : std_ulogic ); port ( --# {{clocks|}} Clock : in std_ulogic; Reset : in std_ulogic; --# {{control|}} Mode : in cordic_mode; --# {{data|}} X : in signed(SIZE-1 downto 0); Y : in signed(SIZE-1 downto 0); Z : in signed(SIZE-1 downto 0); X_result : out signed(SIZE-1 downto 0); Y_result : out signed(SIZE-1 downto 0); Z_result : out signed(SIZE-1 downto 0) ); end component;


cordic.cordic_pipelined

CORDIC with pipeline registers between each stage.

Generics:
  • SIZE (positive) – Width of operands
  • ITERATIONS (positive) – Number of iterations for CORDIC algorithm
  • RESET_ACTIVE_LEVEL (std_ulogic) – Asynch. reset control level
Port:
  • Clock (in std_ulogic) – System clock
  • Reset (in std_ulogic) – Asynchronous reset
  • Mode (in cordic_mode) – Rotation or vector mode selection
  • X (in signed(SIZE-1 downto 0)) – X coordinate
  • Y (in signed(SIZE-1 downto 0)) – Y coordinate
  • Z (in signed(SIZE-1 downto 0)) – Z coordinate (angle in brads)
  • X_result (out signed(SIZE-1 downto 0)) – X result
  • Y_result (out signed(SIZE-1 downto 0)) – Y result
  • Z_result (out signed(SIZE-1 downto 0)) – Z result

cordic_sequential

component cordic_sequential is generic ( SIZE : positive; ITERATIONS : positive; RESET_ACTIVE_LEVEL : std_ulogic ); port ( --# {{clocks|}} Clock : in std_ulogic; Reset : in std_ulogic; --# {{control|}} Data_valid : in std_ulogic; Busy : out std_ulogic; Result_valid : out std_ulogic; Mode : in cordic_mode; --# {{data|}} X : in signed(SIZE-1 downto 0); Y : in signed(SIZE-1 downto 0); Z : in signed(SIZE-1 downto 0); X_result : out signed(SIZE-1 downto 0); Y_result : out signed(SIZE-1 downto 0); Z_result : out signed(SIZE-1 downto 0) ); end component;


cordic.cordic_sequential

CORDIC with a single stage applied iteratively.

Generics:
  • SIZE (positive) – Width of operands
  • ITERATIONS (positive) – Number of iterations for CORDIC algorithm
  • RESET_ACTIVE_LEVEL (std_ulogic) – Asynch. reset control level
Port:
  • Clock (in std_ulogic) – System clock
  • Reset (in std_ulogic) – Asynchronous reset
  • Data_valid (in std_ulogic) – Load new input data
  • Busy (out std_ulogic) – Generating new result
  • Result_valid (out std_ulogic) – Flag when result is valid
  • Mode (in cordic_mode) – Rotation or vector mode selection
  • X (in signed(SIZE-1 downto 0)) – X coordinate
  • Y (in signed(SIZE-1 downto 0)) – Y coordinate
  • Z (in signed(SIZE-1 downto 0)) – Z coordinate (angle in brads)
  • X_result (out signed(SIZE-1 downto 0)) – X result
  • Y_result (out signed(SIZE-1 downto 0)) – Y result
  • Z_result (out signed(SIZE-1 downto 0)) – Z result

cordic_flex_pipelined

component cordic_flex_pipelined is generic ( SIZE : positive; ITERATIONS : positive; PIPELINE_STAGES : natural; RESET_ACTIVE_LEVEL : std_ulogic ); port ( --# {{clocks|}} Clock : in std_ulogic; Reset : in std_ulogic; --# {{control|}} Mode : in cordic_mode; --# {{data|}} X : in signed(SIZE-1 downto 0); Y : in signed(SIZE-1 downto 0); Z : in signed(SIZE-1 downto 0); X_result : out signed(SIZE-1 downto 0); Y_result : out signed(SIZE-1 downto 0); Z_result : out signed(SIZE-1 downto 0) ); end component;


cordic.cordic_flex_pipelined

CORDIC with pipelining implemented with register retiming. This variant can be used to have more or fewer pipeline stages than the number of iterations to fine tune performance and resource usage.

Generics:
  • SIZE (positive) – Width of operands
  • ITERATIONS (positive) – Number of iterations for CORDIC algorithm
  • PIPELINE_STAGES (natural) – Number of register stages
  • RESET_ACTIVE_LEVEL (std_ulogic) – Asynch. reset control level
Port:
  • Clock (in std_ulogic) – System clock
  • Reset (in std_ulogic) – Asynchronous reset
  • Mode (in cordic_mode) – Rotation or vector mode selection
  • X (in signed(SIZE-1 downto 0)) – X coordinate
  • Y (in signed(SIZE-1 downto 0)) – Y coordinate
  • Z (in signed(SIZE-1 downto 0)) – Z coordinate (angle in brads)
  • X_result (out signed(SIZE-1 downto 0)) – X result
  • Y_result (out signed(SIZE-1 downto 0)) – Y result
  • Z_result (out signed(SIZE-1 downto 0)) – Z result

sincos_pipelined

component sincos_pipelined is generic ( SIZE : positive; ITERATIONS : positive; FRAC_BITS : positive; MAGNITUDE : real; RESET_ACTIVE_LEVEL : std_ulogic ); port ( --# {{clocks|}} Clock : in std_ulogic; Reset : in std_ulogic; --# {{control|}} Angle : in signed(SIZE-1 downto 0); --# {{data|}} Sin : out signed(SIZE-1 downto 0); Cos : out signed(SIZE-1 downto 0) ); end component;


cordic.sincos_pipelined

Compute Sine and Cosine with a pipelined CORDIC implementation.

Generics:
  • SIZE (positive) – Width of operands
  • ITERATIONS (positive) – Number of iterations for CORDIC algorithm
  • FRAC_BITS (positive) – Total fractional bits
  • MAGNITUDE (real) – Scale factor for vector length
  • RESET_ACTIVE_LEVEL (std_ulogic) – Asynch. reset control level
Port:
  • Clock (in std_ulogic) – System clock
  • Reset (in std_ulogic) – Asynchronous reset
  • Angle (in signed(SIZE-1 downto 0)) – Angle in brads (2**SIZE brads = 2*pi radians)
  • Sin (out signed(SIZE-1 downto 0)) – Sine of Angle
  • Cos (out signed(SIZE-1 downto 0)) – Cosine of Angle

sincos_sequential

component sincos_sequential is generic ( SIZE : positive; ITERATIONS : positive; FRAC_BITS : positive; MAGNITUDE : real; RESET_ACTIVE_LEVEL : std_ulogic ); port ( --# {{clocks|}} Clock : in std_ulogic; Reset : in std_ulogic; --# {{control|}} Data_valid : in std_ulogic; Busy : out std_ulogic; Result_valid : out std_ulogic; Angle : in signed(SIZE-1 downto 0); --# {{data|}} Sin : out signed(SIZE-1 downto 0); Cos : out signed(SIZE-1 downto 0) ); end component;


cordic.sincos_sequential

Compute Sine and Cosine with a sequential CORDIC implementation.

Generics:
  • SIZE (positive) – Width of operands
  • ITERATIONS (positive) – Number of iterations for CORDIC algorithm
  • FRAC_BITS (positive) – Total fractional bits
  • MAGNITUDE (real) – Scale factor for vector length
  • RESET_ACTIVE_LEVEL (std_ulogic) – Asynch. reset control level
Port:
  • Clock (in std_ulogic) – System clock
  • Reset (in std_ulogic) – Asynchronous reset
  • Data_valid (in std_ulogic) – Load new input data
  • Busy (out std_ulogic) – Generating new result
  • Result_valid (out std_ulogic) – Flag when result is valid
  • Angle (in signed(SIZE-1 downto 0)) – Angle in brads (2**SIZE brads = 2*pi radians)
  • Sin (out signed(SIZE-1 downto 0)) – Sine of Angle
  • Cos (out signed(SIZE-1 downto 0)) – Cosine of Angle

Subprograms

cordic.cordic_gain (Iterations : positive) → real
Compute vector length gain after applying CORDIC.
Parameters:
  • Iterations (positive) – Number of iterations
Returns:

Gain factor.

cordic.adjust_angle (X : in signed; Y : in signed; Z : in signed; Xa : out signed; Ya : out signed; Za : out signed)
Correct angle so that it lies in quadrant 1 or 4.
Parameters:
  • X (in signed) – X coordinate
  • Y (in signed) – Y coordinate
  • Z (in signed) – Z coordinate (angle)
  • Xa (out signed) – Adjusted X coordinate
  • Ya (out signed) – Adjusted Y coordinate
  • Za (out signed) – Adjusted Z coordinate (angle)
cordic.rotate (iterations : in integer; X : in signed; Y : in signed; Z : in signed; Xr : out signed; Yr : out signed; Zr : out signed)
Apply a single iteration of CORDIC rotation mode.
Parameters:
  • X (in signed) – X coordinate
  • Y (in signed) – Y coordinate
  • Z (in signed) – Z coordinate (angle)
  • Xr (out signed) – Rotated X coordinate
  • Yr (out signed) – Rotated Y coordinate
  • Zr (out signed) – Rotated Z coordinate (angle)
cordic.vector (iterations : in integer; X : in signed; Y : in signed; Z : in signed; Xr : out signed; Yr : out signed; Zr : out signed)
Apply a single iteration of CORDIC vector mode.
Parameters:
  • X (in signed) – X coordinate
  • Y (in signed) – Y coordinate
  • Z (in signed) – Z coordinate (angle)
  • Xr (out signed) – Vectored X coordinate
  • Yr (out signed) – Vectored Y coordinate
  • Zr (out signed) – Vectored Z coordinate (angle)
cordic.effective_fractional_bits (Iterations : positive; Frac_bits : positive) → real
Compute the number of usable fractional bits in CORDIC result.
Parameters:
  • Iterations (positive) – Number of CORDIC iterations
  • Frac_bits (positive) – Fractional bits in the input coordinates
Returns:

Effective number of fractional bits.