|
|
|
library vunit_lib;
|
|
|
|
context vunit_lib.vunit_context;
|
|
|
|
|
|
|
|
library ieee;
|
|
|
|
use ieee.std_logic_1164.all;
|
|
|
|
use ieee.numeric_std.all;
|
|
|
|
|
|
|
|
library work;
|
|
|
|
use work.decode_types.all;
|
|
|
|
use work.common.all;
|
|
|
|
use work.ppc_fx_insns.all;
|
|
|
|
|
|
|
|
library osvvm;
|
|
|
|
use osvvm.RandomPkg.all;
|
|
|
|
|
|
|
|
entity multiply_tb is
|
|
|
|
generic (runner_cfg : string := runner_cfg_default);
|
|
|
|
end multiply_tb;
|
|
|
|
|
|
|
|
architecture behave of multiply_tb is
|
|
|
|
signal clk : std_ulogic;
|
|
|
|
constant clk_period : time := 10 ns;
|
|
|
|
|
|
|
|
constant pipeline_depth : integer := 4;
|
|
|
|
|
|
|
|
signal m1 : MultiplyInputType := MultiplyInputInit;
|
|
|
|
signal m2 : MultiplyOutputType;
|
|
|
|
|
|
|
|
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)
|
|
|
|
port map (clk => clk, m_in => m1, m_out => m2);
|
|
|
|
|
|
|
|
clk_process: process
|
|
|
|
begin
|
|
|
|
clk <= '0';
|
|
|
|
wait for clk_period/2;
|
|
|
|
clk <= '1';
|
|
|
|
wait for clk_period/2;
|
|
|
|
end process;
|
|
|
|
|
|
|
|
stim_process: process
|
|
|
|
variable ra, rb, rt, behave_rt: std_ulogic_vector(63 downto 0);
|
|
|
|
variable si: std_ulogic_vector(15 downto 0);
|
|
|
|
variable sign: std_ulogic;
|
|
|
|
variable rnd : RandomPType;
|
|
|
|
begin
|
|
|
|
rnd.InitSeed(stim_process'path_name);
|
|
|
|
|
|
|
|
test_runner_setup(runner, runner_cfg);
|
|
|
|
|
|
|
|
while test_suite loop
|
|
|
|
if run("Test interface") then
|
|
|
|
wait for clk_period;
|
|
|
|
|
|
|
|
m1.valid <= '1';
|
|
|
|
m1.data1 <= x"0000000000001000";
|
|
|
|
m1.data2 <= x"0000000000001111";
|
|
|
|
|
|
|
|
wait for clk_period;
|
|
|
|
check_false(?? m2.valid, result("for valid"));
|
|
|
|
|
|
|
|
m1.valid <= '0';
|
|
|
|
|
|
|
|
wait for clk_period;
|
|
|
|
check_false(?? m2.valid, result("for valid"));
|
|
|
|
|
|
|
|
wait for clk_period;
|
|
|
|
check_false(?? m2.valid, result("for valid"));
|
|
|
|
|
|
|
|
wait for clk_period;
|
|
|
|
check_true(?? m2.valid, result("for valid"));
|
|
|
|
check_equal(m2.result, 16#1111000#);
|
|
|
|
|
|
|
|
wait for clk_period;
|
|
|
|
check_false(?? m2.valid, result("for valid"));
|
|
|
|
|
|
|
|
m1.valid <= '1';
|
|
|
|
|
|
|
|
wait for clk_period;
|
|
|
|
check_false(?? m2.valid, result("for valid"));
|
|
|
|
|
|
|
|
m1.valid <= '0';
|
|
|
|
|
|
|
|
wait for clk_period * (pipeline_depth-1);
|
|
|
|
check_true(?? m2.valid, result("for valid"));
|
|
|
|
check_equal(m2.result, 16#1111000#);
|
|
|
|
|
|
|
|
elsif run("Test mulld") then
|
|
|
|
mulld_loop : for i in 0 to 1000 loop
|
|
|
|
ra := rnd.RandSlv(ra'length);
|
|
|
|
rb := rnd.RandSlv(rb'length);
|
|
|
|
|
|
|
|
behave_rt := ppc_mulld(ra, rb);
|
|
|
|
|
|
|
|
m1.data1 <= absval(ra);
|
|
|
|
m1.data2 <= absval(rb);
|
|
|
|
sign := ra(63) xor rb(63);
|
|
|
|
m1.not_result <= sign;
|
|
|
|
m1.addend <= (others => sign);
|
|
|
|
m1.valid <= '1';
|
|
|
|
|
|
|
|
wait for clk_period;
|
|
|
|
|
|
|
|
m1.valid <= '0';
|
|
|
|
|
|
|
|
wait for clk_period * (pipeline_depth-1);
|
|
|
|
|
|
|
|
check_true(?? m2.valid, result("for valid"));
|
|
|
|
check_equal(m2.result(63 downto 0), behave_rt, result("for mulld " & to_hstring(behave_rt)));
|
|
|
|
end loop;
|
|
|
|
|
|
|
|
elsif run("Test mulhdu") then
|
|
|
|
mulhdu_loop : for i in 0 to 1000 loop
|
|
|
|
ra := rnd.RandSlv(ra'length);
|
|
|
|
rb := rnd.RandSlv(rb'length);
|
|
|
|
|
|
|
|
behave_rt := ppc_mulhdu(ra, rb);
|
|
|
|
|
|
|
|
m1.data1 <= ra;
|
|
|
|
m1.data2 <= rb;
|
|
|
|
m1.not_result <= '0';
|
|
|
|
m1.addend <= (others => '0');
|
|
|
|
m1.valid <= '1';
|
|
|
|
|
|
|
|
wait for clk_period;
|
|
|
|
|
|
|
|
m1.valid <= '0';
|
|
|
|
|
|
|
|
wait for clk_period * (pipeline_depth-1);
|
|
|
|
|
|
|
|
check_true(?? m2.valid, result("for valid"));
|
|
|
|
check_equal(m2.result(127 downto 64), behave_rt, result("for mulhdu " & to_hstring(behave_rt)));
|
|
|
|
end loop;
|
|
|
|
|
|
|
|
elsif run("Test mulhd") then
|
|
|
|
mulhd_loop : for i in 0 to 1000 loop
|
|
|
|
ra := rnd.RandSlv(ra'length);
|
|
|
|
rb := rnd.RandSlv(rb'length);
|
|
|
|
|
|
|
|
behave_rt := ppc_mulhd(ra, rb);
|
|
|
|
|
|
|
|
m1.data1 <= absval(ra);
|
|
|
|
m1.data2 <= absval(rb);
|
|
|
|
sign := ra(63) xor rb(63);
|
|
|
|
m1.not_result <= sign;
|
|
|
|
m1.addend <= (others => sign);
|
|
|
|
m1.valid <= '1';
|
|
|
|
|
|
|
|
wait for clk_period;
|
|
|
|
|
|
|
|
m1.valid <= '0';
|
|
|
|
|
|
|
|
wait for clk_period * (pipeline_depth-1);
|
|
|
|
|
|
|
|
check_true(?? m2.valid, result("for valid"));
|
|
|
|
check_equal(m2.result(127 downto 64), behave_rt, result("for mulhd " & to_hstring(behave_rt)));
|
|
|
|
end loop;
|
|
|
|
|
|
|
|
elsif run("Test mullw") then
|
|
|
|
mullw_loop : for i in 0 to 1000 loop
|
|
|
|
ra := rnd.RandSlv(ra'length);
|
|
|
|
rb := rnd.RandSlv(rb'length);
|
|
|
|
|
|
|
|
behave_rt := ppc_mullw(ra, rb);
|
|
|
|
|
|
|
|
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));
|
|
|
|
sign := ra(31) xor rb(31);
|
|
|
|
m1.not_result <= sign;
|
|
|
|
m1.addend <= (others => sign);
|
|
|
|
m1.valid <= '1';
|
|
|
|
|
|
|
|
wait for clk_period;
|
|
|
|
|
|
|
|
m1.valid <= '0';
|
|
|
|
|
|
|
|
wait for clk_period * (pipeline_depth-1);
|
|
|
|
|
|
|
|
check_true(?? m2.valid, result("for valid"));
|
|
|
|
check_equal(m2.result(63 downto 0), behave_rt, result("for mullw " & to_hstring(behave_rt)));
|
|
|
|
end loop;
|
|
|
|
|
|
|
|
elsif run("Test mulhw") then
|
|
|
|
mulhw_loop : for i in 0 to 1000 loop
|
|
|
|
ra := rnd.RandSlv(ra'length);
|
|
|
|
rb := rnd.RandSlv(rb'length);
|
|
|
|
|
|
|
|
behave_rt := ppc_mulhw(ra, rb);
|
|
|
|
|
|
|
|
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));
|
|
|
|
sign := ra(31) xor rb(31);
|
|
|
|
m1.not_result <= sign;
|
|
|
|
m1.addend <= (others => sign);
|
|
|
|
m1.valid <= '1';
|
|
|
|
|
|
|
|
wait for clk_period;
|
|
|
|
|
|
|
|
m1.valid <= '0';
|
|
|
|
|
|
|
|
wait for clk_period * (pipeline_depth-1);
|
|
|
|
|
|
|
|
check_true(?? m2.valid, result("for valid"));
|
|
|
|
check_equal(m2.result(63 downto 32) & m2.result(63 downto 32), behave_rt, result("for mulhw " & to_hstring(behave_rt)));
|
|
|
|
end loop;
|
|
|
|
|
|
|
|
elsif run("Test mulhwu") then
|
|
|
|
mulhwu_loop : for i in 0 to 1000 loop
|
|
|
|
ra := rnd.RandSlv(ra'length);
|
|
|
|
rb := rnd.RandSlv(rb'length);
|
|
|
|
|
|
|
|
behave_rt := ppc_mulhwu(ra, rb);
|
|
|
|
|
|
|
|
m1.data1 <= (others => '0');
|
|
|
|
m1.data1(31 downto 0) <= ra(31 downto 0);
|
|
|
|
m1.data2 <= (others => '0');
|
|
|
|
m1.data2(31 downto 0) <= rb(31 downto 0);
|
|
|
|
m1.not_result <= '0';
|
|
|
|
m1.addend <= (others => '0');
|
|
|
|
m1.valid <= '1';
|
|
|
|
|
|
|
|
wait for clk_period;
|
|
|
|
|
|
|
|
m1.valid <= '0';
|
|
|
|
|
|
|
|
wait for clk_period * (pipeline_depth-1);
|
|
|
|
|
|
|
|
check_true(?? m2.valid, result("for valid"));
|
|
|
|
check_equal(m2.result(63 downto 32) & m2.result(63 downto 32), behave_rt, result("for mulhwu " & to_hstring(behave_rt)));
|
|
|
|
end loop;
|
|
|
|
|
|
|
|
elsif run("Test mulli") then
|
|
|
|
mulli_loop : for i in 0 to 1000 loop
|
|
|
|
ra := rnd.RandSlv(ra'length);
|
|
|
|
si := rnd.RandSlv(si'length);
|
|
|
|
|
|
|
|
behave_rt := ppc_mulli(ra, si);
|
|
|
|
|
|
|
|
m1.data1 <= absval(ra);
|
|
|
|
m1.data2 <= (others => '0');
|
|
|
|
m1.data2(15 downto 0) <= absval(si);
|
|
|
|
sign := ra(63) xor si(15);
|
|
|
|
m1.not_result <= sign;
|
|
|
|
m1.addend <= (others => sign);
|
|
|
|
m1.valid <= '1';
|
|
|
|
|
|
|
|
wait for clk_period;
|
|
|
|
|
|
|
|
m1.valid <= '0';
|
|
|
|
|
|
|
|
wait for clk_period * (pipeline_depth-1);
|
|
|
|
|
|
|
|
check_true(?? m2.valid, result("for valid"));
|
|
|
|
check_equal(m2.result(63 downto 0), behave_rt, result("for mulli " & to_hstring(behave_rt)));
|
|
|
|
end loop;
|
|
|
|
end if;
|
|
|
|
end loop;
|
|
|
|
|
|
|
|
test_runner_cleanup(runner);
|
|
|
|
wait;
|
|
|
|
end process;
|
|
|
|
end behave;
|