1 |
2 |
takar |
----------------------------------------------------------------------------------------------
|
2 |
|
|
--
|
3 |
|
|
-- Input file : execute.vhd
|
4 |
|
|
-- Design name : execute
|
5 |
|
|
-- Author : Tamar Kranenburg
|
6 |
|
|
-- Company : Delft University of Technology
|
7 |
|
|
-- : Faculty EEMCS, Department ME&CE
|
8 |
|
|
-- : Systems and Circuits group
|
9 |
|
|
--
|
10 |
|
|
-- Description : The Execution Unit performs all arithmetic operations and makes
|
11 |
|
|
-- the branch decision. Furthermore the forwarding logic is located
|
12 |
|
|
-- here. Everything is computed within a single clock-cycle
|
13 |
|
|
--
|
14 |
|
|
--
|
15 |
|
|
----------------------------------------------------------------------------------------------
|
16 |
|
|
|
17 |
|
|
LIBRARY ieee;
|
18 |
|
|
USE ieee.std_logic_1164.ALL;
|
19 |
|
|
USE ieee.std_logic_unsigned.ALL;
|
20 |
|
|
|
21 |
|
|
LIBRARY mblite;
|
22 |
|
|
USE mblite.config_Pkg.ALL;
|
23 |
|
|
USE mblite.core_Pkg.ALL;
|
24 |
|
|
USE mblite.std_Pkg.ALL;
|
25 |
|
|
|
26 |
|
|
ENTITY execute IS GENERIC
|
27 |
|
|
(
|
28 |
|
|
G_USE_HW_MUL : boolean := CFG_USE_HW_MUL;
|
29 |
|
|
G_USE_BARREL : boolean := CFG_USE_BARREL
|
30 |
|
|
);
|
31 |
|
|
PORT
|
32 |
|
|
(
|
33 |
|
|
exec_o : OUT execute_out_type;
|
34 |
|
|
exec_i : IN execute_in_type;
|
35 |
|
|
ena_i : IN std_ulogic;
|
36 |
|
|
rst_i : IN std_ulogic;
|
37 |
|
|
clk_i : IN std_ulogic
|
38 |
|
|
);
|
39 |
|
|
END execute;
|
40 |
|
|
|
41 |
|
|
ARCHITECTURE arch OF execute IS
|
42 |
|
|
|
43 |
|
|
TYPE execute_reg_type IS RECORD
|
44 |
|
|
carry : std_ulogic;
|
45 |
|
|
flush_ex : std_ulogic;
|
46 |
|
|
END RECORD;
|
47 |
|
|
|
48 |
|
|
SIGNAL r, rin : execute_out_type;
|
49 |
|
|
SIGNAL reg, regin : execute_reg_type;
|
50 |
|
|
|
51 |
|
|
BEGIN
|
52 |
|
|
|
53 |
|
|
exec_o <= r;
|
54 |
|
|
|
55 |
|
|
execute_comb: PROCESS(exec_i,exec_i.fwd_mem,exec_i.ctrl_ex,
|
56 |
|
|
exec_i.ctrl_wb,exec_i.ctrl_mem,
|
57 |
|
|
exec_i.ctrl_mem.transfer_size,
|
58 |
|
|
exec_i.ctrl_mem_wb,exec_i.fwd_dec,
|
59 |
|
|
r,r.ctrl_mem,r.ctrl_mem.transfer_size,
|
60 |
|
|
r.ctrl_wb,reg)
|
61 |
|
|
|
62 |
|
|
VARIABLE v : execute_out_type;
|
63 |
|
|
VARIABLE v_reg : execute_reg_type;
|
64 |
|
|
|
65 |
|
|
VARIABLE alu_src_a : std_ulogic_vector(CFG_DMEM_WIDTH - 1 DOWNTO 0);
|
66 |
|
|
VARIABLE alu_src_b : std_ulogic_vector(CFG_DMEM_WIDTH - 1 DOWNTO 0);
|
67 |
|
|
VARIABLE carry : std_ulogic;
|
68 |
|
|
|
69 |
|
|
VARIABLE result : std_ulogic_vector(CFG_DMEM_WIDTH DOWNTO 0);
|
70 |
|
|
VARIABLE result_add : std_ulogic_vector(CFG_DMEM_WIDTH DOWNTO 0);
|
71 |
|
|
VARIABLE zero : std_ulogic;
|
72 |
|
|
|
73 |
|
|
VARIABLE dat_a, dat_b : std_ulogic_vector(CFG_DMEM_WIDTH - 1 DOWNTO 0);
|
74 |
|
|
VARIABLE sel_dat_a, sel_dat_b, sel_dat_d : std_ulogic_vector(CFG_DMEM_WIDTH - 1 DOWNTO 0);
|
75 |
|
|
VARIABLE mem_result : std_ulogic_vector(CFG_DMEM_WIDTH - 1 DOWNTO 0);
|
76 |
|
|
|
77 |
|
|
BEGIN
|
78 |
|
|
|
79 |
|
|
v := r;
|
80 |
|
|
|
81 |
|
|
sel_dat_a := select_register_data(exec_i.dat_a, exec_i.reg_a, exec_i.fwd_dec_result, forward_condition(exec_i.fwd_dec.reg_write, exec_i.fwd_dec.reg_d, exec_i.reg_a));
|
82 |
|
|
sel_dat_b := select_register_data(exec_i.dat_b, exec_i.reg_b, exec_i.fwd_dec_result, forward_condition(exec_i.fwd_dec.reg_write, exec_i.fwd_dec.reg_d, exec_i.reg_b));
|
83 |
|
|
sel_dat_d := select_register_data(exec_i.dat_d, exec_i.ctrl_wb.reg_d, exec_i.fwd_dec_result, forward_condition(exec_i.fwd_dec.reg_write, exec_i.fwd_dec.reg_d, exec_i.ctrl_wb.reg_d));
|
84 |
|
|
|
85 |
|
|
IF reg.flush_ex = '1' THEN
|
86 |
|
|
v.ctrl_mem.mem_write := '0';
|
87 |
|
|
v.ctrl_mem.mem_read := '0';
|
88 |
|
|
v.ctrl_wb.reg_write := '0';
|
89 |
|
|
v.ctrl_wb.reg_d := (OTHERS => '0');
|
90 |
|
|
ELSE
|
91 |
|
|
v.ctrl_mem := exec_i.ctrl_mem;
|
92 |
|
|
v.ctrl_wb := exec_i.ctrl_wb;
|
93 |
|
|
END IF;
|
94 |
|
|
|
95 |
|
|
IF exec_i.ctrl_mem_wb.mem_read = '1' THEN
|
96 |
|
|
mem_result := align_mem_load(exec_i.mem_result, exec_i.ctrl_mem_wb.transfer_size, exec_i.alu_result(1 DOWNTO 0));
|
97 |
|
|
ELSE
|
98 |
|
|
mem_result := exec_i.alu_result;
|
99 |
|
|
END IF;
|
100 |
|
|
|
101 |
|
|
IF forward_condition(r.ctrl_wb.reg_write, r.ctrl_wb.reg_d, exec_i.reg_a) = '1' THEN
|
102 |
|
|
-- Forward Execution Result to REG a
|
103 |
|
|
dat_a := r.alu_result;
|
104 |
|
|
ELSIF forward_condition(exec_i.fwd_mem.reg_write, exec_i.fwd_mem.reg_d, exec_i.reg_a) = '1' THEN
|
105 |
|
|
-- Forward Memory Result to REG a
|
106 |
|
|
dat_a := mem_result;
|
107 |
|
|
ELSE
|
108 |
|
|
-- DEFAULT: value of REG a
|
109 |
|
|
dat_a := sel_dat_a;
|
110 |
|
|
END IF;
|
111 |
|
|
|
112 |
|
|
IF forward_condition(r.ctrl_wb.reg_write, r.ctrl_wb.reg_d, exec_i.reg_b) = '1' THEN
|
113 |
|
|
-- Forward (latched) Execution Result to REG b
|
114 |
|
|
dat_b := r.alu_result;
|
115 |
|
|
ELSIF forward_condition(exec_i.fwd_mem.reg_write, exec_i.fwd_mem.reg_d, exec_i.reg_b) = '1' THEN
|
116 |
|
|
-- Forward Memory Result to REG b
|
117 |
|
|
dat_b := mem_result;
|
118 |
|
|
ELSE
|
119 |
|
|
-- DEFAULT: value of REG b
|
120 |
|
|
dat_b := sel_dat_b;
|
121 |
|
|
END IF;
|
122 |
|
|
|
123 |
|
|
IF forward_condition(r.ctrl_wb.reg_write, r.ctrl_wb.reg_d, exec_i.ctrl_wb.reg_d) = '1' THEN
|
124 |
|
|
-- Forward Execution Result to REG d
|
125 |
|
|
v.dat_d := align_mem_store(r.alu_result, exec_i.ctrl_mem.transfer_size);
|
126 |
|
|
ELSIF forward_condition(exec_i.fwd_mem.reg_write, exec_i.fwd_mem.reg_d, exec_i.ctrl_wb.reg_d) = '1' THEN
|
127 |
|
|
-- Forward Memory Result to REG d
|
128 |
|
|
v.dat_d := align_mem_store(mem_result, exec_i.ctrl_mem.transfer_size);
|
129 |
|
|
ELSE
|
130 |
|
|
-- DEFAULT: value of REG d
|
131 |
|
|
v.dat_d := align_mem_store(sel_dat_d, exec_i.ctrl_mem.transfer_size);
|
132 |
|
|
END IF;
|
133 |
|
|
|
134 |
|
|
-- Set the first operand of the ALU
|
135 |
|
|
CASE exec_i.ctrl_ex.alu_src_a IS
|
136 |
|
|
WHEN ALU_SRC_PC => alu_src_a := sign_extend(exec_i.program_counter, '0', 32);
|
137 |
|
|
WHEN ALU_SRC_NOT_REGA => alu_src_a := NOT dat_a;
|
138 |
|
|
WHEN ALU_SRC_ZERO => alu_src_a := (OTHERS => '0');
|
139 |
|
|
WHEN OTHERS => alu_src_a := dat_a;
|
140 |
|
|
END CASE;
|
141 |
|
|
|
142 |
|
|
-- Set the second operand of the ALU
|
143 |
|
|
CASE exec_i.ctrl_ex.alu_src_b IS
|
144 |
|
|
WHEN ALU_SRC_IMM => alu_src_b := exec_i.imm;
|
145 |
|
|
WHEN ALU_SRC_NOT_IMM => alu_src_b := NOT exec_i.imm;
|
146 |
|
|
WHEN ALU_SRC_NOT_REGB => alu_src_b := NOT dat_b;
|
147 |
|
|
WHEN OTHERS => alu_src_b := dat_b;
|
148 |
|
|
END CASE;
|
149 |
|
|
|
150 |
|
|
-- Determine value of carry in
|
151 |
|
|
CASE exec_i.ctrl_ex.carry IS
|
152 |
|
|
WHEN CARRY_ALU => carry := reg.carry;
|
153 |
|
|
WHEN CARRY_ONE => carry := '1';
|
154 |
|
|
WHEN CARRY_ARITH => carry := alu_src_a(CFG_DMEM_WIDTH - 1);
|
155 |
|
|
WHEN OTHERS => carry := '0';
|
156 |
|
|
END CASE;
|
157 |
|
|
|
158 |
|
|
result_add := add(alu_src_a, alu_src_b, carry);
|
159 |
|
|
|
160 |
|
|
CASE exec_i.ctrl_ex.alu_op IS
|
161 |
|
|
WHEN ALU_ADD => result := result_add;
|
162 |
|
|
WHEN ALU_OR => result := '0' & (alu_src_a OR alu_src_b);
|
163 |
|
|
WHEN ALU_AND => result := '0' & (alu_src_a AND alu_src_b);
|
164 |
|
|
WHEN ALU_XOR => result := '0' & (alu_src_a XOR alu_src_b);
|
165 |
|
|
WHEN ALU_SHIFT => result := alu_src_a(0) & carry & alu_src_a(CFG_DMEM_WIDTH - 1 DOWNTO 1);
|
166 |
|
|
WHEN ALU_SEXT8 => result := '0' & sign_extend(alu_src_a(7 DOWNTO 0), alu_src_a(7), 32);
|
167 |
|
|
WHEN ALU_SEXT16 => result := '0' & sign_extend(alu_src_a(15 DOWNTO 0), alu_src_a(15), 32);
|
168 |
|
|
WHEN ALU_MUL =>
|
169 |
|
|
IF G_USE_HW_MUL = true THEN
|
170 |
|
|
result := '0' & multiply(alu_src_a, alu_src_b);
|
171 |
|
|
ELSE
|
172 |
|
|
result := (OTHERS => '0');
|
173 |
|
|
END IF;
|
174 |
|
|
WHEN ALU_BS =>
|
175 |
|
|
IF G_USE_BARREL = true THEN
|
176 |
|
|
result := '0' & shift(alu_src_a, alu_src_b(4 DOWNTO 0), exec_i.imm(10), exec_i.imm(9));
|
177 |
|
|
ELSE
|
178 |
|
|
result := (OTHERS => '0');
|
179 |
|
|
END IF;
|
180 |
|
|
WHEN OTHERS =>
|
181 |
|
|
result := (OTHERS => '0');
|
182 |
|
|
REPORT "Invalid ALU operation" SEVERITY FAILURE;
|
183 |
|
|
END CASE;
|
184 |
|
|
|
185 |
|
|
-- Set carry register
|
186 |
|
|
IF exec_i.ctrl_ex.carry_keep = CARRY_KEEP THEN
|
187 |
|
|
v_reg.carry := reg.carry;
|
188 |
|
|
ELSE
|
189 |
|
|
v_reg.carry := result(CFG_DMEM_WIDTH);
|
190 |
|
|
END IF;
|
191 |
|
|
|
192 |
|
|
zero := is_zero(dat_a);
|
193 |
|
|
|
194 |
|
|
-- Overwrite branch condition
|
195 |
|
|
IF reg.flush_ex = '1' THEN
|
196 |
|
|
v.branch := '0';
|
197 |
|
|
ELSE
|
198 |
|
|
-- Determine branch condition
|
199 |
|
|
CASE exec_i.ctrl_ex.branch_cond IS
|
200 |
|
|
WHEN BNC => v.branch := '1';
|
201 |
|
|
WHEN BEQ => v.branch := zero;
|
202 |
|
|
WHEN BNE => v.branch := NOT zero;
|
203 |
|
|
WHEN BLT => v.branch := dat_a(CFG_DMEM_WIDTH - 1);
|
204 |
|
|
WHEN BLE => v.branch := dat_a(CFG_DMEM_WIDTH - 1) OR zero;
|
205 |
|
|
WHEN BGT => v.branch := NOT dat_a(CFG_DMEM_WIDTH - 1);
|
206 |
|
|
WHEN BGE => v.branch := NOT dat_a(CFG_DMEM_WIDTH - 1) OR zero;
|
207 |
|
|
WHEN OTHERS => v.branch := '0';
|
208 |
|
|
END CASE;
|
209 |
|
|
END IF;
|
210 |
|
|
|
211 |
|
|
-- Handle CMPU
|
212 |
|
|
IF ( exec_i.ctrl_ex.operation AND NOT (alu_src_a(CFG_DMEM_WIDTH - 1) XOR alu_src_b(CFG_DMEM_WIDTH - 1))) = '1' THEN
|
213 |
|
|
-- Set MSB
|
214 |
|
|
v.alu_result(CFG_DMEM_WIDTH - 1 DOWNTO 0) := (NOT result(CFG_DMEM_WIDTH - 1)) & result(CFG_DMEM_WIDTH - 2 DOWNTO 0);
|
215 |
|
|
ELSE
|
216 |
|
|
-- Use ALU result
|
217 |
|
|
v.alu_result := result(CFG_DMEM_WIDTH - 1 DOWNTO 0);
|
218 |
|
|
END IF;
|
219 |
|
|
|
220 |
|
|
v.program_counter := exec_i.program_counter;
|
221 |
|
|
|
222 |
|
|
-- Determine flush signals
|
223 |
|
|
v.flush_id := v.branch;
|
224 |
|
|
v_reg.flush_ex := v.branch AND NOT exec_i.ctrl_ex.delay;
|
225 |
|
|
|
226 |
|
|
rin <= v;
|
227 |
|
|
regin <= v_reg;
|
228 |
|
|
|
229 |
|
|
END PROCESS;
|
230 |
|
|
|
231 |
|
|
execute_seq: PROCESS(clk_i)
|
232 |
|
|
PROCEDURE proc_execute_reset IS
|
233 |
|
|
BEGIN
|
234 |
|
|
r.alu_result <= (OTHERS => '0');
|
235 |
|
|
r.dat_d <= (OTHERS => '0');
|
236 |
|
|
r.branch <= '0';
|
237 |
|
|
r.program_counter <= (OTHERS => '0');
|
238 |
|
|
r.flush_id <= '0';
|
239 |
|
|
r.ctrl_mem.mem_write <= '0';
|
240 |
|
|
r.ctrl_mem.mem_read <= '0';
|
241 |
|
|
r.ctrl_mem.transfer_size <= WORD;
|
242 |
|
|
r.ctrl_wb.reg_d <= (OTHERS => '0');
|
243 |
|
|
r.ctrl_wb.reg_write <= '0';
|
244 |
|
|
reg.carry <= '0';
|
245 |
|
|
reg.flush_ex <= '0';
|
246 |
|
|
END PROCEDURE proc_execute_reset;
|
247 |
|
|
BEGIN
|
248 |
|
|
IF rising_edge(clk_i) THEN
|
249 |
|
|
IF rst_i = '1' THEN
|
250 |
|
|
proc_execute_reset;
|
251 |
|
|
ELSIF ena_i = '1' THEN
|
252 |
|
|
r <= rin;
|
253 |
|
|
reg <= regin;
|
254 |
|
|
END IF;
|
255 |
|
|
END IF;
|
256 |
|
|
END PROCESS;
|
257 |
|
|
END arch;
|