Merge 215cb19638 into 6081646638
commit
ff4633bd4c
@ -0,0 +1,113 @@
|
|||||||
|
library ieee;
|
||||||
|
use ieee.std_logic_1164.all;
|
||||||
|
use ieee.numeric_std.all;
|
||||||
|
|
||||||
|
entity cordic is
|
||||||
|
generic (
|
||||||
|
DATA_WIDTH : integer := 16;
|
||||||
|
ANGLE_WIDTH : integer := 32;
|
||||||
|
ITER : integer := 16
|
||||||
|
);
|
||||||
|
port (
|
||||||
|
clk : in std_logic;
|
||||||
|
angle : in signed(ANGLE_WIDTH-1 downto 0);
|
||||||
|
Xin : in signed(DATA_WIDTH-1 downto 0);
|
||||||
|
Yin : in signed(DATA_WIDTH-1 downto 0);
|
||||||
|
Xout : out signed(DATA_WIDTH downto 0);
|
||||||
|
Yout : out signed(DATA_WIDTH downto 0)
|
||||||
|
);
|
||||||
|
end entity;
|
||||||
|
|
||||||
|
architecture rtl of cordic is
|
||||||
|
|
||||||
|
type vec_data is array (0 to ITER-1) of signed(DATA_WIDTH downto 0);
|
||||||
|
type vec_angle is array (0 to ITER-1) of signed(ANGLE_WIDTH-1 downto 0);
|
||||||
|
|
||||||
|
signal X : vec_data := (others => (others => '0'));
|
||||||
|
signal Y : vec_data := (others => (others => '0'));
|
||||||
|
signal Z : vec_angle := (others => (others => '0'));
|
||||||
|
|
||||||
|
|
||||||
|
-- π/2 = 2^(ANGLE_WIDTH-2)
|
||||||
|
constant PI_OVER_2 : signed(ANGLE_WIDTH-1 downto 0)
|
||||||
|
:= to_signed(1, ANGLE_WIDTH) sll (ANGLE_WIDTH-2);
|
||||||
|
|
||||||
|
-- Arctan LUT
|
||||||
|
type lut_t is array (0 to 15) of signed(ANGLE_WIDTH-1 downto 0);
|
||||||
|
constant atan_lut : lut_t := (
|
||||||
|
to_signed(16#20000000#, ANGLE_WIDTH),
|
||||||
|
to_signed(16#12B4040D#, ANGLE_WIDTH),
|
||||||
|
to_signed(16#09FB180B#, ANGLE_WIDTH),
|
||||||
|
to_signed(16#05110875#, ANGLE_WIDTH),
|
||||||
|
to_signed(16#028B0D43#, ANGLE_WIDTH),
|
||||||
|
to_signed(16#0142BBF1#, ANGLE_WIDTH),
|
||||||
|
to_signed(16#00A159CE#, ANGLE_WIDTH),
|
||||||
|
to_signed(16#0050AC15#, ANGLE_WIDTH),
|
||||||
|
to_signed(16#00285653#, ANGLE_WIDTH),
|
||||||
|
to_signed(16#00142F8E#, ANGLE_WIDTH),
|
||||||
|
to_signed(16#000A17C8#, ANGLE_WIDTH),
|
||||||
|
to_signed(16#00050BE4#, ANGLE_WIDTH),
|
||||||
|
to_signed(16#000285F3#, ANGLE_WIDTH),
|
||||||
|
to_signed(16#000142FB#, ANGLE_WIDTH),
|
||||||
|
to_signed(16#0000A17D#, ANGLE_WIDTH),
|
||||||
|
to_signed(16#000050BE#, ANGLE_WIDTH)
|
||||||
|
);
|
||||||
|
|
||||||
|
begin
|
||||||
|
|
||||||
|
-- Stage 0 (safe assignments using explicit resize)
|
||||||
|
stage0: process(clk)
|
||||||
|
-- temporaries with the target widths so we never assign unknown sized vectors
|
||||||
|
variable Xin_ext : signed(DATA_WIDTH downto 0);
|
||||||
|
variable Yin_ext : signed(DATA_WIDTH downto 0);
|
||||||
|
variable angle_ext: signed(ANGLE_WIDTH-1 downto 0);
|
||||||
|
begin
|
||||||
|
if rising_edge(clk) then
|
||||||
|
-- make explicit widths
|
||||||
|
Xin_ext := resize(Xin, DATA_WIDTH + 1);
|
||||||
|
Yin_ext := resize(Yin, DATA_WIDTH + 1);
|
||||||
|
angle_ext := resize(angle, ANGLE_WIDTH);
|
||||||
|
|
||||||
|
-- quadrant handling (same semantics as before)
|
||||||
|
if angle_ext > PI_OVER_2 then
|
||||||
|
X(0) <= -Xin_ext; -- note: rotate by +90 (X <- -Y)
|
||||||
|
Y(0) <= Xin_ext; -- rotate inputs intentionally preserved style
|
||||||
|
Z(0) <= angle_ext - PI_OVER_2;
|
||||||
|
elsif angle_ext < -PI_OVER_2 then
|
||||||
|
X(0) <= Yin_ext;
|
||||||
|
Y(0) <= -Xin_ext;
|
||||||
|
Z(0) <= angle_ext + PI_OVER_2;
|
||||||
|
else
|
||||||
|
X(0) <= Xin_ext;
|
||||||
|
Y(0) <= Yin_ext;
|
||||||
|
Z(0) <= angle_ext;
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
end process stage0;
|
||||||
|
-- Iterative pipeline
|
||||||
|
gen: for i in 0 to ITER-2 generate
|
||||||
|
process(clk)
|
||||||
|
variable X_shr, Y_shr : signed(DATA_WIDTH downto 0);
|
||||||
|
begin
|
||||||
|
if rising_edge(clk) then
|
||||||
|
X_shr := X(i) sra i;
|
||||||
|
Y_shr := Y(i) sra i;
|
||||||
|
|
||||||
|
if Z(i)(ANGLE_WIDTH-1) = '1' then
|
||||||
|
X(i+1) <= X(i) + Y_shr;
|
||||||
|
Y(i+1) <= Y(i) - X_shr;
|
||||||
|
Z(i+1) <= Z(i) + atan_lut(i);
|
||||||
|
else
|
||||||
|
X(i+1) <= X(i) - Y_shr;
|
||||||
|
Y(i+1) <= Y(i) + X_shr;
|
||||||
|
Z(i+1) <= Z(i) - atan_lut(i);
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
end process;
|
||||||
|
end generate;
|
||||||
|
|
||||||
|
Xout <= X(ITER-1);
|
||||||
|
Yout <= Y(ITER-1);
|
||||||
|
|
||||||
|
end architecture;
|
||||||
|
|
||||||
@ -0,0 +1,86 @@
|
|||||||
|
library ieee;
|
||||||
|
use ieee.std_logic_1164.all;
|
||||||
|
use ieee.numeric_std.all;
|
||||||
|
|
||||||
|
entity cordic_wb is
|
||||||
|
port(
|
||||||
|
clk : in std_ulogic;
|
||||||
|
rst : in std_ulogic;
|
||||||
|
|
||||||
|
-- Wishbone IO interface (Microwatt)
|
||||||
|
wb_adr_i : in std_ulogic_vector(29 downto 0);
|
||||||
|
wb_dat_i : in std_ulogic_vector(31 downto 0);
|
||||||
|
wb_dat_o : out std_ulogic_vector(31 downto 0);
|
||||||
|
wb_we_i : in std_ulogic;
|
||||||
|
wb_stb_i : in std_ulogic;
|
||||||
|
wb_cyc_i : in std_ulogic;
|
||||||
|
wb_ack_o : out std_ulogic;
|
||||||
|
|
||||||
|
-- CORDIC core interface
|
||||||
|
cordic_x : out std_ulogic_vector(31 downto 0);
|
||||||
|
cordic_y : out std_ulogic_vector(31 downto 0);
|
||||||
|
cordic_start : out std_ulogic;
|
||||||
|
cordic_done : in std_ulogic;
|
||||||
|
cordic_result : in std_ulogic_vector(31 downto 0)
|
||||||
|
);
|
||||||
|
end entity cordic_wb;
|
||||||
|
|
||||||
|
architecture rtl of cordic_wb is
|
||||||
|
|
||||||
|
signal x_reg : std_ulogic_vector(31 downto 0) := (others => '0');
|
||||||
|
signal y_reg : std_ulogic_vector(31 downto 0) := (others => '0');
|
||||||
|
signal start_reg : std_ulogic := '0';
|
||||||
|
|
||||||
|
begin
|
||||||
|
|
||||||
|
-- Drive CORDIC core
|
||||||
|
cordic_x <= x_reg;
|
||||||
|
cordic_y <= y_reg;
|
||||||
|
cordic_start <= start_reg;
|
||||||
|
|
||||||
|
-- Wishbone slave
|
||||||
|
process(clk)
|
||||||
|
variable addr : std_ulogic_vector(2 downto 0);
|
||||||
|
begin
|
||||||
|
if rising_edge(clk) then
|
||||||
|
wb_ack_o <= '0';
|
||||||
|
|
||||||
|
if rst = '1' then
|
||||||
|
x_reg <= (others => '0');
|
||||||
|
y_reg <= (others => '0');
|
||||||
|
start_reg <= '0';
|
||||||
|
wb_dat_o <= (others => '0');
|
||||||
|
|
||||||
|
elsif wb_cyc_i = '1' and wb_stb_i = '1' then
|
||||||
|
wb_ack_o <= '1';
|
||||||
|
addr := wb_adr_i(4 downto 2); -- word offsets
|
||||||
|
|
||||||
|
if wb_we_i = '1' then
|
||||||
|
-- WRITE
|
||||||
|
case addr is
|
||||||
|
when "000" => x_reg <= wb_dat_i; -- 0x00
|
||||||
|
when "001" => y_reg <= wb_dat_i; -- 0x04
|
||||||
|
when "010" => start_reg <= wb_dat_i(0); -- 0x08
|
||||||
|
when others => null;
|
||||||
|
end case;
|
||||||
|
else
|
||||||
|
-- READ
|
||||||
|
case addr is
|
||||||
|
when "000" => wb_dat_o <= x_reg; -- 0x00
|
||||||
|
when "001" => wb_dat_o <= y_reg; -- 0x04
|
||||||
|
when "011" => wb_dat_o <= (31 downto 1 => '0') & cordic_done; -- 0x0C
|
||||||
|
when "100" => wb_dat_o <= cordic_result; -- 0x10
|
||||||
|
when others => wb_dat_o <= (others => '0');
|
||||||
|
end case;
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
-- Auto-clear start when done
|
||||||
|
if cordic_done = '1' then
|
||||||
|
start_reg <= '0';
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
end process;
|
||||||
|
|
||||||
|
end architecture rtl;
|
||||||
|
|
||||||
Loading…
Reference in New Issue