Sunteți pe pagina 1din 8

Introduction

So what is VHDL? VHDL is an acronym that stands for VHSIC (Very High Speed Integrated Circuit) Hardware Description Language. VHDL is an industry standard for the description, modeling and synthesis of digital circuits and systems. One of the nicest features of this language is that it does not depend on a specific PLA (Programmable Logic Array) or FPGA (Field Programmable Gate Array) for its development. Instead, a VHDL description can be placed in libraries to be used over and over again as technology develops. Another nice aspect of the VHDL language is that it is similar in syntax to objected oriented languages such as C++. But remember, it is not a programming language as we use it. It is a hardware description language. Contents

Basic Framework and Syntax


On the most basic level, the description of a logical block is split into two parts, the ENTITY and the ARCHITECTURE. The ENTITY declaration is much like a declaration of a function in C++. In this case, the ENTITY decalaration tells us that we have a device called compare8. It does not tells us how compare8 actually functions... this is left to the ARCHITECTURE section. For example if I were to be describing a 8-bit comparator, I would need two 8-bit inputs and a 1-bit output:
1 ENTITY compare8 IS PORT( 2 x, y: IN std_logic_vector(7 DOWNTO 0) ; 3 res: OUT std_logic ); 4 END compare8;

The first line tells us what we are describing, in this case the name of the entity is compare8. The word PORT followed by a parenthesis tells us that the following information describes the I/O behavior of this entity. Line 2 begins the actual description of our inputs. In this case we are using x and y as inputs and declaring them to be vectors of 8-bits with bit 7 being the most significant and bit 0 the least. Line three describes our output. For a comparison, we only need to know if the values are equal, or not equal. We therefore only need a single bit as the output. The final line tells us that we are at the end of the description for the entity called compare8. The ARCHITECTURE statement is like the actual function in C++, it describes the logic behind the entity. For the case of the comparator, we want to return a 1 if the two values are equal and a 0 if they are not:
1 ARCHITECTURE struct OF compare8 IS 2 BEGIN 3 res <= '1' WHEN (x = y) ELSE '0'; 4 END struct;

The first line tells us that the architecture name of the entity compare8 is struct. This is important because an entity may have several different architectures, perhaps with various levels of detail in their descriptions. For our purposes, however, we will usually only write one architecture. The BEGIN statement tells us that you are beginning your description of the logic. In some cases you may declare types beforehand in which case it would not be the first statement, but we will touch upon that later in this tutorial. Line 3 is the meat of this section, and reads just as it is written: the value 1 will be placed in res when the values of x and y are equal, otherwise it will return a 0. The <= is an assignment operator and can only be used when writing to an output value, variables use a different assignment operator that will be discussed later. The final line tells us that we have completed our description of the architecture struct. Now even with these 8 lines of code, there is still something missing that will make this a complete program. That is the following:
library ieee; use ieee.std_logic_1164.all;

These must be the first two lines of every ENTITY because it tells the compiler that you are using the standard IEEE library and that the signal types that you are declaring in the entity can be found in ieee.std_logic_1164.all (this is where it recognizes what std_logic_vector() and std_logic mean). Thus a complete description of an 8-bit comparator would be:
library ieee; use ieee.std_logic_1164.all; ENTITY compare8 IS PORT( x, y: ;IN std_logic_vector(7 DOWNTO 0) ; res: ;OUT std_logic ); END compare8; ARCHITECTURE struct OF compare8 IS BEGIN res <= '1' WHEN (x = y) ELSE '0'; END struct;

Contents

A Simple Latch
The simplest latch is the S-R latch, which is described by the following truth table: Set --0 0 1 1 Reset --0 1 0 1 | --| | | | Q --Q 0 1 "X" /Q --/Q 1 0 "X"

The most important aspect of a latch is that it not only relies on current inputs, but also is dependent on the previous result. In this case, we will have to use a new type of output, the BUFFER. The BUFFER permits the signal to be read and written within the entity. the signal holds its value because of the process. Thus in the ARCHITECTURE section, we can not only write to the outputs, but also use those values in the next iteration.
ENTITY srlatch IS PORT( s,r: IN std_logic; q,qnot: BUFFER std_logic); END srlatch; ARCHITECTURE struct OF srlatch IS BEGIN PROCESS (s,r) BEGIN IF (r='1' AND s='0') THEN q<='0'; qnot<= NOT q; ELSIF (r='0' and s='1') THEN q<='1'; qnot<= NOT q; ELSIF (r='1' and s='1') THEN q<='X'; qnot<='X'; END IF; END PROCESS; END struct;

This example also introduces the IF...THEN...ELSE structure. As in most programming languages, it is often useful to output different results depending on the input stimulus. In this example, we simply replicate the truth table with if then statements. The X value means unknown. Finally, one of the most important things introduced here is the process statement. The PROCESS statement tells us that the steps within the process are sequential. Now this may be a bit confusing, let us explain Electronic systems are concurrent by nature, in other words, there is not a sense of order in execution. You can even have multiple processes evaluating concurrently. A sequential circuit is different in the fact that the order of signal assignments affects how the logic is synthesized. It should be noted that when we talk about sequential statements and processes, we are not necessarily talking about sequential logic or logic with memory. To get back to the VHDL the PROCESS statement tells the compiler that the following steps are to be sequentially executed and therefore, the ultimate synthesis of the logic will be such that the logic will be evaluated in the same manner as a sequential statement. Contents

Synthesis of a 4-bit ripple carry adder


The purpose of this section is to introduce some more advanced concepts as well as demonstrating a design methodology to be used with VHDL for the synthesis of a logical device.

As you may know, a 4-bit ripple carry adder can be created by simply stringing four 1-bit adders together with a carry path, thus the most logical starting place would be the design of a single bit and the expansion to 4-bits. The truth table of a 1-bit full adder is :
A --0 0 0 0 1 1 1 1 B --0 0 1 1 0 0 1 1 Carry In --0 1 0 1 0 1 0 1 | --| | | | | | | | Sum --0 1 1 0 1 0 0 1 Carry Out --0 0 0 1 0 1 1 1

From this we can generate the equations for the sum and the carry. The equation for the sum is: Sum = A XOR B XOR Carry In while the equation for the carry is: Carry Out = (A AND B) OR (B AND Carry In) OR (A AND Carry In) Once we have derived the boolean equations for a single bit, we can then go on to the actual design of a full adder. From the above we can see three inputs (A, B, and Carry In) and two outputs (Sum, Carry Out), thus our entity declaration would be:
ENTITY addbit IS PORT( A, B, Ci : IN std_logic; S, Co: OUT std_logic); END addbit;

The ARCHITECTURE section of this 1-bit entity would be as follows:


ARCHITECTURE struct OF addbit IS BEGIN PROCESS (A, B, Ci) BEGIN S<= A XOR B XOR Ci; Co<= (A AND B) OR (B AND Ci) OR (A AND Ci); END PROCESS; END struct;

Now that we have designed a single bit, we can cascade four by using the hierarchical structure of VHDL to create our 4-bit adder:
library ieee; use ieee.std_logic_1164.all; ENTITY add4 IS PORT(

A, B: INstd_logic_vector(3 DOWNTO 0); Cin:IN std_logic; Sum: OUT std_logic_vector(3 DOWNTO 0); Cout: OUT std_logic); END add4; ARCHITECTURE struct OF add4 IS COMPONENT addbit PORT( A, B, Ci : IN std_logic; S, Co: OUT std_logic); END COMPONENT; SIGNAL c: std_logic_vector (4 DOWNTO 0); BEGIN g1: FOR i IN 0 TO 3 GENERATE comp: addbit PORT MAP( A => A(i), B=>B(i), S => Sum(i), Ci => c(i), Co => c(i+1) ); END GENERATE g1; c(0) <=Cin; Cout<=c(4); END struct;

In this example we introduce four new concepts: the COMPONENT, the SIGNAL, the FOR GENERATE loop, and the MAP statement. As you may notice, the ENTITY declaration is pretty straightforward so lets skip that and go on to the ARTITECTURE declaration. The first thing you may notice is that the behavior of the 4-bit adder is not directly described; instead we use the COMPONENT statement to say that we are using the previously declared entity addbit (note: the entity addbit must be included in the file containing add4 so that the two are compiled together). In the COMPONENT statement we need to declare which inputs and outputs of the component we will be using. The reason we must declare the component input and output in the architecture section is that these become internal signals to the larger device and thus we do not want them available to outside interaction. This is the same reason that the SIGNAL is declared in the architecture. The SIGNAL statement is like a local variable, but can be thought of as a physical wire inside the device. In this case, we use the signal c to pass along the state of the carry internally. The reason that it is a vector of 5-bits even though we are only using a 4-bit adder is that it reflects the carry path. The statement: FOR i IN 0 TO 3 GENERATE is used to create a loop for mapping the external 4-bit inputs to the single bit inputs of the addbit component. The MAP command as you may have guessed will generate the 1-1 mapping between the I/O of the component being used and the object being built. You will note that the Ci and Co are both mapped to the signal c, but that Carry out of one stage will also be mapped to the carry in stage of the next. Once the mapping is complete, since this 4-bit adder allows a carry in, and produces a carry out, we must then assign the value of the carry in to the first bit in the vector c and the value of the last bit of c to the carry out. This may seem to be a very involved way to create a 4bit adder, and it is. The purpose of this example is not to minimize the amount of code

being written, but to introduce new concepts that will allow you to later create hierarchical designs and reuse code. A much more concise way of building a 4-bit adder would be the following:
library ieee; USE ieee.std_logic_1164.all; ENTITY adder IS PORT ( a, b: IN std_logic_vector (3 DOWNTO 0); sum: OUT std_logic_vector (3 DOWNTO 0); cout: OUT std_logic); END adder; ARCHITECTURE struct OFadder IS SIGNAL c : std_logic_vector (4 DOWNTO 0); BEGIN interm<=a XOR b; c<=((a AND b) OR (interm AND c(3 DOWNTO 0))) & '0'; sum<= interm XOR c(3 DOWNTO 0); cout<=c(4); END struct;

This adder is a bit different as it does not take a carry in as an argument, but produces the same signal output. It also makes use of the concatination operator "&" to extend the value being placed into c to 5-bits as opposed to 4. Contents

Design of an 8-bit register


Our last example will be the design of a 4x8 register as shown below:

A VHDL description of the above model is:


library ieee; USE ieee.std_logic_1164.all;

ENTITY reg8 IS PORT( clk,we: IN std_logic; rdata: IN std_logic_vector (7 DOWNTO 0); Asel, Bsel: IN std_logic_vector (1 DOWNTO 0); Aout,Bout: OUT std_logic_vector (7 DOWNTO 0) ); END reg8; ARCHITECTURE one OF reg8 IS< BEGIN first: PROCESS (clk, we, rdata, Asel, Bsel) TYPE reg_array IS ARRAY(0 TO 3) OF std_logic_vector(7 DOWNTO 0); VARIABLE reg:reg_array(7 DOWNTO 0); BEGIN IF clk'EVENT AND clk='0' THEN IF (we='1') THEN CASE Asel IS WHEN "00" => reg(0):=rdata; WHEN "01" => reg(1):=rdata; WHEN "10" => reg(2):=rdata; WHEN OTHERS => reg(3):=rdata; END CASE; ELSE CASE Asel IS WHEN "00" => Aout<=reg(0); WHEN "01" => Aout<=reg(1); WHEN "10" => Aout<=reg(2); WHEN OTHERS => Aout<=reg(3); END CASE; CASE Bsel IS WHEN "00" => Bout<=reg(0); WHEN "01" => Bout<=reg(1); WHEN "10" => Bout<=reg(2); WHEN OTHERS => Bout<=reg(3); END CASE; END IF; END IF; END PROCESS first; END one;

We introduce three new concepts in this example: TYPE, VARIABLE, and CASE. Earlier we saw something called a SIGNAL which looks like a variable. The difference is that a SIGNAL is analogous to a physical wire while a variable is only visible inside a process, function, or procedure. A variable is typically used as index holders in loops, but can also be used in a similar fashion to a signal. The TYPE definition allows you create new types of variables just as it wold in any other programming language. Since VHDL is a strongly typed language, there are a multitude of types available including integer, array, floating, record, and composite just to name a few. From these types the user can create new types as necessary using the TYPE statement. The last concept introduced here is the CASE statement. The CASE statement is a block of sequential statements that allow the user to dictate the behavior of a part by looking at an input and using the input as a key to determine which path to follow. The "clk'EVENT AND clk='0' " statement evaluates to true when there is a falling edge on the signal clk. Every time a signal

changes states, an event occurs, thus in this case, we want the clock to change states and the current state to be '0'.

S-ar putea să vă placă și