CHAPTER   3

BEHAVIORAL DESCRIPTION

Chapter Objectives

 

3.1  Behavioral Description Highlights

 

In Chapter 2, data-flow simulations were implemented to describe digital systems with known digital structures such as adders, multiplexers, and latches. The behavioral description is a powerful tool to describe systems for which digital logic structures are not known or are hard to generate. Examples of such systems are complex arithmetic units, computer control units, and biological mechanisms that describe the physiological action of certain organs such as the kidney or heart.

Facts

3.2  Structure of the HDL Behavioral Description

 

Listing 3.1 shows a simple example of HDL code describing a system (half_add) using behavioral description. Usually sequential statements such as IF or Case are used to describe the change of the output; however, in this section, Boolean functions are used to describe the change. This is done here to explain how the HDL executes signal-assignment statements written inside process (VHDL) or inside always or initial (Verilog). The code in Listing 3.1 mainly consists of signal-assignment statements.

Referring to the VHDL code, the entity half_add has two input ports, I1 and I2, and two output ports, O1 and O2. The ports are of type bit; this type is recognized by the VHDL package without the need to attach a library. If the type is std_logic, for example, the IEEE library must be attached. The name of the architecture is behave_ex; it is bound to the entity half_add by the predefined word of. Process is the VHDL behavioral-description keyword. Every VHDL behavioral description has to include a process. The statement process (I1, I2) is a concurrent statement, so its execution is determined by the occurrence of an event. I1 and I2 constitute a sensitivity list of the process. The process is executed (activated) only if an event occurs on any element of the sensitivity list; otherwise, the process remains inactive. If the process has no sensitivity list, the process is executed continuously. The process in Listing 3.1 includes two signal-assignment statements: statement 1 and statement 2.

All statements inside the body of a process are executed sequentially. Recall from Section 2.2 that the execution of a signal-assignment statement has two phases: calculation and assignment. The sequential execution here means sequential calculation, which means the calculation of a statement will not wait until the preceding statement is assigned; it will only wait until the calculation is done. To illustrate this sequential execution, refer to Figure 3.1. Assume that in Listing 3.1, at T = T0, I1 changes from 0 to 1, while I2 stays at 1. This change constitutes an event on I1, which in turn activates the process. Statement 1 is calculated as O1 = (I1 XOR I2) = (1 XOR 0) = 1. Then, the value of O2 is calculated, still at T0, as (I1 and I2)= (1 and 0)= 0. After calculation, the value of 1 is assigned to O1 after the delay of 10 ns at T0 +10 ns; the value of 0 is assigned to O2 after the delay of 10ns at T0 + 10ns. For the above example, both data-flow and behavioral descriptions yield the same output for the two signal-assignment statements. This is not the case when a signal appears on both the right-hand side of the statement and the left-hand side of another statement, which will be seen later.

image

Figure 3.1  Execution of signal-assignment statements inside process (VHDL) or inside always (Verilog).

Referring to the Verilog code in Listing 3.1, always is the Verilog behavioral statement. In contrast to VHDL, all Verilog statements inside always are treated as concurrent, the same as in the data-flow description (see Section 2.2). Also, here any signal that is declared as an output or appears at the left-hand side of a signal-assignment statement should be declared as a register (reg) if it appears inside always. In Listing 3.1, O1 and O2 are declared outputs, so they should also be declared as reg.

LISTING 3.1  Example of an HDL Behavioral Description

VHDL Description

entity half_add is

port (I1, I2 : in bit; O1, O2 : out bit);

-- Since we are using type bit, no need for attaching a

-- Library.

-- If we use std_logic, we should attach the IEEE

-- Library.

 

end half_add;

architecture behave_ex of half_add is

begin

process (I1, I2)

    begin

        O1 <= I1 xor I2 after 10 ns; -- statement 1

        O2 <= I1 and I2 after 10 ns; -- statement 2

-- The above two statements are signal-assignment

-- statements with 10 nanoseconds delays.

--

--Other behavioral (sequential) statements can be added

-- here

     end process;

end behave_ex;

 

Verilog Description

module half_add (I1, I2, O1, O2);

input I1, I2;

output O1, O2;

reg O1, O2;

/* Since O1 and O2 are outputs and they are

   written inside “always,” they should be

   declared as reg */

 

always @(I1, I2)

   begin

        #10 O1 = I1 ^ I2; // statement 1.

        #10 O2 = I1 & I2; // statement 2.

/*The above two statements are

signal-assignment statements with 10 simulation screen units delay*/

/*Other behavioral (sequential) statements can be added here*/

   end

endmodule

3.3  The VHDL Variable-Assignment Statement

 

The use of variables inside processes is a common practice in VHDL behavioral description. Consider the following two signal-assignment statements inside a process, where S1, S2, and t1 are signals:

Signl : process(t1)

begin

st1 : S1 <= t1;

st2 : S2 <= not S1;

end process;

In VHDL, a statement can be labeled, and the label should be followed by a colon. In the above code, Signl, st1, and st2 are labels. VHDL code in this example does not use these labels for compilation or simulation; they are optional. Labels are used here to refer to a certain statement by its label. For example, to explain the statement S1 <= t1, it can be referred to by statement st1.

In the above code, signal S1 appears on both the left-hand side of statement st1 and on the right-hand side of statement st2. Assume at simulation time T0, t1 = 0 and S1 = 0, and at simulation time T1, t1 changes from 0 to 1 (see Figure 3.2). This change constitutes an event, and the process labeled Signl is activated. For statement st1, S1 is calculated as 1. S1 does not acquire this new value of 1 at T1, but rather at T1 + D. For statement st2, S2 at T1 is calculated using the old value of S1 (0). Alternately, variable-assignment statements can be used instead of the above signal- assignment statement as follows:

Varb : process(t1)

variable temp1, temp2 : bit; -- This is a variable

                             -- declaration statement

begin

  st3 : temp1 := t1; -- This is a variable assignment

                     -- statement

st4 : temp2 := not temp1; -- This is a variable

                          -- assignment statement

st5 : S1 <= temp1;

st6 : S2 <= temp2;

end process;

image

Figure 3.2  Signal versus variable in VHDL.

Variable-assignment statements, as in C language, are calculated and assigned immediately with no delay time between calculation and assignment. The assignment operator is :=. If t1 acquires a new value of 1 at T1, then momentarily temp1 = 1 and temp2 = 0. For statements st5 and st6, S1 acquires the value of temp1 (1) at T1 + D, and S2 acquires the value of temp2 (0) at T1 + D. Because D is infinitesimally small, S1 and S2 appear on the simulation screen as if they acquire their new values at T1.

3.4  Sequential Statements

 

There are several statements associated with behavioral descriptions. These statements have to appear inside process in VHDL or inside always or initial in Verilog. The following sections discuss some of these statements.

3.4.1  IF Statement

IF is a sequential statement that appears inside process in VHDL or inside always or initial in Verilog. It has several formats, some of which are as follows:

VHDL IF-Else Formats

if (Boolean Expression) then

statement 1;

statement 2;

statement 3;

.......

   else

statement a;

statement b;

statement c;

.......

end if;

 

Verilog IF-Else Formats

if (Boolean Expression)

begin

   statement 1; /* if only one statement, begin and end

                   can be omitted */

   statement 2;

   statement 3;

.......

end

   else

begin

   statement a; /* if only one statement, begin and end

                   can be omitted */

   statement b;

   statement c;

.......

end

The execution of IF statement is controlled by the Boolean expression. If the Boolean expression is true, then statements 1, 2, and 3 are executed. If the expression is false, statements a, b, and c are executed.

 EXAMPLE 3.1   BOOLEAN EXPRESSION AND EXECUTION OF IF

VHDL

if (clk = ‘1’) then

temp := s1;

else

temp := s2;

end if;

 

Verilog

if (clk == 1’b1)

// 1’b1 means 1-bit binary number of value 1.

temp = s1;

else

temp = s2;

In Example 3.1, if clk is high (1), the value of s1 is assigned to the variable temp. Otherwise, s2 is assigned to the variable temp. The else statement can be eliminated, and in this case, the IF statement simulates a latch, as shown in Example 3.2.

 EXAMPLE 3.2    EXECUTION OF IF AS A LATCH

VHDL

 

if clk = ‘1’ then

    temp := s1;

end if;

 

Verilog

 

if (clk == 1)

begin

   temp = s1;

end

If clk is high, the value of s1 is assigned to temp. If clk is not high, temp retains its current value, thus simulating a latch. Another format for the IF statement is Else-IF.

 EXAMPLE 3.3   EXECUTION OF IF AS ELSE-IF

VHDL

 

if (Boolean Expression1) then

statement1; statement2;...

elsif (Boolean expression2) then

statement i; statement ii;...

else

statement a; statement b;...

end if;

 

Verilog

if (Boolean Expression1)

begin

   statement1; statement 2;.....

end

else if (Boolean expression2)

begin

   statementi; statementii;.....

end

else

begin

   statementa; statement b;....

   end

 EXAMPLE 3.4   IMPLEMENTING ELSE-IF

VHDL

 

if signal1 =‘1’ then

temp := s1;      

elsif signal2 = ‘1’ then

temp := s2;

else

temp := s3;

end if;

 

Verilog

if (signal1 == 1’b1)

temp = s1;

else if (signal2 == 1’b1)

temp = s2;

else

temp = s3;

After execution of the above IF statement, temp acquires the values shown in Table 3.1.

Table 3.1  Output Signals (temp) for Else-IF Statements in Example 3.4

image

The Boolean expression may specify other relational operations such as inequality or greater than or less than (see Chapter 1 for details on relational operators).

To illustrate the difference between signal- and variable-assignment statements in VHDL code, the behavioral description of a D-latch is written in Example 3.5. A process is written based on signal-assignment statements, and another process is written based on variable-assignment statements. A comparison of the simulation waveforms of the two processes will highlight the differences between the two assignment statements.

 EXAMPLE 3.5    BEHAVIORAL DESCRIPTION OF A LATCH USING VARIABLE AND SIGNAL ASSIGNMENTS

The functionality of a D-latch can be explained as follows: if the enable (E) is active, the output of the latch (Q) follows the input (d); otherwise, the outputs remain unchanged. Also, Qb, the invert output, is always the invert of Q. Figure 3.3a shows the logic symbol of a D-latch. A flowchart that illustrates this functionality is shown in Figure 3.3b. Listing 3.2 shows the VHDL code of the D-latch using variable-assignment statements.

image

Figure 3.3   D-Latch. a) Logic symbol. b) Flowchart.

LISTING 3.2  VHDL Code for Behavioral Description of D-Latch Using Variable-Assignment Statements

entity DLTCH_var is

     port (d, E : in bit; Q, Qb : out bit);

-- Since we are using type bit, no need for attaching a

-- Library. If std_logic is used, IEEE library should be

--attached

end DLTCH_var;

architecture DLCH_VAR of DLTCH_var is

begin

VAR : process (d, E)

variable temp1, temp2 : bit;

begin

    if E = ‘1’ then

    temp1 := d; -- This is a variable assignment statement.

    temp2 := not temp1; -- This is a variable assignment

                        -- statement.

end if;

Qb <= temp2; -- Value of temp2 is passed to Qb

Q <= temp1; -- Value of temp1 is passed to Q

end process VAR;

end DLCH_VAR;

Figure 3.4 shows the waveform for Listing 3.2. Clearly, from the waveform, the code correctly describes a D-latch where Q follows d when E is high; otherwise, d retains its previous value. Also, Qb is the invert of Q at all times.

image

Figure 3.4  Simulation waveform of a D-Latch using variable-assignment statements. The waveform correctly describes a D-latch.

Next, the same VHDL code from Listing 3.2 is rewritten using signal-assignment statements. Listing 3.3 shows the VHDL behavioral code for a D-Latch using signal-assignment statements.

LISTING 3.3  VHDL Code for Behavioral Description of a D-Latch Using Signal-Assignment Statements

entity Dltch_sig is

port (d, E : in bit; Q : buffer bit; Qb : out bit);

--Q is declared as a buffer because it is an

--input/output signal; it appears on both the left

-- and right hand sides of assignment statements.

end Dltch_sig;

architecture DL_sig of Dltch_sig is

begin

process (d, E)

    begin

    if E = ‘1’ then

       Q <= d; -- signal assignment

       Qb <= not Q; -- signal assignment

    end if;

end process;

end DL_sig;

Figure 3.5 shows the simulation waveform of Listing 3.3. The figure shows Q is following Qb, which is an error because Qb should be the invert of Q. This error is due to the sequential execution of the signal-assignment statements in the behavioral description (see details below).

image

Figure 3.5  Simulation waveform of a D-Latch using signal-assignment statements. Qb is following Q instead of being the invert of Q.

3.4.1.1  Analysis of VHDL Code in Listings 3.2 and 3.3

The variable-assignment statements in Listing 3.2 are temp1 := d and temp2 := not temp1. Referring to Figure 3.4, at simulation time T = 0 ns, initial values are: E = 0, d = 0, Q = 0, and Qb = 0. At T = 50 ns, signal E changes from 0 to 1. Because temp1 and temp2 are variables, they instantaneously acquire their new values 1 and 0, respectively. These correct values are passed to Q and Qb.

Listing 3.3 shows two signal-assignment statements inside the body of the process, Q <= d and Qb <= not q. Initial values at T ≤ 50 ns are: E = 0, d = 0, Q = 0, and Qb = 0. Recall that execution of a signal-assignment statement inside a process is done in two phases (calculation and assignment). At T = 50 ns, E changes from 0 to 1, and d is 1 at T = 50 ns. Q is calculated as Q = d = 1. Q does not acquire this new value of 1 at T = 50 ns but at T = 50 + ∆. At T = 50 ns, Qb is calculated as 1 (using the old value of Q because Q has not yet acquired its new value of 1). After calculation, a value of 1 is assigned to Q, and the same (wrong) value of 1 is assigned to Qb.

One of the major differences between VHDL and Verilog is that Verilog treats all signal-assignment statements as concurrent, whether they are written as data flow or inside the body of always. Listing 3.4 shows the Verilog code for a D-latch; the code generates the same waveform as in Figure 3.4.

LISTING 3.4  Verilog Code for Behavioral Description of a D-Latch

module D_latch (d, E, Q, Qb);

input    d, E;

output Q, Qb;

reg Q, Qb;

always @ (d, E)

begin

    if (E == 1)

        begin

        Q = d;

        Qb = ~ Q;

        end

end

endmodule

 EXAMPLE 3.6    BEHAVIORAL DESCRIPTION OF A 2x1 MULTIPLEXER WITH TRI-STATE OUTPUT

To describe the behavior of the output of a multiplexer with the change in the input, a flowchart is developed. Figure 3.6a shows the logic symbol of the multiplexer, and Figure 3.6b shows diagram a flowchart describing the functionality of the multiplexer. The flowchart shows how the output behaves with the input. The output is high impedance if the enable (Gbar) is high. When the enable is low, the output is equal to input B if select is high; otherwise, the output is equal to A. The logic diagram of the multiplexer is not needed to write the HDL behavioral description. Although the flowchart here represents a 2x1 multiplexer, it can represent any other applications that have the same behavior; these applications may come from a variety of fields such as electrical engineering, computer engineering, science, business, biomedical engineering, and many other fields. In this example, for simplicity, the propagation delays between the input and the output are not considered.

Listing 3.5 shows the HDL description of the multiplexer using the IF-Else statement, and Listing 3.6 shows the HDL description with the Else-IF statement. The VHDL code uses variable-assignment statements to declare the variable temp; this variable is treated as if it is the output. After calculation of its value, the variable is assigned to the output Y. VHDL executes variable-assignment statements, as does C language; no delay time is involved in the execution. The signal-assignment statements Y <= ‘Z’; in VHDL and Y = 1’bz; in Verilog assign high impedance to the single-bit Y. If Y is a three-bit signal, then the two statements in VHDL and Verilog are Y <= “ZZZ”; and Y = 3’bzzz;, respectively. Figure 3.7 shows the simulation waveform of the multiplexer.

image

Figure 3.6  2x1 Multiplexer. a) Logic symbol. b) Flow chart.

LISTING 3.5  HDL Description of a 2x1 Multiplexer Using IF-Else

VHDL Description

library IEEE;

use IEEE.STD_LOGIC_1164.ALL;

entity MUX_if is

port (A, B, SEL, Gbar : in std_logic;

           Y : out std_logic);

end MUX_if;

architecture MUX_bh of MUX_if is

begin

process (A, B, SEL, Gbar)

-- A, B, SEL, and Gbar are the sensitivity list of the process.

   variable temp : std_logic;      

-- Above statement is declaring temp as a variable; it

-- will be calculated as if it is the output of the

-- multiplexer.

begin

    if Gbar = ‘0’ then

        if SEL = ‘1’ then

            temp := B;

            else

            temp := A;

        end if;

--Now assign the variable temp to the output

    Y <= temp;

    else

    Y <= ‘Z’;

    end if;

end process;

end MUX_bh;

 

Verilog Description

module mux2x1 (A, B, SEL, Gbar, Y);

input A, B, SEL, Gbar;

output Y;

reg Y;

always @ (SEL, A, B, Gbar)

begin

    if (Gbar == 1)

    Y = 1’bz;

    else

    begin

        if (SEL)

        Y = B;

 

        else

        Y = A;

    end

end

endmodule

LISTING 3.6  HDL Description of a 2x1 Multiplexer Using Else-IF

VHDL Description

library IEEE;

use IEEE.STD_LOGIC_1164.ALL;

entity MUXBH is

    port (A, B, SEL, Gbar : in std_logic;

    Y : out std_logic);

end MUXBH;

architecture MUX_bh of MUXBH is

begin

process (SEL, A, B, Gbar)

variable temp : std_logic;

   begin

       if (Gbar = ‘0’) and (SEL = ‘1’) then

       temp := B;

       elsif (Gbar = ‘0’) and (SEL = ‘0’)then

       temp := A;

       else

       temp := ‘Z’; -- Z is high impedance.

   end if;

   Y <= temp;

end process;

end MUX_bh;

 

Verilog Description

module MUXBH (A, B, SEL, Gbar, Y);

input A, B, SEL, Gbar;

output Y;

reg Y; /* since Y is an output and appears inside

       always, Y has to be declared as reg( register) */

 

always @ (SEL, A, B, Gbar)

begin

    if (Gbar == 0 & SEL == 1)

    begin

        Y = B;

    end

    else if (Gbar == 0 & SEL == 0)

    Y = A;

    else

    Y = 1’bz; //Y is assigned to high impedance

end

endmodule

image

Figure 3.7  Simulation waveform of a 2x1 multiplexer.

3.4.2  The case Statement

The case statement is a sequential control statement. It has the following format:

VHDL Case Format

case (control-expression) is

when test value or expression1 => statements1;

when test value or expression2 => statements2;

when test value or expression3 => statements3;

when others => statements4;

end case;

 

Verilog Case Format

case (control-expression)

test value1 : begin statements1; end

test value2 : begin statements2; end

test value3 : begin statements3; end

default : begin default statements end

endcase

If, for example, test value1 is true (i.e., it is equal to the value of the control expression), statements1 is executed. The case statement must include all possible conditions (values) of the control-expression. The statement when others (VHDL) or default (Verilog) can be used to guarantee that all conditions are covered. The case resembles IF except the correct condition in case is determined directly, not serially as in IF statements. The begin and end are not needed in Verilog if only a single statement is specified for a certain test value. The case statement can be used to describe data listed into tables.

 EXAMPLE 3.7   THE CASE STATEMENT

VHDL

case sel is

when “00” => temp := I1;

when “01” => temp := I2;

when “10” => temp := I3;

when others => temp := I4;

end case;

 

Verilog

case sel

2’b00 : temp = I1;

2’b01 : temp = I2;

2’b10 : temp = I3;

default : temp = I4;

endcase

In Example 3.7, the control is sel. If sel = 00, then temp = I1, if sel = 01, then temp = I2, if sel = 10, then temp = I3, if sel = 11 (others or default), then temp = I4. All four test values have the same priority; it means that if sel = 10, for example, then the third (VHDL) statement (temp := I3) is executed directly without checking the first and second expressions (00 and 01).

 EXAMPLE 3.8    BEHAVIORAL DESCRIPTION OF A POSITIVE EDGE-TRIGGERED JK FLIP-FLOP USING THE CASE STATEMENT

Edge-triggered flip-flops are sequential circuits. Flip-flops are triggered by the edge of the clock, in contrast to latches where the level of the clock (enable) is the trigger. Positive (negative) edge-triggered flip-flops sample the input only at the positive (negative) edges of the clock; any change in the input that does not occur at the edges is not sampled by the output. Figures 3.8a and 3.8b show the logic symbol and the state diagrams of a positive edge-triggered JK flip-flop, respectively.

image

Figure 3.8  JK flip-flop. a) Logic symbol. b) State diagram.

Table 3.2 shows the excitation table of the JK flip-flop. It conveys the same information as the state diagram. The state diagram (Figure 3.8b) shows the possible states (two in this case: q can take 0 or 1), state 0 and state 1. The transition between these states has to occur only at the positive edges of the clock. If the current state is 0 (q = 0), then the next state is 0(1) if JK = 0x(1x), where x is “don’t care.” If the current state is 1 (q = 1), then the next state is 1(0) if JK = x0(x1). Table 3.2 shows the same results as the state diagram. For example, a transition from 0 to 1, according to the excitation table, can occur if JK = 10 or JK = 11, which is JK = 1x.

Table 3.2  Excitation Table of a Positive Edge-Triggered JK Flip-Flop

image

Listing 3.7 shows the HDL code for a positive edge-triggered JK flip-flop using the case statement. In the Listing, rising_edge (VHDL) and posedge (Verilog) are predefined words called attributes. They represent the positive edge of the clock (clk). If the positive edge is present, the attribute yields to true. For VHDL, the clk has to be in std_logic to use this attribute. Other attributes are covered in Chapters 4, 6, and 7. Any of the four case statements can be replaced with others (VHDL) or default (Verilog). For example:

when “00” => temp1 := temp1; -- VHDL

2’d3 : q =~ q;               // Verilog

can be replaced by:

when others => temp1 := not temp1; -- VHDL

default : q =~ q;                  // Verilog

Because others here refers to 00, this replacement does not change the output of the simulation as long as J and K values are either 0 or 1. The waveform of the flip-flop is shown in Figure 3.9.

image

Figure 3.9  Simulation waveform of a positive edge-triggered JK flip-flop.

LISTING 3.7  HDL Code for a Positive Edge-Triggered JK Flip-Flop Using the case Statement

VHDL Description

library ieee;

use ieee.std_logic_1164.all;

entity JK_FF is

port(JK : in bit_vector (1 downto 0);

clk : in std_logic; q, qb : out bit);

end JK_FF;

architecture JK_BEH of JK_FF is

begin

P1 : process (clk)

variable temp1, temp2 : bit;

begin

if rising_edge (clk) then

case JK is

when “01” => temp1 := ‘0’;

when “10” => temp1 := ‘1’;

when “00” => temp1 := temp1;

when “11” => temp1 := not temp1;

end case;

q <= temp1;

temp2 := not temp1;

qb <= temp2;

end if;

end process P1;

end JK_BEH;

 

Verilog Description

module JK_FF (JK, clk, q, qb);

input [1:0] JK;

input clk;

output q, qb;

reg q, qb;

always @ (posedge clk)

begin

    case (JK)

    2’d0 : q = q;

    2’d1 : q = 0;

    2’d2 : q = 1;

    2’d3 : q =~ q;

    endcase

qb =~ q;

end

 

endmodule

 EXAMPLE 3.9    BEHAVIORAL DESCRIPTION OF A THREE-BIT BINARY COUNTER WITH ACTIVE HIGH SYNCHRONOUS CLEAR

Counters are sequential circuits. For count-up counters (or simply up counters), the next state is the increment of the present state. For example, if the present state is 101, then the next state is 110. For down-count counters (or simply down counters), the next state is the decrement of the present state. For example, if the present state is 101, then the next state is 100. A three-bit binary up counter counts from 0 to 7 (Mod 8). Decade counters count from 0 to 9 (Mod10). Synchronous clear means that clear resets the counter when the clock is active; in contrast, asynchronous clear resets the counter instantaneously. The counter can be depicted by a flowchart showing its function (see Figure 3.10). Although the flowchart here represents a counter, it could have represented any other system with the same behavior. The excitation table for the three-bit binary counter is as shown in Table 3.3. The logic symbol is shown in Figure 3.10a.

image

Figure 3.10  a) Logic symbol of a three-bit counter with clear. b) Flowchart.

Table 3.3  Excitation Table of a Three-Bit Binary Counter with Synchronous Active High Clear

image

image

The most efficient approach to describe the above counter is to use the fact that the next state is the increment of the present for upward counting. The goal here, however, is to use the case statement. Table 3.3 is treated as a look-up table. Listing 3.8 shows the HDL code for the counter. To assign initial values, such as 101, to the count at the start of simulation in Verilog, the procedural initial is used as follows:

  initial

  begin

  q = 3’b101;

  end

The begin and end can be omitted if there is a single initial statement.

In VHDL, the initial value is assigned to the variable temp after the statement process, as shown:

  ctr : process (clk)

  variable temp : std_logic_vector (2 downto 0) := “101”;

  begin

Any value assigned to a variable written between process and its begin is acquired only once at the beginning of the simulation; subsequent execution of the process will not reassign that value to the variable unless a new simulation is executed. Figure 3.11 shows the simulation waveform of the counter.

LISTING 3.8  HDL Code for a Three-Bit Binary Counter Using the case Statement

  VHDL Description

  library IEEE;

  use IEEE.STD_LOGIC_1164.ALL;

  entity CT_CASE is

  port (clk, clr : in std_logic;

        q : buffer std_logic_vector (2 downto 0));

  end CT_CASE;

  architecture ctr_case of CT_CASE is

  begin

  ctr : process(clk)

  variable temp : std_logic_vector (2 downto 0) := “101”;

  --101 is the initial value, so the counter starts from

  -- 110

  begin

      if rising_edge (clk) then

      if clr = ‘0’ then

          case temp is

              when “000” => temp := “001”;

              when “001” => temp := “010”;

              when “010” => temp := “011”;

              when “011” => temp := “100”;

              when “100” => temp := “101”;

              when “101” => temp := “110”;

              when “110” => temp := “111”;

              when “111” => temp := “000”;

              when others => temp := “000”;

          end case;

      else

      temp := “000”;

  end if;

  end if;

  q <= temp;

  end process ctr;

  end ctr_case;

  Verilog Description

  module CT_CASE (clk, clr, q);

  input clk, clr;

  output [2:0] q;

  reg [2:0] q;

  initial

  /* The above initial statement is to force

  the counter to start from initial count q=110 */

  q = 3’b101;

  always @ (posedge clk)

  begin

  if (clr == 0)

  begin

      case (q)

          3’d0 : q = 3’d1;

          3’d1 : q = 3’d2;

          3’d2 : q = 3’d3;

          3’d3 : q = 3’d4;

          3’d4 : q = 3’d5;

          3’d5 : q = 3’d6;

          3’d6 : q = 3’d7;

          3’d7 : q = 3’d0;

      endcase

end

else

q = 3’b000;

end

endmodule

image

Figure 3.11  Simulation waveform of a three-bit positive edge-triggered counter with active high synchronous clear.

 EXAMPLE 3.10A    MODELING THE GENOTYPE AND PHENOTYPE OF HUMAN BLOOD USING BIT_VECTOR

In this example, some biomedical engineering applications are considered. The example is about determining the blood type of a child given the blood type of the parents. First, consider some biological definitions to help in understanding the example:

To find all possible genotypes and phenotypes of human blood, a table is constructed to show all possible blood alleles (A, B, O) from male and female gametes. Then, determine the offspring’s genotype. From the genotype, the phenotype is determined according to the type of allele (recessive, dominant, or codominant). Table 3.4a shows all possible genotypes, and Table 3.4b shows all possible phenotypes for the offspring.

Table 3.4  Genotypes and Phenotypes of Human Blood

image

Tables 3.4a and 3.4b are look-up tables, and the case statement can be used to describe the table. Listing 3.9 shows the code for describing the genotypes and phenotypes using case. As shown in the Listing, the alleles are decoded into two bits and entered in the entity as type bit_vector; the output it is decoded in three bits and entered in the entity as a three-bit vector. The two statements

geno := allelm & allelf; -- VHDL

   geno = {allelm , allelf}; // Verilog

concatenate allelm and allelf into one vector, geno, using the concatenation operator & for VHDL or { , } for Verilog (see Section 1.5.3). For example, if allelm = 10, and allelf = 11, after concatenation, geno = 1011.

LISTING 3.9  HDL Code for Genotypes and Phenotypes Using the case Statement: VHDL and Verilog

This program takes the blood genotypes (alleles) of a male and a female and generates the possible blood phenotypes of their offspring. The statement report (VHDL) or display (Verilog) is used to print the phenotype on the screen of the simulator. The male allele is allelm, and allelf is the female allele. Both allelm and allelf are decoded as 00 for genotype A, 01 for B, or 10 for O. Phenotype A is decoded as 000, B as 001, AB as 010, O as 011, and an illegal allele entry as 111. Figure 3.12 shows the simulation waveform for genotypes and phenotypes of human blood.

VHDL Description

library ieee;

use ieee.std_logic_1164.all;

entity Bld_type is

     port (allelm, allelf : in bit_vector (1 downto 0);

         pheno : out bit_vector (2 downto 0));

end Bld_type;

architecture GEN_BLOOD of Bld_type is

begin

Bld : process (allelm, allelf)

variable geno : bit_vector(3 downto 0);

begin

     geno := allelm & allelf;

 

-- The operator (&) concatenates the two 2-bit vectors

-- allelf and allelm into one 4-bit vector geno.

 

     case geno is

     when “0000” => pheno <= “000”;

     report “phenotype is A “;

--report statement is close to printf in C language.

--The statement here prints on the screen whatever

--written between the quotations.

     when “0001” => pheno <= “010”;

     report “phenotype is AB “;

     when “0010” => pheno <= “000”;

     report “phenotype is A “;

     when “0100” => pheno <= “010”;

     report “phenotype is AB “;

     when (“0101”) => pheno <= “001”;

     report “phenotype is B “;

     when (“0110”) => pheno <= “001”;

     report “phenotype is B “;

     when “1000” => pheno <= “000”;

     report “phenotype is A “;

     when (“1001”) => pheno <= “001”;

     report “phenotype is B “;

     when “1010” => pheno <= “011”;

     report “phenotype is O “;

     when others =>pheno <= “111”;

     report “illegal allele entry “;

end case;

end process;

end GEN_BLOOD;

 

Verilog Description

module bld_type (allelm, allelf, pheno);

input [1:0] allelm, allelf;

output [2:0] pheno;

reg [2:0] pheno;

reg [3:0] geno;

always @ (allelm, allelf)

begin

 

geno = {allelm , allelf};

/* { , } concatenates the two 2-bit vectors

allelm and allelf into one 4-bit vector geno */

case (geno)

4’d0 : begin pheno = 3’d0;

$display (“phenotype is A “); end

4’d1 : begin pheno = 3’d2;

$display (“phenotype is AB “); end

/* $display statement is close to printf in C language.

The statement here prints on the screen whatever

written between the quotations.*/

 

4’d2 : begin pheno = 3’d0;

$display (“phenotype is A “); end

4’d4 : begin pheno = 3’d2;

$display (“phenotype is AB “); end

4’d5 : begin pheno = 3’d1;

$display (“phenotype is B “); end

4’d6 : begin pheno = 3’d10;

$display (“phenotype is B “); end

4’d8 : begin pheno = 3’d0;

$display (“phenotype is A “); end

4’d9 : begin pheno = 3’d1;

$display (“phenotype is B “); end

4’d10 : begin pheno = 3’d3;

$display (“phenotype is O “); end

default: begin pheno = 3’d7;

$display (“illegal allele entry “); end

endcase

end

endmodule

image

Figure 3.12  Simulation waveforms for genotypes and phenotypes of human blood. The phenotype is also printed (not shown here) on the main screen of the simulator.

 EXAMPLE 3.10B    MODELING THE GENOTYPE AND PHENOTYPE OF HUMAN BLOOD USING CHARACTER TYPE

In Listing 3.9, the inputs allelm and allelf and the output pheno had to be decoded into bits so they can be entered as bit_vector. Reading the code in decoded bits is not easy because the reader has to memorize what code was given to each signal. Using charcter type (see Section 1.6.1.1) is more convenient in this case because reading the alleles as A, B, and O is more convenient than reading them as 00, 01, and 10.

For VHDL, the string type is used to declare a signal in characters; it resembles bit_vector, but the elements are ASCII characters rather than bits. If the signal is six charcters in length, for example, the string is declared as string (1 to 6). The double quotaion mark is used to assign the value of the signal in ASCII such as “ABCDEF.”

image

Figure 3.13  Simulation waveforms for genotypes and phenotypes of human blood using character type.

For Verilog, each ASCII character is represented by eight bits (two hex digits). In Listing 3.10, allelm is represented as one character (two hex digits); the output pheno is represented to two charcters (four hex digits of a total of sixteen bits). The character assignment, same as in VHDL, is done between double quotations. Figure 3.13 shows the simulation waveform of Listing 3.10.

LISTING 3.10  HDL Code for Genotypes and Phenotypes Using the case Statement and Character Type

VHDL Description

 

library IEEE;

 

use IEEE.STD_LOGIC_1164.ALL;

 

entity bld_charctr is

port ( allelem, allelef : in string(1 to 1) ;

pheno : out string (1 to 2));

end bld_charctr;

architecture Bld_beh of bld_charctr is

 

begin

 

process (allelem, allelef)

 

variable geno: string (1 to 2);

begin

geno := (allelem & allelef);

case (geno ) is

when “AA” => pheno <= “A “;

when “AB” => pheno <= “AB”;

when “AO” => pheno <= “A “;

 

when “BA” => pheno <= “AB”;

when “BB” => pheno <= “B “;

when “BO” => pheno <= “B “;

 

when “OA” => pheno <= “A “;

when “OB” => pheno <= “B “;

when “OO” => pheno <= “O “;

 

when others => pheno <= “??”;

end case;

 

end process;

end Bld_beh;

 

Verilog Description

module Bld_typeCharctr(allelm, allelf, pheno);

 

input [8:1] allelm, allelf;

output [2*8:1] pheno;

 

reg [2*8:1] pheno; /*Since phenol is two characters;

      two ASCII characters are allocated to it.*/

reg [2*8:1] geno;

always @ (allelm, allelf)

begin

 

geno = {allelm , allelf};

 

case (geno)

“AA”: pheno = “A “;

“AB”: pheno = “AB”;

“AO”: pheno = “A “;

“BB”: pheno = “B “;

“BA”: pheno = “AB”;

“BO”: pheno = “B “;

“OA”: pheno = “A “;

“OB”: pheno = “B “;

“OO”: pheno = “O “;

default : pheno = “??”; //?? means invalid entry

 

endcase

end

endmodule

3.4.2.1  Verilog casex and casez

Section 3.2.3 covered the case statement for both VHDL and Verilog. Verilog has another two variations of case: casex and casez. casex ignores the “don’t care” values of the control expression, and casez ignores the high impedance in the control expression. For example, in the code

casex (a)

4’bxxx1: b = 4’d1;

4’bxx10: b = 4’d2;

....................

endcase;

all occurrences of x are ignored; b = 1 if and only if the least significant bit of a (bit order 0) is 1, regardless of the value of the higher order bits of a, and b = 2 if the bits of order 0 and 1 are 10, regardless of the value of all other bits. For the Verilog variation casez, all high-impedance values (z) in control expressions are ignored. For example:

casez (a)

4’bzzz1 : b = 4’d1;

4’bzz10 : b = 4’d2;

....................

endcase;

b = 1 if and only if the least significant bit (bit of order 0) of a = 1, and b = 2 if bit 0 of a = 0 and bit 1 of a = 1.

 EXAMPLE 3.11    VERILOG DESCRIPTION OF A PRIORITY ENCODER USING CASEX

A priority encoder encodes the inputs according to a priority set by the user, such as when the input represents interrupt requests. If two or more interrupt requests are issued at the same time by the devices needing service, and the central processing unit (CPU) can only serve one device at a time, then one of these requests should be given priority over the others and be served first. A priority encoder can handle this task. The input to the encoder is the interrupt requests, and the output of the encoder can be memory addresses where the service routine is located or an address leading to the actual address of the routines. Table 3.5 shows the truth table of a four-bit encoder; bit 0 of input a has the highest priority. Listing 3.11 shows the Verilog description for a four-bit priority encoder. Figure 3.14 shows the simulation waveform of Listing 3.11.

Table 3.5  Truth Table for Four-Bit Encoder

image

LISTING 3.11  Verilog Description for a Four-Bit Priority Encoder Using casex

module Encoder_4 (Int_req, Rout_addrs);

input [3:0] Int_req;

output [3:0] Rout_addrs;

reg [3:0] Rout_addrs;

 

always @ (Int_req)

begin

casex (Int_req)

4’bxxx1 : Rout_addrs=4’d1;

4’bxx10 : Rout_addrs=4’d2;

4’bx100 : Rout_addrs=4’d4;

4’b1000 : Rout_addrs= 4’d8;

default : Rout_addrs=4’d0;

 

endcase

end

endmodule

image

Figure 3.14  Simulation waveform of a four-bit priority encoder.

3.4.3  The wait-for Statement

The wait statement has several formats; in this section, only wait for a time period is discussed. For example:

VHDl : wait for 10 ns;

Verilog # 10;

The wait statement can be implemented to generate clocks, as it is usually common in bench marks. Listing 3.12 shows an example of using the wait-for statement to generate three different clocks: a with a period of 20 ns, b with a period of 40 ns, and c with a period of 80 ns. Note that if a process (VHDL) or always (Verilog) does not have a sensitivity list, this process or always will run indefinitely. Figure 3.15 shows the waveform of Listing 2.12.

LISTING 3.12  Implementation of the wait-for Statement to Generate Clocks

VHDL

Library IEEE;

use IEEE.STD_LOGIC_1164.ALL;

entity waittestVHDL is

port ( a,b,c : out std_logic);

end waittestVHDL;

 

architecture Behavioral of waittestVHDL is

 

begin

  p1 :process

  variable a1: std_logic := ‘0’;

    begin

      a <= a1;   

      wait for 10 ns;

      a1 := not a1;

      

    end process;

p2 :process

variable b1: std_logic := ‘0’;

  begin

    b <= b1;

    wait for 20 ns;

    b1 := not b1;

end process;

 

p3 :process

variable c1: std_logic := ‘0’;

  begin

    c <= c1;

    wait for 40 ns;

    c1 := not c1;

end process;

END;

 

Verilog

module waitstatement(a,b,c);

output a,b,c;

reg a,b,c;

 

initial

begin

// Initialize Inputs

    a = 0;

    b = 0;

    c = 0;

     end

always

   begin

   #10 ;

   a = ~ a;   

   end

            

always

   begin

   #20 ;

   b = ~ b;

    end

always

   begin

   #40 ;

   c = ~ c;   

   end

 

endmodule

image

Figure 3.15  Simulation waveform of Listing 2.12.

3.4.4  The Loop Statement

Loop is a sequential statement that has to appear inside process in VHDL or inside always or initial in Verilog. Loop is used to repeat the execution of statements written inside its body. The number of repetitions is controlled by the range of an index parameter. The loop allows the code to be compressed; instead of writing a block of code as individual statements, it can be written as one general statement that, if repeated, reproduces all statements in the block. There are several ways to construct a loop. Some of those ways are discussed here.

3.4.4.1  For-Loop

The HDL general format for a For-Loop is:

for <lower index value> <upper index value> <step>

statements1; statement2; statement3; ....

end loop

If the value of index is between lower and upper, all statements written inside the body of the loop are executed. For each cycle, the index is modified at the end loop according to the step. If the value of index is not between the lower and upper values, the loop is terminated.

 EXAMPLE 3.12   FOR-LOOP: VHDL AND VERILOG

VHDL For-Loop

for i in 0 to 2 loop

if temp(i) = ‘1’ then

result := result + 2**i;

end if;

end loop;

statement1; statement2; ....

 

Verilog For-Loop

for (i = 0; i <= 2; i = i + 1)

begin

   if (temp[i] == 1’b1)

        begin

            result = result + 2**i;

        end

    end

statement1; statement2; ....

The index is i, the lower value is 0, the upper value is 2, and the step is 1. All statements between the for statement and end loop (VHDL) or end (Verilog) are executed until the index i goes out of range. At the very beginning of the loop, i takes the value of 0, and the statements if and result are executed as:

if temp(0) = ‘1’ then

result := result + 2**0;

When the program encounters the end of the loop, it increments i by 1. If i is less than or equal to 2, the loop is repeated; otherwise, the program exits the loop and executes statement1, statement2, and so on. In VHDL, index i does not have to be declared, but in Verilog, it has to be declared. If the loop statement is stated without range, the loop will run indefinitely.

3.4.4.2  While-Loop

The general format of the While-Loop is:

while (condition)

Statement1;

Statement2;

............

end

As long as the condition is true, all statements written before the end of the loop are executed. Otherwise, the program exits the loop.

 EXAMPLE 3.13   WHILE-LOOP: VHDL AND VERILOG

VHDL While-Loop

while (i < x)loop

    i := i + 1;

    z := i * z;

end loop;

Verilog While-Loop

while (i < x)

    begin

        i = i + 1;

        z = i * z;

   end

In the above example, the condition is (i < x). As long as i is less than x, i is incremented, and the product i * z (i multiplied by z) is calculated and assigned to z.

3.4.4.3  Verilog repeat

In Verilog, the sequential statement repeat causes the execution of statements between its begin and end to be repeated a fixed number of times; no condition is allowed in repeat.

 EXAMPLE 3.14   VERILOG REPEAT

repeat (32)

begin

  #100 i = i + 1;

end

In the above example, i is incremented 32 times with a delay of 100 screen time units. This describes a five-bit binary counter with a clock period of 100 screen time units.

3.4.4.4  Verilog forever

The statement forever in Verilog repeats the loop endlessly. One common use for forever is to generate clocks in code-oriented test benches. The following code describes a clock with a period of 20 screen time units:

initial

begin

    Clk = 1’b0;

    forever #20 clk = ~clk;

end

3.4.4.5  VHDL next and exit

In VHDL, next and exit are two sequential statements associated with loop; exit causes the program to exit the loop, and next causes the program to jump to the end of the loop, skipping all statements written between next and end loop. The index is incremented, and if its value is still within the loop’s range, the loop is repeated. Otherwise, the program exits the loop.

 EXAMPLE 3.15   VHDL NEXT-EXIT

for i in 0 to 2 loop

......

.....

next When z = ’1’;

statements1;

end loop;

statements2;

In the above example, at the very beginning of the loop’s execution, i takes the value 0; at the statement next When z = ’1’, the program checks the value of z. If z = 1, then statements1 is skipped and i is incremented to 1. The loop is then repeated with i = 1. If z is not equal to 1, then statements1 is executed, i is incremented to 1, and the loop is repeated.

 EXAMPLE 3.16      BEHAVIORAL DESCRIPTION OF A FOUR-BIT POSITIVE EDGE-TRIGGERED SYNCHRONOUS UP COUNTER

In this example, the Loop statement is used to convert values between binary and integer and use this conversion to describe a binary up counter. The HDL package is assumed to not contain predefined functions that will increment a binary input or convert values between binary and integer. In addition, the current and next state are expressed in binary rather than integer. Describing a counter using the above binary-to-integer conversion is not the most efficient way; the main goal here is to demonstrate the implementation of the Loop statement.

The next state of a binary counter is generated by incrementing the current state. Because, in this example, a binary value cannot be incremented directly by the HDL code (as was assumed), it is first converted to an integer. HDL packages can easily increment integers. We increment the integer and convert it back to binary. To convert an integer to binary, the predefined operator MOD in VHDL or % in Verilog (see Section 1.5.3.1.) is used. For example: (X MOD 2) equals 1 if X is 1 (odd) or equals 0 if X is 0 (even, divisible by 2). By successively dividing the integer by 2 and recording the remainder from the outcome of the MOD2, the integer is converted to binary. To convert a binary to integer, multiply each bit by its weight and accumulate the products: 10112 = (1 × 1) + (1 × 2) + (0 × 4) + (1 × 8) = 1110. If the bit is equal to 0, it can be ignored.

Listing 3.13 shows the HDL code of the counter. The simulation waveform is the same as that shown in Figure 3.11, except the count here is from 0 to 15 rather than from 0 to 7 as in the figure.

LISTING 3.13  HDL Code for a Four-Bit Counter With Synchronous Clear: VHDL and Verilog

VHDL Description

library ieee;

use ieee.std_logic_1164.all;

entity CNTR_LOP is

port (clk, clr : in std_logic; q :

    buffer std_logic_vector (3 downto 0));

end CNTR_LOP;

architecture CTR_LOP of CNTR_LOP is

begin

ct : process(clk)

variable temp :

                std_logic_vector (3 downto 0) := “0000”;

variable result : integer := 0;

begin

if rising_edge (clk) then

     if (clr = ‘0’) then

         result := 0;

-- change binary to integer

        lop1 : for i in 0 to 3 loop

             if temp(i) = ‘1’ then

             result := result + 2**i;

             end if;

        end loop;

-- increment result to describe a counter

        result := result + 1;

-- change integer to binary

        for j in 0 to 3 loop

        if (result MOD 2 = 1) then

            temp (j) := ‘1’;

            else temp (j) := ‘0’;

        end if;

-- integer division by 2

        result := result/2;

        end loop;

   else temp := “0000”;

   end if;

q <= temp;

end if;

end process ct;

end CTR_LOP;

 

Verilog Description

module CNTR_LOP (clk, clr, q);

input clk, clr;

output [3:0] q;

reg [3:0] q;

integer i, j, result;

initial

begin

q = 4’b0000; //initialize the count to 0

end

always @ (posedge clk)

begin

    if (clr == 0)

    begin

        result = 0;

        //change binary to integer

        for (i = 0; i < 4; i = i + 1)

            begin

                if (q[i] == 1)

                result = result + 2**i;

            end

            result = result + 1;

            for (j = 0; j < 4; j = j + 1)

            begin

                 if (result %2 == 1)

                 q[j] = 1;

                 else

                 q[j] = 0;

                 result = result/2;

            end

        end

        else q = 4’b0000;

end

endmodule

A more efficient approach to describe a binary counter is to directly increment the current state. As mentioned before, the approach implemented in Listing 3.13 is not the most efficient way to describe a counter. To write an efficient code for a four-bit counter, direct increment of the current state is used. The following Verilog code describes a four-bit binary counter using direct increment of the current state:

module countr_direct (clk, Z);

input clk;

output [3:0] Z;

reg [3:0] Z;

initial

Z = 4’b0000;

 

/*This initialization is needed if we want to start counting

from 0000 */

 

always @ (posedge clk)

Z = Z + 1;

endmodule

 EXAMPLE 3.17      BEHAVIORAL DESCRIPTION OF A FOUR-BIT COUNTER WITH SYNCHRONOUS HOLD USING THE LOOP STATEMENT

To write the code for the counter, binary-integer conversion is used. As mentioned in Example 3.16, this approach is not the most efficient way to describe a counter, but it will be implemented here to demonstrate the use of Loop and the Exit statements. The hold signal in a counter, when active, retains the value of the output and keeps it unchanged until the hold is inactivated. The flowchart of the counter is shown in Figure 3.16. In VHDL, an exit statement is used to exit the loop when the hold is active. Verilog, however, does not have an explicit exit statement, but the loop can be exited by assigning the index a value higher than its upper value. Listing 3.14 shows the HDL code for the counter. Figure 3.17 shows the simulation waveform of the counter.

image

Figure 3.16  Flowchart of a four-bit counter with active high hold.

LISTING 3.14  HDL Code for a Four-Bit Counter with Synchronous Hold: VHDL and Verilog

VHDL Description

library ieee;

use ieee.std_logic_1164.all;

entity CNTR_Hold is

port (clk, hold : in std_logic;

q : buffer std_logic_vector (3 downto 0));

 

end CNTR_Hold;

architecture CNTR_Hld of CNTR_Hold is

begin

ct : process (clk)

variable temp : std_logic_vector

          (3 downto 0) := “0000”;

-- temp is initialized to 0 so count starts at 0

variable result : integer := 0;

begin

if rising_edge (clk) then

    result := 0;

-- change binary to integer

    lop1 : for i in 0 to 3 loop

    if temp(i) = ‘1’ then

        result := result + 2**i;

        end if;

   end loop;

-- increment result to describe a counter

   result := result + 1;

   -- change integer to binary

   lop2 : for i in 0 to 3 loop

-- exit the loop if hold = 1

   exit when hold = ‘1’;

-- “when” is a predefined word

   if (result MOD 2 = 1) then

       temp (i) := ‘1’;

   else

       temp (i) := ‘0’;

   end if;

--Successive division by 2

   result := result/2;

   end loop;

   q <= temp;

end if;

end process ct;

end CNTR_Hld;

 

Verilog 4-Bit Counter with Synchronous Hold Description

module CT_HOLD (clk, hold, q);

input clk, hold;

output [3:0] q;

reg [3:0] q;

integer i, result;

initial

begin

q = 4’b0000; //initialize the count to 0

end

always @ (posedge clk)

begin

result = 0;

 

//change binary to integer

 

for (i = 0; i <= 3; i = i + 1)

begin

if (q[i] == 1)

result = result + 2**i;

end

result = result + 1;

for (i = 0; i <= 3; i = i + 1)

begin

if (hold == 1)

i = 4; //4 is out of range, exit.

else

    begin

        if (result %2 == 1)

        q[i] = 1;

        else

        q[i] = 0;

        result = result/2;

    end

end

end

endmodule

image

Figure 3.17  Simulation waveform of a four-bit binary counter with synchronous hold.

 EXAMPLE 3.18    SHIFT REGISTERS DESCRIPTION USING THE LOOP STATEMENT

The main function of a general-purpose register is to store data. The data can be retrieved, or it can be stored indefinitely. The data in the register can be manuplated by several actions such as shift. The data can be shifted right or left logically (Figure 3.18), where zeros are used to fill the vacant bits after shifting; in this shift, some data can be lost. The data can also be shifted arithmatically (Figure 3.18), where if shifted right, the sign of the data (the most significant bit) is preserved. The data in the register can also be rotated left or right (Figure 3.18); here no data are lost. Shift operation is widely used in many areas of digital design such as arithmetic units and serial communications. Shift registers may have an external input bit that replaces the vacant bit after shift. Other registers may have load and bidirectional shifts; these registers are called universal shift registers and are covered in Chapter 4.

image

Figure 3.18  Single-register shift and rotation.

Listing 3.15 shows a HDL code for describing a logical shift, as shown in Figure 3.18, using the Loop statement. The code shifts register q n bits right or left logically. The number of bits to be shifted is determined by user-selected parameter N. The code resembles the preserved statement sll and slr in VHDL and ( << and >>) in Verilog. See Section 1.5.4.

$display statement in Listing 3.15 is one of Verilog’s system tasks that displays values of objects on the console of the simulator. The statement

     $display (“ i= %d”, i);

will display a printout of the text between the quotation marks ( i = ) excluding the %d, which determines that the object should be displayed in decimal. The i after the comma is the object to be displayed. The $display is a tool that can be used to display objects that are not listed as an output. Several other formats can be selected for display such as:

%b for binary

%o for octal

$d for decimal

%h for hexadecimal

%t for time

%e or %f or %g for real

%c for character

%s for string

%v for binary and strength

LISTING 3.15  HDL Code for Logical Shifting of a Register Using the Loop Statement

VHDL Description

library IEEE;

use IEEE.STD_LOGIC_1164.ALL;

entity shift_register is

     port(start : in std_logic; shft: in std_logic;

         N: in natural;

     q : out std_logic_vector(7 downto 0))

end shift_register;

--N is number of shifts selected by the user

architecture shift_righLift of shift_register is

 

begin

st: process (start)

variable vq : std_logic_vector (7 downto 0)

                 := “11001110”;

--initial values for the vector is selected to be

  -- 1100110

begin

if (start =’1’) then

lop2: for j in 1 to N loop

lop1: for i in 0 to 6 loop

if shft =’0’ then   

--shft = 0 is logical right shift; =1 logical left

-- shift

 

vq(i) := vq(i+1);

vq(7) :=’0’;

else

vq(7-i ) := vq(6-i);

vq(0) := ‘0’;

end if;

end loop lop1;

end loop lop2;

end if;

q <= vq;

end process st;

 

end shift_righLift;

 

Verilog Description

module shft_regVerilog(start,shft, N,q);

input start,shft;

input [7:1] N;

//N is number of requested shifts

output [7:0]q;

reg [7:0]q;

integer i,j;

 

initial

q = 8’b01100110;

/*initial values for the vector is selected to be

1100110 */

 

always @ (posedge start)

begin

lop2: for (j= 1; j <= N; j = j +1)

begin

lop1: for (i= 0; i <= 6; i = i +1)

begin

if (shft == 1’b0 )    

/*shft = 0 is logical right shift; =1 logical left

Shift */

begin

$display (“ shft = %d”, shft);/*This is a system task

         to display The value of shift on the console’s

         screen of the simulator*/

$display (“ i= %d”, i);

$display (“q[i] = %b”, q[i]);

$display (“q[i+1] = %b”, q[i+1]);

  q[i] = q[i+1];

  q[7] =1’b0; $display (“ q = %b”, q);end

 

else

begin q[7-i] = q[6-i];

q[0] = 1’b0; end

$display (“ shft = %d”, shft);

 

end

end

end

 

endmodule

 EXAMPLE 3.19   CALCULATING THE FACTORIAL USING BEHAVIORAL DESCRIPTION WITH WHILE-LOOP

In this example, a HDL behavioral description is written to find the factorial of a positive number N. The factorial of N is (N!) = Nx(N-1)x(N-2)x(N-3)x ....x1. For example, 4!=4×34×24×1=24. In VHDL, N and the output z are declared as natural; this restricts the values that N and z can assume to positive integers. If N and z are declared as std_logic, the multiplication operator (*) cannot be used directly; they must be converted to integers before multiplication or an external library should be attached. In VHDL, be sure to include all the necessary libraries. If the appropriate libraries are not included in the code, the simulator will not accept the declaration and will report it as undefined.

In Verilog, the default declaration of inputs and outputs allows for the direct use of arithmetic operators such as multiplication. Listing 3.16 shows the HDL code for calculating the factorial.

LISTING 3.16  HDL Code for Calculating the Factorial of Positive Integers: VHDL and Verilog

VHDL Description

library IEEE;

use IEEE.STD_LOGIC_1164.ALL;

--The above library statements can be omitted;

--however no error if it is not omitted.

--The basic VHDL has type “natural.”

entity factr is

port(N : in natural; z : out natural);

end factr;

architecture factorl of factr is

begin

process (N)

variable y, i : natural;

begin

    y := 1;

    i := 0;

    while (i < N) loop

    i := i + 1;

    y := y * i;

    end loop;

    z <= y;

end process;

end factorl;

 

Verilog Description

module factr (N, z);

input [5:0] N;

output [15:0] z;

reg [15:0] z;

/* Since z is an output, and it will appear inside

“always,” then Z has to be declared “reg” */

 

integer i;

always @ (N)

begin

    z = 16’d1;

    i = 0;

    while (i < N)

    begin

        i = i + 1;

        z = i * z;

    end

end

endmodule

 CASE STUDY 3.1   BOOTH ALGORITHM

The Booth algorithm is used to multiply two signed numbers. The signed numbers are in twos-complement format. The function of the algorithm is to determine the beginning and end of a string of 1s in the multiplier and perform multiplicand addition-accumulation at the end of the string or perform subtraction-accumulation at the beginning of the string. A string consists of one or more consecutive 1s. For example, 01110 has one string, 1011 has two strings (1 and 11). Any signed number can be written in terms of its bit order at the beginning and end of the string. For example, the number 0111011 has the following bit order:

Bit order     6 5 4 3 2 1 0

                   0 1 1 1 0 1 1

The number above has two strings. One string has two 1s, begins at bit 0, and ends at bit 1. The other string has three 1s, begins at bit 3, and ends at bit 5. The value of any binary number is equal to (2end1+1 − 2begin1) + (2end2+1 − 2begin2)+ ....., where begin1 and begin2 are the bit orders of the beginning of string1 and string2, respectively, and end1 and end2 are the bit orders of the end of string1 and string2, respectively. So, 0111011 = (22 − 20) +(26 − 23) = 3 + 56 = 59. For the multiplication Z = multiplier (X) × multiplicand (Y), we can write:

image

Multiplication of Y by positive power(s) of 2 is a shift left of Y. For example, Y × 23 is a three-left shift of Y. From Equation 3.1, it can be seen that the calculation of the product Z consists of addition at the end of the string, subtraction at the beginning of the string, and a number of shifts equal to the number of the bits of the multiplicand or the multiplier; here we assume multiplier and multiplicand have the same number of bits). To guarantee no overflow, Z is selected to be double the width of X or Y. For example, if X is four bits, then Z is eight bits. The beginning of a string is the transition from 0 to 1, while the end is the transition from 1 to 0. To detect the transition, the one-bit register (E) is used to hold 0 initially. By comparing E with the bits of X, the beginning and end of the string can be detected. The flowchart of the algorithm is shown in Figure 3.19.

image

Figure 3.19  Flowchart of the Booth multiplication algorithm.

To illustrate the algorithm, consider multiplication of two four-bit numbers: –5 (1011) multiplied by 7 (0111). To avoid any possibility of overflow in the product, we assign eight bits to the product. The steps of the Booth algorithm are shown in Table 3.6.

Table 3.6  Example of the Booth Algorithm
X = 1011, Y = 0111, –Y = 1001

image

The answer is Z = 11011101 = –35. Note that Z – Y = Z + (–Y), so subtraction of Y from Z is an addition of the twos-complement of Y to Z.

The HDL code for a 4x4-bit Booth algorithm is shown in Listing 3.17. The multiplier (X) and the multiplicand (Y) have to be declared as signed numbers. To do this declaration, the predefined word signed is used. In VHDL, be sure that the appropriate libraries are attached to the code. The statement sum (7 downto 4) represents four bits of sum starting from bit order seven and ending at bit order four. For example, if sum is the eight-bit number 11001010, then sum (7 downto 4) is 1100.

The statement Y := -Y in VHDL (Y = -Y in Verilog) changes Y to its twos complement. If Y = 1101, then –Y = 0011. The statement sum := sum srl in VHDL (Z = Z >> 1 in Verilog) is the logical shift right of sum(Z) one position. For example, if sum or Z = 11010100, then after right shift, sum(Z) = 01101010. In Listing 3.17, sum and Z are signed numbers; this means that the most significant bit is the sign bit. If this bit is 0, the number is positive, and if it is 1, the number is negative. Notice that after the logical shift, the sign may change, as in our example where sum(Z) changes from 11010100 (a negative number) to 01101010 (a positive number) after a one-position right shift. Another type of shift is arithmetic, where the sign is preserved. An arithmetic right shift of 11010100 yields 11101010. The shift in the Booth algorithm is arithmetic; the following two statements perform arithmetic shift:

VHDL                Verilog

sum := sum srl 1;   Z = Z >>> 1;

sum (7):= sum(6);

The first statement performs logical shift, and the second performs sign preservation. VHDL code has a predefined arithmetic shift operator, sra;. For example, sum := sum sra 2 executes a right shift of two positions and preserves the sign. To use this shift, be sure that the appropriate libraries and simulator are used. The simulation waveform of the Booth algorithm is shown in Figure 3.20.

LISTING 3.17  4x4-Bit Booth Algorithm: VHDL and Verilog

VHDL Description

library ieee;

use ieee.std_logic_1164.all;

use ieee.numeric_std.all;

entity booth is

  port (X, Y : in signed (3 downto 0);

  Z : buffer signed (7 downto 0));

end booth;

architecture booth_4 of booth is

begin

image

Figure 3.20  Simulation waveform of a Booth multiplication algorithm.

process (X, Y)

variable temp : signed (1 downto 0);

variable sum : signed (7 downto 0);

variable E1 : unsigned (0 downto 0);

variable Y1 : signed (3 downto 0);

begin

sum := “00000000”; E1 := “0”;

for i in 0 to 3 loop

temp := X(i) & E1(0);

Y1 := - Y;

case temp is

    when “10” => sum (7 downto 4) :=

    sum (7 downto 4) + Y1;

    when “01” => sum (7 downto 4) :=

    sum (7 downto 4) + Y;

    when others => null;

end case;

sum := sum srl 1; --This is a logical

--shift of one position to the right

sum (7) := sum(6);

 

--The above two statements perform arithmetic

--shift where the sign of the

--number is preserved after the shift.

 

E1(0) := x(i);

end loop;

    if (y = “1000”) then

 

--If Y = 1000; then according to our code,

--Y1 = 1000 (-8 not 8 because Y1 is 4 bits only).

--The statement sum = -sum adjusts the answer.

 

      sum := - sum;

    end if;

z <= sum;

end process;

end booth_4;

 

Verilog Description

module booth (X, Y, Z);

input signed [3:0] X, Y;

output signed [7:0] Z;

reg signed [7:0] Z;

reg [1:0] temp;

integer i;

reg E1;

reg [3:0] Y1;

always @ (X, Y)

begin

Z = 8’d0;

E1 = 1’d0;

for (i = 0; i < 4; i = i + 1)

begin

temp = {X[i], E1};

 

//The above statement is catenation

 

Y1 = - Y;

 

//Y1 is the 2’ complement of Y

 

case (temp)

2’d2 : Z [7 : 4] = Z [7 : 4] + Y1;

2’d1 : Z [7 : 4] = Z [7 : 4] + Y;

default : begin end

endcase

Z = Z >>> 1;

/*The above statement is arithmetic shift of one position to

the right*/

 

E1 = X[i];

   end

if (Y == 4’d8)

 

/*If Y = 1000; then according to our code,

Y1 = 1000 (-8 not 8, because Y1 is 4 bits only).

The statement sum = - sum adjusts the answer.*/

   begin

       Z = - Z;

   end

end

endmodule

 CASE STUDY 3.2    BEHAVIORAL DESCRIPTION OF A SIMPLIFIED RENAL ANTIDIURETIC HORMONE MECHANISM

In this case study, the action of antidiuretic hormone (ADH) on water excreted by the kidney is discussed. One function of the kidney is to regulate the amount of water excreted by the body as urine. Human blood is 70% water by volume. Regulation of the water volume is directly related to blood pressure regulation. An excessive amount of water in the body raises blood pressure, and if the body excretes more water than it needs to maintain proper functions, blood pressure will drop. Kidney failure has a direct effect on blood pressure. The main functional unit in the kidney is the nephron. Figure 3.21 illustrates a schematic of nephron functions.

image

Figure 3.21  Nephron function in the human body.

Nephrons are tiny tubules through which blood flows. In nephrons, some components in the blood, such as sodium and potassium, are reabsorbed by the body, and other components, such as urea, are excreted because they are toxic to the body. Any extra water that the body does not need is also excreted as urine. Several hormones control the amount of water excreted. One of those hormones is ADH. The function of ADH is summarized as follows:

Figure 3.22 describes a simplified possible representation of the relationship between the concentration of ADH and blood pressure (BP). Assume that the relationship is linear, and BP takes only positive integer values.

The HDL code is shown in Listing 3.18. It is assumed that the body samples its blood pressure at intervals; each interval is represented in the code by the period of the clock. The major sequential statement in the code is Else-IF. For simplification, the blood pressure and ADH are allowed to take only integer-positive values. In VHDL, this means that BP and ADH are declared as natural, allowing the application of the equation ADH = BP * (-4) + 180.0. If BP and ADH are declared as std_logic_vectors, VHDL cannot directly multiply or add. In contrast, Verilog allows for direct addition and multiplication if BP and ADH are declared as bit vectors. Figure 3.23 shows the simulation waveform of an ADH-BP relationship.

image

Figure 3.22  Concentration of ADH versus blood pressure (units are arbitrary).

LISTING 3.18  Antidiuretic Hormone Mechanism: VHDL and Verilog

VHDL Description

library IEEE;

use IEEE.STD_LOGIC_1164.ALL;

use IEEE.STD_LOGIC_ARITH.ALL;

use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity ADH_BEH is

    port (clk : in std_logic; BP : in natural;

ADH : out natural);

-- Assume BP takes only positive integer values

end;

architecture ADH_XT of ADH_BEH is

begin

ADHP : process (clk)

variable resADH : natural := 0;

begin

if (clk = ‘1’) then

if Bp <= 20 then resADH := 100;

elsif Bp > 45 then resADH := 0;

else

    resADH := Bp * (-4) + 180;

end if;

end if;

ADH <= resADH;

end process ADHP;

end ADH_XT;

 

Verilog Description

module ADH_BEH (clk, BP, ADH);

input clk;

input [8:0] BP;

// Assume BP takes only positive integer values

output [8:0] ADH;

reg [8:0] ADH;

always @ (clk)

begin

if (clk == 1)

begin

     if (BP <= 20) ADH = 100;

     else if (BP > 45.0) ADH = 0;

     else

     ADH = BP * (-4) + 180.0;

end

end

endmodule

image

Figure 3.23  Simulation waveform of ADH versus blood pressure.

3.5  Common Programming Errors

 

This section discusses some common programming errors. Additional common errors are discussed in Chapter 2.

3.5.1  Common VHDL Programming Errors

The following is a brief discussion of some common syntax and semantic errors in writing VHDL programs. Table 3.7 considers Listing 3.16 (VHDL) and some possible errors if the code is modified.

Table 3.7  Possible Errors in Modified VHDL Listing 3.13

image

image

3.5.2  Common Verilog Programming Errors

Here, some common Verilog syntax and semantic errors are briefly discussed. One of the most common errors for beginners is not adhering to Verilog’s case-sensitive nature. Table 3.8 considers Listing 3.16 (Verilog) and discusses some possible errors if the code is modified.

Table 3.8  Possible Errors in Modified Verilog Listing 3.16

image

3.6  Summary

 

In this chapter, the basics of behavioral description have been covered, including the statements process (VHDL) and always (Verilog). Some sequential statements have also been discussed such as IF, wait, case, and Loop. These sequential statements have to appear inside process in VHDL or inside always or initial in Verilog. In VHDL, all signal-assignment statements inside process are executed sequentially. Here, sequentially means calculating the values of the left-hand side of the statements in the order in which they are written. After calculation, the values are assigned taking into consideration any delay times. In Verilog, all statements inside always are executed concurrently, based on events. Execution of variable-assignment statements inside process in VHDL, in contrast to signal-assignment statements, does not involve any timing delays; execution here is the same as in C language. Table 3.9 shows a list of the VHDL statements covered in this chapter along with their Verilog counterparts (if any).

Table 3.9  Summary of VHDL Behavioral Statements and Their Verilog Counterparts

image

3.7  Exercises

 

  1. Add asynchronous clear signal to the JK flip-flop discussed in Example 3.8. Write both VHDL and Verilog to describe the flip-flop and simulate the code.
  2. Write VHDL and Verilog code for a T flip-flop and simulate.
  3. Modify Listing 3.15 to include rotate and arithmetic shift.
  4. In Example 3.8, a JK flip-flop was described by using a case statement on JK. Change the code to describe the flip-flop by using case on Q. Simulate and verify your description.
  5. Use binary-to-integer conversion to describe a four-bit even counter with active low clear and synchronous load (load from external P to Q). Use Verilog, simulate, and verify.
  6. Using the Booth algorithm (see Case Study 3.1), modify the code to satisfy all the following requirements:
    • The multiplier and the multiplicand are five bits each.
    • If the multiplier or the multiplicand is 0, the product should be 0 without going through the multiplication steps.
    • If the multiplier or the multiplicand is 1 (decimal), the product should be equal to the multiplicand or the multiplier, respectively, without going through the multiplication steps.
  7. In Case Study 3.2, it was assumed that the relationship between ADH and BP is linear: Bp * (-4) + 180 (VHDL). Change this relationship to be exponential: ADH = a exp (b * BP). The value of ADH is 100 for BP ≤ 20 and stays at 10 for BP ≥ 45. Write the VHDL code using the case statement to describe this relationship. You can approximate the values of ADH to be integers but be as accurate as possible.
  8. Design an arithmetic and logical unit (ALU) that performs addition, subtraction, multiplication, and integer division. The input to the ALU is two signals, A and B, of integer type. The output is signal Z of integer type. The ALU performs the operations according to a signal called op_code. This op_code is of character type, and Table 3.10 shows the value of the op_code (in character) and the selected operation.

Table 3.10  op_code and the selected operation

image