Add Tercel PHY reset synchronization
[microwatt.git] / rotator.vhdl
1 library ieee;
2 use ieee.std_logic_1164.all;
3 use ieee.numeric_std.all;
4
5 library work;
6 use work.common.all;
7
8 entity rotator is
9 port (rs: in std_ulogic_vector(63 downto 0);
10 ra: in std_ulogic_vector(63 downto 0);
11 shift: in std_ulogic_vector(6 downto 0);
12 insn: in std_ulogic_vector(31 downto 0);
13 is_32bit: in std_ulogic;
14 right_shift: in std_ulogic;
15 arith: in std_ulogic;
16 clear_left: in std_ulogic;
17 clear_right: in std_ulogic;
18 sign_ext_rs: in std_ulogic;
19 result: out std_ulogic_vector(63 downto 0);
20 carry_out: out std_ulogic
21 );
22 end entity rotator;
23
24 architecture behaviour of rotator is
25 signal repl32: std_ulogic_vector(63 downto 0);
26 signal rot_count: std_ulogic_vector(5 downto 0);
27 signal rot1, rot2, rot: std_ulogic_vector(63 downto 0);
28 signal sh, mb, me: std_ulogic_vector(6 downto 0);
29 signal mr, ml: std_ulogic_vector(63 downto 0);
30 signal output_mode: std_ulogic_vector(1 downto 0);
31
32 -- note BE bit numbering
33 function right_mask(mask_begin: std_ulogic_vector(6 downto 0)) return std_ulogic_vector is
34 variable ret: std_ulogic_vector(63 downto 0);
35 begin
36 ret := (others => '0');
37 for i in 0 to 63 loop
38 if i >= to_integer(unsigned(mask_begin)) then
39 ret(63 - i) := '1';
40 end if;
41 end loop;
42 return ret;
43 end;
44
45 function left_mask(mask_end: std_ulogic_vector(6 downto 0)) return std_ulogic_vector is
46 variable ret: std_ulogic_vector(63 downto 0);
47 begin
48 ret := (others => '0');
49 if mask_end(6) = '0' then
50 for i in 0 to 63 loop
51 if i <= to_integer(unsigned(mask_end)) then
52 ret(63 - i) := '1';
53 end if;
54 end loop;
55 end if;
56 return ret;
57 end;
58
59 begin
60 rotator_0: process(all)
61 variable hi32: std_ulogic_vector(31 downto 0);
62 begin
63 -- First replicate bottom 32 bits to both halves if 32-bit
64 if is_32bit = '1' then
65 hi32 := rs(31 downto 0);
66 elsif sign_ext_rs = '1' then
67 -- sign extend bottom 32 bits
68 hi32 := (others => rs(31));
69 else
70 hi32 := rs(63 downto 32);
71 end if;
72 repl32 <= hi32 & rs(31 downto 0);
73
74 -- Negate shift count for right shifts
75 if right_shift = '1' then
76 rot_count <= std_ulogic_vector(- signed(shift(5 downto 0)));
77 else
78 rot_count <= shift(5 downto 0);
79 end if;
80
81 -- Rotator works in 3 stages using 2 bits of the rotate count each
82 -- time. This gives 4:1 multiplexors which is ideal for the 6-input
83 -- LUTs in the Xilinx Artix 7.
84 -- We look at the low bits of the rotate count first because they will
85 -- have less delay through the negation above.
86 -- First rotate by 0, 1, 2, or 3
87 case rot_count(1 downto 0) is
88 when "00" =>
89 rot1 <= repl32;
90 when "01" =>
91 rot1 <= repl32(62 downto 0) & repl32(63);
92 when "10" =>
93 rot1 <= repl32(61 downto 0) & repl32(63 downto 62);
94 when others =>
95 rot1 <= repl32(60 downto 0) & repl32(63 downto 61);
96 end case;
97 -- Next rotate by 0, 4, 8 or 12
98 case rot_count(3 downto 2) is
99 when "00" =>
100 rot2 <= rot1;
101 when "01" =>
102 rot2 <= rot1(59 downto 0) & rot1(63 downto 60);
103 when "10" =>
104 rot2 <= rot1(55 downto 0) & rot1(63 downto 56);
105 when others =>
106 rot2 <= rot1(51 downto 0) & rot1(63 downto 52);
107 end case;
108 -- Lastly rotate by 0, 16, 32 or 48
109 case rot_count(5 downto 4) is
110 when "00" =>
111 rot <= rot2;
112 when "01" =>
113 rot <= rot2(47 downto 0) & rot2(63 downto 48);
114 when "10" =>
115 rot <= rot2(31 downto 0) & rot2(63 downto 32);
116 when others =>
117 rot <= rot2(15 downto 0) & rot2(63 downto 16);
118 end case;
119
120 -- Trim shift count to 6 bits for 32-bit shifts
121 sh <= (shift(6) and not is_32bit) & shift(5 downto 0);
122
123 -- Work out mask begin/end indexes (caution, big-endian bit numbering)
124 if clear_left = '1' then
125 if is_32bit = '1' then
126 mb <= "01" & insn(10 downto 6);
127 else
128 mb <= "0" & insn(5) & insn(10 downto 6);
129 end if;
130 elsif right_shift = '1' then
131 -- this is basically mb <= sh + (is_32bit? 32: 0);
132 if is_32bit = '1' then
133 mb <= sh(5) & not sh(5) & sh(4 downto 0);
134 else
135 mb <= sh;
136 end if;
137 else
138 mb <= ('0' & is_32bit & "00000");
139 end if;
140 if clear_right = '1' and is_32bit = '1' then
141 me <= "01" & insn(5 downto 1);
142 elsif clear_right = '1' and clear_left = '0' then
143 me <= "0" & insn(5) & insn(10 downto 6);
144 else
145 -- effectively, 63 - sh
146 me <= sh(6) & not sh(5 downto 0);
147 end if;
148
149 -- Calculate left and right masks
150 mr <= right_mask(mb);
151 ml <= left_mask(me);
152
153 -- Work out output mode
154 -- 00 for sl[wd]
155 -- 0w for rlw*, rldic, rldicr, rldimi, where w = 1 iff mb > me
156 -- 10 for rldicl, sr[wd]
157 -- 1z for sra[wd][i], z = 1 if rs is negative
158 if (clear_left = '1' and clear_right = '0') or right_shift = '1' then
159 output_mode(1) <= '1';
160 output_mode(0) <= arith and repl32(63);
161 else
162 output_mode(1) <= '0';
163 if clear_right = '1' and unsigned(mb(5 downto 0)) > unsigned(me(5 downto 0)) then
164 output_mode(0) <= '1';
165 else
166 output_mode(0) <= '0';
167 end if;
168 end if;
169
170 -- Generate output from rotated input and masks
171 case output_mode is
172 when "00" =>
173 result <= (rot and (mr and ml)) or (ra and not (mr and ml));
174 when "01" =>
175 result <= (rot and (mr or ml)) or (ra and not (mr or ml));
176 when "10" =>
177 result <= rot and mr;
178 when others =>
179 result <= rot or not mr;
180 end case;
181
182 -- Generate carry output for arithmetic shift right of negative value
183 if output_mode = "11" then
184 carry_out <= or (rs and not ml);
185 else
186 carry_out <= '0';
187 end if;
188 end process;
189 end behaviour;