diff --git a/rotator.vhdl b/rotator.vhdl index fef9788..45913c9 100644 --- a/rotator.vhdl +++ b/rotator.vhdl @@ -7,17 +7,17 @@ use work.common.all; entity rotator is port (rs: in std_ulogic_vector(63 downto 0); - ra: in std_ulogic_vector(63 downto 0); - shift: in std_ulogic_vector(6 downto 0); - insn: in std_ulogic_vector(31 downto 0); - is_32bit: in std_ulogic; - right_shift: in std_ulogic; - arith: in std_ulogic; - clear_left: in std_ulogic; - clear_right: in std_ulogic; + ra: in std_ulogic_vector(63 downto 0); + shift: in std_ulogic_vector(6 downto 0); + insn: in std_ulogic_vector(31 downto 0); + is_32bit: in std_ulogic; + right_shift: in std_ulogic; + arith: in std_ulogic; + clear_left: in std_ulogic; + clear_right: in std_ulogic; sign_ext_rs: in std_ulogic; - result: out std_ulogic_vector(63 downto 0); - carry_out: out std_ulogic + result: out std_ulogic_vector(63 downto 0); + carry_out: out std_ulogic ); end entity rotator; @@ -31,159 +31,159 @@ architecture behaviour of rotator is -- note BE bit numbering function right_mask(mask_begin: std_ulogic_vector(6 downto 0)) return std_ulogic_vector is - variable ret: std_ulogic_vector(63 downto 0); + variable ret: std_ulogic_vector(63 downto 0); begin - ret := (others => '0'); - for i in 0 to 63 loop - if i >= to_integer(unsigned(mask_begin)) then - ret(63 - i) := '1'; - end if; - end loop; - return ret; + ret := (others => '0'); + for i in 0 to 63 loop + if i >= to_integer(unsigned(mask_begin)) then + ret(63 - i) := '1'; + end if; + end loop; + return ret; end; function left_mask(mask_end: std_ulogic_vector(6 downto 0)) return std_ulogic_vector is - variable ret: std_ulogic_vector(63 downto 0); + variable ret: std_ulogic_vector(63 downto 0); begin - ret := (others => '0'); - if mask_end(6) = '0' then - for i in 0 to 63 loop - if i <= to_integer(unsigned(mask_end)) then - ret(63 - i) := '1'; - end if; - end loop; - end if; - return ret; + ret := (others => '0'); + if mask_end(6) = '0' then + for i in 0 to 63 loop + if i <= to_integer(unsigned(mask_end)) then + ret(63 - i) := '1'; + end if; + end loop; + end if; + return ret; end; begin rotator_0: process(all) variable hi32: std_ulogic_vector(31 downto 0); begin - -- First replicate bottom 32 bits to both halves if 32-bit - if is_32bit = '1' then + -- First replicate bottom 32 bits to both halves if 32-bit + if is_32bit = '1' then hi32 := rs(31 downto 0); - elsif sign_ext_rs = '1' then + elsif sign_ext_rs = '1' then -- sign extend bottom 32 bits hi32 := (others => rs(31)); else - hi32 := rs(63 downto 32); - end if; + hi32 := rs(63 downto 32); + end if; repl32 <= hi32 & rs(31 downto 0); - -- Negate shift count for right shifts - if right_shift = '1' then - rot_count <= std_ulogic_vector(- signed(shift(5 downto 0))); - else - rot_count <= shift(5 downto 0); - end if; + -- Negate shift count for right shifts + if right_shift = '1' then + rot_count <= std_ulogic_vector(- signed(shift(5 downto 0))); + else + rot_count <= shift(5 downto 0); + end if; - -- Rotator works in 3 stages using 2 bits of the rotate count each - -- time. This gives 4:1 multiplexors which is ideal for the 6-input - -- LUTs in the Xilinx Artix 7. - -- We look at the low bits of the rotate count first because they will - -- have less delay through the negation above. - -- First rotate by 0, 1, 2, or 3 - case rot_count(1 downto 0) is - when "00" => - rot1 <= repl32; - when "01" => - rot1 <= repl32(62 downto 0) & repl32(63); - when "10" => - rot1 <= repl32(61 downto 0) & repl32(63 downto 62); - when others => - rot1 <= repl32(60 downto 0) & repl32(63 downto 61); - end case; - -- Next rotate by 0, 4, 8 or 12 - case rot_count(3 downto 2) is - when "00" => - rot2 <= rot1; - when "01" => - rot2 <= rot1(59 downto 0) & rot1(63 downto 60); - when "10" => - rot2 <= rot1(55 downto 0) & rot1(63 downto 56); - when others => - rot2 <= rot1(51 downto 0) & rot1(63 downto 52); - end case; - -- Lastly rotate by 0, 16, 32 or 48 - case rot_count(5 downto 4) is - when "00" => - rot <= rot2; - when "01" => - rot <= rot2(47 downto 0) & rot2(63 downto 48); - when "10" => - rot <= rot2(31 downto 0) & rot2(63 downto 32); - when others => - rot <= rot2(15 downto 0) & rot2(63 downto 16); - end case; + -- Rotator works in 3 stages using 2 bits of the rotate count each + -- time. This gives 4:1 multiplexors which is ideal for the 6-input + -- LUTs in the Xilinx Artix 7. + -- We look at the low bits of the rotate count first because they will + -- have less delay through the negation above. + -- First rotate by 0, 1, 2, or 3 + case rot_count(1 downto 0) is + when "00" => + rot1 <= repl32; + when "01" => + rot1 <= repl32(62 downto 0) & repl32(63); + when "10" => + rot1 <= repl32(61 downto 0) & repl32(63 downto 62); + when others => + rot1 <= repl32(60 downto 0) & repl32(63 downto 61); + end case; + -- Next rotate by 0, 4, 8 or 12 + case rot_count(3 downto 2) is + when "00" => + rot2 <= rot1; + when "01" => + rot2 <= rot1(59 downto 0) & rot1(63 downto 60); + when "10" => + rot2 <= rot1(55 downto 0) & rot1(63 downto 56); + when others => + rot2 <= rot1(51 downto 0) & rot1(63 downto 52); + end case; + -- Lastly rotate by 0, 16, 32 or 48 + case rot_count(5 downto 4) is + when "00" => + rot <= rot2; + when "01" => + rot <= rot2(47 downto 0) & rot2(63 downto 48); + when "10" => + rot <= rot2(31 downto 0) & rot2(63 downto 32); + when others => + rot <= rot2(15 downto 0) & rot2(63 downto 16); + end case; - -- Trim shift count to 6 bits for 32-bit shifts - sh <= (shift(6) and not is_32bit) & shift(5 downto 0); + -- Trim shift count to 6 bits for 32-bit shifts + sh <= (shift(6) and not is_32bit) & shift(5 downto 0); - -- Work out mask begin/end indexes (caution, big-endian bit numbering) - if clear_left = '1' then - if is_32bit = '1' then - mb <= "01" & insn(10 downto 6); - else - mb <= "0" & insn(5) & insn(10 downto 6); - end if; - elsif right_shift = '1' then - -- this is basically mb <= sh + (is_32bit? 32: 0); - if is_32bit = '1' then - mb <= sh(5) & not sh(5) & sh(4 downto 0); - else - mb <= sh; - end if; - else - mb <= ('0' & is_32bit & "00000"); - end if; - if clear_right = '1' and is_32bit = '1' then - me <= "01" & insn(5 downto 1); - elsif clear_right = '1' and clear_left = '0' then - me <= "0" & insn(5) & insn(10 downto 6); - else - -- effectively, 63 - sh - me <= sh(6) & not sh(5 downto 0); - end if; + -- Work out mask begin/end indexes (caution, big-endian bit numbering) + if clear_left = '1' then + if is_32bit = '1' then + mb <= "01" & insn(10 downto 6); + else + mb <= "0" & insn(5) & insn(10 downto 6); + end if; + elsif right_shift = '1' then + -- this is basically mb <= sh + (is_32bit? 32: 0); + if is_32bit = '1' then + mb <= sh(5) & not sh(5) & sh(4 downto 0); + else + mb <= sh; + end if; + else + mb <= ('0' & is_32bit & "00000"); + end if; + if clear_right = '1' and is_32bit = '1' then + me <= "01" & insn(5 downto 1); + elsif clear_right = '1' and clear_left = '0' then + me <= "0" & insn(5) & insn(10 downto 6); + else + -- effectively, 63 - sh + me <= sh(6) & not sh(5 downto 0); + end if; - -- Calculate left and right masks - mr <= right_mask(mb); - ml <= left_mask(me); + -- Calculate left and right masks + mr <= right_mask(mb); + ml <= left_mask(me); - -- Work out output mode - -- 00 for sl[wd] - -- 0w for rlw*, rldic, rldicr, rldimi, where w = 1 iff mb > me - -- 10 for rldicl, sr[wd] - -- 1z for sra[wd][i], z = 1 if rs is negative - if (clear_left = '1' and clear_right = '0') or right_shift = '1' then - output_mode(1) <= '1'; - output_mode(0) <= arith and repl32(63); - else - output_mode(1) <= '0'; - if clear_right = '1' and unsigned(mb(5 downto 0)) > unsigned(me(5 downto 0)) then - output_mode(0) <= '1'; - else - output_mode(0) <= '0'; - end if; - end if; + -- Work out output mode + -- 00 for sl[wd] + -- 0w for rlw*, rldic, rldicr, rldimi, where w = 1 iff mb > me + -- 10 for rldicl, sr[wd] + -- 1z for sra[wd][i], z = 1 if rs is negative + if (clear_left = '1' and clear_right = '0') or right_shift = '1' then + output_mode(1) <= '1'; + output_mode(0) <= arith and repl32(63); + else + output_mode(1) <= '0'; + if clear_right = '1' and unsigned(mb(5 downto 0)) > unsigned(me(5 downto 0)) then + output_mode(0) <= '1'; + else + output_mode(0) <= '0'; + end if; + end if; - -- Generate output from rotated input and masks - case output_mode is - when "00" => - result <= (rot and (mr and ml)) or (ra and not (mr and ml)); - when "01" => - result <= (rot and (mr or ml)) or (ra and not (mr or ml)); - when "10" => - result <= rot and mr; - when others => - result <= rot or not mr; - end case; + -- Generate output from rotated input and masks + case output_mode is + when "00" => + result <= (rot and (mr and ml)) or (ra and not (mr and ml)); + when "01" => + result <= (rot and (mr or ml)) or (ra and not (mr or ml)); + when "10" => + result <= rot and mr; + when others => + result <= rot or not mr; + end case; - -- Generate carry output for arithmetic shift right of negative value - if output_mode = "11" then - carry_out <= or (rs and not ml); - else - carry_out <= '0'; - end if; + -- Generate carry output for arithmetic shift right of negative value + if output_mode = "11" then + carry_out <= or (rs and not ml); + else + carry_out <= '0'; + end if; end process; end behaviour;