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.

[SOLVED] VHDL dcfifo duplicate values on read output

Status
Not open for further replies.

player80

Full Member level 2
Joined
May 31, 2013
Messages
122
Helped
0
Reputation
0
Reaction score
1
Trophy points
1,298
Activity points
2,414
Hi,

I would like to use a dual clock fifo (Altera Quartus II) for transferring data from one clock domain to another one.

Now the problem is that I'm getting duplicate data on the read side from time to time

The input clock has around 5 MHz, the output clock has 12 MHz, the bus is 8bit wide on the input and output.

Can anyone give me some hint where to look for in order to solve that problem?

Code:
002e4840  f4 f5 f6 f6 f7 f8 f9 f9  fa fb fc fc fd fe fe ff  |................|
002e4850  00 01 01 02 03 03 04 05  06 06 07 08 09 09 0a 0b  |................|
002e4860  0b 0c 0d 0e 0e 0f 10 11  11 12 13 13 14 15 16 16  |................|
002e4870  17 18 18 19 1a 1b 1b 1c  1d 1e 1e 1f 20 20 21 22  |............  !"|
002e4880  23 23 24 25 25 26 27 28  28 29 2a 2b 2b 2c 2d 2d  |##$%%&'(()*++,--|
002e4890  2e 2f 30 30 31 32 33 33  34 35 35 36 37 38 38 39  |./00123345567889|
002e48a0  3a 3a 3b 3c 3d 3d 3e 3f  40 40 41 42 42 43 44 45  |::;<==>?@@ABBCDE|
002e48b0  45 46 47 47 48 49 4a 4a  4b 4c 4d 4d 4e 4f 4f 50  |EFGGHIJJKLMMNOOP|
002e48c0  51 52 52 53 54 55 55 56  57 57 58 59 5a 5a 5b 5c  |QRRSTUUVWWXYZZ[\|
002e48d0  5c 5d 5e 5f 5f 60 61 62  62 63 64 64 65 66 67 67  |\]^__`abbcddefgg|
002e48e0  68 69 6a 6a 6b 6c 6c 6d  6e 6f 6f 70 71 71 72 73  |hijjkllmnoopqqrs|
002e48f0  74 74 75 76 77 77 78 79  79 7a 7b 7c 7c 7d 7e 7e  |ttuvwwxyyz{||}~~|
002e4900  7f 80 81 81 82 83 84 84  85 86 86 87 88 89 89 8a  |................|
002e4910  8b 8c 8c 8d 8e 8e 8f 90  90 91 92 93 93 94 95 95  |................|


Read code:
Code:
	begin
		if rising_edge(clock_out) then
				ldma_rdy := dma_rdy;
				rdreq_sig <= '0';
				valid_out <= '0';
				if (ldma_rdy = '0') then
					poscnt:=0;
				end if;
				if (ldma_rdy = '1' and poscnt<1024 and rdempty_sig = '0') then
						rdreq_sig <= '1';
						valid_out <= '1';
						--po<=rdusedw_sig(7 downto 0);
						po<=q_sig; --std_logic_vector(to_unsigned(counter, 8));
						--po<=std_logic_vector(to_unsigned(counter, 8));
						counter:=counter+1;
						poscnt:=poscnt+1;
				end if;


write code:
Code:
if rising_edge(clk_in) then
			wrreq_sig <=  '0';
			data_sig <= x"00";
			if (sync_in = '1') then
				enabledata:='1';
				bytepos:=0;
			end if;
			if (valid_in = '1' and enabledata = '1') then
				bytebuf(7-bytepos):=dat;
				bytepos:=bytepos+1;
				if (bytepos = 8) then
					wrreq_sig <= '1';
					data_sig <= std_logic_vector(to_unsigned(counter, 8));
					counter := counter+1;
					bytepos:=0;
				end if;
			end if;
 

without the entire design, it's difficult to say whats going on, and whether you're just writing every value twice, or ready every valid value twice.
Can you post the code and the testbench you used to test the design?
 

without the entire design, it's difficult to say whats going on, and whether you're just writing every value twice, or ready every valid value twice.
Can you post the code and the testbench you used to test the design?

thank you for your reply.

I'm new with VHDL so the testbench might be a bit difficult for me, I'm just trying to steadily write some values into the dcfifo and read it on the other side. So I would expect an output like 1 2 3 4 5 6 etc. and not 1 2 2 3 4 5 5 5 etc.

If I comment out following line in the reader part of the VHDL code:
--po<=std_logic_vector(to_unsigned(counter, 8));

the output is counting up steadily.

But for testing the DCFIFO I have now moved the counter into the feeder process, and I'm trying to read those values in the output process. But something's going wrong there so I get duplicate values from time to time.
Basically that's the feeder, just counting +1 every clock cycle (I'm simulating some dataframes that's why I have some other logic around it):

data_sig <= std_logic_vector(to_unsigned(counter, 8));
counter := counter+1;

As mentioned the fifo input is around 5MHz (although clk_in runs at around 40Mhz serial), and the output should be 8bit parallel.

Code:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library dcf;
use dcf.all;

entity leddecoder is
   port(valid_in: std_logic;
        clk_in: std_logic;
        sync_in: std_logic;
        dat: in std_logic;
        valid_out: out std_logic;
        po: out std_logic_vector(7 downto 0);
        clock_out: in std_logic;
	rst: in std_logic;
        dma_rdy: in std_logic;
        watermark: in std_logic);	
end leddecoder;


architecture behaviour of leddecoder is
	signal rdclk_sig: std_logic;
	signal wrempty_sig: std_logic;
	signal wrfull_sig: std_logic;
	signal q_sig: std_logic_vector(7 downto 0);
	signal rdempty_sig: std_logic;
	signal wrclk_sig: std_logic;
	signal wrreq_sig: std_logic;
	signal wrusedw_sig: std_logic_vector(11 downto 0);
	signal data_sig: std_logic_vector(7 downto 0);
	signal rdreq_sig: std_logic;
	signal rdusedw_sig: std_logic_vector(11 downto 0);
	
COMPONENT dcf
	PORT (
			rdclk	: IN STD_LOGIC ;
			wrempty	: OUT STD_LOGIC ;
			wrfull	: OUT STD_LOGIC ;
			q	: OUT STD_LOGIC_VECTOR (7 DOWNTO 0);
			rdempty	: OUT STD_LOGIC ;
			wrclk	: IN STD_LOGIC ;
			wrreq	: IN STD_LOGIC ;
			wrusedw	: OUT STD_LOGIC_VECTOR (11 DOWNTO 0);
			data	: IN STD_LOGIC_VECTOR (7 DOWNTO 0);
			rdreq	: IN STD_LOGIC ;
			rdusedw	: OUT STD_LOGIC_VECTOR (11 DOWNTO 0)
	);
END COMPONENT;
	TYPE MACHINE_STATE IS (STATE_IDLE, STATE_WRITE_1, STATE_WRITE_2, STATE_PAUSE);  -- Define the states
	SIGNAL State : MACHINE_STATE := STATE_IDLE;    -- Create a signal that uses 
begin
dcf_inst : dcf PORT MAP (
		data	 => data_sig,
		rdclk	 =>  clock_out,
		rdreq	 => rdreq_sig,
		wrclk	 => clk_in,
		wrreq	 => wrreq_sig,
		q	 => q_sig,
		rdempty	 => rdempty_sig,
		wrempty	 => wrempty_sig,
		wrfull	 => wrfull_sig,
		wrusedw	 => wrusedw_sig,
		rdusedw   => rdusedw_sig
	);
	
	process(clock_out)
	variable startread: std_logic := '0';
	variable readpos: natural range 0 to 500:= 0;
	variable data_avail: std_logic := '0';
	variable cnt_enable: natural range 0 to 3:=0;
	variable dpos: std_logic_vector(2 downto 0);
	variable init: std_logic := '0';
	variable transfer_started: std_logic := '0';
	variable counter: natural range 0 to 255 := 0;
	variable dma_rdy_toggled: std_logic := '1';
	variable startcnt: integer := 0;
	variable poscnt: integer := 0;
	variable lrdempty_sig: std_logic := '0';
	variable ldma_rdy: std_logic := '0';
	begin
		if rising_edge(clock_out) then
				ldma_rdy := dma_rdy;
				rdreq_sig <= '0';
				valid_out <= '0';
				if (ldma_rdy = '0') then
					poscnt:=0;
				end if;
				if (ldma_rdy = '1' and poscnt<1024 and rdempty_sig = '0') then
						rdreq_sig <= '1';
						valid_out <= '1';
						--po<=rdusedw_sig(7 downto 0);
						po<=q_sig; --std_logic_vector(to_unsigned(counter, 8));
						--po<=std_logic_vector(to_unsigned(counter, 8));
						counter:=counter+1;
						poscnt:=poscnt+1;
				end if;
			end if;
    end process;
	
	process(clk_in)
	variable bytebuf: std_logic_vector(7 downto 0) := x"00";
	variable enabledata: std_logic := '0';
	variable bytepos: integer range 0 to 8 := 0;
	variable counter: natural range 0 to 255 := 0; 
	
	begin
		if (rst = '1') then
			wrreq_sig <= '0';
		elsif rising_edge(clk_in) then
			wrreq_sig <=  '0';
			data_sig <= x"00";
			if (sync_in = '1') then
				enabledata:='1';
				bytepos:=0;
			end if;
			if (valid_in = '1' and enabledata = '1') then
				bytebuf(7-bytepos):=dat;
				bytepos:=bytepos+1;
				if (bytepos = 8) then
					wrreq_sig <= '1';
					data_sig <= std_logic_vector(to_unsigned(counter, 8));
					counter := counter+1;
					bytepos:=0;
				end if;
			end if;
		end if;
	end process;
end behaviour;
 

First off, if you're new to VHDL, I suggest you stay away from variables entirely. There is nothing you can do with variables that you cannot do with a signal. Signals will give you behaviour you expect, whereas variables do have some gotchas with them.

Without a testbench, it can be difficult to see whats going wrong. With simulation you can easily debug this code.

Is the FIFO a lookahead fifo? If it is, then I can you'll get the output twice at the start of a sequence as the read_request only goes high with the valid, meaning you'll be outputting the same output twice and marking it valid. This would be easy to see.
 

First off, if you're new to VHDL, I suggest you stay away from variables entirely. There is nothing you can do with variables that you cannot do with a signal. Signals will give you behaviour you expect, whereas variables do have some gotchas with them.

Without a testbench, it can be difficult to see whats going wrong. With simulation you can easily debug this code.

Is the FIFO a lookahead fifo? If it is, then I can you'll get the output twice at the start of a sequence as the read_request only goes high with the valid, meaning you'll be outputting the same output twice and marking it valid. This would be easy to see.

This is no lookahead fifo. I'm aware of the differences of variables and signals so far (variables are assigned immediately while signals are only assigned at the end of the process).

Just a generic question, shouldn't a dcfifo take care about the input / output synchronisation by itself?
Also what I'm confused about is rdusedw_sig, shouldn't I be able to do a check like if unsigned(rdusedw_sig) > 0 then ...

If I do that it always ends up with false (not entering the if at all).

I think I understand the dcfifo a wrong way in general
 

Yes, the fifo will take care of synchronisation. When rdempty = '0', then there is a word in the fifo for you to collect.
rdusedw tells you how many words are in the fifo. If it's never greater than 0 then I suggest theres nothing in the FIFO. But unless you have some pipeline you need to be able to accomodate in the fifo, you shouldnt have to use the rdusedw or wrusedw signals at all.
 

I was expecting the same what you wrote however the practical approach gives me a different result again...


Code:
lused := to_integer(unsigned(rdusedw_sig));
if lused > 0 then
...
end if;
it never enters the if path

I would expect that it has to enter the if path

----

now if I do:

Code:
if rdempty_sig = 0 then
  po <= rdusedw_sig(7 downto 0);
  ...
end if;

it will enter the if path and the output shows values greater than 0

Code:
00002f90  01 01 00 01 01 00 01 02  01 00 01 01 01 00 01 01  |................|
00002fa0  00 01 01 01 00 01 01 00  01 02 01 00 01 01 01 00  |................|
00002fb0  01 01 00 01 02 01 00 01  01 00 01 02 01 00 01 01  |................|
00002fc0  01 00 01 01 00 01 02 01  00 01 01 01 00 01 01 00  |................|
00002fd0  01 01 01 00 01 01 00 01  02 01 00 01 01 00 01 01  |................|
00002fe0  01 00 01 01 00 01 02 01  00 01 01 01 00 01 01 00  |................|
00002ff0  01 02 01 00 01 01 01 00  01 01 00 01 01 01 00 01  |................|
00003000  00 00 00 ff fe fd fc fb  fb fb fa fa f9 f9 f8 f8  |................|
00003010  f7 f7 f7 f6 f6 f5 f5 f4  f4 f4 f3 f3 f2 f2 f1 f1  |................|
00003020  f1 f0 f0 ef ef ee ee ee  ed ed ec ec eb eb ea ea  |................|
00003030  ea e9 e9 e8 e8 e7 e7 e7  e6 e6 e5 e5 e4 e4 e4 e3  |................|
00003040  e3 e2 e2 e1 e1 e1 e0 e0  df df de de dd dd dd dc  |................|
00003050  dc db db da da da d9 d9  d8 d8 d7 d7 d7 d6 d6 d5  |................|
00003060  d5 d4 d4 d4 d3 d3 d2 d2  d1 d1 d0 d0 d0 cf cf ce  |................|
00003070  ce cd cd cd cc cc cb cb  ca ca ca c9 c9 c8 c8 c7  |................|

Any idea what I'm doing wrong here, why isn't the first one entering the if at all? Or why can't I check if rdusedw_sig is greater than 0?

- - - Updated - - -

ok ignore this post I've done something wrong (but which is still unrelated to the original dcfifo problem)

there's a second argument in the if check which is not met (there's no problem with rdusedw_sig)
 

I think the problem you are having with duplicates is the read operation has to be gated with the empty flag, as the empty flag goes inactive after the clock edge that did the read, so if you look at empty in a clocked process you will already have another read (to an empty FIFO) that results in repeated data.

Code:
         1       2
          ___     ___     ___     ___    
  clk ___|   |___|   |___|   |___|   |___
                    _____________________
empty _____________|
           _______________
rd_en ____|      ^        |______________
                 Empty is still 0
                 so it reads an empty FIFO

- - - Updated - - -

This is based on the following snippet of code:

Code VHDL - [expand]
1
2
3
4
5
6
7
8
9
10
if rising_edge(clock_out) then
                ldma_rdy := dma_rdy;
                rdreq_sig <= '0';
                valid_out <= '0';
                if (ldma_rdy = '0') then
                    poscnt:=0;
                end if;
                if (ldma_rdy = '1' and poscnt<1024 and rdempty_sig = '0') then
                        rdreq_sig <= '1'; -- reads will occur after the FIFO is already empty
                                          -- as you are looking at the old state of rdempty_sig.

 

Hmm... can you give me a hint how to overcome that problem?
 

Hmm... can you give me a hint how to overcome that problem?

Sure, the solutions are actually rich in theory.

The first method is to use a two-process design -- at least for the read signal. When done only for the read signal, this method can be error prone with errors going undetected. This is because logic for the read enable must* be tightly coupled to the logic in the process while being written in a different style. As read logic gets more complex, this method becomes more error-prone. It becomes easier to miss a corner case and more likely for updates to the file to miss a corner case. Because the fifo may have internal combinatorial logic using the read enable, this method may also have lower max clock rate.

The second method performs or adds some form of size > N, N >=2 check. In this case, you can read from the fifo if "size >= N or size >= 1 and didn't read in the last (N-1) cycles" -- for N = 2. For this example, it means that when size >= 2 you will read at full rate. Otherwise you will read at half-rate. This allows the fifo to flush while still allowing full performance when the input can provide data fast enough. The general idea here is to get confirmation that you can do a read safely because N words have been written or N cycles have past since 1 word has been written. If the size > N "not almost empty" flag has a long clock-to-out, this could affect max frequency, especially with high-fanout.

The third method is to check the underflow flag on the output of the fifo. The issue with the normal case is that all reads are treated as successful reads. If the logic is written to confirm read success before treating the read as successful you will be ok. This method is less used because it normally isn't difficult to ensure valid reads on a fifo. Also, treating all read attempts as successful is a very useful property. However, the method is used in some cases when the fifo just need to be read as fast as possible.

(* you could also use a two process design style for the entire state machine logic. This style is not favored in 2016 because)
 

The second method performs or adds some form of size > N, N >=2 check. In this case, you can read from the fifo if "size >= N or size >= 1 and didn't read in the last (N-1) cycles" -- for N = 2. For this example, it means that when size >= 2 you will read at full rate.

thank you for your explanation, although I still don't seem to fully understand the whole issue it seems (for the reason that I cannot get it work)

So you mean following should do the trick (in theory) in the read process?

Code:
if ldma_rdy = '1' and poscnt<1024 and rdempty_sig = '0' and unsigned(rdusedw_sig) > 0 then
...
end if;

As soon as I try to access rdusedw_sig in the if check it doesn't enter the if anymore, although if I use po<=rdusedw_sig(7 downto 0); inside the if check and remove the rdusedw_sig check I can clearly see that there are values available.
That doesn't make sense no?

In signaltap I'm unable to find rdempty_sig the result of the other ones is dma_rdy=1, poscnt=0, rdusedw_sig=0

Since the dcfifo is fed by another process I do not see how the small if check in the reader process can affect the entire value of rdusedw_sig.

I'm surprised that the dcfifo is getting so difficult
 

This is a classic data hazard. You delay reading by one cycle by registering the read signal. As a result, the empty signal is also delayed by one cycle -- you didn't read on this cycle due to your added delay. The diagram by ads-ee shows this much better.

What I am saying is that the data hazard -- using inputs that have not been affected by previous outputs -- can be solved in a simple enough manner. When you decide to read, it take TWO cycles to know if that action results in the fifo becoming empty. One cycle to register the read signal, and one cycle to perform the read + generate the empty signal.

At this point -- with just empty -- you know that you can issue a read once every other cycle. You can issue a read using one cycle, wait one additional cycle for the action to complete, and then check to see if the fifo is empty. This actually should work for your use case, as 12MHz > 2*5Mhz.

However, it is also possible to read from the fifo if you know the fifo has enough valid entries that a read on this cycle couldn't possibly cause an underflow due to this off-by-one error. For example, if you know the fifo has 1000 valid entries and it will take you 2 cycles to see that number drop, then your double-read issue will cause it to drop to 998. 998 is still much more than 0. So you could very safely say you can read if the fifo has > 1000 valid entries on the current cycle. This number of 1000 could be lowered -- if you know the fifo has 2 valid entries, this double read would result in the fifo reaching exactly 0.

With these two conditions combined, you can read from a fifo with ((2+ entries) or ((when the fifo was not read on the last cycle) and has (1+ entries))).




And I suggest just doing a simulation on the fifo with some simplified read/write logic.
 

so shouldn't something like that delay it for a few cycles:

Code:
variable delay: std_logic_vector(3 downto 0) :="1111";
...
delay:=delay(2 downto 0) & rdempty_sig;
if ldma_rdy = '1' and delay = "0000" and poscnt<1024 then

because this also doesn't seem to work :-(
 

Is there any other (easier) way to transfer data from one process to another one available?

dual clock fifo doesn't seem to be as easy as I thought and it seems like there are too many ways to get it wrong and I don't even understand why things don't work out eg. the shifting of the rdempty_sig.
 

A simple solution is to add an almost empty flag to the FIFO set to 1. When inactive, 0, read at full speed when you find it is active, 1, then add an empty flag wait state to stop reading every clock cycle.

Also learn to use a simulator, functional verification by signal tap on hardware is a huge time waster.
 

https://www.edaboard.com/threads/360484/#post1543573

can someone explain that issue, why the greater than check is not working but there's still a value in rdusedw_sig (if I output it as data)?

and also that one:
delay:=delay(3 downto 0) & rdempty_sig;
if ldma_rdy = '1' and delay="00000" and poscnt<1024 then

why does that not work?
In that case I would expect to have at least 4 more entries in the dcfifo that should be enough to avoid a buffer underrun no?
 

so shouldn't something like that delay it for a few cycles:

Code:
variable delay: std_logic_vector(3 downto 0) :="1111";
...
delay:=delay(2 downto 0) & rdempty_sig;
if ldma_rdy = '1' and delay = "0000" and poscnt<1024 then

because this also doesn't seem to work :-(
Stop using variables and you'll have a lot less problems with understanding why things work or don't work. I've been developing FPGAs and ASICs for over 2 decades and I've never resorted to using variables or used blocking (Verilog) statements in sequential (FF) code. The only place I use variables is for memories due to the extreme performance hit you will see in the simulator if you create a large memory in VHDL and don't use a variable declaration. Of course there are a few others here that do use them but they admittedly use them sparingly and not for creating FFs mostly for generating some combinational logic that feeds a FF or similar.


Code VHDL - [expand]
1
2
3
4
5
6
7
8
9
10
variable ff_mess : unsigned (3 downto 0) := "0000";
process (clk)
begin
  if rising_edge(clk) then
    ff_mess := ff_mess + 1;  -- variable ff_mess has to be updated prior to the COMPARE! It is NOT a FF at this point it is a combinational ADD.
    if (ff_mess > 0) then  -- actually does (ff_mess + 1) > 0 so now you have an ADD and a COMPARE in the same combinational cone, lower Fmax.
      -- do stuff
    end if;
  end if;
end process;


The FFs generated by this code will be on the RHS ff_mess as that needs to be saved each time for the next clock cycle, but all the compares will be done on the combinational ADD operation. This is why I never use variables because you can end up with junk like this.

I'll admit I've used variables on occasion for purposes of clarity like in the following code:

Code VHDL - [expand]
1
2
3
4
5
6
7
8
9
10
11
variable active_tx := std_logic;
process (clk)
begin
  if rising_edge(clk) then
    tx_ok := tx_enabled AND tx_ready AND buffer_cnt > 10 AND tx_enable AND NOT rx_backpressure;
 
    if (tx_ok = '1') then -- now it's easy to see what this chunk of code is supposed to do, instead of decoding some long logic equation
      -- do some tx stuff
    end if;
  end if;
end process;

Note the variable is not used with any type of feedback (implying there has to be a FF added somewhere). The variable in this case is a combinational circuit feeding an enable statement (the if) in the code.

and also that one:
delay:=delay(3 downto 0) & rdempty_sig;
if ldma_rdy = '1' and delay="00000" and poscnt<1024 then

why does that not work?
In that case I would expect to have at least 4 more entries in the dcfifo that should be enough to avoid a buffer underrun no?
Adding delay to the empty flag will just make things worse.
original empty flag to read relationship.
Code:
         1       2
          ___     ___     ___     ___    
  clk ___|   |___|   |___|   |___|   |___
                    _____________________
empty _____________|
           _______________
rd_en ____|      ^        |______________
                 Empty is still 0
                 so it reads an empty FIFO

delayed empty flag to generate read.
Code:
         1       2
          ___     ___     ___     ___     ___    
  clk ___|   |___|   |___|   |___|   |___|   |___
                    _____________________________
empty _____________|     ^
           _______________ <- read while empty
rd_en ____|      ^        |______________________
                 Empty is still 0, so it starts
                 another read of an empty FIFO
                                   ______________
delay ____________________________|
           _______________________________ 
rd_en ____|      ^       ^       ^       ^|______
                 OK      E       E       E
                 Four reads are occuring with
                 three of them on an empty FIFO!
Delaying the empty makes the problem worse, you need to delay the read until you know if the FIFO is empty.

I think you're approaching this like a software engineer and are losing sight that this is a hardware description language. Variables make lousy hardware they can be interpreted as either combinational or FFs depending on how they are used in the code. As a hardware engineer I'd much rather tell the tools I WANT a FF HERE and I WANT a COMBO circuit HERE. I would never have built boards back in the day saying I want an IC that can change between combinational gates and FFs depending on how I connect it in the schematic.

- - - Updated - - -

Update.

Here is an example of why the use of variables is a bad coding style...
This code...

Code VHDL - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
library ieee;
use ieee.std_logic_1164.all; 
use ieee.numeric_std.all;
 
entity test is
port (
  clk     : in std_logic;
  o       : out std_logic
);
end test;
 
architecture behav of test is
 
begin
 
  process (clk)
    variable cnt : unsigned (3 downto 0) := x"0";
  begin
    if rising_edge(clk) then
      cnt := cnt + 1;
      if (cnt < x"A") then
        o <= '1';
      else
        o <= '0';
      end if;
    end if;
 
  end process;
 
end behav;



produces the following elaborated schematic.
Capture.PNG
Notice the registers for cnt that feed the ADD and then feed the comparison with x"A" before generating the o output.

Changing this to a signal results in the following circuit, which has slightly different timing but will also have a much improved Fmax.
Capture.PNG
 

Stop using variables and you'll have a lot less problems with understanding why things work or don't work.


produces the following elaborated schematic.
View attachment 133068
Notice the registers for cnt that feed the ADD and then feed the comparison with x"A" before generating the o output.

Changing this to a signal results in the following circuit, which has slightly different timing but will also have a much improved Fmax.
View attachment 133069

I think that is not a good example.
since variables are assigned immediately and signals are assigned at the end of the process you would have to put the increasing statement to the end of the process.

To what I can see it produces exactly the same RTL logic?

For some reason I cannot upload the picture:
Capture.PNG
 
Last edited by a moderator:

The problem with variables is that many company coding guidelines and engineers dont like them. They can be used to make just the same logic as signals, but as you've just shown, the position of a line of code can change the whole circuit.
You can use variables to keep local stuff local to the process only. But you can also do that with generates (you can put signals inside a generate).
If you insist on using variables you will come up a lot of resistance - Using them is seen as "bad form" and make people think of you as a converted software programmer, not someone who thinks in circuits.

signals are assigned at the end of the process

Not true. Signals are updated when a process suspends either through hitting a wait statement or the end of a process in the case of an event triggered process. consider the following:


Code VHDL - [expand]
1
2
3
4
5
6
7
process
begin
  op <= '0';
  wait until rising_edge(clk);
 
  op <= ip;
end process;



Here, op is always '0'.
I know it's poor code - but it highlights the answer.
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top