GitHub

Variables – VHDL Example

Variables in VHDL act similarly to variables in C. Their value is valid at the exact location in the code where the variable is modified. Therefore, if a signal uses the value of the variable before the assignment , it will have the old variable value. If a signal uses the value of the variable after the assignment it will have the new variable value.

Rules of Variables:

  • Variables can only be used inside processes
  • Any variable that is created in one process cannot be used in another process
  • Variables need to be defined after the keyword process but before the keyword begin
  • Variables are assigned using the := assignment symbol
  • Variables that are assigned immediately take the value of the assignment

The most important thing to understand is that variables immediately take the value of their assignment. Here’s an example that shows one useful way to use variables: storing data for temporary use . It uses a case statement and the ampersand (&) concatenation operator .

In the previous example, we concatenated the two signals so that they could be used in the case statement. The variable v_Choices was immediately available for use as soon as it was assigned. Let’s look at another example. The example below is more comprehensive and demonstrates how variables immediately take the value of their assignment. The signals r_Var_Copy1 and r_Var_Copy2 appear to be the same, but r_Var_Copy2 is never able to get to 5 before it is reset.

In order to simulate our design, we need to create a testbench . Also, variables can be a bit tricky to display in simulation. If you are using Modelsim, read more about how to see your variables in Modelsim’s waveform window .

The example above demonstrates how variables act differently from signals. The signals r_Var_Copy1 and r_Var_Copy2 appear to be the same, but r_Var_Copy2 is never able to get to 5 before it is reset.

Read more about how variables and signals are different

Learn Verilog

Leave A Comment Cancel reply

Save my name, email, and website in this browser for the next time I comment.

courses:system_design:vhdl_language_and_syntax:sequential_statements:variables

Fundamentals

  • Name within process declarations
  • Known only in this process
  • Immediate assignment
  • Keep the last value
  • Signal to variable
  • Variable to signal
  • Types have to match

Variables can only be defined in a process and they are only accessible within this process.

Variables and signals show a fundamentally different behavior. In a process, the last signal assignment to a signal is carried out when the process execution is suspended. Value assignments to variables, however, are carried out immediately. To distinguish between a signal and a variable assignment different symbols are used: ’⇐’ indicates a signal assignment and ’:=’ indicates a variable assignment.

Variables vs. Signals

  • Signal values are assigned after the process execution
  • Only the last signal assignment is carried out
  • M ⇐ A; is overwritten by M ⇐ C;
  • The 2nd adder input is connected to C

The two processes shown in the example implement different behavior as both outputs Z and Y will be set to the result of B+C when signals are used instead of variables.

Please note that the intermediate signals have to added to the sensitivity list, as they are read during process execution.

Use of Variables

  • signal to variable assignment
  • execution of algorithm
  • variable to signal assignments
  • no access to variable values outside their process
  • variables store their value until the next process call

Variables are especially suited for the implementation of algorithms. Usually, the signal values are copied into variables before the algorithm is carried out.

The result is assigned to a signal again afterwards.

Variables keep their value from one process call to the next, i.e. if a variable is read before a value has been assigned, the variable will have to show storage behavior. That means it will have to be synthesized to a latch or flip flop respectively.

Variables: Example

  • Parity calculation
  • Synthesis result:

In the example a further difference between signals and variables is shown. While a (scalar) signal can always be associated with a line, this is not valid for variables. In the example the for loop is executed four times. Each time the variable TMP describes a different line of the resulting hardware. The different lines are the outputs of the corresponding XOR gates.

Shared Variables (VHDL’93)

  • Accessible by all processes of an architecture (shared variables)
  • Can introduce non determinism

In VHDL 93, global variables are allowed.

These variables are not only visible within a process but within the entire architecture.

The problem may occur, that two processes assign a different value to a global variable at the same time. It is not clear then, which of these processes assigns the value to the variable last.

This can lead to a non deterministic behavior!

In synthesizable VHDL code global variables must not be used.

Chapters of System Design > VHDL Language and Syntax > Sequential Statements

  • Sequential Statements
  • IF Statement
  • CASE Statement
  • WAIT Statement

Chapters of System Design > VHDL Language and Syntax

  • General Issues
  • VHDL Structural Elements
  • Process Execution
  • Extended Data Types
  • Subprograms
  • Subprogram Declaration and Overloading
  • Concurrent Statements

variable assignment in vhdl

In VHDL -93, shared variables may be declared within an architecture, block, generate statement, or package:

Chapter 4 - Behavioral Descriptions

Section 2 - using variables.

  • Getting started with vhdl
  • D-Flip-Flops (DFF) and latches
  • Digital hardware design using VHDL in a nutshell
  • Identifiers
  • Protected types
  • Recursivity
  • Resolution functions, unresolved and resolved types
  • Static Timing Analysis - what does it mean when a design fails timing?

vhdl Getting started with vhdl Signals vs. variables, a brief overview of the simulation semantics of VHDL

Fastest entity framework extensions.

This example deals with one of the most fundamental aspects of the VHDL language: the simulation semantics. It is intended for VHDL beginners and presents a simplified view where many details have been omitted (postponed processes, VHDL Procedural Interface, shared variables...) Readers interested in the real complete semantics shall refer to the Language Reference Manual (LRM).

Signals and variables

Most classical imperative programming languages use variables. They are value containers. An assignment operator is used to store a value in a variable:

and the value currently stored in a variable can be read and used in other statements:

VHDL also uses variables and they have exactly the same role as in most imperative languages. But VHDL also offers another kind of value container: the signal. Signals also store values, can also be assigned and read. The type of values that can be stored in signals is (almost) the same as in variables.

So, why having two kinds of value containers? The answer to this question is essential and at the heart of the language. Understanding the difference between variables and signals is the very first thing to do before trying to program anything in VHDL.

Let us illustrate this difference on a concrete example: the swapping.

Note: all the following code snippets are parts of processes. We will see later what processes are.

swaps variables a and b . After executing these 3 instructions, the new content of a is the old content of b and conversely. Like in most programming languages, a third temporary variable ( tmp ) is needed. If, instead of variables, we wanted to swap signals, we would write:

with the same result and without the need of a third temporary signal!

Note: the VHDL signal assignment operator <= is different from the variable assignment operator := .

Let us look at a second example in which we assume that the print subprogram prints the decimal representation of its parameter. If a is an integer variable and its current value is 15, executing:

will print:

If we execute this step by step in a debugger we can see the value of a changing from the initial 15 to 30, 25 and finally 5.

But if s is an integer signal and its current value is 15, executing:

If we execute this step by step in a debugger we will not see any value change of s until after the wait instruction. Moreover, the final value of s will not be 15, 30, 25 or 5 but 3!

This apparently strange behavior is due the fundamentally parallel nature of digital hardware, as we will see in the following sections.

Parallelism

VHDL being a Hardware Description Language (HDL), it is parallel by nature. A VHDL program is a collection of sequential programs that run in parallel. These sequential programs are called processes:

The processes, just like the hardware they are modelling, never end: they are infinite loops. After executing the last instruction, the execution continues with the first.

As with any programming language that supports one form or another of parallelism, a scheduler is responsible for deciding which process to execute (and when) during a VHDL simulation. Moreover, the language offers specific constructs for inter-process communication and synchronization.

The scheduler maintains a list of all processes and, for each of them, records its current state which can be running , run-able or suspended . There is at most one process in running state: the one that is currently executed. As long as the currently running process does not execute a wait instruction, it continues running and prevents any other process from being executed. The VHDL scheduler is not preemptive: it is each process responsibility to suspend itself and let other processes run. This is one of the problems that VHDL beginners frequently encounter: the free running process.

Note: variable a is declared locally while signals s and r are declared elsewhere, at a higher level. VHDL variables are local to the process that declares them and cannot be seen by other processes. Another process could also declare a variable named a , it would not be the same variable as the one of process P3 .

As soon as the scheduler will resume the P3 process, the simulation will get stuck, the simulation current time will not progress anymore and the only way to stop this will be to kill or interrupt the simulation. The reason is that P3 has not wait statement and will thus stay in running state forever, looping over its 3 instructions. No other process will ever be given a chance to run, even if it is run-able .

Even processes containing a wait statement can cause the same problem:

Note: the VHDL equality operator is = .

If process P4 is resumed while the value of signal s is 3, it will run forever because the a = 16 condition will never be true.

Let us assume that our VHDL program does not contain such pathological processes. When the running process executes a wait instruction, it is immediately suspended and the scheduler puts it in the suspended state. The wait instruction also carries the condition for the process to become run-able again. Example:

means suspend me until the value of signal s changes . This condition is recorded by the scheduler. The scheduler then selects another process among the run-able , puts it in running state and executes it. And the same repeats until all run-able processes have been executed and suspended.

Important note: when several processes are run-able , the VHDL standard does not specify how the scheduler shall select which one to run. A consequence is that, depending on the simulator, the simulator's version, the operating system, or anything else, two simulations of the same VHDL model could, at one point, make different choices and select a different process to execute. If this choice had an impact on the simulation results, we could say that VHDL is non-deterministic. As non-determinism is usually undesirable, it would be the responsibility of the programmers to avoid non-deterministic situations. Fortunately, VHDL takes care of this and this is where signals enter the picture.

Signals and inter-process communication

VHDL avoids non determinism using two specific characteristics:

  • Processes can exchange information only through signals
Note: VHDL comments extend from -- to the end of the line.
  • The value of a VHDL signal does not change during the execution of processes

Every time a signal is assigned, the assigned value is recorded by the scheduler but the current value of the signal remains unchanged. This is another major difference with variables that take their new value immediately after being assigned.

Let us look at an execution of process P5 above and assume that a=5 , s=1 and r=0 when it is resumed by the scheduler. After executing instruction a := s + 1; , the value of variable a changes and becomes 2 (1+1). When executing the next instruction r <= a; it is the new value of a (2) that is assigned to r . But r being a signal, the current value of r is still 0. So, when executing a := r + 1; , variable a takes (immediately) value 1 (0+1), not 3 (2+1) as the intuition would say.

When will signal r really take its new value? When the scheduler will have executed all run-able processes and they will all be suspended. This is also referred to as: after one delta cycle . It is only then that the scheduler will look at all the values that have been assigned to signals and actually update the values of the signals. A VHDL simulation is an alternation of execution phases and signal update phases. During execution phases, the value of the signals is frozen. Symbolically, we say that between an execution phase and the following signal update phase a delta of time elapsed. This is not real time. A delta cycle has no physical duration.

Thanks to this delayed signal update mechanism, VHDL is deterministic. Processes can communicate only with signals and signals do not change during the execution of the processes. So, the order of execution of the processes does not matter: their external environment (the signals) does not change during the execution. Let us show this on the previous example with processes P5 and P6 , where the initial state is P5.a=5 , P6.a=10 , s=17 , r=0 and where the scheduler decides to run P5 first and P6 next. The following table shows the value of the two variables, the current and next values of the signals after executing each instruction of each process:

With the same initial conditions, if the scheduler decides to run P6 first and P5 next:

As we can see, after the execution of our two processes, the result is the same whatever the order of execution.

This counter-intuitive signal assignment semantics is the reason of a second type of problems that VHDL beginners frequently encounter: the assignment that apparently does not work because it is delayed by one delta cycle. When running process P5 step-by-step in a debugger, after r has been assigned 18 and a has been assigned r + 1 , one could expect that the value of a is 19 but the debugger obstinately says that r=0 and a=1 ...

Note: the same signal can be assigned several times during the same execution phase. In this case, it is the last assignment that decides the next value of the signal. The other assignments have no effect at all, just like if they never had been executed.

It is time to check our understanding: please go back to our very first swapping example and try to understand why:

actually swaps signals r and s without the need of a third temporary signal and why:

would be strictly equivalent. Try to understand also why, if s is an integer signal and its current value is 15, and we execute:

the two first assignments of signal s have no effect, why s is finally assigned 3 and why the two printed values are 15 and 3.

Physical time

In order to model hardware it is very useful to be able to model the physical time taken by some operation. Here is an example of how this can be done in VHDL. The example models a synchronous counter and it is a full, self-contained, VHDL code that could be compiled and simulated:

In process P1 the wait instruction is not used to wait until the value of a signal changes, like we saw up to now, but to wait for a given duration. This process models a clock generator. Signal clk is the clock of our system, it is periodic with period 20 ns (50 MHz) and has duty cycle.

Process P2 models a register that, if a rising edge of clk just occurred, assigns the value of its input nc to its output c and then waits for the next value change of clk .

Process P3 models an incrementer that assigns the value of its input c , incremented by one, to its output nc ... with a physical delay of 5 ns. It then waits until the value of its input c changes. This is also new. Up to now we always assigned signals with:

which, for the reasons explained in the previous sections, we can implicitly translate into:

This small digital hardware system could be represented by the following figure:

A synchronous counter

With the introduction of the physical time, and knowing that we also have a symbolic time measured in delta , we now have a two dimensional time that we will denote T+D where T is a physical time measured in nano-seconds and D a number of deltas (with no physical duration).

The complete picture

There is one important aspect of the VHDL simulation that we did not discuss yet: after an execution phase all processes are in suspended state. We informally stated that the scheduler then updates the values of the signals that have been assigned. But, in our example of a synchronous counter, shall it update signals clk , c and nc at the same time? What about the physical delays? And what happens next with all processes in suspended state and none in run-able state?

The complete (but simplified) simulation algorithm is the following:

  • Set current time Tc to 0+0 (0 ns, 0 delta-cycle)
  • Initialize all signals.
  • Record the values and delays of signal assignments.
  • Record the conditions for the process to resume (delay or signal change).
  • The resume time of processes suspended by a wait for <delay> .
  • The next time at which a signal value shall change.
  • Update signals that need to be.
  • Put in run-able state all processes that were waiting for a value change of one of the signals that has been updated.
  • Put in run-able state all processes that were suspended by a wait for <delay> statement and for which the resume time is Tc .
  • If Tn is infinity, stop simulation. Else, start a new simulation cycle.

Manual simulation

To conclude, let us now manually exercise the simplified simulation algorithm on the synchronous counter presented above. We arbitrary decide that, when several processes are run-able, the order will be P3 > P2 > P1 . The following tables represent the evolution of the state of the system during the initialization and the first simulation cycles. Each signal has its own column in which the current value is indicated. When a signal assignment is executed, the scheduled value is appended to the current value, e.g. a/b@T+D if the current value is a and the next value will be b at time T+D (physical time plus delta cycles). The 3 last columns indicate the condition to resume the suspended processes (name of signals that must change or time at which the process shall resume).

Initialization phase:

Simulation cycle #1.

Note: during the first simulation cycle there is no execution phase because none of our 3 processes has its resume condition satisfied. P2 is waiting for a value change of clk and there has been a transaction on clk , but as the old and new values are the same, this is not a value change .

Simulation cycle #2

Note: again, there is no execution phase. nc changed but no process is waiting on nc .

Simulation cycle #3

Simulation cycle #4, simulation cycle #5.

Note: one could think that the nc update would be scheduled at 15+2 , while we scheduled it at 15+0 . When adding a non-zero physical delay (here 5 ns ) to a current time ( 10+2 ), the delta cycles vanish. Indeed, delta cycles are useful only to distinguish different simulation times T+0 , T+1 ... with the same physical time T . As soon as the physical time changes, the delta cycles can be reset.

Simulation cycle #6

Simulation cycle #7, simulation cycle #8, simulation cycle #9, simulation cycle #10, simulation cycle #11, got any vhdl question.

pdf

  • Advertise with us
  • Cookie Policy
  • Privacy Policy

Get monthly updates about new articles, cheatsheets, and tricks.

A variable assignment statement replaces the current value of a variable with a new value specified by an expression.

Description:

The expression assigned to a variable must give results of the same type as the variable. The target at the left-hand side of the assignment can be either a name of a variable or an aggregate .

A variable name can be in the form of simple name, selected name, indexed name or slice name.

If the target is an aggregate, then the type of the aggregate must be determinable from the context.

  • Variable assignment takes effect immediately.
  • Variable assignment can not be specified with a delay.

Expression , Sequential statement , Signal assignment , Variable

VHDLwhiz

Using variables for registers or memory in VHDL

Variables used as registers in VHDL

One question that I’ve debated many times over the years is whether it’s OK to use variables for registers in VHDL. It’s safe to say that newbies are more likely to do it than experienced VHDL designers. But is there any merit to that, or is it just a matter of preference?

In this blog post, I will try to shed some light on the issue so that you can make an informed decision about using this design practice.

First of all, let me explain what I mean by using a variable as a register.

If you read a variable in a VHDL process before you write to it, the synthesis tool will have to implement it using physical storage. That’s because its value has to be stored somewhere until the next time the process wakes up. In FPGAs, that means either registers (flip-flops) or memory (block RAM).

The code below shows an example process where my_var is not a register. The logic doesn’t rely on any previous value of the variable. We give it a default value of ‘0’ as soon as we enter the process.

If we comment out the default assignment to my_var , as shown in the example below, it becomes a register. That’s because if some_condition is false, my_signal gets whatever value my_var had the last time the process completed. You are telling the synthesis tool to remember the value of my_var over time, and the only way to do that is by using a register.

It’s perfectly legal to use variables like that in VHDL. Also, the FPGA tools won’t have any trouble implementing it most of the time. Still, it’s a design practice that’s frowned upon by many FPGA engineers. Some companies even prohibit such use of variables through their coding standards. Let’s have a look at an example and examine the pros and cons of using variables over signals.

Example using a variable to infer block RAM

In this example, I’ve created a VHDL process for inferring a dual-port RAM. The width and depth match a configuration of the Xilinx RAMB36E1 primitive, as shown on page 30 of the 7 Series FPGAs Memory Resources user guide. The code below shows the VHDL process. We store the values in the ram_v object, which is a regular variable.

When we synthesize the code in Xilinx Vivado, we see that it has indeed implemented ram_v in block RAM. Below is an excerpt from the synthesis log, showing the variable’s name mapped to a RAMB36 primitive.

Variables used for limiting the scope

A possible advantage of using a variable is that its scope is limited to within the process. Along with the variable, we can also place the type declaration of the array inside of the process. Limiting the scope of data objects is generally considered to be a good coding practice. Keeping all the constructs that “belong” to the process within it helps to refine the process as a separate design unit.

There are ways of creating limited scopes for signals as well, for example, by using the VHDL block statement . But as you can see from the example below, it adds more code lines and another indentation level to your VHDL file. I have to give a small victory to variables when it comes to encapsulation.

Line ordering matters with variables

A thing to be aware of when using variables is that the ordering of the lines matter. If we swap lines 7 and 8 in the original DUAL_PORT_RAM process, it’s broken. That’s not the case if we swap lines 12 and 13 in the code above. With signals, only which enclosure they are within matters, while with variables, the correct ordering of code lines is crucial.

Refer to my earlier blog post to understand the general difference between signals and variables: How a signal is different from a variable in VHDL

That’s one of the main objections many VHDL designers have against variables used for registers. Some engineers are accustomed to reading the code within an enclosure, like an if-statement, as parallel events. By using both variables and signals interchangeably, it becomes harder to follow the program flow. The code becomes less readable because your mind has to comprehend two constructs with different sets of rules, describing the same thing.

Of course, the arguments about readability is a subjective one. Furthermore, if you expect only signals to describe registers, you may be more inclined to overlook a variable that does the same. But if you use variables for that regularly, it may not be that big an issue for you.

Viewing variables in the ModelSim waveform

When using variables for data storage, you may want to track the value over time in the simulator. Most simulators treat variables different from signals in many ways. In ModelSim, they are not immediately accessible from the Objects window. It’s something to be aware of, but it’s a minor problem.

The video above shows how you can add a variable to the waveform in ModelSim. Bring up the Locals window by choosing View→Locals from the main menu. Select the process that contains the variable, and it will appear under Locals . Right-click the variable and add select Add Wave , just as you would with a signal.

Final thoughts

Before writing this article, I posted a question in my private Facebook group to see what other FPGA engineers had to say about using variables for storage. As I expected, most dislike using variables in this way in RTL modules. The consensus is that they are confusing to work with when they assume the same role as signals: to act as registers.

One user wrote that there’s a higher risk of creating latches with variables than signals. I’ve heard that statement before, and I tried to construct an example to demonstrate the problem, but I couldn’t. I wasn’t able to find any situations where a variable causes a latch while a signal doesn’t. Of course, that doesn’t mean that it can’t happen. But we will have to leave that statement unconfirmed at the moment.

Leave a comment if you have such an example!

Finally, a user whose first name is Ray sums up nicely what I think is the most significate argument against variables. He says:

My problem with this is that you are now relying on the synthesis tool to do “the right thing” rather than simply writing code that makes it do the right thing. I would only use variables in processes that are implementing some combinatorial logic. Then I’d register that output in a separate clocked process with its own reset.

And I have to agree on that. It’s better to be explicit in VHDL. If you want a register, it’s safest to use a signal.

' src=

I’m from Norway, but I live in Bangkok, Thailand. Before I started VHDLwhiz, I worked as an FPGA engineer in the defense industry. I earned my master’s degree in informatics at the University of Oslo.

Similar Posts

How to make an AXI FIFO in block RAM using the ready/valid handshake

How to make an AXI FIFO in block RAM using the ready/valid handshake

I was a little annoyed by the peculiarities of the AXI interface the first time I had to create logic to interface an AXI module. Instead of the regular busy/valid, full/valid, or empty/valid control signals, the AXI interface uses two control signals named “ready” and “valid”. My frustration soon changed to awe. The AXI interface…

How to create a linked list in VHDL

The linked list is a dynamic data structure. A linked list can be used when the total number of elements is not known in advance. It grows and shrinks in memory, relative to the number of items it contains. Linked lists are most conveniently implemented using classes in an object-oriented programming language. VHDL has some…

Make Lattice iCEcube2 work on Ubuntu 20.04 and program the iCEstick FPGA board

Make Lattice iCEcube2 work on Ubuntu 20.04 and program the iCEstick FPGA board

This tutorial shows how to install the Lattice iCEcube2 FPGA design software on Ubuntu 20.04. Instead of the Lattice Diamond Programmer, we will use the alternative programmer from Project IceStorm that works flawlessly on Ubuntu Linux. The Lattice iCEcube2 FPGA design software only works on Red Hat-based Linux distributions out of the box. Fortunately, we…

Why you always need a testbench

Why you always need a testbench

As most hardware engineers, I started off my computer science career by learning a sequential programming language. The first language I learned at the University of Oslo was Java. While it’s not considered to be the most exciting language today, at the time, Java was at the pinnacle of its popularity. The engineers who built…

Clk’event vs rising_edge

Clk’event vs rising_edge

When you have worked with VHDL code written by many other FPGA engineers, you are bound to notice that there are two common ways to model an edge detector in VHDL. There’s the rising_edge(clk) statement, and there’s the old-style clk’event and clk = ‘1’ method. The two if-statements do the same thing once the code…

One-process vs two-process vs three-process state machine

One-process vs two-process vs three-process state machine

Most of us stick to a certain way of writing a state machine. Perhaps you type out the construct that you are most familiar with without giving much thought to the alternatives. Depending on the method that you were taught when learning VHDL, you may prefer one method to another. Over the years, I have…

I acknowledge the positive effect of encapsulation provided by varuables, BUT:

My coding style tends to favour short VHDL files. I,.e. I tend to prefer breaking up my design into small blocks. I seldom have files larger than 300 lines in total.

When the files are small, the benefit of encapsulation is much less.

I agree with you on that. It’s much better to break up a large architecture into a structural module with multiple submodules. The total number of files and lines increases, but so does the readability.

>> If we swap lines 7 and 8 in the original DUAL_PORT_RAM process, it’s broken.

How is it broken? It looks like write-before-read, dual port memory.

Thank you for another interesting and thought-provoking article!

Hello Andrew, that’s a good question! Let’s see what happens if we swap lines 7 and 8 in the DUAL_PORT_RAM process using variables. The listing below is from the Vivado synthesis log. It has mapped the ram_v variable to 192 RAM64M primitives, aka distributed RAM, also known as LUTRAM in Xilinx FPGAs.

Write-before-read in block RAM is only possible on the same port. By that, I mean using the same address and clock. In dual-port RAM, you can have two identical ports with separate clocks, addresses, and a write enable input. Take a look at the example code below. I have implemented one such port that has a wr_en signal that controls if we are writing to the RAM.

The code example is write-first. In the listing below, we can see that Vivado correctly mapped it to a RAMB36 block RAM primitive. Also, take note that it says WRITE_FIRST in the PORT A column, while in the Preliminary Mapping Report in the blog post, it said READ_FIRST in the same column.

I’m going to create a blog post about block RAM to clear up some misunderstandings, and also to educate myself. It’s easy to get confused with all the different configuration options that block RAM have.

>> I’m going to create a blog post about block RAM to clear up some misunderstandings, and also >> to educate myself. It’s easy to get confused with all the different configuration options that >> block RAM have.

Looking forward to that blog post Jonas!

Yes, I probably should have created that article already. It’s just that I currently have 148 future blog posts on my list. ?

Thanks for reminding me.

Vivado has some surprises. I extended your code with byte selectable write enable, which works fine for READ_FIRST

but make it WRITE_FIRST

and Vivado cannot infer the BRAM (even though this type is configurable from the IP tools). It reports

[Synth 8-2914] Unsupported RAM template

Here you have another example of using variables: The two process method from Gaisler https://www.gaisler.com/doc/vhdl2proc.pdf

This method is inline with Ray says. What do you think about it?

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Notify me of replies to my comment via email

Dot Matrix VHDL and FPGA Course

This is the most extensive course VHDLwhiz has ever made.

VHDL Logical Operators and Signal Assignments for Combinational Logic

In this post, we discuss the VHDL logical operators, when-else statements , with-select statements and instantiation . These basic techniques allow us to model simple digital circuits.

In a previous post in this series, we looked at the way we use the VHDL entity, architecture and library keywords. These are important concepts which provide structure to our code and allow us to define the inputs and outputs of a component.

However, we can't do anything more than define inputs and outputs using this technique. In order to model digital circuits in VHDL, we need to take a closer look at the syntax of the language.

There are two main classes of digital circuit we can model in VHDL – combinational and sequential .

Combinational logic is the simplest of the two, consisting primarily of basic logic gates , such as ANDs, ORs and NOTs. When the circuit input changes, the output changes almost immediately (there is a small delay as signals propagate through the circuit).

Sequential circuits use a clock and require storage elements such as flip flops . As a result, changes in the output are synchronised to the circuit clock and are not immediate. We talk more specifically about modelling combinational logic in this post, whilst sequential logic is discussed in the next post.

Combinational Logic

The simplest elements to model in VHDL are the basic logic gates – AND, OR, NOR, NAND, NOT and XOR.

Each of these type of gates has a corresponding operator which implements their functionality. Collectively, these are known as logical operators in VHDL.

To demonstrate this concept, let us consider a simple two input AND gate such as that shown below.

The VHDL code shown below uses one of the logical operators to implement this basic circuit.

Although this code is simple, there are a couple of important concepts to consider. The first of these is the VHDL assignment operator (<=) which must be used for all signals. This is roughly equivalent to the = operator in most other programming languages.

In addition to signals, we can also define variables which we use inside of processes. In this case, we would have to use a different assignment operator (:=).

It is not important to understand variables in any detail to model combinational logic but we talk about them in the post on the VHDL process block .

The type of signal used is another important consideration. We talked about the most basic and common VHDL data types in a previous post.

As they represent some quantity or number, types such as real, time or integer are known as scalar types. We can't use the VHDL logical operators with these types and we most commonly use them with std_logic or std_logic_vectors.

Despite these considerations, this code example demonstrates how simple it is to model basic logic gates.

We can change the functionality of this circuit by replacing the AND operator with one of the other VHDL logical operators.

As an example, the VHDL code below models a three input XOR gate.

The NOT operator is slightly different to the other VHDL logical operators as it only has one input. The code snippet below shows the basic syntax for a NOT gate.

  • Mixing VHDL Logical Operators

Combinational logic circuits almost always feature more than one type of gate. As a result of this, VHDL allows us to mix logical operators in order to create models of more complex circuits.

To demonstrate this concept, let’s consider a circuit featuring an AND gate and an OR gate. The circuit diagram below shows this circuit.

The code below shows the implementation of this circuit using VHDL.

This code should be easy to understand as it makes use of the logical operators we have already talked about. However, it is important to use brackets when modelling circuits with multiple logic gates, as shown in the above example. Not only does this ensure that the design works as intended, it also makes the intention of the code easier to understand.

  • Reduction Functions

We can also use the logical operators on vector types in order to reduce them to a single bit. This is a useful feature as we can determine when all the bits in a vector are either 1 or 0.

We commonly do this for counters where we may want to know when the count reaches its maximum or minimum value.

The logical reduction functions were only introduced in VHDL-2008. Therefore, we can not use the logical operators to reduce vector types to a single bit when working with earlier standards.

The code snippet below shows the most common use cases for the VHDL reduction functions.

Mulitplexors in VHDL

In addition to logic gates, we often use multiplexors (mux for short) in combinational digital circuits. In VHDL, there are two different concurrent statements which we can use to model a mux.

The VHDL with select statement, also commonly referred to as selected signal assignment, is one of these constructs.

The other method we can use to concurrently model a mux is the VHDL when else statement.

In addition to this, we can also use a case statement to model a mux in VHDL . However, we talk about this in more detail in a later post as this method also requires us to have an understanding of the VHDL process block .

Let's look at the VHDL concurrent statements we can use to model a mux in more detail.

VHDL With Select Statement

When we use the with select statement in a VHDL design, we can assign different values to a signal based on the value of some other signal in our design.

The with select statement is probably the most intuitive way of modelling a mux in VHDL.

The code snippet below shows the basic syntax for the with select statement in VHDL.

When we use the VHDL with select statement, the <mux_out> field is assigned data based on the value of the <address> field.

When the <address> field is equal to <address1> then the <mux_out> signal is assigned to <a>, for example.

We use the the others clause at the end of the statement to capture instance when the address is a value other than those explicitly listed.

We can exclude the others clause if we explicitly list all of the possible input combinations.

  • With Select Mux Example

Let’s consider a simple four to one multiplexer to give a practical example of the with select statement. The output Q is set to one of the four inputs (A,B, C or D) depending on the value of the addr input signal.

The circuit diagram below shows this circuit.

This circuit is simple to implement using the VHDL with select statement, as shown in the code snippet below.

VHDL When Else Statements

We use the when statement in VHDL to assign different values to a signal based on boolean expressions .

In this case, we actually write a different expression for each of the values which could be assigned to a signal. When one of these conditions evaluates as true, the signal is assigned the value associated with this condition.

The code snippet below shows the basic syntax for the VHDL when else statement.

When we use the when else statement in VHDL, the boolean expression is written after the when keyword. If this condition evaluates as true, then the <mux_out> field is assigned to the value stated before the relevant when keyword.

For example, if the <address> field in the above example is equal to <address1> then the value of <a> is assigned to <mux_out>.

When this condition evaluates as false, the next condition in the sequence is evaluated.

We use the else keyword to separate the different conditions and assignments in our code.

The final else statement captures the instances when the address is a value other than those explicitly listed. We only use this if we haven't explicitly listed all possible combinations of the <address> field.

  • When Else Mux Example

Let’s consider the simple four to one multiplexer again in order to give a practical example of the when else statement in VHDL. The output Q is set to one of the four inputs (A,B, C or D) based on the value of the addr signal. This is exactly the same as the previous example we used for the with select statement.

The VHDL code shown below implements this circuit using the when else statement.

  • Comparison of Mux Modelling Techniques in VHDL

When we write VHDL code, the with select and when else statements perform the same function. In addition, we will get the same synthesis results from both statements in almost all cases.

In a purely technical sense, there is no major advantage to using one over the other. The choice of which one to use is often a purely stylistic choice.

When we use the with select statement, we can only use a single signal to determine which data will get assigned.

This is in contrast to the when else statements which can also include logical descriptors.

This means we can often write more succinct VHDL code by using the when else statement. This is especially true when we need to use a logic circuit to drive the address bits.

Let's consider the circuit shown below as an example.

To model this using a using a with select statement in VHDL, we would need to write code which specifically models the AND gate.

We must then include the output of this code in the with select statement which models the multiplexer.

The code snippet below shows this implementation.

Although this code would function as needed, using a when else statement would give us more succinct code. Whilst this will have no impact on the way the device works, it is good practice to write clear code. This help to make the design more maintainable for anyone who has to modify it in the future.

The VHDL code snippet below shows the same circuit implemented with a when else statement.

Instantiating Components in VHDL

Up until this point, we have shown how we can use the VHDL language to describe the behavior of circuits.

However, we can also connect a number of previously defined VHDL entity architecture pairs in order to build a more complex circuit.

This is similar to connecting electronic components in a physical circuit.

There are two methods we can use for this in VHDL – component instantiation and direct entity instantiation .

  • VHDL Component Instantiation

When using component instantiation in VHDL, we must define a component before it is used.

We can either do this before the main code, in the same way we would declare a signal, or in a separate package.

VHDL packages are similar to headers or libraries in other programming languages and we discuss these in a later post.

When writing VHDL, we declare a component using the syntax shown below. The component name and the ports must match the names in the original entity.

After declaring our component, we can instantiate it within an architecture using the syntax shown below. The <instance_name> must be unique for every instantiation within an architecture.

In VHDL, we use a port map to connect the ports of our component to signals in our architecture.

The signals which we use in our VHDL port map, such as <signal_name1> in the example above, must be declared before they can be used.

As VHDL is a strongly typed language, the signals we use in the port map must also match the type of the port they connect to.

When we write VHDL code, we may also wish to leave some ports unconnected.

For example, we may have a component which models the behaviour of a JK flip flop . However, we only need to use the inverted output in our design meaning. Therefore, we do not want to connect the non-inverted output to a signal in our architecture.

We can use the open keyword to indicate that we don't make a connection to one of the ports.

However, we can only use the open VHDL keyword for outputs.

If we attempt to leave inputs to our components open, our VHDL compiler will raise an error.

  • VHDL Direct Entity Instantiation

The second instantiation technique is known as direct entity instantiation.

Using this method we can directly connect the entity in a new design without declaring a component first.

The code snippet below shows how we use direct entity instantiation in VHDL.

As with the component instantiation technique, <instance_name> must be unique for each instantiation in an architecture.

There are two extra requirements for this type of instantiation. We must explicitly state the name of both the library and the architecture which we want to use. This is shown in the example above by the <library_name> and <architecture_name> labels.

Once the component is instantiated within a VHDL architecture, we use a port map to connect signals to the ports. We use the VHDL port map in the same way for both direct entity and component instantiation.

Which types can not be used with the VHDL logical operators?

Scalar types such as integer and real.

Write the code for a 4 input NAND gate

We can use two different types of statement to model multiplexors in VHDL, what are they?

The with select statement and the when else statement

Write the code for an 8 input multiplexor using both types of statement

Write the code to instantiate a two input AND component using both direct entity and component instantiation. Assume that the AND gate is compiled in the work library and the architecture is named rtl.

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Save my name, email, and website in this browser for the next time I comment.

Table of Contents

Sign up free for exclusive content.

Don't Miss Out

We are about to launch exclusive video content. Sign up to hear about it first.

IMAGES

  1. VHDL Introduction

    variable assignment in vhdl

  2. VHDL types

    variable assignment in vhdl

  3. PPT

    variable assignment in vhdl

  4. VHDL Processes

    variable assignment in vhdl

  5. PPT

    variable assignment in vhdl

  6. PPT

    variable assignment in vhdl

VIDEO

  1. How a Signal is different from a Variable in VHDL

  2. VHDL Tutorial: And Gate using Process Statement

  3. #vhdl#

  4. How Sequential statement works in VHDL? What is VHDL process?

  5. VHDL Basics : How Sequential and Concurrent Statements works in VHDL

  6. VHDL Basics

COMMENTS

  1. Variable

    Variables - VHDL Example. Variables in VHDL act similarly to variables in C. Their value is valid at the exact location in the code where the variable is modified. Therefore, if a signal uses the value of the variable before the assignment, it will have the old variable value. If a signal uses the value of the variable after the assignment it ...

  2. Variables

    Value assignments to variables, however, are carried out immediately. To distinguish between a signal and a variable assignment different symbols are used: '⇐' indicates a signal assignment and ':=' indicates a variable assignment. ... In VHDL 93, global variables are allowed. These variables are not only visible within a process but ...

  3. VHDL Reference Guide

    Variable assignments are generally synthesisable, providing they use types and operators acceptable to the synthesis tool. In a "clocked process", each variable which has its value read before it has had an assignment to it will be synthesised as the output of a register. ... In VHDL-93, a variable assignment may have a label: label: variable ...

  4. what exactly is a variable in VHDL?

    For your specific code, yes, the variable var will cause a flip flop to be synthesized. It would also do the exact same thing if 'var' was a signal and the output <= var; assignment was outside of the process. In your code, var is set based on the sole assignment to refer to the Dout wire of a clocked element (flip flop) that has a Din of input ...

  5. The Variable: A Valuable Object in Sequential VHDL

    However, variables are local to a process. They are used to store the intermediate values and cannot be accessed outside of the process. Moreover, as shown by line 4 of the above code, the assignment to a variable uses the ":=" notation, whereas, the signal assignment uses "<=". Multiple Assignments to a Variable. Consider the following ...

  6. PDF VHDL Syntax Reference

    3.1 Variables Variables are objects used to store intermediate values between sequential VHDL statements. Variables are only allowed in processes, procedures and functions, and they are always local to those functions. When a value is assigned to a variable, ":=" is used. Example: signal Grant, Select: std_logic; process(Rst, Clk)

  7. VHDL Reference Guide

    In a "clocked process", each variable which has its value read before it has had an assignment to it will be synthesised as the output of a register. In a "combinational process", reading a variable before it has had an assignment may cause a latch to be synthesised. Variables declared in a subprogram are synthesised as combinational logic.

  8. VHDL Tutorial

    A variable behaves like you would expect in a software programming language, which is much different than the behavior of a signal. Although variables represent data like the signal, they do not have or cause events and are modified differently. Variables are modified with the variable assignment. For example, a:=b; assigns the value of b to a.

  9. VHDL Online Help

    The variable assignment statement modifies the value of the variable. The new value of the variable is obtained by assigning an expression to this variable. In order to distinguish variable assignment from signal assignment, the variable assignment symbol is different (:=). The expression assigned to a variable must give results of the same ...

  10. vhdl Tutorial => Signals vs. variables, a brief overview of the

    VHDL also uses variables and they have exactly the same role as in most imperative languages. But VHDL also offers another kind of value container: the signal. Signals also store values, can also be assigned and read. The type of values that can be stored in signals is (almost) the same as in variables.

  11. Variable Assignment

    Description: The expression assigned to a variable must give results of the same type as the variable. The target at the left-hand side of the assignment can be either a name of a variable or an aggregate. A variable name can be in the form of simple name, selected name, indexed name or slice name. If the target is an aggregate, then the type ...

  12. VHDL

    Description. The variable assignment statement modifies the value of the variable. The new value of the variable is obtained by assigning an expression to this variable. In order to distinguish variable assignment from signal assignment, the variable assignment symbol is different (:=). The expression assigned to a variable must give results of ...

  13. Using variables for registers or memory in VHDL

    That's one of the main objections many VHDL designers have against variables used for registers. Some engineers are accustomed to reading the code within an enclosure, like an if-statement, as parallel events. By using both variables and signals interchangeably, it becomes harder to follow the program flow.

  14. An Introduction to VHDL Data Types

    When we assign data to a variable we use the := symbol. We discuss variables in more depth in the post on VHDL process blocks. ... The code snippet below gives some examples of how we assign data to vector types in VHDL.-- Assigning a value of 11b to a std_logic_vector example <= "11"; -- Assigning a hex value to a std_logic_vector example <= x ...

  15. VHDL Logical Operators and Signal Assignments for Combinational Logic

    The VHDL code shown below uses one of the logical operators to implement this basic circuit. and_out <= a and b; Although this code is simple, there are a couple of important concepts to consider. The first of these is the VHDL assignment operator (<=) which must be used for all signals.

  16. Difference between Blocking and Non-Blocking assignment in VHDL

    However, variable assignments are always local to a process, and hence, we don't need to worry about that set of race conditions. In addition, variables never have a delay. Signals update either after a simulation cycle or a specified delay. So perhaps this is a little like Verilog's non-blocking assignment. The delay in VHDL only applies to ...

  17. Multiple assignments in CASE statement in VHDL

    For assign to multiple signals in one statement, the VHDL-2008 supports aggregate assignment, so if you are using VHDL-2008, you can write: WHEN "10" => (output3, output2, output1, output0) <= std_logic_vector'("0100"); For VHDL-2003, a solution may be to create an intermediate output signal as std_logic_vector, and then assign to this. Code ...

  18. Variables in VHDL

    1. When you declare a variable inside a process in VHDL, if you also initialise it to a certain value, i.e. a 0 or a 1, does this variable's value from previous iterations get 're-initialised' to the value you have given it? For example every time this process is enabled by the change in the 10MHz clock, does the variable shift be initialised ...

  19. vhdl

    What I want to do doesn't seem particularly complex, but I can't think of a simple way to do it in VHDL. I have a component with a generic parameter called FOO.I would like to generate 16 of these components and for the first 8 instances I want FOO to be set to 0 and the other 8 instances I want FOO to be set to 4096.. Ideally, I would be able to do something like this: