You are on page 1of 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 final line tells us that we have completed our description of the architecture struct. however. but we will touch upon that later in this tutorial. END compare8. otherwise it will return a 0.IN std_logic_vector(7 DOWNTO 0) . Thus a complete description of an 8-bit comparator would be: library ieee. perhaps with various levels of detail in their descriptions.std_logic_1164.OUT std_logic ). we will usually only write one architecture. That is the following: library ieee. Line 3 is the meat of this section.all (this is where it recognizes what std_logic_vector() and std_logic mean). 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" . END struct. variables use a different assignment operator that will be discussed later.all.all. y: . ARCHITECTURE struct OF compare8 IS BEGIN res <= '1' WHEN (x = y) ELSE '0'. ENTITY compare8 IS PORT( x. The <= is an assignment operator and can only be used when writing to an output value. use ieee. there is still something missing that will make this a complete program. res: . For our purposes. Contents A Simple Latch The simplest latch is the S-R latch.std_logic_1164. 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. and reads just as it is written: the value 1 will be placed in res when the values of x and y are equal. use ieee.std_logic_1164. Now even with these 8 lines of code. 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.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.

qnot<= NOT q. ARCHITECTURE struct OF srlatch IS BEGIN PROCESS (s. ENTITY srlatch IS PORT( s. END IF.. q.r) BEGIN IF (r='1' AND s='0') THEN q<='0'. This example also introduces the IF. It should be noted that when we talk about sequential statements and processes.r: IN std_logic. let us explain… Electronic systems are concurrent by nature.. . one of the most important things introduced here is the process statement. the ultimate synthesis of the logic will be such that the logic will be evaluated in the same manner as a sequential statement. END srlatch. we are not necessarily talking about sequential logic or logic with memory. The PROCESS statement tells us that the steps within the process are sequential. the signal holds its value because of the process. The BUFFER permits the signal to be read and written within the entity. As in most programming languages. qnot<='X'. but also is dependent on the previous result. we can not only write to the outputs.THEN. END PROCESS. we simply replicate the truth table with if then statements. qnot<= NOT q. You can even have multiple processes evaluating concurrently. it is often useful to output different results depending on the input stimulus.. Finally. In this case. To get back to the VHDL… the PROCESS statement tells the compiler that the following steps are to be sequentially executed and therefore. In this example. ELSIF (r='1' and s='1') THEN q<='X'.The most important aspect of a latch is that it not only relies on current inputs. 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.ELSE structure. the BUFFER. The ‘X‘ value means unknown. ELSIF (r='0' and s='1') THEN q<='1'. A sequential circuit is different in the fact that the order of signal assignments affects how the logic is synthesized. Now this may be a bit confusing. we will have to use a new type of output. in other words. there is not a sense of order in execution.. END struct. but also use those values in the next iteration. Thus in the ARCHITECTURE section.qnot: BUFFER std_logic).

END struct. thus the most logical starting place would be the design of a single bit and the expansion to 4-bits. The ARCHITECTURE section of this 1-bit entity would be as follows: ARCHITECTURE struct OF addbit IS BEGIN PROCESS (A. Co<= (A AND B) OR (B AND Ci) OR (A AND Ci). and Carry In) and two outputs (Sum. we can then go on to the actual design of a full adder. B. ENTITY add4 IS PORT( . S.std_logic_1164. Ci : IN std_logic. Ci) BEGIN S<= A XOR B XOR Ci. END addbit.As you may know. B. Now that we have designed a single bit. a 4-bit ripple carry adder can be created by simply stringing four 1-bit adders together with a carry path. use ieee. 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. From the above we can see three inputs (A. thus our entity declaration would be: ENTITY addbit IS PORT( A. Carry Out). 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. Co: OUT std_logic).all. END PROCESS. B. we can cascade four by using the hierarchical structure of VHDL to create our 4-bit adder: library ieee.

END COMPONENT. Co: OUT std_logic). Cout<=c(4). 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. Cin:IN std_logic. B=>B(i). 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. 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). Sum: OUT std_logic_vector(3 DOWNTO 0). The first thing you may notice is that the behavior of the 4-bit adder is not directly described. Once the mapping is complete. 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. but can be thought of as a physical wire inside the device. c(0) <=Cin. and produces a carry out.A. END add4. This is the same reason that the SIGNAL is declared in the architecture. The purpose of this example is not to minimize the amount of code . B. BEGIN g1: FOR i IN 0 TO 3 GENERATE comp: addbit PORT MAP( A => A(i). Ci => c(i). Cout: OUT std_logic). we use the signal c to pass along the state of the carry internally. S => Sum(i). As you may notice. the FOR… GENERATE loop. B: INstd_logic_vector(3 DOWNTO 0). and it is. 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. You will note that the Ci and Co are both mapped to the signal c. since this 4-bit adder allows a carry in. Co => c(i+1) ). In the COMPONENT statement we need to declare which inputs and outputs of the component we will be using. S. 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. END struct. This may seem to be a very involved way to create a 4bit adder. END GENERATE g1. ARCHITECTURE struct OF add4 IS COMPONENT addbit PORT( A. and the MAP statement. the ENTITY declaration is pretty straightforward so lets skip that and go on to the ARTITECTURE declaration. In this case. but that Carry out of one stage will also be mapped to the carry in stage of the next. the SIGNAL. Ci : IN std_logic. The SIGNAL statement is like a local variable. SIGNAL c: std_logic_vector (4 DOWNTO 0). In this example we introduce four new concepts: the COMPONENT.

sum: OUT std_logic_vector (3 DOWNTO 0). END adder. c<=((a AND b) OR (interm AND c(3 DOWNTO 0))) & '0'. cout<=c(4). ENTITY adder IS PORT ( a. It also makes use of the concatination operator "&" to extend the value being placed into c to 5-bits as opposed to 4.std_logic_1164.being written. A much more concise way of building a 4-bit adder would be the following: library ieee.std_logic_1164. USE ieee.all. sum<= interm XOR c(3 DOWNTO 0). This adder is a bit different as it does not take a carry in as an argument. . cout: OUT std_logic). but produces the same signal output. ARCHITECTURE struct OFadder IS SIGNAL c : std_logic_vector (4 DOWNTO 0). USE ieee. 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. END struct. BEGIN interm<=a XOR b.all. but to introduce new concepts that will allow you to later create hierarchical designs and reuse code. b: IN std_logic_vector (3 DOWNTO 0).

WHEN "01" => Bout<=reg(1). but can also be used in a similar fashion to a signal. Asel. floating. END CASE. VARIABLE. and CASE. there are a multitude of types available including integer. The "clk'EVENT AND clk='0' " statement evaluates to true when there is a falling edge on the signal clk. END IF. A variable is typically used as index holders in loops. WHEN "01" => Aout<=reg(1). Since VHDL is a strongly typed language. we. WHEN OTHERS => reg(3):=rdata. Every time a signal . function. ELSE CASE Asel IS WHEN "00" => Aout<=reg(0). Earlier we saw something called a SIGNAL which looks like a variable. WHEN "10" => reg(2):=rdata. and composite just to name a few. record. The difference is that a SIGNAL is analogous to a physical wire while a variable is only visible inside a process. array. END CASE. END IF.Bout: OUT std_logic_vector (7 DOWNTO 0) ). or procedure. 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. From these types the user can create new types as necessary using the TYPE statement. END reg8. Aout. The last concept introduced here is the CASE statement. END one. CASE Bsel IS WHEN "00" => Bout<=reg(0). WHEN OTHERS => Aout<=reg(3). ARCHITECTURE one OF reg8 IS< BEGIN first: PROCESS (clk. VARIABLE reg:reg_array(7 DOWNTO 0). WHEN "10" => Aout<=reg(2).we: IN std_logic. WHEN "10" => Bout<=reg(2).ENTITY reg8 IS PORT( clk. Bsel) TYPE reg_array IS ARRAY(0 TO 3) OF std_logic_vector(7 DOWNTO 0). Asel. END PROCESS first. Bsel: IN std_logic_vector (1 DOWNTO 0). WHEN "01" => reg(1):=rdata. The TYPE definition allows you create new types of variables just as it wold in any other programming language. rdata. BEGIN IF clk'EVENT AND clk='0' THEN IF (we='1') THEN CASE Asel IS WHEN "00" => reg(0):=rdata. rdata: IN std_logic_vector (7 DOWNTO 0). WHEN OTHERS => Bout<=reg(3). END CASE. We introduce three new concepts in this example: TYPE.

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