2 use ieee.std_logic_1164.all;
3 use ieee.numeric_std.all;
8 sys_clk : in std_logic;
9 sys_res_n : in std_logic;
15 do_calc : in std_logic;
16 calc_done : out std_logic;
17 calc_error : out std_logic
21 architecture beh of alu is
22 type ALU_STATE is (SIDLE, SADD, SSUB, SMUL, SDIV, SDIV_SHIFT_TO_MSB,
23 SDIV_CALC, SDIV_DONE, 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 laengediv_int, laengediv_next : divinteger;
30 signal quo_int, quo_next, op1_int, op1_next, op2_int, op2_next : csigned;
31 signal sign_int, sign_next : std_logic;
35 calc_done <= calc_done_int;
36 calc_error <= calc_error_int;
39 process(sys_clk, sys_res_n)
41 if sys_res_n = '0' then
43 op3_int <= (others => '0');
44 opM_int <= (others => '0');
46 calc_error_int <= '0';
48 laengediv_int <= (others => '0');
49 quo_int <= (others => '0');
50 op1_int <= (others => '0');
51 op2_int <= (others => '0');
53 elsif rising_edge(sys_clk) then
54 state_int <= state_next;
57 calc_done_int <= calc_done_next;
58 calc_error_int <= calc_error_next;
60 laengediv_int <= laengediv_next;
64 sign_int <= sign_next;
69 process(opcode, do_calc, state_int, op1, op2, laengediv_int, quo_int,
70 sign_int, op1_int, op2_int, op3_int, opM_int)
71 variable multmp : signed(((2*CBITS)-1) downto 0);
72 variable mulsign : std_logic;
73 variable tmp : csigned;
75 variable laengediv_var, divtmp : divinteger;
76 variable aktdiv_int_var, op1_var, op2_var : csigned;
77 variable quobit : std_logic;
79 calc_done_next <= '0';
80 calc_error_next <= '0';
82 laengediv_next <= laengediv_int;
86 sign_next <= sign_int;
90 -- set a default value for next state
91 state_next <= state_int;
92 -- next state berechnen
96 op1_next <= (others => '0');
97 op2_next <= (others => '0');
98 opM_next <= (others => '0');
100 if do_calc = '1' then
102 when ALU_ADD => state_next <= SADD;
103 when ALU_SUB => state_next <= SSUB;
104 when ALU_MUL => state_next <= SMUL;
105 when ALU_DIV => state_next <= SDIV;
106 when others => state_next <= SIDLE;
114 -- over- bzw. underflow?
115 if (op1(CBITS-1) = op2(CBITS-1)) and (op1(CBITS-1) /= tmp(CBITS -1)) then
116 state_next <= SERROR;
123 -- over- bzw. underflow?
124 if (op1(CBITS-1) /= op2(CBITS-1)) and (op1(CBITS-1) /= tmp(CBITS -1)) then
125 state_next <= SERROR;
128 mulsign := op1(CBITS-1) xor op2(CBITS-1);
130 op3_next((CBITS-2) downto 0) <= multmp((CBITS-2) downto 0);
131 op3_next(CBITS-1) <= mulsign;
133 if mulsign = '1' then
134 multmp := (not multmp) + 1;
138 if(multmp((2*CBITS)-2 downto (CBITS-1)) > 0) then
139 state_next <= SERROR;
142 -- modifizierte binaere division nach ~hwmod/doc/division.pdf
144 -- division durch 0 checken
145 if op2 = to_signed(0, CBITS) then
146 state_next <= SERROR;
151 if op1(CBITS-1) = '1' then
152 op1_var := (not op1_var) + 1;
154 if op2(CBITS-1) = '1' then
155 op2_var := (not op2_var) + 1;
159 -- anmerkung: xst (xilinx) kann folgende zeile nicht uebersetzen
160 -- > if op1 = to_signed(-2147483648, CBITS) then
161 -- darum folgende schreibweise ->
162 if op1 = x"80000000" then
163 if op2 = to_signed(10,CBITS) then
164 -- so ziemlich das boeseste was passieren kann
165 -- deswegen, weil divisor und dividend in positive
166 -- zahlen umgewandelt werden.
167 -- daher: hardcodiertes ergebnis fuer division durch 10 (fuer parser)
168 op3_next <= to_signed(-214748364,CBITS);
169 opM_next <= to_signed(8,CBITS);
172 state_next <= SERROR;
174 elsif (op1_var < op2_var) then
175 -- => man braucht nix grossartiges rechnen
176 op3_next <= to_signed(0,CBITS);
179 -- spannend! signale initialisieren fuer den naechsten schritt
180 state_next <= SDIV_SHIFT_TO_MSB;
181 laengediv_next <= (others => '0');
182 quo_next <= (others => '0');
185 sign_next <= op1(CBITS-1) xor op2(CBITS-1);
188 when SDIV_SHIFT_TO_MSB =>
189 -- shifte divisor so lange nach links, bis MSB = '1' ist
190 if op2_int(CBITS-1) = '1' then
191 state_next <= SDIV_CALC;
193 -- und mitzaehlen wie oft geshiftet wurde
194 laengediv_next <= laengediv_int + 1;
195 op2_next <= op2_int sll 1;
198 multmp := (others => '0');
199 multmp(CBITS downto 0) := signed('0' & std_logic_vector(op1_int)) - signed('0' & std_logic_vector(op2_int));
201 -- beim sign bit sieht man ob sich op2_int in op1_int ausging oder nicht
202 -- es muss daher negiert werden
203 quobit := not multmp(CBITS);
205 -- ergebnis dieser runde uebernehmen
206 quo_next <= quo_int(CBITS-2 downto 0) & quobit;
208 -- wenn es sich ausging, soll neuer dividend uebernommen werden
210 op1_next <= multmp(CBITS-1 downto 0);
213 laengediv_next <= laengediv_int - 1;
214 -- divisor nach rechts shiften
215 op2_next <= op2_int srl 1;
217 -- wenn laengediv_int in *dieser* runde =0 ist dann ist man
218 -- fertig, weil man braucht (runden zum shiften + 1) runden zum
219 -- berechnen des eregbnisses
220 if laengediv_int = 0 then
221 state_next <= SDIV_DONE;
224 if sign_int = '1' then
225 op3_next <= (not quo_int) + 1;
229 -- wichtig: rest nur fuer postive paare gueltig!
230 -- (fuer unsere zwecke ausreichend)
233 when SDONE | SERROR =>
234 calc_done_next <= '1';
235 if state_int = SERROR then
236 calc_error_next <= '1';
238 if do_calc = '0' then
243 end architecture beh;