alu: refactor von drei prozessmodell auf zwei prozessmodell
[hwmod.git] / src / alu.vhd
1 library ieee;
2 use ieee.std_logic_1164.all;
3 use ieee.numeric_std.all;
4 use work.gen_pkg.all;
5
6 entity alu is
7         port
8         (
9                 sys_clk : in std_logic;
10                 sys_res_n : in std_logic;
11                 opcode : in alu_ops;
12                 op1 : in csigned;
13                 op2 : in csigned;
14                 op3 : out csigned;
15                 opM : out csigned;
16                 do_calc : in std_logic;
17                 calc_done : out std_logic;
18                 calc_error : out std_logic
19         );
20 end entity alu;
21
22 architecture beh of alu is
23         type ALU_STATE is (SIDLE, SADD, SSUB, SMUL, SDIV, SDIV_CALC, SDONE, SERROR);
24         signal state_int, state_next : ALU_STATE;
25         signal op3_int, op3_next, opM_int, opM_next : csigned;
26         signal calc_done_int, calc_done_next : std_logic;
27         signal calc_error_int, calc_error_next : std_logic;
28         -- signale fuer division
29         signal dividend_msb_int, dividend_msb_next, laengediv_int, laengediv_next : divinteger;
30         signal quo_int, quo_next, aktdiv_int, aktdiv_int_next, op1_int, op1_next, op2_int, op2_next : csigned;
31         signal sign_int, sign_next : std_logic;
32 begin
33         op3 <= op3_int;
34         opM <= opM_int;
35         calc_done <= calc_done_int;
36         calc_error <= calc_error_int;
37
38         -- sync
39         process(sys_clk, sys_res_n)
40         begin
41                 if sys_res_n = '0' then
42                         state_int <= SIDLE;
43                         op3_int <= (others => '0');
44                         opM_int <= (others => '0');
45                         calc_done_int <= '0';
46                         calc_error_int <= '0';
47                         --div
48                         dividend_msb_int <= (others => '0');
49                         laengediv_int <= (others => '0');
50                         quo_int <= (others => '0');
51                         aktdiv_int <= (others => '0');
52                         op1_int <= (others => '0');
53                         op2_int <= (others => '0');
54                         sign_int <= '0';
55                 elsif rising_edge(sys_clk) then
56                         state_int <= state_next;
57                         op3_int <= op3_next;
58                         opM_int <= opM_next;
59                         calc_done_int <= calc_done_next;
60                         calc_error_int <= calc_error_next;
61                         -- div
62                         dividend_msb_int <= dividend_msb_next;
63                         laengediv_int <= laengediv_next;
64                         quo_int <= quo_next;
65                         aktdiv_int <= aktdiv_int_next;
66                         op1_int <= op1_next;
67                         op2_int <= op2_next;
68                         sign_int <= sign_next;
69                 end if;
70         end process;
71
72         -- next state & out
73         process(opcode, do_calc, state_int, op1, op2, dividend_msb_int,
74                         laengediv_int, quo_int, aktdiv_int, sign_int, op1_int, op2_int,
75                         op3_int, opM_int)
76                 -- http://www.velocityreviews.com/forums/showpost.php?p=137148&postcount=5
77                 function find_msb(a : std_logic_vector) return std_logic_vector is
78                         function bits_to_fit(n : positive) return natural is
79                                 variable nn, bits : natural := 0;
80                         begin
81                                 nn := n;
82                                 while nn > 0 loop
83                                         bits := bits + 1;
84                                         nn := nn/2;
85                                 end loop;
86                                 return bits;
87                         end;
88
89                         function or_all(p : std_logic_vector) return std_logic is
90                                 variable r : std_logic;
91                         begin
92                                 r := '0';
93                                 for i in p'range loop
94                                         r := r or p(i);
95                                 end loop;
96                                 return r;
97                         end;
98
99                         constant wN : positive := bits_to_fit(a'length - 1);
100                         constant wP : positive := 2 ** wN;
101                         variable pv : std_logic_vector(wP-1 downto 0);
102                         variable n : std_logic_vector(wN downto 1);
103                 begin
104                         if a'length <= 2 then
105                                 n(n'right) := a(a'left);
106                         else
107                                 pv(a'length-1 downto 0) := a;
108                                 if or_all(pv(wP-1 downto wP/2)) = '1' then
109                                         n := '1' & find_msb((pv(wP-1 downto wP/2)));
110                                 else
111                                         n := '0' & find_msb((pv(wP/2-1 downto 0)));
112                                 end if;
113                         end if;
114                         return n;
115                 end function find_msb;
116                 -- -- alternativ: eleganter, braucht aber mehr logic cells
117                 -- for i in (CBITS-1) downto 0 loop
118                 --       exit when a(i) = '1';
119                 --       r := r+1;
120                 -- end loop;
121                 -- return (CBITS - r);
122
123                 variable multmp : signed(((2*CBITS)-1) downto 0);
124                 variable mulsign : std_logic;
125                 variable tmp : csigned;
126                 -- vars fuer div
127                 variable laengediv_var, dividend_msb_var, divtmp : divinteger;
128                 variable aktdiv_int_var, quo_var, op1_var, op2_var : csigned;
129         begin
130                 calc_done_next <= '0';
131                 calc_error_next <= '0';
132                 -- default fuer div
133                 dividend_msb_next <= (others => '0');
134                 laengediv_next <= (others => '0');
135                 quo_next <= (others => '0');
136                 aktdiv_int_next <= aktdiv_int;
137                 op1_next <= (others => '0');
138                 op2_next <= (others => '0');
139                 sign_next <= '0';
140                 op3_next <= op3_int;
141                 opM_next <= opM_int;
142                 -- set a default value for next state
143                 state_next <= state_int;
144                 -- next state berechnen
145                 case state_int is
146                         when SIDLE =>
147                                 aktdiv_int_next <= (others => '0');
148                                 -- opM_next <= (others => '0');
149
150                                 if do_calc = '1' then
151                                         case opcode is
152                                                 when ALU_ADD => state_next <= SADD;
153                                                 when ALU_SUB => state_next <= SSUB;
154                                                 when ALU_MUL => state_next <= SMUL;
155                                                 when ALU_DIV => state_next <= SDIV;
156                                                 when others => state_next <= SIDLE;
157                                         end case;
158                                 end if;
159                         when SADD =>
160                                 tmp := op1 + op2;
161                                 op3_next <= tmp;
162
163                                 state_next <= SDONE;
164                                 -- over- bzw. underflow?
165                                 if (op1(CBITS-1) = op2(CBITS-1)) and (op1(CBITS-1) /= tmp(CBITS -1)) then
166                                         state_next <= SERROR;
167                                 end if;
168                         when SSUB =>
169                                 tmp := op1 - op2;
170                                 op3_next <= tmp;
171
172                                 state_next <= SDONE;
173                                 -- over- bzw. underflow?
174                                 if (op1(CBITS-1) /= op2(CBITS-1)) and (op1(CBITS-1) /= tmp(CBITS -1)) then
175                                         state_next <= SERROR;
176                                 end if;
177                         when SMUL =>
178                                 mulsign := op1(CBITS-1) xor op2(CBITS-1);
179                                 multmp := op1 * op2;
180                                 op3_next((CBITS-2) downto 0) <= multmp((CBITS-2) downto 0);
181                                 op3_next(CBITS-1) <= mulsign;
182
183                                 if mulsign = '1' then
184                                         multmp := (not multmp) + 1;
185                                 end if;
186                                 state_next <= SDONE;
187                                 -- overflow?
188                                 if(multmp((2*CBITS)-2 downto (CBITS-1)) > 0) then
189                                         state_next <= SERROR;
190                                 end if;
191                         when SDIV =>
192                                 -- division implementiert nach ~hwmod/doc/division.pdf
193                                 if ((op1 = x"80000000" and op2 = to_signed(-1, CBITS)) or op2 = to_signed(0, CBITS)) then
194                                         state_next <= SERROR;
195                                 else
196                                         -- sign check
197                                         op1_var := op1;
198                                         op2_var := op2;
199                                         if op1(CBITS-1) = '1' then
200                                                 op1_var := (not op1_var) + 1;
201                                         end if;
202                                         if op2(CBITS-1) = '1' then
203                                                 op2_var := (not op2_var) + 1;
204                                         end if;
205
206                                         dividend_msb_var := divinteger(find_msb(std_logic_vector(op1_var)))-1;
207                                         laengediv_var := divinteger(find_msb(std_logic_vector(op2_var)))-1;
208
209                                         aktdiv_int_next <= op1_var srl to_integer(dividend_msb_var - laengediv_var + 1);
210
211                                         -- anmerkung: xst (xilinx) kann folgende zeile nicht uebersetzen
212                                         -- > if op1 = to_signed(-2147483648, CBITS) then
213                                         -- darum folgende schreibweise ->
214                                         state_next <= SDONE;
215                                         if op1 = x"80000000" then
216                                                 -- so ziemlich das boeseste was passieren kann
217                                                 op3_next <= to_signed(-214748364,CBITS);
218                                                 opM_next <= to_signed(8,CBITS);
219                                         elsif (op1_var < op2_var) then
220                                                 op3_next <= to_signed(0,CBITS);
221                                                 opM_next <= op1_var;
222                                         else
223                                                 state_next <= SDIV_CALC;
224                                                 dividend_msb_next <= dividend_msb_var;
225                                                 laengediv_next <= laengediv_var;
226                                                 quo_next <= (others => '0');
227                                                 op1_next <= op1_var;
228                                                 op2_next <= op2_var;
229                                                 sign_next <= op1(CBITS-1) xor op2(CBITS-1);
230                                         end if;
231                                 end if;
232                         when SDIV_CALC =>
233                                 divtmp := dividend_msb_int - laengediv_int + 1;
234
235                                 if divtmp > 0 then
236                                         aktdiv_int_var := aktdiv_int sll 1;
237                                         aktdiv_int_var(0) := op1_int(to_integer(divtmp) - 1);
238
239                                         quo_var := quo_int sll 1;
240                                         if aktdiv_int_var >= op2_int then
241                                                 quo_var(0) := '1';
242                                                 aktdiv_int_var := aktdiv_int_var - op2_int;
243                                         end if;
244
245                                         quo_next <= quo_var;
246                                         aktdiv_int_next <= aktdiv_int_var;
247                                         dividend_msb_next <= dividend_msb_int;
248                                         laengediv_next <= laengediv_int + 1;
249                                         op1_next <= op1_int;
250                                         op2_next <= op2_int;
251                                         sign_next <= sign_int;
252                                 else
253                                         if sign_int = '1' then
254                                                 op3_next <= (not quo_int) + 1;
255                                         else
256                                                 op3_next <= quo_int;
257                                         end if;
258                                         opM_next <= aktdiv_int;
259                                         state_next <= SDONE;
260                                 end if;
261                         when SDONE | SERROR =>
262                                 calc_done_next <= '1';
263                                 if state_int = SERROR then
264                                         calc_error_next <= '1';
265                                 end if;
266                                 if do_calc = '0' then
267                                         state_next <= SIDLE;
268                                 end if;
269                 end case;
270         end process;
271 end architecture beh;