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.

Newbie/hobbiest question: VHDL simulator unexpectedly shows "X" (forcing unknown)

Status
Not open for further replies.

bit4man

Newbie
Newbie level 2
Joined
Feb 13, 2021
Messages
2
Helped
0
Reputation
0
Reaction score
0
Trophy points
1
Activity points
25
I've created a few "how to learn" VHDL projects in Vivado, and started a quest to control a simple TM1638 that I have no problems with using a MCU, but it seemed a good project to get better at FPGA programming. For now I am using VHDL - that's what I started learning - and what I have right now is no where close to done, but my initial tests shows "something is wrong" and I'm not sure I understand why.
Screenshot from 2021-02-13 13-30-31.png
This illustrates the error/issue I'm seeing. w_TX_STB is not showing high (and it's not sync'ed correctly) but shows X instead. I understand that this can be due to it being unintialized ; it seem to be to me, so I'm a bit lost here. Here's the relevant code (it's a very small project for now):
Code:
tm1638.vhd
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity tm1638 is
 
  PORT (
     i_clock     : in std_logic;
     i_reset     : in std_logic := '0'; -- active high
     i_setled    : in std_logic_vector(7 downto 0) := (others => '0');
     i_enable    : in std_logic := '0';
     i_num1      : in std_logic_vector(10 downto 0) := (others => '0');
     i_num2      : in std_logic_vector(10 downto 0) := (others => '0');
     o_tx_serial : out std_logic;
     o_tx_stb    : out std_logic;
     o_btpush    : out std_logic_vector(7 downto 0)
  );

end tm1638;

architecture beh of tm1638 is
  constant CMD_TURNON  : std_logic_vector(7 downto 0) := X"8F"; 
  constant CMD_TURNOFF : std_logic_vector(7 downto 0) := X"87";
  constant CMD_SIGNLE  : std_logic_vector(7 downto 0) := X"44";
  constant CMD_SEQ     : std_logic_vector(7 downto 0) := X"40";
  constant CMD_READB   : std_logic_vector(7 downto 0) := X"42"; 
 
  type comstate is (turnon, turnoff, statewait, idle, dispnum1, dispnum2, displed, readkeys);
 
  component ser_tx is
    port (
      i_clk       : in  std_logic;
      i_tx_dv     : in  std_logic;
      i_tx_byte   : in  std_logic_vector(7 downto 0);
      o_tx_active : out std_logic;
      o_tx_serial : out std_logic;
      o_tx_done   : out std_logic
      );
  end component ser_tx;
 
  signal r_CLOCK     : std_logic                    := '0';
  signal r_TX_DV     : std_logic                    := '0';
  signal r_TX_BYTE   : std_logic_vector(7 downto 0) := (others => '0');
  signal w_TX_SERIAL : std_logic;
  signal w_TX_ACTIVE : std_logic;
  signal w_TX_DONE   : std_logic;
 
  signal s_enabled   : std_logic := '0';
  signal s_oldstate   : comstate := idle;
  signal s_comstate   : comstate := idle;
  signal s_nextstate  : comstate := idle;
  signal s_nextcomstate : comstate := idle;
  signal s_tx_stb     : std_logic := '0';

begin
  -- Instantiate SER transmitter
  SER_TX_INST : ser_tx
    port map (
      i_clk       => r_CLOCK,
      i_tx_dv     => r_TX_DV,
      i_tx_byte   => r_TX_BYTE,
      o_tx_active => w_TX_ACTIVE,
      o_tx_serial => w_TX_SERIAL,
      o_tx_done   => w_TX_DONE
      );
      
   r_clock <= i_clock;
   o_tx_serial <= w_TX_SERIAL;
   o_tx_stb <= s_tx_stb;
  
   statesys : process(i_clock)
   begin
     if rising_edge(i_clock)
     then
       if i_reset='1'
       then
         r_TX_BYTE <= (others => '0');
         r_TX_DV         <= '0';
         s_enabled       <= '0';
         s_comstate      <= idle;
         s_nextcomstate  <= idle;
         s_tx_stb        <= '0';
       else
         case s_comstate is
          when idle =>
            if i_enable /= s_enabled
            then
              s_oldstate <= s_comstate; -- remember old state
              s_enabled   <= i_enable;
              if i_enable='1' then s_comstate <= turnon; else s_comstate <= turnoff; end if;
            else
              if s_oldstate/=idle then s_comstate <= s_oldstate; else s_comstate <= dispnum1; end if;
              s_oldstate <= idle;
            end if;
            s_tx_stb <= '0';
          when statewait =>
             if r_TX_DV = '1'
             then
                 r_TX_DV  <= '0'; -- Switch off once set
                 s_tx_stb <= '1';
             end if;
             if w_TX_DONE='1'
             then
               s_tx_stb <= '0';
               s_comstate <= s_nextstate;
             else
               s_comstate <= statewait;
             end if;
          when turnon =>
              r_TX_DV <= '1';
              r_TX_BYTE <= CMD_TURNON;
              s_nextstate <= idle;
              s_comstate <= statewait;
          when turnoff =>
              r_TX_DV <= '1';
              r_TX_BYTE <= CMD_TURNOFF;
              s_nextstate <= idle;
              s_comstate <= statewait;
          when dispnum1 =>
              s_nextstate <= dispnum2;
              s_comstate <= statewait;
          when dispnum2 =>
              s_nextstate <= displed;
              s_comstate <= statewait;
          when displed =>
              s_nextstate <= readkeys;
              s_comstate <= statewait;
          when readkeys =>
              s_nextstate <= idle;
              s_comstate <= statewait;
          when others =>
            s_comstate <= idle;
         end case; 
       end if;
     end if;
   end process statesys;
 
end beh;

SER_TX:

Code:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.numeric_std.all;

entity SER_TX is
  Port ( i_Clk : in STD_LOGIC;
         i_TX_DV : in STD_LOGIC;
         i_TX_Byte : in STD_LOGIC_VECTOR (7 downto 0);
         o_TX_Active : out STD_LOGIC;
         o_TX_Serial : out STD_LOGIC;
         o_TX_Done : out STD_LOGIC);
end SER_TX;

architecture RTL of SER_TX is
  type t_SM_Main is (s_Idle, s_TX_Data_Bits, s_Cleanup, s_CleanupSleep);
  signal r_SM_Main : t_SM_Main := s_Idle;
  constant c_cycles : integer := 5;
 
  signal r_Bit_Index : integer range 0 to 7 := 7;  -- 8 Bits Total
  signal r_TX_Data   : std_logic_vector(7 downto 0) := (others => '0');
  signal r_TX_Done   : std_logic := '0';
  signal r_sleepcycles : integer range 0 to 10 := 0;
begin
  p_SER_TX : process (i_Clk)
  begin
    if rising_edge(i_Clk) then
        
      case r_SM_Main is
 
        when s_Idle =>
          o_TX_Serial <= '1';         -- Drive Line High for Idle
          r_TX_Done   <= '0';
          r_Bit_Index <= 7;
 
          if i_TX_DV = '1' then
            o_TX_Active <= '1';
            r_TX_Data <= i_TX_Byte;
            r_SM_Main <= s_TX_Data_Bits;
          else
            r_SM_Main <= s_Idle;
            o_TX_Active <= '0';
          end if;
                  
        -- Wait g_CLKS_PER_BIT-1 clock cycles for data bits to finish         
        when s_TX_Data_Bits =>
          o_TX_Serial <= r_TX_Data(r_Bit_Index);
                      
            -- Check if we have sent out all bits
            if r_Bit_Index > 0 then
              r_Bit_Index <= r_Bit_Index - 1;
              r_SM_Main   <= s_TX_Data_Bits;
            else
              r_Bit_Index <= 7;
              r_SM_Main   <= s_Cleanup;
            end if;
                    
        -- Stay here 1 clock
        when s_Cleanup =>
          r_TX_Done   <= '1';
          if r_sleepcycles = c_cycles then
            o_TX_Active <= '0';
            r_SM_Main <= s_idle;
            r_sleepcycles <= 0;
          else
            r_sleepcycles <= r_sleepcycles + 1;
            r_SM_Main <= s_Cleanup;
          end if;
                                
        when others =>
          r_SM_Main <= s_Idle;
 
      end case;
    end if;
  end process p_SER_TX;
 
  o_TX_Done <= r_TX_Done;
end RTL;

Finally the test unit (tm1638_tb - very simple for now):
Code:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity tm1638_tb is
end tm1638_tb;

architecture tmbeh of tm1638_tb is
  component tm1638 is
  port (
     i_clock     : in std_logic;
     i_reset     : in std_logic;
     i_setled    : in std_logic_vector(7 downto 0) := (others => '0');
     i_enable    : in std_logic := '0';
     i_num1      : in std_logic_vector(10 downto 0) := (others => '0');
     i_num2      : in std_logic_vector(10 downto 0) := (others => '0');
     o_tx_serial : out std_logic;
     o_tx_stb    : out std_logic;
     o_btpush    : out std_logic_vector(7 downto 0)
   );
  end component tm1638;
  
  
  signal s_CLOCK     : std_logic                    := '0';
  signal s_reset     : std_logic                    := '0';
  signal s_enable    : std_logic                    := '0';
  signal s_setled    : std_logic_vector(7 downto 0) := (others => '0');
  signal s_num1      : std_logic_vector(10 downto 0) := (others => '0');
  signal s_num2      : std_logic_vector(10 downto 0) := (others => '0');
  signal w_TX_STB    : std_logic;
  signal w_TX_SERIAL : std_logic;
  signal w_btpush    : std_logic_vector(7 downto 0);
 
  begin
    TM1638_INST : tm1638
      port map (
        i_clock    => s_clock,
        i_reset    => s_reset,
        i_setled   => s_setled,
        i_enable   => s_enable,
        i_num1     => s_num1,
        i_num2     => s_num2,
        o_tx_serial=> w_TX_SERIAL,
        o_tx_stb   => w_TX_STB,
        o_btpush   => w_btpush
    );
  
  s_clock <= not s_clock after 50 ns;
 
  process is
  begin
    w_TX_STB <= '0';
  
    wait until rising_edge(s_clock);
    wait until rising_edge(s_clock);
    s_reset <= '1';
    wait for 10ns;
    
    wait until rising_edge(s_clock);
    s_reset <= '0';
    s_enable <= '1';
    
    wait for 2us;
        
    assert false report "Tests Complete" severity failure;
    
  end process;

All the states that are active during the current test are setting s_tx_stb to a value.
STB (Strobe) is what the TM1638 uses to indicate where there are commands/data - sorta like an "enable" flag. It's important that it's set at 8 bit boundaries and what I thought would be my challenge (not there yet as I found this challenge instead) is that some commands have multiple bytes being sent while STB is high. This explains the rather odd structure, which of course may be very wrong.
 

w_TX_STB has multiple drivers. Remove assignment in process.
 

    bit4man

    Points: 2
    Helpful Answer Positive Rating
w_TX_STB has multiple drivers. Remove assignment in process.
I guess I never looked at the test-unit as part of the whole. My fault.
I am curious - I thought the compiler would error out when there was multiple drivers? I didn't see one here? Is there a way you can get the Vivado IDE to help identify issues like this? I imagine complex projects would be hard to find issues like this in?
 

std_logic(_vector) is a resolved type, hence it allows multiple drivers. This allows things like tri-state IO to to be simulated in HDL. Hence it is not an error in simulation for multiple drivers. Synthesis likely would have picked this up (only in your synthesisable code), but obviously it needs to go through the whole synthesis.

It is possible to get a compilation error by using a non-resolved type. This will be any type not based on std logic, such as integer, bit, std_ulogic. For a while, a some of people were advocating the use of std_ulogic(_vector) everywhere to avoid the problem you have just had. Multiple drivers are illegal in compilation. But the problem was in standards prior to vhdl 2008 std_logic_vector and std_ulogic_vector could not be directly connected and because std_logic_vector was everywhere, it is not the defacto standard. This was fixed in VHDL 2008 (std_logic_vector was made a subtype of std_ulogic_vector rather than a completly independent type) but the damage was already done and std_logic_vector is the pervasive type.

Yes, it can sometimes be annoying finding multiple drivers, but it is pretty obvious when you have Xs propogate through a design, and any good self checking testbench should pick up on it.
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top