Search code examples
vhdl

Cannot drive signal to '1' or '0'


I have a very basic problem. I have a clock, a counter, and a signal indicating that two other signals, which are routed to outputs in the final implementation on an FPGA, should change.

My problem is that when I simulate the following testbench, the cs_a_o and cs_g_o are driven to 'X' rather than '0'. When the problem started I was driving the signal several places, but I can't see how the code can be simpler, given it must be in processes (final implementation will handle serial communication)

In my efforts to solve the problem I've made a new signal, can, which does the same as cs_X_o does and at the same time - except it isn't in the port map since it is an internal signal. I don't understand why one signal does as expected, while the other two aren't, even though they are subject to the same manipulations in the code.

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;

ENTITY tb IS
END tb;

ARCHITECTURE behavior OF tb IS 
    -- Component Declaration for the Unit Under Test (UUT)

    COMPONENT test
    PORT(
         clk : IN  std_logic;
         CS_A_O : out  std_logic;
         CS_G_O : out  std_logic
         );
    END COMPONENT;

   --Inputs
   signal clk : std_logic := '0';

    --Outputs
    signal counter : integer range 0 to 125000 := 0;
    signal counter_next : integer range 0 to 125000 := 0;
    signal CS_A_O : std_logic := '1';
    signal CS_G_O : std_logic := '1';
    signal cs : std_logic := '1';
    signal can : std_logic := '1';
   -- Clock period definitions
   constant clk_period : time := 20 ns;

BEGIN

    -- Instantiate the Unit Under Test (UUT)
   uut: test PORT MAP (
          clk => clk,
          CS_A_O => CS_A_O,
          CS_G_O => CS_G_O
        );

   -- Clock process definitions
   clk_process :process
   begin
        clk <= '0';
        wait for clk_period/2;
        clk <= '1';
        wait for clk_period/2;
    end process;

    counter_process : process (clk) begin
        if (rising_edge(clk)) then
            counter <= counter_next;
            counter_next <= counter_next + 1;
            if (counter = 199) then
                counter <= 0;
                counter_next <= 1;
                cs <= not cs;
            end if;
        end if;
    end process;

    switching : process(clk) begin
        if (rising_edge(clk)) then
            if cs = '1' and can = '1' then
                can <= not can; -- this does as expected
                cs_a_o <= not cs_a_o; -- this doesn't work
            elsif cs = '0' and can = '0' then
                can <= not can; -- this does as expected
                cs_g_o <= not cs_g_o; -- this doesn't work
            end if;
        end if;
    end process;

    ASSERT ((CS_A_O = '1' or CS_A_O = '0')
    and (CS_G_O = '1' or CS_G_O = '0'))
        report "It's dead wrong. CS_A_O = " & std_logic'image(CS_A_O) &
        "  CS_G_O = " & std_logic'image(CS_G_O)
        severity error;
END;

Solution

  • You have two drivers for cs_a_o and cs_g_o. First there's the instantiation of component test with the label uut. Then there's your process switching.

    Try commenting out uut:

     -- Instantiate the Unit Under Test (UUT)
     -- uut: test PORT MAP (
     --        clk => clk,
     --        CS_A_O => CS_A_O,
     --        CS_G_O => CS_G_O
     --      );
    

    Any concurrent statement assigning a signal creates a driver. The value of all drivers for resolved types contribute to the effective value. In the package body std_logic_1164 you can find the resolution table and resolution function for std_logic.