VHDL variables.  - Page 1
Forum section: electronics / general

author: GuilTy
author_rank: Contributor
timestamp: April 08, 2016, 12:46:57 pm
content: Hello,Does anybody know how to use a variable in VHDL, that has the same behaviour like a static variable in C?For example, I have an initial value which is 100. I subtract 10 from it and the new value is 90. But, then I want to substract 10 from the last value, which is 90, so the result will be 80, and so on.I tried to save the result in an intermediate variable, but when I try to subtract the second time, the value is still 90.Thank you,G

author: dmills
author_rank: Super Contributor
timestamp: April 08, 2016, 12:53:01 pm
content: Take one addition operation and imply a register at the output, feed the register back to the adder.Each time the process fires the register output will take the new value from the adder output, and the adder will get the new value from the register.Regards, Dan.

author: GuilTy
author_rank: Contributor
timestamp: April 08, 2016, 01:09:56 pm
content: And after the first rising edge of the clock, the initial value will update to the new value(which will come from the output of the register)? Is this what you are saying?G

author: rstofer
author_rank: Super Contributor
timestamp: April 08, 2016, 01:29:25 pm
content: Declarationvariable addr_v : unsigned(addr_i'range);Inside a clocked processaddr_v := addr_v + BLOCK_SIZE_G;

author: dmills
author_rank: Super Contributor
timestamp: April 08, 2016, 02:40:06 pm
content: Thats the one.Regards, Dan.

author: suicidaleggroll
author_rank: Super Contributor
timestamp: April 08, 2016, 02:47:43 pm
content: Quote from: GuilTy on April 08, 2016, 12:46:57 pmIt works the same as in any other language (see rstofer's example), with one major caveat. In a VHDL process, everything happens simultaneously. This means that something like the following:Code:addr_v := addr_v + BLOCK_SIZE_G;addr_v := addr_v + BLOCK_SIZE_G;will NOT add 2*BLOCK_SIZE_G, it will only do it once. You can only update a variable once per clock cycle, if you want to add BLOCK_SIZE_G a second time, you need to do it on the next clock cycle.

author: AndyC_772
author_rank: Super Contributor
timestamp: April 08, 2016, 02:54:13 pm
content: No, I don't think so; variables update immediately, so your example will indeed add 2*BLOCK_SIZE_G.By contrast,signalsonly update on events (assuming the new value is assigned within a clocked process). A later assignment will supersede an earlier one.

author: GuilTy
author_rank: Contributor
timestamp: April 08, 2016, 04:38:42 pm
content: Thank you all for your responses.@suicidaleggroll, in a process things happen sequentially, not simulatenously.G

author: rstofer
author_rank: Super Contributor
timestamp: April 08, 2016, 05:07:26 pm
content: Quote from: AndyC_772 on April 08, 2016, 02:54:13 pmI need to work on 'variables'. I don't tend to use them (like never) because I don't understand how they are synthesized and simulation is not hardware. Just a part of the universe I haven't explored.Here is an incredibly good discussion of VHDLhttp://www.utdallas.edu/~zxb107020/EE6306/Tutorial/VHDL.pdf

author: Scrts
author_rank: Frequent Contributor
timestamp: April 08, 2016, 06:06:11 pm
content: I've always used unsigned and casted to variables if needed for bit indexing. This kept me out of these dilemmas

author: AndyC_772
author_rank: Super Contributor
timestamp: April 08, 2016, 06:20:19 pm
content: Quote from: GuilTy on April 08, 2016, 04:38:42 pmNot really; in a process, things happen concurrently each time one of the signals in the process's sensitivity list changes.If you say:Code:IF clk'event AND clk = '1' THENb <= c;a <= b;END IF;... then both a and b take new values at exactly the same time. Signal 'a' will take its new value from whatever the value of 'b' was at the instant of the clock edge, not the new value (ie. the one equal to c).Variables are different, though:Code:IF clk'event AND clk = '1' THENb := c;a := b;END IF;In this case, on each edge, variables 'a' and 'b' will both get new values, and both will end up equal to c.

author: suicidaleggroll
author_rank: Super Contributor
timestamp: April 08, 2016, 06:40:30 pm
content: Quote from: AndyC_772 on April 08, 2016, 02:54:13 pmSorry, I so rarely use variables that I didn't realize they behaved differently than signals in this regard.

author: rstofer
author_rank: Super Contributor
timestamp: April 08, 2016, 06:59:55 pm
content: Quote from: AndyC_772 on April 08, 2016, 06:20:19 pmThank you for the motivation to experiment a bit and thanks for the education I gained!Code:library IEEE;use IEEE.STD_LOGIC_1164.ALL;entity Variables isPort ( clk : in STD_LOGIC;input : in STD_LOGIC;W : out STD_LOGIC;X : out STD_LOGIC;Y : out STD_LOGIC;Z : out STD_LOGIC);end Variables;architecture Behavioral of Variables issignal a,b : std_logic;shared variable c,d : std_logic;beginW <= a;X <= b;Y <= c;Z <= d;processbeginIF clk'event AND clk = '1' THENa <= input;b <= a;end if;if clk'event AND clk = '1' thenc := input;d := c;end if;end process;end Behavioral;After I synthesized the code, I took a look at the RTL schematic. At all times, W, Y & Z are identical and simply the output of a single D-flop connected to input and clk.Only X is clocked through 2 D-flops.I just knew there was a reason I didn't use variables and I'll have to think carefully if I use them in my next project. Variables are spooky!Now I want to see what they do in a CASE statement when they appear in a case that isn't executed. I see variables used instead of logic vectors for things like counters. I don't see the motivation but I do see them used. I need to do some more experiments.

author: Neilm
author_rank: Super Contributor
timestamp: April 08, 2016, 07:10:50 pm
content: Generally, I only use variables in state machines and counters.

author: AndyC_772
author_rank: Super Contributor
timestamp: April 08, 2016, 08:03:48 pm
content: I use them a lot to break down and clarify expressions that might be too long and complicated to easily read otherwise.For example, suppose I have a 32-bit integer, and want to replace 8 bits of it with a byte that's been read in from elsewhere.One way to do it would be to write:Code:VARIABLE v_long_integer : STD_LOGIC_VECTOR (31 DOWNTO 0);v_long_integer := CONV_STD_LOGIC_VECTOR (long_integer, 32);v_long_integer (15 DOWNTO 8) := CONV_STD_LOGIC_VECTOR (external_byte, 8);long_integer <= CONV_INTEGER (UNSIGNED(v_long_integer));These few lines of code simply indicate that bits 15..8 take a new value, and the rest remain unchanged. The actual logic that ends up getting synthesized is trivial. Inferring the correct logic without the use of variables is much more complex and difficult to express clearly.

author: rstofer
author_rank: Super Contributor
timestamp: April 08, 2016, 09:27:18 pm
content: QuoteI tend to just use concatenation...signal longvector : std_logic_vector(31 downto 0);signal newdata : std_logic_vector(7 downto 0);longvector <= longvector(31 downto 16) & newdata & longvector(7 downto 0);I hope I didn't mess up the syntax! Anyway, I tend to use the concat operator quite a bit.And then there is Verilog. I don't know anything about that language so I think I'll force myself to use it when I rewrite my CPU project for a newer chip. Maybe after 10 or 20 thousand lines of code, I'll get the hang of it.

author: rstofer
author_rank: Super Contributor
timestamp: April 08, 2016, 10:45:56 pm
content: Quote from: rstofer on April 08, 2016, 09:27:18 pmThe concatenation would have to be in a clocked process. The variable approach wouldn't have to be clocked (AFAIK).

author: AndyC_772
author_rank: Super Contributor
timestamp: April 09, 2016, 03:26:44 pm
content: Both are just different ways to express the same intent; there's no difference between how they'd behave.I prefer the variable approach because it allows the assignment to be broken down into clear, individual steps:- convert from integer type to vector- replace some bits in the vector with the new value- convert the new, updated vector back into an integerIn this example, the type conversion doesn't actually require any physical hardware - but it could.My personal favourite use of variables in VHDL was to implement a CRC algorithm. The classical description of how to compute a CRC involves shifting the data a bit at a time into a shift register, and performing an XOR involving various taps (and the new data bit) to work out the value of the next bit to shift in.This is all well and good, but it's not really much help if new data is available a byte at a time.There's plenty of example code showing how to implement a byte-wide CRC, but it's not particularly readable. Big tables of magic numbers start appearing, and to someone familiar with the bit-at-a-time approach, the algorithm isn't immediately recognisable.So, a nice trick to do in VHDL is to use variables, and to let the compiler do the hard work of figuring out how to deal with a whole byte at a time, given an algorithm that operates on a single bit at a time. Something like:Code:SIGNAL crc : STD_LOGIC_VECTOR (31 DOWNTO 0);CONSTANT poly : STD_LOGIC_VECTOR (31 DOWNTO 0) := "10001...."; -- generator polynomialSIGNAL new : STD_LOGIC_VECTOR (7 DOWNTO 0);VARIABLE v_new_crc : STD_LOGIC_VECTOR (31 DOWNTO 0);VARIABLE v_new_bit : STD_LOGIC;IF clk'event AND clk = '1' THENv_new_crc := crc;FOR i IN 0 TO 7 LOOPv_new_bit := new (i); -- pick out the next bit from our new data byte-- Step through the whole of the generator polynomial to find out where the taps are-- If there's a tap in a given position, XOR the new data bit with the shift reg contentsFOR j IN 0 TO 31 LOOPIF poly (j) = '1' THENv_new_bit := v_new_bit XOR v_new_crc (j);END IF;END IF;v_new_crc (31 DOWNTO 1) := v_new_crc (30 DOWNTO 0);v_new_crc (0) := v_new_bit;END LOOP;crc <= v_new_crc;END IF;I may have the details of the algorithm wrong, but I think as a way to illustrate the use of variables, it's still valid. What this code describes is a whole bunch of operations to be carried out on each clock edge, and the key thing to note is that on each edge there's exactly one assignment of a new value to a signal - namely, the update of signal 'crc' right at the end.The new value of 'crc' is computed by following a sequence of steps incorporating a nested loop, and if it were being executed on a microprocessor core, it would be quite inefficient. But in VHDL, themeaningof that nested loop is evaluated at compile time, and the compiler's job is to work out a way to make the FPGA's hardware deliver the correct net end result.Nothing in the FPGA actually iterates here. There's no state machine, and no sequence of steps that are actually executed one after the other.... just a single 32-bit value which is updated once per clock edge, based on the value of a data byte.

author: exmadscientist
author_rank: Frequent Contributor
timestamp: April 09, 2016, 04:54:30 pm
content: Expanding on that theme, here's a chunk of VHDL that computes 32-bit CRCs on an entire 32-bit input word, which has the additional issue of dealing with byte ordering. This is a piece of production code I wrote a while back, which has been tested and verified with CRC-32 and CRC-32C checksums.I really don't know how to write this sanely and readably without variables. Performance is excellent, because the synthesizer sorts out all the complicated logic and produces an implementation that gives you one word of output per clock.Code:--------------------------------------------------------------------------------- File : crc32.vhd-- Description : Generic 32-bit CRC calculator. Consumes one 32-bit input word-- every clock, updating the output CRC value. Parameterized to-- compute the major CRC variants encountered in the wild.--------------------------------------------------------------------------------library ieee;use ieee.std_logic_1164.all;use ieee.numeric_std.all;--------------------------------------------------------------------------------- Entity-------------------------------------------------------------------------------entity crc32 isgeneric (-- Default parameters are for the standard "CRC-32" (IEEE 802.3) algorithmPOLY : std_logic_vector(31 downto 0) := X"04C11DB7";XORIN : std_logic_vector(31 downto 0) := X"FFFFFFFF";XOROUT : std_logic_vector(31 downto 0) := X"FFFFFFFF";REFLECTIN : boolean := true;REFLECTOUT: boolean := true);port (clk : in std_logic;reset : in std_logic;ena : in std_logic;data : in std_logic_vector(31 downto 0);crc : out std_logic_vector(31 downto 0));end entity crc32;--------------------------------------------------------------------------------- Architecture-------------------------------------------------------------------------------architecture rtl of crc32 issignal crc_i : std_logic_vector(31 downto 0);signal crc_i_reflected : std_logic_vector(31 downto 0);beginpr_crc32 : process (clk)variable v_fb : std_logic_vector(31 downto 0);variable crc_reg : std_logic_vector(31 downto 0);variable crc0 : std_logic;beginif (rising_edge(clk)) thenif (reset = '1') thencrc_reg := XORIN;crc_i <= crc_reg;elseif (ena = '1') then--For each bit in the input, calculate the serial CRC.--Always consume LSByte first in CRC calculations.if REFLECTIN then--Reflected bit order:--Consume the LSBit of each byte first.for bit_idx in 0 to 31 loopcrc0 := crc_reg(31);crc_reg := (crc_reg(30 downto 0) & '0');if (crc0 /= data(bit_idx)) thencrc_reg := crc_reg xor POLY;end if;end loop;else--Normal bit order:--We still consume the least significant byte first,-- but bit order within each byte is reversed to-- consume the MSBit first.for byte_idx in 0 to 3 loopfor bit_idx in 7 downto 0 loopcrc0 := crc_reg(31);crc_reg := (crc_reg(30 downto 0) & '0');if (crc0 /= data(8*byte_idx + bit_idx)) thencrc_reg := crc_reg xor POLY;end if;end loop;end loop;end if;crc_i <= crc_reg;end if;end if;end if;end process pr_crc32;g_reversed_output: for i in 0 to 31 generatecrc_i_reflected(31-i) <= crc_i(i);end generate;crc <= crc_i_reflected xor XOROUT when REFLECTOUTelse crc_i xor XOROUT;end architecture rtl;

author: rstofer
author_rank: Super Contributor
timestamp: April 10, 2016, 12:14:26 am
content: OK guys! I give...You are both way above my pay grade!. Now I'll have to spend a couple of hours coding this up and seeing how it synthesizes. So much to learn, so little time...

author: GuilTy
author_rank: Contributor
timestamp: April 11, 2016, 01:24:26 pm
content: I wish I had found this pdf earlier.Quote from: rstofer on April 08, 2016, 05:07:26 pmGracias

author: tggzzz
author_rank: Super Contributor
timestamp: April 11, 2016, 01:55:10 pm
content: Quote from: GuilTy on April 08, 2016, 12:46:57 pmThatkindof question is always worrying.With any new language it is necessary to understand whatthat languagemeans by certain words. Doubly so for the differences between procesural software languages and hardware description languages.

author: GuilTy
author_rank: Contributor
timestamp: April 11, 2016, 02:04:30 pm
content: Quote from: tggzzz on April 11, 2016, 01:55:10 pmDo you have any good documentation about VHDL?

author: jahonen
author_rank: Super Contributor
timestamp: April 11, 2016, 02:15:32 pm
content: I use variables if I have something which is purely local thing for a process. It makes things less cluttered as signals are then always for things which are shared between processes. It also makes it easy to duplicate the process if necessary without adding any extra clutter, say, in generate context.I think that synthesis is pretty clear. With signals one can only access the registered version of the value (if value is assigned by clocked process), or give new value to the input of the register in question.But with variables, if one reads the variable value before changing it in a clocked process, then it is like in signal case, output of a register. But if value of a variable is read (or used in any way) after it is changed, then it is the result from the combination logic feeding that register (simple?). So I think there is nothing inherently bad about using them on an actual hardware, if used correctly. Of course, abuse is easier with variables.Regards,Janne

author: tggzzz
author_rank: Super Contributor
timestamp: April 11, 2016, 03:18:30 pm
content: Quote from: GuilTy on April 11, 2016, 02:04:30 pmI have around 20 bookmarks which have been useful to me in the past. All were found by googling for what I needed to know at the time. Some have been mentioned here already, some may be dead links by now.It very much depends on whatyouneed for yournextproblem. I would suggest you start looking for "style guides" or "primers" or "FAQs" and similar, and then understandwhythey recommend that style.

author: GuilTy
author_rank: Contributor
timestamp: April 11, 2016, 08:19:29 pm
content: Quote from: jahonen on April 11, 2016, 02:15:32 pmIt makes more sense now. As I said, I'm new to VHDL.Quote from: tggzzz on April 11, 2016, 01:55:10 pmI find your advice useful. It's way simpler to search for a specific thing.Thanks to the both of you,G

author: blackbird
author_rank: Regular Contributor
timestamp: April 12, 2016, 08:02:42 am
content: Quote from: GuilTy on April 11, 2016, 02:04:30 pmBesides the numerous websites I've bookmarked myself, I have two hard copies of VHDL books:Digital System Design with VHDLby Mark Zwolinski.This one I would not recommend to start with VHDL (I had to buy this one as one of my first books at uni)Circuit Design and Simulation with VHDLby Volnei Pedroni.This is a much better one, to my opinion suitable for starters. Had to buy this one for my second year at uni.If you search long enough you can find these digitally on the web although I strongly recommend to have a hard copy (at least of the second one).

author: GuilTy
author_rank: Contributor
timestamp: April 12, 2016, 12:54:15 pm
content: Quote from: blackbird on April 12, 2016, 08:02:42 amThank you. Now I'm reading "FPGA PROTOTYPING BY VHDL EXAMPLES " by Pong P. Chu. Maybe it will help someone else too.G