Sida 1 av 2

Hjälp med VHDL felsökning

Postat: 11 mars 2009, 17:55:50
av LHelge
Har precis fått lite tid över att leka med Spartan 3A evalkittet från avnet vi samköpte här på forumet för ett tag sedan, är helt och hållet nybörjare på VHDL och jag tänkte börja med att skicka och ta emot seriell data. Resultatet är följande state machine som funkar perfekt vid simulering men vid syntes får jag felet:

line 98: Signal next_state cannot be synthesized, bad synchronous description. The description style you are using to describe a synchronous element (register, memory, etc.) is not supported in the current software release.

jag använder Xilinx webpack och rad 98 är den som börjar med NEXT_STATE_DECODE:

Någon som kan peka mig i rätt riktning? Förmodligen har jag väl skapat en oönskad latch någonstans...

Kod: Markera allt

entity uart_rx is
    Port ( clk : in  STD_LOGIC;
           reset : in  STD_LOGIC;
           rx : in  STD_LOGIC;
           done : out  STD_LOGIC;
           data : out  STD_LOGIC_VECTOR (7 downto 0));
end uart_rx;

architecture Behavioral of uart_rx is
	signal counter : STD_LOGIC_VECTOR(7 downto 0) := "00000000";
	signal c_enable : STD_LOGIC := '0';
	signal rx_done : STD_LOGIC := '0';
	signal rx_data : STD_LOGIC_VECTOR(9 downto 0) := "0000000000";
	signal bit_counter : integer range 0 to 10;
	type state_type is (idle, start, sample, delay, ready);
	signal state, next_state : state_type;
begin
	-- Clock used for delays
	DELAY_CLOCK: process (clk) 
	begin
		if clk='1' and clk'event then
			if c_enable='1' then
				counter <= counter + 1;
			else
				counter <= (others => '0');
			end if;
		end if;
	end process; 

	SYNC_PROC: process (clk)
   begin
      if (clk'event and clk = '1') then
         if (reset = '1') then
            state <= idle;
            data <= "00000000";
				done <= '0';
         else
            state <= next_state;
				data <= rx_data(8 downto 1);
				done <= rx_done;
         end if;        
      end if;
   end process;
 
   OUTPUT_DECODE: process (state)
   begin
		-- Enable counter for waiting states
		if state = start OR state = delay then
			c_enable <= '1';
		else
			c_enable <= '0';
		end if;
		
		-- Set done output if start & stop are OK and reset bit counter on done state 
		if state = ready then
			rx_done <= rx_data(9) and not rx_data(0);
			bit_counter <= 0;
		else
			rx_done <= '0';
      end if;
		
		-- Shift in the sampled bit and increase bit counter
		if state = sample then
			rx_data <= rx & rx_data(9 downto 1);
			bit_counter <= bit_counter + 1;
		end if;	
   end process;
 
   NEXT_STATE_DECODE: process (state, rx, counter, bit_counter)
   begin
      --declare default state for next_state to avoid latches
      next_state <= state;  --default is to stay in current state

      case (state) is
         when idle =>
            if rx'event AND rx = '0' then
               next_state <= start;
            end if;
         when start =>
            if counter = 69 then -- = 69 which is half a bit for 115200 baud and 16 MHz
               next_state <= sample;
            end if;
         when sample =>
				if bit_counter < 10 then -- one start bit, eight data bits and one stop bit
					next_state <= delay;
				else
					next_state <= ready;
				end if;
			when delay =>
            if counter = 139 then --  = 139 which is one bit time for 115200 baud and 16 MHz
               next_state <= sample;
            end if;
			when ready =>
            next_state <= idle;
      end case;      
   end process;
end Behavioral;

Re: Hjälp med VHDL felsökning

Postat: 11 mars 2009, 18:05:18
av cyr
Nu är min VHDL väldigt rostig (Verilog FTW!), men är inte problemet att du skrivit kod som använder en flank på "rx" som en del av logiken.

Om du skippar rx'event tror jag du får ren kombinatorik på next_state (vilket jag antar är vad du vill).

Re: Hjälp med VHDL felsökning

Postat: 11 mars 2009, 18:14:28
av LHelge
Det är ju såklart helt onödigt efter som mina states uppdateras synkront.

Tack så mycket!

Re: Hjälp med VHDL felsökning

Postat: 13 mars 2009, 12:45:22
av AAVE
avnet samköp? hoppsan, det missade jag :(


en fråga: kommer RX direkt från en pinne?

Re: Hjälp med VHDL felsökning

Postat: 14 mars 2009, 13:53:16
av LHelge
Ja, det gör det från en Cypress PSoC som vidarebefordrar det från USB.

Har inte riktigt fått det att fungera än. Är det någon annan som lyckats implementera UART på sin avnet-moj? Tycker att dokumentationen kring vad som händer inne i PSoC vad gäller UART är lite bristfällig. Kan lägga upp lite mer info om vad jag gjort senare så kanske nån kan hjälpa till.

Re: Hjälp med VHDL felsökning

Postat: 14 mars 2009, 14:56:02
av strombom
LHelge: Jag gissar att anledningen till att AAVE ställde den frågan var att du bör dubbelbuffra den, du bör alltså klocka den genom en vippa innan du läser av värdet.

Så här kanske:

Kod: Markera allt

   -- Buffer inputs
   BUFFER_INPUTS: process (clk)
   begin
      if clk='1' and clk'event then
         rx_buf <= rx;
      end if;
   end process; 

Re: Hjälp med VHDL felsökning

Postat: 14 mars 2009, 15:43:54
av AAVE
tack strombom, det var precis vad jag ville säga, man ska alltid "sampla" externa signaler två gånger innan användning.


jag har ingen "avnet-moj", men kanske kan hjälpa dig lite om jag får liter mer info

Re: Hjälp med VHDL felsökning

Postat: 14 mars 2009, 17:28:37
av cyr
Det där att sampla 2ggr är för att minimera risken för metastabilitet antar jag, en bra ide om det är asynkrona signaler.

Har inte heller något sånt där kit, men jag har skrivit och felsökt ett par UARTs...

Mitt första tips är att simulera (Modelsim eller likn), och om koden fungerar där men inte i verkligheten så kika på Xilinx ChipScope (går att ladda hem en 60-dagars trial). Extremt smidigt att kunna se vad som verkligen händer där inne i den svarta lådan när saker inte fungerar som det ska! FPGA-motsvarighet till en on-chip debugger...

Re: Hjälp med VHDL felsökning

Postat: 14 mars 2009, 20:24:27
av LHelge
Kan lägga upp det jag gjort hittills, har inte haft tid att testa det än men förhoppningsvis hinner jag göra det senare ikväll. Simuleringen ser iaf ut som jag har förväntat mig, Tanken är att den ska ta emot en bokstav flippa case på den och skicka tillbaka den, i simuleringen nedan skickar jag ett l och ett L ska komma tillbaka.

Simulering

Lägger med koden till uart rx/tx samt koden som kopplar ihop allt, där jag inkluderat buffringen av rx. Ni får gärna påpeka misstag, best practise och sånt som jag missat. Är som jag sa tidigare nybörjare vad gäller VHDL. Har läst lite sporadiskt i några böcker, men de verkar vara mest iriktade mot simulering, och inte syntes.

Vad gäller chipscope så jag inte säker på att man kan använda det eftersom kortet programmeras via USB.

uart_rx:

Kod: Markera allt

entity uart_rx is
    Port ( clk   : in  STD_LOGIC;
           reset : in  STD_LOGIC;
           rx    : in  STD_LOGIC;
           done  : out STD_LOGIC;
           data  : out STD_LOGIC_VECTOR (7 downto 0);
			  busy  : out STD_LOGIC);
end uart_rx;

architecture Behavioral of uart_rx is
	signal counter  : STD_LOGIC_VECTOR(7 downto 0) := "00000000";
	signal c_enable : STD_LOGIC := '0';
	signal rx_done  : STD_LOGIC := '0';
	signal rx_data  : STD_LOGIC_VECTOR(9 downto 0) := "0000000000";
	signal rx_busy  : STD_LOGIC := '1';
	signal bit_counter : integer range 0 to 10;
	type state_type is (idle, start, sample, delay, ready);
	signal state, next_state : state_type;
begin
	-- Clock used for delays
	DELAY_CLOCK: process (clk) 
	begin
		if clk='1' and clk'event then
			if c_enable='1' then
				counter <= counter + 1;
			else
				counter <= (others => '0');
			end if;
		end if;
	end process; 

	SYNC_PROC: process (clk)
   begin
      if (clk'event and clk = '1') then
         if (reset = '1') then
            state <= idle;
            data <= "00000000";
				done <= '0';
				busy <= '1';
         else
            state <= next_state;
				data <= rx_data(8 downto 1);
				done <= rx_done;
				busy <= rx_busy;
         end if;        
      end if;
   end process;
 
   OUTPUT_DECODE: process (state)
   begin
		-- Enable counter for waiting states
		if state = start OR state = delay then
			c_enable <= '1';
		else
			c_enable <= '0';
		end if;
		
		-- Always busy if state is not idle
		if state = idle then
			rx_busy <= '0';
		else
			rx_busy <= '1';
		end if;
		
		-- Set done output if start & stop are OK and reset bit counter on done state 
		if state = ready then
			rx_done <= rx_data(9) and not rx_data(0);
			bit_counter <= 0;
		else
			rx_done <= '0';
      end if;
		
		-- Shift in the sampled bit and increase bit counter
		if state = sample then
			rx_data <= rx & rx_data(9 downto 1);
			bit_counter <= bit_counter + 1;
		end if;	
   end process;
 
   NEXT_STATE_DECODE: process (state, rx, counter, bit_counter)
   begin
      next_state <= state;  --default is to stay in current state

      case (state) is
         when idle =>
            if rx = '0' then
               next_state <= start;
            end if;
         when start =>
            if counter = 69 then -- = 69 which is half a bit for 115200 baud and 16 MHz
               next_state <= sample;
            end if;
         when sample =>
				if bit_counter < 10 then -- one start bit, eight data bits and one stop bit
					next_state <= delay;
				else
					next_state <= ready;
				end if;
			when delay =>
            if counter = 139 then --  = 139 which is one bit time for 115200 baud and 16 MHz
               next_state <= sample;
            end if;
			when ready =>
            next_state <= idle;
      end case;      
   end process;
end Behavioral;
uart_tx

Kod: Markera allt

entity uart_tx is
    Port ( clk   : in  STD_LOGIC;
           reset : in  STD_LOGIC;
           send  : in  STD_LOGIC;
           data  : in  STD_LOGIC_VECTOR (7 downto 0);
			  tx    : out STD_LOGIC;
           done  : out  STD_LOGIC;
			  busy  : out STD_LOGIC);
end uart_tx;

architecture Behavioral of uart_tx is
	signal counter  : STD_LOGIC_VECTOR(7 downto 0) := "00000000";
	signal c_enable : STD_LOGIC := '0';
	signal tx_done  : STD_LOGIC := '0';
	signal tx_out   : STD_LOGIC := '1';
	signal tx_data  : STD_LOGIC_VECTOR(9 downto 0) := "0000000000";
	signal tx_busy  : STD_LOGIC := '0';
	signal bit_counter : integer range 0 to 10;
	type state_type is (idle, start, delay, shift, ready);
	signal state, next_state : state_type;
begin

	-- Clock used for delays
	DELAY_CLOCK: process (clk) 
	begin
		if clk='1' and clk'event then
			if c_enable='1' then
				counter <= counter + 1;
			else
				counter <= (others => '0');
			end if;
		end if;
	end process; 

	SYNC_PROC: process (clk)
   begin
      if (clk'event and clk = '1') then
         if (reset = '1') then
            state <= idle;
            tx <= '1';
				done <= '0';
				busy <= '1';
         else
            state <= next_state;
				tx <= tx_out;
				done <= tx_done;
				busy <= tx_busy;
         end if;        
      end if;
   end process;
 
   OUTPUT_DECODE: process (state)
   begin
	
		-- When idle, put 1 on tx-line, otherwise the next byte to be sent.
		if state = idle then
			tx_out <= '1';
			tx_busy <= '0';
		else
			tx_out <= tx_data(0);
			tx_busy <= '1';
		end if;
		
		-- Latch data in start state
		if state = start then
			tx_data <= "1" & data & "0";
		end if;
		
		-- Enable counter while waiting
		if state = delay then
			c_enable <= '1';
		else
			c_enable <= '0';
		end if;
		
		-- shift the bits in tx_data right one step and increase bit counter
		if state = shift then
			tx_data <= "0" & tx_data(9 downto 1);
			bit_counter <= bit_counter + 1;
		end if;
		
		-- Set done output and reset bit counter on done state 
		if state = ready then
			tx_done <= '1';
			bit_counter <= 0;
		else
			tx_done <= '0';
      end if;
   end process;
 
   NEXT_STATE_DECODE: process (state, send, counter, bit_counter)
   begin
      next_state <= state;  --default is to stay in current state

      case (state) is
         when idle =>
            if send = '1' then
               next_state <= start;
            end if;
         when start =>
				next_state <= delay;
			when delay =>
            if counter = 138 then -- = 139 which is one bit time for 115200 baud
					if bit_counter < 9 then
						next_state <= shift;
					else
						next_state <= ready;
					end if;
            end if;
         when shift =>
				next_state <= delay;
			when ready =>
            next_state <= idle;
         when others =>
            next_state <= idle;
      end case;      
   end process;

end Behavioral;
uart_test

Kod: Markera allt

entity uart_test2 is
    Port ( clk : in  STD_LOGIC;
           rx : in  STD_LOGIC;
           tx : out  STD_LOGIC;
			  rx_busy : out STD_LOGIC;
			  tx_busy : out STD_LOGIC;
			  tx_done : out STD_LOGIC);
end uart_test2;

architecture Behavioral of uart_test2 is
	signal rx_buf  : STD_LOGIC := '1';
	signal reset   : STD_LOGIC := '0';
	signal rx_data : STD_LOGIC_VECTOR (7 downto 0);
	signal tx_data : STD_LOGIC_VECTOR (7 downto 0);
	signal send    : STD_LOGIC := '0';
	
	component caps_change
      port ( char_in  : in  STD_LOGIC_VECTOR (7 downto 0); 
             char_out : out STD_LOGIC_VECTOR (7 downto 0));
   end component;
   
   component uart_rx
      port ( clk   : in  STD_LOGIC; 
             reset : in  STD_LOGIC; 
             rx    : in  STD_LOGIC; 
             done  : out STD_LOGIC; 
             data  : out STD_LOGIC_VECTOR (7 downto 0);
				 busy  : out STD_LOGIC);
   end component;
   
   component uart_tx
      port ( clk   : in  STD_LOGIC; 
             reset : in  STD_LOGIC; 
             send  : in  STD_LOGIC; 
             data  : in  STD_LOGIC_VECTOR (7 downto 0); 
             tx    : out STD_LOGIC; 
             done  : out STD_LOGIC;
				 busy  : out STD_LOGIC);
   end component;
begin

	-- Buffer the rx pin
	BUFFER_RX: process(clk)
	begin
		if clk='1' and clk'event then
			rx_buf <= rx;
		end if;
	end process;
	
	caps_change1 : caps_change port map (char_in(7 downto 0) => rx_data(7 downto 0), char_out(7 downto 0) => tx_data(7 downto 0));
   
   uart_rx1 : uart_rx port map (clk=>clk, reset=>reset, rx=>rx_buf, data(7 downto 0)=>rx_data(7 downto 0), done=>send, busy=>rx_busy);
   
   uart_tx1 : uart_tx port map (clk=>clk, data(7 downto 0)=>tx_data(7 downto 0), reset=>reset, send=>send, done=>tx_done, tx=>tx, busy=>tx_busy);
end Behavioral;

Re: Hjälp med VHDL felsökning

Postat: 16 mars 2009, 23:47:41
av LHelge
Nu har jag hunnit testa lite mera, och kommit lite framåt, men inte hela vägen. Jag använder koden ovan och kopplar rx och tx busy till varsin led. När jag sedan öppnar en anslutning och håller ned en knapp så att ett gäng tecken skickas lyser den led som är kopplad till rx_busy. Om en byte mottogs som den skulle borde även tx-busy lysa, men det gör den inte.

Jag har en aning om vad som skulle kunna vara felet, men jag vet inte riktigt hur jag ska gå tillväga för att lösa det. När jag skapar syntesen så får jag en varning:
One or more signals are missing in the process sensitivity list. To enable synthesis of FPGA/CPLD hardware, XST will assume that all necessary signals are present in the sensitivity list. Please note that the result of the synthesis may differ from the initial design specification. The missing signals are:
för processen OUTPUT_DECODE både för rx och tx. som synes står det inte villka signaler det är, men jag skulle kunna tänka mig att det kan gå fel om till exempel rx_data eller tx_data läggs till i sensitivity list eftersom bit_counter skulle kunna räkna för fort.

Kan det vara detta som är felet, och i så fall hur ska jag göra för att de inte ska komma med i sensitivity list?

Eller är det någon som har någon annan ide?

Det skulle ju kunna vara ett timing fel men det är lite svårare att felsöka då jag inte har något oscilloskop. I simuleringen använder jag en bit-längd på 8,68 us villket jag vill få till 115200 baud. Jag kanske borde testa att gå ner till 9600 baud i felsökningssyfte för att se om det fungerar bättre?

Kan även tillägga att jag får dessa varningar för både rx & tx:
Found 4-bit latch for signal <bit_counter>. Latches may be generated from incomplete case or if statements. We do not recommend the use of latches in FPGA/CPLD designs, as they may lead to timing problems.
Found 10-bit latch for signal <rx_data>. Latches may be generated from incomplete case or if statements. We do not recommend the use of latches in FPGA/CPLD designs, as they may lead to timing problems.

Men det har jag fått för mig att det är i sin ordning eftersom jag vill att de ska vara latchade.

Re: Hjälp med VHDL felsökning

Postat: 17 mars 2009, 10:33:51
av AAVE
kollade snabbt på din OUTPUT_DECODE i uart_rx.

du bör ha alla signaler höger om "<=" i listan. i ditt fall innebär det att rx, rx_data och bit_counter ska med :(
sen har du en bit_counter som räknar upp asynkron, inte en per klockcykel... jag föreslår att du flyttar allting till din synkrona process.

Kod: Markera allt

	SYNC_PROC: process (clk)
	begin
	  if (clk'event and clk = '1') then
		 if (reset = '1') then
			state <= idle;
			data <= "00000000";
			done <= '0';
			busy <= '1';

			bit_counter <= 0;
			rx_data <= (others => '0');
		 else
			state <= next_state;
			data <= rx_data(8 downto 1);
			done <= rx_done;
			busy <= rx_busy;

			if state = sample then
				rx_data <= rx_buf & rx_data(9 downto 1);
				bit_counter <= bit_counter + 1;
			elsif state = ready then
				bit_counter <= 0;
			end if;   

		 end if;        
	  end if;
	end process;

	c_enable <= '1' when (state = start or state = delay) else '0';
	rx_busy <= '0' when (state = idle) else '1';
	rx_done <= (rx_data(9) and not rx_data(0)) when (state = ready) else '0';
jag har inte testat koden, det kan hända att en signal kommer en cykel för tidigt/sent...

Re: Hjälp med VHDL felsökning

Postat: 17 mars 2009, 11:03:01
av AAVE
här är förresten en lite mer avancerade design från Lattice för er som tröttnat på fpga4funs enkla uart:
http://www.latticesemi.com/products/int ... usrece.cfm

För er som inte upptäckt pärlan PicoBlaze än, ta en titt på den nu. Innehåller en otrolig kompakt liten uart:
http://www.google.com/search?q=kcuart_tx

Re: Hjälp med VHDL felsökning

Postat: 17 mars 2009, 13:18:07
av LHelge
Smart att lägga det i den asynkrona processen, det tänkte jag inte på. Ska testa det lite senare. Ska även titta på de andra lösningarna, men eftersom jag gör detta mest för att lära mig vhdl och tänka lite mer paralellt, efter många år som C# programmerare, så vill jag inte planka en annan lösning rakt av. Så tillsvidare får ni stå ut med mina nybörjarfrågor. Jag är däremot oerhört tacksam för den hjälp jag fått hittills.

Re: Hjälp med VHDL felsökning

Postat: 17 mars 2009, 13:46:31
av AAVE
jag tycker faktiskt du klarar dig riktigt bra

Re: Hjälp med VHDL felsökning

Postat: 23 mars 2009, 23:04:21
av arte
LHelge skrev:One or more signals are missing in the process sensitivity list. To enable synthesis of FPGA/CPLD hardware, XST will assume that all necessary signals are present in the sensitivity list. Please note that the result of the synthesis may differ from the initial design specification. The missing signals are:[/color]
för processen OUTPUT_DECODE både för rx och tx.
Är lite irriterande att de inte skriver ut det i varningsfönstret (du använder ISE va?).
Men i fall du kollar i synthes rapporten så står det vilka signaler det är, står även mycket annat intressant där.

Normalt sett så spelar sensitivity list inte någon roll när du kör på kortet men däremot för viss simulering.
Till exempel Modelsim är stenhårt på att signalerna finns med, får inga varningar men det kan bugga under simulering.
LHelge skrev: Det skulle ju kunna vara ett timing fel men det är lite svårare att felsöka då jag inte har något oscilloskop. I simuleringen använder jag en bit-längd på 8,68 us villket jag vill få till 115200 baud. Jag kanske borde testa att gå ner till 9600 baud i felsökningssyfte för att se om det fungerar bättre?
...
Found 10-bit latch for signal <rx_data>. Latches may be generated from incomplete case or if statements. We do not recommend the use of latches in FPGA/CPLD designs, as they may lead to timing problems.[/color]
Men det har jag fått för mig att det är i sin ordning eftersom jag vill att de ska vara latchade.
Vill du att rx_data skalll ha ett register på utgången?
Vet inte hur LATCHar blir i FPGA sammanhang, vet däremot att det är dåligt och skapar många problem som inte finns i simulering.
Så när du ser en sådan varning så tänk att något är fel :)
Skillnaden mellan en latch och en flipflop blir väl att latchen "läser in" värdet under hela halva klockcykeln och låser sedan medans en flipflop låser vid rising_edge.

Men detta felet får du inte väl inte med AVVEs kodändringen?

För tips om hur man skriver bra VHDL så kan jag rekomendera läsningen http://www.gaisler.com/doc/vhdl2proc.pdf