-
Notifications
You must be signed in to change notification settings - Fork 1
/
alu.vhd.bak
221 lines (216 loc) · 12 KB
/
alu.vhd.bak
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
LIBRARY work;
USE work.bv_arithmetic.ALL;
USE work.dlx_types.ALL;
--------------------------- Arithmetic-Logic Unit -------------------------------------------
-- This unit takes in two 32-bit values, and a 4-bit operation code
-- that specifies which ALU operation (eg. add, subtract, multiply, etc) is to be performed
-- on the two operands. For non commutative operations like subtract or divide, operand1
-- always goes on the left of the operator and operand2 on the right.
---------------------------------------------------------------------------------------------
-- The operation codes are
-- 0000 = unsigned add
-- 0001 = unsigned subtract
-- 0010 = two's complement add
-- 0011 = two's complement subtract
-- 0100 = two's complement multiply
-- 0101 = two's complement divide
-- 0110 = logical AND
-- 0111 = bitwise AND
-- 1000 = logical OR
-- 1001 = bitwise OR
-- 1010 = logical NOT of operand1 (ignore operand2)
-- 1011 = bitwise NOT of operand1 (ignore operand2)
-- 1100-1111 = just output all zeroes
---------------------------------------------------------------------------------------------
-- The unit returns the 32-bit result of the operation and a 4-bit error code. The meaning of
-- the error code should be
-- 0000 = no error
-- 0001 = overflow
-- 0010 = underflow
-- 0011 = divide by zero
---------------------------------------------------------------------------------------------
entity ALU is
Port (
operand1 : in dlx_word; -- Operand 1 input 32-bit
operand2 : in dlx_word; -- Operand 2 input 32-bit
operation : in alu_operation_code; -- 4-bit Op Code from dlx_types
result : out dlx_word;
error : out error_code
);
end entity ALU;
architecture behavior of ALU is
-- Define any types here that will be used
begin
alu_process: process(operand1, operand2, operation) is
-- Declare any local variables here
variable temp_result: dlx_word := x"00000000";
variable logical_true: dlx_word := x"00000001";
variable logical_false: dlx_word := x"00000000";
variable overflow_flag_set: boolean;
variable div_by_zero: boolean;
variable op1_logical_status: bit; -- 0 means false; 1 means true
variable op2_logical_status: bit; -- 0 means false; 1 means true
begin
error <= "0000"; -- Default value for port signal output error
case(operation) is
when "0000" => -- UNSIGNED ADD
bv_addu(operand1, operand2, temp_result, overflow_flag_set);
if overflow_flag_set then
error <= "0001";
end if;
result <= temp_result;
when "0001" => -- UNSIGNED SUBTRACT
bv_subu(operand1, operand2, temp_result, overflow_flag_set);
if overflow_flag_set then
error <= "0010";
-- Unsigned subtract is only concerned with underflow
end if;
result <= temp_result;
when "0010" => -- TWO'S COMPLEMENT ADD
bv_add(operand1, operand2, temp_result, overflow_flag_set);
if overflow_flag_set then
-- IF (+A) + (+B) = -C
if (operand1(31) = '0') AND (operand2(31) = '0') then
if (temp_result(31) = '1') then
error <= "0001"; -- overflow occurred
end if;
-- (-A) + (-B) = +C
elsif (operand1(31) = '1') AND (operand2(31) = '1') then
if (temp_result(31) = '0') then
error <= "0010"; -- underflow occurred
end if;
end if;
end if;
result <= temp_result;
when "0011" => -- TWO'S COMPLEMENT SUBTRACT
bv_sub(operand1, operand2, temp_result, overflow_flag_set);
if overflow_flag_set then
-- IF (-A) - (+B) = +C
if (operand1(31) = '1') AND (operand2(31) = '0') then
if (temp_result(31) = '0') then
error <= "0010"; -- underflow occurred
end if;
-- IF (+A) - (-B) = -C
elsif (operand1(31) = '0') AND (operand2(31) = '1') then
if (temp_result(31) = '1') then
error <= "0001"; -- overflow occurred
end if;
end if;
end if;
result <= temp_result;
when "0100" => -- TWO'S COMPLEMENT MULTIPLY - (2 underflow Conditions + 2 overflow conditions)
bv_mult(operand1, operand2, temp_result, overflow_flag_set);
if overflow_flag_set then
if (operand1(31) = '1') AND (operand2(31) = '0') then -- (-A x +B) = +C
error <= "0010"; -- underflow
elsif (operand1(31) = '0') AND (operand2(31) = '1') then -- (+A x -B) = +C
error <= "0010"; -- underflow
else -- (+A x +B) = -C OR (-A x -B) = -C
error <= "0001"; -- overflow
end if;
end if;
result <= temp_result;
when "0101" => -- TWO'S COMPLEMENT DIVIDE
----------------------------------------------------------------------------------------
-- The only way a two's complement divide can underflow is if you divide the most
-- negative value by -ve 1. Divide underflow occurs when the divisor is much smaller
-- than the dividend. The result is almost zero. Test with 80000000 / FFFFFFFF
-- (Quotient will be smaller than the dividend)
-- NOTE: For grading purposes, this condition will not be tested but must be implemented
-----------------------------------------------------------------------------------------
bv_div(operand1, operand2, temp_result, div_by_zero, overflow_flag_set);
if div_by_zero then
error <= "0011"; --
elsif overflow_flag_set then
error <= "0010"; -- only an underflow can occur with divide (see note above)
end if;
result <= temp_result;
when "0110" => -- PERFORM LOGICAL AND
------------------------------------------------------------------------
-- For logical operations, anything resulting in a non-zero value is 1,
-- for true. Anything resulting in all zeroes is assigned 0, false.
-- Logical operation always results in true (1) or false (0).
------------------------------------------------------------------------
op1_logical_status := '0'; -- Default logical status for operand1
op2_logical_status := '0'; -- Default logical status for operand2
-- check if operand1 is a non-zero value --
for i in 31 downto 0 loop
-- If non-zero value, operand1 is logical true;
if (operand1(i) = '1') then
op1_logical_status := '1';
exit;
end if;
end loop;
-- check if operand2 is a non-zero value
for i in 31 downto 0 loop
-- If non-zero value, operand2 is logical true;
if (operand2(i) = '1') then
op2_logical_status := '1';
exit;
end if;
end loop;
-- IF operand statuses result in --> '1' && '1' = '1'
if ((op1_logical_status AND op2_logical_status) = '1') then
result <= logical_true; -- The result is logical true x"00000001"
else
result <= logical_false; -- Else result is logical false x"00000000"
end if;
when "0111" => -- PERFORM BITWISE AND
for i in 31 downto 0 loop
temp_result(i) := operand1(i) AND operand2(i);
end loop;
result <= temp_result;
when "1000" => -- PERFORM LOGICAL OR
------------------------------------------------------------------------
-- For logical operations, anything resulting in a non-zero value is 1,
-- for true. Anything resulting in a zero is assigned 0, false.
-- Logical operation always results in true (1) or false (0).
------------------------------------------------------------------------
op1_logical_status := '0'; -- Default logical status for operand 1
op2_logical_status := '0'; -- Default logical status for operand 2
-- check if operand1 is a non-zero value --
for i in 31 downto 0 loop
-- If non-zero value, operand1 is logical true;
if (operand1(i) = '1') then
op1_logical_status := '1';
exit;
end if;
end loop;
-- check if operand2 is a non-zero value
for i in 31 downto 0 loop
-- If non-zero value, operand2 is logical true;
if (operand2(i) = '1') then
op2_logical_status := '1';
exit;
end if;
end loop;
-- IF operand statuses result in --> ('1'||'1' OR '1'||'0' OR '0'||'1' ) = '1'
if ((op1_logical_status OR op2_logical_status) = '1') then
result <= logical_true; -- The result is logical true x"00000001"
else
result <= logical_false; -- Else result is logical false x"00000000"
end if;
when "1001" => -- PERFORM BITWISE OR
for i in 31 downto 0 loop
temp_result(i) := operand1(i) OR operand2(i);
end loop;
result <= temp_result;
when "1010" => -- PERFORM LOGICAL NOT OF OPERAND1 (ignore operand2)
temp_result := logical_false; -- Initially assigned to false (i.e. 32'h00000000)
for i in 31 downto 0 loop
if (NOT operand1(i) = '0') then -- i.e. IF operand1 is non-zero
temp_result := logical_true; -- logical NOT resulted in true, assign true (i.e. 32'h00000001)
exit;
end if;
end loop;
result <= temp_result;
when "1011" => -- PERFORM BITWISE NOT OF OPERAND1 (ignore operand2)
for i in 31 downto 0 loop
temp_result(i) := NOT operand1(i);
end loop;
result <= temp_result;
when others => -- 1100 thru 1111 outputs all zeroes
result <= x"00000000";
end case;
end process alu_process;
end architecture behavior;