@ -14,6 +14,7 @@ entity execute1 is
generic (
generic (
EX1_BYPASS : boolean := true;
EX1_BYPASS : boolean := true;
HAS_FPU : boolean := true;
HAS_FPU : boolean := true;
HAS_SHORT_MULT : boolean := false;
-- Non-zero to enable log data collection
-- Non-zero to enable log data collection
LOG_LENGTH : natural := 0
LOG_LENGTH : natural := 0
);
);
@ -95,6 +96,7 @@ architecture behaviour of execute1 is
signal a_in, b_in, c_in : std_ulogic_vector(63 downto 0);
signal a_in, b_in, c_in : std_ulogic_vector(63 downto 0);
signal cr_in : std_ulogic_vector(31 downto 0);
signal cr_in : std_ulogic_vector(31 downto 0);
signal xerc_in : xer_common_t;
signal xerc_in : xer_common_t;
signal mshort_p : std_ulogic_vector(31 downto 0) := (others => '0');
signal valid_in : std_ulogic;
signal valid_in : std_ulogic;
signal ctrl: ctrl_t := (others => (others => '0'));
signal ctrl: ctrl_t := (others => (others => '0'));
@ -230,6 +232,24 @@ architecture behaviour of execute1 is
return msr_out;
return msr_out;
end;
end;
-- Work out whether a signed value fits into n bits,
-- that is, see if it is in the range -2^(n-1) .. 2^(n-1) - 1
function fits_in_n_bits(val: std_ulogic_vector; n: integer) return boolean is
variable x, xp1: std_ulogic_vector(val'left downto val'right);
begin
x := val;
if val(val'left) = '0' then
x := not val;
end if;
xp1 := bit_reverse(std_ulogic_vector(unsigned(bit_reverse(x)) + 1));
x := x and not xp1;
-- For positive inputs, x has ones at the positions
-- to the left of the leftmost 1 bit in val.
-- For negative inputs, x has ones to the left of
-- the leftmost 0 bit in val.
return x(n - 1) = '1';
end;
-- Tell vivado to keep the hierarchy for the random module so that the
-- Tell vivado to keep the hierarchy for the random module so that the
-- net names in the xdc file match.
-- net names in the xdc file match.
attribute keep_hierarchy : string;
attribute keep_hierarchy : string;
@ -304,6 +324,17 @@ begin
p_out => pmu_to_x
p_out => pmu_to_x
);
);
short_mult_0: if HAS_SHORT_MULT generate
begin
short_mult: entity work.short_multiply
port map (
clk => clk,
a_in => a_in(15 downto 0),
b_in => b_in(15 downto 0),
m_out => mshort_p
);
end generate;
dbg_msr_out <= ctrl.msr;
dbg_msr_out <= ctrl.msr;
log_rd_addr <= r.log_addr_spr;
log_rd_addr <= r.log_addr_spr;
@ -509,7 +540,11 @@ begin
case current.sub_select(1 downto 0) is
case current.sub_select(1 downto 0) is
when "00" =>
when "00" =>
if HAS_SHORT_MULT and r.mul_in_progress = '0' then
muldiv_result <= std_ulogic_vector(resize(signed(mshort_p), 64));
else
muldiv_result <= multiply_to_x.result(63 downto 0);
muldiv_result <= multiply_to_x.result(63 downto 0);
end if;
when "01" =>
when "01" =>
muldiv_result <= multiply_to_x.result(127 downto 64);
muldiv_result <= multiply_to_x.result(127 downto 64);
when "10" =>
when "10" =>
@ -1121,10 +1156,20 @@ begin
icache_inval <= '1';
icache_inval <= '1';
when OP_MUL_L64 | OP_MUL_H64 | OP_MUL_H32 =>
when OP_MUL_L64 | OP_MUL_H64 | OP_MUL_H32 =>
if HAS_SHORT_MULT and e_in.insn_type = OP_MUL_L64 and e_in.insn(26) = '1' and
fits_in_n_bits(a_in, 16) and fits_in_n_bits(b_in, 16) then
-- Operands fit into 16 bits, so use short multiplier
if e_in.oe = '1' then
-- Note 16x16 multiply can't overflow, even for mullwo
set_ov(v.e, '0', '0');
end if;
else
-- Use standard multiplier
v.e.valid := '0';
v.e.valid := '0';
v.mul_in_progress := '1';
v.mul_in_progress := '1';
v.busy := '1';
v.busy := '1';
x_to_multiply.valid <= '1';
x_to_multiply.valid <= '1';
end if;
when OP_DIV | OP_DIVE | OP_MOD =>
when OP_DIV | OP_DIVE | OP_MOD =>
v.e.valid := '0';
v.e.valid := '0';