• 0
FlyingBlindOnARocketCycle

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

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

Edited by FlyingBlindOnARocketCycle
adding VHDL tag

Share this post


Link to post
Share on other sites

Recommended Posts

  • 1

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.

 

Share this post


Link to post
Share on other sites
  • 0
3 hours ago, FlyingBlindOnARocketCycle said:

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

@FlyingBlindOnARocketCycle

Your problem isn't understanding sensitivity lists it understanding combinatorial logic. What's happening is that the synthesis tool is likely ( you should be able to see a message from the synthesis tool; you do read the messages don't you? ) inferring a register that isn't being clocked. You have storage but nothing regulating it. Try a clocked process with the clock ( perhaps a reset? ) in the sensitivity list. Then think about button contact bounce and what you want to do about that.

Now, extremely fast ring counters can be constructed using your technique but I suggest that you don't try that with FPGA logic.

Edited by zygot

Share this post


Link to post
Share on other sites
  • 0

I have a differing view from @Zygot's

You are right - the counter shouldn't be running continuously, If you follow the language spec to the letter, your counter should change any time the state of BTN changes. That is what you should get in simulation.

However, what you haven't defined is some way to filter out the changes of BTN, such that the counter only incremented with some of the possible state changes (.e.g a "rising_edge()" clause).

When the synthesis tools try to convert your designs into hardware they are looking for either clocks or async resets or clocks to act as triggers for changes in state. The design has neither of these - it can't see that BTN should act as a dual-edged clock, so along with some warnings (I hope it gives warnings, heck, the tools give warnings for everything!) it just gives you an adder, with nothing controlling the timing of when up_test is updated.

The synthesis guys will are that this is what you want and this is what you asked for, and they will also argue that the sensitivity list is just a hint for simulation....

What you really want is something like:

btn_clk_proc : process (btn)
   begin
      if rising_edge(btn) then
         test <= test+1;
      end if;
   end process;

... but then that leads onto discussions of switch bounce, routing delays and metastabiliy. 

 

 

Edited by hamster

Share this post


Link to post
Share on other sites
  • 0

... maybe to pick up on the last line of @hamster's post:

FPGAs have two kinds of wires, information signals and clock signals. Think of them as car lanes and bicycle lanes. You can physically drive on the wrong one and it may be even legal but usually it's not a good idea.
Using an ill-defined switch signal as clock is a bad idea. What will happen is that different parts of the circuit may interpret the ill-defined signal in a different way, and then the logic does what engineers euphemistically call "rapid disintegration" - it starts moving into many directions at the same time :).

Clock your register from a "clean" crystal clock. If you want to do it properly, add a 2nd identical register in series and flag both with "attribute ASYNC_REG". Vivado will recognize the pattern, put both physically close together, which solves (disclaimer: strictly speaking it can't be "solved" but never mind) the metastability thing.

A problem with hardware description languages is that they are much more flexible than the hardware, because they are supposed to do other things (e.g. testbenches) that aren't possible in hardware. A big part of the learning process is IMHO to make a mental inventory of the language patterns that are allowed and meaningful. Sometimes the patterns recognized by the tool are very sophisticated, e.g. inference of dual-port memory, multipliers or state machine recognition (it may even convert e.g. to one-hot encoding for performance)

 

Edited by xc6lx45

Share this post


Link to post
Share on other sites
  • 0

First of all, thank you all for time and help. 

Indeed this HDL performs as I expect in simulation yet the signal runs away when implemented on the chip.

Please note that this design serves the sole purpose of proving a point to me so I could know for sure that I designed a bad process.  The fact that I would experience switch bounce and other issues was ignored in an attempt to trim this problem example down to the least possible parts.

I would like to understand all the advice I've received on this thread.  So going in order...

@hamster Yes sir you and zygot are correct in stating that I get warnings.  I get several warnings in synthesis, NO warnings  or errors in Implementation, and 2 DRC warnings.

All "regular" warnings I get are understood 

signal 'up_test' is read in the process but is not in the sensitivity list , numerous warnings about driving a port with a constant (driving led's off as I'm not using them)

What I don't know how to interpret is the Critical warning from synthesis.

Vivado says it found a timing loop and points to the entity btn_test declaration as the location of there error.  There are also a lot of errors in the out of context module run for the ila which I have no idea what to do with.

The 2 DRC are I have are, no CFGBVS value set, and the others are to do with the ila.

I agree with zygot's statement that a clocked process would work around my issues here, I had actually done that and seen it work before posting my question but, as you mentioned, the process shouldn't get triggered when btn never changes and I want understand why this bad process is bad rather than continue in my ignorance.

I don't understand what you mean by 

1 hour ago, hamster said:

you haven't defined is some way to filter out the changes of BTN

 

Also, btn is a std_logic_vector(4 downto 0)  how would a rising_edge(btn) work?

 

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 still don't comprehend why the process is triggering.

Share this post


Link to post
Share on other sites
  • 0
1 hour ago, FlyingBlindOnARocketCycle said:

would a rising_edge(btn) work ?

Ok, perhaps we should all step back a bit and stop ignoring this:

 

1 hour ago, FlyingBlindOnARocketCycle said:

the simple concept of a sensitivity list appears to be over my head.

That's a good place for you to start investigating. I'd suggest a good textbook on VHDL syntax for describing digital logic behavior. Then try to understand the difference between clocked and combinatorial logic and processes. All the suggested changes to your code is unlikely to be helpful, despite everyone's best intentions, if you're not grasping the fundamental concept. If you feel as if you are baffled by what's going on then deal with that. I suggest that you learn at a pace that suits you.

I will point out that there are differences in style that a textbook won't cover. And this might be confusing if you try to follow the advise of "experienced" people. Coding styles for Xilinx synthesis tools really are slightly different than those for other vendors. But this isn't the time or place to delve into that territory.

HDLs are not all that intuitive even if you are a pro at digital design methodology. You should understand that it it possible to have a piece of logic work with an ILA attached and not work without it ( been there done that ). Simulations are great too, if you understand how they work. The best place start though, in my opinion, is to understand the HDL that you want to use. In this sense it's no different than learning a computer language. You wouldn't do that by writing whole programs and then trying to understand what the compiler gave you would you?

If you don't have a good textbook then there are places with decent tutorials on the internet that is likely to be more helpful than this forum. It seems like a reasonable proposition to me that having a bunch of well meaning "experts" argue about what they think your confusion will be fixed by is not a good substitute for study.

 

Edited by zygot

Share this post


Link to post
Share on other sites
  • 0
7 minutes ago, hamster said:

helpfully added it to the process's sensitivity list.

WHAAAAA!!!  I didn't realize that Vivado was adding the signal to the sensitivity list for me.  That explains everything.  I'm not insane after all... just naive.  I always understood why inputs to a FSM needed to be in the sensitivity list but thought I could get away with things like the code in this discussion.  I think I need to find some in depth tutorials on FSM's

 

Thanks so much for the help

Share this post


Link to post
Share on other sites
  • 0
6 minutes ago, FlyingBlindOnARocketCycle said:

 I always understood why inputs to a FSM needed to be in the sensitivity list but thought I could get away with things like the code in this discussion. 

You might be using "FSM" when you mean "combinatorial logic". :-)

Share this post


Link to post
Share on other sites
  • 0

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

Share this post


Link to post
Share on other sites
  • 0

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

Share this post


Link to post
Share on other sites
  • 0
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.

Share this post


Link to post
Share on other sites
  • 0
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! ;)

Edited by hamster

Share this post


Link to post
Share on other sites
  • 0

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

Share this post


Link to post
Share on other sites
  • 0
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.

Edited by xc6lx45

Share this post


Link to post
Share on other sites
  • 0
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 :)

Share this post


Link to post
Share on other sites
  • 0

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

Edited by FlyingBlindOnARocketCycle
didn't post the screen shot corretly

Share this post


Link to post
Share on other sites
  • 0
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

Edited by zygot

Share this post


Link to post
Share on other sites
  • 0

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?

Share this post


Link to post
Share on other sites
  • 0

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.

 

 

Share this post


Link to post
Share on other sites
  • 0

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.

Share this post


Link to post
Share on other sites
  • 0

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

 

Edited by zygot

Share this post


Link to post
Share on other sites
  • 0

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)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now