parser: ausdruecke werden erfolgreich geparst, einschraenkungen:
[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                 do_calc : in std_logic;
16                 calc_done : out std_logic;
17                 calc_error : out std_logic
18         );
19 end entity alu;
20
21 architecture beh of alu is
22         type ALU_STATE is (SIDLE, SADD, SSUB, SMUL, SDIV, SDIV_CALC, SDIV_DONE,
23         SDONE, SERROR);
24         signal state_int, state_next : ALU_STATE;
25         signal done_intern, error_intern, div_calc_done, div_go_calc : std_logic;
26         signal op3_int, op3_next : csigned;
27         signal calc_done_int, calc_done_next : std_logic;
28         signal calc_error_int, calc_error_next : std_logic;
29         -- signale fuer division
30         signal dividend_msb_int, dividend_msb_next, laengediv_int, laengediv_next : natural;
31         signal quo_int, quo_next, aktdiv_int, aktdiv_int_next, op1_int, op1_next, op2_int, op2_next : csigned;
32         signal sign_int, sign_next : std_logic;
33 begin
34         op3 <= op3_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                         calc_done_int <= '0';
45                         calc_error_int <= '0';
46                         --div
47                         dividend_msb_int <= 0;
48                         laengediv_int <= 0;
49                         quo_int <= (others => '0');
50                         aktdiv_int <= (others => '0');
51                         op1_int <= (others => '0');
52                         op2_int <= (others => '0');
53                         sign_int <= '0';
54                 elsif rising_edge(sys_clk) then
55                         state_int <= state_next;
56                         op3_int <= op3_next;
57                         calc_done_int <= calc_done_next;
58                         calc_error_int <= calc_error_next;
59                         -- div
60                         dividend_msb_int <= dividend_msb_next;
61                         laengediv_int <= laengediv_next;
62                         quo_int <= quo_next;
63                         aktdiv_int <= aktdiv_int_next;
64                         op1_int <= op1_next;
65                         op2_int <= op2_next;
66                         sign_int <= sign_next;
67                 end if;
68         end process;
69
70         -- next state
71         process(state_int, opcode, done_intern, error_intern, do_calc,
72                 div_calc_done, div_go_calc)
73         begin
74                 -- set a default value for next state
75                 state_next <= state_int;
76                 -- next state berechnen
77                 case state_int is
78                         when SIDLE =>
79                                 if do_calc = '1' then
80                                         case opcode is
81                                                 when ALU_ADD =>
82                                                         state_next <= SADD;
83                                                 when ALU_SUB =>
84                                                         state_next <= SSUB;
85                                                 when ALU_MUL =>
86                                                         state_next <= SMUL;
87                                                 when ALU_DIV =>
88                                                         state_next <= SDIV;
89                                                 when others =>
90                                                         state_next <= SIDLE;
91                                         end case;
92                                 end if;
93                         when SADD | SSUB | SMUL | SDIV_DONE =>
94                                 if done_intern = '1' then
95                                         state_next <= SDONE;
96                                 end if;
97                                 if error_intern = '1' then
98                                         state_next <= SERROR;
99                                 end if;
100                         when SDIV =>
101                                 if div_go_calc = '1' then
102                                         state_next <= SDIV_CALC;
103                                 end if;
104                                 if error_intern = '1' then
105                                         state_next <= SERROR;
106                                 end if;
107                         when SDIV_CALC =>
108                                 if div_calc_done = '1' then
109                                         state_next <= SDIV_DONE;
110                                 end if;
111                         when SDONE | SERROR =>
112                                 if do_calc = '0' then
113                                         state_next <= SIDLE;
114                                 end if;
115                 end case;
116         end process;
117
118         -- output
119         process(state_int, op1, op2, dividend_msb_int, laengediv_int, quo_int, aktdiv_int, sign_int, op1_int, op2_int, op3_int)
120                 variable multmp, multmp2 : signed(((2*CBITS)-1) downto 0);
121                 variable mulsign : std_logic;
122                 variable tmp : csigned;
123                 -- vars fuer div
124                 variable laengediv_var, dividend_msb_var : natural;
125                 variable aktdiv_int_var, quo_var, op1_var, op2_var : csigned;
126         begin
127                 calc_done_next <= '0';
128                 calc_error_next <= '0';
129                 div_calc_done <= '0';
130                 div_go_calc <= '0';
131                 done_intern <= '0';
132                 error_intern <= '0';
133                 -- default fuer div
134                 dividend_msb_next <= 0;
135                 laengediv_next <= 0;
136                 quo_next <= (others => '0');
137                 aktdiv_int_next <= (others => '0');
138                 op1_next <= (others => '0');
139                 op2_next <= (others => '0');
140                 sign_next <= '0';
141                 op3_next <= op3_int;
142
143                 case state_int is
144                         when SIDLE =>
145                                 null;
146                         when SADD =>
147                                 tmp := op1 + op2;
148                                 op3_next <= tmp;
149
150                                 -- over- bzw. underflow?
151                                 if (op1(CBITS-1) = op2(CBITS-1)) and (op1(CBITS-1) /= tmp(CBITS -1)) then
152                                         error_intern <= '1';
153                                 else
154                                         done_intern <= '1';
155                                 end if;
156                         when SSUB =>
157                                 tmp := op1 - op2;
158                                 op3_next <= tmp;
159
160                                 -- over- bzw. underflow?
161                                 if (op1(CBITS-1) /= op2(CBITS-1)) and (op1(CBITS-1) /= tmp(CBITS -1)) then
162                                         error_intern <= '1';
163                                 else
164                                         done_intern <= '1';
165                                 end if;
166                         when SMUL =>
167                                 mulsign := op1(CBITS-1) xor op2(CBITS-1);
168                                 multmp := op1 * op2;
169                                 op3_next((CBITS-2) downto 0) <= multmp((CBITS-2) downto 0);
170                                 op3_next(CBITS-1) <= mulsign;
171
172                                 if mulsign = '1' then
173                                         multmp2 := (not multmp) + 1;
174                                 else
175                                         multmp2 := multmp;
176                                 end if;
177                                 -- overflow?
178                                 if(multmp2((2*CBITS)-2 downto (CBITS-1)) > 0) then
179                                         error_intern <= '1';
180                                 else
181                                         done_intern <= '1';
182                                 end if;
183
184                         when SDIV =>
185                                 -- division implementiert nach ~hwmod/doc/division.pdf
186                                 if ((op1 = x"80000000" and op2 = to_signed(-1, CBITS)) or op2 = to_signed(0, CBITS)) then
187                                         error_intern <= '1';
188                                 else
189                                         -- sign check
190                                         op1_var := op1;
191                                         op2_var := op2;
192                                         if op1(CBITS-1) = '1' then
193                                                 op1_var := (not op1_var) + 1;
194                                         end if;
195                                         if op2(CBITS-1) = '1' then
196                                                 op2_var := (not op2_var) + 1;
197                                         end if;
198
199                                         dividend_msb_var := find_msb(op1_var)-1;
200                                         laengediv_var := find_msb(op2_var)-1;
201
202                                         aktdiv_int_next <= op1_var srl (dividend_msb_var - laengediv_var + 1);
203
204                                         div_go_calc <= '1';
205                                         dividend_msb_next <= dividend_msb_var;
206                                         laengediv_next <= laengediv_var;
207                                         quo_next <= (others => '0');
208                                         op1_next <= op1_var;
209                                         op2_next <= op2_var;
210                                         sign_next <= op1(CBITS-1) xor op2(CBITS-1);
211                                 end if;
212                         when SDIV_CALC =>
213                                 if (dividend_msb_int - laengediv_int + 1) > 0 then
214                                         aktdiv_int_var := aktdiv_int sll 1;
215                                         aktdiv_int_var(0) := op1_int(dividend_msb_int - laengediv_int);
216
217                                         quo_var := quo_int sll 1;
218                                         if aktdiv_int_var >= op2_int then
219                                                 quo_var(0) := '1';
220                                                 aktdiv_int_var := aktdiv_int_var - op2_int;
221                                         end if;
222
223                                         quo_next <= quo_var;
224                                         aktdiv_int_next <= aktdiv_int_var;
225                                         dividend_msb_next <= dividend_msb_int;
226                                         laengediv_next <= laengediv_int + 1;
227                                         op1_next <= op1_int;
228                                         op2_next <= op2_int;
229                                         sign_next <= sign_int;
230                                 else
231                                         if sign_int = '1' then
232                                                 quo_next <= (not quo_int) + 1;
233                                         else
234                                                 quo_next <= quo_int;
235                                         end if;
236                                         div_calc_done <= '1';
237                                 end if;
238                         when SDIV_DONE =>
239                                 op3_next <= quo_int;
240                                 done_intern <= '1';
241                         when SDONE | SERROR =>
242                                 calc_done_next <= '1';
243                                 if (state_int = SERROR) then
244                                         calc_error_next <= '1';
245                                 end if;
246                 end case;
247         end process;
248 end architecture beh;
249