Add CORDIC accelerator peripheral and Wishbone wrapper
Signed-off-by: KirupaNithi <kirupanithi789@gmail.com>pull/463/head
parent
efd0571b5f
commit
1f4d363934
@ -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