alu/sync: warum hat sich da keiner der beiden tools aufgeregt? wird das nicht sonst...
[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         );
18 end entity alu;
19
20 architecture beh of alu is
21         type ALU_STATE is (SIDLE, SADD, SSUB, SMUL, SDIV, SDIV_CALC, SDIV_DONE, SDONE);
22         signal state, state_next : ALU_STATE;
23         signal done_intern, div_calc_done, div_go_calc : std_logic;
24         signal op3_int, op3_next : csigned;
25         signal calc_done_int, calc_done_next : std_logic;
26         -- signale fuer division
27         signal dividend_msb, dividend_msb_next, laengediv, laengediv_next : natural;
28         signal quo, quo_next, aktdiv, aktdiv_next, op1_int, op1_next, op2_int, op2_next : csigned;
29         signal sign, sign_next : std_logic;
30 begin
31         op3 <= op3_int;
32         calc_done <= calc_done_int;
33
34         -- sync
35         process(sys_clk, sys_res_n)
36         begin
37                 if sys_res_n = '0' then
38                         state <= SIDLE;
39                         op3_int <= (others => '0');
40                         calc_done_int <= '0';
41                         --div
42                         dividend_msb <= 0;
43                         laengediv <= 0;
44                         quo <= (others => '0');
45                         aktdiv <= (others => '0');
46                         op1_int <= (others => '0');
47                         op2_int <= (others => '0');
48                         sign <= '0';
49                 elsif rising_edge(sys_clk) then
50                         state <= state_next;
51                         op3_int <= op3_next;
52                         calc_done_int <= calc_done_next;
53                         -- div
54                         dividend_msb <= dividend_msb_next;
55                         laengediv <= laengediv_next;
56                         quo <= quo_next;
57                         aktdiv <= aktdiv_next;
58                         op1_int <= op1_next;
59                         op2_int <= op2_next;
60                         sign <= sign_next;
61                 end if;
62         end process;
63
64         -- next state
65         process(state, opcode, done_intern, do_calc, div_calc_done, div_go_calc)
66         begin
67                 -- set a default value for next state
68                 state_next <= state;
69                 -- next state berechnen
70                 case state is
71                         when SIDLE =>
72                                 if do_calc = '1' then
73                                         case opcode is
74                                                 when ADD =>
75                                                         state_next <= SADD;
76                                                 when SUB =>
77                                                         state_next <= SSUB;
78                                                 when MUL =>
79                                                         state_next <= SMUL;
80                                                 when DIV =>
81                                                         state_next <= SDIV;
82                                                 when others =>
83                                                         state_next <= SIDLE;
84                                         end case;
85                                 end if;
86                         when SADD =>
87                                 if done_intern = '1' then
88                                         state_next <= SDONE;
89                                 end if;
90                         when SSUB =>
91                                 if done_intern = '1' then
92                                         state_next <= SDONE;
93                                 end if;
94                         when SMUL =>
95                                 if done_intern = '1' then
96                                         state_next <= SDONE;
97                                 end if;
98                         when SDIV =>
99                                 if div_go_calc = '1' then
100                                         state_next <= SDIV_CALC;
101                                 end if;
102                         when SDIV_CALC =>
103                                 if div_calc_done = '1' then
104                                         state_next <= SDIV_DONE;
105                                 end if;
106                         when SDIV_DONE =>
107                                 if done_intern = '1' then
108                                         state_next <= SDONE;
109                                 end if;
110                         when SDONE =>
111                                 if do_calc = '0' then
112                                         state_next <= SIDLE;
113                                 end if;
114                 end case;
115         end process;
116
117         -- output
118         process(state, op1, op2, dividend_msb, laengediv, quo, aktdiv, sign, op1_int, op2_int)
119                 variable tmperg : csigned;
120                 variable multmp : signed(((2*CBITS)-1) downto 0);
121                 -- vars fuer div
122                 variable laengediv_var, dividend_msb_var : natural;
123                 variable aktdiv_var, quo_var, op1_var, op2_var : csigned;
124         begin
125                 op3_next <= (others => '0');
126                 calc_done_next <= '0';
127                 div_calc_done <= '0';
128                 div_go_calc <= '0';
129                 done_intern <= '0';
130                 -- default fuer div
131                 dividend_msb_next <= 0;
132                 laengediv_next <= 0;
133                 quo_next <= (others => '0');
134                 aktdiv_next <= (others => '0');
135                 op1_next <= (others => '0');
136                 op2_next <= (others => '0');
137                 sign_next <= '0';
138
139                 case state is
140                         when SIDLE =>
141                                 tmperg := (others => '0');
142                         when SADD =>
143                                 tmperg := op1 + op2;
144                                 done_intern <= '1';
145                         when SSUB =>
146                                 tmperg := op1 - op2;
147                                 done_intern <= '1';
148                         when SMUL =>
149                                 multmp := op1 * op2;
150                                 tmperg(CBITS-1) := multmp((2*CBITS)-1);
151                                 tmperg((CBITS-2) downto 0) := multmp((CBITS-2) downto 0);
152                                 done_intern <= '1';
153                         when SDIV =>
154                                 -- division implementiert nach ~hwmod/doc/division.pdf
155                                 tmperg := (others => '0');
156                                 if op2 = to_signed(0,CBITS) then
157                                         -- TODO: err out signal
158                                         done_intern <= '1';
159                                 else
160                                         -- sign check
161                                         op1_var := op1;
162                                         op2_var := op2;
163                                         if op1(CBITS-1) = '1' then
164                                                 op1_var := not (op1_var + 1);
165                                         end if;
166                                         if op2(CBITS-1) = '1' then
167                                                 op2_var := not (op2_var + 1);
168                                         end if;
169
170                                         dividend_msb_var := find_msb(op1_var)-1;
171                                         laengediv_var := find_msb(op2_var)-1;
172
173                                         aktdiv_next <= op1_var srl (dividend_msb_var - laengediv_var + 1);
174
175                                         div_go_calc <= '1';
176                                         dividend_msb_next <= dividend_msb_var;
177                                         laengediv_next <= laengediv_var;
178                                         quo_next <= (others => '0');
179                                         op1_next <= op1_var;
180                                         op2_next <= op2_var;
181                                         sign_next <= op1(CBITS-1) xor op2(CBITS-1);
182                                 end if;
183                         when SDIV_CALC =>
184                                 tmperg := (others => '0');
185
186                                 if (dividend_msb - laengediv + 1) > 0 then
187                                         aktdiv_var := aktdiv sll 1;
188                                         aktdiv_var(0) := op1_int(dividend_msb - laengediv);
189
190                                         quo_var := quo sll 1;
191                                         if aktdiv_var >= op2_int then
192                                                 quo_var(0) := '1';
193                                                 aktdiv_var := aktdiv_var - op2_int;
194                                         end if;
195
196                                         quo_next <= quo_var;
197                                         aktdiv_next <= aktdiv_var;
198                                         dividend_msb_next <= dividend_msb;
199                                         laengediv_next <= laengediv + 1;
200                                         op1_next <= op1_int;
201                                         op2_next <= op2_int;
202                                         sign_next <= sign;
203                                 else
204                                         if sign = '1' then
205                                                 quo_next <= (not quo) + 1;
206                                         else
207                                                 quo_next <= quo;
208                                         end if;
209                                         div_calc_done <= '1';
210                                 end if;
211                         when SDIV_DONE =>
212                                 tmperg := quo;
213                                 done_intern <= '1';
214                         when SDONE =>
215                                 done_intern <= '1';
216                                 calc_done_next <= '1';
217                                 op3_next <= tmperg;
218                                 tmperg := (others => '0');
219                 end case;
220         end process;
221 end architecture beh;
222