aboutsummaryrefslogtreecommitdiffstats
path: root/testsuite/gna/issue1655
diff options
context:
space:
mode:
Diffstat (limited to 'testsuite/gna/issue1655')
-rw-r--r--testsuite/gna/issue1655/absenc_master.vhdl607
-rw-r--r--testsuite/gna/issue1655/absenc_master_endat.vhdl314
-rw-r--r--testsuite/gna/issue1655/absenc_pkg.vhdl776
-rw-r--r--testsuite/gna/issue1655/absenc_utils.vhdl239
-rw-r--r--testsuite/gna/issue1655/endat_tb.vhdl130
-rw-r--r--testsuite/gna/issue1655/repro.vhdl24
-rw-r--r--testsuite/gna/issue1655/repro1.vhdl25
-rwxr-xr-xtestsuite/gna/issue1655/testsuite.sh16
8 files changed, 2131 insertions, 0 deletions
diff --git a/testsuite/gna/issue1655/absenc_master.vhdl b/testsuite/gna/issue1655/absenc_master.vhdl
new file mode 100644
index 000000000..3fa3fee12
--- /dev/null
+++ b/testsuite/gna/issue1655/absenc_master.vhdl
@@ -0,0 +1,607 @@
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.std_logic_unsigned.all;
+use ieee.numeric_std.all;
+use ieee.math_real.all;
+
+library work;
+
+
+entity master is
+
+generic
+(
+ CLK_FREQ: integer;
+ ENABLE_ENDAT: boolean;
+ ENABLE_BISS: boolean;
+ ENABLE_SSI: boolean
+);
+port
+(
+ -- local clock
+ clk: in std_logic;
+ rst: in std_logic;
+
+ -- generated clock for slave
+ -- fdiv divides CLK_FREQ
+ ma_fdiv: in unsigned;
+ ma_clk: out std_logic;
+
+ -- master out, slave in
+ mosi: out std_logic;
+ miso: in std_logic;
+
+ -- gate to drive output (1 to drive it)
+ gate: out std_logic;
+
+ -- data from slave, and data length
+ data: out std_logic_vector;
+ len: in unsigned;
+
+ -- encoder type
+ enc_type: in integer;
+
+ -- ssi specific control registers
+ ssi_flags: in std_logic_vector;
+ ssi_delay_fdiv: in unsigned
+);
+
+end entity;
+
+
+architecture absenc_master_rtl of master is
+
+constant DATA_LEN: integer := data'length;
+
+--
+-- conversion pipeline
+
+type conv_state_t is
+(
+ CONV_WAIT_LATCH,
+ CONV_LSB_TO_MSB,
+ CONV_GRAY_TO_BIN,
+ CONV_EXTEND_SIGN,
+ CONV_DONE
+);
+
+constant CONV_ERR: conv_state_t := CONV_WAIT_LATCH;
+
+signal curr_state: conv_state_t;
+signal next_state: conv_state_t;
+
+signal latched_data: std_logic_vector(data'range);
+signal msb_data: std_logic_vector(data'range);
+signal bin_data: std_logic_vector(data'range);
+signal signed_data: std_logic_vector(data'range);
+signal conv_data: std_logic_vector(data'range);
+signal len_mask: std_logic_vector(data'range);
+
+--
+-- enable conversion stages
+
+signal gray_to_bin_en: std_logic;
+signal lsb_to_msb_en: std_logic;
+
+--
+-- timeout counter
+
+constant TM_MAX: integer := work.absenc_pkg.us_to_count
+ (work.absenc_pkg.MAX_TM_US, CLK_FREQ, integer'high);
+
+constant TM_LEN: integer :=
+ work.absenc_pkg.integer_length(TM_MAX);
+
+constant DEFAULT_TM_TOP: integer := work.absenc_pkg.us_to_count
+ (work.absenc_pkg.MASTER_DEFAULT_TM_US, CLK_FREQ, TM_LEN);
+
+signal tm_val: unsigned(TM_LEN - 1 downto 0);
+signal tm_top: unsigned(tm_val'range);
+signal tm_match: std_logic;
+
+--
+-- general counter
+
+signal count_val:
+ unsigned(work.absenc_pkg.integer_length(DATA_LEN) - 1 downto 0);
+signal count_top: unsigned(count_val'range);
+signal count_top_latched: unsigned(count_val'range);
+signal count_rst: std_logic;
+signal count_match: std_logic;
+
+--
+-- serial in, parallel out (SIPO) register
+
+signal sipo_val: std_logic_vector(DATA_LEN - 1 downto 0);
+signal sipo_latch_redge: std_logic;
+signal sipo_latch_pre: std_logic;
+signal sipo_latch: std_logic;
+
+--
+-- master clock
+
+signal ma_clk_rst_en: std_logic;
+signal ma_clk_rst_val: std_logic;
+
+signal ma_clk_val: std_logic;
+
+signal ma_half_fdiv: unsigned(ma_fdiv'length - 1 downto 0);
+signal ma_half_count: unsigned(ma_half_fdiv'length - 1 downto 0);
+signal ma_half_match: std_logic;
+
+--
+-- master clock rising falling edges
+
+signal ma_clk_redge: std_logic;
+signal ma_clk_fedge: std_logic;
+signal ma_clk_edge: std_logic;
+
+--
+-- encoder multiplexed signal
+--
+-- the mux size depends on ENABLE_xxx generics. the idea is to eliminate
+-- unneeded FPGA logic by instantiating only modules enabled by the generics.
+-- to do so, we have functions that translate from ENC_TYPE_xxx to ENC_MUX_xxx
+-- and vice versa. ENC_TYPE_xxx represent all the possible encoders, while
+-- ENC_MUX_xxx represent an encoder index in the mux, if enabled by generics.
+
+subtype tm_val_t is unsigned(tm_val'range);
+type tm_val_array_t is array(integer range<>) of tm_val_t;
+
+subtype count_val_t is unsigned(count_val'range);
+type count_val_array_t is array(integer range<>) of count_val_t;
+
+constant enc_mux_to_type: work.absenc_pkg.enc_type_array_t :=
+ work.absenc_pkg.gen_enc_mux_to_type(ENABLE_ENDAT, ENABLE_BISS, ENABLE_SSI);
+
+constant ENC_MUX_COUNT: integer :=
+ work.absenc_pkg.get_enc_mux_count(ENABLE_ENDAT, ENABLE_BISS, ENABLE_SSI);
+
+constant ENC_MUX_ENDAT: integer :=
+ work.absenc_pkg.get_enc_mux_endat(ENABLE_ENDAT, ENABLE_BISS, ENABLE_SSI);
+
+constant ENC_MUX_BISS: integer :=
+ work.absenc_pkg.get_enc_mux_biss(ENABLE_ENDAT, ENABLE_BISS, ENABLE_SSI);
+
+constant ENC_MUX_SSI: integer :=
+ work.absenc_pkg.get_enc_mux_ssi(ENABLE_ENDAT, ENABLE_BISS, ENABLE_SSI);
+
+signal ma_clk_edge_mux: std_logic_vector(ENC_MUX_COUNT - 1 downto 0);
+signal ma_clk_rst_en_mux: std_logic_vector(ENC_MUX_COUNT - 1 downto 0);
+signal ma_clk_rst_val_mux: std_logic_vector(ENC_MUX_COUNT - 1 downto 0);
+signal mosi_mux: std_logic_vector(ENC_MUX_COUNT - 1 downto 0);
+signal gate_mux: std_logic_vector(ENC_MUX_COUNT - 1 downto 0);
+signal tm_top_mux: tm_val_array_t(ENC_MUX_COUNT - 1 downto 0);
+signal count_rst_mux: std_logic_vector(ENC_MUX_COUNT - 1 downto 0);
+signal count_top_mux: count_val_array_t(ENC_MUX_COUNT - 1 downto 0);
+signal sipo_latch_mux: std_logic_vector(ENC_MUX_COUNT - 1 downto 0);
+signal gray_to_bin_en_mux: std_logic_vector(ENC_MUX_COUNT - 1 downto 0);
+signal lsb_to_msb_en_mux: std_logic_vector(ENC_MUX_COUNT - 1 downto 0);
+
+
+begin
+
+
+--
+-- assert lengths to reduce generated logic
+-- ie. counter and comparator sizes
+
+assert (ma_fdiv'length <= 16)
+report "ma_fdiv'length too large" severity failure;
+
+
+--
+-- master clock generation
+-- master clock frequency is clk divided by ma_fdiv
+-- generate edges using a counter from ma_fdiv/2 to 0
+
+ma_half_fdiv <= ma_fdiv srl 1;
+ma_half_match <= '1' when ma_half_count = 1 else '0';
+
+process
+begin
+ wait until rising_edge(clk);
+
+ if ((rst or ma_clk_rst_en or ma_half_match) = '1') then
+ ma_half_count <= ma_half_fdiv;
+ else
+ ma_half_count <= ma_half_count - 1;
+ end if;
+
+end process;
+
+
+process
+begin
+ wait until rising_edge(clk);
+
+ if ((rst or ma_clk_rst_en) = '1') then
+ ma_clk_val <= ma_clk_rst_val;
+ else
+ ma_clk_val <= ma_clk_val xor ma_half_match;
+ end if;
+
+end process;
+
+ma_clk <= ma_clk_val;
+
+
+--
+-- master clock edges
+
+process
+begin
+ wait until rising_edge(clk);
+ ma_clk_redge <= ma_half_match and (not ma_clk_val);
+end process;
+
+process
+begin
+ wait until rising_edge(clk);
+ ma_clk_fedge <= ma_half_match and ma_clk_val;
+end process;
+
+
+--
+-- timeout counter
+-- tm_val decrement from tm_top to 0
+-- tm_val reloaded at ma_clk_edge
+
+process
+begin
+ wait until rising_edge(clk);
+
+ tm_match <= '0';
+
+ if ((rst or ma_clk_edge) = '1') then
+ tm_val <= tm_top;
+ elsif (tm_val = 0) then
+ tm_val <= tm_top;
+ tm_match <= '1';
+ else
+ tm_val <= tm_val - 1;
+ end if;
+
+end process;
+
+
+--
+-- general purpose counter
+-- monotically incrementing
+-- increment every master edge
+-- starts from 1
+
+process
+begin
+
+ wait until rising_edge(clk);
+
+ if (count_rst = '1') then
+ count_val <= to_unsigned(integer(1), count_val'length);
+ elsif (ma_clk_edge = '1') then
+ count_val <= count_val + 1;
+ end if;
+
+end process;
+
+
+--
+-- general purpose counter comparator
+-- count_match set to one when count_val = count_top
+
+process
+begin
+
+ wait until rising_edge(clk);
+
+ if (count_rst = '1') then
+ count_top_latched <= count_top;
+ end if;
+
+end process;
+
+count_match <= '1' when (count_val = count_top_latched) else '0';
+
+
+--
+-- sipo register
+
+process
+begin
+
+ wait until rising_edge(clk);
+
+ if (ma_clk_edge = '1') then
+ sipo_val <= sipo_val(sipo_val'length - 2 downto 0) & miso;
+ end if;
+
+end process;
+
+
+--
+-- sipo_latch edge detector
+-- ma_clk_redge is not used as ma_clk may be disabled.
+-- instead, clk is used for detecting sipo_latch edges
+
+process
+begin
+ wait until rising_edge(clk);
+ sipo_latch_pre <= sipo_latch;
+end process;
+
+sipo_latch_redge <= (not sipo_latch_pre) and sipo_latch;
+
+
+--
+-- data conversion pipeline. ordering:
+-- data from slave (latched at sipo_latch redge from sipo_val)
+-- lsb_to_msb
+-- gray_to_bin
+-- extend_sign
+-- latched to data
+-- bin_to_sfixed (implemented in top)
+
+process
+begin
+ wait until rising_edge(clk);
+
+ if (rst = '1') then
+ curr_state <= CONV_WAIT_LATCH;
+ else
+ curr_state <= next_state;
+ end if;
+
+end process;
+
+
+process(curr_state, sipo_latch_redge)
+begin
+
+ next_state <= curr_state;
+
+ case curr_state is
+
+ when CONV_WAIT_LATCH =>
+ if (sipo_latch_redge = '1') then
+ next_state <= CONV_LSB_TO_MSB;
+ end if;
+
+ when CONV_LSB_TO_MSB =>
+ next_state <= CONV_GRAY_TO_BIN;
+
+ when CONV_GRAY_TO_BIN =>
+ next_state <= CONV_EXTEND_SIGN;
+
+ when CONV_EXTEND_SIGN =>
+ next_state <= CONV_DONE;
+
+ when CONV_DONE =>
+ next_state <= CONV_WAIT_LATCH;
+
+ when others =>
+ next_state <= CONV_ERR;
+
+ end case;
+
+end process;
+
+
+process
+begin
+ wait until rising_edge(clk);
+
+ latched_data <= latched_data;
+ conv_data <= conv_data;
+
+ case curr_state is
+
+ when CONV_WAIT_LATCH =>
+ latched_data <= sipo_val and len_mask;
+
+ when CONV_LSB_TO_MSB =>
+
+ when CONV_EXTEND_SIGN =>
+
+ when CONV_DONE =>
+ conv_data <= signed_data;
+
+ when others =>
+
+ end case;
+
+end process;
+
+data <= conv_data;
+
+
+len_to_mask: work.absenc_pkg.len_to_mask
+port map
+(
+ len => len,
+ mask => len_mask
+);
+
+
+lsb_to_msb: work.absenc_pkg.lsb_to_msb
+port map
+(
+ en => lsb_to_msb_en,
+ data_len => len,
+ lsb_data => latched_data,
+ msb_data => msb_data
+);
+
+
+gray_to_bin: work.absenc_pkg.gray_to_bin
+port map
+(
+ en => gray_to_bin_en,
+ gray_data => msb_data,
+ bin_data => bin_data
+);
+
+
+extend_sign: work.absenc_pkg.extend_sign
+port map
+(
+ data_len => len,
+ data_in => bin_data,
+ data_out => signed_data,
+ len_mask => len_mask
+);
+
+
+--
+-- encoder master implementations
+
+gen_endat: if ENABLE_ENDAT = TRUE generate
+master_endat: work.absenc_pkg.master_endat
+generic map
+(
+ CLK_FREQ => CLK_FREQ
+)
+port map
+(
+ clk => clk,
+ rst => rst,
+ ma_clk_fedge => ma_clk_fedge,
+ ma_clk_redge => ma_clk_redge,
+ ma_clk_edge => ma_clk_edge_mux(ENC_MUX_ENDAT),
+ ma_clk_rst_en => ma_clk_rst_en_mux(ENC_MUX_ENDAT),
+ ma_clk_rst_val => ma_clk_rst_val_mux(ENC_MUX_ENDAT),
+ mosi => mosi_mux(ENC_MUX_ENDAT),
+ miso => miso,
+ gate => gate_mux(ENC_MUX_ENDAT),
+ len => len,
+ tm_match => tm_match,
+ tm_top => tm_top_mux(ENC_MUX_ENDAT),
+ count_top => count_top_mux(ENC_MUX_ENDAT),
+ count_match => count_match,
+ count_rst => count_rst_mux(ENC_MUX_ENDAT),
+ sipo_val => sipo_val,
+ sipo_latch => sipo_latch_mux(ENC_MUX_ENDAT),
+ gray_to_bin_en => gray_to_bin_en_mux(ENC_MUX_ENDAT),
+ lsb_to_msb_en => lsb_to_msb_en_mux(ENC_MUX_ENDAT)
+);
+end generate gen_endat;
+
+
+gen_biss: if ENABLE_BISS = TRUE generate
+master_biss: work.absenc_pkg.master_biss
+generic map
+(
+ CLK_FREQ => CLK_FREQ
+)
+port map
+(
+ clk => clk,
+ rst => rst,
+ ma_clk_fedge => ma_clk_fedge,
+ ma_clk_redge => ma_clk_redge,
+ ma_clk_edge => ma_clk_edge_mux(ENC_MUX_BISS),
+ ma_clk_rst_en => ma_clk_rst_en_mux(ENC_MUX_BISS),
+ ma_clk_rst_val => ma_clk_rst_val_mux(ENC_MUX_BISS),
+ mosi => mosi_mux(ENC_MUX_BISS),
+ miso => miso,
+ gate => gate_mux(ENC_MUX_BISS),
+ len => len,
+ tm_match => tm_match,
+ tm_top => tm_top_mux(ENC_MUX_BISS),
+ count_top => count_top_mux(ENC_MUX_BISS),
+ count_match => count_match,
+ count_rst => count_rst_mux(ENC_MUX_BISS),
+ sipo_val => sipo_val,
+ sipo_latch => sipo_latch_mux(ENC_MUX_BISS),
+ gray_to_bin_en => gray_to_bin_en_mux(ENC_MUX_BISS),
+ lsb_to_msb_en => lsb_to_msb_en_mux(ENC_MUX_BISS)
+);
+end generate gen_biss;
+
+
+gen_ssi: if ENABLE_SSI = TRUE generate
+master_ssi: work.absenc_pkg.master_ssi
+generic map
+(
+ CLK_FREQ => CLK_FREQ
+)
+port map
+(
+ clk => clk,
+ rst => rst,
+ ma_clk_fedge => ma_clk_fedge,
+ ma_clk_redge => ma_clk_redge,
+ ma_clk_edge => ma_clk_edge_mux(ENC_MUX_SSI),
+ ma_clk_rst_en => ma_clk_rst_en_mux(ENC_MUX_SSI),
+ ma_clk_rst_val => ma_clk_rst_val_mux(ENC_MUX_SSI),
+ mosi => mosi_mux(ENC_MUX_SSI),
+ miso => miso,
+ gate => gate_mux(ENC_MUX_SSI),
+ len => len,
+ tm_match => tm_match,
+ tm_top => tm_top_mux(ENC_MUX_SSI),
+ count_top => count_top_mux(ENC_MUX_SSI),
+ count_match => count_match,
+ count_rst => count_rst_mux(ENC_MUX_SSI),
+ sipo_val => sipo_val,
+ sipo_latch => sipo_latch_mux(ENC_MUX_SSI),
+ gray_to_bin_en => gray_to_bin_en_mux(ENC_MUX_SSI),
+ lsb_to_msb_en => lsb_to_msb_en_mux(ENC_MUX_SSI),
+ ssi_flags => ssi_flags,
+ ssi_delay_fdiv => ssi_delay_fdiv
+);
+end generate gen_ssi;
+
+
+--
+-- enc_type multiplexer
+
+process
+(
+ enc_type,
+ ma_clk_edge_mux,
+ ma_clk_rst_en_mux,
+ ma_clk_rst_val_mux,
+ mosi_mux,
+ gate_mux,
+ tm_top_mux,
+ count_rst_mux,
+ count_top_mux,
+ sipo_latch_mux,
+ gray_to_bin_en_mux,
+ lsb_to_msb_en_mux
+)
+
+begin
+
+ ma_clk_edge <= ma_clk_redge;
+ ma_clk_rst_en <= '0';
+ ma_clk_rst_val <= '1';
+ mosi <= '0';
+ gate <= '0';
+ tm_top <= to_unsigned(DEFAULT_TM_TOP, tm_top'length);
+ count_rst <= '0';
+ count_top <= (others => '0');
+ sipo_latch <= '0';
+ gray_to_bin_en <= '0';
+ lsb_to_msb_en <= '0';
+
+ for i in 0 to ENC_MUX_COUNT - 1 loop
+ if enc_mux_to_type(i) = enc_type then
+ ma_clk_edge <= ma_clk_edge_mux(i);
+ ma_clk_rst_en <= ma_clk_rst_en_mux(i);
+ ma_clk_rst_val <= ma_clk_rst_val_mux(i);
+ mosi <= mosi_mux(i);
+ gate <= gate_mux(i);
+ tm_top <= tm_top_mux(i);
+ count_rst <= count_rst_mux(i);
+ count_top <= count_top_mux(i);
+ sipo_latch <= sipo_latch_mux(i);
+ gray_to_bin_en <= gray_to_bin_en_mux(i);
+ lsb_to_msb_en <= lsb_to_msb_en_mux(i);
+ end if;
+ end loop;
+
+end process;
+
+
+end absenc_master_rtl;
diff --git a/testsuite/gna/issue1655/absenc_master_endat.vhdl b/testsuite/gna/issue1655/absenc_master_endat.vhdl
new file mode 100644
index 000000000..2d0daf141
--- /dev/null
+++ b/testsuite/gna/issue1655/absenc_master_endat.vhdl
@@ -0,0 +1,314 @@
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.std_logic_unsigned.all;
+use ieee.numeric_std.all;
+use ieee.math_real.all;
+
+library work;
+
+
+entity master_endat is
+
+generic
+(
+ CLK_FREQ: integer
+);
+port
+(
+ -- local clock
+ clk: in std_logic;
+ rst: in std_logic;
+
+ -- master clock edges
+ ma_clk_fedge: in std_logic;
+ ma_clk_redge: in std_logic;
+
+ -- the edge we are interested in
+ ma_clk_edge: out std_logic;
+
+ -- master clock reset
+ -- if ma_clk_rst_en, use ma_clk_rst_level
+ ma_clk_rst_en: out std_logic;
+ ma_clk_rst_val: out std_logic;
+
+ -- master out, slave in
+ mosi: out std_logic;
+ miso: in std_logic;
+
+ -- gate to drive output (1 to drive it)
+ gate: out std_logic;
+
+ -- desired data length
+ len: in unsigned;
+
+ -- timeout counter
+ tm_match: in std_logic;
+ tm_top: out unsigned;
+
+ -- general purpose counter
+ count_top: out unsigned;
+ count_match: in std_logic;
+ count_rst: out std_logic;
+
+ -- sipo register
+ sipo_val: in std_logic_vector;
+ sipo_latch: out std_logic;
+
+ -- enable data conversion stages
+ gray_to_bin_en: out std_logic;
+ lsb_to_msb_en: out std_logic
+);
+
+end entity;
+
+
+architecture absenc_master_endat_rtl of master_endat is
+
+
+--
+-- default timeout value. standard says: 10 to 30 us
+
+constant TM_VAL: integer := work.absenc_pkg.us_to_count
+ (work.absenc_pkg.MASTER_DEFAULT_TM_US, CLK_FREQ, tm_top'length);
+
+
+--
+-- main state machine
+
+type endat_state_t is
+(
+ ENDAT_INIT,
+
+ ENDAT_T0,
+ ENDAT_T1,
+ ENDAT_MODE,
+ ENDAT_T3,
+ ENDAT_T4,
+
+ ENDAT_T5,
+
+ ENDAT_START,
+ ENDAT_F1,
+ ENDAT_DATA,
+
+ ENDAT_CRC5_FIRST,
+ ENDAT_CRC5_CONT,
+
+ ENDAT_DONE
+);
+
+constant ENDAT_TMOUT: endat_state_t := ENDAT_DONE;
+constant ENDAT_ERR: endat_state_t := ENDAT_DONE;
+
+signal curr_state: endat_state_t;
+signal next_state: endat_state_t;
+
+
+--
+-- right shifted parallel in, serial out register
+-- loaded values are in reverse order
+
+constant piso_ini: std_logic_vector := "111000";
+signal piso_val: std_logic_vector(piso_ini'length - 1 downto 0);
+signal piso_load: std_logic;
+
+
+begin
+
+
+--
+-- state automaton
+
+process
+begin
+ wait until rising_edge(clk);
+
+ if (rst = '1') then
+ curr_state <= ENDAT_TMOUT;
+ elsif ((tm_match or ma_clk_fedge) = '1') then
+ curr_state <= next_state;
+ end if;
+
+end process;
+
+
+process(curr_state, count_match, tm_match, miso)
+begin
+
+ next_state <= curr_state;
+
+ case curr_state is
+
+ when ENDAT_INIT =>
+ next_state <= ENDAT_T0;
+
+ when ENDAT_T0 =>
+ next_state <= ENDAT_T1;
+
+ when ENDAT_T1 =>
+ next_state <= ENDAT_MODE;
+
+ when ENDAT_MODE =>
+ if (count_match = '1') then
+ next_state <= ENDAT_T3;
+ end if;
+
+ when ENDAT_T3 =>
+ next_state <= ENDAT_T4;
+
+ when ENDAT_T4 =>
+ next_state <= ENDAT_T5;
+
+ when ENDAT_T5 =>
+ next_state <= ENDAT_START;
+
+ when ENDAT_START =>
+ if (miso = '1') then
+ next_state <= ENDAT_F1;
+ elsif (tm_match = '1') then
+ next_state <= ENDAT_TMOUT;
+ end if;
+
+ when ENDAT_F1 =>
+ next_state <= ENDAT_DATA;
+
+ when ENDAT_DATA =>
+ if (count_match = '1') then
+ next_state <= ENDAT_CRC5_FIRST;
+ end if;
+
+ when ENDAT_CRC5_FIRST =>
+ next_state <= ENDAT_CRC5_CONT;
+
+ when ENDAT_CRC5_CONT =>
+ if (count_match = '1') then
+ next_state <= ENDAT_DONE;
+ end if;
+
+ when ENDAT_DONE =>
+ -- wait for at least one timeout
+ next_state <= ENDAT_INIT;
+
+ when others =>
+ next_state <= ENDAT_ERR;
+
+ end case;
+
+end process;
+
+
+process
+begin
+
+ wait until rising_edge(clk);
+
+ ma_clk_rst_en <= '0';
+ count_top <= (count_top'range => '0');
+ count_rst <= '0';
+ sipo_latch <= '0';
+ gate <= '0';
+ mosi <= '0';
+ piso_load <= '0';
+
+ case curr_state is
+
+ when ENDAT_INIT =>
+ gate <= '1';
+
+ when ENDAT_T0 =>
+ gate <= '1';
+
+ when ENDAT_T1 =>
+ piso_load <= '1';
+ gate <= '1';
+ count_top <= to_unsigned(6, count_top'length);
+ count_rst <= '1';
+
+ when ENDAT_MODE =>
+ mosi <= piso_val(0);
+ gate <= '1';
+
+ when ENDAT_T3 =>
+ mosi <= '0';
+ gate <= '1';
+
+ when ENDAT_T4 =>
+ mosi <= '0';
+ gate <= '1';
+
+ when ENDAT_T5 =>
+
+ when ENDAT_START =>
+
+ when ENDAT_F1 =>
+ count_top <= len(count_top'range);
+ count_rst <= '1';
+
+ when ENDAT_DATA =>
+ -- sent LSb first
+
+ when ENDAT_CRC5_FIRST =>
+ count_top <= to_unsigned(integer(5 - 1), count_top'length);
+ count_rst <= '1';
+ sipo_latch <= '1';
+
+ when ENDAT_CRC5_CONT =>
+
+ when ENDAT_DONE =>
+ ma_clk_rst_en <= '1';
+
+ when others =>
+
+ end case;
+
+end process;
+
+
+--
+-- right shifted piso register
+-- set at falling edge, sample by slave at redge
+
+process
+begin
+ wait until rising_edge(clk);
+
+ if (piso_load = '1') then
+ piso_val <= piso_ini;
+ elsif (ma_clk_fedge = '1') then
+ piso_val <= '0' & piso_val(piso_val'length - 1 downto 1);
+ end if;
+
+end process;
+
+
+--
+-- clock reset or idle value
+
+ma_clk_rst_val <= '1';
+
+
+--
+-- timeout
+
+tm_top <= to_unsigned(TM_VAL, tm_top'length);
+
+
+--
+-- gray to binary disabled
+
+gray_to_bin_en <= '0';
+
+
+--
+-- lsb to msb enabled
+
+lsb_to_msb_en <= '1';
+
+
+--
+-- use falling edge
+
+ma_clk_edge <= ma_clk_fedge;
+
+
+end architecture;
diff --git a/testsuite/gna/issue1655/absenc_pkg.vhdl b/testsuite/gna/issue1655/absenc_pkg.vhdl
new file mode 100644
index 000000000..e5a439746
--- /dev/null
+++ b/testsuite/gna/issue1655/absenc_pkg.vhdl
@@ -0,0 +1,776 @@
+--
+-- package for absolute encoder slave and master
+-- supported formats: ENDAT, BISS, SSI
+--
+-- there is a bunch of code here. a typical user is
+-- interested in the following 2 components:
+-- absenc_pkg.slave
+-- absenc_pkg.master
+--
+-- refer to sim/common/main.vhd for usage.
+
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.std_logic_unsigned.all;
+use ieee.numeric_std.all;
+use ieee.math_real.all;
+
+
+package absenc_pkg is
+
+
+--
+-- encoder type identifiers
+
+constant ENC_TYPE_ENDAT: integer := 0;
+constant ENC_TYPE_BISS: integer := 1;
+constant ENC_TYPE_SSI: integer := 2;
+constant ENC_TYPE_COUNT: integer := 3;
+
+
+--
+-- encoder positions in mux
+
+function get_enc_mux_endat
+(
+ enable_endat: boolean;
+ enable_biss: boolean;
+ enable_ssi: boolean
+)
+return integer;
+
+
+function get_enc_mux_biss
+(
+ enable_endat: boolean;
+ enable_biss: boolean;
+ enable_ssi: boolean
+)
+return integer;
+
+
+function get_enc_mux_ssi
+(
+ enable_endat: boolean;
+ enable_biss: boolean;
+ enable_ssi: boolean
+)
+return integer;
+
+
+--
+-- count enabled encoders
+
+function get_enc_mux_count
+(
+ enable_endat: boolean;
+ enable_biss: boolean;
+ enable_ssi: boolean
+)
+return integer;
+
+
+--
+-- mux position to encoder type
+
+type enc_type_array_t is array(ENC_TYPE_COUNT - 1 downto 0) of integer;
+
+function gen_enc_mux_to_type
+(
+ enable_endat: boolean;
+ enable_biss: boolean;
+ enable_ssi: boolean
+)
+return enc_type_array_t;
+
+
+--
+-- compute integer length
+
+function integer_length
+(
+ i: integer
+)
+return integer;
+
+
+--
+-- microsecond to counter clocked by freq
+
+function us_to_count
+(
+ us: integer;
+ freq: integer;
+ len: integer
+)
+return integer;
+
+
+--
+-- default timeout us
+-- conditions the lowset and highest ma_clk
+
+constant MAX_TM_US: integer := 100;
+constant MASTER_DEFAULT_TM_US: integer := 60;
+constant SLAVE_DEFAULT_TM_US: integer := 20;
+
+
+--
+-- default ssi related values
+-- no spy mode
+-- binary coding
+-- no special terminating pattern
+-- no delay
+
+constant SSI_DEFAULT_FLAGS: std_logic_vector := "00000";
+constant SSI_DEFAULT_DELAY_FDIV: unsigned(0 downto 0) := to_unsigned(0, 1);
+
+
+--
+-- encoder slave interface
+
+component slave
+generic
+(
+ -- local clock frequency
+ CLK_FREQ: integer;
+
+ -- enable a specific implementation, or all by default
+ -- disabling unneeded implementations optimizes resources
+ ENABLE_ENDAT: boolean := TRUE;
+ ENABLE_BISS: boolean := TRUE;
+ ENABLE_SSI: boolean := TRUE
+);
+port
+(
+ -- local clock and reset
+ clk: in std_logic;
+ rst: in std_logic;
+
+ -- clock from master
+ ma_clk: in std_logic;
+
+ -- master in, slave out
+ miso: out std_logic;
+ mosi: in std_logic;
+
+ -- gate to drive output (1 to drive it). used in PEPU
+ -- first versions, set to open if not used.
+ gate: out std_logic;
+
+ -- data sent to master. typically the position
+ -- important: use the smallest possible width, as
+ -- this is used to derive other resource sizes
+ data: in std_logic_vector;
+
+ -- data length. typically the encoder resolution
+ -- important: use the smallest possible width, as
+ -- this is used to derive other resource sizes
+ len: in unsigned;
+
+ -- the selected encoder type
+ enc_type: in integer;
+
+ -- ssi specific flags
+ -- set to work.absenc_pkg.SSI_DEFAULT_FLAGS if unused
+ -- ssi_flags<0>: unused
+ -- ssi_flags<1>: 0 or 1 for binary or gray data coding
+ -- ssi_flags<2>: '.S' terminating pattern
+ -- ssi_flags<3>: 'ES' terminating pattern
+ -- ssi_flags<4>: 'OS' terminating pattern
+ ssi_flags: in std_logic_vector
+);
+end component;
+
+
+component slave_endat
+generic
+(
+ CLK_FREQ: integer
+);
+port
+(
+ -- local clock
+ clk: in std_logic;
+ rst: in std_logic;
+
+ -- master clock edges
+ ma_clk_redge: in std_logic;
+ ma_clk_fedge: in std_logic;
+
+ -- the edge we are interested in
+ ma_clk_edge: out std_logic;
+
+ -- master in, slave out
+ miso: out std_logic;
+ mosi: in std_logic;
+
+ -- gate to drive output (1 to drive it)
+ gate: out std_logic;
+
+ -- actual data to send and length
+ data: in std_logic_vector;
+ len: in unsigned;
+
+ -- timeout counter
+ tm_match: in std_logic;
+ tm_top: out unsigned;
+
+ -- general purpose counter
+ count_top: out unsigned;
+ count_match: in std_logic;
+ count_rst: out std_logic;
+
+ -- piso register
+ piso_rval: in std_logic_vector;
+ piso_lval: in std_logic_vector;
+ piso_ini: out std_logic_vector;
+ piso_load: out std_logic
+);
+end component;
+
+
+component slave_biss
+generic
+(
+ CLK_FREQ: integer
+);
+port
+(
+ -- local clock
+ clk: in std_logic;
+ rst: in std_logic;
+
+ -- master clock edges
+ ma_clk_redge: in std_logic;
+ ma_clk_fedge: in std_logic;
+
+ -- the edge we are interested in
+ ma_clk_edge: out std_logic;
+
+ -- master in, slave out
+ miso: out std_logic;
+ mosi: in std_logic;
+
+ -- gate to drive output (1 to drive it)
+ gate: out std_logic;
+
+ -- actual data to send and length
+ data: in std_logic_vector;
+ len: in unsigned;
+
+ -- timeout counter
+ tm_match: in std_logic;
+ tm_top: out unsigned;
+
+ -- general purpose counter
+ count_top: out unsigned;
+ count_match: in std_logic;
+ count_rst: out std_logic;
+
+ -- piso register
+ piso_rval: in std_logic_vector;
+ piso_lval: in std_logic_vector;
+ piso_ini: out std_logic_vector;
+ piso_load: out std_logic
+);
+end component;
+
+
+component slave_ssi
+generic
+(
+ CLK_FREQ: integer
+);
+port
+(
+ -- local clock
+ clk: in std_logic;
+ rst: in std_logic;
+
+ -- master clock edges
+ ma_clk_redge: in std_logic;
+ ma_clk_fedge: in std_logic;
+
+ -- the edge we are interested in
+ ma_clk_edge: out std_logic;
+
+ -- master in, slave out
+ miso: out std_logic;
+ mosi: in std_logic;
+
+ -- gate to drive output (1 to drive it)
+ gate: out std_logic;
+
+ -- actual data to send and length
+ data: in std_logic_vector;
+ len: in unsigned;
+
+ -- timeout counter
+ tm_match: in std_logic;
+ tm_top: out unsigned;
+
+ -- general purpose counter
+ count_top: out unsigned;
+ count_match: in std_logic;
+ count_rst: out std_logic;
+
+ -- piso register
+ piso_rval: in std_logic_vector;
+ piso_lval: in std_logic_vector;
+ piso_ini: out std_logic_vector;
+ piso_load: out std_logic;
+
+ -- refer to absenc_pkg.slave for comments
+ ssi_flags: in std_logic_vector
+);
+end component;
+
+
+--
+-- encoder master interface
+
+component master
+generic
+(
+ -- local clock frequency
+ CLK_FREQ: integer;
+
+ -- enable a specific implementation, or all by default
+ -- disabling unneeded implementations optimizes resources
+ ENABLE_ENDAT: boolean := TRUE;
+ ENABLE_BISS: boolean := FALSE;
+ ENABLE_SSI: boolean := FALSE
+);
+port
+(
+ -- local clock and reset
+ clk: in std_logic;
+ rst: in std_logic;
+
+ -- ma_clk is the clock signal generated by the master
+ -- to the slave. its frequency is CLK_FREQ / ma_fdiv
+ ma_fdiv: in unsigned;
+ ma_clk: out std_logic;
+
+ -- master out, slave in
+ mosi: out std_logic;
+ miso: in std_logic;
+
+ -- gate to drive output (1 to drive it). used in PEPU
+ -- first versions, set to open if not used.
+ gate: out std_logic;
+
+ -- data received from slave. typically the position
+ -- important: use the smallest possible width, as
+ -- this is used to derive other resource sizes
+ data: out std_logic_vector;
+
+ -- data length. typically the encoder resolution
+ -- important: use the smallest possible width, as
+ -- this is used to derive other resource sizes
+ len: in unsigned;
+
+ -- the selected encoder type
+ enc_type: in integer;
+
+ -- ssi specific flags
+ -- set to work.absenc_pkg.SSI_DEFAULT_FLAGS if unused
+ -- ssi_flags<0>: ssi spy mode (ie. master without clock)
+ -- ssi_flags<1>: 0 or 1 for binary or gray data coding
+ -- ssi_flags<2>: '.S' terminating pattern
+ -- ssi_flags<3>: 'ES' terminating pattern
+ -- ssi_flags<4>: 'OS' terminating pattern
+ ssi_flags: in std_logic_vector;
+
+ -- ssi frame delay. divides CLK_FREQ
+ -- set to work.absenc_pkg.SSI_DEFAULT_DELAY_FDIV if unsued
+ ssi_delay_fdiv: in unsigned
+);
+end component;
+
+
+component master_endat
+generic
+(
+ CLK_FREQ: integer
+);
+port
+(
+ -- local clock
+ clk: in std_logic;
+ rst: in std_logic;
+
+ -- master clock edges
+ ma_clk_fedge: in std_logic;
+ ma_clk_redge: in std_logic;
+
+ -- the edge we are interested in
+ ma_clk_edge: out std_logic;
+
+ -- master clock reset
+ -- if ma_clk_rst_en, use ma_clk_rst_level
+ ma_clk_rst_en: out std_logic;
+ ma_clk_rst_val: out std_logic;
+
+ -- master out, slave in
+ mosi: out std_logic;
+ miso: in std_logic;
+
+ -- gate to drive output (1 to drive it)
+ gate: out std_logic;
+
+ -- desired data length
+ len: in unsigned;
+
+ -- timeout counter
+ tm_match: in std_logic;
+ tm_top: out unsigned;
+
+ -- general purpose counter
+ count_top: out unsigned;
+ count_match: in std_logic;
+ count_rst: out std_logic;
+
+ -- sipo register
+ sipo_val: in std_logic_vector;
+ sipo_latch: out std_logic;
+
+ -- enable data conversion stages
+ gray_to_bin_en: out std_logic;
+ lsb_to_msb_en: out std_logic
+);
+end component;
+
+
+component master_biss
+generic
+(
+ CLK_FREQ: integer
+);
+port
+(
+ -- local clock
+ clk: in std_logic;
+ rst: in std_logic;
+
+ -- master clock edges
+ ma_clk_fedge: in std_logic;
+ ma_clk_redge: in std_logic;
+
+ -- the edge we are interested in
+ ma_clk_edge: out std_logic;
+
+ -- master clock reset
+ -- if ma_clk_rst_en, use ma_clk_rst_level
+ ma_clk_rst_en: out std_logic;
+ ma_clk_rst_val: out std_logic;
+
+ -- master out, slave in
+ mosi: out std_logic;
+ miso: in std_logic;
+
+ -- gate to drive output (1 to drive it)
+ gate: out std_logic;
+
+ -- desired data length
+ len: in unsigned;
+
+ -- timeout counter
+ tm_match: in std_logic;
+ tm_top: out unsigned;
+
+ -- general purpose counter
+ count_top: out unsigned;
+ count_match: in std_logic;
+ count_rst: out std_logic;
+
+ -- sipo register
+ sipo_val: in std_logic_vector;
+ sipo_latch: out std_logic;
+
+ -- enable data conversion stages
+ gray_to_bin_en: out std_logic;
+ lsb_to_msb_en: out std_logic
+);
+end component;
+
+
+component master_ssi
+generic
+(
+ CLK_FREQ: integer
+);
+port
+(
+ -- local clock
+ clk: in std_logic;
+ rst: in std_logic;
+
+ -- master clock edges
+ ma_clk_fedge: in std_logic;
+ ma_clk_redge: in std_logic;
+
+ -- the edge we are interested in
+ ma_clk_edge: out std_logic;
+
+ -- master clock reset
+ -- if ma_clk_rst_en, use ma_clk_rst_level
+ ma_clk_rst_en: out std_logic;
+ ma_clk_rst_val: out std_logic;
+
+ -- master out, slave in
+ mosi: out std_logic;
+ miso: in std_logic;
+
+ -- gate to drive output (1 to drive it)
+ gate: out std_logic;
+
+ -- desired data length
+ len: in unsigned;
+
+ -- timeout counter
+ tm_match: in std_logic;
+ tm_top: out unsigned;
+
+ -- general purpose counter
+ count_top: out unsigned;
+ count_match: in std_logic;
+ count_rst: out std_logic;
+
+ -- sipo register
+ sipo_val: in std_logic_vector;
+ sipo_latch: out std_logic;
+
+ -- enable data conversion stages
+ gray_to_bin_en: out std_logic;
+ lsb_to_msb_en: out std_logic;
+
+ -- refer to absenc_pkg.master for comments
+ ssi_flags: in std_logic_vector;
+ ssi_delay_fdiv: in unsigned
+);
+end component;
+
+
+component reader_hssl is
+generic
+(
+ CLK_FREQ: integer
+);
+port
+(
+ -- local clock
+ clk: in std_logic;
+ rst: in std_logic;
+
+ -- sender clock
+ sclk: in std_logic;
+
+ -- sender out, reader in
+ sori: in std_logic;
+
+ -- actual data to send and length
+ data: out std_logic_vector;
+
+ -- configuration
+ len: in unsigned;
+ tm_gap: in unsigned
+);
+
+end component;
+
+
+--
+-- utilities
+
+component len_to_mask
+port
+(
+ len: in unsigned;
+ mask: out std_logic_vector
+);
+end component;
+
+
+component lsb_to_msb
+port
+(
+ en: in std_logic;
+ data_len: in unsigned;
+ lsb_data: in std_logic_vector;
+ msb_data: out std_logic_vector
+);
+end component;
+
+
+component bin_to_gray
+port
+(
+ en: in std_logic;
+ bin_data: in std_logic_vector;
+ gray_data: out std_logic_vector
+);
+end component;
+
+
+component gray_to_bin
+port
+(
+ en: in std_logic;
+ gray_data: in std_logic_vector;
+ bin_data: out std_logic_vector
+);
+end component;
+
+
+component extend_sign
+port
+(
+ data_len: in unsigned;
+ data_in: in std_logic_vector;
+ data_out: out std_logic_vector;
+ len_mask: in std_logic_vector
+);
+end component;
+
+
+end package absenc_pkg;
+
+
+package body absenc_pkg is
+
+--
+-- encoder positions in mux
+
+function get_enc_mux_endat
+(
+ enable_endat: boolean;
+ enable_biss: boolean;
+ enable_ssi: boolean
+)
+return integer is
+begin
+ return 0;
+end get_enc_mux_endat;
+
+
+function get_enc_mux_biss
+(
+ enable_endat: boolean;
+ enable_biss: boolean;
+ enable_ssi: boolean
+)
+return integer is
+ variable i: integer;
+begin
+ i := 0;
+ if enable_endat = TRUE then i := i + 1; end if;
+ return i;
+end get_enc_mux_biss;
+
+
+function get_enc_mux_ssi
+(
+ enable_endat: boolean;
+ enable_biss: boolean;
+ enable_ssi: boolean
+)
+return integer is
+ variable i: integer;
+begin
+ i := 0;
+ if enable_endat = TRUE then i := i + 1; end if;
+ if enable_biss = TRUE then i := i + 1; end if;
+ return i;
+end get_enc_mux_ssi;
+
+
+--
+-- count enabled encoders
+
+function get_enc_mux_count
+(
+ enable_endat: boolean;
+ enable_biss: boolean;
+ enable_ssi: boolean
+)
+return integer is
+ variable n: integer;
+begin
+ n := 0;
+ if enable_endat = TRUE then n := n + 1; end if;
+ if enable_biss = TRUE then n := n + 1; end if;
+ if enable_ssi = TRUE then n := n + 1; end if;
+ return n;
+end get_enc_mux_count;
+
+
+--
+-- mux position to encoder type
+
+function gen_enc_mux_to_type
+(
+ enable_endat: boolean;
+ enable_biss: boolean;
+ enable_ssi: boolean
+)
+return enc_type_array_t is
+ variable a: enc_type_array_t;
+ variable i: integer;
+begin
+
+ i := 0;
+
+ if enable_endat = TRUE then
+ a(i) := ENC_TYPE_ENDAT;
+ i := i + 1;
+ end if;
+
+ if enable_biss = TRUE then
+ a(i) := ENC_TYPE_BISS;
+ i := i + 1;
+ end if;
+
+ if enable_ssi = TRUE then
+ a(i) := ENC_TYPE_SSI;
+ i := i + 1;
+ end if;
+
+ return a;
+end gen_enc_mux_to_type;
+
+
+--
+-- compute integer length
+
+function integer_length
+(
+ i: integer
+)
+return integer is
+begin
+ return integer(ceil(log2(real(i))));
+end integer_length;
+
+
+--
+-- microsecond to counter clocked by freq
+
+function us_to_count
+(
+ us: integer;
+ freq: integer;
+ len: integer
+)
+return integer is
+ variable count: integer;
+begin
+ count := integer(ceil(real(us) * real(freq) / 1000000.0));
+ assert (integer_length(count) <= len) report "tm too high" severity failure;
+ return count;
+end us_to_count;
+
+
+end package body absenc_pkg;
diff --git a/testsuite/gna/issue1655/absenc_utils.vhdl b/testsuite/gna/issue1655/absenc_utils.vhdl
new file mode 100644
index 000000000..92d881b38
--- /dev/null
+++ b/testsuite/gna/issue1655/absenc_utils.vhdl
@@ -0,0 +1,239 @@
+--
+-- create a mask with all length bit set
+
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.std_logic_unsigned.all;
+use ieee.numeric_std.all;
+
+
+entity len_to_mask is
+port
+(
+ len: in unsigned;
+ mask: out std_logic_vector
+);
+end entity;
+
+architecture len_to_mask_rtl of len_to_mask is
+
+constant size: integer := mask'length;
+
+begin
+
+--
+-- result in a mask such as:
+-- mask(mask'length - 1 downto len) = '0';
+-- mask(len - 1 downto 0) = '1';
+
+process(len)
+begin
+ for i in 2 to size loop
+ if i = to_integer(len) then
+ mask(size - 1 downto i) <= (others => '0');
+ mask(i - 1 downto 0) <= (others => '1');
+ end if;
+ end loop;
+end process;
+
+end len_to_mask_rtl;
+
+
+--
+-- lsb to msb conversion
+
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.std_logic_unsigned.all;
+use ieee.numeric_std.all;
+
+
+entity lsb_to_msb is
+port
+(
+ en: in std_logic;
+ data_len: in unsigned;
+ lsb_data: in std_logic_vector;
+ msb_data: out std_logic_vector
+);
+end entity;
+
+architecture lsb_to_msb_rtl of lsb_to_msb is
+
+constant size: integer := lsb_data'length;
+
+begin
+
+--
+-- lsb_data: uuuuLxxxxM
+-- msb_data: uuuuMxxxxL
+-- where u undefined, x 0 or 1
+
+process(en, lsb_data)
+begin
+
+ if (en = '1') then
+
+ for i in 1 to size loop
+ if i = to_integer(data_len) then
+ msb_data(msb_data'length - 1 downto i) <= (others => '0');
+ for j in 0 to (i - 1) loop
+ msb_data(j) <= lsb_data(i - 1 - j);
+ end loop;
+ exit ;
+ end if;
+ end loop;
+
+ else
+
+ msb_data <= lsb_data;
+
+ end if;
+
+end process;
+
+end lsb_to_msb_rtl;
+
+
+--
+-- binary to gray conversion
+
+
+library ieee;
+use ieee.std_logic_1164.all;
+
+
+entity bin_to_gray is
+port
+(
+ -- enable conversion
+ en: in std_logic;
+ bin_data: in std_logic_vector;
+ gray_data: out std_logic_vector
+);
+end entity;
+
+architecture bin_to_gray_rtl of bin_to_gray is
+
+constant size: integer := bin_data'length;
+
+begin
+
+assert (bin_data'length = gray_data'length)
+report "size differs" severity failure;
+
+process(en, bin_data) is
+begin
+ if en = '1' then
+ for j in 0 to (size - 2) loop
+ gray_data(j) <= bin_data(j) xor bin_data(j + 1);
+ end loop;
+ gray_data(size - 1) <= bin_data(size - 1);
+ else
+ gray_data <= bin_data;
+ end if;
+end process;
+
+end bin_to_gray_rtl;
+
+
+--
+-- gray to binary conversion
+
+
+library ieee;
+use ieee.std_logic_1164.all;
+
+
+entity gray_to_bin is
+port
+(
+ -- enable conversion
+ en: in std_logic;
+ gray_data: in std_logic_vector;
+ bin_data: out std_logic_vector
+);
+end entity;
+
+architecture gray_to_bin_rtl of gray_to_bin is
+
+constant size: integer := bin_data'length;
+
+signal tmp_data: std_logic_vector(bin_data'range);
+
+begin
+
+assert (bin_data'length = gray_data'length)
+report "size differs" severity failure;
+
+process(en, gray_data, tmp_data) is
+begin
+ if (en = '1') then
+ for j in 0 to (size - 2) loop
+ tmp_data(j) <= gray_data(j) xor tmp_data(j + 1);
+ end loop;
+ tmp_data(size - 1) <= gray_data(size - 1);
+ bin_data <= tmp_data;
+ else
+ bin_data <= gray_data;
+ end if;
+end process;
+
+end gray_to_bin_rtl;
+
+
+--
+-- extend sign
+
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.std_logic_unsigned.all;
+use ieee.numeric_std.all;
+
+
+entity extend_sign is
+port
+(
+ data_len: in unsigned;
+ data_in: in std_logic_vector;
+ data_out: out std_logic_vector;
+ len_mask: in std_logic_vector
+);
+end entity;
+
+architecture extend_sign_rtl of extend_sign is
+
+constant size: integer := data_in'length;
+signal is_signed: std_logic;
+
+begin
+
+process(data_in, data_len)
+begin
+ -- fixme: modelsim fails without this check
+ -- synthesis translate_off
+ is_signed <= '0';
+ if data_len > 0 then
+ -- synthesis translate_on
+
+ is_signed <= data_in(to_integer(data_len) - 1);
+
+ -- synthesis translate_off
+ end if;
+ -- synthesis translate_on
+
+end process;
+
+process(is_signed, data_in)
+begin
+ if (is_signed = '1') then
+ data_out <= data_in or not len_mask;
+ else
+ data_out <= data_in;
+ end if;
+end process;
+
+end extend_sign_rtl;
diff --git a/testsuite/gna/issue1655/endat_tb.vhdl b/testsuite/gna/issue1655/endat_tb.vhdl
new file mode 100644
index 000000000..ecf4a1932
--- /dev/null
+++ b/testsuite/gna/issue1655/endat_tb.vhdl
@@ -0,0 +1,130 @@
+library IEEE;
+use IEEE.std_logic_1164.all;
+use IEEE.numeric_std.all;
+
+library work;
+
+
+entity ENDAT_TB is
+end ENDAT_TB;
+
+
+architecture BEHAVIORAL of ENDAT_TB is
+
+ -- Component declaration
+ component master
+ port ( -- local clock
+ clk: in std_logic;
+ rst: in std_logic;
+
+ -- generated clock for slave
+ -- fdiv divides CLK_FREQ
+ ma_fdiv: in unsigned;
+ ma_clk: out std_logic;
+
+ -- master out, slave in
+ mosi: out std_logic;
+ miso: in std_logic;
+
+ -- gate to drive output (1 to drive it)
+ gate: out std_logic;
+
+ -- data from slave, and data length
+ data: out std_logic_vector;
+ len: in unsigned;
+
+ -- encoder type
+ enc_type: in integer;
+
+ -- ssi specific control registers
+ ssi_flags: in std_logic_vector;
+ ssi_delay_fdiv: in unsigned
+ ); end component;
+
+-- Configuration
+for u_master: master use entity work.master(absenc_master_rtl);
+
+-- Clock period
+constant period: time := 10 ns;
+
+-- Signals
+signal clk, rst, ma_clk, mosi, miso, gate, down, up: std_logic;
+signal cnt_out: std_logic_vector (3 downto 0);
+signal ma_fdiv, ssi_delay_fdiv, len: unsigned(31 downto 0);
+signal enc_type: integer;
+signal data, ssi_flags: std_logic_vector(31 downto 0);
+
+begin
+
+ -- Instantiate counter...
+ u_master : master port map (
+ clk => clk,
+ rst => rst,
+
+ ma_fdiv => ma_fdiv,
+ ma_clk => ma_clk,
+
+ mosi => mosi,
+ miso => miso,
+
+ gate => gate,
+
+ data => data,
+ len => len,
+
+ enc_type => enc_type,
+
+ ssi_flags => ssi_flags,
+ ssi_delay_fdiv => ssi_delay_fdiv
+
+ );
+
+ -- Process for applying patterns
+ process
+
+ -- Helper to perform one clock cycle...
+ procedure run_cycle is
+ begin
+ clk <= '0';
+ wait for period / 2;
+ clk <= '1';
+ wait for period / 2;
+ end procedure;
+
+ begin
+
+ -- Reset counter...
+ --down <= '1'; up <= '1';
+ --run_cycle;
+ --assert cnt_out = "0000" report "Reset does not work";
+
+ -- Count up and keep state...
+ -- for n in 1 to 20 loop
+ -- down <= '0'; up <= '1';
+ -- run_cycle;
+ -- assert cnt_out = std_logic_vector (to_unsigned (n mod 16, 4)) report "Counting up does not work";
+ -- down <= '0'; up <= '0';
+ -- run_cycle;
+ -- assert cnt_out = std_logic_vector (to_unsigned (n mod 16, 4)) report "Keeping the state does not work";
+ -- end loop;
+
+ -- Count down and keep state...
+ -- down <= '1'; up <= '1';
+ -- run_cycle;
+ -- for n in 15 downto integer(-5) loop
+ -- down <= '1'; up <= '0';
+ -- run_cycle;
+ -- assert cnt_out = std_logic_vector (to_unsigned (n mod 16, 4)) report "Counting down does not work";
+ -- down <= '0'; up <= '0';
+ -- run_cycle;
+ -- assert cnt_out = std_logic_vector (to_unsigned (n mod 16, 4)) report "Keeping the state does not work";
+ -- end loop;
+
+ -- Print a note & finish simulation...
+ -- assert false report "Simulation finished" severity note;
+ -- wait;
+
+ end process;
+
+end BEHAVIORAL;
+
diff --git a/testsuite/gna/issue1655/repro.vhdl b/testsuite/gna/issue1655/repro.vhdl
new file mode 100644
index 000000000..d8d2be2b6
--- /dev/null
+++ b/testsuite/gna/issue1655/repro.vhdl
@@ -0,0 +1,24 @@
+entity repro_ch is
+ generic (v : natural);
+ port (i : bit);
+end;
+
+architecture behav of repro_ch is
+begin
+ assert v > 5;
+end;
+
+entity repro is
+end;
+
+architecture behav of repro is
+ component comp is
+ port (i : bit);
+ end component;
+
+ signal s : bit;
+
+ for inst : comp use entity work.repro_ch(behav);
+begin
+ inst: comp port map (i => s);
+end;
diff --git a/testsuite/gna/issue1655/repro1.vhdl b/testsuite/gna/issue1655/repro1.vhdl
new file mode 100644
index 000000000..c33e1f52d
--- /dev/null
+++ b/testsuite/gna/issue1655/repro1.vhdl
@@ -0,0 +1,25 @@
+entity repro1_ch is
+ generic (v : natural);
+ port (i : bit);
+end;
+
+architecture behav of repro1_ch is
+begin
+ assert v > 5;
+end;
+
+entity repro1 is
+end;
+
+architecture behav of repro1 is
+ component comp is
+ generic (v : natural);
+ port (i : bit);
+ end component;
+
+ signal s : bit;
+
+ for inst : comp use entity work.repro1_ch(behav);
+begin
+ inst: comp port map (i => s);
+end;
diff --git a/testsuite/gna/issue1655/testsuite.sh b/testsuite/gna/issue1655/testsuite.sh
new file mode 100755
index 000000000..b977e14e1
--- /dev/null
+++ b/testsuite/gna/issue1655/testsuite.sh
@@ -0,0 +1,16 @@
+#! /bin/sh
+
+. ../../testenv.sh
+
+GHDL_STD_FLAGS=-fsynopsys
+analyze absenc_pkg.vhdl absenc_utils.vhdl absenc_master.vhdl absenc_master_endat.vhdl endat_tb.vhdl
+elab_failure endat_tb
+
+analyze repro.vhdl
+elab_failure repro
+
+analyze_failure repro1.vhdl
+
+clean
+
+echo "Test successful"