Add CORDIC accelerator peripheral and Wishbone wrapper

Signed-off-by: KirupaNithi <kirupanithi789@gmail.com>
pull/463/head
KirupaNithi 1 month ago
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…
Cancel
Save