United Business Media EE Times


Search

HOMEMARKET INTELLIGENCE UNITFORUMSDESIGNNEW PRODUCTSCAREERSBLOGSCONTACTEVENTSSIGN UP!RSSMost Popular contentTrusted Sources

 



Design Automation

An Introduction to Parameterized Design With VHDL

Parameterized designs are reusable by virtue of their built-in flexibility. With growing attention to design reuse, they are becoming more important.

by Matt Henry


Design reuse is receiving growing attention in an era of shrinking development cycles as perhaps the most effective tool for productivity improvement. Some designs are reusable because of standardization or even pure simplicity. A parameterized design is one which is reusable by virtue of its built-in flexibility to be adapted to different requirements. A combination of language features and development methodology makes HDLs ideal hosts for parameterized design. Hardware description languages (HDLs) have established themselves as the de facto vehicle for digital design expression and verification.

The following discussion explores some possible approaches to parameterized design with VHDL, with a particular focus on synthesizable building blocks. Many of the techniques apply to Verilog as well. We will concentrate on examples of VHDL code that illustrate the application of relevant language features and design approaches. The reader should have some familiarity with VHDL to fully appreciate the discussion.

Paradigm shift Let's illustrate the power of these language features and some coding style issues with the example of a right logical shifter. A very regular technique for building such an element is to instantiate a two-dimensional array of 2:1 multiplexers with depth Q and width N, where N = 2Q and the maximum shift is N-1. Each jth row of N multiplexers passes the output of the previous row unmodified or shifts it right by 2j. Therefore, the shifter has a Q-bit shift count bus. If a 2j shift demands that bit i of row j receive a bit from the previous stage whose index is greater than N-1, then that bit instead receives a specified value called Fill.

Our first modeling decision is the choice of parameters. Since N derives more easily from Q than vice-versa, we select Q as the fundamental parameter. We could specify a shifter width that is independent of Q, but in this case we can achieve the same effect by tying off/disconnecting unused inputs/outputs if the required Q derives an N that is larger than needed. The entity declaration for our parameterized shifter is depicted in Listing 1a. Q is realized as a generic (see "Generics and generates" for a discussion of this term) in this entity declaration.

There are a few ways to model our shifter, even given the somewhat regimented structure that has been specified. If we have a particular structure in mind, it is best to begin with a diagram such as the one shown in Figure 1.



Figure 1. The manageable value of Q (here, 3) is used to deduce the necessary structure of the implied hardware and interconnect.


Here we assume a manageable value of Q (in this case 3) to deduce the necessary structure of implied hardware and interconnect. The hardware is simple enough in this case: a Q=3 by N=8 array of 2:1 multiplexers labeled with the indices shown.

The interconnect is just a bit trickier. Each row must connect somehow to the previous row; row 0 must connect to the Operand bus, and row 2 must connect to the Result bus. This requires Q+1 rows of interconnect. If a row does not shift (Shift(j) = '0'), its multiplexer inputs 0 connect directly to the previous row's multiplexer outputs. If a row does shift (Shift(j) = '1'), its ith multiplexer input 1 connects to the i+2j multiplexer output from the previous row, or to the Fill bit if i+2j > N-1. We can treat our Operand bus as though it were the output of phantom multiplexer row -1 and our Result bus as though it were input 0 of a phantom multiplexer row 3. Fortunately, that all sounds more difficult than it is.

Listing 1b is a concurrent architecture that implements this. We first define a two-dimensional array of size N by Q+1 for our interconnect. Signal Between is really the only interconnect we need, but we declare signal In1 so that we have the flexibility to specify an irregular connection of Between to inputs 1 of our multiplexers. Mux2to1 is our multiplexer cell. It could be from an ASIC library, or it could have its own simple entity/architecture. The nested Depth and Width generates instantiate the mux array. The Shift-Con generate connects In1 to shifted Between if the index of i is small enough, whereas the FillCon generate connects In1 to the Fill input otherwise.

In some ways this is a brute-force modeling technique. It makes use of many signals, which are less efficient than variables from a simulation standpoint. Furthermore, we cannot assign signals to default values and selectively override them later; our connection specifications must be specific, complete, and non-overlapping. It is far too easy to produce code which multiply drives some signals and leaves others undriven, particularly when the parametric equations are complex. Sometimes irregular structures cannot be implied with generates, for we have access to a limited set of conditional constructs. However, if we wish to very explicitly imply a certain cell in our design, this is a powerful technique.

Listing 1c illustrates an equivalent sequential architecture for the right logical shifter. It is very similar in structure to the concurrent implementation, as it uses the sequential analogs to the concurrent generate statements. The sequential approach affords us the use of a variable for "between," and an "in1" variable is not necessary because we no longer instantiate a mux component. We make a default assignment of between (j) to between (j+1) for the non-shifting case and selectively override it for the shifting case. Although this code does not explicitly instantiate the array of multiplexers, it still directly implies that very same structure.

Listing 1d is a more direct translation of the right logical shifter functional requirements into VHDL code. Again, we loop across the range of the operand. At each index the model compares the specified shift count to the present distance from the most significant bit: if the shift count is greater than this distance, the shifter delivers the Fill bit for that index; if the shift count is less than or equal to the distance, the shifter delivers the operand bit whose index is greater by the shift count. This model does use an integer-to-std_logic_vector conversion function but is very concise and efficient. The weakness of this version is that it does not imply a natural or efficient hardware structure on which to base the logical shift. Whereas the first two versions use arithmetic to define the framework in which hardware is implied, this version actually implies arithmetic hardware to build the function. The difference is subtle but critical to high-quality synthesis results.


Listing 1a-d
Logical right shifter model
(a)

LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
ENTITY log_shifter_right IS
GENERIC ( 
Q : POSITIVE := 5
);
PORT (
Operand : IN std_logic_vector (2**Q-1 DOWNTO 0);
Shift : IN std_logic_vector (Q-1 DOWNTO 0);
Fill : IN std_logic;
Result : OUT std_logic_vector
(2**Q-1 DOWNTO 0)
);
END log_shifter_right;

(b) ARCHITECTURE concurrent OF log_shifter_right IS SUBTYPE shift_word IS std_logic_vector (2**Q-1 DOWNTO 0); TYPE shift_array IS ARRAY (Q DOWNTO 0) OF shift_word; SIGNAL In1, Between : shift_array; COMPONENT mux2to1 PORT (In0, In1, Sel : IN std_logic; Out0 : OUT std_logic); END COMPONENT; BEGIN Between (0) <= Operand; Result <= Between (Q); Depth : FOR j IN 0 TO Q-1 GENERATE Width : FOR i IN 0 TO (2**Q)-1 GENERATE Selector : mux2to1 PORT MAP (In0 => Between (j) (i), In1 => In1 (j) (i), Sel => Shift (j), Out0 => Between (j+1) (i)); ShftCon : IF (i <= (2**Q)-1-(2**j)) GENERATE In1 (j) (i) <= Between (j) (i+(2**j)); END GENERATE ShftCon; FillCon : IF (i > (2**Q)-1-(2**j)) GENERATE In1 (j) (i) <= Fill; END GENERATE FillCon; END GENERATE Width; END GENERATE Depth; END concurrent;

(c) ARCHITECTURE sequential OF log_shifter_right IS BEGIN Combinational : PROCESS (Operand, Shift, Fill) SUBTYPE shift_word IS std_logic_vector (2**Q-1 DOWNTO 0); TYPE shift_array IS ARRAY (Q DOWNTO 0) OF shift_word; VARIABLE between : shift_array; BEGIN between (0) := Operand; Depth : FOR j IN 0 TO Q-1 LOOP between (j+1) := between (j); Width : FOR i IN 0 TO (2**Q)-1 LOOP IF (Shift (j) = '1') THEN IF (i <= (2**Q)-1-(2**j)) THEN between (j+1) (i) := between (j) (i+(2**j)); ELSE between (j+1) (i) := Fill; END IF; END IF; END LOOP Width; END LOOP Depth; Result <= between (Q); END PROCESS Combinational; END sequential;

(d) USE work.conversions.ALL; ARCHITECTURE behavior OF log_shifter_right IS BEGIN Combinational : PROCESS (Operand, Shift, Fill) BEGIN Width : FOR i IN Operand'RANGE LOOP IF (((2**Q)-1-i) < to_integer (Shift)) THEN Result (i) <= Fill; ELSE Result (i) <= Operand (i + to_integer (Shift)); END IF; END LOOP Width; END PROCESS Combinational; END behavior;




Components exposed The notion of declaring a component in VHDL seems quite mundane and even redundant. After all, isn't it obvious what the component represents when I instantiate it? According to the way components are commonly used it is obvious. But those clever framers of the language had ulterior motives as well. When one instantiates a component, one need not map all ports or all generics under the following conditions:

  • The port is of mode OUT or BUFFER: Unmapped output ports in VHDL assume the OPEN state. In other words, they are unconnected and have no effect on the surrounding circuit. Synthesis tools excel at removing logic that drives an unconnected port.

  • The port is of mode IN and the port has been declared with a default state assignment. In such a case, the unmapped input simply assumes the default state (usually logic '1' or '0') as though it were tied off.

  • The generic has been assigned a default value. A generic map in a component instantiation is only necessary to override the default state of the generic.



Generics and generates
Generics: Generics, static properties which adjust the interface and/or behavior of a VHDL entity and its associated architecture(s), are the very foundation of parameterized design in VHDL. Generics commonly pass timing characteristics (type TIME) or size constraints (type INTEGER) into a model, although the language allows generics of any type.

Note the static condition in our definition; a generic must resolve to a constant value during elaboration of the VHDL model. Therefore, the model cannot dynamically adjust the value of a generic during simulation.

The generic declaration is an optional part of an entity declaration that appears before any port declarations. Usually a generic receives a default value as part of its declaration. When instantiating a component that is bound to an entity with one or more generics, one can optionally override the default values of each. Generics may also pass information through multiple levels of design hierarchy.

For the purposes of parameterizing a synthesizable VHDL model we can view generics as properties which specify size, value, or composition:

Size: The most straightforward way in which to parameterize a model is to include one or more integer generics that specify length, width, or depth of the hardware structure being modeled. Such models typically repeat the implied structure in one or more dimensions and can be thought of as "telescoping models." Because generic declarations appear before port declarations, generics can size ports as well as embedded signals.

An underlying architecture must operate on signals and ports in a way that is not sensitive to their size. For example, we can loop over signal or port indices using generics as boundary conditions or using the pre-defined attributes 'RANGE and 'REVERSE_RANGE. Aggregates can also accommodate generics to make signal or variable assignments independent of size.

Value: A generic may also represent a value that controls the behavior of the model. Examples include the reset state of a register, the rollover value of a counter, and the decoded address that enables a peripheral. It is most convenient to declare a value generic of the same type as the signal or variable which will receive the value, thereby avoiding the need for conversion functions in the assignment.

Composition: The very structure of the modeled hardware is subject to the whim of an innocent generic. Does our UART model contain a FIFO to buffer received bytes, or only a register? We can specify either with a boolean generic. A process might test the state of the generic and execute one of several alternate behaviors, or the generic can directly control the generation different components, processes, or other concurrent statements.

Generate statements Generate statements conditionally instantiate concurrent constructs of any type. There are two types of generates. The IF...GENERATE tests a specified condition to determine if the enclosed statements exist in the elaborated VHDL model. The FOR...GENERATE specifies a range over which the enclosed statements replicate or telescope. One can nest the two types of generate statements in any way and to dizzying depths. VHDL textbooks often treat generate statements as advanced topics, but they are too powerful and important to be deferred to that level.

Advanced users of Mentor Graphics design capture tools might recognize the analog between generate statements and schematic "case frames." Case frames are actually graphical versions of generates, with the generated elements restricted to component instantiations and signal assignments.




These rules give rise to the notion of superset modeling, which we loosely define as the practice of defining a building block with more features than any one user is likely to want or need. Then, to give the appearance to management that we have designed 10 or 20 building blocks, we unveil the mechanism by which this one ambitious component can be instantiated many unique ways, each of which reveals only the degree of sophistication that the application demands. This is a hardware engineer's version of object-oriented design.

Consider the example shift_reg presented in Listing 2.


Listing 2
Shift register model
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
ENTITY shift_reg IS
GENERIC (
N : POSITIVE := 8; -- Length of shift register
SR : std_logic_vector := "00000000";
AR : std_logic_vector := "00000000"
);
PORT (
Clk : IN std_logic;
AsyncRstN : IN std_logic; -- Active-low asynchronous reset
SyncRst : IN std_logic;
-- Active-high synchronous reset
Ld : IN std_logic; -- Active-high load enable
Rotate : IN std_logic; -- Active-high rotate enable
Right : IN std_logic; -- Active-high right shift
ShiftEn : IN std_logic; -- Active-high shift enable
LSBIn : IN std_logic; -- LSB serial input
MSBIn : IN std_logic; -- MSB serial
input
ParIn : IN std_logic_vector (N-1 DOWNTO 0); -- Parallel data input bus
ScanEn : IN std_logic; -- Active-high scan-path enable
ScanIn : IN std_logic; -- Scan data input
ScanOut : OUT std_logic; -- Scan data output
ParOut : OUT std_logic_vector (N-1 DOWNTO 0); -- Parallel data output bus
MSBOut : OUT std_logic; -- MSB serial output
LSBOut : OUT
std_logic -- LSB serial output
);
END shift_reg;
ARCHITECTURE dataflow OF shift_reg IS
TYPE three_bit IS ARRAY (2 DOWNTO 0) of std_logic;
SIGNAL StateReg : std_logic_vector (N-1 DOWNTO 0);
BEGIN
Sequential : PROCESS (AsyncRstN, Clk)
BEGIN
IF (AsyncRstN = '0') THEN
StateReg <= AR;
ELSIF Clk'EVENT AND (Clk = '1') THEN
-- Perform shift based on left/right, enable, and rotate controls
CASE three_bit'(ShiftEn & Right & Rotate) IS
WHEN "101" => -- Rotate left
StateReg <= StateReg (N-2 DOWNTO 0) & StateReg (N-1);
WHEN "100" => -- Shift left
StateReg <= StateReg (N-2 DOWNTO 0) & LSBIn;
WHEN "111" => -- Rotate right
StateReg <= StateReg (0) & StateReg (N-1 DOWNTO 1);
WHEN "110" => -- Shift right
StateReg <= MSBIn & StateReg (N-1 DOWNTO 1);
WHEN OTHERS => -- No shift
NULL;
END CASE;
IF (Ld = '1')
THEN
StateReg <= ParIn;
END IF;
IF (SyncRst = '1') THEN
StateReg <= SR;
END IF;
IF (ScanEn = '1') THEN
StateReg <= ScanIn & StateReg (N-1 DOWNTO 1);
END IF;
END IF;
END PROCESS Sequential;
ScanOut <= StateReg (0);
ParOut <= StateReg;
MSBOut <= StateReg (N-1);
LSBOut <= StateReg (0);
END dataflow;



This shift register has the following feature set:

  • Variable Length: the register may be sized to any length by the generic N.

  • Asynchronous Reset: the register asynchronously assumes the state specified by the generic AR when AsyncRstN is asserted low.

  • Synchronous Reset: the register assumes the state specified by the generic SR on the next rising clock edge when SyncRst is asserted high.

  • Scan-Path Testing: the register is forced to shift ScanIn to MSB ... LSB to ScanOut to effect full-scan testing when ScanEn is asserted high (redundant in this case, but not in general).

  • Load Enable: the register assumes the state of ParIn on the next rising edge of the clock when Load is asserted high. The contents of the register appear on the output ParOut at all times.

  • Shift Enable: the register shifts on each rising clock edge only when ShiftEn is asserted high.

  • Left/Right Shift: the register shifts right when Right is high and left when Right is low. When the register shifts right, MSBIn feeds the MSB of the shift register, while LSBIn feeds the LSB of the shift register when it shifts left. In either case, the MSB of the shift register connects to MSBOut and the LSB of the shift register connects to LSBOut .

  • Rotate: Regardless of shift direction, the register rotates its contents on the next rising edge of the clock if ShiftEn is asserted high and Rotate is asserted high (states of LSBIn and MSBIn ignored).

Listing 3a illustrates the component declaration for shift_reg . Note that each control input except ShiftEn has a default state assignment equal to its inactive state. Since the direction control has no true inactive state, we arbitrarily select a right shift as the default. Eight is the default length. Listings 3b through 3d depict templates for three unique and entirely valid instantiations of shift_reg with the following subsets of the feature list:

(b) N-bit shift right with shift enable.

(c) N-bit shift left/right with synchronous reset.

(d) 8-bit shift right with load enable and asynchronous reset.

Many other instantiation templates are possible. If we desire a left-only shift register, we must instantiate one with bidirectional shift and manually tie Right to '0'.

What if you create a superset model, believe you've thought of every usable feature, and later discover you did not? Simply add the missing feature to your model and create any new instantiation template(s). Existing instantiation templates should remain valid in most cases.


Listing 3a-d
Shift register component declaration and instantiation templates
 
(a)

COMPONENT shift_reg
GENERIC (
N : POSITIVE := 8;
SR : std_logic_vector := "00000000";
AR : std_logic_vector := "00000000"
);
PORT (
Clk : IN std_logic;
AsyncRstN : IN std_logic := '1';
SyncRst : IN std_logic := '0';
Ld : IN std_logic := '0';
Rotate : IN std_logic := '0';
Right : IN std_logic := '1';
ShiftEn : IN std_logic := '1';
LSBIn : IN std_logic := '0';
MSBIn : IN std_logic := '0';
ParIn : IN std_logic_vector (N-1 DOWNTO 0) := (OTHERS => '0');
ScanEn : IN std_logic := '0';
ScanIn : IN std_logic := '0';
ScanOut : OUT std_logic;
ParOut : OUT std_logic_vector (N-1 DOWNTO 0);
MSBOut : OUT std_logic;
LSBOut : OUT
std_logic
);
END COMPONENT;

(b) UXX : shift_reg GENERIC MAP (N => ) PORT MAP (Clk => , ShiftEn => , MSBIn => , LSBOut => );

(c) UXX : shift_reg GENERIC MAP (N => , SR => ) PORT MAP (Clk => , SyncRst => , Right => , MSBIn => , LSBIn => , MSBOut => , LSBOut => );

(d) UXX : shift_reg GENERIC MAP (AR => ) PORT MAP (Clk => , AsyncRstN => , Load => , MSBIn => , ParIn => , ParOut => , LSBOut => );




Verification and synthesis issues As one might expect, verification of parameterized models is more involved than that for fixed ones. A model that telescopes in size need only be checked for typical cases and boundary conditions. Such a model can be verified within a testbench which expands or contracts the test sequence to correspond to the selected size. Superset models or ones which selectively implement multiple functions require more careful analysis. Simulation coverage tools are available to aid the designer in determining when his test has touched on every feature, or executed every line, of a parameterized model.

Logic synthesis tools do not universally support all of the modeling techniques presented here. For example, the Synopsys .com/isdweb/&lf=isd-sendtolog"> Synopsys VHDL Compiler does not compile the shift_reg model, which includes non-integer generics, and parses but ignores default port assignments in component declarations. One can always instantiate a superset model with all input ports explicitly mapped and selectively tied off, but that clutters the code unnecessarily. Synthesis tool vendors, who have rested on their synthesizable subsets for some time now, should address these and other unsupported language features.

Going for it Parameterized design with VHDL is an excellent foundation for an in-house design reuse program. We have only sampled what is possible. The investments in learning parameterized coding techniques and performing more complex module verification become quite rewarding as your library of pre-characterized building blocks grows.

This work was supported by the United States Department of Energy under Contract DE-AC04-94AL85000.

Matt Henry is a senior member of the technical staff in the digital ASIC department at Sandia National Laboratories (Albuquerque, NM). He received a BS in Electrical Engineering from Penn State University in 1984.

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


integrated system design  August 1995



[ 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 © 1996 - 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