You are on page 1of 14

Designing with VHDL part 3

signal

attributes
arrays and records
variables
functions and procedures
assertions
packages
Jon Turner

Signal Attributes
For

signal x: std_logic_vector(15 downto 0),

xleft=15, xright=0
these are referred to as attributes of x
other attributes include xhigh (=15), xlow (=0),
xrange (=15 downto 0) and xlength (=16)
Signal

attributes can be used to write code that is


less dependent on specific signal lengths
for example
x(xhigh) <= 1; x(xlow+3 downto xlow) <= xc;
x <= (xhigh => 1, xlow => 1, others => 0);

This

can make code easier to change and is useful


when writing modules with generic signal lengths

Arrays of std_logic_vectors
-- using these declarations
subtype word is std_logic_vector(wordSize-1 downto 0);
type regFileTyp is array(0 to regFileSize-1) of word;
signal reg: regFileType;
-- we can write things like
reg(2) <= reg(1) + reg(4);
reg(3 downto 0) <= reg(7 downto 4);
reg(3)(5) <= 1;
reg(int(x)) <= reg(int(y)) -- int() converts to integer
Synthesizer

can implement such arrays using registers


constructed from flip flops
Sometimes can be implemented using memory blocks
depends on how the array is used in the VHDL
for large arrays of words that are accessed one at a time,
synthesizer will typically use a memory block

Defining 2d Constant Arrays


Constant

arrays can be used to define tables of values

subtype asciiChar is std_logic_vector(7 downto 0)


type hex2AsciiMap is array(0 to 15) of asciiChar;
constant hex2Ascii: hex2AsciiMap := (
x"30", x"31", x"32", x"33",x"34", -- 0-4
x"35", x"36", x"37",x"38", x"39", -- 5-9
x"61", x"62",x"63", x"64", x"65", x"66" -- a-f
);
...
ascii3 <= hex2Ascii(3);
Constant

arrays are read-only so, synthesizer can


implement using Read-Only Memory (ROM)
ROMs are generally less expensive than read/write memory

Defining Records
-- with these definitions
type entryType is record
valid: std_logic;
key, value: word
end record entryType;
constant tableSize: integer := 8;
type tableTyp is array(0 to tableSize-1) of entryType;
signal table: tableType
-- we can write
table(2).key <= table(1).value
if table(0).valid = 1 then
table(5) <= (1, xabcd, x0123);
end if;

Synthesizer can implement using registers

Review Questions
1.

2.

3.

Consider the declaration


signal x: std_logic_vector(0 to 7);
what are the values of the following attributes
xlow xhigh xleft xright xrange xlength
Write the declarations needed to define a constant array called
firstOne, with 16 entries of 4 bits each, where the value of
firstOne(x) is the position in x of the rightmost 1 bit. So for
example, firstOne(0010)=01, firstOne(1100)=10. If none
of the bits in x are 1, make firstOne(x)=00
Write the declarations to define a table in which each entry has
three fields, x, y and z, where x is a single bit signal and y and z
are eight bit signals. Entries should be numbered 1, 2,...,8. Write
an assignment that copies the y field of the second entry in the
table to the z field of the fifth entry if the x fields of both entries
are equal.

Variables
VHDL

provides variables in addition to signals

unlike signals, variables do not correspond to wires


best to think of variable assignment as an abbreviation
a <= x"3a";
y := a + x"01";

-- assignment to variable y

b <= y;
y := y + x"10";

-- defines new abbreviation for y

c <= y;
-- equivalent code segment without variables
a <= x"3a";
b <= a + x"01";
c <= (a+x"01") + x"10";
To

reduce confusion, no variable should be used in both a


synchronous and asynchronous context

Use of Variables in Loops


architecture a1 of findFirstOne is
signal got1: std_logic_vector(wordSize downto 0);
begin
process (dIn,got1) begin
got1(0) <= 0; index <= (others => 0);
for i in 0 to wordSize-1 loop
if got1(i) < dIn(i) then index <= slv(i,lgWordSize); end if;
got1(i+1) <= dIn(i) or got(i);
end loop;
got1(i) is high if there is a 1
valid <= got1(wordSize);
that comes before bit i in array
end process;
end a1;

architecture a1 of findFirstOne is begin


process (dIn)
variable got1: std_logic;
begin
got1 := 0; index <= (others => 0);
for i in 0 to wordSize-1 loop
if got1 < dIn(i) then index <= slv(i,lgWordSize); end if;
got1 := dIn(i) or got1;
end loop;
got1 signal plays same role;
valid <= got1;
can yield more efficient circuit
end process;
end a1;

Functions
Functions

can be used to define sub-circuits that are


used repeatedly within a larger circuit
function max(x,y: word) return word is
begin
if x > y then return x; else return y; end if;
end function max;

Each

distinct use of a function causes a copy of the


subcircuit to be synthesized
q <= max(s,t);
r <= max(u,q);
exception: multiple uses
with same inputs dont
require separate copies

Procedures
Procedures

can be used to define subcircuits with


multiple outputs
procedure inRange(x: in word;
inRange: out std_logic;
tooHigh: out std_logic;
tooLow: out std_logic) is
constant loBound: word := x1234";
constant hiBound: word := xabcd";
begin
tooLow := '0'; inRange := '0'; tooHigh := '0';
if
x < loBound then tooLow := '1';
elsif x <= hiBound then inRange := '1';
else
tooHigh := '1';
end if;
end procedure;

Procedure

parameters are variables

use variable assignment when assigning output values

Assertions
Assertion

statements are useful for debugging a


circuit specification
assert 0 < x and x < y;
the condition in the assert statement is checked during
simulation and triggers an error message if violated

Add

report clause to specify error message

assert 0 < x and x < y report x out of range;


Add

severity clause to force early termination

assert 0 < x and x < y severity failure;


Also

useful in testbenches to compare circuit


output with expected output

Packages
Packages

can be used to define constants, types and functions/procedures used by


multiple modules

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_arith.all;
use IEEE.std_logic_unsigned.all;

constant, type, subtype


definitions, function and
procedure declarations

package commonDefs is
constant wordsize: integer := 16;
constant nBtn: integer := 4;...
subtype word is std_logic_vector(wordSize-1 downto 0);
subtype buttons is std_logic_vector(nBtn-1 downto 0);...
function int(d: std_logic_vector) return integer;
end package commonDefs;
library IEEE; ...
package body commonDefs is
function int(d: std_logic_vector) return integer is
begin return conv_integer(unsigned(d)); end function int;
end package body commonDefs;

Typically

placed in a separate source file

package body
with function,
procedure
definitions

Exercises
1. Write a VHDL declaration for an array
of records, where the index range for
the record is the same as the index
range for a std_logic_vector, called z.
Each record in your array should have
two fields; field A is a std_logic_vector
with a descending range that has the
same limits as z, field B is a
std_logic_vector with an ascending
range that has the same limits as z.

2. In the VHDL code segment shown


below, determine the value assigned to
each of the signals x and y on the next
clock tick assuming that their initial
values are x4 and x7.
if rising_edge(clk) then
a := x + y;
x <= a + x1;
y <= a + x;
a := y - x3;
x <= a + x2;
end if;
3. Write a VHDL procedure minMax that
takes two eight bit inputs and produces
two eight bit outputs. The first of the
outputs is equal to the smaller of the
two input values, while the second is
equal to the larger of the two inputs.

Solutions
1.type recTyp: record is
A: std_logic_vector(zhigh
downto zlow);
B: std_logic_vector(zlow
to zhigh);
end record;
type recArray: array(zrange)
of recType;
2. The first assignment to x has no effect,
so the new value of x is a+x2,
where a=yx3=x4; so the new
value of x is x6.
The new value of y is a+x,
where a=x+y=xb, so the new value
of y is xf.

3.procedure minMax(
a, b: in SLV(7 downto 0);
x, y: out SLV(7 downto 0))
is begin
if a < b then
x := a; y := b;
else
x := b; y := a;
end if;
end procedure minMax;

You might also like