Jump to content
  • 0

Why is my Process getting triggered with no change to the sensitivity


FlyingBlindOnARocketCycle

Question

I have built a very simple test case, built for a Basys3, in an effort to isolate my mental error.  In the VHDL below I am expecting that the process(btn) will only be triggered when the input "btn" changes.  The ila I have in place shows that the process is running continuously.  Well at least that is what I think it is showing me.  The ila shows "btn" signal remains at zero while the up_test is increasing at a rate that appears to be free running.

I must have some horrible misunderstanding about the behavior of a process with respect to its sensitivity list.

Please set me straight.

 

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


entity btn_test is
    Port ( 
           clk_100M : in    STD_LOGIC;
           btn      : in    STD_LOGIC_VECTOR (4 downto 0);
           led      : out   STD_LOGIC_VECTOR (15 downto 0);
           seg      : out   STD_LOGIC_VECTOR (6 downto 0);
           an       : out   STD_LOGIC_VECTOR (3 downto 0);
           dp       : out   STD_LOGIC
          );
end btn_test;

architecture Behavioral of btn_test is


signal up_test		: natural := 0;
signal up_test_i	: std_logic_vector (31 downto 0);

COMPONENT ila_0
PORT (
	clk : IN STD_LOGIC;
	probe0 : IN STD_LOGIC_VECTOR(31 DOWNTO 0);
	probe1 : IN STD_LOGIC_VECTOR(4 DOWNTO 0)
);
END COMPONENT  ;

begin

up_test_i		<= std_logic_vector(to_unsigned(up_test,32));

up_test_ila : ila_0
PORT MAP (
	clk 	=> clk_100M,
	probe0 	=> up_test_i,
	probe1	=> btn
);                                

count_button_process_triggers: process(btn)
	begin
		up_test <= up_test +1;
	end process; 
 
led <= (others => '0');
seg <= (others => '0'); 
an  <= (others => '1');   
dp  <= '0';   
                
end Behavioral;

 

image.thumb.png.799bb45fa3d0894ebcf15090d9e780d6.png

Link to comment
Share on other sites

Recommended Posts

This is the warning that matters: "signal 'up_test' is read in the process but is not in the sensitivity list"

What has happened is the tools have detected that you read the value of "up_test" in the process, assumes that you have made an error, and helpfully added it to the process's sensitivity list. This is because for any async logic in processes all signals that are used in the process should be included in the sensitivity list. 

Were "up_test" included in the sensitivity list you would get exactly the observed behavior (although now any simulations would hang/break... sigh).

If this is the right thing for the tools to do is an open question - sometimes it is, sometimes it isn't. Throwing an error rather than a warning would break existing code bases... issuing warnings lets these sorts of issues slip through.

By "you haven't defined is some way to filter out the changes of BTN", Ignore me - I was just waffling on to allude that you need to use "rising_edge()" somewhere to control the timing of when "up_test" gets updated.

 

Link to comment
Share on other sites

In general the tools will let you try anything. If you want to "ski off piste" the let you. They may warn strongly against it, or might even need you to stamp your feet a little with directives and settings, but you might have a valid need to do what you are asking.

They also can only control what you do inside the FPGA. For example,  if you had "output_pins <= std_logic_vector(unsigned(input_pins)+1);" and wire your outputs and inputs together you will get exactly what you have inside the chip (but a little slower).

If you work with software you should all be used to this. Take this small C program:

$ cat div.c
#include <stdlib.h>
int main(int argv, char *argc[]) {
  return atoi(argc[1])/0;
}

$ gcc -o div div.c -Wall -pedantic -O4
div.c: In function ‘main’:
div.c:3:23: warning: division by zero [-Wdiv-by-zero]
   return atoi(argc[1])/0;
                       ^

$ ./div 123
Floating point exception (core dumped)

$

Should divide by a constant zero be a critical error? How is the compiler supposed to know if you are really doing this by accident, or are writing a program to test the behavior of divide by zero?

Part of the learning curve for FPGAs is to develop a feeling for what is the "safe area" to work in, and recognize when you are leaving wandering outside of it.

It is a shame that in this case you stumbled into this by accident, but you get big bonus points from me for realizing that you were in a strange & weird place, and attempting to make some sense of it before moving on.

(BTW, I like playing in these areas)

Link to comment
Share on other sites

On 3/6/2018 at 2:24 PM, FlyingBlindOnARocketCycle said:

...take credit for the idea like it was mine. ;)

Just for laughs, grab a random paper on metastability like this one and the list of references goes back to the days of the Cuban missile crisis.
What we're talking here is as basic as plus and minus for an accountant. Maybe I'll remember to give proper credit in my next tax report for the used operators :)

Link to comment
Share on other sites

Maybe Hamster is still watching....

What about this?  My counter "cnt" returns to 0 after 1 clock.  I don't see why. What Im trying to do here is easily accomplished with a clocked process but I want to understand why this doesn't work.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;


entity FSM_ila_test_top is
    Port (    
           clk 		: in    STD_LOGIC;
           btn      : in    STD_LOGIC_VECTOR (4 downto 0)
          );
end FSM_ila_test_top;

architecture Behavioral of FSM_ila_test_top is

signal button       : std_logic_vector(4 downto 0); 
signal next_button	: std_logic_vector(4 downto 0);
signal cnt 			: unsigned(7 downto 0) := "00000000";
signal next_cnt		: unsigned(7 downto 0) := "00000000";
signal cnt_delay	: unsigned(7 downto 0) := "00000000";
signal Q1, Q2, Q3 	: STD_LOGIC_VECTOR(4 downto 0) := "00000";


COMPONENT button_ila

PORT (
	clk 	: IN STD_LOGIC;
	probe0 	: IN STD_LOGIC_VECTOR(4 DOWNTO 0); 
	probe1 	: IN STD_LOGIC_VECTOR(4 DOWNTO 0); 
	probe2 	: IN STD_LOGIC_VECTOR(7 DOWNTO 0);
	probe3 	: IN STD_LOGIC_VECTOR(7 DOWNTO 0)
);
END COMPONENT  ;


begin
                         
process(clk)
begin
    if rising_edge(clk) then
         Q1 <= btn;
         Q2 <= Q1;
         Q3 <= Q2;
   end if;
end process;
 
next_button <= Q1 and Q2 and (not Q3);  
        
process(clk)
begin
	if rising_edge(clk) then
		cnt			<= next_cnt;
		button		<= next_button;
	end if;
end process;
                
process(button, cnt)
    begin
		
		case button is
	
		when "00010" 	=>	--up
			next_cnt	<=	cnt + 1;
			
		when "00100"   =>	--down	
			next_cnt	<=	cnt - 1;
			
		when "00001" 	=>	--center	
			next_cnt	<=	TO_UNSIGNED(0,8);
			
        when others =>  
      	end case;  
      	      
      end process;      
 
button_press : button_ila
      PORT MAP (
      	clk 	=> clk,
      	probe0 	=> next_button, 
      	probe1 	=> button, 
      	probe2 	=> std_logic_vector(next_cnt),
      	probe3 	=> std_logic_vector(cnt)
      );        
               

end Behavioral;

comb_process.thumb.JPG.cfcd4a65071129ad6669f80c2584cce5.JPG

comb_process.thumb.JPG.77aee1571f419c5451dcd17e57961bc0.JPG

Link to comment
Share on other sites

On 3/4/2018 at 5:32 PM, hamster said:

What has happened is the tools have detected that you read the value of "up_test" in the process, assumes that you have made an error, and helpfully added it to the process's sensitivity list. This is because for any async logic in processes all signals that are used in the process should be included in the sensitivity list.

@hamster's statement shown above has been bugging me ever since I first read it.. about once a week it comes into my consciousness and irritates me. 

I contend that hamster's comment is just plain wrong and that the only reason that the poster got any thing to configure his board with was because of the ILA requiring a clock. I still think that what the original ILA output was showing is a ring counter sampled by a 100 MHz clock....

I realize that the poster didn't like my comments but I decided to re-create his original code project in order to restart the thread commentary in a more helpful direction. So here's what I did. I made minor modifications to remove the ILA from the code as it is causing confusion as to what's going on. Instead I send out 24 of the 32 counter bits to IO so that up_test isn't optimized out of existence. I then tried to create a configuration file using Vivado 2016.3.

Here is the BITGEN error message:

ERROR: [DRC 23-20] Rule violation (LUTLP-1) Combinatorial Loop Alert - 1 LUT cells form a combinatorial loop. This can create a race condition. Timing analysis may not be accurate. The preferred resolution is to modify the design to remove combinatorial logic loops. If the loop is known and understood, this DRC can be bypassed by acknowledging the condition and setting the following XDC constraint on any net in the loop: 'set_property ALLOW_COMBINATORIAL_LOOPS TRUE [net_nets <myHier/myNet>'. The cells in the loop are: JA_OBUF[0]_inst_i_7.


Below are attached the project sources as modified by me. I invite anyone interested in recreating the project to see the results....

 

btn_test.vhd

btn_test.xdc

Link to comment
Share on other sites

It turns out the code I posted above wants the When others => case utilized.

  process(clk)
begin
	if rising_edge(clk) then
		cnt			<= next_cnt;
		button		<= next_button;
	end if;
end process;
                
process(button, cnt)
    begin
		
		case button is
	
		when "00010" 	=>	--up
			next_cnt	<=	cnt + 1;
			
		when "00100"   =>	--down	
			next_cnt	<=	cnt - 1;
			
		when "00001" 	=>	--center	
			next_cnt	<=	TO_UNSIGNED(0,8);
			
        when others =>  

      	end case;  
      	      
      end process;   

If I add next_cnt <= cnt; to the otheres case, this works as expected.  I guess that makes sense but I thought that next_cnt would retain its value if nothing else was writing to it.  I bet if this case process was a clocked process, next_cnt would indeed register a value.  I wonder what it driving next_cnt low when its not being driving by a clocked in value?

Link to comment
Share on other sites

Sorry to have irritated you...

Here is my example:

- I used an unsigned datatype for the counter

- I also had all bits used - the low 24 on the PMODS, the high 8 on the LEDs.

- It was built for the Nexys2 board, using the latest version of ISE.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity btn_test is
    Port ( 
           clk_100M : in    STD_LOGIC;
           btnC     : in    STD_LOGIC; 
           led      : out   STD_LOGIC_VECTOR( 7 downto 0);
           seg      : out   STD_LOGIC_VECTOR( 6 downto 0);
           an       : out   STD_LOGIC_VECTOR( 3 downto 0);
           dp       : out   STD_LOGIC;
           JA       : out   STD_LOGIC_VECTOR( 7 downto 0);
           JB       : out   STD_LOGIC_VECTOR( 7 downto 0);
           JC       : out   STD_LOGIC_VECTOR( 7 downto 0));
end btn_test;

architecture Behavioral of btn_test is
	signal up_test    : unsigned (31 downto 0) := (others => '0');
begin

count_button_process_triggers: process(btnC)
	begin
	   up_test <= up_test +1;
	end process; 

   JA  <= std_logic_vector(up_test( 7 DOWNTO  0));   
   JB  <= std_logic_vector(up_test(15 DOWNTO  8)); 
   JC  <= std_logic_vector(up_test(23 DOWNTO 16)); 
   led <= std_logic_vector(up_test(31 DOWNTO 24)); 	

	seg <= (others => '0'); 
	an  <= (others => '1');   
	dp  <= '0';
end Behavioral;

The constraints are almost the standard Nexys2 ones, so I won't include them.

Although it produces a metric truckload of warning about combintatorial logic oops, it does produce a BIT file, and when programmed it does do as expected, but what it arguably shouldn't be doing. Without a change in state of btnC the counter is counting up.

It cycles through all 32-bit values in about 5 seconds, so each addition is taking about 1.2ns (or is free-running at about 800 MHz, if you like).

Or maybe it doesn't - maybe it skips some values and the lowest bits are not counting properly. But it looks as if it counts, without a clock or an event on btnC signal.

 

 

Link to comment
Share on other sites

That's interesting Hamster.  Does Zygot's posted error message about the combinatorial loop point out that up_test is getting added into the sensitivity list by the Xilinx IDE? When it says "The cells in the loop are: JA_OBUF[0]_inst_i_7" the only loop that I see possible is the fact that JA is driven by up_test.  Does the error message actually point out that up_test is added to sensitivity list of the count button process like you suggest? 

Also I find it super interesting that the message suggests that "If the loop is known and understood, this DRC can be bypassed by.."  Does that indicate that, if you know what you are doing and WANT the FPGA to do something at the speed of (whatever the logic can support), then the Xilinx tools will allow you to do that?  Yes it would be asynchronous but fast.

Link to comment
Share on other sites

@hamster, No worries about irritating me... it's more a situation of being self-irritated... when something just doesn't seem right is sticks around in my subconscious. So after reducing the source to the basic functionality, without the ILA, we probably agree that understanding what's going on is an interesting problem to analyze.

I did see that I forgot to comment out a few lines in my constraints file.

I was thinking of posting the source as an "interactive discussion" on the tutorial section of the forum so as not to co-opt this thread. I think that the resulting discussion might be interesting. Any encouragement to do so? I realize that simply telling someone asking for help how to write code that might move his progress along might be useful in a limited context but even more useful might be testing out what the experienced folks "know". On one level is the VHDL language and extensions, and on another is the FPGA architecture and tools. In my experience the sum of those is more complex than the parts.

5 hours ago, FlyingBlindOnARocketCycle said:

Does that indicate that, if you know what you are doing and WANT the FPGA to do something at the speed of (whatever the logic can support), then the Xilinx tools will allow you to do that?  Yes it would be asynchronous but fast.

Yes, I think that you are (generally) correct. The synthesis tool doesn't complain about the source code at all except  that the counter isn't in the sensitivity list. As to VHDL and writing synthesizable code that does what you want it to do the source is problematic. Of course the synthesis tool isn't magic and has limits in it's ability to interpret the intentions of source code. But it would seem that the synthesis tool has decided that you want something that looks a lot like a ring counter.. perhaps.

A problem with trying to use a counter that is essentially a feedback loop is controllability. Even if you were to assign the logic to specific LUTs it would be difficult ( not impossible ) to control the count frequency and get the place and route tools to understand timing. It would be more difficult to use this structure effectively. The reason that I decided to post the previous alternate source is to spur conversation for the sake of education. Even those of us who think that we know things should step back from time to time to test what it is that we thought we knew in the context of our current experience. Your original question is actually a lot more complicated and interesting than you might have expected.

As to the next step in "improving" the original source it would seem that using a clocked process, event or rising_edge approach would be better. But what's the difference? Does any approach work or have the same outcome? Hmm...

 

Link to comment
Share on other sites

This has inspired me to attempt some changes to a division module I made.  The module takes two std_logic_vector inputs, and provides the quotient and remainder.  The catch is, the results will take a set number of clock cycles (input vector width + 2 ) before being available.  I am thinking that I could possibly change some things around so my inputs are registered into the module, have the division "free running" and after completion register the output and a ready bit to get back to synchronous.  The process would no longer be deterministic but it should be complete faster than (the bitwidth of the input +2) x clock rate.  Probably much faster.

Link to comment
Share on other sites

Having some time on my hands this weekend I decided to run some tests myself and share results with you.

In my opinion, coding the VHDL process is covered very loosely by majority of textbooks and tutorials.  In my opinion Xilinx UG901 is the most useful and accurate source. Specifically, I would point to pages 191, 192 describing the syntax and components of VHDL process. I believe that it is better/safer to stick to this guide since they wrote the synthesis tool. BTW, it says: " If any signals are missing from the sensitivity list, the synthesis results can differ from the initial design specification. In this case, Vivado synthesis issues a warning message and adds the missing signals to the sensitivity list."

For testing I took liberty to reuse published code with several simplifications and adaptations for my Zybo board. I tested three versions of code.

The first one is by the book clock counter as Xilinx recommends:
-------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity NBT is
    Port (
            clk   : in    STD_LOGIC;  -- 0.201562 MHz
            btn0  : in    STD_LOGIC;
            led0  : out   STD_LOGIC;
            led1  : out   STD_LOGIC;
            led2  : out   STD_LOGIC;
            led3  : out   STD_LOGIC );
end NBT;

architecture Behavioral of NBT is
    signal up_test    : unsigned (18 downto 0) := (others => '0');
begin

    led0 <= btn0;    -- Button LED control
    led1 <= up_test(16);
    led2 <= up_test(17);
    led3 <= up_test(18);
 
count_button_process_triggers: process(clk)
    begin
       if rising_edge(clk) then    -- "clock event"
           up_test <= up_test +1;
       end if;
    end process;
end Behavioral;
----------------
This version worked flawlessly, no critical warnings, etc.

Version 2 was modified to count pushing the button as shown below:
----------------
count_button_process_triggers: process(btn0)
    begin
       if rising_edge(btn0) then     -- "clock event"
           up_test <= up_test +1;
       end if;
    end process;
-----------------
The version 2 worked as intended, no false counts, but it produced a number of warnings, specifically, in Timing Check Worst Severity warnings: no_clock, unconstraint_internal_endpoints, - no_output_delay.

The version 3 was a copy of Hamster's counter where "clock event" was removed:
-----------------
count_button_process_triggers: process(btn0)
    begin
           up_test <= up_test +1;
    end process;
-----------------
This version failed to create bitstream with 5 errors, including  [DRC LUTLP-1] Combinatorial Loop Alert: 1 LUT cells form a combinatorial loop. This can create a race condition.....

I hope this helps to make conclusions.
For me it is obvious that time considerations = constraints should be included. It is impossible to create layout without timing constraints. In many cases Xilinx takes care of this behind the scene using clock parameters but if the clock is not defined by the designer the result is a mess.

 

 

Link to comment
Share on other sites

Thats interesting that you got the timing loop error.  I have also seen that before and failed to create a bit stream.  I wonder why hamster and I have been able to get this to build?  Do you have any kind of one-shot debounce on your button input?  I am using a 5 bit version of the Vivado template below for all 5 buttons on the Basys3.  Do you think that might appease Vivado's timing loop fury down to a mild discontent?


--  Provides a one-shot pulse from a non-clock input, with reset
--**Insert the following between the 'architecture' and
---'begin' keywords**
signal Q1, Q2, Q3 : std_logic;

--**Insert the following after the 'begin' keyword**
process(<clock>)
begin
   if (<clock>'event and <clock> = '1') then
      if (<reset> = '1') then
         Q1 <= '0';
         Q2 <= '0';
         Q3 <= '0';
      else
         Q1 <= D_IN;
         Q2 <= Q1;
         Q3 <= Q2;
      end if;
   end if;
end process;

Q_OUT <= Q1 and Q2 and (not Q3);

 

Link to comment
Share on other sites

You could inspect the implemented design as schematic.

Now, typical switch bounce extends over a length of thousands of clock cycles. It's a job for a counter, otherwise I guarantee there will be multiple triggers, "down" events on "key up" and vice versa.

For the record, to properly bring in an asynchronous signal there should be a synchronizer (see pragma ASYNC_REG discussion before and the related documentation). A single register will catch "almost" 100 % of metastability, but you're asking for trouble in a real-world design when it leads to a once-per-week catastrophic failure that the customer finds "almost" acceptable. See Xilinx docs.

What may happen in this specific example is that Q1 is slow to settle when the input voltage creeps through the threshold at the clock edge. Then Q2 sees some result and the expression in Q_OUT sees something else. Boom.
A whole clock cycle seems a long time for Q1 to settle but the design tools may utilize most of it for routing / logic delay so I need to consider Q1's slow settling relative to the timing margin, not the clock cycle (so this is where the ASYNC_REG pragma comes in: Tell the tool to please put no delay in-between two vanilla registers so that the whole cycle length can be used for settling)

And: the official MTBF test circuit (same docs) might be an interesting beast to study wrt, "non-standard" design.

 

 

Link to comment
Share on other sites

@FlyingBlindOnARocketCycle

Introducing async button signal into the FPGA creates clock domain crossing problem. This is what you had in the first place, another problem is that you didn't make Xilinx synthesizer aware of this making impossible to create timing goals/constraints.

Now anything that brings button signal into the main clock domain should solve the problem. It can be debouncer code or the code you proposed to use which is more like a latch. I am not sure you want one-time event.

If I get some spare time I will add debouncer to my code, run it and post results. 

Also in my experience we should pay very serious attention to Vivado warnings and find the way to clear them. Very useful tool for fixing timing constraints is a "Constraints Wizard" located inside the Implementation section. Unfortunately, this part of FPGA design is very poorly described.

Update

After adding button debouncer everything works as intended. Single 100 Mhz clock is used and no critical or any serious warnings from Vivado.

I post VHDL files and the block diagram just in case somebody wants to verify.

image.thumb.png.67272f65d3360272785b03e98556e08b.png

DBounce.vhd

NBT.vhd

Link to comment
Share on other sites

Notarobot: I don't understand why you say this is a latch?  Is it because the logic would not allow for the detection of a button that was being held down vs pressed and released?  I have the one time event because I only want to register a single event per button press. For what its worth, this one-shot debounce hdl was provided by the Vivado 2017.4 language template library.  I've been told that I should not trust the language template as a source.  I find that disappointing. Maybe Xilinx should stop including it if its not good code.

xc6lx45: Is there a rule of thumb on how clock cycles should be observed to eliminate debounce?  If there is, would it need to be a function of the clock rate?  Assuming some kind of normalized average for button (type, quality, construction,...) it would seem that the faster the clock the worse the potential for false hits on the button.

I wonder if I should drop this debounce topic to leave the thread focused on process sensitivity....

Link to comment
Share on other sites

Dear @FlyingBlindOnARocketCycle

The debouncer has two purposes:

1) to convert async signal into the signal with edges aligned with the clock that is to bring it into a single clock domain. There is no process sensitivity issue in such design.

2) eliminate multiple ON/OFF contact bounces which are typical for mechanical switches. Depending on the switch technology it takes from 10 to 50 ms to reach stable state. In my experience 20-40 ms worked just fine.

It's up to you to decide what hdl to use I just noted that it looks like a latch at the first glance. I also try Xilinx templates before making my own because theirs are 100% synthesizable. I think it is a good practice until you get proficiency.

Your post and others helped me to reach understanding and even I've never had such issues in my work I know how to avoid them.

Thank you and good luck, bye....

Link to comment
Share on other sites

19 hours ago, FlyingBlindOnARocketCycle said:

At the end of the day my major concern is my inability to build a finite state machine because the simple concept of a sensitivity list appears to be over my head.

I would put it this way, you're trying to re-invent a FSM. If you were just building one, you'd copy a design pattern.

For example, take this one here starting at line 341 with the clock edge trigger in line 284:

if rising_edge(clk_i) then
	if reset_i='1' then
		...
	else // this is the actual FSM. state updates itself at every posedge of clk_i.
		case state is
        	when st_idle =>
				...
				state <= st_resync;
		when st_resync =>
 				...
                state     <= st_resync2;
		when st_resync2 =>
                ...

The "sensitivitity list" concept is NOT simple, it's quite a mess actually.
Learn a proven pattern => see above, stick to it, and other people may actually later be able to decipher your code :)

The "correct" way (in a textbook sense) to handle the button is to load it into an externally clocked register, load the result into a second register, flag both with pragma ASYNC_REG to form a synchronizer. I can invent many other approaches that will simulate OK but fail in hardware once per minute or per hour or per day or per week. Neither is tolerable, and the last is actually the worst because it's hard to debug something you can't observe.

Link to comment
Share on other sites

@hamster,

Your short tutorial on digital design and VHDL really illustrates well why I am hesitant to provide this kind of answer to someone who appears to be insufficiently prepared to accomplish a desired goal. While it isn't necessarily wrong ( and here I am referring to nitpicking that would bother someone well versed in both subjects ) is isn't really comprehensive enough to be "right" if the goal is to resolve misunderstanding ( to someone not well versed in either subject). I'm not challenging your comments or choice to present them. You present ideas worth investigating and that's good provided that anyone trying to understand the basic concepts understands it in that context. In the long run over simplification is not a path to understanding. 

One day no one will download Vivado to their computer. Everyone will just connect to whatever it is that everyone will be required to connect to and say "Hey Vivado I want ...." and their connected hardware will get configured automatically. I won't be one to see this as wonderful. Between now and then there is just no excuse for not doing the work required to become educated enough to use the tools that are a means to accomplishing an end. The information is available and free except for time.

Link to comment
Share on other sites

1 hour ago, FlyingBlindOnARocketCycle said:

No worries guys.  When I said FSM that's what I meant to say.  I'm not implying that the example in this thread is representing a FSM.  I do admit that I always thought of combinatorial logic to be logic that is used outside of a process and from the statements made here, that may not always be the case?  I have personally never used a sensitivity list for anything other than a FSM, preferring all processes to be rising edge clocked.  But again, I have very limited experience.

Thanks again

There are a couple of ideas used to divide digital logic designs into different classes.

Combinatorial vs Sequential

Combinatorial logic is pretty much any logic with outputs that should responds 'instantly' to changes in the input, and where the output is a pure function of the present input only (i.e. has no internal state)

vs

Sequential logic is logic with output depends not only on the present value of its input signals but also the sequence of past inputs (i.e. it has internal state). Most FPGA designs (if not all!) fall into this category.

Synchronous vs Asynchronous

Synchronous logic updates on the edge of a clock, which provides the timing information. Most FPGA designs fall into this category.

Asynchronous logic updates the outputs as the input changes - the changes of the input signals provide the timing information. These designs use things like latches and subtle timing behavior to function properly, and are not usually compatible with FPGAs.

How this relates to VHDL concurrent statements vs processes

VHDL concurrent statements generally describing asynchronous logic, and processes are usually describing synchronous logic - but not this is not always true!

Complex async logic can be best expressed in processes,as you can use "if" and "case" statements - you can tell these because of the long sensitivity lists, rather than being sensitive to just a single clock signal.

And with statements like "Q <= D when rising_edge(clk);" you can make a concurrent statement implement synchronous logic, and squirrel them away where others are not expecting to see them! ;)

Link to comment
Share on other sites

1 hour ago, FlyingBlindOnARocketCycle said:

I do admit that I always thought of combinatorial logic to be logic that is used outside of a process and from the statements made here, that may not always be the case?

No this is not the case. But I won't keep repeating my previous advise.

Link to comment
Share on other sites

No worries guys.  When I said FSM that's what I meant to say.  I'm not implying that the example in this thread is representing a FSM.  I do admit that I always thought of combinatorial logic to be logic that is used outside of a process and from the statements made here, that may not always be the case?  I have personally never used a sensitivity list for anything other than a FSM, preferring all processes to be rising edge clocked.  But again, I have very limited experience.

Thanks again

Link to comment
Share on other sites

@FlyingBlindOnARocketCycle,

Yeah, I'm not sure that the light that went on is really the right light either.

I always suggest that people, even very experienced people, read and understand the documentation for the FPGA vendor that they are targeting. I suggest that you use the Documentation Navigator and find the Syntheses and Simulation Design Guide. It can't hurt to know what Xilinx's opinion on using their tools are can it? It is not a replacement for a good VHDL or Verilog textbook but does help those who have a good grasp of the language and concepts understand how to get along with the Xilinx tools.

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...