1
0
mirror of https://github.com/antonblanchard/microwatt.git synced 2026-02-10 10:10:08 +00:00
Files
antonblanchard.microwatt/multiply_tb.vhdl
Paul Mackerras 374f4c536d writeback: Do data formatting and condition recording in writeback
This adds code to writeback to format data and test the result
against zero for the purpose of setting CR0.  The data formatter
is able to shift and mask by bytes and do byte reversal and sign
extension.  It can also put together bytes from two input
doublewords to support unaligned loads (including unaligned
byte-reversed loads).

The data formatter starts with an 8:1 multiplexer that is able
to direct any byte of the input to any byte of the output.  This
lets us rotate the data and simultaneously byte-reverse it.
The rotated/reversed data goes to a register for the unaligned
cases that overlap two doublewords.  Then there is per-byte logic
that does trimming, sign extension, and splicing together bytes
from a previous input doubleword (stored in data_latched) and the
current doubleword.  Finally the 64-bit result is tested to set
CR0 if rc = 1.

This removes the RC logic from the execute2, multiply and divide
units, and the shift/mask/byte-reverse/sign-extend logic from
loadstore2.

Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
2019-10-15 15:23:28 +11:00

263 lines
7.3 KiB
VHDL

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.glibc_random.all;
use work.ppc_fx_insns.all;
entity multiply_tb is
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 : Decode2ToMultiplyType;
signal m2 : MultiplyToWritebackType;
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);
begin
wait for clk_period;
m1.valid <= '1';
m1.insn_type <= OP_MUL_L64;
m1.write_reg <= "10001";
m1.data1 <= '0' & x"0000000000001000";
m1.data2 <= '0' & x"0000000000001111";
m1.rc <= '0';
wait for clk_period;
assert m2.valid = '0';
m1.valid <= '0';
wait for clk_period;
assert m2.valid = '0';
wait for clk_period;
assert m2.valid = '0';
wait for clk_period;
assert m2.valid = '1';
assert m2.write_reg_enable = '1';
assert m2.write_reg_nr = "10001";
assert m2.write_reg_data = x"0000000001111000";
assert m2.rc = '0';
wait for clk_period;
assert m2.valid = '0';
m1.valid <= '1';
m1.rc <= '1';
wait for clk_period;
assert m2.valid = '0';
m1.valid <= '0';
wait for clk_period * (pipeline_depth-1);
assert m2.valid = '1';
assert m2.write_reg_enable = '1';
assert m2.write_reg_nr = "10001";
assert m2.write_reg_data = x"0000000001111000";
assert m2.rc = '1';
-- test mulld
mulld_loop : for i in 0 to 1000 loop
ra := pseudorand(ra'length);
rb := pseudorand(rb'length);
behave_rt := ppc_mulld(ra, rb);
m1.data1 <= '0' & ra;
m1.data2 <= '0' & rb;
m1.valid <= '1';
m1.insn_type <= OP_MUL_L64;
wait for clk_period;
m1.valid <= '0';
wait for clk_period * (pipeline_depth-1);
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);
end loop;
-- test mulhdu
mulhdu_loop : for i in 0 to 1000 loop
ra := pseudorand(ra'length);
rb := pseudorand(rb'length);
behave_rt := ppc_mulhdu(ra, rb);
m1.data1 <= '0' & ra;
m1.data2 <= '0' & rb;
m1.valid <= '1';
m1.insn_type <= OP_MUL_H64;
wait for clk_period;
m1.valid <= '0';
wait for clk_period * (pipeline_depth-1);
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);
end loop;
-- test mulhd
mulhd_loop : for i in 0 to 1000 loop
ra := pseudorand(ra'length);
rb := pseudorand(rb'length);
behave_rt := ppc_mulhd(ra, rb);
m1.data1 <= ra(63) & ra;
m1.data2 <= rb(63) & rb;
m1.valid <= '1';
m1.insn_type <= OP_MUL_H64;
wait for clk_period;
m1.valid <= '0';
wait for clk_period * (pipeline_depth-1);
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);
end loop;
-- test mullw
mullw_loop : for i in 0 to 1000 loop
ra := pseudorand(ra'length);
rb := pseudorand(rb'length);
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.valid <= '1';
m1.insn_type <= OP_MUL_L64;
wait for clk_period;
m1.valid <= '0';
wait for clk_period * (pipeline_depth-1);
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);
end loop;
-- test mulhw
mulhw_loop : for i in 0 to 1000 loop
ra := pseudorand(ra'length);
rb := pseudorand(rb'length);
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.valid <= '1';
m1.insn_type <= OP_MUL_H32;
wait for clk_period;
m1.valid <= '0';
wait for clk_period * (pipeline_depth-1);
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);
end loop;
-- test mulhwu
mulhwu_loop : for i in 0 to 1000 loop
ra := pseudorand(ra'length);
rb := pseudorand(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.valid <= '1';
m1.insn_type <= OP_MUL_H32;
wait for clk_period;
m1.valid <= '0';
wait for clk_period * (pipeline_depth-1);
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);
end loop;
-- test mulli
mulli_loop : for i in 0 to 1000 loop
ra := pseudorand(ra'length);
si := pseudorand(si'length);
behave_rt := ppc_mulli(ra, si);
m1.data1 <= ra(63) & ra;
m1.data2 <= (others => si(15));
m1.data2(15 downto 0) <= si;
m1.valid <= '1';
m1.insn_type <= OP_MUL_L64;
wait for clk_period;
m1.valid <= '0';
wait for clk_period * (pipeline_depth-1);
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);
end loop;
assert false report "end of test" severity failure;
wait;
end process;
end behave;