APS-X84 VHDL/FPGA SYNTHESIS TUTORIAL

VHDL DATA OBJECTS

There are many data objects which can be used in VHDL. To keep to the concept of this Lab book we will restrict ourselves to the following objects for our discussions:

1) std_logic
2) std_logic_vector
3) Integers

std_logic basically describes a bit. A bit can usually be described using two states (1 or 0). However there could be some other conditions such as high impedance, or don't cares which could be used in simulation or even in synthesis. In fact the std_logic package is a 9 value bit.

std_logic's defined states

'U' - Uninitialized
'X' - Forced Unknown
'0' - Logic zero
'1' - Logic one
'Z' - High Impedance
'W' - Weak unknown
'L' - Weak Zero
'H' - Weak One
'-' - Don't care

Keeping our minds on Synthesis only here we will basically use only 1 or 0 and perhaps Z(high impedance). From our ANDGATE program you can see that in our ENTITY declarations we declared Ain, Bin and COut all as std_logic.

ENTITY ANDGATE IS PORT ( Ain: in STD_LOGIC; Bin: in STD_LOGIC ; COut: out STD_LOGIC ); END ANDGATE;

std_logic_vector is an array of bits. This array can be declared in basically 2 formats

BusIn : in STD_LOGIC_VECTOR(7 downto 0); -- eight bit bus OR BusIn: in STD_LOGIC_VECTOR(0 to 7); -- eight bit bus

It doesn't really matter which way you declare your vector as long as you are consistent throughout your code. I prefer to use the first method and feel it better represents the BYTE and WORD formats.

Once an array is declared, individual members can be accessed as shown:

BusIn(3 downto 0) <= "1010"; BusIn(4) <= '1'; BusIn(7) <= Ain;

Notice how individual bits are surrounded by a single apostrophe ('1') while the standard double quote is used to describe strings or arrays of values.("1010"). Also notice how Ain (a std_logic) can be assigned to one bit of a std_logic array ( BusIn(7) ). All individual pins ant the top level ENTITY will be std_logic or std_logic_vectors in the examples.

-- -- Covert standard logic vector to integer -- FUNCTION slvect2int(vect : std_logic_vector) RETURN INTEGER IS VARIABLE size : INTEGER RANGE vect'length-1 DOWNTO 0; VARIABLE result : INTEGER RANGE (2**size)-1 DOWNTO 0; BEGIN result := 0; FOR i IN 0 TO size LOOP IF (vect(i) = '1') THEN result := result + 2**i; END IF; END LOOP; RETURN result; END slvect2int;

The code segment above is a function (which we will cover later). Notice that size is declared as a vect'length size INTEGER. vect is the name of the STD_LOGIC_VECTOR which is passed into the FUNCTION. length is an attribute of the STD_LOGIC_VECTOR object. VHDL has many Object Oriented aspects to it which are beyond the scope of this text. There are many other attributes of STD_LOGIC_VECTORs and other VHDL data types which are available for use. We will not discuss these in this text but it is a feature worth exploring in a more detailed VHDL text.

INTEGERS are used to describe numbers which are easy to increment and do simple math on. They typically describe an N bit std_logic_vector where N is the largest numbers of bits which can describe the integers maximum range. Integers are very useful for counter operations. An integer is declared in the program below:

library IEEE; use IEEE.std_logic_1164.all; library METAMOR; use METAMOR.attributes.all; library SYNOPSYS; use SYNOPSYS.std_logic_arith.all; use SYNOPSYS.std_logic_unsigned.all; library PN_PAK; use PN_PAK.PN_PAK.all; ENTITY X84DEMO IS PORT ( The555In: IN std_logic; DivSigOut: BUFFER std_logic; DivCntIn: IN std_logic_vector(7 downto 0) ); attribute pinnum of DivCntIn : signal is "P10,P9,P8,P7,P6,P5,P4,P3"; attribute pinnum of DivSigOut : signal is "P35"; attribute pinnum of The555In : signal is "P24"; END X84DEMO; ---------------------------------------------------------------- ---------------------------------------------------------------- ARCHITECTURE behave OF X84DEMO IS SIGNAL Count: INTEGER RANGE 0 TO 255; SIGNAL MultCnt: INTEGER RANGE 0 TO 255; -- Divide input by Multiplier times the DivCntIn value CONSTANT Multiplier : INTEGER RANGE 0 to 255 := 10; BEGIN DIVIDER: PROCESS BEGIN WAIT UNTIL The555In'EVENT AND The555In = '1'; -- wait til rising edge IF MultCnt >= Multiplier THEN Count <= Count +1; -- increment counter MultCnt <= 0; -- reinitialize Multiplier Counter ELSE MultCnt <= MultCnt + 1; -- Output divided pulse; END IF; IF Count >= slvect2int(DivCntIn,8) THEN DivSigOut <= NOT DivSigOut; -- toggle LED on X84 Count <= 0; -- reinitialize counter END IF; END PROCESS; END behave;

Upon examination of the code above we see highlighted two statements which declare SIGNALS (BASICALLY INTERNAL WIRES) which are
INTEGERS in the range of 0 to 255 or 256 values. This INTEGER could be represented by 8 bits since 2^8 is equal to 256. By having the COUNT and MultCnt declared as INTEGERS we can more easily add and subtract counts.

We also see an INTEGER which is not a SIGNAL but is in fact a CONSTANT. This is exactly what it sounds like. The format for the CONSTANT is the same as the SIGNAL format except the := sign is used to assign the CONSTANT value. This value will be STATIC and can be assigned or manipulated throughout the code. In our example we use the value to set a CONSTANT Multiplier which sets is used for comparison in an IF THEN condition statement.

While we are here you will also notice some other new code elements. A new library called PN_PAK is USED and a FUNCTION slvect2int() (which is contained in PN_PAK is used. These will be discussed in greater detail in the INCLUDE STUFF discussion.