type Execute1ToMultiplyType is record
valid: std_ulogic;
- insn_type: insn_type_t;
- data1: std_ulogic_vector(64 downto 0);
- data2: std_ulogic_vector(64 downto 0);
+ data1: std_ulogic_vector(63 downto 0);
+ data2: std_ulogic_vector(63 downto 0);
is_32bit: std_ulogic;
+ neg_result: std_ulogic;
end record;
- constant Execute1ToMultiplyInit : Execute1ToMultiplyType := (valid => '0', insn_type => OP_ILLEGAL,
- is_32bit => '0',
+ constant Execute1ToMultiplyInit : Execute1ToMultiplyType := (valid => '0',
+ is_32bit => '0', neg_result => '0',
others => (others => '0'));
type Execute1ToDividerType is record
type MultiplyToExecute1Type is record
valid: std_ulogic;
- write_reg_data: std_ulogic_vector(63 downto 0);
+ result: std_ulogic_vector(127 downto 0);
overflow : std_ulogic;
end record;
constant MultiplyToExecute1Init : MultiplyToExecute1Type := (valid => '0', overflow => '0',
mul_in_progress : std_ulogic;
div_in_progress : std_ulogic;
cntz_in_progress : std_ulogic;
+ slow_op_insn : insn_type_t;
slow_op_dest : gpr_index_t;
slow_op_rc : std_ulogic;
slow_op_oe : std_ulogic;
constant reg_type_init : reg_type :=
(e => Execute1ToWritebackInit, lr_update => '0',
mul_in_progress => '0', div_in_progress => '0', cntz_in_progress => '0',
- slow_op_rc => '0', slow_op_oe => '0', slow_op_xerc => xerc_init,
+ slow_op_insn => OP_ILLEGAL, slow_op_rc => '0', slow_op_oe => '0', slow_op_xerc => xerc_init,
next_lr => (others => '0'), ldst_nia => (others => '0'), others => (others => '0'));
signal r, rin : reg_type;
v.div_in_progress := '0';
v.cntz_in_progress := '0';
- -- signals to multiply unit
- x_to_multiply <= Execute1ToMultiplyInit;
- x_to_multiply.insn_type <= e_in.insn_type;
- x_to_multiply.is_32bit <= e_in.is_32bit;
-
- if e_in.is_32bit = '1' then
- if e_in.is_signed = '1' then
- x_to_multiply.data1 <= (others => a_in(31));
- x_to_multiply.data1(31 downto 0) <= a_in(31 downto 0);
- x_to_multiply.data2 <= (others => b_in(31));
- x_to_multiply.data2(31 downto 0) <= b_in(31 downto 0);
- else
- x_to_multiply.data1 <= '0' & x"00000000" & a_in(31 downto 0);
- x_to_multiply.data2 <= '0' & x"00000000" & b_in(31 downto 0);
- end if;
- else
- if e_in.is_signed = '1' then
- x_to_multiply.data1 <= a_in(63) & a_in;
- x_to_multiply.data2 <= b_in(63) & b_in;
- else
- x_to_multiply.data1 <= '0' & a_in;
- x_to_multiply.data2 <= '0' & b_in;
- end if;
- end if;
-
- -- signals to divide unit
+ -- signals to multiply and divide units
sign1 := '0';
sign2 := '0';
if e_in.is_signed = '1' then
abs2 := - signed(b_in);
end if;
+ x_to_multiply <= Execute1ToMultiplyInit;
+ x_to_multiply.is_32bit <= e_in.is_32bit;
+
x_to_divider <= Execute1ToDividerInit;
x_to_divider.is_signed <= e_in.is_signed;
x_to_divider.is_32bit <= e_in.is_32bit;
if e_in.insn_type = OP_MOD then
x_to_divider.is_modulus <= '1';
end if;
+
+ x_to_multiply.neg_result <= sign1 xor sign2;
x_to_divider.neg_result <= sign1 xor (sign2 and not x_to_divider.is_modulus);
if e_in.is_32bit = '0' then
-- 64-bit forms
+ x_to_multiply.data1 <= std_ulogic_vector(abs1);
+ x_to_multiply.data2 <= std_ulogic_vector(abs2);
if e_in.insn_type = OP_DIVE then
x_to_divider.is_extended <= '1';
end if;
x_to_divider.divisor <= std_ulogic_vector(abs2);
else
-- 32-bit forms
+ x_to_multiply.data1 <= x"00000000" & std_ulogic_vector(abs1(31 downto 0));
+ x_to_multiply.data2 <= x"00000000" & std_ulogic_vector(abs2(31 downto 0));
x_to_divider.is_extended <= '0';
if e_in.insn_type = OP_DIVE then -- extended forms
x_to_divider.dividend <= std_ulogic_vector(abs1(31 downto 0)) & x"00000000";
v.e.valid := '1';
v.e.write_reg := e_in.write_reg;
+ v.slow_op_insn := e_in.insn_type;
v.slow_op_dest := gspr_to_gpr(e_in.write_reg);
v.slow_op_rc := e_in.rc;
v.slow_op_oe := e_in.oe;
if (r.mul_in_progress = '1' and multiply_to_x.valid = '1') or
(r.div_in_progress = '1' and divider_to_x.valid = '1') then
if r.mul_in_progress = '1' then
- result := multiply_to_x.write_reg_data;
- overflow := multiply_to_x.overflow;
+ overflow := '0';
+ case r.slow_op_insn is
+ when OP_MUL_H32 =>
+ result := multiply_to_x.result(63 downto 32) &
+ multiply_to_x.result(63 downto 32);
+ when OP_MUL_H64 =>
+ result := multiply_to_x.result(127 downto 64);
+ when others =>
+ -- i.e. OP_MUL_L64
+ result := multiply_to_x.result(63 downto 0);
+ overflow := multiply_to_x.overflow;
+ end case;
else
result := divider_to_x.write_reg_data;
overflow := divider_to_x.overflow;
library work;
use work.common.all;
-use work.decode_types.all;
entity multiply is
generic (
- PIPELINE_DEPTH : natural := 16
+ PIPELINE_DEPTH : natural := 4
);
port (
clk : in std_logic;
end entity multiply;
architecture behaviour of multiply is
- signal m: Execute1ToMultiplyType;
+ signal m: Execute1ToMultiplyType := Execute1ToMultiplyInit;
type multiply_pipeline_stage is record
valid : std_ulogic;
- insn_type : insn_type_t;
- data : signed(129 downto 0);
+ data : unsigned(127 downto 0);
is_32bit : std_ulogic;
+ neg_res : std_ulogic;
end record;
constant MultiplyPipelineStageInit : multiply_pipeline_stage := (valid => '0',
- insn_type => OP_ILLEGAL,
- is_32bit => '0',
+ is_32bit => '0', neg_res => '0',
data => (others => '0'));
type multiply_pipeline_type is array(0 to PIPELINE_DEPTH-1) of multiply_pipeline_stage;
multiply_1: process(all)
variable v : reg_type;
- variable d : std_ulogic_vector(129 downto 0);
+ variable d : std_ulogic_vector(127 downto 0);
variable d2 : std_ulogic_vector(63 downto 0);
variable ov : std_ulogic;
begin
- v := r;
-
- m_out <= MultiplyToExecute1Init;
-
v.multiply_pipeline(0).valid := m.valid;
- v.multiply_pipeline(0).insn_type := m.insn_type;
- v.multiply_pipeline(0).data := signed(m.data1) * signed(m.data2);
+ v.multiply_pipeline(0).data := unsigned(m.data1) * unsigned(m.data2);
v.multiply_pipeline(0).is_32bit := m.is_32bit;
+ v.multiply_pipeline(0).neg_res := m.neg_result;
loop_0: for i in 1 to PIPELINE_DEPTH-1 loop
v.multiply_pipeline(i) := r.multiply_pipeline(i-1);
end loop;
- d := std_ulogic_vector(v.multiply_pipeline(PIPELINE_DEPTH-1).data);
- ov := '0';
+ if v.multiply_pipeline(PIPELINE_DEPTH-1).neg_res = '0' then
+ d := std_ulogic_vector(v.multiply_pipeline(PIPELINE_DEPTH-1).data);
+ else
+ d := std_ulogic_vector(- signed(v.multiply_pipeline(PIPELINE_DEPTH-1).data));
+ end if;
- -- TODO: Handle overflows
- case_0: case v.multiply_pipeline(PIPELINE_DEPTH-1).insn_type is
- when OP_MUL_L64 =>
- d2 := d(63 downto 0);
- if v.multiply_pipeline(PIPELINE_DEPTH-1).is_32bit = '1' then
- ov := (or d(63 downto 31)) and not (and d(63 downto 31));
- else
- ov := (or d(127 downto 63)) and not (and d(127 downto 63));
- end if;
- when OP_MUL_H32 =>
- d2 := d(63 downto 32) & d(63 downto 32);
- when OP_MUL_H64 =>
- d2 := d(127 downto 64);
- when others =>
- --report "Illegal insn type in multiplier";
- d2 := (others => '0');
- end case;
+ ov := '0';
+ if v.multiply_pipeline(PIPELINE_DEPTH-1).is_32bit = '1' then
+ ov := (or d(63 downto 31)) and not (and d(63 downto 31));
+ else
+ ov := (or d(127 downto 63)) and not (and d(127 downto 63));
+ end if;
- m_out.write_reg_data <= d2;
+ m_out.result <= d;
m_out.overflow <= ov;
-
- if v.multiply_pipeline(PIPELINE_DEPTH-1).valid = '1' then
- m_out.valid <= '1';
- end if;
+ m_out.valid <= v.multiply_pipeline(PIPELINE_DEPTH-1).valid;
rin <= v;
end process;
constant pipeline_depth : integer := 4;
- signal m1 : Execute1ToMultiplyType;
+ signal m1 : Execute1ToMultiplyType := Execute1ToMultiplyInit;
signal m2 : MultiplyToExecute1Type;
+
+ function absval(x: std_ulogic_vector) return std_ulogic_vector is
+ begin
+ if x(x'left) = '1' then
+ return std_ulogic_vector(- signed(x));
+ else
+ return x;
+ end if;
+ end;
+
begin
multiply_0: entity work.multiply
generic map (PIPELINE_DEPTH => pipeline_depth)
wait for clk_period;
m1.valid <= '1';
- m1.insn_type <= OP_MUL_L64;
- m1.data1 <= '0' & x"0000000000001000";
- m1.data2 <= '0' & x"0000000000001111";
+ m1.data1 <= x"0000000000001000";
+ m1.data2 <= x"0000000000001111";
wait for clk_period;
assert m2.valid = '0';
wait for clk_period;
assert m2.valid = '1';
- assert m2.write_reg_data = x"0000000001111000";
+ assert m2.result = x"00000000000000000000000001111000";
wait for clk_period;
assert m2.valid = '0';
wait for clk_period * (pipeline_depth-1);
assert m2.valid = '1';
- assert m2.write_reg_data = x"0000000001111000";
+ assert m2.result = x"00000000000000000000000001111000";
-- test mulld
mulld_loop : for i in 0 to 1000 loop
behave_rt := ppc_mulld(ra, rb);
- m1.data1 <= '0' & ra;
- m1.data2 <= '0' & rb;
+ m1.data1 <= absval(ra);
+ m1.data2 <= absval(rb);
+ m1.neg_result <= ra(63) xor rb(63);
m1.valid <= '1';
- m1.insn_type <= OP_MUL_L64;
wait for clk_period;
assert m2.valid = '1';
- assert to_hstring(behave_rt) = to_hstring(m2.write_reg_data)
- report "bad mulld expected " & to_hstring(behave_rt) & " got " & to_hstring(m2.write_reg_data);
+ assert to_hstring(behave_rt) = to_hstring(m2.result(63 downto 0))
+ report "bad mulld expected " & to_hstring(behave_rt) & " got " & to_hstring(m2.result(63 downto 0));
end loop;
-- test mulhdu
behave_rt := ppc_mulhdu(ra, rb);
- m1.data1 <= '0' & ra;
- m1.data2 <= '0' & rb;
+ m1.data1 <= ra;
+ m1.data2 <= rb;
+ m1.neg_result <= '0';
m1.valid <= '1';
- m1.insn_type <= OP_MUL_H64;
wait for clk_period;
assert m2.valid = '1';
- assert to_hstring(behave_rt) = to_hstring(m2.write_reg_data)
- report "bad mulhdu expected " & to_hstring(behave_rt) & " got " & to_hstring(m2.write_reg_data);
+ assert to_hstring(behave_rt) = to_hstring(m2.result(127 downto 64))
+ report "bad mulhdu expected " & to_hstring(behave_rt) & " got " & to_hstring(m2.result(127 downto 64));
end loop;
-- test mulhd
behave_rt := ppc_mulhd(ra, rb);
- m1.data1 <= ra(63) & ra;
- m1.data2 <= rb(63) & rb;
+ m1.data1 <= absval(ra);
+ m1.data2 <= absval(rb);
+ m1.neg_result <= ra(63) xor rb(63);
m1.valid <= '1';
- m1.insn_type <= OP_MUL_H64;
wait for clk_period;
assert m2.valid = '1';
- assert to_hstring(behave_rt) = to_hstring(m2.write_reg_data)
- report "bad mulhd expected " & to_hstring(behave_rt) & " got " & to_hstring(m2.write_reg_data);
+ assert to_hstring(behave_rt) = to_hstring(m2.result(127 downto 64))
+ report "bad mulhd expected " & to_hstring(behave_rt) & " got " & to_hstring(m2.result(127 downto 64));
end loop;
-- test mullw
behave_rt := ppc_mullw(ra, rb);
- m1.data1 <= (others => ra(31));
- m1.data1(31 downto 0) <= ra(31 downto 0);
- m1.data2 <= (others => rb(31));
- m1.data2(31 downto 0) <= rb(31 downto 0);
+ m1.data1 <= (others => '0');
+ m1.data1(31 downto 0) <= absval(ra(31 downto 0));
+ m1.data2 <= (others => '0');
+ m1.data2(31 downto 0) <= absval(rb(31 downto 0));
+ m1.neg_result <= ra(31) xor rb(31);
m1.valid <= '1';
- m1.insn_type <= OP_MUL_L64;
wait for clk_period;
assert m2.valid = '1';
- assert to_hstring(behave_rt) = to_hstring(m2.write_reg_data)
- report "bad mullw expected " & to_hstring(behave_rt) & " got " & to_hstring(m2.write_reg_data);
+ assert to_hstring(behave_rt) = to_hstring(m2.result(63 downto 0))
+ report "bad mullw expected " & to_hstring(behave_rt) & " got " & to_hstring(m2.result(63 downto 0));
end loop;
-- test mulhw
behave_rt := ppc_mulhw(ra, rb);
- m1.data1 <= (others => ra(31));
- m1.data1(31 downto 0) <= ra(31 downto 0);
- m1.data2 <= (others => rb(31));
- m1.data2(31 downto 0) <= rb(31 downto 0);
+ m1.data1 <= (others => '0');
+ m1.data1(31 downto 0) <= absval(ra(31 downto 0));
+ m1.data2 <= (others => '0');
+ m1.data2(31 downto 0) <= absval(rb(31 downto 0));
+ m1.neg_result <= ra(31) xor rb(31);
m1.valid <= '1';
- m1.insn_type <= OP_MUL_H32;
wait for clk_period;
assert m2.valid = '1';
- assert to_hstring(behave_rt) = to_hstring(m2.write_reg_data)
- report "bad mulhw expected " & to_hstring(behave_rt) & " got " & to_hstring(m2.write_reg_data);
+ assert to_hstring(behave_rt) = to_hstring(m2.result(63 downto 32) & m2.result(63 downto 32))
+ report "bad mulhw expected " & to_hstring(behave_rt) & " got " &
+ to_hstring(m2.result(63 downto 32) & m2.result(63 downto 32));
end loop;
-- test mulhwu
m1.data1(31 downto 0) <= ra(31 downto 0);
m1.data2 <= (others => '0');
m1.data2(31 downto 0) <= rb(31 downto 0);
+ m1.neg_result <= '0';
m1.valid <= '1';
- m1.insn_type <= OP_MUL_H32;
wait for clk_period;
assert m2.valid = '1';
- assert to_hstring(behave_rt) = to_hstring(m2.write_reg_data)
- report "bad mulhwu expected " & to_hstring(behave_rt) & " got " & to_hstring(m2.write_reg_data);
+ assert to_hstring(behave_rt) = to_hstring(m2.result(63 downto 32) & m2.result(63 downto 32))
+ report "bad mulhwu expected " & to_hstring(behave_rt) & " got " &
+ to_hstring(m2.result(63 downto 32) & m2.result(63 downto 32));
end loop;
-- test mulli
behave_rt := ppc_mulli(ra, si);
- m1.data1 <= ra(63) & ra;
- m1.data2 <= (others => si(15));
- m1.data2(15 downto 0) <= si;
+ m1.data1 <= absval(ra);
+ m1.data2 <= (others => '0');
+ m1.data2(15 downto 0) <= absval(si);
+ m1.neg_result <= ra(63) xor si(15);
m1.valid <= '1';
- m1.insn_type <= OP_MUL_L64;
wait for clk_period;
assert m2.valid = '1';
- assert to_hstring(behave_rt) = to_hstring(m2.write_reg_data)
- report "bad mulli expected " & to_hstring(behave_rt) & " got " & to_hstring(m2.write_reg_data);
+ assert to_hstring(behave_rt) = to_hstring(m2.result(63 downto 0))
+ report "bad mulli expected " & to_hstring(behave_rt) & " got " & to_hstring(m2.result(63 downto 0));
end loop;
std.env.finish;