Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

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

Status
Not open for further replies.

wtr

Full Member level 5
Joined
May 1, 2014
Messages
299
Helped
29
Reputation
58
Reaction score
25
Trophy points
1,308
Activity points
4,108
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;

 

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).
 

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,
 

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.
 

'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.
 

'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.
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top