aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTristan Gingold <tgingold@free.fr>2020-02-01 11:22:08 +0100
committerTristan Gingold <tgingold@free.fr>2020-02-01 11:22:08 +0100
commit1fe0dce8f25255bcf9a3a3cfe317f763f1e410ce (patch)
tree4c8b724922c40afe9492c559d7ba93e2d68b6c81
parent579d59ed60396da77f015da6e86fce80c53dbeda (diff)
downloadghdl-1fe0dce8f25255bcf9a3a3cfe317f763f1e410ce.tar.gz
ghdl-1fe0dce8f25255bcf9a3a3cfe317f763f1e410ce.tar.bz2
ghdl-1fe0dce8f25255bcf9a3a3cfe317f763f1e410ce.zip
testsuite/synth: add tests for #1122
-rw-r--r--testsuite/synth/issue1122/mult.vhd174
-rw-r--r--testsuite/synth/issue1122/mult_pkg.vhd115
-rw-r--r--testsuite/synth/issue1122/repro.vhdl62
-rw-r--r--testsuite/synth/issue1122/repro2.vhdl22
-rwxr-xr-xtestsuite/synth/issue1122/testsuite.sh15
5 files changed, 388 insertions, 0 deletions
diff --git a/testsuite/synth/issue1122/mult.vhd b/testsuite/synth/issue1122/mult.vhd
new file mode 100644
index 000000000..da115faab
--- /dev/null
+++ b/testsuite/synth/issue1122/mult.vhd
@@ -0,0 +1,174 @@
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+use work.mult_pkg.all;
+
+entity mult is port (
+ clk : in std_logic;
+ rst : in std_logic;
+ slot : in std_logic;
+ a : in mult_i_t;
+ y : out mult_o_t);
+end mult;
+
+architecture stru of mult is
+ signal this_c : mult_reg_t;
+ signal this_r : mult_reg_t := MULT_RESET;
+
+ begin
+ mult : process(this_r, slot, a)
+ variable this : mult_reg_t;
+ variable aa : std_logic_vector(31 downto 0);
+ variable ah : std_logic_vector(30 downto 0);
+ variable bh : std_logic_vector(15 downto 0);
+ variable abh2 : std_logic_vector(32 downto 0);
+ variable p2 : std_logic_vector(31 downto 0);
+ variable p3 : std_logic_vector(31 downto 0);
+ variable sgn : std_logic_vector(31 downto 0);
+ variable pm : std_logic_vector(47 downto 0);
+ variable c : std_logic_vector(63 downto 0);
+ variable acc : std_logic_vector(63 downto 0);
+ variable region: std_logic_vector(2 downto 0);
+ variable sat : std_logic;
+ variable code : mult_codeline_t;
+ begin
+ this := this_r;
+
+ code := MULT_CODE(this.state);
+ y.busy <= code.busy; -- FIXME: warning : combinatorial output
+
+ -- operand intermediates, multiplier and input mux, lower 31bits of A and upper/lower 16bits of B
+ aa := this.m1;
+ if code.sela = MB then aa := this.mb; end if;
+
+ ah := aa(30 downto 0);
+ if code.size = B16 then ah(30 downto 15) := (others => '0'); end if;
+
+ bh := this.m2(15 downto 0);
+ if code.size = B16 then bh(15) := '0';
+ elsif code.shift = '1' then bh := '0' & this.m2(30 downto 16); end if;
+
+ -- partial product adder input mux
+ if code.size = B16 then abh2 := '0' & x"0000" & (aa(15) and this.m2(15)) & this.abh(29 downto 15);
+ elsif this.shift = '0' then abh2 := '0' & this.abh(46 downto 15);
+ else abh2 := '0' & (aa(31) and this.m2(31)) & this.abh(45 downto 15); end if;
+
+ -- partial products adders
+ p2 := (others => '0');
+ if aa(31) = '1' and code.shift = '1' then p2 := '0' & this.m2(30 downto 0); end if;
+ if aa(15) = '1' and code.size = B16 then p2 := x"0000" & '0' & this.m2(14 downto 0); end if;
+
+ p3 := (others => '0');
+ if this.m2(31) = '1' and code.shift = '1' then p3 := '0' & aa(30 downto 0); end if;
+ if this.m2(15) = '1' and code.size = B16 then p3 := x"0000" & '0' & aa(14 downto 0); end if;
+
+ if code.sign = 1 then sgn := (others => '1'); else sgn := (others => '0'); end if;
+ pm := std_logic_vector(unsigned(abh2) + unsigned(sgn(0) & (this.p23 xor sgn)) + code.sign) & this.abh(14 downto 0);
+
+ this.p23 := std_logic_vector(unsigned(p2) + unsigned(p3));
+
+ if this.shift = '0' then
+ if pm(47) = '1' and code.size = B16 then c := x"ffff" & pm;
+ else c := x"0000" & pm; end if;
+ else c := pm & x"0000";
+ end if;
+
+ -- accumulator
+ acc := std_logic_vector(unsigned(c) + unsigned((this.mach and to_slv(code.use_h, 32)) & this.macl));
+
+ -- saturate
+ sat := '1'; region := (others => '0');
+ case this.result_op is
+ when IDENTITY => sat := '0';
+
+ when SATURATE64 =>
+ if acc(63) = '0' and acc(62 downto 47) /= x"0000" then region(0) := '1';
+ elsif acc(63) = '1' and acc(62 downto 47) /= x"ffff" then region(0) := '1'; end if;
+
+ region(2 downto 1) := this.mach(31) & acc(63);
+
+ if c(63) = '0' then
+ case region is
+ when "001" | "010" | "011" | "101" => acc := P48MAX;
+ when "111" => acc := N48MAX;
+ when others => sat := '0';
+ end case;
+ else
+ case region is
+ when "001" => acc := P48MAX;
+ when "011" | "100" | "101" | "111" => acc := N48MAX;
+ when others => sat := '0';
+ end case;
+ end if;
+
+ when SATURATE32 =>
+ region := this.macl(31) & acc(31) & '0';
+ if c(31) = '0' then
+ case (region) is
+ when "010" => acc := P32MAX;
+ when others => sat := '0';
+ end case;
+ else
+ case (region) is
+ when "100" => acc := N32MAX;
+ when others => sat := '0';
+ end case;
+ end if;
+ end case;
+
+ -- multiplier
+ this.abh := std_logic_vector(unsigned(ah) * unsigned(bh));
+
+ -- load the internal registers from the CPU
+ if slot = '1' then
+ if a.command /= NOP then
+ this.m2 := a.in2;
+ if a.command = MACL or a.command = MACW then this.mb := this.m1; end if;
+ end if;
+
+ if a.wr_m1 = '1' then this.m1 := a.in1; end if;
+ end if;
+
+ if slot = '1' and a.wr_mach = '1' then this.mach := a.in1;
+ elsif slot = '1' and (a.command = DMULSL or a.command = DMULUL) then this.mach := x"00000000";
+ elsif this.state = MACWS1 and sat = '1' then this.mach := this.mach or x"00000001";
+ elsif code.mach_en = '1' then this.mach := acc(63 downto 32);
+ end if;
+
+ if slot = '1' and a.wr_macl = '1' then this.macl := a.in2;
+ elsif slot = '1' and a.command /= NOP and a.command /= MACL and a.command /= MACW then this.macl := x"00000000";
+ elsif code.macl_en = '1' then this.macl := acc(31 downto 0);
+ end if;
+
+ -- delayed versions of the control signals to delay for p23 pipeline register
+ this.state := code.state;
+ this.shift := code.shift;
+
+ -- load the command from the CPU
+ if code.busy = '0' and slot = '1' then
+ this.result_op := IDENTITY;
+ this.state := a.command;
+
+ if a.command = MACL then
+ if a.s = '1' then this.result_op := SATURATE64; end if;
+ elsif a.command = MACW then -- override start state, MACWS and MACW set different busy and mach_en values
+ if a.s = '1' then this.result_op := SATURATE32; this.state := MACWS; end if;
+ end if;
+ end if;
+
+ this_c <= this;
+ end process;
+
+ mult_r0 : process(clk, rst)
+ begin
+ if rst='1' then
+ this_r <= MULT_RESET;
+ elsif clk='1' and clk'event then
+ this_r <= this_c;
+ end if;
+ end process;
+
+ -- drive the outputs
+ y.mach <= this_r.mach;
+ y.macl <= this_r.macl;
+end stru;
diff --git a/testsuite/synth/issue1122/mult_pkg.vhd b/testsuite/synth/issue1122/mult_pkg.vhd
new file mode 100644
index 000000000..88dac9c7b
--- /dev/null
+++ b/testsuite/synth/issue1122/mult_pkg.vhd
@@ -0,0 +1,115 @@
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+package mult_pkg is
+ type mult_state_t is (NOP, DMULSL, DMULSL1, DMULSL2, DMULUL, DMULUL1, DMULUL2, MACL, MACL1, MACL2, MACW, MACW1, MACWS, MACWS1, MULL, MULL1, MULL2, MULSW, MULSW1, MULUW, MULUW1);
+ type mult_result_op_t is (IDENTITY, SATURATE32, SATURATE64);
+ type mult_sela_t is ( M1, MB );
+
+ type mult_size_t is ( B16, B32 );
+ constant P48MAX : std_logic_vector(63 downto 0) := x"00007fffffffffff";
+ constant N48MAX : std_logic_vector(63 downto 0) := x"ffff800000000000";
+ constant P32MAX : std_logic_vector(63 downto 0) := x"000000007fffffff";
+ constant N32MAX : std_logic_vector(63 downto 0) := x"ffffffff80000000";
+
+ type mult_codeline_t is record
+ state : mult_state_t;
+ busy : std_logic;
+ sela : mult_sela_t;
+ shift : std_logic;
+ sign : integer range 0 to 1;
+ size : mult_size_t;
+ mach_en : std_logic;
+ macl_en : std_logic;
+ use_h : std_logic;
+ end record;
+
+ type mult_microcode_t is array (mult_state_t) of mult_codeline_t;
+
+ constant MULT_CODE : mult_microcode_t := (
+-- state busy sela shft sign size h_en l_en use_h
+ ( NOP, '0', M1, '0', 0, B16, '0', '0', '1' ), -- NOP
+ ( DMULSL1, '1', M1, '0', 1, B32, '0', '0', '1' ), -- DMULSL
+ ( DMULSL2, '1', M1, '1', 1, B32, '1', '1', '1' ), -- DMULSL1
+ ( NOP, '0', M1, '1', 1, B32, '1', '1', '1' ), -- DMULSL2
+ ( DMULUL1, '1', M1, '0', 0, B32, '0', '0', '1' ), -- DMULUL
+ ( DMULUL2, '1', M1, '1', 0, B32, '1', '1', '1' ), -- DMULUL1
+ ( NOP, '0', M1, '1', 0, B32, '1', '1', '1' ), -- DMULUL2
+ ( MACL1, '1', MB, '0', 1, B32, '0', '0', '1' ), -- MACL
+ ( MACL2, '1', MB, '1', 1, B32, '1', '1', '1' ), -- MACL1
+ ( NOP, '0', MB, '1', 1, B32, '1', '1', '1' ), -- MACL2
+ ( MACW1, '1', M1, '0', 1, B16, '0', '0', '1' ), -- MACW
+ ( NOP, '0', M1, '0', 1, B16, '1', '1', '1' ), -- MACW1
+ ( MACWS1, '1', M1, '0', 1, B16, '0', '0', '0' ), -- MACWS
+ ( NOP, '0', M1, '0', 1, B16, '0', '1', '0' ), -- MACWS1
+ ( MULL1, '1', M1, '0', 1, B32, '0', '0', '0' ), -- MULL
+ ( MULL2, '1', M1, '1', 1, B32, '0', '1', '0' ), -- MULL1
+ ( NOP, '0', M1, '1', 1, B32, '0', '1', '0' ), -- MULL2
+ ( MULSW1, '1', M1, '0', 1, B16, '0', '0', '0' ), -- MULSW
+ ( NOP, '0', M1, '0', 1, B16, '0', '1', '0' ), -- MULSW1
+ ( MULUW1, '1', M1, '0', 0, B16, '0', '0', '0' ), -- MULUW
+ ( NOP, '0', M1, '0', 0, B16, '0', '1', '0' ) -- MULUW1
+ );
+
+ type mult_i_t is record
+ wr_m1 : std_logic;
+ command : mult_state_t;
+ s : std_logic;
+ wr_mach : std_logic;
+ wr_macl : std_logic;
+ in1 : std_logic_vector(31 downto 0);
+ in2 : std_logic_vector(31 downto 0);
+ end record;
+
+ type mult_o_t is record
+ mach : std_logic_vector(31 downto 0);
+ macl : std_logic_vector(31 downto 0);
+ busy : std_logic;
+ end record;
+
+ type mult_reg_t is record
+ state : mult_state_t;
+ result_op : mult_result_op_t;
+ m1, m2, mb : std_logic_vector(31 downto 0);
+ p23 : std_logic_vector(31 downto 0);
+ mach, macl : std_logic_vector(31 downto 0);
+ shift : std_logic;
+ abh : std_logic_vector(46 downto 0);
+ end record;
+
+ constant MULT_RESET : mult_reg_t := (state => NOP,
+ result_op => IDENTITY,
+ m1 => (others => '0'),
+ m2 => (others => '0'),
+ mb => (others => '0'),
+ p23 => (others => '0'),
+ mach => (others => '0'),
+ macl => (others => '0'),
+ shift => '0',
+ abh => (others => '0')
+ );
+
+ component mult is
+
+ port (
+ clk : in std_logic;
+ rst : in std_logic;
+ slot : in std_logic;
+ a : in mult_i_t;
+ y : out mult_o_t);
+ end component mult;
+
+ function to_slv(b : std_logic; s : integer) return std_logic_vector;
+end package;
+
+package body mult_pkg is
+
+ function to_slv(b : std_logic; s : integer) return std_logic_vector is
+ variable r : std_logic_vector(s-1 downto 0);
+ begin
+ r := (others => b);
+ return r;
+ end function to_slv;
+
+end package body;
diff --git a/testsuite/synth/issue1122/repro.vhdl b/testsuite/synth/issue1122/repro.vhdl
new file mode 100644
index 000000000..a0dfd78ea
--- /dev/null
+++ b/testsuite/synth/issue1122/repro.vhdl
@@ -0,0 +1,62 @@
+entity repro is
+ port (clk : bit;
+ rst : bit;
+ d : bit_vector (7 downto 0);
+ q : out bit_vector (7 downto 0));
+end repro;
+
+architecture behav of repro is
+ constant c : bit_vector (7 downto 0) := x"7e";
+ signal s : bit_vector (7 downto 0) := c;
+begin
+ process (clk)
+ begin
+ if rst = '1' then
+ s <= c;
+ elsif clk = '1' and clk'event then
+ s <= d;
+ end if;
+ end process;
+
+ q <= s;
+end behav;
+
+-- For this design:
+-- %3:$o[8]{n7w8} := 8'uh7e
+-- \s:$o[8]{n8w8} := $isignal{i7} (
+-- .$i: %8:$o[8]{n12w8} := $mux2{i11} (
+-- .$s: \rst{n2w1},
+-- .$i0: %7:$o[8]{n11w8} := $mux2{i10} (
+-- .$s: %6:$o{n10w1} := $edge{i9} (
+-- .$i: \clk{n1w1}),
+-- .$i0: \s:$o{n8w8},
+-- .$i1: \d{n3w8}),
+-- .$i1: %3:$o{n7w8}),
+-- .$init: %3:$o{n7w8})
+-- \q := \s:$o{n8w8}
+
+-- For repro2:
+-- \s:$o{n8w1} := $isignal{i7} (
+-- .$i: %9:$o{n13w1} := $mux2{i12} (
+-- .$s: \rst{n2w1},
+-- .$i0: %8:$o{n12w1} := $mux2{i11} (
+-- .$s: %7:$o{n11w1} := $edge{i10} (
+-- .$i: \clk{n1w1}),
+-- .$i0: \s:$o{n8w1},
+-- .$i1: \d{n3w1}),
+-- .$i1: %6:$o{n10w1} := 1'uh1),
+-- .$init: %3:$o{n7w1} := 1'uh1)
+-- \q := \s:$o{n8w1}
+
+-->
+
+-- %3:$o{n7w1} := 1'uh1
+-- \s:$o{n8w1} := $isignal{i7} (
+-- .$i: %10:$q{n14w1} := $iadff{i13} (
+-- .$clk: \clk{n1w1},
+-- .$d: \d{n3w1},
+-- .$rst: \rst{n2w1},
+-- .$rst_val: %6:$o{n10w1} := 1'uh1,
+-- .$init: %3:$o{n7w1}),
+-- .$init: %3:$o{n7w1})
+-- \q := \s:$o{n8w1}
diff --git a/testsuite/synth/issue1122/repro2.vhdl b/testsuite/synth/issue1122/repro2.vhdl
new file mode 100644
index 000000000..7492e36c9
--- /dev/null
+++ b/testsuite/synth/issue1122/repro2.vhdl
@@ -0,0 +1,22 @@
+entity repro2 is
+ port (clk : bit;
+ rst : bit;
+ d : bit;
+ q : out bit);
+end repro2;
+
+architecture behav of repro2 is
+ constant c : bit := '1';
+ signal s : bit := c;
+begin
+ process (clk)
+ begin
+ if rst = '1' then
+ s <= c;
+ elsif clk = '1' and clk'event then
+ s <= d;
+ end if;
+ end process;
+
+ q <= s;
+end behav;
diff --git a/testsuite/synth/issue1122/testsuite.sh b/testsuite/synth/issue1122/testsuite.sh
new file mode 100755
index 000000000..ad74b19cc
--- /dev/null
+++ b/testsuite/synth/issue1122/testsuite.sh
@@ -0,0 +1,15 @@
+#! /bin/sh
+
+. ../../testenv.sh
+
+synth mult.vhd mult_pkg.vhd -e > syn_mult.vhdl
+analyze mult_pkg.vhd syn_mult.vhdl
+clean
+
+for t in repro repro2; do
+ synth $t.vhdl -e $t > syn_$t.vhdl
+ analyze syn_$t.vhdl
+ clean
+done
+
+echo "Test successful"