68 Essential VHDL 7 Digital Engineering with VHDL IEEE Library Declarations Every VHDL file should begin with library declarations. Generally these will be the IEEE libraries that are becoming a standard for VHDL synthesis. It may also be necessary to include vendor specific libraries to access various vendor specific features. This text is about starting to learn how to design large digital systems. A large part of that activity is knowing how to use and apply electronic design automation tools including hardware description languages (HDLs) for design specification, simulation, and synthesis. This chapter describes the essential VHDL needed for this text. VHDL is used in this text for designing, simulating, and implementing digital systems at the gate and register transfer level (RTL) of specification, and hence we concentrate on the synthesis subset of the language. VHDL, because it is a concurrent programming language with support for describing circuit delays and structure, can also be used to create abstract high-level models of digital systems. These simulation models, and those aspects of the language, can be extremely complex and are beyond the scope of this text. VHDL is chosen because it is an IEEE standard and can be used to write abstract system-level models to gate level specifications for programming a simple field programmable device (FPD). Verilog would also be a good choice, but most low cost tools support VHDL and not Verilog. As to other specialized or vendor specific languages that just target FPDs, they are not really any simpler to learn, and are not sufficient for complex tasks. VHDL will be a language you can use throughout your engineering career whether you are programming a 16V8 PLD or modeling a flight control system. The following style guidelines should be sufficient to study the problems posed in this text. These are a minimal synthesis set and will work with almost all VHDL synthesis tools (with minor modifications). See your tools for additional supported constructs. This chapter provides general background. Additional language details and examples are provided in subsequent chapters. library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; Figure 7.1 Library Declarations The library declaration makes the library IEEE visible and the use declarations cause the packages std_logic_1164, std_logic_arith, and std_logic_unsigned to be used when referenced. Packages contain useful predefined language elements such as standard types and over-loaded arithmetic operators such as arithmetic addition (‘‘+’’) and subtraction (‘‘-’’) that can be used with logic valued types such as std_logic_vector. Types VHDL defines data representation types, and the scalar and array types include objects such as integer, real, and bit. For various reasons none of these are quite right for describing digital circuit values. Most synthesis tools, and simulation models, use the type std_logic from the IEEE library. The type std_logic is a resolved type that can model buses by allowing the representation of multiple tristate drivers driving a signal and is derived from a base type std_ulogic. Essential VHDL TYPE std_ulogic IS ( ’U’, ’X’, ’0’, ’1’, ’Z’, ’W’, ’L’, ’H’, ’-’ ); Figure 7.2 69 ---------- Uninitialized Forcing Unknown Forcing 0 Forcing 1 High Impedance Weak Unknown Weak 0 Weak 1 Don’t care 70 Digital Engineering with VHDL library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; VHDL Std_logic Values For modeling of digital systems the type std_logic with it range of signal values other than just ’0’ and ’1’can better represent the physical behavior of digital systems. For synthesis, where the function of a circuit is defined, as opposed to modeling the behavior of an existing system, only four of the nine possible values are needed. These include the fundamental boolean values ’1’ and ’0’, ’Z’ to represent the high-impedance state, and ’-’ to indicate a don’t care value. The ’-’ is the equivalent of a don’t care in a K-map. The other values such as a forcing unknown (’X’) would never be used in synthesis, though it might appear in simulation due to a design flaw from a driver conflict on a signal. In this text we will use the types std_logic and std_logic_vector to the near exclusion of all other types. Std_logic is a scaler (a one bit signal) and std_logic_vector is an array (or composite or aggregate) of one bit values. Std_logic_vectors are used to represent buses. Our std_logic_vectors will always have a descending range. That is (N downto 0). The least significant bit (LSB) 20 will be X(0) and the most significant value 2n (MSB) will be X(N). Constant std_logic values are represented by ’0’, ’1’, ’-’, and ’Z’, while std_logic_vectors are a string value of 1’s, 0’s, ’-’, and ’Z’ surrounded by double quotes, e.g. "00110010". entity example is port (A, B: in std_logic_vector(7 downto 0); C: out std_logic_vector(15 downto 0); MSB, LSB: out std_logic; ONE: out std_logic; TWO: out std_logic_vector(3 downto 0)); end example; architecture synthesis of example is begin C <= A & B; --Concatenate two 8-bit vectors -- into a 16-bit vector MSB <= A(7); --Slice off MSB LSM <= B(0); --Slice off LSB ONE <= ’1’; -- A constant ’1’ TWO <= "0010"; -- A constant decimal 2 end synthesis; Figure 7.3 Std_logic and Std_logic_vector Assignments Most synthesis tools will support synthesis of integers when the range is constrained by a subtype declaration. In other words, if we declare that an integer signal can only hold values in the range 0 and 15 the synthesis tool can map this onto a 4-bit binary vector (which can represent the decimal values 0 through 15). Using unconstrained integers will result in a mapping onto a 32-bit vector which will create an excessively large solution which will be difficult to simulate, difficult to synthesize, difficult to map to an actual device, and typically is not what is wanted. While using integer subtypes makes for more readable VHDL, it may require using conversion functions to convert between the integer subtype and the types std_logic and std_logic_vector. Essential VHDL 71 72 Digital Engineering with VHDL synthesis tool might encode the states as binary, gray, or one-hot, converting each string literal to a unique binary value. library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; entity ints is port (a, b: in integer range 0 to 15; sum: out integer range 0 to 15; sb: out std_logic); end ints; entity fsm is port ( control: out std_logic_vector(4 downto 0); reset, clk: in std_logic); end fsm; architecture synthesis of ints is architecture synthesis of fsm is --Define a subtype fourbits subtype nibble is integer range 0 to 15; --Define three state with an enumerated type type states is (start, run, halt); --Create a signal using the enumerated type signals state: states; --Declare a signal int_tmp of type nibble signal int_tmp: fourbits; signal bit_tmp: std_logic_vector(3 downto 0); begin --Add a and b and assign to an integer int_tmp <= a + b; --Convert integer to a std_logic_vector bit_tmp <= CONV_STD_LOGIC_VECTOR(int_tmp, 4); --Convert std_logic_vector to a integer sum <= CONV_INTEGER(bit_tmp); --Slice a bit and assign it to a std_logic sb <= bit_tmp(3); end synthesis; Figure 7.4 VHDL Integers It is also possible to use non-numeric types in synthesis. These enumerated types allow specifying integer values as string literals. They are very useful for describing states and distinct operations. Descriptive names such as START, STOP, RUN are easier to understand then binary or integer encodings such as "001", "010", and "100". Typically the synthesis tool will encode the enumerated types for conversion to a state machine depending on its settings. For example a begin process begin wait until clk=’1’; if reset = ’1’ then state <= start; control <= "0000"; else case state is when start => state <= run; control <= "0011"; when run => state <= halt; control <= "1100"; when halt => state <= halt; control <= "1100"; end case; end if; end process; end synthesis; Figure 7.5 VHDL Enumerated Types Essential VHDL 73 74 Digital Engineering with VHDL Entity Declarations DESIGN Every digital circuit has input and output ports. VHDL uses an ENTITY declaration to describe the circuit’s ports. You can think of the ENTITY declaration as a block in a block diagram. The ENTITY declares the names of the inputs and outputs, specifies their direction. and defines their type and width. entity DESIGN is port( A, B: in std_logic_vector(7 downto 0); DOUT: out std_logic_vector(7 downto 0); RESET: in std_logic; CLK: in std_logic); end DESIGN; Figure 7.6 VHDL Basic Entity Declaration Ports, the inputs and outputs of a circuit, have a mode that specifies their direction. Modes used in this text are IN, OUT, INOUT, and BUFFER. Ports of IN can only be read in the entity’s architecture. Trying to write, or assign a value to a port of mode IN will result in an error. In other words, ports of mode IN can only appear on the right hand side (RHS) of an assignment statement. Ports of mode OUT can only be written, attempting to read the value will result in an error. Ports of mode OUT can only appear on the left-hand side (LHS) of an assignment statement. A port of INOUT can be both read and written by the entity and is usually used for true bi-directional ports. INOUT ports can be driven by other modules and these external values can be read by the entity. BUFFER ports can be written, and read, but only the value written by the entity can be read. In other words a BUFFER is like an OUT tied to an IN. Ports of mode BUFFER can be used to avoid using an internal signal to store a value, allowing a port to be both a port and the output of a register or combinational logic. SIGNAL_NAME: MODE TYPE; Figure 7.7 B[7..0] RESET DOUT[7..0] CLK U1 Figure 7.8 entity ENTITY_NAME is port( SIGNAL_NAMES: DIRECTION_MODE TYPE ); end ENTITY_NAME; A[7..0] Example Entity Declaration Let’s try to put this all together. The example entity named DESIGN has two 8-bit input buses A and B, one output bus DOUT, and two more inputs RESET and CLK. All but purely combinational circuits will have a clock and reset. Most interesting circuits in this text will be synchronous sequential circuits and will have a reset and clock input. So to create most entities for this text simply change the name, the number of ports, their modes, and type of the ports in entity DESIGN to match the new design problem. Architecture Declarations While the entity declaration is used to describe the ports of the digital system, the architecture is used to describe the behavior and internal structure of the system. architecture ARCH_NAME of ENTITY_NAME is SIGNAL_DECLARATIONS; begin THE_HARD_STUFF; VHDL Basic Por t Declaration end ARCH_NAME; The basic port declaration has a SIGNAL_NAME that is the identifier or name of the port. The only thing to remember here is not to use a VHDL keyword (like "entity" or "IN" or "OUT") or start the identifier with a number. Popular signal_names might be AIN, Data_out, Clock, and reset. VHDL literals are not case sensitive. In other words AIN, ain, Ain, and aIn all refer to the same identifier. The MODE is either IN, OUT, INOUT, or BUFFER, and the type will typically be a std_logic scaler or a std_logic_vector. Figure 7.9 Basic Architecture Every architecture has a name (ARCH_NAME) and is associated with an entity (ENTITY_NAME). There is a declarative region between the architecture declaration and the BEGIN in which signals (circuit nodes) internal to the component are declared. While ports on entities are visible to other entities, internal signals are not. After the BEGIN is where the ‘‘hard stuff’’ is specified. Here is Essential VHDL 75 where the statements that describe the behavior and structure of the digital system are declared. The sample architecture shows some basic signal declarations. 76 Digital Engineering with VHDL components execute concurrently. In many ways ‘‘hardware design’’ is the design of concurrent system. While once the realm of the hardware designer, concurrent systems design is becoming more a part of software systems, ever more blurring the line between ‘‘hardware’’ and ‘‘software’’. Signals are used to connect concurrent operations. architecture synthesis of design is architecture synthesis of example begin X signal X, Y, Z: std_logic; signal tmp: std_logic_vector(7 downto 0); --These three statements exeucte simultaneously --whenever X, Y, A, or B change Y begin --The Hard Stuff Missing TMP Z end synthesis; Figure 7.10 Sample Architecture A <= X AND Y; B <= X OR Y; C <= A AND B; end synthesis; Figure 7.11 Describing Circuit Behavior At this point the ‘‘boiler-plate’’ needed for the basic use of VHDL for synthesis has been described. ‘‘Boiler-plate’’ is the standard stuff for all designs. (As in steel plate to build a boiler.) We now need to study how to define the behavior and structure of digital systems in a subset of VHDL. It is important to remember that VHDL is a large language, used for many different purposes and only a tiny subset of it is presented in this text. VHDL that might be acceptable to a full VHDL simulator may not synthesize, or may not produce the hardware implementation you expect. Unlike programming and compiling a program, different forms of the same specification will frequently result in quite different hardware implementations. Synthesis tools require more piloting than compilers to arrive at the desired circuit implementation, size, and performance. Concurrent Statements Unlike programming languages, some statements in a VHDL architecture execute concurrently, not in sequential order typical of most programming languages. This is necessary if we are to be able to describe digital hardware. In a digital circuit consisting of multiple components, all the components are active simultaneously, updating their outputs whenever an input changes. The hardware X A Y C B These three components execute simultaneously updating their outputs on any change on their inputs. Concurrent Statements Concurrent signal assignment statements are the simplest VHDL statements and are typically used to specify combinational logic. Operators available for our use include AND, OR, NOT, NAND, NOR, XOR, XNOR, + (binary addition), (binary subtraction), and & (concatenation). Basic concurrent signal assignments can be used to specify basic boolean functions, leaving it up to the synthesis tools to minimize and optimize the equation. A <= X + Y; B <= (M AND N) OR (O AND P); C <= X & Y; Figure 7.12 Legal Concurrent Assignment Statements VHDL is a strongly typed language. The types on the RHS and the LHS must be the same, and if vectors (arrays), must be of the same length. This makes sense and helps to avoid design errors. One should not be able to tie a 4-bit bus to an 8-bit bus unless one explicitly resolves the dangling 4 bits. Essential VHDL 77 signal X: std_logic_vector(3 downto 0); signal Y: std_logic_vector(7 downto 0); A <= X AND Y OR W AND Z; ----- begin Y <= "0000" & X; --Extending a 4 bit bus with zeros. Figure 7.13 Concatenating Vectors Combine two buses into one larger bus B(0) B(1) B(2) B(3) architecture synthesis of example is signal A, B, C: std_logic_vector(3 downto 0); signal X: std_logic_vector(7 downto 0); X(0) X(1) X(2) X(3) X(4) X(5) X(6) X(7) AND and OR have the same precedence. Parenthesis must be used to indicate the order of evaluation or an error will be reported. B <= NOT M AND N; --This is the same as ... B <= (NOT M) AND N; -- as the NOT has higher precedence than AND -- hence NOT M is evaluated before the AND term. Figure 7.15 VHDL Boolean Operator Precedence At this point with simple signal assignment statements we can write boolean equations in VHDL, and even arithmetic equations using the overloaded ‘‘+’’ and ‘‘-’’ operators, but we are still forced to derive the boolean equations manually. The advantage of VHDL comes from using complex VHDL concurrent signal assignment statements and letting the synthesis tool derive the implied boolean (logical) equations and their optimized implementation. begin X <= B & A; C <= X(7 downto 4); Concurrent Signal Assignment Statements end process; We will use two forms of concurrent signal assignment statements. The conditional signal assignment statement allows the expression of arbitrary if-then-elsifthen-else-end conditionals in concurrent signal assignment statements. This statement is the equivalent of an if statement within a VHDL process statement. (The process statement is discussed later.) Slice off a part of a bus C(0) C(1) C(2) C(3) Figure 7.14 Digital Engineering with VHDL A <= (X AND Y) OR (W AND Z); -- Typically what is wanted Most of the operators like AND, OR, and arithmetic addition ‘‘+’’ should be familiar to you. One that may not have an obvious function is the concatenation operator ‘‘&’’. Concatenation allows signals to be combined into larger composites (bigger arrays or buses). The opposite, slicing apart a bus, is implied by the language. A(0) A(1) A(2) A(3) 78 Concatenation and Slices An important issue in writing boolean equations in VHDL is the precedence of operators. This determines how the language associates operators. If two operators, such as AND and OR, have the same precedence, the association must be made clear by the use of parenthesis. NOT has a higher precedence than AND and OR so that it associates with the nearest literal without parenthesis. Of course using parenthesis even when not required won’t hurt, and will make the equation more readable and less prone to errors. Essential VHDL A <= B when X = ’1’ else C when Y = "00" else D; 79 --Process equivalent form process begin if X = ’1’ then A <= B; elsif Y = "00" then A <= C; else A <= D; end if; end process; Figure 7.16 X B C D 1 MUX 0 1 MUX A with X select A <= B when "00", C when "01", D when others; 0 Y NOR Conditional Signal Assignment Statement Figure 7.18 Digital Engineering with VHDL --Process equivalent form process begin case X is when "00" => A <= B; when "01" => A <= C; when others => A <= D; end case; end process; X B C D D 00 01 MUX A 10 11 Selected Signal Assignment Statement with STATIC_EXPRESSION select SIGNAL <= EXPRESSION when CHOICES, EXPRESSION when CHOICES, EXPRESSION when others;, SIGNAL <= EXPRESSION when CONDITIONAL else EXPRESSION when CONDITIONAL else EXPRESSION; Figure 7.17 80 General Conditional Signal Assignment Statement The general form of the conditional signal assignment consists of expressions to be assigned to the signal and arbitrary conditions which determine when each expression is assigned to the signal. This statement looks and acts like an arbitrary if-elsif-else statement, and it has a shortcoming with respect to hardware. An ifelsif-else statement implies a priority. If two conditions are true, the first in the list is executed. This results in more hardware to enforce the order of execution priority, unless the conditions are mutually exclusive in which case a CASE statement can be used. Another problem is that if the statement does not have a trailing else the hardware generated will have a latch generated. The reason is quite simple. Without an else the signal being assigned may not be assigned a value every time the if-elsif is executed. This implies that the signal must hold it previous value and hence a latch is needed in the digital circuit to faithfully replicate that behavior. Many synthesis tools enforce the else in conditional signal assignment statements, some do not. Either way, if you use a conditional signal assignment statement make sure to include the final else to ensure that combinational logic is generated. While the conditional signal assignment is like an if-elsif-else statement the selected signal assignment statement is equivalent to a case statement. Figure 7.19 General Selected Signal Assignment Statement The selected signal assignment statement typically tests a signal (in this case X) and assigns values to a target (in this case A) based on the possible values of X. The difference between the conditional statement (if-elsif-else) and the selected signal assignment is that the selected signal assignment statement enforces the mutual exclusion of the conditions (because the conditions are choices based on a single literal and the values it can hold), and all the possible values of the literal must be covered either explicitly or with the ‘‘others’’ clause. The true advantage of the conditional statement is it uses less hardware as no priority of conditions needs to be enforced. Both the conditional signal assignment statement and the selected signal assignment statement allows the direct expression of a boolean truth table in VHDL. Essential VHDL 81 A B C | Z --------0 0 0 | 0 0 0 1 | 1 0 1 0 | 0 0 1 1 | 0 1 0 0 | 1 1 0 1 | 1 1 1 0 | 0 1 1 1 | 1 with ABC select Z <= ’0’ ’1’ ’0’ ’0’ ’1’ ’1’ ’0’ ’1’ Figure 7.20 when when when when when when when when "000", "001", "010", "011", "100", "101", "110", others; Truth Tables in VHDL Conditionals in VHDL test the relationships between objects such as signals, ports, and constants. The usual operators are available including equality (=), inequality (/=), less than (<), less than equal (<=), greater than (>), and greater than or equal (>=). Comparisons can be between signals or between signals and literals (constants). The IEEE libraries allow the comparison of std_logic_vectors with integer literals and signals. signal X: std_logic_vector(7 downto 0); signal Y: std_logic_vector(7 downto 0); signal A: std_logic; signal B: std_logic; X = "00001000" --Is X equal to 8 X /= 255 --Is X not equal to 255 decimal X > Y --Is X greater than Y (X < 16) OR (X > 32) --Is X less than 16 or greater than 32 A = X(0) --Compare two bits 82 Digital Engineering with VHDL Complex Behavior At this point we can write an entity, create an architecture, and even describe combinational circuits in VHDL. But this does not allow us to describe more complex behaviors associated with sequential circuits, nor to take full advantage of the synthesis system’s ability to generate the digital circuit implementation from a complex VHDL description using familiar programming constructs. Within the body of an architecture the general form of concurrent statement is the process statement. The process statement is the general method for the expression of concurrency in VHDL. The process statement contains statements that execute in sequential order and in zero time. This allows specifying complex behaviors of components above the boolean equation level. Any concurrent signal assignment statement (as just described) can be expressed as process statement. Conditional and selected signal assignments statements are actually a shorthand for a corresponding process with an if-elsif-else or case statement within a process declaration. The process statement has the general form of a process declaration, a declarative region for variables local to the process, and then a statement declarative region. Of all the VHDL constructs we will use in this text, the process statement will be the most simplified. It will be used for describing all clocked circuits, and complex combinational circuits. It is also how concurrency is expressed in VHDL, with multiple processes within a single architecture expressing the concurrency of digital hardware. process --Variables are declared here in the process declarative region begin --Sequential statements are here in the statement declarative region (A AND B) = ’1’ --Compare a boolean equation to a constant end process; Figure 7.22 Figure 7.21 Conditional Expressions Process Declaration Essential VHDL 83 84 architecture count of synthesis is Digital Engineering with VHDL CLOCK signal A: std_logic_vector(3 downto 0); begin process begin wait until clk=’1’; if reset = ’0’ then A <= "0000"; else A <= A + 1; end if; end process; + A+1 Register A "1" RESET Figure 7.24 Synthesized Counter end synthesis; Figure 7.23 Simple Counter Process The above process reads exactly as one expects and the synthesis tool will create the expected circuit. This process waits until the clk goes from ’0’ to ’1’ then executes the sequential statements. Notice that the process has only one wait statement and it is the first statement. Do not try to use more wait statements or use them elsewhere in the process with an RTL level synthesis tool. (Behavioral synthesis tools can support multiple wait statements.) The VHDL (or circuit) tests the value of reset, and if it is ’0’, A is cleared, else A is incremented by 1. The following circuit shows one possible implementation. An important point is to notice what has happened to the signal A. It has become a register. This makes sense in terms of the semantics of VHDL and those of a clocked circuit. Signals hold their values, and so do registers. So while a signal is a node in the circuit, in this case the synthesis system places a register driving the node A. Hence the signal A and the register that holds the value of A are one in the same. The synthesis tool inferred a register from the VHDL syntax and semantics. Not all signals become the output of registers. If A was simply assigned a value of a combinational equation, and there was no ‘‘wait until clk=’1’’’ statement, it would be that function and appear to be the output of the corresponding gates. The synthesis tool inferred a register from the VHDL syntax and semantics. Essential VHDL 85 Synthesis infers a flip-flop from the wait statement. LHS is the output Q LHS is the output Q process begin wait until clk = ’1’; Q <= not Q and not RESET; RESET D Q Q CLK end process; 86 Digital Engineering with VHDL use a different style for a clocked process. The asynchronous reset puts the reset condition first in the if-elsif statement giving it priority over the clock, just as in a asynchronous clear flip-flop. process(clk,reset) --Don’t use variables begin if reset=’0’ then -- Initial conditions for registers RHS of the signal assignment statement is the D input, elsif (clk’event and clk=’1’) then process begin C <= not X and not Y; B <= C and Z; end process; X Y C B Z -- Behavior of the circuit when not in reset. end if; end process; Figure 7.27 Asynchronous Reset Without a wait statement combinational logic is generated Inferring Flip-flops Figure 7.25 process begin wait until clk=’1’; if reset = ’0’ then -- Reset either active high or low (’1’ or ’0’) -- Initial conditions for registers else -- Behavior of the circuit when not in reset. end if; end process; Figure 7.26 Generic Clocked Process The use of an explicit wait statement implies an synchronous reset. This is frequently not a problem as many small FPDs don’t support asynchronous resets (their flip-flops simply don’t have that capability). To specify an asynchronous reset and make use of the global asynchronous resets available in FPGAs one must At this point you might notice that synthesis tools depend on "style" to infer much of the function of the circuit. The condition (clk’event and clk=’1’) is a sample of full VHDL. The clause clk’event is true when clk has just changed value (’0’ to ’1’ or ’1’ to ’0’) and clk=’1’ tests for clk being one. Together these two statements test if clk has just changed from ’0’ to ’1’. For the synthesis tool (clk’event and clk=’1’) is effectively just style keywords that directs it to implement the design using positive edge-triggerd flip-flops. The form (clk’event and clk=’1’) does simulate correctly (before synthesis in a VHDL simulator) and so is used for synthesis. As with the wait until clk=’1’; the (clk’event and clk=’1’) can only appear once as the elsif condition. No ‘‘else’’ part is allowed. Negative edge-triggered flip-flops can be indicated with wait until clk=’0’; or (clk’event and clk=’0’). Style is very important to VHDL synthesis. Arbitrary VHDL may produce an error or worse synthesize to an unexpected and unwanted circuit. On the other hand, particular style guidelines may be needed by a particular tool to take advantage of a particular tool’s capability or technology. On the other hand if you are familiar with programming then feel free to experiment. For example a slight modification of the VHDL for a asynchronous reset allows it to be used for a synchronous reset simply by making the (clk’event and clk=’1’) the if conditional for an if-then-end statement. Essential VHDL 87 process(clk,A) begin if (clk’event and clk=’1’) then if reset = ’1’ then A <= "0000"; else A <= A + 1; end if; end if; end process; Figure 7.28 88 Digital Engineering with VHDL process begin wait until clk = ’1’ Alternative Synchronous Reset if reset = ’0’ then X <= "0000"; else if A = "00" then X <= X + 1; else X <= X; end if; end if; end process; Sequential Statements Figure 7.30 VHDL has the full range of sequential statements found in any programming language including IF, CASE, and various forms of LOOP. We will not use the LOOP constructs much (though they can be synthesized if the loop values are constants). Loops in VHDL are typically used for describing combinational logic and implied structure. VHDL also has GENERATE statements for the conditional generation of structural descriptions. Advanced synthesis tools can convert general for loops into sequential machines by inferring and creating the state machine to implement the loop counter and control logic. if conditional then --sequential statements elsif conditional then --sequential statements else --sequential statements end if; Figure 7.29 Use if statements freely in clocked process. You can also nest them as necessary. You get what you expected. A register to hold X that is only incremented by one when A = "00". But things go awry if the if conditional does not cover all cases and the circuit is not clocked. process(A,X) begin if A = "00" then X <= X + 1; elsif A = "01" then X <= X + 2; end if; end process; Figure 7.31 If Conditional If Conditional in a Process Improper IF What happens with an ‘‘improper if’’ that does not cover all cases is that when A is not equal to "00" or "01" no value is assigned to X. Since the value of X is not defined for all values of A it must hold its value for values of A other than "00" and "01". Hence while this process does not have a clock it still implies a register and the synthesis tool builds a latch controlled by the value of A (and not the clock). It will latch X on A = "00" or A = "01". While expecting a combinational equation, one ends up with an unclocked transparent latch controlled by combinational logic, and very unpredictable behavior. Essential VHDL 89 process(A,X) begin if A = "00" then X <= X + 1; elsif A = "01" then X <= X + 2; else X <= X + 4; end if; end process; Figure 7.32 case X is when "00" when "01" when "10" when others end case; Figure 7.34 Proper IF Covers Every Case The above unclocked ‘‘proper if’’ process will generate a purely combinational circuit. Notice the "else" condition. X is assigned a value for any possible execution of this process. The following process achieves the same result, in a much more round about way, by creating a variable, assigning a value to it outside of the if, changing the value if the if statement executes, and then finally assigning it to the target signal X. process variable tmp: std_logic_vector(1 downto 0); begin tmp := X + 4; --tmp gets unconditionally assigned if A = "00" then tmp := X + 1; elsif A = "01" then tmp := X + 2; end if; X <= tmp; end process; Figure 7.33 90 Proper IF with Variables In general, IF statements should be used with care when specifying combinational logic. First they add logic for enforcing the implied priority of an IF statement in addition to the possibility of unintended latches. Instead use a CASE statement when possible. It will enforce that every input is covered ensuring a combinational circuit in unclocked processes. Digital Engineering with VHDL => => => => Z Z Z Z <= <= <= <= "001"; "111"; "011"; "101"; Case Statement The above case statement simply implements a truth table of input variables X(1) and X(0) and outputs Z(2), Z(1), Z(0). The use of the others condition is required for std_logic_vectors. While the case will typically explicitly cover all the combinations of ’1’s and ’0’s, std_logic defines another seven values (’Z’, ’-’, ’X’, ’U’, ’L’, ’H’, ’W’). These other choices are covered by the others. Essential VHDL 91 case Q is when "00" => Z when "01" => Z when "10" => Z when "11" => Z when others => end case; if sel=’1’ then A <= X; else A <= Y; end if; SEL X Y process(d0, d1, d2, d3, d4, d5, d6, d7) variable tmp: std_logic_vector(2 downto 0); variable ins: std_logic_vector(7 downto 0); ’1’ ’0’ ’1’ ’1’ A 0 00 begin Z 01 10 tmp := "000"; ins := d0 & d1 & d2 & d3 & d4 & d5 & d6 & d7; 11 for I in 0 to 7 loop tmp := tmp + ins(I); end loop; if SIG = "11"then D <= X1; end if; if M = ’1’ then B <= TMP1; elsif N = ’0’ then B <= TMP2; else B <= TMP3; end if; cnt <= tmp; X1 D Q D end process; N SIG(1) M TMP2 TMP3 Figure 7.35 CP --Alternative equivalent concurrent statement cnt <= ("000" & d0) + ("000" & d1) + ("000" & d2) + ("000" & d3) + ("000" & d4) + ("000" & d5) + ("000" & d6) + ("000" & d7); SIG(0) 0 0 1 Digital Engineering with VHDL expresses the general form of the algorithm and automates the generation of the equation. The synthesis tool effectively ‘‘unrolls’’ the for loop, generating the final value of tmp. <= ’1’; <= ’0’; <= ’1’; <= ’1’; null; Q 1 92 TMP1 Figure 7.36 B 1 Example Circuit Translations While we won’t make much use of loop statements a couple examples are worth considering. An interesting problem is to express the function that counts the number of one’s in an input array. Assuming an 8-bit input, if the pattern is "00100010" then the output should be 2. If the input pattern is "11110000" then the output is 4. Such a function is readily described with a truth table, but is cumbersome to generate manually. Instead a FOR LOOP can be used to sum the bits. The for loop simply calculates the sum of the inputs as tmp := ins(0) + ins(1) + ins(2) + ins(3) + ins(4) + ins(5) + ins(6) + ins(7);. The advantage of the FOR LOOP is that it Count One’s Process Another example is a simple parity checker of 2-input XOR gates. Here the loop is again unrolled to generate the final value of the variable result and the signal parity_out. Essential VHDL 93 94 Digital Engineering with VHDL ’0’ process(input) variable result : bit; begin INPUT(0) result := ’0’; INPUT(1) for k in 0 to 3 loop result:= result xor input(k); end loop; INPUT(2) PARITY_OUT parity_out <= result; INPUT(3) end process; Figure 7.37 For Loop Generated Form For Loop Parity Checker INPUT(0) INPUT(1) PARITY_OUT INPUT(2) INPUT(3) Simplified Form Figure 7.38 Parity Checker Circuit Structural Design In this course our VHDL designs are generally small enough that the entire design is readily described by a single entity/architecture pair with at most several processes. But as in schematic capture or programming there comes a point when breaking the design into separate modules makes the problem easier to solve and to understand. It also supports repeated reuse of a module. Divide and conquer. VHDL supports the structural design of digital systems with several language constructs. First there are packages that can contain functions and procedures. The package is intended to hold types, functions, and procedures common to a design. But these simply allow organizing the language, and do not directly allow Essential VHDL 95 expressing the structure of the digital system under design. The basic structural statement is the component instantiation statement that names the instance, declares which entity is being instantiated, and associates signals and ports with the ports on the entity. CLOCK --Required for VHDL 1987 component reg port( DIN: in std_logic_vector(7 downto 0); DOUT: out std_logic_vector(7 downto 0); RESET: in std_logic; CLK: in std_logic); end component; ADDER A REGISTER SUM BIN B entity example of port ( AIN, BIN: in std_logic_vector(7 downto 0); DREG: out std_logic_vector(7 downto 0); CLOCK: in std_logic; RESET: in std_logic); end example; --Required for VHDL 1987 component adder port(A, B: in std_logic_vector(7 downto 0); S: out std_logic_vector(7 downto 0)); end component; DREG RESET AIN Digital Engineering with VHDL architecture structural of example is EXAMPLE AIN BIN 96 TMP DIN CLK DOUT DREG RESET signal TMP: std_logic_vector(7 downto 0); begin CLOCK --VHDL 1987 Instantiation U0: adder port map (AIN, BIN, TMP); U1: reg port map (TMP, DOUT, RESET, CLOCK); RESET Figure 7.39 Structural Design Assuming an adder and a register entity are available they can combined by creating a new entity/architecture pair that specifies how they are to be connected or wired together to build an incrementer. --VHDL 1993 Direct Instantiation U0: entity work.adder(synth) port map (AIN, BIN, TMP); U1: entity work.reg(synth) port map (TMP, DREG, RESET, CLOCK); end structural; Figure 7.40 Structural Design A bit of bother is the component declaration (VHDL-93 does not require this as it supports direct instantiation) that is required in the architecture (or a supporting package) that specifies the ports on the instantiated entity (notice that the component declaration contains the same information as the entity declaration.) Essential VHDL 97 Basic Circuit and VHDL Semantics At this point you have been introduced informally to the syntax of VHDL. This section attempts to informally present the behavior, or semantics, implied by VHDL. Together these informal introductions should allows you to write simple VHDL descriptions of digital circuits that will produce the intended synthesized circuit behavior. The entity declaration as mentioned before simply names and describes the mode (in, out, inout, buffer) and type (std_logic, std_logic_vector) of the ports of the circuit. It does not impact the behavior of the circuit directly. The architecture is where the behavior is described. The biggest obstacle to writing synthesizable VHDL is that in VHDL same behavior can be described in multiple ways. Complicating the matter even more is that different, functionally equivalent, VHDL descriptions when given to a synthesis tool can produce different implementations that can differ in size and performance. Digital systems are concurrent systems. In other words a system’s components are all simultaneously active. VHDL is a concurrent programming language and concurrency is expressed by the use of multiple processes. In other words, processes correspond to the simultaneously active components in a digital circuit. These processes can have arbitrarily complex behaviors. Single threaded behaviors are described by a series of sequential steps. Hence while processes all execute concurrently the statements within a process execute in order, but in zero time. 98 Digital Engineering with VHDL entity simple is port(A,B,CLK: in std_logic; X: out std_logic); end simple; architecture synthesis of simple is signal TMP: std_logic; begin process(A, B) begin TMP <= A OR B; end process; A TMP B X D CLK Q process begin wait until clk=’1’; X <= TMP; end process; end architecture; Figure 7.41 Concurrency When writing VHDL the concurrent operations of the digital system are described using processes, concurrent signal assignments, and component instantiation statements within an architecture body. Processes allow the description of complex behaviors using sequential statements. Concurrent signal assignments are a shorthand for simple behaviors. And component instantiation statements allow describing systems in terms of the interconnection of entities (which consist themselves of processes, concurrent signal assignment statements, and component instantiation statements). Any digital system that can be described in VHDL can be described as a collection of processes. Structural VHDL is simply a way of organizing the design such that processes reside in separate architectures. But the design could be collapsed into a single architecture containing all the processes and signal to interconnect them. All concurrent signal assignment statements have an equivalent process form. Processes, concurrent signal assignments, and component instantiation statements communicate via signals within an architecture. Signals are the wires in VHDL that connect together the digital components described by VHDL processes, concurrent signal assignments, and component instantiation. Ports are also signals, and allow entities to communicate when they are attached to signals when instantiated within another architecture. Essential VHDL 99 When describing systems for synthesis, circuit delays are determined by the target technology, and hence when writing VHDL for synthesis signal assignment statements never include a delay assignment. But all digital circuit elements have a delay, even if it is infinitesimally short. This 0ns delay (delta delay) has little impact on writing VHDL for synthesis but most be included so that all circuits will be physically realizable. Physical circuits always have have finite delays. Zero delay circuits, and circuit designs that depend on zero delay components could never be built. A finite non-zero delay corresponds to a unit delay. The only time this non-zero signal assignment of RHS values to LHS values is noticeable is in processes where statements are evaluated sequentially. In this case multiple assignments always read the old value of a signal, never the new value. This has little consequence in combinational processes as the values will take on the new value in two delta delays and the circuit will behave as if the assignment to the signal occurred in zero time. In other words the combinational logic generated will be correct. A Always at least one delta delay B A Q D Q Y C X B X D Y CLK C process(A,B,C) begin X <= A AND B; Y <= X AND C; end process; process wait until clk = ’1’; X <= A AND B; Y <= X AND C; end process; Implied wait Figure 7.42 Signal Assignment Delays For clocked processes the result is quite different. In combination with the non-zero delay and the inference of flip-flops it becomes clear the Y is working with the old value of X. (The previously stored value of X). One way to understand this is that X does not take on a new value until a delta delay after the clock 0 to 1 transition and is to late to be assigned to Y. This behavior is identical to the behavior of flip-flops. Not matter the technology the output of the flip-flop does not change until after the clock edge and the output of a flip-flop is delayed by a full clock cycle when driving the input of another flip-flop. 100 Digital Engineering with VHDL The semantics of signals in VHDL is described by the simulation semantics of the language. Signals only take on their new values when the process has suspended during simulation. A process suspends when it reaches a wait statement. Either the explicit wait such as ‘‘wait until clk=’1’’’ or an implicit wait defined by a sensitivity list ‘‘process(A,B,CLK)’’. The sensitivity list implies a wait statement as the last statement in a process as ‘‘wait on A,B,CLK’’. This notion of a process waiting on signals works for both simulation and as a good model of how digital circuits operate. The concurrent components of a digital system wait for an change on an input, and then update their outputs. VHDL also support variables within processes. These do take on new values immediately. Typically variables are used to generate intermediate or temporary values within process. Variables should be used carefully as unless unconditionally assigned will generate a register to hold the value between invocations of the process. This can cause the variable to behave like a signal, defeating its use, and creating unintended registers. Essential VHDL 101 102 Digital Engineering with VHDL Common Mistakes 1) Getting fancy. Keep your VHDL simple. If you are lost draw a block diagram and then write the VHDL for each block as a process in an entity/architecture pair connecting the processes with signals. 2) Being too simple. Remember digital systems are concurrent systems. Use multiple processes and concurrent signal assignment statements to break up the behavior of your circuit. A typical use of multiple processes and current statements is to separate sequential blocks from combinational blocks. 3) Forgetting your boolean algebra - A NAND B NAND C is not equal to NOT (A AND B AND C). 4) Precedence - VHDL does not assign precedence to the AND and OR operators. Hence given the equation A AND B OR C AND D you will get a compiler error. Parenthesis must be supplied. You will likely want (A AND B) OR (C AND D). 5) Duplicate assignments - In this course we can only have one concurrent signal assignment to a signal or port. If two drivers assign a common node in a circuit an error will occur both in the VHDL simulation and in the actual circuit. This is a very common error. Outputs cannot be connected directly together. This does not work in VHDL or in digital logic at the RTL level. You must use a multiplexer or a tri-state bus controlled by a conditional to enforce mutual exclusion on the shared signal. A signal can be assigned repeatedly in a single process, but not in multiple processes. -- Multiple Concurrent Signal Assignments architecture syn of conflict is begin Adder drives a value on A A <= X + Y; A <= X - Y; Subtracter drives a value on A end synthesis; Adder drives a value on A X Y -- Multiple Concurrent Process Signal Assignments architecture syn of conflict is begin process(X, Y) begin A <= X + Y; end process; process(X, Y) begin A <= X - Y; end process; + Value of A is unknown Adder drives a value on A Subtracter drives a value on A end synthesis; A X Y - Subtracter drives a value on A Figure 7.43 Signal Assignment Conflict Essential VHDL 103 Multiplexer and control signal enforces mutual exclusion so only adder or subtracter drives signal A Adder drives a value on A Y Digital Engineering with VHDL Don’t assume the synthesis tool will make obvious optimizations. If you want a particular implementation you must be explicit. Either in behavioral VHDL or by using a structural implementation. Tri-state drivers and control signal enforces mutual exclusion so only adder or subtracter drives signal A CON CON X 104 X + A Y TMP <= Y when SEL = ’1’ else Z; A <= X + TMP; if SEL = ’1’ then A <= X + Y; else A <= X + Z; end if; Adder drives a value on A + A X Y X - Subtracter drives a value on A Multiplex values onto A Y SEL X - + Subtracter drives a value on A Y 0 TMP 0 A Create two tri-state drivers to mutiplex values onto A Z X A <= A+B when CON=’1’ else A-B; 1 1 + A X A <= X+Y when CON=’1’ else "ZZZZ"; A <= X-Y when CON=’0’ else "ZZZZZ"; Figure 7.44 Y + Multiplexer and Tri-State Buses Z 6) Unintended latches and flip-flops - A common problem is the creation (or insertion) of latches and flip-flops. Combinational latches typically arise when signals are not assigned values for all possible execution paths of a process or concurrent signal assignment statement. To avoid a latch and make sure that every signal is assigned a value under all execution paths, use a case statement or selected signal assignment statement, use an else part for if statements, or assign the signal a value unconditionally before any conditional assignment. Unintended flip-flops can also arise in clocked processes. All signals and variables appearing on the LHS of an assignment statement in a clocked process will be assigned to a flip-flop unless the signal or variable is unconditionally assigned a value. 7) Unintended hardware - In the following example equivalent behaviors result in quite different implementations. Both cause A to be assigned either the value X+Y or X+Z but the first uses two adders while the second uses one adder. SEL Figure 7.45 Unintended Hardware Essential VHDL 105 Basic Rules 106 Digital Engineering with VHDL • The use of variables does not ensure the generation of combinational logic. The same rules as for signals must be observed. • Always include the library and use declarations. • Use the std_logic and std_logic_vector types. No need to get fancy with entity declarations. • Adhere to the style guidelines. • Use the architecture declarative region to declare signals. • Use case statements instead of if statements. • Simple combinational circuits should use concurrent statements. • Signals in unclocked processes must be assigned a value for every possible execution sequence of the process to avoid unintended latches. • Use case statements for combinational logic. • If statements when used for combinational logic must include an else part to ensure all signals are assigned a value under all possible execution sequences of the if conditional. • Use a process for clock circuits. • Use ‘‘Wait until clk =’1’;’’ for a synchronous reset. • ‘‘Wait until clk =’1’;’’ must be the first statement in a process and can only appear once. • Use (clk’event and clk=’1’) for asynchronous resets. • ‘‘(clk’event and clk=’1’)’’ must either be the only conditional of an if-then-end statement, or must be the elsif conditional of a if-then-elsif-then-end statement. • Understand the capabilities of your target technology and don’t ask through your VHDL synthesis system do more than it can. Remember you are describing hardware that consists of basic gates, registers, adders, and counters.