RT Level Hardware Description with VHDL:Combinational Circuits
Combinational Circuits
A combinational circuit can be represented by its subcomponents at its gate level. VHDL does not provide primitive structures and thus any gate primitive (NAND, NOR, etc.) must be separately described using an entity–architecture pair. Figure 87.5 shows the VHDL code for several common gate level components.
Gate Level Combinational Circuits
This section describes the VHDL codes for individual gates of Figure 87.5. As for the 2-input AND gate component, the entity has been defined with in1 and in2 as its input pins of type std_logic and a single output named out1. For defining the component’s functionality a signal assignment is used. A signal assignment statement assigns values to its left-hand-side signal or output, buffer, or inout ports. An event observed on in1 or in2, right-hand-side signals of the signal assignment of the AND2 gate causes the evaluation of the right-hand-side expression. The VHDL code shows a 3 ns delay for the 2-input AND component. This results in the assignment of a new value to out1 taking place 3 ns after the evaluation of the right-hand-side expression.
The BUFIF1 and BUFIF0 gates are implemented using conditional signal assignments which will be described later. Other primitive gates can be easily defined as shown above. These primitive gates provide a sufficient set of components for the description of larger structures. With the help of component instantiation, which will be shortly discussed, larger components can be described.
Majority Example
We will use the majority example of Figure 87.6 to illustrate how a defined component can be instantiated and used in a design. Figure 87.6 shows a structural description of a majority circuit consisting of four
subcomponent instantiation. Components that are to be instantiated in this architecture need to be declared in its declarative part. A component declaration consists of the name of the component followed by its ports. In the statement part, these components are instantiated and interconnected. Each component instantiation starts with an arbitrary label followed by the name of the component and then by a mapping between the ports of the instantiated component and the actual component. The interconnection between these subcomponents is done with signals declared in the declarative part of the architecture. The components used in this example are described in Figure 87.5.
Multiplexer Example
The multiplexer example is a good example to show how a resolution function works for a signal. As shown in Figure 87.7 the 2-to-1 multiplexer is described using BUFIF1 and BUFIF0, which we defined in Figure 87.5.
When a line is derived with two drivers a resolution function needs to be specified for that signal. The std_logic type has a predefined resolution function in the IEEE Std 1164 package. Since wiring two signals, one with a 0 value and another with a 1 value results in an unknown value, driving 0 and 1 simultaneously into a resolved signal results in X. Although the resolved resolution function satisfies most design require- ments, other resolution functions can be described in VHDL. Table 87.2 illustrates how the resolved function in the IEEE Std 1164 package works for five of the more commonly used values.
Description by Use of Equations
A combinational circuit may also be described by the use of Boolean, logical, and arithmetic expressions. The VHDL language has a set of standard operators that can be used for Boolean, logical, and arithmetic equations. Table 87.3 shows this set of operators. These operators can be used in assign statements to create the desired functionality for the circuit.
XOR Example
Consider the description of an XOR gate using Boolean equations in Figure 87.8. As discussed before, a signal assignment can be used to assign values to ports or other signals. Here the xor operator has been used in a simple signal assignment to assign the result of in1 xored with in2 to the output after a 3 ns delay.
So, it can be seen that instead of having to write our own gates in the way described in Section 87.2.1, we can simply use operators listed in Table 87.3 to produce any desired expression.
Full Adder Example
The code shown in Figure 87.9 corresponds to a single-bit full adder. A full adder can be simply described by two signal assign statements: one for sum and one for carry out. The sum output can be easily generated with a Boolean expression using two xor operators. The expression will be the same as the XOR example described above with the difference of having three operands this time. Therefore two xor operators will be used. As for the carryOut output, again another signal assignment with and and or operators is used. Note that the use of parenthesis is necessary in the carry signal assignment.
Another property of signal assignment statements is their concurrency. This means that all statements are concurrent and their order of appearance is not significant.
Comparator Example
Consider the code shown in Figure 87.10, which corresponds to a 4-bit comparator. To define 4-bit arrays, a predefined array type in the std package called std_logic_vector which represents a collection of
std_logics, is used. Notice how the std_logic_vector is used in the definition of a port or a signal. (3 downto 0) is the range of indices for the vector (3 is the index of the leftmost element and 0 is for the rightmost element in the vector). Note that the range can also be declared as (0 to 3), but the former declaration is recommended since the indices correspond to bit position weights in an array.
First, the result of XORing bits of in1 and in2 are assigned to im, which is defined as a signal in the declaration part of the architecture. In the next line a function call is used to produce the eq output. A function is a subprogram consisting of sequential statements that can be called anywhere in a VHDL code. Functions can be declared in several places such as the declarative part of an architecture or a process. A function declaration starts with the function keyword and a function name followed by its parameters and finally a single return value type. In this case, our function has a 4-bit input of type std_logic_vector and a std_logic return type. This function performs bit-by-next-bit operation, giving a 1-bit result. The function is simply called in the architecture statement body with im as its input.
As shown in Figure 87.10, result is defined as a variable. Notice the use of := instead of <= in the assignment. There will be more on variables later in the chapter.
Another way to describe the comparator circuit is to use a conditional signal assignment. A conditional signal assignment is a signal assignment that takes place only when the condition stated after the when keyword is met. In the case of our comparator example, the below conditional signal assignment produces the correct eq value.
eq <= ‘1’ when in1 = in2 else ‘0’;
Note that it is possible to have another conditional part after the else keyword.
Multiplexer Example
The multiplexer example is another good example of the use of conditional signal assignments. Figure 87.11 illustrates a 2-to-1 multiplexer.
Decoder Example
Figure 87.12 shows a 2-to-4 decoder, coded using a selected signal assignment. The behavior of a selected signal assignment is similar to the case statement. A case statement can only appear in VHDL sequential bodies where, selected signal assignments are for the concurrent bodies of VHDL, e.g., an architecture body. A selected signal assignment statement is very similar to a conditional signal assignment in the way that it chooses from a number of expressions based on a condition, but they differ in that only conditions relating to one signal are used in a selected signal assignment.
Adder Example
As another example, consider a full adder circuit with a carry-in and a carry-out output shown in Figure 87.13. An assignment statement is used to set the two outputs to their values. The left-hand side of this assignment is an aggregate. Aggregate is a collection of values. In this example an aggregate is used to match the return 2-bit vector produced from adding a, b, and ci.
Description with Procedural Statements
As described earlier in the chapter, VHDL provides constructs such as different kinds of signal assignments, component instantiation, and processes to model concurrency. In addition to these constructs, VHDL also provides constructs for sequential description of hardware. This is referred to as the behavioral approach to describe hardware components. In this approach, the designer expresses the functionality or behavior of hardware instead of its structural details. Behavioral descriptions are supported with the process statements in VHDL.
A process statement runs concurrently with other concurrent components but its body consists of sequential statements. The process statement can appear in the architecture body just as signal assignments and, encloses in a begin-end pair. The sequential statements in a process statement run repeatedly during a simulation run. The process keyword starts the definition of a process statement. A list of signals enclosed in a pair of parenthesis can appear after the process keyword as its sensitivity list. Any event on any of these signals will cause the process to be executed again. If no sensitivity list is specified for a process statement, that process will run continuously until the end of the simulation time.
A process statement consists of a declarative part and a statement part. The statement part is where the sequential statements are listed while the declarative part consists of function, variable, and other decla- rations (signal declarations are not allowed in the declarative part of a process). Variables are used to store intermediate values within a process. Variable declaration is similar to signals and it takes place in the declarative part of a process. Assigning values to variables is done with :=. Initial values can also be assigned to variables in their declarations.
Although variables can be data carriers like signals but they differ from them in several ways. Signals do not change in a process execution and therefore cannot hold intermediate values within a process. This is where variables become handy. They can store intermediate values by a variable assignment. Declarations including variable declarations take place once at the beginning of a simulation run and a variable’s value is retained between process iterations. Another difference between signals and variables is that only signal assignments are timed and the after clause cannot be used with variable statements.
Another issue regarding signal assignments in concurrent bodies is the delta delay. A simulation cycle is referred to as delta delay in VHDL. Consider two signal assignments in an architecture body, one of which its output causes the evaluation of the right-hand side of the other signal assignment. Since these are concurrent statements one expects both of their results to be ready at the same time. On the other hand, the first signal assignment causes an event on the right-hand side of the second signal assignments. So it is obvious that there is a time delay between these two statements. This delay is what is referred to as delay time or delta delay, and is shown by the δ symbol.
Majority Example
Figure 87.14 shows a majority circuit described by the use of a process statement. This process statement is sensitive to a, b, and c signals. Any event on these signals will cause the process block to run again and a new value will be assigned to the y output. No delay has been considered for this signal assignment. Therefore, the value of y will be updated δ time after any event on a, b, or c.
Majority Example with Delay
The VHDL code corresponding to a majority circuit with delay is shown in Figure 87.15. The code is very similar to the code described in Figure 87.14 with an after clause with a 5 ns delay value. In this case the result of the right-hand side will be placed on y’s driver with the 5 ns delay value.
Procedural Multiplexer Example
Figure 87.16 illustrates another example of procedural blocks using an if statement. VHDL allows the use of if statements in process statements. An if statement is similar to the conditional signal assignment construct, with the difference that it is only allowed in sequential bodies. Depending on the condition specified for the if statement, a corresponding branch is taken. Note that each if statement contains a corresponding then branch. An if statement ends with the end if keyword. There can be any number of elsif branches to an if statement. In contrast, a maximum of one else statement is allowed per each if statement. This optional else statement should be the last branch in an if statement.
In this example, if the selector is equal to zero the block after the then keyword is executed and y takes i0, otherwise the block of statements after the else are taken and therefore y takes i1.
Procedural ALU Example
A case statement is similar to if statements, described in the previous example, in branching on a condition. However a case statement chooses a branch based on the value of the case expression, which does not need to be a Boolean. Case statements are preferred over if statements when many choices exist. This is why we have used the case statement in Figure 87.17. A case statement is somehow similar to selected signal assignment described earlier. As discussed before, selected signal assignments and conditional signal assignments cannot be used in process statement bodies.
This ALU receives a, b, and f as its inputs. The process statement, shown in the VHDL code, is sensitive to all its inputs. The case statement used here selects the correct operation corresponding to f from the case alternatives. Consider the when others case alternative used in the last line of the case statement. This branch is taken when the condition does not match any of the other alternatives. In our example inputs containing Z or X will take this branch.
Combinational Rules
Now that if and case statements are covered, consider a case where there are conditions under which the output of a combinational circuit is not assigned a value. Obviously the output retains its previous value, which implies the latching behavior. This latching behavior is unwanted in describing combinational circuits. Therefore two rules can be considered in describing combinational circuits with process statements.
1. List all inputs of the combinational circuit in the sensitivity list of the process statement describing it.
2. Make sure all combinational circuit outputs receive some value regardless of how the program flows in the conditions of if or case statements. If there are too many conditions to check, set all outputs to their inactive values at the beginning of the process statement.
Bussing
Bus structures can be implemented by the use of multiplexers or three-state logic. Various methods of describing combinational logic can be used for the description of a bus, in VHDL.
Figure 87.18 shows the VHDL code for a three-state bus with three sources, busin1, busin2, and busin3. These sources are put on busout by active high enabling control signals: en1, en2, and en3.
Three conditional signal assignments are used for assigning values to busout. Each conditional signal assignment either selects a bus driver or a 4-bit Z value for busout. As mentioned before, multiple assignments to a signal produce multiple drivers for that circuit. Therefore, multiple conditional signal assignments are appropriate for representing busses in VHDL. Note that only one enable should be active at a time. Multiple driving values for busout are resolved using the resolved resolution function. Enabled inputs of busout produce logic values on their drivers, while inactive ones put all Z values on their drivers. Resolving Z with logic values results in a valid logic value, but resolving multiple logic values results in unknown. This is why we use high impedance for inactive enables.
Comments
Post a Comment