Line 12... |
Line 12... |
-- here. Everything is computed within a single clock-cycle
|
-- here. Everything is computed within a single clock-cycle
|
--
|
--
|
--
|
--
|
----------------------------------------------------------------------------------------------
|
----------------------------------------------------------------------------------------------
|
|
|
LIBRARY ieee;
|
library ieee;
|
USE ieee.std_logic_1164.ALL;
|
use ieee.std_logic_1164.all;
|
USE ieee.std_logic_unsigned.ALL;
|
use ieee.std_logic_unsigned.all;
|
|
|
LIBRARY mblite;
|
library mblite;
|
USE mblite.config_Pkg.ALL;
|
use mblite.config_Pkg.all;
|
USE mblite.core_Pkg.ALL;
|
use mblite.core_Pkg.all;
|
USE mblite.std_Pkg.ALL;
|
use mblite.std_Pkg.all;
|
|
|
ENTITY execute IS GENERIC
|
entity execute is generic
|
(
|
(
|
G_USE_HW_MUL : boolean := CFG_USE_HW_MUL;
|
G_USE_HW_MUL : boolean := CFG_USE_HW_MUL;
|
G_USE_BARREL : boolean := CFG_USE_BARREL
|
G_USE_BARREL : boolean := CFG_USE_BARREL
|
);
|
);
|
PORT
|
port
|
(
|
(
|
exec_o : OUT execute_out_type;
|
exec_o : out execute_out_type;
|
exec_i : IN execute_in_type;
|
exec_i : in execute_in_type;
|
ena_i : IN std_logic;
|
ena_i : in std_logic;
|
rst_i : IN std_logic;
|
rst_i : in std_logic;
|
clk_i : IN std_logic
|
clk_i : in std_logic
|
);
|
);
|
END execute;
|
end execute;
|
|
|
ARCHITECTURE arch OF execute IS
|
architecture arch of execute is
|
|
|
TYPE execute_reg_type IS RECORD
|
type execute_reg_type is record
|
carry : std_logic;
|
carry : std_logic;
|
flush_ex : std_logic;
|
flush_ex : std_logic;
|
END RECORD;
|
end record;
|
|
|
SIGNAL r, rin : execute_out_type;
|
signal r, rin : execute_out_type;
|
SIGNAL reg, regin : execute_reg_type;
|
signal reg, regin : execute_reg_type;
|
|
|
BEGIN
|
begin
|
|
|
exec_o <= r;
|
exec_o <= r;
|
|
|
execute_comb: PROCESS(exec_i,exec_i.fwd_mem,exec_i.ctrl_ex,
|
execute_comb: process(exec_i,exec_i.fwd_mem,exec_i.ctrl_ex,
|
exec_i.ctrl_wb,exec_i.ctrl_mem,
|
exec_i.ctrl_wrb,exec_i.ctrl_mem,
|
exec_i.ctrl_mem.transfer_size,
|
exec_i.ctrl_mem.transfer_size,
|
exec_i.ctrl_mem_wb,exec_i.fwd_dec,
|
exec_i.ctrl_mem_wrb,exec_i.fwd_dec,
|
r,r.ctrl_mem,r.ctrl_mem.transfer_size,
|
r,r.ctrl_mem,r.ctrl_mem.transfer_size,
|
r.ctrl_wb,reg)
|
r.ctrl_wrb,reg)
|
|
|
VARIABLE v : execute_out_type;
|
variable v : execute_out_type;
|
VARIABLE v_reg : execute_reg_type;
|
variable v_reg : execute_reg_type;
|
|
|
VARIABLE alu_src_a : std_logic_vector(CFG_DMEM_WIDTH - 1 DOWNTO 0);
|
variable alu_src_a : std_logic_vector(CFG_DMEM_WIDTH - 1 downto 0);
|
VARIABLE alu_src_b : std_logic_vector(CFG_DMEM_WIDTH - 1 DOWNTO 0);
|
variable alu_src_b : std_logic_vector(CFG_DMEM_WIDTH - 1 downto 0);
|
VARIABLE carry : std_logic;
|
variable carry : std_logic;
|
|
|
VARIABLE result : std_logic_vector(CFG_DMEM_WIDTH DOWNTO 0);
|
variable result : std_logic_vector(CFG_DMEM_WIDTH downto 0);
|
VARIABLE result_add : std_logic_vector(CFG_DMEM_WIDTH DOWNTO 0);
|
variable result_add : std_logic_vector(CFG_DMEM_WIDTH downto 0);
|
VARIABLE zero : std_logic;
|
variable zero : std_logic;
|
|
|
VARIABLE dat_a, dat_b : std_logic_vector(CFG_DMEM_WIDTH - 1 DOWNTO 0);
|
variable dat_a, dat_b : std_logic_vector(CFG_DMEM_WIDTH - 1 downto 0);
|
VARIABLE sel_dat_a, sel_dat_b, sel_dat_d : std_logic_vector(CFG_DMEM_WIDTH - 1 DOWNTO 0);
|
variable sel_dat_a, sel_dat_b, sel_dat_d : std_logic_vector(CFG_DMEM_WIDTH - 1 downto 0);
|
VARIABLE mem_result : std_logic_vector(CFG_DMEM_WIDTH - 1 DOWNTO 0);
|
variable mem_result : std_logic_vector(CFG_DMEM_WIDTH - 1 downto 0);
|
|
|
BEGIN
|
begin
|
|
|
v := r;
|
v := r;
|
|
|
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));
|
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));
|
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));
|
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));
|
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));
|
sel_dat_d := select_register_data(exec_i.dat_d, exec_i.ctrl_wrb.reg_d, exec_i.fwd_dec_result, forward_condition(exec_i.fwd_dec.reg_write, exec_i.fwd_dec.reg_d, exec_i.ctrl_wrb.reg_d));
|
|
|
IF reg.flush_ex = '1' THEN
|
if reg.flush_ex = '1' then
|
v.ctrl_mem.mem_write := '0';
|
v.ctrl_mem.mem_write := '0';
|
v.ctrl_mem.mem_read := '0';
|
v.ctrl_mem.mem_read := '0';
|
v.ctrl_wb.reg_write := '0';
|
v.ctrl_wrb.reg_write := '0';
|
v.ctrl_wb.reg_d := (OTHERS => '0');
|
v.ctrl_wrb.reg_d := (others => '0');
|
ELSE
|
else
|
v.ctrl_mem := exec_i.ctrl_mem;
|
v.ctrl_mem := exec_i.ctrl_mem;
|
v.ctrl_wb := exec_i.ctrl_wb;
|
v.ctrl_wrb := exec_i.ctrl_wrb;
|
END IF;
|
end if;
|
|
|
IF exec_i.ctrl_mem_wb.mem_read = '1' THEN
|
if exec_i.ctrl_mem_wrb.mem_read = '1' then
|
mem_result := align_mem_load(exec_i.mem_result, exec_i.ctrl_mem_wb.transfer_size, exec_i.alu_result(1 DOWNTO 0));
|
mem_result := align_mem_load(exec_i.mem_result, exec_i.ctrl_mem_wrb.transfer_size, exec_i.alu_result(1 downto 0));
|
ELSE
|
else
|
mem_result := exec_i.alu_result;
|
mem_result := exec_i.alu_result;
|
END IF;
|
end if;
|
|
|
IF forward_condition(r.ctrl_wb.reg_write, r.ctrl_wb.reg_d, exec_i.reg_a) = '1' THEN
|
if forward_condition(r.ctrl_wrb.reg_write, r.ctrl_wrb.reg_d, exec_i.reg_a) = '1' then
|
-- Forward Execution Result to REG a
|
-- Forward Execution Result to REG a
|
dat_a := r.alu_result;
|
dat_a := r.alu_result;
|
ELSIF forward_condition(exec_i.fwd_mem.reg_write, exec_i.fwd_mem.reg_d, exec_i.reg_a) = '1' THEN
|
elsif forward_condition(exec_i.fwd_mem.reg_write, exec_i.fwd_mem.reg_d, exec_i.reg_a) = '1' then
|
-- Forward Memory Result to REG a
|
-- Forward Memory Result to REG a
|
dat_a := mem_result;
|
dat_a := mem_result;
|
ELSE
|
else
|
-- DEFAULT: value of REG a
|
-- DEFAULT: value of REG a
|
dat_a := sel_dat_a;
|
dat_a := sel_dat_a;
|
END IF;
|
end if;
|
|
|
IF forward_condition(r.ctrl_wb.reg_write, r.ctrl_wb.reg_d, exec_i.reg_b) = '1' THEN
|
if forward_condition(r.ctrl_wrb.reg_write, r.ctrl_wrb.reg_d, exec_i.reg_b) = '1' then
|
-- Forward (latched) Execution Result to REG b
|
-- Forward (latched) Execution Result to REG b
|
dat_b := r.alu_result;
|
dat_b := r.alu_result;
|
ELSIF forward_condition(exec_i.fwd_mem.reg_write, exec_i.fwd_mem.reg_d, exec_i.reg_b) = '1' THEN
|
elsif forward_condition(exec_i.fwd_mem.reg_write, exec_i.fwd_mem.reg_d, exec_i.reg_b) = '1' then
|
-- Forward Memory Result to REG b
|
-- Forward Memory Result to REG b
|
dat_b := mem_result;
|
dat_b := mem_result;
|
ELSE
|
else
|
-- DEFAULT: value of REG b
|
-- DEFAULT: value of REG b
|
dat_b := sel_dat_b;
|
dat_b := sel_dat_b;
|
END IF;
|
end if;
|
|
|
IF forward_condition(r.ctrl_wb.reg_write, r.ctrl_wb.reg_d, exec_i.ctrl_wb.reg_d) = '1' THEN
|
if forward_condition(r.ctrl_wrb.reg_write, r.ctrl_wrb.reg_d, exec_i.ctrl_wrb.reg_d) = '1' then
|
-- Forward Execution Result to REG d
|
-- Forward Execution Result to REG d
|
v.dat_d := align_mem_store(r.alu_result, exec_i.ctrl_mem.transfer_size);
|
v.dat_d := align_mem_store(r.alu_result, exec_i.ctrl_mem.transfer_size);
|
ELSIF forward_condition(exec_i.fwd_mem.reg_write, exec_i.fwd_mem.reg_d, exec_i.ctrl_wb.reg_d) = '1' THEN
|
elsif forward_condition(exec_i.fwd_mem.reg_write, exec_i.fwd_mem.reg_d, exec_i.ctrl_wrb.reg_d) = '1' then
|
-- Forward Memory Result to REG d
|
-- Forward Memory Result to REG d
|
v.dat_d := align_mem_store(mem_result, exec_i.ctrl_mem.transfer_size);
|
v.dat_d := align_mem_store(mem_result, exec_i.ctrl_mem.transfer_size);
|
ELSE
|
else
|
-- DEFAULT: value of REG d
|
-- DEFAULT: value of REG d
|
v.dat_d := align_mem_store(sel_dat_d, exec_i.ctrl_mem.transfer_size);
|
v.dat_d := align_mem_store(sel_dat_d, exec_i.ctrl_mem.transfer_size);
|
END IF;
|
end if;
|
|
|
-- Set the first operand of the ALU
|
-- Set the first operand of the ALU
|
CASE exec_i.ctrl_ex.alu_src_a IS
|
case exec_i.ctrl_ex.alu_src_a is
|
WHEN ALU_SRC_PC => alu_src_a := sign_extend(exec_i.program_counter, '0', 32);
|
when ALU_SRC_PC => alu_src_a := sign_extend(exec_i.program_counter, '0', 32);
|
WHEN ALU_SRC_NOT_REGA => alu_src_a := NOT dat_a;
|
when ALU_SRC_NOT_REGA => alu_src_a := not dat_a;
|
WHEN ALU_SRC_ZERO => alu_src_a := (OTHERS => '0');
|
when ALU_SRC_ZERO => alu_src_a := (others => '0');
|
WHEN OTHERS => alu_src_a := dat_a;
|
when others => alu_src_a := dat_a;
|
END CASE;
|
end case;
|
|
|
-- Set the second operand of the ALU
|
-- Set the second operand of the ALU
|
CASE exec_i.ctrl_ex.alu_src_b IS
|
case exec_i.ctrl_ex.alu_src_b is
|
WHEN ALU_SRC_IMM => alu_src_b := exec_i.imm;
|
when ALU_SRC_IMM => alu_src_b := exec_i.imm;
|
WHEN ALU_SRC_NOT_IMM => alu_src_b := NOT exec_i.imm;
|
when ALU_SRC_NOT_IMM => alu_src_b := not exec_i.imm;
|
WHEN ALU_SRC_NOT_REGB => alu_src_b := NOT dat_b;
|
when ALU_SRC_NOT_REGB => alu_src_b := not dat_b;
|
WHEN OTHERS => alu_src_b := dat_b;
|
when others => alu_src_b := dat_b;
|
END CASE;
|
end case;
|
|
|
-- Determine value of carry in
|
-- Determine value of carry in
|
CASE exec_i.ctrl_ex.carry IS
|
case exec_i.ctrl_ex.carry is
|
WHEN CARRY_ALU => carry := reg.carry;
|
when CARRY_ALU => carry := reg.carry;
|
WHEN CARRY_ONE => carry := '1';
|
when CARRY_ONE => carry := '1';
|
WHEN CARRY_ARITH => carry := alu_src_a(CFG_DMEM_WIDTH - 1);
|
when CARRY_ARITH => carry := alu_src_a(CFG_DMEM_WIDTH - 1);
|
WHEN OTHERS => carry := '0';
|
when others => carry := '0';
|
END CASE;
|
end case;
|
|
|
result_add := add(alu_src_a, alu_src_b, carry);
|
result_add := add(alu_src_a, alu_src_b, carry);
|
|
|
CASE exec_i.ctrl_ex.alu_op IS
|
case exec_i.ctrl_ex.alu_op is
|
WHEN ALU_ADD => result := result_add;
|
when ALU_ADD => result := result_add;
|
WHEN ALU_OR => result := '0' & (alu_src_a OR alu_src_b);
|
when ALU_OR => result := '0' & (alu_src_a or alu_src_b);
|
WHEN ALU_AND => result := '0' & (alu_src_a AND alu_src_b);
|
when ALU_AND => result := '0' & (alu_src_a and alu_src_b);
|
WHEN ALU_XOR => result := '0' & (alu_src_a XOR alu_src_b);
|
when ALU_XOR => result := '0' & (alu_src_a xor alu_src_b);
|
WHEN ALU_SHIFT => result := alu_src_a(0) & carry & alu_src_a(CFG_DMEM_WIDTH - 1 DOWNTO 1);
|
when ALU_SHIFT => result := alu_src_a(0) & carry & alu_src_a(CFG_DMEM_WIDTH - 1 downto 1);
|
WHEN ALU_SEXT8 => result := '0' & sign_extend(alu_src_a(7 DOWNTO 0), alu_src_a(7), 32);
|
when ALU_SEXT8 => result := '0' & sign_extend(alu_src_a(7 downto 0), alu_src_a(7), 32);
|
WHEN ALU_SEXT16 => result := '0' & sign_extend(alu_src_a(15 DOWNTO 0), alu_src_a(15), 32);
|
when ALU_SEXT16 => result := '0' & sign_extend(alu_src_a(15 downto 0), alu_src_a(15), 32);
|
WHEN ALU_MUL =>
|
when ALU_MUL =>
|
IF G_USE_HW_MUL = true THEN
|
if G_USE_HW_MUL = true then
|
result := '0' & multiply(alu_src_a, alu_src_b);
|
result := '0' & multiply(alu_src_a, alu_src_b);
|
ELSE
|
else
|
result := (OTHERS => '0');
|
result := (others => '0');
|
END IF;
|
end if;
|
WHEN ALU_BS =>
|
when ALU_BS =>
|
IF G_USE_BARREL = true THEN
|
if G_USE_BARREL = true then
|
result := '0' & shift(alu_src_a, alu_src_b(4 DOWNTO 0), exec_i.imm(10), exec_i.imm(9));
|
result := '0' & shift(alu_src_a, alu_src_b(4 downto 0), exec_i.imm(10), exec_i.imm(9));
|
ELSE
|
else
|
result := (OTHERS => '0');
|
result := (others => '0');
|
END IF;
|
end if;
|
WHEN OTHERS =>
|
when others =>
|
result := (OTHERS => '0');
|
result := (others => '0');
|
REPORT "Invalid ALU operation" SEVERITY FAILURE;
|
report "Invalid ALU operation" severity FAILURE;
|
END CASE;
|
end case;
|
|
|
-- Set carry register
|
-- Set carry register
|
IF exec_i.ctrl_ex.carry_keep = CARRY_KEEP THEN
|
if exec_i.ctrl_ex.carry_keep = CARRY_KEEP then
|
v_reg.carry := reg.carry;
|
v_reg.carry := reg.carry;
|
ELSE
|
else
|
v_reg.carry := result(CFG_DMEM_WIDTH);
|
v_reg.carry := result(CFG_DMEM_WIDTH);
|
END IF;
|
end if;
|
|
|
zero := is_zero(dat_a);
|
zero := is_zero(dat_a);
|
|
|
-- Overwrite branch condition
|
-- Overwrite branch condition
|
IF reg.flush_ex = '1' THEN
|
if reg.flush_ex = '1' then
|
v.branch := '0';
|
v.branch := '0';
|
ELSE
|
else
|
-- Determine branch condition
|
-- Determine branch condition
|
CASE exec_i.ctrl_ex.branch_cond IS
|
case exec_i.ctrl_ex.branch_cond is
|
WHEN BNC => v.branch := '1';
|
when BNC => v.branch := '1';
|
WHEN BEQ => v.branch := zero;
|
when BEQ => v.branch := zero;
|
WHEN BNE => v.branch := NOT zero;
|
when BNE => v.branch := not zero;
|
WHEN BLT => v.branch := dat_a(CFG_DMEM_WIDTH - 1);
|
when BLT => v.branch := dat_a(CFG_DMEM_WIDTH - 1);
|
WHEN BLE => v.branch := dat_a(CFG_DMEM_WIDTH - 1) OR zero;
|
when BLE => v.branch := dat_a(CFG_DMEM_WIDTH - 1) or zero;
|
WHEN BGT => v.branch := NOT (dat_a(CFG_DMEM_WIDTH - 1) OR zero);
|
when BGT => v.branch := not (dat_a(CFG_DMEM_WIDTH - 1) or zero);
|
WHEN BGE => v.branch := NOT dat_a(CFG_DMEM_WIDTH - 1);
|
when BGE => v.branch := not dat_a(CFG_DMEM_WIDTH - 1);
|
WHEN OTHERS => v.branch := '0';
|
when others => v.branch := '0';
|
END CASE;
|
end case;
|
END IF;
|
end if;
|
|
|
-- Handle CMPU
|
-- Handle CMPU
|
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
|
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
|
-- Set MSB
|
-- Set MSB
|
v.alu_result(CFG_DMEM_WIDTH - 1 DOWNTO 0) := (NOT result(CFG_DMEM_WIDTH - 1)) & result(CFG_DMEM_WIDTH - 2 DOWNTO 0);
|
v.alu_result(CFG_DMEM_WIDTH - 1 downto 0) := (not result(CFG_DMEM_WIDTH - 1)) & result(CFG_DMEM_WIDTH - 2 downto 0);
|
ELSE
|
else
|
-- Use ALU result
|
-- Use ALU result
|
v.alu_result := result(CFG_DMEM_WIDTH - 1 DOWNTO 0);
|
v.alu_result := result(CFG_DMEM_WIDTH - 1 downto 0);
|
END IF;
|
end if;
|
|
|
v.program_counter := exec_i.program_counter;
|
v.program_counter := exec_i.program_counter;
|
|
|
-- Determine flush signals
|
-- Determine flush signals
|
v.flush_id := v.branch;
|
v.flush_id := v.branch;
|
v_reg.flush_ex := v.branch AND NOT exec_i.ctrl_ex.delay;
|
v_reg.flush_ex := v.branch and not exec_i.ctrl_ex.delay;
|
|
|
rin <= v;
|
rin <= v;
|
regin <= v_reg;
|
regin <= v_reg;
|
|
|
END PROCESS;
|
end process;
|
|
|
execute_seq: PROCESS(clk_i)
|
execute_seq: process(clk_i)
|
PROCEDURE proc_execute_reset IS
|
procedure proc_execute_reset is
|
BEGIN
|
begin
|
r.alu_result <= (OTHERS => '0');
|
r.alu_result <= (others => '0');
|
r.dat_d <= (OTHERS => '0');
|
r.dat_d <= (others => '0');
|
r.branch <= '0';
|
r.branch <= '0';
|
r.program_counter <= (OTHERS => '0');
|
r.program_counter <= (others => '0');
|
r.flush_id <= '0';
|
r.flush_id <= '0';
|
r.ctrl_mem.mem_write <= '0';
|
r.ctrl_mem.mem_write <= '0';
|
r.ctrl_mem.mem_read <= '0';
|
r.ctrl_mem.mem_read <= '0';
|
r.ctrl_mem.transfer_size <= WORD;
|
r.ctrl_mem.transfer_size <= WORD;
|
r.ctrl_wb.reg_d <= (OTHERS => '0');
|
r.ctrl_wrb.reg_d <= (others => '0');
|
r.ctrl_wb.reg_write <= '0';
|
r.ctrl_wrb.reg_write <= '0';
|
reg.carry <= '0';
|
reg.carry <= '0';
|
reg.flush_ex <= '0';
|
reg.flush_ex <= '0';
|
END PROCEDURE proc_execute_reset;
|
end procedure proc_execute_reset;
|
BEGIN
|
begin
|
IF rising_edge(clk_i) THEN
|
if rising_edge(clk_i) then
|
IF rst_i = '1' THEN
|
if rst_i = '1' then
|
proc_execute_reset;
|
proc_execute_reset;
|
ELSIF ena_i = '1' THEN
|
elsif ena_i = '1' then
|
r <= rin;
|
r <= rin;
|
reg <= regin;
|
reg <= regin;
|
END IF;
|
end if;
|
END IF;
|
end if;
|
END PROCESS;
|
end process;
|
END arch;
|
end arch;
|
|
|
No newline at end of file
|
No newline at end of file
|