-
Notifications
You must be signed in to change notification settings - Fork 1
/
alu.vhd
166 lines (151 loc) · 5.04 KB
/
alu.vhd
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
library IEEE;
use IEEE.STD_LOGIC_1164.all;
package P_ALU is
subtype T_ALU_OP is STD_LOGIC_VECTOR (4 downto 0);
constant OP_ADD : T_ALU_OP := '0' & x"0";
constant OP_ADDC : T_ALU_OP := '0' & x"1";
constant OP_SUB : T_ALU_OP := '0' & x"2";
constant OP_SUBC : T_ALU_OP := '0' & x"3";
constant OP_AND : T_ALU_OP := '0' & x"4";
constant OP_OR : T_ALU_OP := '0' & x"5";
constant OP_XOR : T_ALU_OP := '0' & x"6";
constant OP_COPY : T_ALU_OP := '0' & x"7";
constant OP_COMP : T_ALU_OP := '0' & x"8";
constant OP_BIT : T_ALU_OP := '0' & x"9";
constant OP_MULU : T_ALU_OP := '0' & x"a";
constant OP_MULS : T_ALU_OP := '0' & x"b";
constant OP_INC : T_ALU_OP := '1' & x"0";
constant OP_DEC : T_ALU_OP := '1' & x"1";
constant OP_INCD : T_ALU_OP := '1' & x"2";
constant OP_DECD : T_ALU_OP := '1' & x"3";
constant OP_NOT : T_ALU_OP := '1' & x"4";
constant OP_LOGIC_LEFT : T_ALU_OP := '1' & x"5";
constant OP_LOGIC_RIGHT : T_ALU_OP := '1' & x"6";
constant OP_ARITH_LEFT : T_ALU_OP := '1' & x"7";
constant OP_ARITH_RIGHT : T_ALU_OP := '1' & x"8";
constant OP_NEG : T_ALU_OP := '1' & x"9";
constant OP_SWAP : T_ALU_OP := '1' & x"a";
constant OP_TEST : T_ALU_OP := '1' & x"b";
end package;
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use IEEE.NUMERIC_STD.ALL;
use work.P_ALU.all;
entity alu is
port (
OP : in T_ALU_OP;
LEFT, RIGHT : in STD_LOGIC_VECTOR (15 downto 0);
CARRY_IN : in STD_LOGIC;
RESULT : out STD_LOGIC_VECTOR (15 downto 0);
CARRY_OUT : out STD_LOGIC;
ZERO_OUT : out STD_LOGIC;
NEG_OUT : out STD_LOGIC;
OVER_OUT : out STD_LOGIC
);
end entity;
architecture behavioural of alu is
begin
process (LEFT, RIGHT, OP, CARRY_IN)
variable TEMP_LEFT : STD_LOGIC_VECTOR (16 downto 0) := (others => '0');
variable TEMP_RIGHT : STD_LOGIC_VECTOR (16 downto 0) := (others => '0');
variable TEMP_RESUlT : STD_LOGIC_VECTOR (16 downto 0) := (others => '0');
variable GIVE_RESULT : STD_LOGIC := '0';
begin
GIVE_RESULT := '1';
TEMP_LEFT := '0' & LEFT (15 downto 0);
TEMP_RIGHT := '0' & RIGHT (15 downto 0);
case OP is
when OP_ADD =>
TEMP_RESULT := TEMP_RIGHT + TEMP_LEFT;
when OP_ADDC =>
TEMP_RESULT := TEMP_RIGHT + TEMP_LEFT + CARRY_IN;
when OP_SUB =>
TEMP_RESULT := TEMP_RIGHT - TEMP_LEFT;
when OP_SUBC =>
TEMP_RESULT := TEMP_RIGHT - TEMP_LEFT - CARRY_IN;
when OP_AND =>
TEMP_RESULT := TEMP_RIGHT and TEMP_LEFT;
when OP_OR =>
TEMP_RESULT := TEMP_RIGHT or TEMP_LEFT;
when OP_XOR =>
TEMP_RESULT := TEMP_RIGHT xor TEMP_LEFT;
when OP_COPY =>
TEMP_RESULT := TEMP_LEFT;
when OP_COMP =>
TEMP_RESULT := TEMP_RIGHT - TEMP_LEFT;
GIVE_RESULT := '0';
when OP_BIT =>
TEMP_RESULT := TEMP_RIGHT and TEMP_LEFT;
GIVE_RESULT := '0';
when OP_MULU =>
TEMP_RESULT := '0' & STD_LOGIC_VECTOR(unsigned(TEMP_RIGHT (7 downto 0)) * unsigned(TEMP_LEFT (7 downto 0)));
when OP_MULS =>
TEMP_RESULT := '0' & STD_LOGIC_VECTOR(signed(TEMP_RIGHT (7 downto 0)) * signed(TEMP_LEFT (7 downto 0)));
when OP_INC =>
TEMP_RESULT := TEMP_RIGHT + 1;
when OP_DEC =>
TEMP_RESULT := TEMP_RIGHT - 1;
when OP_INCD =>
TEMP_RESULT := TEMP_RIGHT + 2;
when OP_DECD =>
TEMP_RESULT := TEMP_RIGHT - 2;
when OP_NOT =>
TEMP_RESULT := not ('1' & TEMP_RIGHT (15 downto 0));
when OP_LOGIC_LEFT =>
TEMP_RESULT := TEMP_RIGHT (15 downto 0) & '0';
when OP_LOGIC_RIGHT =>
TEMP_RESULT := TEMP_RIGHT (0) & '0' & TEMP_RIGHT (15 downto 1);
when OP_ARITH_LEFT =>
TEMP_RESULT := TEMP_RIGHT (15 downto 0) & '0';
when OP_ARITH_RIGHT =>
TEMP_RESULT := TEMP_RIGHT (0) & TEMP_RIGHT (15) & TEMP_RIGHT (15 downto 1);
when OP_NEG =>
TEMP_RESULT := not TEMP_RIGHT + 1;
when OP_SWAP =>
TEMP_RESULT := '0' & TEMP_RIGHT (7 downto 0) & TEMP_RIGHT (15 downto 8);
when OP_TEST =>
TEMP_RESULT := TEMP_RIGHT;
GIVE_RESULT := '0';
when others =>
TEMP_RESULT := (others => '0');
end case;
if (GIVE_RESULT = '1') then
RESULT <= TEMP_RESULT (15 downto 0);
else
RESULT <= RIGHT;
end if;
CARRY_OUT <= TEMP_RESULT (16);
if (TEMP_RESULT (15 downto 0) = x"0000") then
ZERO_OUT <= '1';
else
ZERO_OUT <= '0';
end if;
NEG_OUT <= TEMP_RESULT (15);
-- When adding then if sign of result is different to the sign of both the
-- operands then it is an overflow condition
if (OP = OP_ADD or OP = OP_ADDC) then
if (TEMP_LEFT (15) /= TEMP_RESULT (15) and TEMP_RIGHT (15) /= TEMP_RESULT (15)) then
OVER_OUT <= '1';
else
OVER_OUT <= '0';
end if;
-- Likewise for sub, but invert the left sign for test as its a subtract
elsif (OP = OP_SUB or OP = OP_SUBC) then
if (TEMP_LEFT (15) = TEMP_RESULT (15) and TEMP_RIGHT (15) /= TEMP_RESULT (15)) then
OVER_OUT <= '1';
else
OVER_OUT <= '0';
end if;
-- For arith shift left, if the sign changed then it is an overflow
elsif (OP = OP_ARITH_LEFT) then
if (TEMP_RIGHT (15) /= TEMP_RESULT (15)) then
OVER_OUT <= '1';
else
OVER_OUT <= '0';
end if;
else
OVER_OUT <= '0';
end if;
end process;
end architecture;