+ Post New Thread
Results 1 to 7 of 7
  1. #1
    Full Member level 5
    Points: 2,369, Level: 11

    Join Date
    May 2014
    Posts
    279
    Helped
    28 / 28
    Points
    2,369
    Level
    11

    VHDL use of 'Z' std logic for bus, or should one use interconnect?

    Hello all,

    Basically in simulation land the following works. However the question is can an FPGA handle tristating internally, because on hardware I've just bricked the device.

    OVERSEER takes response from peripherals and sends response to master. If the system times out then dtackb is set to mirror the csb & subsequently the bus acknowledges a response and fails "gracefully"
    Code VHDL - [expand]
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    
    -- Description : This block will forward the pcie -> csif command onto the rest of the system.
    --               However it shall forward a response after a watchdog timer & it shall only allow addresses 
    --               within the range allowed
    library ieee;
        use ieee.std_logic_1164.all;
    library universal_lib;
    library xil_defaultlib;
     
    entity local_bus_overseer is
        port
        (
            sys_clk       : in    std_logic;
            reset         : in    std_logic;
     
            MGT_CSb       : in    Std_Logic;
            MGT_ADD       : in    Std_Logic_Vector(31 downto 0);
            MGT_DATA_IN   : in    Std_Logic_Vector(31 downto 0);
            MGT_DATA_OUT  : out   Std_Logic_Vector(31 downto 0);
            MGT_writeb    : in    Std_Logic;
            MGT_DTACKb    : out   Std_Logic;
     
            lb_CSb        : out   std_logic;
            lb_ADDRESS    : out   Std_Logic_Vector(31 downto 0);
            lb_DATA_IN    : out   Std_Logic_Vector(31 downto 0);
            lb_DATA_out   : in    Std_Logic_Vector(31 downto 0);
            lb_WRITEb     : out   Std_Logic;
            lb_dtackb     : in    std_logic
        );
    end entity local_bus_overseer;
     
     
    architecture rtl of local_bus_overseer is
     
        type fsm_t is (idle, transfer, timeout_trig);
        signal fsm : fsm_t;
        signal MGT_CSb_reg       :  Std_Logic;
        signal MGT_ADD_reg       :  Std_Logic_Vector(31 downto 0);
        signal MGT_DATA_IN_reg   :  Std_Logic_Vector(31 downto 0);
        signal MGT_DATA_OUT_reg  :  Std_Logic_Vector(31 downto 0);
        signal MGT_writeb_reg    :  Std_Logic;
        signal MGT_DTACKb_reg    :  Std_Logic;
        signal timer_reset       :  std_logic;
        signal timer_go          :  std_logic;
        signal timeout           :  std_logic;
        signal mux_ctrl          :  std_logic;
        signal fsm_slv           :  std_logic_vector(1 downto 0);
        COMPONENT overseer_ila
            PORT (
                clk : IN STD_LOGIC;
                probe0 : IN STD_LOGIC_VECTOR(1 DOWNTO 0); 
                probe1 : IN STD_LOGIC_VECTOR(0 DOWNTO 0); 
                probe2 : IN STD_LOGIC_VECTOR(0 DOWNTO 0); 
                probe3 : IN STD_LOGIC_VECTOR(0 DOWNTO 0); 
                probe4 : IN STD_LOGIC_VECTOR(0 DOWNTO 0); 
                probe5 : IN STD_LOGIC_VECTOR(0 DOWNTO 0);
                probe6 : IN STD_LOGIC_VECTOR(31 DOWNTO 0)
            );
        END COMPONENT  ;
     
    begin
     
        --wait for 100 us
        u_timer : entity universal_lib.delay_timer 
        generic map
        (
            delay_unit => 1 us,
            clk_period => 8 ns
        )
        port map
        (
            clk             => sys_clk,
            rst             => timer_reset,
            time_delay      => 10,
            start_delay     => timer_go,
            timer_complete  => timeout
        );
     
        reg : process(sys_clk) is
        begin
     
            if rising_edge(sys_clk) then
                if reset='1' then
                    MGT_CSb_reg      <= '1';
                    MGT_ADD_reg      <= (others => '0');
                    MGT_DATA_IN_reg  <= (others => '0');
                    MGT_DATA_OUT_reg <= (others => '0');
                    MGT_writeb_reg   <= '1';
                    MGT_DTACKb_reg   <= '1';
                else
                    MGT_CSb_reg      <= MGT_CSb;
                    MGT_ADD_reg      <= MGT_ADD;
                    MGT_DATA_IN_reg  <= MGT_DATA_IN;
                    MGT_writeb_reg   <= MGT_writeb;
                    for i in MGT_DATA_OUT_reg'range loop
                        if lb_DATA_out(i) = 'Z' then
                            MGT_DATA_OUT_reg(I) <= '1';
                        else
                            MGT_DATA_OUT_reg(i) <= lb_DATA_out(i);
                        end if;
                    end loop;
                    if lb_dtackb /= '0' then
                        MGT_DTACKb_reg   <= '1';
                    else
                        MGT_DTACKb_reg   <= lb_dtackb;
                    end if;
                end if;
            end if;
        end process;
     
     
        ctrl : process(sys_clk) is
        begin
     
            if rising_edge(sys_clk) then
     
                if reset='1' then
                    timer_reset <= '1';
                    fsm         <= idle;
                    timer_go    <= '0';
                    mux_ctrl    <= '0';
                    fsm_slv     <= "00";
     
                else
                    timer_go <= '0';
                    mux_ctrl <= '0';
     
                    case fsm is
     
                        when idle => 
                            fsm_slv <= "01";
                            timer_reset <= '1';
                            -- csb_trig
                            if MGT_CSb='0' and MGT_CSb_reg='1' then
                                timer_reset <= '0';
                                fsm         <= transfer;
                                timer_go    <= '1';
                            end if;
     
                        when transfer => 
                            -- dtackb returned
                            fsm_slv <= "10";
                            if lb_dtackb = '0' and MGT_DTACKb_reg='1' then
                                fsm         <= idle;
                                timer_reset <= '1';
                            end if;
                            if timeout = '1' then
                                fsm <= timeout_trig;
                            end if;
     
                        when timeout_trig => 
                            -- fail gracefully
                            fsm_slv <= "11";
                            mux_ctrl <= '1';
                            if MGT_CSb='1' and MGT_CSb_reg='0' then
                                fsm <= idle;
                            end if;
     
                        when others => 
                            fsm <= timeout_trig;
     
                    end case;
                end if;
            end if;
        end process;
     
        MGT_DATA_OUT          <= MGT_data_out_reg when mux_ctrl='0' else x"DEADFEED"; --bad5ec for blocks inside
        MGT_DTACKb            <= MGT_dtackb_reg   when mux_ctrl='0' else MGT_CSb_reg;
        --MGT_bresp             <= "00"             when mux_ctrl='0' else "10";
        --MGT_rresp             <= "00"             when mux_ctrl='0' else "10";
        lb_CSb                <= MGT_CSb_reg      when mux_ctrl='0' else '1';
        lb_ADDRESS            <= MGT_ADD_reg      when mux_ctrl='0' else (others => '0');
        lb_DATA_IN            <= MGT_DATA_IN_reg  when mux_ctrl='0' else (others => '0');
        lb_WRITEb             <= MGT_WRITEb_reg   when mux_ctrl='0' else '1';
     
     
        u_ila : overseer_ila 
        port map
        (
            clk => sys_clk,
            probe0 => fsm_slv,
            probe1(0) => mux_ctrl,
            probe2(0) => timer_go,
            probe3(0) => timeout,
            probe4(0) => timer_reset,
            probe5(0) => lb_dtackb,
            probe6 => lb_DATA_out
        );
     
    end architecture;

    Here is an example of the version registers, whereby if the address is within range then it response otherwise the dtackb is left in tristate 'Z'.
    Code VHDL - [expand]
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    
    library ieee;
    use ieee.std_logic_1164.all;
    Library CONFIGURATION_lib;
        Use CONFIGURATION_lib.Local_Bus_Configuration.ALL;
     
    entity version_reg is
        generic 
        (
            lower_address      :  std_logic_vector(31 downto 0) := x"00000100";
            upper_address      :  std_logic_vector(31 downto 0) := x"000001A0"
        );
        port
        (
        clk       : in    std_logic;
        reset     : in    std_logic;
        writeb    : in    std_logic;
        csb       : in    std_logic;
        address   : in    std_logic_vector(31 downto 0);
        data_out  : out   std_logic_vector(31 downto 0);
        dtackb    : out   std_logic
    );
    end entity version_reg;
    architecture rtl of version_reg is
     
        signal general_read_data : std_logic_vector(31 downto 0);
      --Signal PART_NO_VALUE           : Std_Logic_Vector(15 downto 0);
      --Signal ISSUE_VALUE             : Std_Logic_Vector(15 downto 0);
      Signal COMPILE_YEAR_VALUE      : Std_Logic_Vector(15 downto 0);
      Signal COMPILE_DAY_VALUE       : Std_Logic_Vector(15 downto 0);
      Signal COMPILE_TIME_VALUE      : Std_Logic_Vector(15 downto 0);
      Signal COMPILE_TOOL_VALUE      : Std_Logic_Vector(15 downto 0);
      signal dtackb_int : std_logic;
     
    begin
     
        dtackb   <= dtackb_int        when address >= lower_address and address <= upper_address else 'Z';
        data_out <= general_read_data when address >= lower_address and address <= upper_address else (others => 'Z');
     
        --PART_NUMBER_LOWER               <= PART_NUMBER(5 to 5);
     
        --PART_NO_VALUE                   <= conv_hex_to_std(PART_NUMBER(1 to 4));
     
        --ISSUE_VALUE(15 downto 12)       <= conv_hex_to_std(PART_NUMBER_LOWER);
        --ISSUE_VALUE(11 downto  8)       <= (Others => '0');
        --ISSUE_VALUE( 7 downto  0)       <= conv_alpha_to_std(ISSUE);
     
        COMPILE_YEAR_VALUE              <= x"2019";
     
        COMPILE_DAY_VALUE(15 downto 8)  <= x"10";
        COMPILE_DAY_VALUE( 7 downto 0)  <= x"07";
        COMPILE_TIME_VALUE(15 downto 8) <= x"16";
        COMPILE_TIME_VALUE( 7 downto 0) <= x"20";
        COMPILE_TOOL_VALUE              <= x"7E28";
     
        reg_proc : process(clk) is
        begin
     
            if rising_edge(clk) then
                if reset = '1' then 
                    dtackb_int <= '1';
                    general_read_data <= (others => '0'); 
                else
                    dtackb_int <= '1';
                    general_read_data <= (others => '0'); 
                    if address >= lower_address and address <= upper_address then
                        if csb = '0' then
                            Case ADDRESS(GENERAL_ADDR_RANGE) is
                                --When PART_NO_UPPER_ADDR => GENERAL_READ_DATA(15 downto 0) <= PART_NO_VALUE; dtackb_int <= '0';
                                --When PART_NO_LOWER_ADDR => GENERAL_READ_DATA(15 downto 0) <= ISSUE_VALUE; dtackb_int <= '0';
                                When COMP_YEAR_ADDR     => GENERAL_READ_DATA(15 downto 0) <= COMPILE_YEAR_VALUE; dtackb_int <= '0';
                                When COMP_DAY_ADDR      => GENERAL_READ_DATA(15 downto 0) <= COMPILE_DAY_VALUE; dtackb_int <= '0';
                                When COMP_HOUR_ADDR     => GENERAL_READ_DATA(15 downto 0) <= COMPILE_TIME_VALUE; dtackb_int <= '0';
                                When COMP_TOOL_ADDR     => GENERAL_READ_DATA(15 downto 0) <= COMPILE_TOOL_VALUE; dtackb_int <= '0';
                                when others => GENERAL_READ_DATA <= x"bad0" & lower_address(31 downto 16); dtackb_int <= '0';
                            end case;
                        end if;
                    end if;
                end if;
            end if;
        end process;
     
    end architecture rtl;

    •   AltAdvertisement

        
       

  2. #2
    Advanced Member level 5
    Points: 37,911, Level: 47
    Achievements:
    7 years registered

    Join Date
    Jun 2010
    Posts
    6,874
    Helped
    2019 / 2019
    Points
    37,911
    Level
    47

    Re: VHDL use of 'Z' std logic for bus, or should one use interconnect?

    Internal tri-states haven't existed inside FPGAs (other than the IO pins) for about 20 years. Any tri-state style code will be converted to muxes in synth tools so it should all still work.

    BUT

    your code appears to have no tri-states in it. A tri-state driver would be able to read and write to the same signal - your code appears to have discrete ins and outs, whereas a tri-state would be done via an inout. I only see muxes in your own code. You also have code that checks for 'Z' state, which is impossible in real hardware (it will probably be removed in synthesis).

    Basically, dont use internal tri-states.

    I also doubt you have bricked your device from internal logic. If it is bricked, you probably did something bad with the power rails (nothing to do with logic).



  3. #3
    Full Member level 5
    Points: 2,369, Level: 11

    Join Date
    May 2014
    Posts
    279
    Helped
    28 / 28
    Points
    2,369
    Level
    11

    Re: VHDL use of 'Z' std logic for bus, or should one use interconnect?

    Not ...bricked bricked, but dead to comms now. It works when I put the old build on, which used an interconnect setup with a huge slv of dtackbs AND reduced.

    I'm looking at the schematic and it's not mux'd the supposed dtackb output of one peripheral are fed into another peripheral as an imput, which not representative of the code.

    Could you show me how it could work, or more accurately what you'd do for
    comms bus
    |
    |
    device1 -----device 2




    Regards,



    •   AltAdvertisement

        
       

  4. #4
    Advanced Member level 5
    Points: 37,911, Level: 47
    Achievements:
    7 years registered

    Join Date
    Jun 2010
    Posts
    6,874
    Helped
    2019 / 2019
    Points
    37,911
    Level
    47

    Re: VHDL use of 'Z' std logic for bus, or should one use interconnect?

    Use a mux.



  5. #5
    Super Moderator
    Points: 31,607, Level: 43
    ads-ee's Avatar
    Join Date
    Sep 2013
    Location
    USA
    Posts
    7,311
    Helped
    1719 / 1719
    Points
    31,607
    Level
    43

    Re: VHDL use of 'Z' std logic for bus, or should one use interconnect?

    Never tried stuff like this:
    Code:
                        if lb_DATA_out(i) = 'Z' then
                            MGT_DATA_OUT_reg(I) <= '1';
                        else
                            MGT_DATA_OUT_reg(i) <= lb_DATA_out(i);
                        end if;
    don't know what synthesis will do with it as a 'Z' can never exist inside an FPGA after the hi-Z condition of the external pin goes through the I/O input buffer. You'll either get a 1 (most likely) or a 0 internal to the FPGA array.



  6. #6
    Super Moderator
    Points: 260,240, Level: 100
    Awards:
    1st Helpful Member

    Join Date
    Jan 2008
    Location
    Bochum, Germany
    Posts
    45,445
    Helped
    13828 / 13828
    Points
    260,240
    Level
    100

    Re: VHDL use of 'Z' std logic for bus, or should one use interconnect?

    'Z' or 'X' isn't a detectable state in synthesized logic.

    Respectively Quartus synthesis tool assumes that 'Z' can't be sensed on input and proceeds to the else condition.

    The version_reg code looks synthesizable to me and can be expected to infer a multiplexer.



    •   AltAdvertisement

        
       

  7. #7
    Super Moderator
    Points: 31,607, Level: 43
    ads-ee's Avatar
    Join Date
    Sep 2013
    Location
    USA
    Posts
    7,311
    Helped
    1719 / 1719
    Points
    31,607
    Level
    43

    Re: VHDL use of 'Z' std logic for bus, or should one use interconnect?

    Quote Originally Posted by FvM View Post
    'Z' or 'X' isn't a detectable state in synthesized logic.

    Respectively Quartus synthesis tool assumes that 'Z' can't be sensed on input and proceeds to the else condition.

    The version_reg code looks synthesizable to me and can be expected to infer a multiplexer.
    Regardless of it being synthesizable, IMO it is wrong to code like this.

    As VHDL is a hardware description language and this can't be implemented in fpgaware you are not describing hardware anymore. Hence why I didn't have much of a clue how Quartus/Vivado/ISE/etc would actually handle this type of "wrong" code as i always code with the resulting hardware intent in mind.



--[[ ]]--