diff --git a/lib/emac/src/shifter.vhd b/lib/emac/src/shifter.vhd new file mode 100644 index 0000000..b0d09d2 --- /dev/null +++ b/lib/emac/src/shifter.vhd @@ -0,0 +1,112 @@ +LIBRARY IEEE; +USE IEEE.STD_LOGIC_1164.ALL; +USE IEEE.NUMERIC_STD.ALL; +use std.textio.all; -- Imports the standard textio package. + +use work.utils_pkg.all; -- Imports the standard textio package. + +ENTITY shifter IS + Generic + ( + data_width : natural := 32; + aggregate_size : natural := 8; + do_pipelined : boolean := true + ); + Port + ( + rst : in STD_LOGIC; + clk : in STD_LOGIC; + shift_left : in STD_LOGIC; + sa : in unsigned(NextExpBaseTwo(data_width/aggregate_size)-1 downto 0); + din_vld : in STD_LOGIC; + din : in unsigned(data_width-1 downto 0); + dout_vld : out STD_LOGIC; + dout : out unsigned(data_width-1 downto 0) + + ); +END shifter; + +ARCHITECTURE behavior OF shifter IS + + constant num_rounds : natural := NextExpBaseTwo(data_width/aggregate_size); + subtype word_t is unsigned(data_width-1 downto 0); + type word_array_t is array (0 to num_rounds) of word_t; + + signal rot_data : word_array_t; + signal sa_rnd : unsigned (num_rounds-1 downto 0); + + subtype sa_rnd_t is unsigned(num_rounds-1 downto 0); + type sa_rnd_array_t is array (0 to num_rounds) of sa_rnd_t; + signal sa_rnd_pipe : sa_rnd_array_t; + signal dout_vld_pipe : unsigned(0 to num_rounds); + +-------------------------------------------------------------------------- +function rot_stage(x : unsigned; en : std_logic; stage_num : natural; size : natural) return unsigned is + variable result : unsigned(x'range); + constant sa : natural := (2**stage_num) * size; + begin + if en = '1' then + result := x(sa-1 downto 0) & x(x'left downto sa); + else + result := x; + end if; + return result; +end rot_stage; + +-------------------------------------------------------------------------- +begin + +-------------------------------------------------------------------------- +gen_non_pipelined: +if do_pipelined = false generate +begin + + rot_data(0) <= din; + +gen_rotate_right: + for stage in 0 to num_rounds-1 generate + begin + rot_data(stage+1) <= rot_stage(rot_data(stage), sa_rnd(stage), stage, aggregate_size); + end generate; + + sa_rnd <= not sa + 1 when shift_left = '1' else sa; + dout <= rot_data(num_rounds); + dout_vld <= din_vld; + +end generate; + +-------------------------------------------------------------------------- +gen_pipelined: +if do_pipelined = true generate +begin + + rot_data(0) <= din; + sa_rnd_pipe(0) <= not sa + 1 when shift_left = '1' else sa; + dout_vld_pipe(0) <= din_vld; + +gen_rotate_right: + for stage in 0 to num_rounds-1 generate + begin + process(clk) + begin + if rising_edge(clk) then + if rst = '1' then + dout_vld_pipe(stage+1) <= '0'; + else + dout_vld_pipe(stage+1) <= dout_vld_pipe(stage); + if dout_vld_pipe(stage) = '1' then + sa_rnd_pipe(stage+1) <= sa_rnd_pipe(stage); + rot_data(stage+1) <= rot_stage(rot_data(stage), sa_rnd_pipe(stage)(stage), stage, aggregate_size); + end if; + end if; + end if; + end process; + end generate; + + dout <= rot_data(num_rounds); + dout_vld <= dout_vld_pipe(num_rounds); + +end generate; + +-------------------------------------------------------------------------- +end behavior;