mirror of
https://github.com/Nuand/bladeRF-wiphy.git
synced 2025-01-29 15:43:59 +00:00
202 lines
8.0 KiB
VHDL
202 lines
8.0 KiB
VHDL
-- This file is part of bladeRF-wiphy.
|
|
--
|
|
-- Copyright (C) 2020 Nuand, LLC.
|
|
--
|
|
-- This program is free software; you can redistribute it and/or modify
|
|
-- it under the terms of the GNU General Public License as published by
|
|
-- the Free Software Foundation; either version 2 of the License, or
|
|
-- (at your option) any later version.
|
|
--
|
|
-- This program is distributed in the hope that it will be useful,
|
|
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
-- GNU General Public License for more details.
|
|
--
|
|
-- You should have received a copy of the GNU General Public License along
|
|
-- with this program; if not, write to the Free Software Foundation, Inc.,
|
|
-- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
|
library ieee ;
|
|
use ieee.std_logic_1164.all ;
|
|
use ieee.numeric_std.all ;
|
|
|
|
package cordic_p is
|
|
|
|
-- Vectoring mode forces outputs.y to 0
|
|
-- Rotation mode forces outputs.z to 0
|
|
type cordic_mode_t is (CORDIC_ROTATION, CORDIC_VECTORING) ;
|
|
|
|
-- TODO: Make this a generic package
|
|
type cordic_xyz_t is record
|
|
x : signed(15 downto 0) ;
|
|
y : signed(15 downto 0) ;
|
|
z : signed(15 downto 0) ;
|
|
valid : std_logic ;
|
|
end record ;
|
|
|
|
end package ; -- cordic_p
|
|
|
|
library ieee ;
|
|
use ieee.std_logic_1164.all ;
|
|
use ieee.numeric_std.all ;
|
|
use ieee.math_real.all ;
|
|
|
|
library work ;
|
|
use work.cordic_p.all ;
|
|
|
|
entity cordic is
|
|
port (
|
|
clock : in std_logic ;
|
|
reset : in std_logic ;
|
|
mode : in cordic_mode_t ;
|
|
inputs : in cordic_xyz_t ;
|
|
normalized : out cordic_xyz_t ;
|
|
outputs : out cordic_xyz_t
|
|
) ;
|
|
end entity ; -- cordic
|
|
|
|
architecture arch of cordic is
|
|
|
|
-- TODO: Make this generic
|
|
constant NUM_STAGES : natural := 14 ;
|
|
|
|
-- TODO: Use the VHDL-2008 integer_vector
|
|
type integer_array_t is array(natural range <>) of integer ;
|
|
|
|
-- Each stage of the CORDIC is atan(2^(-i))
|
|
function calculate_cordic_table return integer_array_t is
|
|
variable rv : integer_array_t(0 to NUM_STAGES-1) := (others => 0) ;
|
|
begin
|
|
for i in 0 to rv'high loop
|
|
rv(i) := integer(round((2.0**NUM_STAGES)*arctan(2.0**(-i))/MATH_PI)) ;
|
|
end loop ;
|
|
return rv ;
|
|
end function ;
|
|
|
|
-- Constant array
|
|
constant K : integer_array_t := calculate_cordic_table ;
|
|
|
|
-- The array for CORDIC stages
|
|
type xyzs_t is array(0 to NUM_STAGES-1) of cordic_xyz_t ;
|
|
|
|
-- ALl the XYZ's for the CORDIC stages
|
|
signal xyzs : xyzs_t ;
|
|
signal nxyzs : xyzs_t ;
|
|
|
|
signal nflip : std_logic_vector(0 to NUM_STAGES-1) ;
|
|
begin
|
|
|
|
rotate : process(clock, reset)
|
|
begin
|
|
if( reset = '1' ) then
|
|
xyzs <= (others =>(x => (others =>'0'), y => (others =>'0'), z => (others =>'0'), valid => '0')) ;
|
|
nxyzs <= (others =>(x => (others =>'0'), y => (others =>'0'), z => (others =>'0'), valid => '0')) ;
|
|
nflip <= (others => '0') ;
|
|
elsif( rising_edge( clock ) ) then
|
|
-- First stage will rotate the vector to be within -pi/2 to pi/2
|
|
xyzs(0).valid <= inputs.valid ;
|
|
nxyzs(0).valid <= inputs.valid ;
|
|
if( inputs.valid = '1' ) then
|
|
case mode is
|
|
when CORDIC_ROTATION =>
|
|
-- Make sure we're only rotating -pi/2 to pi/2 and adjust accordingly
|
|
if( inputs.z > 2**(NUM_STAGES-1) ) then
|
|
xyzs(0).x <= -inputs.x ;
|
|
xyzs(0).y <= -inputs.y ;
|
|
xyzs(0).z <= inputs.z - 2**NUM_STAGES ;
|
|
elsif( inputs.z < -(2**(NUM_STAGES-1)) ) then
|
|
xyzs(0).x <= -inputs.x ;
|
|
xyzs(0).y <= -inputs.y ;
|
|
xyzs(0).z <= inputs.z + 2**NUM_STAGES ;
|
|
else
|
|
xyzs(0).x <= inputs.x ;
|
|
xyzs(0).y <= inputs.y ;
|
|
xyzs(0).z <= inputs.z ;
|
|
end if ;
|
|
when CORDIC_VECTORING =>
|
|
nxyzs(0).x <= to_signed(1243, nxyzs(0).x'length) ;
|
|
nxyzs(0).y <= (others => '0') ;
|
|
nflip(0) <= '1' ;
|
|
|
|
-- Make sure we're in the 1st or 4th quadrant only
|
|
if( inputs.x < 0 and inputs.y < 0 ) then
|
|
xyzs(0).x <= -inputs.x ;
|
|
xyzs(0).y <= -inputs.y ;
|
|
xyzs(0).z <= inputs.z - 2**(NUM_STAGES) ;
|
|
elsif( inputs.x < 0 ) then
|
|
xyzs(0).x <= -inputs.x ;
|
|
xyzs(0).y <= -inputs.y ;
|
|
xyzs(0).z <= inputs.z + 2**(NUM_STAGES) ;
|
|
else
|
|
xyzs(0).x <= inputs.x ;
|
|
xyzs(0).y <= inputs.y ;
|
|
xyzs(0).z <= inputs.z ;
|
|
nflip(0) <= '0' ;
|
|
end if ;
|
|
end case ;
|
|
|
|
end if ;
|
|
|
|
-- Run through all the other stages
|
|
for i in 0 to xyzs'high-1 loop
|
|
xyzs(i+1).valid <= xyzs(i).valid ;
|
|
nxyzs(i+1).valid <= nxyzs(i).valid ;
|
|
nflip(i+1) <= nflip(i) ;
|
|
if( xyzs(i).valid = '1' ) then
|
|
case mode is
|
|
when CORDIC_ROTATION =>
|
|
if( xyzs(i).z < 0 ) then
|
|
xyzs(i+1).x <= xyzs(i).x + shift_right(xyzs(i).y, i) ;
|
|
xyzs(i+1).y <= xyzs(i).y - shift_right(xyzs(i).x, i) ;
|
|
xyzs(i+1).z <= xyzs(i).z + K(i) ;
|
|
else
|
|
xyzs(i+1).x <= xyzs(i).x - shift_right(xyzs(i).y, i) ;
|
|
xyzs(i+1).y <= xyzs(i).y + shift_right(xyzs(i).x, i) ;
|
|
xyzs(i+1).z <= xyzs(i).z - K(i) ;
|
|
end if ;
|
|
when CORDIC_VECTORING =>
|
|
if( xyzs(i).y < 0 ) then
|
|
xyzs(i+1).x <= xyzs(i).x - shift_right(xyzs(i).y, i) ;
|
|
xyzs(i+1).y <= xyzs(i).y + shift_right(xyzs(i).x, i) ;
|
|
xyzs(i+1).z <= xyzs(i).z - K(i) ;
|
|
|
|
nxyzs(i+1).x <= nxyzs(i).x + shift_right(nxyzs(i).y, i) ;
|
|
nxyzs(i+1).y <= nxyzs(i).y - shift_right(nxyzs(i).x, i) ;
|
|
else
|
|
xyzs(i+1).x <= xyzs(i).x + shift_right(xyzs(i).y, i) ;
|
|
xyzs(i+1).y <= xyzs(i).y - shift_right(xyzs(i).x, i) ;
|
|
xyzs(i+1).z <= xyzs(i).z + K(i) ;
|
|
|
|
nxyzs(i+1).x <= nxyzs(i).x - shift_right(nxyzs(i).y, i) ;
|
|
nxyzs(i+1).y <= nxyzs(i).y + shift_right(nxyzs(i).x, i) ;
|
|
end if ;
|
|
end case ;
|
|
end if ;
|
|
end loop ;
|
|
|
|
-- Output stage
|
|
outputs <= xyzs(xyzs'high) ;
|
|
end if ;
|
|
end process ;
|
|
|
|
normalized_output : process(clock, reset)
|
|
begin
|
|
if( reset = '1' ) then
|
|
normalized <= (x => (others =>'0'), y => (others =>'0'), z => (others =>'0'), valid => '0') ;
|
|
elsif( rising_edge( clock ) ) then
|
|
normalized.valid <= '0' ;
|
|
if( nxyzs(nxyzs'high).valid = '1' ) then
|
|
if( nflip(nflip'high) = '1' ) then
|
|
normalized.x <= - nxyzs(nxyzs'high).x ;
|
|
normalized.y <= - nxyzs(nxyzs'high).y ;
|
|
else
|
|
normalized.x <= nxyzs(nxyzs'high).x ;
|
|
normalized.y <= nxyzs(nxyzs'high).y ;
|
|
end if ;
|
|
normalized.valid <= '1' ;
|
|
end if ;
|
|
end if ;
|
|
end process ;
|
|
|
|
end architecture ; -- arch
|