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