United Business Media EE Times


Search

HOMEMARKET INTELLIGENCE UNITFORUMSDESIGNNEW PRODUCTSCAREERSBLOGSCONTACTEVENTSSIGN UP!RSSMost Popular contentTrusted Sources

 

Design Automation

Transitioning from ABEL-HDL to VHDL

For users of programmable logic, the increasing capacities of devices require a change to a new hardware description language.

by Dennis McCrohan, Mike Holley, and Ryan Linderman


This article provides the designer who is already familiar with ABEL-HDL with an introduction to the VHDL language and how it is used for the design of programmable logic. In this article, we will use a series of three design examples that compare the features of the ABEL language with VHDL. We cannot promise to turn you into a VHDL expert in a few pages, but we do hope that by the end of this article you will find VHDL considerably less complex than you might have thought.

Example 1--differences We begin our exploration of the differences between ABEL-HDL and VHDL with a simple design, shown schematically in Figure 1 and as an ABEL listing in Listing 1A. It is important to remember that a logic schematic is just another HDL--one that has become standardized in an ad hoc way during the past 35 years. While simple, this design encompasses the three major categories of digital-logic behavior: combinatorial, latched, and registered logic. Listing 1B shows the VHDL implementation of this design.


Figure 1. The schematic diagram illustrates the various parts of the design being discussed.

The VHDL model consists of two principle pieces: an entity declaration and an architecture. LIBRARY and USE statements precede these pieces in the source file. These statements guide a VHDL compiler as to where to look for objects not declared in this source file. In this case, we reference a standard package called std_logic_1164 . The Institute of Electrical and Electronics Engineers developed this package, which defines a nine-level logic system and the operators for it. The logic system is perhaps the first surprise VHDL novices encounter--the data types that hardware designers use were not defined as part of the language. The 1164 package (as it is commonly known) defines two types of data with a range of logic values: std_ulogic and std_logic . std_ulogic can only be used when a signal will have just one driver, whereas std_logic can be used in situations that demand multiple drivers on a net, such as three-state buses or wired logic.

The key word ENTITY begins the entity declaration, followed by the name of the entity and then the list of ports. Ports are analogous to pins on a schematic symbol: they are how information enters or leaves an entity. Ports may be either scalar (1-bit wide) or a vector (multiple-bits wide). In this example, we have declared four 1-bit inputs, a , b , clk , and oe , and an output bus called dout , which is declared using the std_logic_vector type, defined in std_logic_1164 . A std_logic vector is simply an array of std_logic bits, and a std_ulogic vector is an array of std_ulogic .

An architecture for ex1, the design for a gate and latch, follows the entity declaration. VHDL allows an entity to have as many implementations as desired, with each implementation containing a different architecture. In this example, we have what is called a behavioral architecture. That is, the code is written at a level of abstraction that specifies the desired behavior of ex1 without specifying how that behavior is to be achieved. It is possible to create more abstract implementations, but the level of abstraction discussed here is one understood by most synthesis tools currently on the market.

This particular architecture starts with the declaration of an internal signal called a_and_b . Note that the language allows us to assign an initial value to a_and_b , and in this case, we are assigning a value of 0. Initial-value assignments are not normally used in synthesizable VHDL because they are ignored by synthesis tools. Without an initial-value assignment, signals declared to be of type std_logic or std_ulogic take on the value U (for uninitialized) at the beginning of simulation.

The key word BEGIN marks the end of the architecture's declaration section and is followed by the body of the architecture. The body describes the design's behavior. Here, you can see two of the most commonly used constructs in VHDL: the concurrent-signal assignment and the process. The first two lines are concurrent-signal assignments that assign values to the least significant bit (LSB) of dout and to our internal signal, a_and_b . We said that these statements are called concurrent-signal assignments, which implies they execute in parallel, not sequentially, as they would in C or Pascal. The simulator evaluates each assignment, and a new value is assigned to the driven signal when any signal on the right-hand side of the assignment operator <= changes.

Two processes follow the concurrent-signal assignment statements. We have given these processes optional labels of p_reg and p_lat , respectively, for reasons that will become obvious. Following the key-word process is the sensitivity list for the process. There are two key concepts to understand here: (1) the code in these processes is executed only when one or more of the signals in the sensitivity list changes; and (2) the code within a process executes sequentially--within a process, code does execute "down the page."

VHDL supports several decision-making constructs within the sequential logic of a process. Here, we use the "if-then" construct to conditionally execute signal assignments. In p_reg , we assign the middle bit of dout to a_and_b whenever there is a rising edge on clk . We detect the rising edge by using another unique VHDL feature called a signal attribute. The signal attribute 'event , applied to clk , will evaluate as true only if clk is in the process of changing value. The behavior exhibited by p_reg is that of a D flip-flop, and in fact, this style of process is the one synthesis tools most commonly use to infer a register. The process p_lat , on the other hand, assigns a new value to the most significant bit (MSB) of dout anytime clk is 1. Note that to get the correct latch behavior, we must include a_and_b in the sensitivity list of this process because the output of a latch should follow the input when the latch enable is active.

Like any modern language, VHDL allows you to insert comments in the source code, with the beginning of a comment indicated by the string "--" and the end, by an end-of-line.

At this point, back up and take a look at the entire architecture for ex1 . There are four code blocks--two concurrent-signal assignments and two processes--all executing in parallel (concurrently) and taking some number of inputs as well as driving a value onto an output. The obvious analogy is to a board full of TTL small- and medium-scale integration components, with each concurrent-signal assignment or process corresponding to a different component. While processes may drive more than one signal (as we will see), no two processes or concurrent-signal assignments may attempt to drive the same signal, unless, as with TTL, they are implementing three-state or wired logic.

Example 2--address decoder The module statement gives the ABEL-HDL module the name ex2 . Inputs are declared for the clk pin, address-input pins, csn pin, and the select-output pins (see Listing 2A and Listing 2B).

A set called addr is created using range notation and includes all the address-input pins. It becomes easier in the equations section to deal with the single name rather than dealing with a grouping of input pins.

Because each output is considered registered, the equations used must feed the D input to each register. In ABEL-HDL, a register will implicitly go to zero, assuming no other asynchronous controls are used on the register on the next clock unless its D equation is satisfied. Thus, latches are not created by default. Further, no order is implied in evaluating these equations, and therefore no priority-decode is created by this equation set. The decode equations are written in a high-level ABEL-HDL equation syntax, making manipulation of large data widths straightforward and easy to modify.

Now consider the VHDL implementation. For the entity ex2 , we define the clk and csn inputs as being of type std_logic , but we will make the address an integer, with an optional range constraint. It is convenient in this case to specify the range of address using the hexadecimal notation 16#FFFF#, rather than the corresponding decimal value 65535. It we had not given a range constraint for address, a synthesis tool would have to assume an integer value no less than 2147483647. In other words, that address was 31 bits wide. This makes it important to use range constraints on all integer values when writing synthesizable VHDL.

In the architecture for ex2 , we implement the entire address-decode function in one process. Because we have specified that the address is to be decoded synchronously, we must ensure that the code in process is executed only when clk rises. To detect clk 's rising edge, we use the function rising_edge , which is defined in std_logic_1164 , in conjunction with a WAIT statement. A WAIT statement can be used to halt the execution of a process and wait for a specified period of time, until a change occurs on one or more signals, or, as in this case, until a specified Boolean condition is true. WAIT statements are typically used as an alternative to a process-sensitivity list, and in fact, VHDL does not allow you to use a WAIT and a sensitivity list in the same process.

In the declaration section of this process (the area between the key word PROCESS and the key word BEGIN), we declare a variable called t_selects . The declaration of a variable looks much like the declaration of a signal, but there are several important differences, as shown by the following four items:

  1. Variables are local to, and declared within, processes.

  2. The assignment operator for variables is := rather than <=.

  3. Variables don't have any associated attributes, such as 'event .

  4. Assignments to variables are made immediately, rather than with some explicit or implicit delay.

The implications of items 1 and 2 are fairly obvious. The implication of item 3 is that during simulation, variables do not carry as much overhead baggage as signals. This reduces the amount of memory required by the simulator and may even make the simulation run faster. We will defer discussion of item 4 for a moment.

In the body of the process, we implement the one-hot decode of address using a series of "if-then" statements, each checking address against the appropriate range. Because all the outputs must be low when csn is not active, we added the assignment:

t_selects := (others => '0');

to the process right after detecting clk 's rising edge. This translates in plain English to the statement "assign all bits of t_selects to the value 0," and is more convenient than typing:

t_selects := "000000000"

Including this assignment in the design of the VHDL code is extremely important; if we had not, the synthesis tool would have been forced to infer that feedback from the Q output of each flip-flop, through an OR gate, back into the D input. Consequently, each select output would stay at 1 once the proper address was decoded, and it would never return to 0. Alternately, we could have fully specified all the bits of t_selects for each condition (see Listing 3).

Back to Item 4, at the end of the process, we assign the variable t_selects to the following output port:

selects <= t_selects after 10 ns;

This statement introduces another VHDL feature: the ability to specify that a signal assignment takes place with some specified delay, in this case 10 ns. Because this process is executed only on clk 's rising edge, during simulation it will appear that the selects output has 10 ns of propagation delay, with respect to clk . If no explicit delay is given, signal assignments are assumed to occur with one-delta delay. From the user's perspective, a delta is one execution pass of a process. In this example, the process p_reg is executed once each time clk changes value. Variable assignments, on the other hand, happen immediately. An implication of this is that if we had declared t_selects to be a signal, we would introduce an extra clock-cycle delay on the selects output. A simple rule to remember is that in a clocked process such as this, each signal assignment introduces pipeline registers in the synthesized logic.

Example 3--state machine Our third example is a simple state machine. The ABEL-HDL code for this design is shown in Listing 4A. In Listing 4B, we see the VHDL code.

The ABEL-HDL description declares inputs, outputs, and two sets: streg (state registers) and stin (state-input variables). The state_diagram key word establishes the existence of a state machine to the ABEL-HDL compiler and sets it up to interpret the next section in terms of ABEL-HDL state-machine language syntax.

The VHDL entity declaration contains four port declarations--three inputs and one output. Note that the two vector ports are declared with a range that runs from LSB to MSB and that we use the key word to instead of downto .

In this architecture, we introduce another new VHDL concept: the enumerated type. A type declaration begins with the key word TYPE, which is followed by the type name and a list containing the possible values for the type. Using enumerated types is common in VHDL (remember that the type std_logic that we have been using throughout this article is an enumerated type, declared in the package std_logic_1164 ). You can also define subtypes, for example:

subtype small_integer is integer range -128 to 127;

A subtype is defined in terms of another predefined type. An advantage of using a subtype is that it inherits the operators defined for the parent type.

For this example, we are using the enumerated type states simply to represent the state of a finite-state machine (FSM). There are two common ways to represent an FSM in VHDL: the single-process form or the two-process form. This example uses the two-process form, mainly because it is simpler for novices to understand. The single-process form is more efficient from a simulation standpoint and probably more commonly used.

In the two-process form, one process is used to infer the behavior of the state registers and, the second, to implement the combinatorial logic. For this example, the process p_reg will infer the registers that will hold the present state of the state machine. To make the example more complex, we have defined the design to have an asynchronous reset that will reset the state machine to its initial state. This is accomplished by making p_reg sensitive to reset (in addition to clk ) and by detecting a 1 on reset before checking for a rising edge on clk . This way, present_state will remain at st0 as long as reset is 1, regardless of clk .

The process p_trans defines the combinatorial logic for the state machine and generates the signal next_state , which is registered by p_reg . This process must be sensitive to the present state and combinatorial inputs to the state machine. Two common mistakes are made when writing this type of process--

  1. Forgetting to make the process sensitive to all the signals to which it needs to be sensitive. A basic rule is that the process must be sensitive to all signals that appear on the right-hand side of a signal assignment or to those that appear in a conditional expression (if, case, elsif, etc.).

  2. Assigning a value to a signal under certain conditions (in this example, in certain states) but not others. Suppose that in this example that we omitted the assignment to state_outputs while in st2 . This would imply that in state st2 , our state machine would "remember" the value that state_outputs had been set to in the previous state and in hardware, "remembering" requires a memory element, either a flip-flop or a latch. Because this process never detects an edge on any input, a level-sensitive latch would be inferred.

This process also introduces a new VHDL control construct: the case statement, which can be used similarly to "if-then" for decision making. VHDL requires that a case statement handle all possible cases. For example, if we omitted the block of code for case st3 in this example, we should get an error from our compiler. You can place one or more cases to be handled the same way under an "others" clause: for example,

when others =>

state_outputs <= "11";
if state_inputs = "11" then
next_state <= st3;
else
next_state <= st0;
end if;

Because the choices for a case statement are mutually exclusive and exhaustive, this code should synthesize into less logic than code using an "if-elsif" construct.

In this architecture for our FSM, the output state_outputs is combinatorial. If we change the specification for the FSM to make state_outputs a registered output, we can rewrite the architecture using the single-process form. This is shown in Listing 4C. Because the process p_single is executed only when clk or reset change, this architecture should be more simulation-efficient than the two-process architecture, where process p_trans is executed each time the inputs or the current state change.

After completing our design, we must verify functionality with a simulator. Historically, simulators have had various methods of providing stimuli to the design being simulated. Designs performed using ABEL typically have test vectors written in ABEL Test Vector language. Some VHDL simulators may still provide a proprietary method of generating stimuli, such as test vector files or waveform-entry tools, but the primary (and portable) method of generating stimuli for a design in a VHDL environment is with a testbench. A VHDL testbench is simply another VHDL entity, with two distinguishing characteristics: (1) the entity declaration contains no ports; and (2) the architecture body instantiates the user's design.

Testbenches provide an excellent opportunity for VHDL designers to create elaborate testbenches tailored to the needs of the design in question. Testbenches can not only provide stimuli, but can also check for expected outputs, reducing the need for manual verification. At one extreme, a testbench may consist of just one process reading data from an input file and applying them to the inputs of the design being simulated. A situation in which this style of testbench might be used is a microprocessor design, where a cross-assembler could be used to generate a data file that the testbench reads. The testbench, in turn, behaves as a ROM, responding to instruction fetches by placing the data read from the file onto the processor's data bus.

Conclusion We probably have not turned you into a VHDL expert, but we hope you have gained enough insight to ask the right questions and begin your own experiments with VHDL. While VHDL is a large, complex language, the extent of the language that designers writing synthesizable logic use is usually quite small. You can start with the small subset shown in this article and branch out as you become familiar with the language. You have also seen that it is not necessary to abandon your existing design methodologies. If you are using ABEL, look at using a tool that supports ABEL and VHDL as design-entry methods. If you prefer schematics, then you should probably consider tools that support a mix of schematic and VHDL entry.

Dennis McCrohan is a product marketing engineer, Mike Holley is a senior engineer, and Ryan Linderman is an applications engineer at Data I/O's Synario Design Automation (Redmond, WA).

To voice an opinion on this or any Integrated System Design article, please e-mail your message to michael@isdmag.com.


integrated system design  January 1997



[ Articles from Integrated System Design Magazine ] [ ICs and uPs ]
[ Custom ICs and Programmable Logic ] [ Vendor Guide ]
[ Design and Development Tools ] [ Home ]



For more information about isdmag.com e-mail cam@isdmag.com
For advertising information e-mail amstjohn@mfi.com
Comments on our editorial are welcome
Copyright © 1997 Integrated System Design Magazine

  Free Subscription to EE Times
First Name Last Name
Company Name Title
Email address
  Click here for your Free Subscription to EETimes Europe
 
CAREER CENTER
Looking for a new job?
SEARCH JOBS
SPONSOR

RECENT JOB POSTINGS
CAREER NEWS
SRC Expands R&D Centers
The Semiconductor Research Corp has added a new center to its university R&D efforts.

For more great jobs, career related news, features and services, please visit EETimes' Career Center.


All White Papers »   

 
Education and
Learning


Learn Now:












Home | About | Editorial Calendar | Feedback | Subscriptions | Newsletter | Media Kit | Contact | Reprints|  RSS|   Digital|  Mobile
Network Websites
International
Network Features




All materials on this site Copyright © 2009 TechInsights, a Division of United Business Media LLC All rights reserved.
Privacy Statement | Terms of Service | About