Orhan Gazi

A Tutorial Introduction to VHDL Programming

Orhan Gazi

Department of Electronics and Communication Engineering, Çankaya University, Ankara, Turkey

ISBN 978-981-13-2308-9e-ISBN 978-981-13-2309-6

https://doi.org/10.1007/978-981-13-2309-6

Library of Congress Control Number: 2018952599

© Springer Nature Singapore Pte Ltd. 2019

This work is subject to copyright. All rights are reserved by the Publisher, whether the whole or part of the material is concerned, specifically the rights of translation, reprinting, reuse of illustrations, recitation, broadcasting, reproduction on microfilms or in any other physical way, and transmission or information storage and retrieval, electronic adaptation, computer software, or by similar or dissimilar methodology now known or hereafter developed.

The use of general descriptive names, registered names, trademarks, service marks, etc. in this publication does not imply, even in the absence of a specific statement, that such names are exempt from the relevant protective laws and regulations and therefore free for general use.

The publisher, the authors, and the editors are safe to assume that the advice and information in this book are believed to be true and accurate at the date of publication. Neither the publisher nor the authors or the editors give a warranty, express or implied, with respect to the material contained herein or for any errors or omissions that may have been made. The publisher remains neutral with regard to jurisdictional claims in published maps and institutional affiliations.

This Springer imprint is published by the registered company Springer Nature Singapore Pte Ltd.

The registered company address is: 152 Beach Road, #21-01/04 Gateway East, Singapore 189721, Singapore

Contents

1 Entity, Architecture and VHDL Operators 1

1.​1 Entity 1

1.​2 The Data Types Used in Input/​Output Ports 6

1.​3 Architecture 14

1.​4 Data Objects 19

1.​4.​1 Constant Object 19

1.​4.​2 Signal Object 22

1.​4.​3 Variable Object 23

1.​5 VHDL Operators 25

1.​5.​1 Assignment Operators 25

1.​5.​2 Logical Operators and Shift Operators 26

1.​5.​3 Relational Operators 29

1.​5.​4 Arithmetic Operators 29

1.​5.​5 Concatenation Operator “&​” 32

1.​5.​6 Generic Statement 33

2 Combinational Logic Circuit Design and Concurrent Coding in VHDL 37

2.​1 “When” and “Select” Statements 37

2.​2 Generate Statement 42

2.​3 Examples for Combinational Circuits Implemented in VHDL 45

3 Simulation of VHDL Programs 79

3.​1 Test-Bench Writing 79

4 User Defined Data Types, Arrays and Attributes 99

4.​1 User Defined Data Types 99

4.​1.​1 Enumerated Types 100

4.​2 User Defined Array Data Types 101

4.​2.​1 Constrained Arrays 101

4.​2.​2 Unconstrained Arrays 103

4.​2.​3 Defining PORT Arrays 105

4.​3 Defining 2D Arrays or Matrices 107

4.​3.​1 Matrix as Column Wise Concatenated Row Vectors 107

4.​3.​2 Matrix as Table of Numbers 110

4.​3.​3 3D Arrays 111

4.​4 Subtypes 113

4.​4.​1 Type Conversion 113

4.​5 Attributes of Data Types 114

4.​5.​1 Attributes for Scalar Data Types 115

4.​5.​2 Attributes for Array Data Types 117

4.​5.​3 Attributes for Signal Objects 119

5 Sequential Circuit Implementation in VHDL 123

5.​1 Sequential Circuits in VHDL 123

5.​1.​1 Process 124

5.​1.​2 IF Statement 124

5.​2 Example Implementations for Sequential Logic Units 125

5.​2.​1 D-Type Flip Flop 125

5.​2.​2 Multiplexer 130

5.2.3 JK and T Flip-Flops 131

5.​2.​4 Counter 133

5.​2.​5 Clock Divider (Frequency Divider) 135

5.​2.​6 BCD to SS Converter with 1 s BCD Counter 143

5.​3 The Wait Statement 145

5.​3.​1 Wait Until 145

5.​3.​2 Wait on 146

5.​4 Case Statement 147

5.​5 Loop Statements 149

5.​5.​1 Next and Exit Statements 149

5.​6 Example Sequential Logic Circuit Implementation in VHDL 150

6 VHDL Implementation of Logic Circuits Involving Registers and Counters 165

6.​1 Shift Registers 165

6.​1.​1 Shift Register with Parallel Load 168

6.​1.​2 Logic Circuits Involving Shift Registers and Counter 170

6.​1.​3 Serial Transfer Unit 174

6.​1.​4 Serial Adder Unit 177

7 Packages, Components, Functions and Procedures 189

7.​1 Packages 189

7.​2 Components 191

7.​3 Functions and Procedures 205

7.​3.​1 Functions 205

7.​3.​2 Operator Overloading 211

7.​4 Procedures 212

7.​4.​1 Differences Between a Function and a Procedure 214

8 Fixed and Floating Point Numbers 217

8.​1 Fixed Point Numbers 217

8.​1.​1 Type Conversion Functions 221

8.​1.​2 Operators for Fixed Point Numbers 222

8.​1.​3 Arithmetic Operations with Fixed Point Numbers and Sizing Rules 223

8.​1.​4 Automatic Resizing 224

8.​1.​5 Resize Function 226

8.​1.​6 Add Cary Procedure 228

8.​1.​7 Divide Function 230

8.​1.​8 Reciprocal Function 230

8.​1.​9 Remainder Function 231

8.​1.​10 Scalb Function 232

8.​1.​11 Maximum and Minimum Function 233

8.​1.​12 ‘Find Left Most’ and ‘Find Right Most’ Functions 234

8.​1.​13 ABS Function 235

8.​2 Floating Point Numbers 236

8.​2.​1 Floating Point Type Conversion Functions 238

8.​2.​2 Operators for Floating Point Numbers 243

8.​2.​3 Copysign Function 244

8.​2.​4 Scalb Function 244

8.​2.​5 Logb Function 245

Bibliography247

Index249

© Springer Nature Singapore Pte Ltd. 2019

Orhan GaziA Tutorial Introduction to VHDL Programminghttps://doi.org/10.1007/978-981-13-2309-6_1

1. Entity, Architecture and VHDL Operators

Orhan Gazi1 

(1)

Department of Electronics and Communication Engineering, Çankaya University, Ankara, Turkey

VHDL stands for “very high speed integrated circuits hardware description language”, and first developed by the US department of defense in 1980s. It is used to describe the behavior of an electronic circuit. VHDL programs consist of program modules. A module is nothing but a program segment written for some specific purposes. For instance, we have package modules, test modules, and main VHDL modules, i.e., main programs.

In this chapter, entity and architecture parts of a VHDL program will be explained in details. Entity part is used to describe the input and output ports of an electronic circuit, i.e., used to describe I/O ports. On the other hand, architecture part of a VHDL module is used to describe the operation of the electronic circuit. During the circuit operation, the circuit process its input data obtained from input ports, and produces its output data to be sent to the output ports. We will also discuss the data types used for the ports available in entity part. In addition, VHDL operators will be explained shortly.

1.1 Entity

As we mentioned in the previous paragraph, entity part of the VHDL program describes the I/O ports of an electronic circuit. A port can be an input port, or an output port, or both input and output port at the same time, or can be a buffer port. In Fig. 1.1, the graphical illustration of the port types is given.

Fig. 1.1

Black box representation of an electronic circuit

The general structure of the entity part is shown in PR 1.1

PR 1.1

General structure of entity unit

where ‘[entity] [entity_name]’ means that you can omit or keep words inside braces. Let’s illustrate the use of entity by an example.

Example 1.1

The black box representation of an electronic circuit is shown in Fig. 1.2. Describe the electronic circuit ports by a VHDL program, i.e., by PR.

Fig. 1.2

Black box representation of an electronic circuit for Example 1.1

Solution 1.1

We can write the entity part for the black box shown in Fig. 1.2 with the following steps.

(S1) First, write the reserved word entity as in PR 1.2.

PR 1.2

Program 1.2

(S2) In step 2, we give a name to entity as in PR 1.3.

PR 1.3

Program 1.3

(S3) In step 3, write the reserved word is to the end of the line of PR 1.3 as in PR 1.4.

PR 1.4

Program 1.4

(S4) In step 4, write the closing tag of entity part as in PR 1.5.

PR 1.5

Program 1.6

(S5) In step 5, put a semicolon to the end of the closing tag as in PR 1.6.

PR 1.6

Program 1.6

(S6) In step 6, write the reserved word port as in PR 1.7.

PR 1.7

Program 1.7

(S7) In step 7, add parentheses to the port as in PR 1.8.

PR 1.8

Program 1.8

(S8) In step 8, put a semicolon to the end of port() as in PR 1.9.

PR 1.9

Program 1.9

(S9) If we look at the black box in Fig. 1.2, we see that we have two input ports and three output ports. Let’s give names to these ports as in PR 1.10.

PR 1.10

Program 1.10

(S10) In step 10, we indicate the type of the ports using the reserved words in and out as in PR 1.11.

PR 1.11

Program 1.11

(S11) In Step 11, we indicate the data type available at the input and output ports an in PR 1.12 where we used std_ logic for all port data types.

PR 1.12

Program 1.12

(S12) In step 12, we put semicolon to the end of every std_logic except for the last one as in PR 1.13.

PR 1.13

Program 1.13

The enclosing tag or enclosing line of the program segment in PR 1.13 can also be written as in PR 1.14. We can also write the enclosing line as “end entity my_circuit_name”.

PR 1.14

Program 1.14

It is up to the programmer to select the enclosing line of the entity part.

(S12) In Step 12, add the header lines which are necessary for the data type std_logic to be meaningful in our VHDL program as in PR 1.15.

PR 1.15

Program 1.15

(S12) Finally, we can add some comments to our VHDL code. For this purpose, we can use

format in our program. Then, our entity part becomes as in PR 1.16.

PR 1.16

Program 1.16

The VHDL program in PR 1.16 completely describes the input/output ports of the electronic circuit whose black box representation is given in Fig. 1.2.

The VHDL program in PR 1.16 can also be written as in PR 1.17 where the port types are written in the same line.

PR 1.17

Program 1.17

1.2 The Data Types Used in Input/Output Ports

In this section, we will give information about the data types used in VHDL programming.

std_logic

In PR 1.17 the data type used for the ports is std_logic defined in the package IEEE.std_logic_1164.all. For std_logic data type, there are 8 possible values available, and these values are tabulated in Table 1.1.

Table 1.1

std_logic values

‘X’ Unknown

‘0’ Logic 0

‘1’ Logic 1

‘Z’ High Impedance

‘W’ Weak Unknown

‘L’ Weak Low

‘H’ Weak High

‘-’ Don’t Care

std_logic_vector

The std_logic_ vector data type is defined in the library IEEE.std_logic_1164.all. If an I/O port has data type of std_logic_vector, it means that the I/O port has a number of std_logic values.

std_ulogic

The data type std_ ulogic is defined in the package IEEE.std_logic_1164.all. For std_ulogic data type, there are 9 possible values available, and these values are tabulated in Table 1.2.

Table 1.2

std_ulogic values

‘U’ Uninitialized

‘X’ Unknown

‘0’ Logic 0

‘1’ Logic 1

‘Z’ High Impedance

‘W’ Weak Unknown

‘L’ Weak Low

‘H’ Weak High

‘-’ Don’t Care

std_ulogic_vector

The std_ulogic_vector data type is defined in the library IEEE.std_logic_1164.all. If an I/O port has data type of std_ulogic_vector, it means that the I/O port has a number of std_ulogic values.

bit

The bit data type is defined in standard package, i.e., we don’t need to include an extra package at the header of the VHDL program. For instance, if we use data type bit for port I/Os, we can write PR 1.17 as in PR 1.18 where it is seen that no header file is needed.

PR 1.18

Program 1.18

bit_vector

The bit_ vector data type is defined in standard package, i.e., we don’t need to include an extra package at the header of the VHDL program. If an I/O port has data type of bit_vector, it means that the I/O port has a number of bit values.

integer, natural, positive

The data types integer, natural , positive are defined in standard package, i.e., we don’t need to include an extra package at the header of the VHDL program. The data type integer is used to represent integer numbers in the range $$ - 2^{31} $$ to $$ 2^{31} - 1 $$. The data type natural is used to represent the integers in the range 0 to $$ 2^{31} - 1 $$. On the other hand, the data type positive is used to represent the integers in the range 1 to $$ 2^{31} - 1 $$.

unsigned, signed

The data types unsigned and signed are defined in the packages numeric_ std and std_logic_arith. One of these packages should be included in the header of the VHDL program to be able to use these data types in entity declarations. The data type unsigned is used to represent unsigned numbers, i.e., nonnegative integers, and the data type signed is used to represent the signed numbers, i.e., integers.

An electronic circuit with a number of ports which consists of a number of bits can be expressed with a number of equivalent ways. Let’s illustrate this concept with an example.

Example 1.2

The black box representation of an electronic circuit is shown in Fig. 1.3. Describe the electronic circuit ports by a VHDL program.

Fig. 1.3

The black box representation of an electronic circuit for Example 1.2

(a)

Use the data type std_logic_vector to describe the ports in entity part.

(b)

Use the data type bit_vector to describe the ports in entity part.

(c)

Use the data type integer to describe the ports in entity part.

(d)

Use the data type natural to describe the ports in entity part.

(e)

Use the data type positive to describe the ports in entity part.

(f)

Use the data type unsigned to describe the ports in entity part.

(g)

Use the data type signed to describe the ports in entity part.

Solution 1.2

Let’s solve the part-a in details, and follow the same approach for the other parts in short.

In Fig. 1.3, the number of bits available at the ports is indicated, however, the type of the data available at the ports is not clarified. For this reason, we can employ all the data types mentioned in the question to represent the bits. Otherwise, considering the type of the data available at the ports, we would select the suitable VHDL data type representation in our VHDL program. Now let’s proceed with the solution of part-a.

(a)

We can write the entity part for the black box as shown in Fig. 1.3 with the following steps.

(S1) First, write the reserved word entity as in PR 1.19.

PR 1.19

Program 1.19

(S2) In step 2, we give a name to entity as in PR 1.20.

(S3) In step 3, write the reserved word is to the end of the line of PR 1.20 as in PR 1.21.

PR 1.20

Program 1.20

PR 1.21

Program 1.21

(S4) In step 4, write the closing tag of entity part as in PR 1.22.

PR 1.22

Program 1.22

(S5) In step 5, put a semicolon to the end of the closing tag as in PR 1.23.

PR 1.23

Program 1.23

(S6) In step 6, write the reserved word port as in PR 1.24.

PR 1.24

Program 1.24

(S7) In step 7, add parentheses to the port as in PR 1.25.

PR 1.25

Program 1.25

(S8) In step 8, put a semicolon to the end of port() as in PR 1.26.

PR 1.26

Program 1.26

(S9) If we look at the black box in Fig. 1.3, we see that we have two input ports and two output ports. Let’s give names to these ports as in PR 1.27.

PR 1.27

Program 1.27

(S10) In step 10, we indicate the type of the ports using the reserved words in and out as in PR 1.28.

PR 1.28

Program 1.28

(S11) In Step 11, we indicate the data type available at the input and output ports an in PR 1.29 where we used std_logic_vector for all port data types.

PR 1.29

Program 1.29

(S12) In step 12, we put semicolon to the end of every std_logic_vector except for the last one as in as in PR 1.30.

PR 1.30

Program 1.30

The enclosing tag or enclosing line of the program segment in PR 1.30 can also be written as in PR 1.31.

PR 1.31

Program 1.31

Another alternative for the closing tag of the entity is to use “end;” alone at the end of the declaration. Besides, we can also use “end entity FourBit_Circuit” fort he enclosing lines of the entity unit. It is up to the programmer to select the enclosing line of the entity part.

(S13) In Step 12, add the header lines which are necessary for the data type std_logic_ vector to be meaningful in our VHDL program as in PR 1.32.

PR 1.32

Program 1.32

(b)

We can write the entity segment using the data type bit_vector. However, in this case since bit_vector is defined in standard package, we don’t need to include any header file. Then, entity segment can be written as in PR 1.33.

PR 1.33

Program 1.33

(c)

We can write the entity segment using the data type integer . The data type integer is defined in standard package; we don’t need to include any header file. However, it is logical to indicate a range for the integer data type. It is seen from Fig. 1.3 that the circuit accepts 4-bit inputs, and there is no additional information about the sign of the input number. If we assume that the port accepts non-negative integers, with 4-bits we can get integers in the range 0–15. Thus, we can write the entity segment as in PR 1.34.

PR 1.34

Program 1.34

However, if we assume that the circuit port accepts both positive and negative integers, in this case, using 4-bits we can get the integers in the range $$ - 8 $$ to 7, and using 5-bits we can get integers in the range $$ - 16 $$ to 15.

Thus, we can write the entity segment as in PR 1.35,

PR 1.35

Program 1.35

(d)

The data type natural is used to indicate the non-negative integers. Using 4 bits we can represent the non-negative integers in the range 0–15. The natural is defined in the standard package .

Thus, we can write the entity segment as in PR 1.36.

PR 1.36

Program 1.36

(e)

The data type positive is used to indicate the positive integers. Using 4 bits we can represent the positive integers in the range 1–15. The positive is defined in the standard package.

Thus, we can write the entity segment as in PR 1.37.

PR 1.37

Program 1.37

(f)

The data type unsigned is used to represent the non-negative integers of any number of bits. The difference of this representation from that of the natural is that we decide on the number of bits to be used to represent the non-negative integers as a bit vector. To be able to use the unsigned data type in our VHDL programs we need to use IEEE.numeric_std. all package at our header.

Thus, we can write the entity segment as in PR 1.38.

PR 1.38

Program 1.38

(g)

The data type signed is used to represent the integers of any number of bits. The difference of this representation from that of the integer is that we decide on the number of bits to be used to represent integers as a bit vector. To be able to use the signed data type in our VHDL programs we need to use IEEE.numeric_std.all package at our header.

Thus, we can write the entity segment as in PR 1.39.

PR 1.39

Program 1.39

Example 1.3

The black box representation of an electronic circuit is shown in Fig. 1.4. Describe the electronic circuit ports by a VHDL entity segment. Use std_logic_vector for the data types of the ports.

Fig. 1.4

The black box representation of an electronic circuit for Example 1.3

Solution 1.3

The black box illustration of the circuit shown in Fig. 1.4 has input, output, input/output and buffer ports. Considering the port types, we can write an entitle for the given circuit as in PR 1.40.

PR 1.40

Program 1.40

1.3 Architecture

The architecture part of a VHDL program describes the internal behavior of the electronic circuit. The data received from the ports of the electronic circuit is processed inside the architecture part and the output data is obtained. The produced output data is sent to the output ports of the electronic circuit. The general syntax of the architecture part is depicted in PR 1.41.

PR 1.41

Program 1.41

The last line of the architecture can be either “end architecture” or “end architecture_name” or “end architecture architecture_name” or just “end”.

Example 1.4

The program segments given in PR 1.42 are equal to each other.

PR 1.42

Program 1.42

Example 1.5

The black box representation of a digital circuit is given in Fig. 1.5. Write a VHDL program for the implementation of the circuit given in Fig. 1.5.

Fig. 1.5

The black box representation of a digital circuit for Example 1.5

Solution 1.5

The entity part for the black box given in Fig. 1.5 can be written as in PR 1.43.

PR 1.43

Program 1.43

The behavior of the circuit can be expressed in architecture part. The architecture part of the circuit can be written considering the following steps.

(S1) First, write the reserved word architecture as in PR 1.44.

PR 1.44

Program 1.44

(S2) In step 2, we give a name to architecture as in PR 1.45.

PR 1.45

Program 1.45

(S3) In step 3, write the reserved word of to the end of the line of PR 1.45 as in PR 1.46.

PR 1.46

Program 1.46

(S4) In step 4, write name of the entity after the reserved word of as in PR 1.47.

PR 1.47

Program 1.47

(S5) In step 5, write the reserved word is to the end of title name as in PR 1.48.

PR 1.48

Program 1.48

(S6) In step 6, write the closing tag of architecture part as in PR 1.49.

PR 1.49

Program 1.49

(S7) In step 7, put a semicolon to the end of the closing tag as in PR 1.50.

PR 1.50

Program 1.50

(S8) In step 8, write the reserved word begin as in PR 1.51.

PR 1.51

Program 1.51

(S8) In step 8, we add the VHDL implementation of the Boolean functions $$ f_{1} = ab^{{\prime }} + c $$ and $$ f_{2} = abc^{{\prime }} $$ as in PR 1.52.

PR 1.52

Program 1.52

With the entity part, our complete VHDL program becomes as in PR 1.53.

PR 1.53

Program 1.53

Note: In PR 1.53 the last line of the VHDL program can be written as “end architecture” or as “end;” For the name of the architecture part of a VHDL program, the names logic_flow, behavioral, behavior_of_the_circuit, circuit_logic, can be used.

Example 1.6

Write VHDL statements for the Boolean functions $$ f_{1} = ab^{{\prime }} + c $$.

Solution 1.6

Let’s implement the $$ f_{1} $$ function as

However, this implementation is not complete, we have missing parenthesis around and logic. The correct statement is

Example 1.7

A digital logic circuit is given in Fig. 1.6. Write a VHDL program for the implementation of the circuit given in Fig. 1.6.

Fig. 1.6

Digital logic circuit or Example 1.7

Solution 1.7

The title part for the given circuit can be written as in PR 1.54.

PR 1.54

Program 1.54

The behavior of the circuit can be expressed in architecture part. The architecture part of the circuit can be written considering the following steps.

(S1) First, write the reserved word architecture as in PR 1.55.

PR 1.55

Program 1.55

(S2) In step 2, we give a name to architecture as in PR 1.56.

PR 1.56

Program 1.56

(S3) In step 3, write the reserved word of to the end of the line of PR 1.56 as in PR 1.57.

PR 1.57

Program 1.57

(S4) In step 4, write name of the entity after the reserved word of as in PR 1.58.

PR 1.58

Program 1.58

(S5) In step 5, write the reserved word is to the end of title name as in PR 1.59.

PR 1.59

Program 1.59

(S6) In step 6, write the closing tag of architecture part as in PR 1.60.

PR 1.60

Program 1.60

(S7) In step 7, put a semicolon to the end of the closing tag as in PR 1.61.

PR 1.61

Program 1.61

(S8) In step 8, write the reserved word begin as in PR 1.62.

PR 1.62

Program 1.62

(S8) In step 8, we add the VHDL implementation of the intermediate Boolean functions $$ g = xy $$ and $$ h = y^{\prime } z $$ as in PR 1.63 Since, g and h are the internal outputs of the logic circuit, to hold the value of these outputs, we define two signal at the declarative part of the architecture as it is seen in PR 1.63. Note that the declarative part is the part between the words architecture and begin .

PR 1.63

Program 1.63

(S9) In step 9, we add the VHDL implementation of the Boolean function $$ f = g + h $$ as in PR 1.64.

PR 1.64

Program 1.64

With the entity part, our complete VHDL program becomes as in PR 1.65.

PR 1.65

Program 1.65

1.4 Data Objects

In VHDL programming we have data objects which hold values. A data object has a name and data type. The general syntax for the use of the data object is as

where the data object can be signal , variable, or constant. The object name is up to you. The data type can be any data type available in VHDL programming, such as bit, std_logic, integer, unsigned, signed, std_logic_vector, bit_vector, etc.

The signal objects can be declared in the declarative part of the architecture. On the other hand, the variable objects can be declared inside the sequential program segments, like process , procedure, function.

The constant objects are usually declared in the declarative part of the architecture, entity, package, process, procedure and function. However, it can also be declared in the package body, block, generate.

1.4.1 Constant Object

The value of the constant object cannot be changed through the program. Its syntax is as follows

Example 1.8

Inspect the constant object declarations in PR 1.66.

PR 1.66

Program 1.66

Example 1.9

Declare a constant object which uses unsigned data type with initial value “100100”, i.e., the length of the unsigned bit vector is 6.

Solution 1.9

We can declare the constant object in the question by the following steps.

(S1) First, write the reserved word constant as in PR 1.67.

PR 1.67

Program 1.67

(S2) In step 2, we give a name to constant object as in PR 1.68.

PR 1.68

Program 1.68

(S3) In step 3, put a colon, i.e., :, to the end of the line as in PR 1.69.

PR 1.69

Program 1.69

(S4) In step 4, write the type of the data to the end of the line as in PR 1.70.

PR 1.70

Program 1.70

(S5) In step 5, put ‘:=’ to the end of data type as in PR 1.71.

PR 1.71

Program 1.71

(S6) In step 6, add the initial value to the end of the line as in PR 1.72.

PR 1.72

Program 1.72

(S7) Finally, put a semicolon to the end of the line as in PR 1.73.

PR 1.73

Program 1.73

Example 1.10

Declare a constant object which uses natural data type with initial value 2234566.

Solution 1.10

We can declare the constant object in the question by the following steps.

(S1) First, write the reserved word constant as in PR 1.74.

PR 1.74

Program 1.74

(S2) In step 2, we give a name to constant object as in PR 1.75.

PR 1.75

Program 1.75

(S3) In step 3, put a colon, i.e., :, to the end of the line as in PR 1.76.

PR 1.76

Program 1.76

(S4) In step 4, write the type of the data to the end of the line as in PR 1.77.

PR 1.77

Program 1.77

(S5) In step 5, put ‘:=’ to the end of data type as in PR 1.78.

PR 1.78

Program 1.78

(S6) In step 6, add the initial value to the end of the line as in PR 1.79.

PR 1.79

Program 1.79

(S7) Finally, put a semicolon to the end of the line as in PR 1.80.

PR 1.80

Program 1.80

1.4.2 Signal Object

Signal object declarations may or may not include an initial value. Signal objects are usually employed in the declarative part of the architectures, and packages . Signal declarations are not allowed inside sequential program segments, such as function, procedure, and process. Its syntax is as follows

Example 1.11

Inspect the following signal object declarations. (PR 1.81)

PR 1.81

Program 1.81

Example 1.12

Declare a signal object which uses signed data type for 6-bit integers.

Solution 1.12

We can declare the signal object using the following steps.

(S1) First, write the reserved word signal as in PR 1.82.

PR 1.82

Program 1.82

(S2) In step 2, we give a name to signal object as in PR 1.83.

PR 1.83

Program 1.83

(S3) In step 3, put a colon, i.e., :, to the end of the line as in PR 1.84.

PR 1.84

Program 1.84

(S4) In step 4, write the type of the data to the end of the line as in PR 1.85.

PR 1.85

Program 1.85

(S7) Since no initial value is indicated in the question, we can terminate the declaration by putting a semicolon to the end of the line as in PR 1.86.

PR 1.86

Program 1.86

1.4.3 Variable Object

Variable object declarations may or may not include an initial value. Variable objects are employed in sequential program units, such as function, procedure, and process. Its syntax is as follows

Example 1.13

Inspect the variable object declarations in PR 1.87.

PR 1.87

Program 1.87

Example 1.14

Declare a variable object which uses integer data type with initial value 124542.

Solution 1.14

We can declare the variable object in the question by the following steps.

(S1) First, write the reserved word variable as in PR 1.88.

PR 1.88

Program 1.88

(S2) In step 2, we give a name to variable object as in PR 1.89.

PR 1.89

Program 1.89

(S3) In step 3, put a colon, i.e., :, to the end of the line as in PR 1.90.

PR 1.90

Program 1.90

(S4) In step 4, write the type of the data to the end of the line as in PR 1.91.

PR 1.91

Program 1.91

(S5) In step 5, assign the initial value of the data type putting ‘: = 124542’ to the end of data type as in PR 1.92.

PR 1.92

Program 1.92

(S6) In step 6, we terminate the declaration by putting a semicolon to the end of the line as in PR 1.93.

PR 1.93

Program 1.93

Example 1.15

The architecture of a VHDL program is given as in PR 1.94. Indicate the declarative part of the given architecture segment.

PR 1.94

Program 1.94

Solution 1.15

The declarative part of the architecture is the part between the reserved word architecture and begin. Considering this information, we can indicate the declarative part of the architecture as in PR 1.95.

PR 1.95

Program 1.95

1.5 VHDL Operators

The operators provided by VHDL can be classified in the following main categories.

Assignment Operators

Logical Operators

Relational Operators

Arithmetic Operators

Concatenation Operator

Let’s briefly explain all those operators.

1.5.1 Assignment Operators

Operator “:=”

We use operator “:=” for either initial value assignment or to assign a value to a variable, constant or generic.

Note that “:=” is used for signal objects only for initial value assignment. It is not used for signal objects in any other cases.

Example 1.16

signal my_signal: integer:=10; -- Initial value assignment

my_signal <=30; -- Value assignment

Example 1.17

variable my_signal: integer:=10; -- Initial value assignment

my_signal:=40; -- Value assignment

Example 1.18

constant my_number: natural:=214; -- Initial value assignment

Operator “<=”

We use the operator “<=” to assign a value to a signal object.

Example 1.19

signal my_signal: bit_vector(3 downto 0):= “10011”; -- Initial value assignment

my_signal<= “11011”; – Value assignment

Operator “=>” and “others” keyword

We use operator “=>” to assign values to vector elements. The operator “=>” is usually employed with the reserved word others which indicates the index values of the unassigned vector elements.

Example 1.20

After the program line

signal x_vec: std_logic_vector(5 downto 1): =(4|3=> ‘1’, others=> ‘0’);

we have x_vec=“01100”, and after the line

x_vec<=(1 to 3=>‘1’, others=>‘0’);

we have x_vec=“00111”,

Example 1.21

After the program line

variable x_vec: std_logic_vector(0 to 10): =(1|3|5=> ‘1’, 2=> ‘Z’, others=>‘0’);

we have x_vec= “01Z10100000”, and after the line

x_vec:=(1 to 5=>‘0’, others=>‘Z’);

we have x_vec=“Z00000ZZZZZ”,

1.5.2 Logical Operators and Shift Operators

The logical operators are used for data types bit, std_logic, std_logic_vector, std_ulogic, std_ulogic_vector, and Boolean. Logical operators are used for the implementation combinational logic circuits. The logical operators and shift operators can be summarized as in Table 1.3.

Table 1.3

Logical and shift operators

Logical operators

and, or, nand, nor, xor, xnor, not

Shift operators

sll, srl, sla, sra, rol, ror

Let’s briefly explain the logical shift operators briefly.

Shift Operators

Let’s briefly explain the logical shift operators briefly.

SLL: Shift Left Logical

The bits are shifted to the left and new positions are filled by zeros.

Example 1.22

If

then

produces

SLA: Shift Left Arithmetic

The bits are shifted to the left and new positions are filled by the value of the rightmost bit.

Example 1.23

If

then

produces

SRL: Shift Right Logical

The bits are shifted to the right and new positions are filled by zeros.

Example 1.24

If

then

produces

SRA: Shift Right Arithmetic

The bits are shifted to the right and new positions are filled by the value of the leftmost bit.

Example 1.25

If

then

produces

ROL: Rotate Left

The bits are shifted towards left, and the new positions on the right are filled with the bits dropped from the left edge.

Example 1.26

If

then

produces

ROR: Rotate Right

The bits are shifted towards right, and the new positions on the left are filled with the bits dropped from the right edge.

Example 1.27

If

then

produces

Note: Multiplying an unsigned integer by two is the same as shifting the number to the left by one bit. In a similar manner, dividing an unsigned integer by two is the same as shifting the number to the right by one bit.

Example 1.28

Write a VHDL program described as follows. The program inputs an 8-bit number. Let’s denote this number by x. The program sends the numbers are $$ y_{1} = 2^{4} \times x $$, $$ y_{2} = 2^{ - 3} \times x $$ to its ports.

Solution 1.28

With the given information, we can write the entity part of the program as in PR 1.96.

PR 1.96

Program 1.96

The operations $$ y_{1} = 2^{4} \times x $$, $$ y_{2} = 2^{ - 3} \times x $$ can be achieved using the shift operators shl and shr as in PR 1.97.

PR 1.97

Program 1.97

1.5.3 Relational Operators

Relational operators are used for comparison purposes. The following relational operators can be used in VHDL programming are

The result of the relational operator is a Boolean value, i.e., true or false.

1.5.4 Arithmetic Operators

Arithmetic operators are used to do arithmetic operations on integers or numeric values. The arithmetic operators that can be used in VHDL programming are

Let’s explain these operators shortly:

Operator $$ \varvec{**} $$

The operation

can be implemented in VHDL using

Exponentiation operator is synthesizable for $$ x = 2 $$ and integer a values, or it is synthesizable when $$ a = 2 $$. For other cases, it is not synthesizable.

Example 1.29

Write a VHDL program that calculates $$ y = 2^{x} $$ where x is an integer in the range 0–7.

Solution 1.29

The function $$ y = 2^{x} $$ can be implemented in VHDL as shown in PR 1.98.

PR 1.98

Program 1.98

Operator mod

The result of $$ x\,\varvec{mod}\,y $$ is the remainder of $$ x/y $$, and the remainder has the sign of y. The operator $$ \varvec{mod} $$ is synthesizable without any restrictions.

Example 1.30

For the $$ \varvec{mod} $$ operator we can give the following examples

Example 1.31

Write a VHDL program that takes a four-bit integer from the port, and calculates the remainder after division by 3, and displays the remainder at the output port.

Solution 1.31

The function $$ y = x\,\varvec{mod}\,3 $$ can be implemented in VHDL as shown in PR 1.99.

PR 1.99

Program 1.99

Operator rem

The result of $$ x\,\varvec{rem}\,y $$ is the remainder of $$ x/y $$, and the remainder has the sign of x. The operator $$ \varvec{rem} $$ is synthesizable.

Example 1.32

Example 1.33

Write a VHDL program that takes a four-bit integer from the port, and calculates the remainder after division by 3, and displays the remainder at the output port.

Solution 1.33

The function $$ y = x\,\varvec{rem}\,3 $$ can be implemented in VHDL as shown in PR 1.100.

PR 1.100

Program 1.100

Operator abs

The abs operator checks the most significant bit of the number, and if it is ‘1’, then two’s complement of the number is evaluated, otherwise, the number is kept as it is.

The abs operator has been implemented for different arguments in different packages. These packages and their abs implementations are summarized as follows:

Package: std_logic_ arith , have the functions:

function “abs”(L: signed) return signed;

function “abs”(L: signed) return std_logic_vector;

Package: numeric_bit, have the function.

function “abs” (arg: signed) return signed;

Package: std_logic_signed, have the function:

function “abs”(L: std_logic_vector) return std_logic_vector;

Package: numeric_std, have the function:

function “abs” (arg: signed) return signed;

Example 1.34

Write a VHDL program that takes two eight-bit signed integers x and y from the port, and calculates $$ z = \left| x \right| + \left| y \right| $$ and sends the result to an output port.

Solution 1.34

The function $$ z = \left| x \right| + \left| y \right| $$ can be implemented in VHDL as shown in PR 1.101.

PR 1.101

Program 1.101

Example 1.35

If I edit the package file std_logic_signed.vhd, I see the following line inside the file code:

What does this line mean?

Solution 1.35

This line means that you can use abs operator in your VHDL program as in the form

if you include std_logic_signed package as header file in your VHDL program.

1.5.5 Concatenation Operator “&”

Concatenation operator is used to merge logic or bit vectors to get longer logic vector. The concatenation operator can be used to merge the data types, bit_vector, std_logic_vector, std_ulogic_vector, signed, unsigned, string, integer vector, boolean-vector.

Example 1.36

Write a VHDL program that takes two bit-vectors of length 5 and 7, concatenates them and sends the result to an output port.

Solution 1.36

We can write the required VHDL program as in PR 1.102.

PR 1.102

Program 1.102

Example 1.37

Another example for the concatenation operator is given in PR 1.103.

PR 1.103

Program 1.103

1.5.6 Generic Statement

The keyword generic is used to declare generic parameters which can be used through the VHDL program. In this way, it becomes easier to adapt the VHDL program to different applications. The generic declarations are done in the entity part before the port section. The syntax for generic declarations is as follows:

Example 1.38

An example use of generic declarations is shown in PR 1.104. Note that generic declarations are made before the port declarations.

PR 1.104

Program 1.104

Example 1.39

Declare any two logic vectors as generic parameters.

Solution 1.39

We can declare two generic logic vectors as follows:

(S1) First, write the reserved word entity as in PR 1.105

PR 1.105

Program 1.105

(S2) In step 2, add parentheses to the generic as in PR 1.106.

PR 1.106

Program 1.106

(S3) In step 3, put a semicolon to the end of the line as in PR 1.107.

PR 1.107

Program 1.107

(S4) In step 4, write the name of the generic parameters as in PR 1.108.

PR 1.108

Program 1.108

(S5) In step 5, put colons after parameter names and write the data type as in PR 1.109.

PR 1.109

Program 1.109

(S6) In step 6, assign values to the generic vectors as in PR 1.110.

PR 1.110

Program 1.110

(S7) In step 7, put a semicolon after the first generic declaration as in PR 1.111. Note that after the last generic declaration, we do not use a semicolon at the end of the line.

PR 1.111

Program 1.111

(S8) Lastly, don’t forget that we place the generic declarations before the port section of the entity part, as in PR 1.112.

PR 1.112

Program 1.112

Problems

(1)

The black box representation of an electronic circuit is shown in Fig. 1.P1. Describe the electronic circuit ports by a VHDL program.

Fig. 1.P1

Black box representation of an electronic circuit

(a)

Use the data type std_logic_vector to describe the ports in entity part.

(b)

Use the data type bit_vector to describe the ports in entity part.

(c)

Use the data type integer to describe the ports in entity part.

(d)

Use the data type natural to describe the ports in entity part.

(e)

Use the data type positive to describe the ports in entity part.

(f)

Use the data type unsigned to describe the ports in entity part.

(g)

Use the data type signed to describe the ports in entity part.

(2)

Implement the Boolean function $$ f = ab^{{\prime }} + bc^{{\prime }} $$ in VHDL.

(3)

Define a signal object with data type integer, and the initial value of the object is 2342.

(4)

Consider the signal object “signal my_obj: integer;”. How many bits are used for this signal object?

(5)

State the differences between a signal object and variable object.

(6)

Find the results of the following operations

(7)

Declare two generic signal objects having integer data types with initial values 8 and 15.

© Springer Nature Singapore Pte Ltd. 2019

Orhan GaziA Tutorial Introduction to VHDL Programminghttps://doi.org/10.1007/978-981-13-2309-6_2

2. Combinational Logic Circuit Design and Concurrent Coding in VHDL

Orhan Gazi1 

(1)

Department of Electronics and Communication Engineering, Çankaya University, Ankara, Turkey

In this chapter we will explain the implementations of combinational logic circuits in VHDL language. The combinational logic circuits can be implemented using logic operators and VHDL statements. The VHDL statements when and select are used for the implementation if conditional expressions are available in logic circuit implementation. The combinational circuits are implemented via concurrent codes.

2.1 “When” and “Select” Statements

The VHDL statements when and select can be employed in concurrent VHDL codes. These statements are not used in sequential, i.e., clocked, program units. We can employ VHDL statements when and select for the implementation of combinational circuits. These statements are employed for the conditional implementation of the logic circuits. The syntax of the when statement is as follows:

The when and select statements are similar to each other. They differ only in implementation syntax. The syntax of the select statement is as follows:

Let’s now give some examples illustrating the combinational synthesizable logic circuit design using VHDL programming.

Example 2.1

Implement the Boolean function $$ f\left( {x,y,z} \right) = x^{\prime } y^{\prime } + y^{\prime } z $$ using logical operators.

Solution 2.1

The Boolean function $$ f\left( {x,y,z} \right) = x^{{\prime }} y^{{\prime }} + y^{{\prime }} z $$ can be implemented using logical operators as

A VHDL program that implements the Boolean function $$ f\left( {x,y,z} \right) = x^{{\prime }} y^{{\prime }} + y^{{\prime }} z $$ can be written as in PR 2.1.

PR 2.1

Program 2.1

Example 2.2

The truth table of a Boolean function is given in Table 2.1..

Table 2.1

Truth table of a Boolean function

x

y

z

f (x, y, z)

0

0

0

1

0

0

1

1

0

1

0

0

0

1

1

0

1

0

0

0

1

0

1

1

1

1

0

0

1

1

1

0

Implement the Boolean function using when and select statements.

Solution 2.2

With when statement, it can be implemented as

With select statement, it can be implemented as

Example 2.3

Implement the Boolean function $$ f\left( {x,y,z} \right) = x^{{\prime }} y^{{\prime }} + y^{{\prime }} z $$ using when statement.

Solution 2.3

First, let’s construct the truth table of the Boolean function $$ f\left( {x,y,z} \right) = x^{{\prime }} y^{{\prime }} + y^{{\prime }} z $$. If the Boolean function $$ f\left( {x,y,z} \right) = x^{{\prime }} y^{{\prime }} + y^{{\prime }} z $$ is inspected in details, we see that the function takes the value of 1 for $$ x = y = 0 $$ or for $$ y = 0,z = 1 $$. Considering this information, we can make the truth table of the given Boolean function as in Table 2.2.

Table 2.2

Truth table of $$ f = x^{{\prime }} y^{{\prime }} + y^{{\prime }} z $$

x

y

z

f (x, y, z)

0

0

0

1

0

0

1

1

0

1

0

0

0

1

1

0

1

0

0

0

1

0

1

1

1

1

0

0

1

1

1

0

Regarding the truth table, we can write VHDL program with when statement as in PR 2.2.

PR 2.2

Program 2.2

The program in PR 2.2 can also be written as in PR 2.3.

PR 2.3

Program 2.3

Example 2.4

We can implement the Boolean function $$ f\left( {x, y,z} \right) = x^{{\prime }} y^{{\prime }} + y^{{\prime }} z $$ using select statement as in PR 2.4.

PR 2.4

Program 2.4

Example 2.5

Implement the function in (2.1) using VHDL.

(2.1)

Solution 2.5

The real valued function given in the question can be implemented in VHDL as in PR 2.5.

PR 2.5

Program 2.5

2.2 Generate Statement

The VHDL statement generate is a concurrent statement. It is used to generate multiple instances of a program segment. The generate statement has two different forms which are unconditional generate and conditional generate. Let’s see these forms separately.

Unconditional Generate

The unconditional generate as its name implies has no conditional part. Its syntax is as follows:

The use of Label is a must in generate statement, and the word begin is used if declarative part is available in the generate statement.

Example 2.6

The generate statement in

is the same as the program segment

That is, the same digital logic circuit synthesized for both program segments.

Example 2.7

Write a VHDL statement that reverses the elements of an 8-bit logic vector.

Solution 2.7

Let x and y be an 8-bit vectors. We can reverse the content of vector x using the following VHDL statement:

Example 2.8

Write the previous example as a complete VHDL program.

Solution 2.8

The complete VHDL program is given in PR 2.6.

PR 2.6

Program 2.6

Parity Generator

The parity of the binary vector

(2.2)

is calculated as

(2.3)

where $$ \oplus $$ is the xor operation. Note that, xor is an odd function, i.e., if the number of ‘1’s in binary vector $$ \bar{x} $$ is an odd integer, then $$ p = 1 $$, otherwise $$ p = 0 $$.

Example 2.9

Write a VHDL statement that calculates the parity for 16-bit logic vector.

Solution 2.9

Let x_vec be a 16-bit vector, and parr_vec be another 16-bit vector. We can calculate the parity bit for x_vec using the following VHDL statement:

Example 2.10

Write the previous example as a complete VHDL program.

Solution 2.10

The complete VHDL program is given in PR 2.7.

PR 2.7

Program 2.7

Conditional Generate

The syntax of the conditional generate is as

where ‘condition’ must be a static expression.

Note: Note that in VHDL syntax $$ \left[ \cdots \right] $$ shows the optional part.

Example 2.11

Write a VHDL statement that checks a constant positive integer and detects whether it is an even or odd integer.

Solution 2.11

The VHDL program segment can be written as follows:

Example 2.12

Write the previous example as a complete VHDL program.

Solution 2.12

The complete program is depicted in PR 2.8.

PR 2.8

Program 2.8

Let’s see the VHDL implementation of some well-known combinational circuits which do not require a clock for the operation of the circuits.

2.3 Examples for Combinational Circuits Implemented in VHDL

In this section we will see the implementation of some well-known combinational circuits in VHDL.

Multiplexer

The black box representation of a $$ 2 \times 1 $$ multiplexer is depicted in Fig. 2.1.

Fig. 2.1

$$ 2 \times 1 $$ Multiplexer

The multiplexer can be considered as a traffic regulator for digital circuits. The truth table of a $$ 2 \times 1 $$ multiplexer is given in Table 2.3.

Table 2.3

Truth Table of the $$ 2 \times 1 $$ Multiplexer

S

f

x

y

S

f

0

x

→

0

0

0

0

1

y

0

0

1

0

0

1

0

0

0

1

1

1

1

0

0

1

1

0

1

0

1

1

0

1

1

1

1

1

Using the truth table given in Table 2.3, we can express the output of the $$ 2 \times 1 $$ multiplexer circuit in terms of the selection and input logics as

(2.4)

The internal circuit diagram of the black box in Fig. 2.1 is shown in Fig. 2.2.

Fig. 2.2

$$ 2 \times 1 $$ Multiplexer circuit diagram

There are a number of ways to implement a multiplexer in VHDL. Let’s see the implementation of a $$ 2 \times 1 $$ multiplexer in VHDL.

Example 2.13

Implement $$ 2 \times 1 $$ multiplexer in VHDL.

Solution 2.13

Considering Table 2.1, the output of the multiplexer can be expressed in terms of selection and input logics as

(2.5)

Using the expression in (2.5), we can implement the $$ 2 \times 1 $$ multiplexer as in PR 2.9.

PR 2.9

Program 2.9

Using the when VHDL statement we can implement $$ 2 \times 1 $$ multiplexer as in PR 2.10.

PR 2.10

Program 2.10

Or using the explicit form of the truth table in Table 2.3, we can implement the $$ 2 \times 1 $$ multiplexer using when statement as in PR 2.11.

PR 2.11

Program 2.11

If we use logic vector at the input port, we can write PR 2.11 as in PR 2.12.

PR 2.12

Program 2.12

Using the select statement , we can implement the $$ 2 \times 1 $$ multiplexer as in PR 2.13.

PR 2.13

Program 2.13

Example 2.14

Implement the digital circuit given in Fig. 2.3 in VHDL.

Fig. 2.3

Digital circuit for Example-2.14

Solution 2.14

We can write a Boolean function for the output of the multiplexer in terms of the circuit inputs, and use the written function for the implementation of the circuit in VHDL language. At the selection line of the multiplexer, we have the Boolean function $$ S = yz $$. The operation of the multiplexer can be described as

(2.6)

Then, the output of the multiplexer can be written as $$ f = S^{{\prime }} x + Sy $$ in which using $$ S = yz $$ we get

(2.7)

And using the obtained Boolean function , we can implement the circuit given in Fig. 2.3 as in PR 2.14.

PR 2.14

Program 2.14

Using the when VHDL statement, we can implement the circuit in Fig. 2.3 as in PR 2.15.

PR 2.15

Program 2.15

Using the select VHDL statement, we can implement the circuit in Fig. 2.3 as in PR 2.16.

PR 2.16

Program 2.16

Example 2.15

Implement the digital circuit shown in Fig. 2.4 in VHDL. Use when statement in your implementation.

Fig. 2.4

Digital circuit for Example 2.15

Solution 2.15

First we write the entity part of the program and define the port identities as in PR 2.17.

PR 2.17

Program 2.17

Next, the internal signals $$ f_{1} $$ and $$ f_{2} $$ are defined in the declarative part of the architecture unit as in PR 2.18.

PR 2.18

Program 2.18

The architecture part can be written in a number of different ways. The architecture part using the when statement is implemented in PR 2.19.

PR 2.19

Program 2.19

Note that the sequence orders of the statements in the architecture part of PR 2.19 is not important. Since all the statements in the architecture part are concurrently run. The architecture part of PR 2.19 can also be written as in PR 2.20.

PR 2.20

Program 2.20

Example 2.16

Implement the digital circuit shown in Fig. 2.5 in VHDL. Use when statement in your implementation.

Fig. 2.5

Digital circuit for Example 2.16

Solution 2.16

First, we define input output port parameters $$ x,y,f $$ in the entity part as in PR 2.21.

PR 2.21

Program 2.21

Second, we define the internal signals $$ sm, eq, gr, f_{1} $$ and $$ f_{2} $$ in the declarative part of the architecture unit as in PR 2.22.

PR 2.22

Program 2.22

In the final part, the body part of the architecture unit is written considering the operation of comparator and multiplexer units of the circuit in Fig. 2.5 as in PR 2.23.

PR 2.23

Program 2.23

$$ \mathbf {2 \times 1} $$ Multiplexer with bus inputs and outputs

Multiplexer inputs may accept logic vectors. The black box representation of a $$ 2 \times 1 $$ multiplexer accepting 8-bit logic vectors is shown in Fig. 2.6.

Fig. 2.6

$$ 2 \times 1 $$ multiplexer with $$ 8 $$-bit busses

Example 2.17

In PR 2.24 and 2.25, implementation of $$ 2 \times 1 $$ multiplexers accepting logic vectors are given.

PR 2.24

Program 2.24

PR 2.25

Program 2.25

In PR 2.25, in the port declarations, for the ports x and y, direction of the ports is not indicated. In this case, default direction, i.e., input, is accepted. And for the ports x, y and f the data type is integer, but, a range is not defined for the integer data type. In this case, the default range is accepted. The default range for the integers is the same as 32-bit signed integer range, i.e., from $$ - 2^{31} $$ to $$ 2^{31} - 1 $$.

4 × 1 Multiplexer

The black-box representation of $$ 4 \times 1 $$ multiplexer is shown in Fig. 2.7.

Fig. 2.7

$$ 4 \times 1 $$ multiplexer

The truth table of the $$ 4 \times 1 $$ multiplexer is depicted in Table 2.4 in two different ways.

Table 2.4

Truth table of $$ 4 \times 1 $$ multiplexer

S ₁

S ₀

f

w

x

y

z

S ₁

S ₀

f

0

0

f ₀

↔

0

0

0

0

0

0

0

0

1

f ₁

0

0

0

1

0

0

0

1

0

f ₂

0

0

1

0

0

0

0

1

1

f ₃

0

0

1

1

0

0

0

0

1

0

0

0

1

1

0

1

0

1

0

1

1

0

1

1

0

0

1

1

0

1

1

1

0

1

1

0

0

0

0

1

0

0

1

0

0

1

1

0

0

1

0

1

0

1

0

1

1

0

1

1

1

0

1

1

1

0

0

1

1

0

1

1

0

1

1

1

1

1

1

1

0

1

1

0

1

1

1

1

1

1

1

For a $$ 4 \times 1 $$ multiplexer, the internal circuit diagram is depicted in Fig. 2.8.

Fig. 2.8

Internal circuit for $$ 4 \times 1 $$ multiplexer

Example 2.18

Implement the $$ 4 \times 1 $$ multiplexer shown in Fig. 2.7 in VHDL language.

Solution 2.18

The implementation of $$ 4 \times 1 $$ multiplexer is given in PR 2.26.

PR 2.26

Program 2.26

Example 2.19

The $$ 4 \times 1 $$ multiplexer shown in Fig. 2.7 in can alternatively be implemented as in PR 2.27, 2.28, 2.29.

PR 2.27

Program 2.27

PR 2.28

Program 2.28

PR 2.29

Program 2.29

Example 2.20

Implement the 4 × 1 multiplexer shown in Fig. 2.7 in VHDL language. Use select statement for your implementation.

Solution 2.20

The VHDL implementation of $$ 4 \times 1 $$ multiplexer with select statement is depicted in PR 2.30.

PR 2.30

Program 2.30

Note that the use of others in with— select statement is a must, if all the conditions are not tested, for instance, we did not include “ZZ”, “WZ”, etc., in conditional expression, and in this case, others should be included in the last conditional expression.

Example 2.21

Implement the $$ 4 \times 1 $$ multiplexer whose inputs are 9-bit signed integers.

Solution 2.21

The VHDL implementation to $$ 4 \times 1 $$ multiplexer with 9-bit signed integers is depicted in PR 2.31.

PR 2.31

Program 2.31

Example 2.22

Convert the conditional when statement in PR 2.32 into a conditional select statement.

PR 2.32

Program 2.32

Solution 2.22

The conversion is outlined as follows.

(S1) First add with…select to the top as in PR 2.33.

PR 2.33

Program 2.33

(S2) Move the conditional parameter of when statement into the conditional parameter of select statement, and leave the numeric values of the conditional parameters of when as in PR 2.34.

PR 2.34

Program 2.34

(S3) Remove reserved word else and put a comma after each line except the last one as in PR 2.35.

PR 2.35

Program 2.35

(S4) Add the word when others to the last line as in PR 2.36.

PR 2.36

Program 2.36

Example 2.23

Implement the circuit shown in Fig. 2.9 in VHDL language. Use when statement in your implementation.

Fig. 2.9

Digital circuit for Example 2.23

Solution 2.23

Let $$ f_{0} $$ and $$ f_{1} $$ be the outputs of the OR and NOR gates respectively, and $$ I_{0} $$, $$ I_{1} $$, $$ I_{2} $$, $$ I_{3} $$ are the inputs of the 4 × 1 multiplexer as shown in Fig. 2.10. Note that $$ f_{0} $$, $$ f_{1} $$, $$ I_{0} $$, $$ I_{1} $$, $$ I_{2} $$ and $$ I_{3} $$ are nothing but internal signals of the circuit.

Fig. 2.10

Digital circuit with internal signals labeled

We define I/O signals of the circuit at the entity part, and define the internal signals at the declarative part of the architecture as in PR 2.37.

PR 2.37

Program 2.37

Considering Fig. 2.10, we can write the functions $$ f_{0} $$, $$ f_{1} $$, $$ I_{0} $$, $$ I_{1} $$, $$ I_{2} $$ and $$ I_{3} $$ as in

(2.8)

The implementation of the internals signals and circuit output can be written in the architecture part as indicated in PR 2.38.

PR 2.38

Program 2.38

Example 2.24

Implement the circuit shown in Fig. 2.10 in VHDL language. Use select statement in your implementation.

Solution 2.24

We can just convert the when statement of the previous solution as in PR 2.39.

PR 2.39

Program 2.39

Gray Code

Grad code is used to encode the integers $$ 0, 1, 2, \ldots ,15 $$. The binary strings used for encoding of consecutive numbers differ in only 1-bit location. The Gray coding is illustrated in Table 2.5.

Table 2.5

Gray code table

Number

Gray code

0

0000

1

0001

2

0011

3

0010

4

0110

5

0111

6

0101

7

0100

8

1100

9

1101

10

1111

11

1110

12

1010

13

1011

14

1001

15

1000

Example 2.25

Implement the Gray coding in VHDL language.

Solution 2.25

The Gray coding operation illustrated in Table 2.3 can be implemented as in PR 2.40.

PR 2.40

Program 2.40

Exercise

Implement the BCD code illustrated in Table 2.6.

Table 2.6

BCD code table

0 ↔ 0000

1 ↔ 0001

2 ↔ 0010

3 ↔ 0011

4 ↔ 0100

5 ↔ 0101

6 ↔ 0110

7 ↔ 0111

8 ↔ 1000

9 ↔ 1001

Octal Encoder : Encoders are employed to represent integers by binary strings. Binary encoders are used to represent integers by binary numbers expressed in base two. One of the binary encoders is the octal encoder. It is used to represent the integers $$ 0, 1, 2, \ldots ,7 $$. It accepts a digit in the range 0–7 and outputs a 3-bit binary string. The black box representation of octal encoder is depicted in Fig. 2.11.

Fig. 2.11

Octal encoder black box representation

Considering the operation of the octal encoder, we can construct its truth table as in Table 2.7.

Table 2.7

Octal encoder truth table

I ₇

I ₆

I ₅

I ₄

I ₃

I ₂

I ₁

I ₀

f ₂

f ₁

f ₀

0

0

0

0

0

0

0

1

0

0

0

0

0

0

0

0

0

1

0

0

0

1

0

0

0

0

0

1

0

0

0

1

0

0

0

0

0

1

0

0

0

0

1

1

0

0

0

1

0

0

0

0

1

0

0

0

0

1

0

0

0

0

0

1

0

1

0

1

0

0

0

0

0

0

1

1

0

1

0

0

0

0

0

0

0

1

1

1

Example 2.26

Implement the octal encoding operation in VHDL language.

Solution 2.26

The octal encoding operation illustrated in Table 2.5 can be implemented as in PR 2.41, 2.42 and 2.43. In PR 2.41, the implementation is performed using with-select statement. On the other hand, in PR 2.42 and 2.43, the implementation is done using the when statement.

PR 2.41

Program 2.41

PR 2.42

Program 2.42

PR 2.43

Program 2.43

Priority Encoder

In priority encoder , the integers to be encoded have different priorities. If a numbers of integers are to be encoded at the same time, then the number having the largest priority is encoded. Such encoders are called priority encoders.

The black box representation of a typical octal priority encoder is depicted in Fig. 2.12.

Fig. 2.12

Octal priority encoder black box representation

The operation of the octal priority encoder is illustrated in Fig. 2.13. Let’s assume that the integers 1, 3 and 5 are to be encoded at the same time. The integer 5 which has the highest priority is encoded as illustrated in Fig. 2.13.

Fig. 2.13

Operation of the octal priority encoder

The black box representation of a 4-bit priority encoder with valid output indicator bit, i.e., bit $$ v $$, is depicted in Fig. 2.14.

Fig. 2.14

4-bit priority encoder black box representation

The truth table of the 4-bit priority encoder with valid result indicator is shown Table 2.8.

Table 2.8

Truth table of 4-bit priority encoder

I ₃

I ₂

I ₁

I ₀

x

y

z

1

×

×

×

1

1

1

0

1

×

×

1

0

1

0

0

1

×

0

1

1

0

0

0

1

0

0

1

0

0

0

0

×

×

0

Example 2.27

Implement the $$ 4 $$-bit priority encoder, whose truth table is shown Table 2.8, in VHDL language.

Solution 2.27

The priority encoding operation illustrated in Table 2.8 can be implemented as in PR 2.44. For the don’t care condition, we use ‘−’ symbol, for instance “$$ 1 \times \times \times $$” can be implemented in VHDL as “$$ 1 - - - $$”.

PR 2.44

Program 2.44

Binary Coded Decimal (BCD) Encoding

BCD encoding is used to encode only the digits, $$ 0, 1, 2, \ldots ,9 $$. It is not used to encode the numbers greater than $$ 9 $$. The BCD encoding logic is illustrated in Table 2.9.

Table 2.9

BCD encoding operation

0 ↔ 0000

1 ↔ 0001

2 ↔ 0010

3 ↔ 0011

4 ↔ 0100

5 ↔ 0101

6 ↔ 0110

7 ↔ 0111

8 ↔ 1000

9 ↔ 1001

Decoders

The task of the decoders is the opposite of that of the encoders. The codeword, i.e., binary string, is resolved to the character it represents. The encoder and decoder units are designed in a coherent manner to each other. One of the decoders used in digital design is the BCD decoder whose black box representation is depicted in Fig. 2.15.

Fig. 2.15

BCD decoder black box representation

The operation of the BCD decoder is illustrated in Fig. 2.16 where at the input of the decoder we have a codeword, and at the output of the decoder the integer represented by the codeword is indicated by the logic value ‘1’.

Fig. 2.16

Operation of BCD decoder

As it is seen from Fig. 2.16, the codeword ‘0101’ when resolved activates the output port indexed by 5. That means that the codeword ‘0101’ represent the integer 5.

Example 2.28

Implement the BCD decoder in VHDL language.

Solution 2.28

Referring to Table 2.9, BCD decoder can be implemented in VHDL language as in PR 2.45.

Table 2.10

BCD and SS display codes

Digit

BCD code

Seven segment display code

wxyz

abcdefg

0

0000

0000001

1

0001

1001111

2

0010

0010010

3

0011

0000110

4

0100

1001100

5

0101

0100100

6

0110

0100000

7

0111

0001111

8

1000

0000000

9

1001

0000100

PR 2.45

Program 2.45

BCD-to-Seven Segment Display Converter

The seven segment display an electronic unit is used to display the digits $$ 0, 1, \ldots ,9 $$. The symbolic representation of seven segment display is depicted in Fig. 2.17.

Fig. 2.17

Seven segment display symbolic representation

The BCD codes representing digits and their corresponding seven segment display codes are depicted in Table 2.10.

Example 2.29

Implement the BCD to Seven Segment Display Converter in VHDL language.

Solution 2.29

Referring to Table 2.10, BCD to Seven Segment Display Converter in VHDL language can be implemented as in PR 2.46.

PR 2.46

Program 2.46

Problems

(1)

Implement the Boolean function $$ f = x^{\prime}y + xz + y^{\prime}z $$ in VHDL.

(2)

Implement the hexadecimal binary encoder in VHDL.

(3)

Implement the hexadecimal binary decoder in VHDL.

(4)

Implement the truth table of the Boolean function given in Table 2.P4 in VHDL.

Table 2.P4

Truth table of a Boolean function

xyz

f (x,y,z)

000

1

001

1

010

0

011

1

100

1

101

0

110

1

111

1

(5)

Implement the combinational circuit shown in Fig. 2.P5 in VHDL.

Fig. 2.P5

A combinational circuit diagram

(6)

Implement the combinational circuit shown in Fig. 2.P6 in VHDL.

Fig. 2.P6

Combinational circuit with a multiplexer

(7)

Implement the combinational circuit shown in Fig. 2.P7 in VHDL.

Fig. 2.P7

Multiplexer circuit

(8)

Implement the combinational circuit shown in Fig. 2.P8 in VHDL.

Fig. 2.P8

Combinational circuit involving multiplexer and de-multiplexer

(9)

Implement the combinational circuit shown in Fig. 2.P9 in VHDL

Fig. 2.P9

1-bit arithmetic logic unit

© Springer Nature Singapore Pte Ltd. 2019

Orhan GaziA Tutorial Introduction to VHDL Programminghttps://doi.org/10.1007/978-981-13-2309-6_3

3. Simulation of VHDL Programs

Orhan Gazi1 

(1)

Department of Electronics and Communication Engineering, Çankaya University, Ankara, Turkey

In this chapter we will give information about the simulation of VHDL programs . Once we implement a digital circuit or an algorithm in VHDL language, we need to check the correctness of the implementation. For this purpose, we write test programs which are used to supply values to the input ports of the VHDL program, and it is possible to observe the values at the output ports. The test program written to simulate the input and output behavior of the VHDL programs is usually called test-bench .

If we cannot observe the expected output values for the supplied input values, we decide that the written VHDL program has some bugs inside, and we check the written program for possible mistakes. We repeat this procedure until we observe the expected values at output ports for the supplied input values.

3.1 Test-Bench Writing

The best way to learn how to write a test-bench passes through an example. Let’s illustrate how to write a test-bench with the following example.

Example 3.1

Write a test-bench for the simulation of the Boolean function $$ f\left( {x,\,y,\,z} \right) = x^{\prime } y^{\prime } + y^{\prime } z $$ implemented in VHDL.

Solution 3.1

First, we implement the Boolean function as in PR 3.1.

PR 3.1

Program 3.1

To test the VHDL program given in PR 3.1, we can write a test-bench considering the following steps.

(S1) In Step-1, we write an empty entity part as in PR 3.2. The name of the entity for the test-bench can be chosen anything, however, the convention is to add the suffix _TB to the end of the entity name of the VHDL unit to be tested, i.e., for this example it is formed as f_xyz_TB.

PR 3.2

Program 3.2

(S2) In Step-2, we add the structure of the architecture unit as in PR 3.3 where declarative part, the part between architecture and begin, and the body part, the part between begin and end architecture, of the architecture unit are displayed empty.

PR 3.3

Program 3.3

(S3) In Step-3, we copy the entity unit of the main program to be tested to the declarative part of the architecture unit as in PR 3.4.

PR 3.4

Program 3.4

(S4) In Step-4, in the copied entity unit of PR 3.4, change the word entity to component, and drop the word is as in PR 3.5. Note that it is optional to drop the word “is” from the end of the component name, it can be kept as well.

PR 3.5

Program 3.5

(S5) In Step-5, the initial values to be supplied to the input ports are placed below the component declaration in the declarative part of the architecture unit as in PR 3.6. The name of the parameters to supply the initial input port values can be the same as the port input names, or they can be chosen differently. In PR 3.6 we used port input names for the parameter names.

PR 3.6

Program 3.6

(S6) In Step-6, Component instantiation is done in the body part of the architecture unit as seen in PR 3.7, and the initial values to be supplied to the input ports are send to the input ports using the port map statement as in PR 3.7.

PR 3.7

Program 3.7

If we had used different names for the initialization parameters other than the same port names, then we would write our program as in PR 3.8.

PR 3.8

Program 3.8

Note that in the assignments y <= x and w => z, the values are at the right and the destination parameters are on the left hand side.

(S7) After initial value supplement stage, in Step-7, we provide different input values to the input ports. For this purpose, we use process units of the VHDL language. We can write more than one process units to provide values to the input ports. Keep in your mind that process units are sequential program units , and if more than one process is written, they are run in parallel, although they are sequential inside. In PR 3.9, we used a single process unit with simulation values.

PR 3.9

Program 3.9

The wait statement at the end of process unit guarantees the simulation to be performed once for the supplied values. If wait statement is not placed at the end of process unit, then the simulation is repeated over and over again with the same simulation values, and the simulation graph shows the simulation results in a periodic manner, i.e., the same graph is repeated in time.

We can use three process units to provide the values for the input ports as in PR 3.10. In fact, we can use any number of process units.

PR 3.10

Program 3.10

The test-bench shown in PR 3.10 can be used for simulation purposes. For illustration purposes, we used the XILINX ISE platform for the simulation process. In XILINX ISE platform, it is possible to see the simulation results as time waveforms. For our test-bench, the simulation results are expressed as time waveforms in Fig. 3.1 where the grey areas indicate the logic ‘1’.

Fig. 3.1

Test-bench simulation results in XILINX ISE platform

The truth table of the Boolean function $$ f\left( {x, y,z} \right) = x^{\prime } y^{\prime } + y^{\prime } z $$ is shown in Table 3.1.

Table 3.1

Truth table of $$ f = x^{\prime } y^{\prime } + y^{\prime } z $$

x

y

z

f(x, y, z)

0

0

0

1

0

0

1

1

0

1

0

0

0

1

1

0

1

0

0

0

1

0

1

1

1

1

0

0

1

1

1

0

If Table 3.1 is compared to the simulation parameter values in PR 3.10, it is seen that the simulation values in PR 3.10 are nothing but the values taken from the truth table converted to time waveforms using the wait for statement.

The test-bench in PR 3.10 can also be written as in PR 3.11 where it is seen that we use the same input port names for the names of the initialization parameters.

PR 3.11

Program 3.11

Example 3.2

The black box representation of a $$ 2 \times 1 $$ multiplexer is depicted in Fig. 3.2.

Fig. 3.2

The black box representation of a $$ 2 \times 1 $$ multiplexer

Assume that the multiplexer inputs are 32-bit signed integers, i.e., x and y are 32-bit signed integers. Implement the multiplexer in VHDL, and write a test-bench for the simulation of the written VHDL program.

Solution 3.2

Using the when VHDL statement we can implement the 2 × 1 multiplexer as in PR 3.12.

PR 3.12

Program 3.12

To test the VHDL program given in PR 3.12, we can write a test-bench considering the following steps.

(S1) In Step-1, we write an empty entity part as in PR 3.13. The name of the entity for the test-bench can be chosen anything, however, the convention is to add the suffix _TB to the end of the entity name of the VHDL unit to be tested.

PR 3.13

Program 3.13

(S2) In Step-2, we add the structure of the architecture unit as in PR 3.14 where declarative part, the part between architecture and begin, and the body part, the part between begin and end architecture, of the architecture unit are displayed empty.

PR 3.14

Program 3.14

(S3) In Step-3, we copy the entity unit of the main program to be tested to the declarative part of the test-bench as in PR 3.15.

PR 3.15

Program 3.15

(S4) In Step-4, in the copied entity unit of PR 3.15, change the word entity to component, and we can drop the word is as in PR 3.16. Note that dropping the word “is” is not a must.

PR 3.16

Program 3.16

(S5) In Step-5, the initial values to be supplied to the input ports are placed below the component declaration in the declarative part of the architecture unit as in PR 3.17. The name of the parameters to supply the initial input port values can be the same as the port input names, or they can be chosen differently. In PR 3.17 we used port input names for the parameter names.

PR 3.17

Program 3.17

(S6) In Step-6, Component instantiation is done in the body part of the architecture unit as seen in PR 3.18, and the initial values to be supplied to the input ports are send to the input ports using the port map statement as in PR 3.18.

PR 3.18

Program 3.18

If we had used different names for the initialization parameters other than the same port names, then we would write our program as in PR 3.19.

PR 3.19

Program 3.19

(S7) After initial value supplement stage, in Step-7, we provide different input values to the input ports. For this purpose, we use process units of the VHDL language. A single process unit with simulation values is shown in PR 3.20.

PR 3.20

Program 3.20

The test-bench shown in PR 3.20 can be used for simulation purposes. For this purpose, we can use any simulation platform released by companies, for instance XILINX ISE platform, or XILINX Vivado platform. The test-bench in PR 3.20 can also be written as in PR 3.21 where it is seen that we used the same input port names for the names of the initialization parameters.

PR 3.21

Program 3.21

It is possible to create the test-bench using the XILINX ISE platform. However, in this case a template is created, and the data types of the inputs ports of the entity to be tested may not comply to the data types of the component unit created automatically by the ISE platform. In such a case, manual correction should be performed on the created test-bench file. For instance, for the 2 × 1 integer multiplexer implemented in PR 3.12, the test-bench file automatically created by ISE platform is depicted in PR 3.22.

PR 3.22

Program 3.22

However, when PR 3.22 is inspected, it is seen that the automatically created test-bench file needs serious modification so that it can be for testing of PR 3.22.

Exercise: Implement the 4 × 1 multiplexer shown in Fig. 3.3 in VHDL and write a test-bench for the testing of the written implementation. Obtain the simulation waveforms using any simulation platform.

Fig. 3.3

4 × 1 multiplexer

Example 3.3

Implement the 4-bit priority encoder, whose truth table is given in Table 3.2, in VHDL language and write a test-bench for the written implementation.

Table 3.2

Truth table of 4-bit priority encoder

I ₃

I ₂

I ₁

I ₀

x

y

z

1

x

x

x

1

1

1

0

1

x

x

1

0

1

0

0

1

x

0

1

1

0

0

0

1

0

0

1

0

0

0

0

x

x

0

Solution 3.3

The priority encoding operation illustrated in Table 3.2 can be implemented as in PR 3.23. For the don’t care condition, we use ‘-’ symbol, for instance “1 ×××” can be implemented in VHDL as “$$ 1 - - - $$”.

PR 3.23

Program 3.23

Test-bench for VHDL program in PR 3.23 can be written as in PR 3.24.

PR 3.24

Program 3.24

Problems

(1)

The truth table of a Boolean function is shown in Table 3.P1. Implement the given truth table in VHDL and write a test-bench for this implementation.

Table 3.P1

The truth table of a Boolean function

x

y

z

f(x, y, z)

0

0

0

0

0

0

1

1

0

1

0

0

0

1

1

1

1

0

0

1

1

0

1

0

1

1

0

0

1

1

1

1

(2)

The truth table of a Boolean function is shown in Table 3.P2. Implement the given truth table in VHDL and write a test-bench for this implementation.

Table 3.P2

The truth table of a Boolean function

x

y

z

f(x, y, z)

0

0

0

1

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

0

(3)

Consider the BCD to Seven Segment Display code converter. Implement the BCD to Seven Segment Display code converter in VHDL and write a test-bench for this implementation.

(4)

Implement the Boolean function $$ f\left( {w,x,y,z} \right) = y^{{\prime }} z^{{\prime }} + yz + w^{{\prime }} z $$ in VHDL, and obtain the truth table of the function, and write a test-bench for the VHDL this implementation, and use the truth table while deciding on the values of the simulation parameters of the test-bench.

(5)

The truth table of a Boolean function is shown in Table 3.P3. Implement the given truth table in VHDL and write a test-bench for this implementation.

Table 3.P3

The truth table of a Boolean function employing four variables

w

x

y

z

f(x, y, z)

0

0

0

0

0

0

0

0

1

0

0

0

1

0

0

0

0

1

1

1

0

1

0

0

0

0

1

0

1

1

0

1

1

0

1

0

1

1

1

1

0

0

0

0

1

0

0

1

1

1

0

1

0

0

1

0

1

1

1

1

1

0

0

1

1

1

0

1

0

1

1

1

0

0

1

1

1

1

1

(6)

Obtain the truth table of the logic circuit depicted in Fig. 3.4. Implement the circuit in VHDL and write a test-bench for this implementation.

Fig. 3.4

Logic circuit for Problem-5

© Springer Nature Singapore Pte Ltd. 2019

Orhan GaziA Tutorial Introduction to VHDL Programminghttps://doi.org/10.1007/978-981-13-2309-6_4

4. User Defined Data Types, Arrays and Attributes

Orhan Gazi1  

(1)

Department of Electronics and Communication Engineering, Çankaya University, Ankara, Turkey

Orhan Gazi

Email: o.gazi@cankaya.edu.tr

It is vital for a programmer to have a good knowledge of data types and arrays together with the attributes to be able to write qualified programs. In this chapter we will first provide information about defining the data types other than the standard ones available in VHDL libraries, and then the use of arrays together with the attributes will be explained in details with sufficient number of examples.

4.1 User Defined Data Types

In addition to standard data types, such as integer, std_logic, bit, etc., we can define our own data types to be used in VHDL programming. The user defined data types are described using the VHDL statement type. The syntax of the type is as follows:

User defined data types are usually defined in the declarative part of the architecture unit, or it is defined in the packet unit.

Example 4.1

In PR 4.1, we define a new data type and use it to declare a signal object.

PR 4.1

Program 4.1

4.1.1 Enumerated Types

User defined enumerated data types are usually employed for the implementation of finite state machines in VHDL language. User defined enumerated data types can be considered as a set of logic values defined by the user. The syntax of the user defined enumerated data types is as follows:

Example 4.2

In PR 4.2, we define a new enumerated data type and use it in the declaration of a signal object.

PR 4.2

Program 4.2

Example 4.3

In PR 4.3, we define an enumerated data type called states, and use it in the declaration of a signal object.

PR 4.3

Program 4.3

4.2 User Defined Array Data Types

We have already seen the data types, std_logic_vector, bit_vector, and these vectors are nothing but arrays of std_logic, and bit data types. We can define the vectors or arrays for the other standard data types or for the user defined data types. Arrays can be defined in two different methods. One of them is the constrained arrays whose declaration includes the explicit declaration of the array size, i.e., the array size, a fixed number, is included in the type definition.

4.2.1 Constrained Arrays

The syntax of the user defined constrained array data types is as follows.

Example 4.4

In PR 4.4, we define an integer vector of length 8, and use it in the body of the architecture part.

PR 4.4

Program 4.4

Example 4.5

In PR 4.5, we define a vector whose elements are std_logic_vector of length 8, and use it in the body of the architecture part.

PR 4.5

Program 4.5

Accessing to the elements of an array is achieved using the index of the elements. If x is an array, then x(indx) is the element of array at the position indx. Example 4.6 illustrates the concept.

Example 4.6

Accessing to the elements of arrays is illustrated in PR 4.6.

PR 4.6

Program 4.6

4.2.2 Unconstrained Arrays

In unconstrained array definitions, the size of the array is not a deterministic value, i.e., undefined length. The syntax of the unconstrained array definition is as

where “natural range <>” implies that the range limits of the array must fall within the natural number range. We can also use positive, or integer instead of natural in array declaration, i.e., we can also have

Example 4.7

In PR 4.7 we define integer vectors of different lengths in the declarative part of the architecture and use them in the body part of the architecture.

PR 4.7

Program 4.7

Example 4.8

In PR 4.8 we define two vectors whose elements are logic vectors of length 8.

PR 4.8

Program 4.8

4.2.3 Defining PORT Arrays

As we have seen in our previous examples, we can use data types std_logic_vector, and bit_vector at the port inputs and outputs. If we want to use user defined data vectors at the port inputs and outputs, we need to define these vectors before the entity unit of the VHDL program. This is possible if we define user defined vector data types in the package unit which comes before the entity unit of the VHDL program. The package unit can be written in a different file or it can be written in the same file with the entity unit. In both cases, we need to add the sentence

before the entity unit.

Example 4.9

Write a VHDL program that inputs an integer vector of length 8 and adds 2 to the every element of the vector and sends it to the output port whose data type is integer vector of length 8.

Solution 4.9

In PR 4.9, we wrote the package and entity units in the same file. However, after package declaration we included the sentence use work.my_data_type.all so that we can use the defined data types declared in package unit.

PR 4.9

Program 4.9

Example 4.10

Write a VHDL program that inputs a 4 × 4 logic matrix and sends it to an output port.

Solution 4.10

In PR 4.10, we wrote the package and entity units in the same file. After package declaration, we include use work.my_data_type.all so that we can use the defined data types declared in package unit.

PR 4.10

Program 4.10

The body part of the architecture unit of PR 4.10 can also be written using the generate statement as in PR 4.11.

PR 4.11

Program 4.11

4.3 Defining 2D Arrays or Matrices

2D arrays can be considered as matrices . We can consider a matrix as a column vector whose elements are nothing but row vectors and vice versa, or we can consider a matrix as table of numbers and the table elements are accessed using the corresponding row and column indexes. The formation of matrix logic is illustrated in Fig. 4.1.

Fig. 4.1

Interpretation of a matrix in different ways

Now, considering a matrix as a column whose elements are row vectors, i.e., row vectors are concatenated in column wise manner as depicted in Fig. 4.1a, we will study its implementation in VHDL language. For such kind of implementation, we will use the type statement.

4.3.1 Matrix as Column Wise Concatenated Row Vectors

Example 4.11

Define a matrix data type of size $$ N \times M $$.

Assuming that N and M are static numbers, we can define the logic matrix of size $$ N \times M $$ as in PR 4.12.

PR 4.12

Program 4.12

Example 4.12

Write a VHDL program that inputs an $$ N \times M $$ logic matrix and sends it to an output port. Consider the matrix as concatenation of row vectors .

Solution 4.12

We cannot get the matrix sizes from input ports. They should be static. We can define them as constant number in the package unit and use them later as in PR 4.13.

PR 4.13

Program 4.13

Once we define a matrix as concatenation of row vectors, we can access to the elements or rows of the matrix as in PR 4.14.

PR 4.14

Program 4.14

4.3.2 Matrix as Table of Numbers

A matrix of size $$ N \times M $$ can be defined using the syntax

Example 4.13

Define a matrix of size 3 × 4. The elements of the matrix are the std_logic.

Solution 4.13

The solution is provided in PR 4.15.

PR 4.15

Program 4.15

Example 4.14

In PR 4.16, we define a constant matrix of size 3 × 4 and read its elements.

PR 4.16

Program 4.16

Example 4.15

We can define a matrix of size 3 × 4 using unconstrained matrix declaration as in PR 4.17. The elements of the matrix are the std_logic.

PR 4.17

Program 4.17

Solution 4.15

The solution is provided in PR 4.17.

4.3.3 3D Arrays

Vector of 2D Arrays, i.e., array of 2D arrays, can be considered as 3D arrays . Following the same logic, we can also define 4D, 5D, … arrays. Let’s illustrate the concept with an example.

3D arrays can be defined with two different approaches. In the first approach, we define the 3D array via vector of matrices. In the second approach, we define 3D arrays as 3 dimensional table of integers.

Example 4.16

Declaration of 2D, 3D, and 4D arrays can be done as in PR 4.18.

PR 4.18

Program 4.18

Example 4.17

In PR 4.19, type declarations for complex number arrays are given. The real and imaginary parts of the complex numbers are integers.

PR 4.19

Program 4.19

4.4 Subtypes

A subtype declaration does not introduce a new type. Although operations are not allowed between different data types, they are allowed between a type and its subtype. Subtype data declarations are usually done in the declarative part of the architecture or in the package unit. The syntax of the subtype declaration is as:

The type of a subtype is the same type as its base type. When objects of a subtype and its base type are assigned to each other, no type conversion is needed.

Example 4.18

In PR 4.20, we provide some examples for subtype declarations.

PR 4.20

Program 4.20

4.4.1 Type Conversion

A binary string may represent, a std_logic_vector, an unsigned bit vector, a signed bit vector, an integer, a natural, or a positive data. It is possible to convert a binary string, or bit vector, from a data type to the other via casting operation. The following example illustrates the concept clearly.

Example 4.19

In PR 4.21, type conversion operation is illustrated. In PR 4.21 we included numeric_std package at the top of the program. This packet is needed for the conversions from std_logic_vector to unsigned from std_logic_vector to signed data types.

PR 4.21

Program 4.21

Example 4.20

If a, b and c are of signed data type and d is of std_logic_vector data type, then for the conversion

we need the numeric_std package in our program. On the other hand, if

then for the conversion

we need to include std_logic_arith package in our program.

There are also type conversion functions available. Some of these functions can be outlined as follows:

4.5 Attributes of Data Types

Attributes can be considered for scalar, array, and signal objects separately.

4.5.1 Attributes for Scalar Data Types

We can define a scalar data type using

such as

or we can already use a pre-defined data type T such as natural. For a scalar data type T, we have the attributes in Table 4.1.

Table 4.1

Attributes for scalar data types

Attribute

Result

T’left

is the leftmost value of data type T

T’right

is the rightmost value of data type T

T’high

is the largest value of data type T

T’low

is the smallest value of data type T

T’pos(x)

is the index of value x in the data type T

T’val(x)

is the value whose index in the data type T is x

T’value(x)

is the value of data type T converted from string x

T’leftof(x)

is the value one position to the left of x

T’rightof(x)

is the value one position to the right of x

T’succ(x)

is the value at position one greater than position of x in T

T’pred(x)

is the value at position one less than position of x in T

T’ascending

is true of the range of T is ascending, false otherwise

T’base

is the base type of the type T

T’image(x)

is a string representation of x of data type T

For ascending ranges, we have

and for descending ranges, we have

Example 4.21

In PR 4.22, we define a new data type and use it to illustrate the attributes.

PR 4.22

Program 4.22

Example-4.22

In PR 4.23, we define a new data type and use it to illustrate the attributes.

PR 4.23

Program 4.23

Note that in PR 4.22 and PR 4.23 we made multiple assignments to the same signal object for illustrative purposes, in fact, only a signal assignment is allowed to a signal object in the body of the architecture unit.

4.5.2 Attributes for Array Data Types

Let A be an object whose data type is array. Then, for this object we have the attributes listed in Table 4.2.

Table 4.2

Attributes for array data types

Attribute

Result

A’left

leftmost index of array range

A’right

rightmost index of array range

A’low

smallest index value of the array range

A’high

largest index value of the array range

A’range

index range of the array

A’reverse_range

reverse of the array range

A’length

the length of the array range

A’ascending

true if index range is ascending, otherwise it is false

Example 4.23

In PR 4.24, we define a new array data type and use it to illustrate the attributes.

PR 4.24

Program 4.24

A multi-dimensional array A have the attributes listed in Table 4.3.

Table 4.3

Attributes for multi-dimensional arrays

Attribute

Result

A’left(n)

leftmost index of array range for the nth dimension

A’right(n)

rightmost index of array range for the nth dimension

A’low(n)

smallest index value of the array range for the nth dimension

A’high(n)

largest index value of the array range for the nth dimension

A’range(n)

index range of the array for the nth dimension

A’reverse_range(n)

reverse of array range for the nth dimension

A’length(n)

the length of array range for the nth dimension

A’ascending(n)

for the nth dimension, true for ascending array, otherwise it is false

Example 4.24

In PR 4.25, we define two dimensional array data type and use it to illustrate the attributes.

PR 4.25

Program 4.25

Example 4.25

In PR 4.26, part of the previous example is available in a complete VHDL program.

PR 4.26

Program 4.26

4.5.3 Attributes for Signal Objects

If S is a signal object , then we can define the attributes in Table 4.4 for the given signal object.

Table 4.4

Attributes for signal objects

Attribute

Result

S’active

true if a transaction is scheduled for S, false otherwise

S’last_event

is the amount of time passed since the last event on signal S

S’last_active

is the amount of time passed since signal S was last active

S’last_value

is the previous value of signal S before the last event

S’event

is true if an event has occurred on S in the current simulation cycle

S’transaction

is a bit that toggles as S becomes active in the current simulation cycle

S’quiet

is true if no event occurs on S during the current simulation cycle

S’stable

is true if no event has occurred on S during the current simulation cycle

S’delayed(T)

is the value of S at time t-T, i.e., value of the S delayed by T

S’stable(T)

is true if no event has occurred on S during the last T units of time

S’quiet(T)

is true if there has been no transaction on S during the last T units of time

Example 4.26

In PR 4.27, different VHDL statements for the rising edge detection of a clock signal are provided.

PR 4.27

Program 4.27

From the VHDL statements in PR 4.27 for the rising edge detection of a clock signal, the most commonly used one is

Example 4.27

In PR 4.28, different VHDL statements for the falling edge detection of a clock signal are provided.

PR 4.28

Program 4.28

Problems

(1)

Define a data type for complex numbers.

(2)

Define an array for a complex number vector.

(3)

What is the difference between a constrained array and an unconstrained array.

(4)

Define an unconstrained 3D array of complex numbers.

(5)

Define a matrix for complex numbers.

(6)

Find the mistake in the following declaration.

(7)

Is there any mistake in the following declaration

(8)

Consider the VHDL program in PR 4.P1, trace the program and find the values of row_vector1, row_vector2, a, b, c, data_matrix3(10 downto 7).

PR 4.P1

Program 4P1

© Springer Nature Singapore Pte Ltd. 2019

Orhan GaziA Tutorial Introduction to VHDL Programminghttps://doi.org/10.1007/978-981-13-2309-6_5

5. Sequential Circuit Implementation in VHDL

Orhan Gazi1  

(1)

Department of Electronics and Communication Engineering, Çankaya University, Ankara, Turkey

Orhan Gazi

Email: o.gazi@cankaya.edu.tr

In this chapter we will explain the implementation of sequential logic circuits in VHDL. Implementation of clocked or sequential logic circuits differ from the implementation of combinational logic circuits in the type of VHDL coding. The sequential logic circuits as its name implies works in a sequential manner, and the sequence of operations are controlled by a periodic signal called clock. The VHDL codes written for the implementation of the sequential logic circuits works in a sequential manner. On the other hand, the VHDL codes written for the implementation of the combinational logic circuits work in a parallel manner, i.e., work in a concurrent manner.

5.1 Sequential Circuits in VHDL

Digital logic circuits can be divided into two main categories. The first one is the combinational logic circuits, the second one is the synchronous sequential logic circuits, i.e., clocked circuits.

In concurrent coding, we can use the VHDL statements when, select..with, generate. On the other hand, in sequential coding, the statements if, wait, loop, and case are employed.

The implementation of the combinational logic circuits is done in the architecture unit of the VHDL program, and combinational circuits are implemented using concurrent VHDL codes. On the other hand, sequential logic circuits are implemented using sequential program units. These sequential units are process, function, and procedure. The process unit is usually considered to be used in the architecture part of the VHDL module, whereas, the function, and procedure units are usually employed inside the packet unit.

5.1.1 Process

The syntax of the process unit is as illustrated in PR 5.1.

PR 5.1

Program 5.1

A process is used to implement a sequential logic circuit. Whenever a parameter in the sensitivity list of the process changes, the process is executed. The variable object if needed can be used in the declaration and body part of the process. Declaration of the signal objects are not allowed inside processes.

As mentioned previously if, wait, for, loop, and case statements are used inside the sequential program units.

5.1.2 IF Statement

The if statement is used to check the conditions. The syntax of the if statement is as follows:

Let’s see the implementation of some of the sequential logic circuits in VHDL language.

5.2 Example Implementations for Sequential Logic Units

In this section, we will provide some examples for the implementation of some well-known clocked logic units.

5.2.1 D-Type Flip Flop

Example 5.1

The symbolic representation of the positive edge triggered D-type flip flop is shown in Fig. 5.1.

Fig. 5.1

The symbolic representation of the positive edge triggered D-type flip flop

The characteristic table of the D-type flip flop is depicted in Table 5.1.

Table 5.1

The characteristic table of the D-type flip flop

Implement the positive edge triggered D-type flip flop in VHDL language.

Solution 5.1

The implementation of the positive edge triggered D-type flip flop is given in PR 5.2.

PR 5.2

Program 5.2

The triggering condition

of the D-type flip-flop can be replaced by

In this case, PR 5.2 happens to be as in PR 5.3.

PR 5.3

Program 5.3

Example 5.2

If a reset control is added to the D-type flip flop as shown in Fig. 5.2, then the implementation of the D-type flip flop with synchronous reset can be done as in PR 5.4 and with asynchronous reset it can be implemented as in PR 5.5.

Fig. 5.2

D-type flip flop with reset input

PR 5.4

Program 5.4

PR 5.5

Program 5.5

Example 5.3

If the D-type flip flop includes both reset and set controls as shown in Fig. 5.3, then the implementation of the D-type flip flop happens to be as in PR 5.6.

Fig. 5.3

D-type flip flop with reset and set inputs

PR 5.6

Program 5.6

We can, although not very necessary, use the if statement for the implementation of the combinational circuits in VHDL language. Let’s illustrate this with an example.

5.2.2 Multiplexer

Example 5.4

Implement the $$ 4 \times 1 $$ multiplexer shown in Fig. 5.4 using the if-then-else statement.

Fig. 5.4

$$ 4 \times 1 $$ multiplexer symbolic representation

Solution 5.4

The implementation of $$ 4 \times 1 $$ multiplexer shown in Fig. 5.4 is depicted in PR 5.7 with a process unit.

PR 5.7

Program 5.7

5.2.3 JK and T Flip-Flops

Example 5.5

The black box representation of positive and negative edge triggered JK and T flip-flops are depicted in Fig. 5.5, and the excitation tables of JK and T flip-flops are shown in Table 5.2. Implement the JK and T flip-flops in VHDL.

Fig. 5.5

JK and T flip-flops

Table 5.2

Excitation lists of JK and T flip-flops

Solution 5.5

The implementation of positive edge triggered JK flip flop is provided in PR 5.8.

PR 5.8

Program 5.8

The implementation of positive edge triggered T flip flop is provided in PR 5.9.

PR 5.9

Program 5.9

The implementation of negative edge triggered JK and T flip-flops is very similar to PR 5.9. The only exception is that instead of “rising_edge(clk)”, we should use “falling_edge(clk)” in the “if” statement.

5.2.4 Counter

An N-bit counter, whose symbolic representation is depicted in Fig. 5.6, is a digital circuit that increments the integer at its output at every clock pulse.

Fig. 5.6

Symbolic representation of N-bit counter

Example 5.6

Implement a 4-bit counter in VHDL language.

Solution 5.6

A 4-bit counter can be implemented in a number of ways as in PR 5.10, 5.11, and 5.12.

PR 5.10

Program 5.10

PR 5.11

Program 5.11

PR 5.12

Program 5.12

If we use std_logic_vector for counter data type as in PR 5.12, then we need to initialize it at the declarative part of the architecture to see the simulation results. Otherwise, we cannot observe the counter increment. Since, the default value of any data type is its leftmost value. For std_logic, the leftmost value is ‘U’.

5.2.5 Clock Divider (Frequency Divider)

Clock generation at the desired frequency is a very important concept for the design of sequential logic units. For this reason, we advise the reader study and understand very well the topics explained in this section.

We can use the counters to generate different square pulse trains with different frequencies. The output pins of an l-bit counter can be used as a frequency divider circuit. If the clock frequency of the counter is f Hz, then at the most significant bit, i.e., $$ (l - 1)^{th} $$ bit, of the counter, we have a pulse train of frequency $$ f/2^{l} $$. This situation is illustrated in Fig. 5.7.

Fig. 5.7

Frequency division using an l-bit counter

Using l bits we can generate the integers in the range 0 to $$ 2^{l - 1} $$. For instance when $$ l = 3 $$, we can generate the integers $$ 0, 1, 2, 3, \ldots ,7 $$. To construct a 0 to $$ K - 1 $$ counter such that $$ K &lt; 2^{l - 1} $$, the counter device needs a reset when the binary equivalent of integer K is available at the l-bit counter output. For instance, for $$ l = 3 $$, a 0–5 counter can be constructed as in Fig. 5.8.

Fig. 5.8

Construction of a 0–5 counter

A frequency divider can be constructed using a 0 to $$ K - 1 $$ counter. For instance using a 0–5 counter we can construct a frequency divider circuit as in Fig. 5.9 where the synchronous reset operation is performed, i.e., reset operation is performed when counter value reaches 6. This means for the when counter value reaches to 5, we wait for the next clock pulse for the reset operation.

Fig. 5.9

Frequency division operation using a 0–5 counter

The timing waveform of the circuit in Fig. 5.9 is depicted in Fig. 5.10 where it is seen that using a 0–5 counter we can generate a frequency of

from an f Hz pulse train. We can generalize this result as: using a 0 to $$ K - 1 $$ counter we can generate a

clock source from an f Hz pulse train.

Fig. 5.10

Frequency divider timing waveform using a 0–5 counter

In fact, if Figs. 5.9 and 5.10 are inspected, we see that our counter counts up to the 6, but the value 6 is never seen at the counter output. The reason for this situation is that when the value 6 is reached the counter is reset. For this reason, the value of 6 is never seen at the counter output. Considering this, we call this counter as 0–5 counter. Since only those values from 0 to 5 are seen at the counter output.

A less complex circuit for a general frequency divider involving less logic units is depicted in Fig. 5.11. The timing waveform of this circuit for a 0–5 counter is the same as the waveform of Fig. 5.10.

Fig. 5.11

Frequency divider circuit

A frequency divider with a 0 to $$ K - 1 $$ counter equals to a frequency divider with a 1 to K counter. Hence, we can state that using a frequency divider with either a 0 to $$ K - 1 $$ counter or with a 1 to K counter it is possible to generate a clock source of $$ \frac{f}{2K}{\text{Hz}} $$ from an f Hz supply.

Example 5.7

We have a frequency divider. When the counter value is reached to 25 a reset operation is performed. Find the frequency of the divider output.

Solution 5.7

Our counter repeats the count sequence $$ 0, 1, 2, \ldots ,24 $$. From this sequence we see that

Then, out frequency divider output is

Frequency Divider in VHDL

Frequency division operation in VHDL shows some differences considering the use of signal and variable objects for counter index. The value assignment to a signal object is not immediate, and for this reason, a signal object used for a counter index creates more delay considering the same count sequence compared to a variable object used for counter index. When we mention a 1 to K counter, we mean the at the counter output the sequence $$ 1, 2, \ldots ,K $$ appears repeatedly.

Let f be the frequency of the FPGA device. If we use a signal object for the counter index, then a 0 to $$ K - 2 $$ counter can generate a clock of

or a 1 to $$ K - 1 $$ counter can generate a clock of

If we use a variable object for counter index, then a 0 to $$ K - 1 $$ counter can generate a clock of

or a 1 to K counter can generate a clock of

Example 5.8

Design a frequency divider that divides the clock frequency of the FPGA device by 10.

Solution 5.8

We can write this program using many different approaches. If we use a signal object for the counter, and if our counter repeats the sequence 1,2,3,4, then by toggling a logic value when counter value reaches to 5 and initializing the counter value to 1 again, we can obtain the desired frequency.

The required frequency divider using a signal object is implemented in VHDL in PR 5.13.

PR 5.13

Program 5.13

On the other hand, the same goal can be achieved using a variable object employed for counter index. In this case, our counter repeats the sequence 1,2,3,4,5, and when the counter value reaches to 6, we toggle a logic value and initialize the counter value to 1 again. The frequency divider with variable object is given in PR 5.14.

PR 5.14

Program 5.14

Example 5.9

Design a frequency divider that generates a clock frequency of 1 Hz from a clock frequency of 50 MHz.

Solution 5.9

We need a counter for the required clock frequency. Using the formula

for the desired frequency, i.e.,

and substituting $$ f = 50,000,000 $$, we get $$ K = 25,000,000. $$ Thus, using a 1–24,999,999 counter, we can achieve the desired clock frequency as in PR 5.15.

PR 5.15

Program 5.15

Example 5.10

Design a frequency divider that generates a clock frequency of 4 MHz from a clock frequency of 100 MHz.

Solution 5.10

Using the formula

for the desired frequency, i.e.,

and substituting $$ f = 100,000,000 $$, we get $$ K = 12.5 $$. Thus, using a 0–11 counter, we can approximately achieve the desired clock frequency as in PR 5.16.

PR 5.16

Program 5.16

5.2.6 BCD to SS Converter with 1 s BCD Counter

Example 5.11

Design a digital circuit that displays the digits 0–9 every 1 s on seven segment display in a sequential manner for an FPGA device. Assume that FPGA has 100 MHz clock.

Solution 5.11

To display the digits 0–9 every 1 s on seven segment display in a sequential manner, we need a counter that increments its output every one second, and a seven segment display connected in series with counter. The black box representation of the circuit is depicted in Fig. 5.12.

Fig. 5.12

Digital circuit that displays the digits 0–9 every 1 s on seven segment display

For the implementation of 1 s counter, we need a clock frequency of 1 Hz. The generation of 1 Hz frequency can be achieved using 1–49,999,999 counter as in PR 5.17.

PR 5.17

Program 5.17

Once we have the 1 Hz clock generator, we can add the seven segment display unit in a separate process as in PR 5.18.

PR 5.18

Program 5.18

5.3 The Wait Statement

The wait statement can be used in some sequential program units. The use of the wait statement can be in one of the forms:

wait;

wait until conditional statement;

wait on signal sensitivity list;

wait for time duration.

We cannot use the different type of the wait statements:

inside a process with a sensitivity list,

inside a process which is called from a procedure having a sensitivity list,

inside a function unit,

inside a procedure which is called from a function.

The statements wait for and wait are used in simulation programs, i.e., in test-benches, and they are not synthesizable.

5.3.1 Wait Until

The statement wait until is mostly considered for the implementation of clocked sequential circuits.

Example 5.12

We can implement the D-type flip-flop using the wait until statement as in PR 5.19.

PR 5.19

Program 5.19

We can use wait until statement more than once in a process unit. For instance, the process unit of the D-type flip-flop with enable input can be written as in PR 5.20.

PR 5.20

Program 5.20

5.3.2 Wait on

The wait on statement is used to check the changes in the signal parameter list, and if any change occurs in the parameter list, the process unit is executed. The processes P1 and P2 in PR 5.21 are equal to each other.

PR 5.21

Program 5.21

The position of the wait on statement inside the process unit is not an important issue. We can place it in any suitable place inside the procedure unit. However, we prefer to place it after the begin, or before the end statements.

Example 5.13

We can implement the D-type flip-flop using the wait on statement as in PR 5.22.

PR 5.22

Program 5.22

5.4 Case Statement

Another statement used in sequential programming is the case statement. The syntax of the case statement is as follows:

Example 5.14

Implement the $$ 4 \times 1 $$ multiplexer shown in Fig. 5.13 using the case sequential statement.

Fig. 5.13

$$ 4 \times 1 $$ multiplexer

Solution 5.14

The implementation of $$ 4 \times 1 $$ multiplexer using the case statement is given in PR 5.23.

PR 5.23

Program 5.23

We can consider more than a single value at the same line of the case statement. In this case the syntax of the case statement becomes as:

Example 5.15

In PR 5.24, the use of case statement for multiple parameter values is illustrated.

PR 5.24

Program 5.24

5.5 Loop Statements

Loop structures are vital part of the sequential programming. There are three kinds of loop structures available in VHDL programming. These structures are:

where labels are optional and they can be omitted.

Sequential loops can also be utilized with next and exit statements.

5.5.1 Next and Exit Statements

Next statement is used if we want to continue with the next iteration without finalizing the current iteration. Exit statement is used to exit the current loop. The syntax of the next and exit statements are as follows:

Example 5.16

Possible uses of next and exit statements are given in PR 5.25.

PR 5.25

Program 5.25

Example 5.17

In PR 5.26, we provide small examples for the three kind of loops used in sequential programming.

PR 5.26

Program 5.26

5.6 Example Sequential Logic Circuit Implementation in VHDL

In this section, we will provide examples for the implementation of sequential logic circuits that can involve combinational logic circuits.

Example 5.18

Implement the digital circuit of Fig. 5.14 in VHDL language.

Fig. 5.14

Digital circuit for Example 5.18

Solution 5.18

Let’s label the internal signals by $$ q_{a} $$ and $$ q_{b} $$ as in Fig. 5.15.

Fig. 5.15

Digital circuit with internal signals labeled

Considering Fig. 5.15, we can write the title part and declare the internal signals in the declarative part of the architecture as in PR 5.27.

PR 5.27

Program 5.27

In the next step, we implement the operation of the circuit in the body part of the architecture as in PR 5.28.

PR 5.28

Program 5.28

Example 5.19

Implement the digital circuit in Fig. 5.16 using VHDL.

Fig. 5.16

Digital circuit for Example 5.19

Solution 5.19

We first label the internal signals of the circuit as shown in Fig. 5.17 and implement the I/O ports in entity unit, and declare the internal signals in the declarative part of the architecture unit as in PR 5.29.

Fig. 5.17

Digital circuit with internal signals labeled

PR 5.29

Program 5.29

From Fig. 5.17, we can write the mathematical expressions for the internal signals as

which are implemented together with the operation of D-type flip-flop in the body part of the architecture unit as in PR 5.30.

PR 5.30

Program 5.30

Exercise: Implement the digital circuit in Fig. 5.18 using VHDL.

Fig. 5.18

Digital circuit for exercise

Example 5.20

Implement the digital circuit in Fig. 5.19 using VHDL.

Fig. 5.19

Digital circuit for Example 5.20

Solution 5.20

We first label the internal signals as in Fig. 5.20.

Fig. 5.20

Digital circuit with internal signals labeled

Considering Fig. 5.20, we define the port parameters in the entity unit and internal signals in the body part of the architecture unit as in PR 5.31.

PR 5.31

Program 5.31

The operation of the combinational circuit, i.e., multiplexer unit, can be implemented in the declarative part of the architecture unit as in PR 5.32.

PR 5.32

Program 5.32

Adding the implementation of the D flip flop, we get the full VHDL program as in PR 5.33.

PR 5.33

Program 5.33

Example 5.21

Implement the digital circuit in Fig. 5.21 using VHDL.

Fig. 5.21

Digital circuit for Example 5.21

Solution 5.21

The digital circuit shown in Fig. 5.21 can be implemented in a number of ways. One implementation of the circuit shown in Fig. 5.21 is given in PR 5.34.

PR 5.34

Program 5.34

Exercise: Implement the digital circuit in Fig. 5.22 using VHDL.

Fig. 5.22

Digital circuit for VHDL implementation

Exercise: Implement the digital circuit in Fig. 5.23 using VHDL.

Fig. 5.23

Digital circuit for VHDL implementation

Problems

(1)

Using 100 MHz FPGA clock frequency design a 1 kHz clock generator .

(2)

Assume that FPGA device has 100 MHz clock generator. Design two clock sources with 1 kHz clock frequency such that if the first clock waveform is denoted by $$ clk(t) $$, then the second waveform is denoted by $$ clk\left( {t + T/2} \right) $$ where T is the period of $$ clk(t) $$, i.e., the second clock waveform has some phase shift w.r.t. first clock waveform.

(3)

Assume that you have two clock waveforms with the same frequency $$ F_{c} $$, and if the first clock waveform is denoted by $$ clk(t) $$, then the second waveform is denoted by $$ clk\left( {t + T/2} \right) $$ where T is the period of $$ clk(t) $$. Using these two waveforms design a clock generator with frequency $$ 2F_{c} $$.

(4)

Write a VHDL program such that the digits 0–9 are displayed on seven segment display with 1 s time durations.

(5)

The characteristic table of the MN flip flop is displayed on the left of Fig. 5.P1. Implement the logic circuit shown on the right of Fig. 5.P1 in VHDL. Do not use components in your implementation.

P5.1

Digital circuit for VHDL implementation

(6)

Using a variable object in your frequency divider, design 1 kHz clock generator using 100 MHz FPGA clock generator.

(7)

Implement the circuit shown in Fig. 5.P2 in VHDL. Use components in your implementation.

P5.2

Digital circuit for VHDL implementation

(8)

Implement the circuit shown in Fig. 5.P3 in VHDL.

P5.3

Digital circuit for VHDL implementation

(9)

Implement the circuit shown in Fig. 5.P4 in VHDL. In your implementation do not use any concurrent coding for logic units, i.e., use only process units for the implementation of logic blocks.

P5.4

Digital circuit for VHDL implementation

(10)

Implement the circuit shown in Fig. 5.P5 in VHDL.

5.P5

Digital circuit for VHDL implementation

(11)

Write a VHDL program that displays the numbers $$ 00, 01, 02, \ldots 59, 60 $$ in a sequential manner with 1 s durations each on two seven-segment displays.

(12)

Implement a digital clock in VHDL.

(13)

Implement the circuit shown in Fig. 5.P6 in VHDL.

P5.6

Digital circuit for VHDL implementation

(14)

Write a VHDL program that displays the sequence 7, 21, 45, 32, 78, 12, 98, 48, 87, 2 repeatedly on two seven-segment displays, and elements of the sequence are displayed in sequential manner with 1 s durations for each number on two seven-segment displays.

(15)

Assume that FPGA device has 50 MHz clock generator. Design four clock sources with 1 kHz clock frequency such that if the first clock waveform is denoted by $$ clk(t) $$, then the second, third and fourth waveforms are denoted by $$ clk\left( {t + T/4} \right), $$ $$ clk\left( {t + 2T/4} \right) $$, $$ clk\left( {t + 3T/4} \right) $$ where T is the period of $$ clk(t) $$.

(16)

If the clock frequency of the FPGA is 100 MHz, can you design a clock generator with frequency 200 MHz? If yes, implement your design in VHDL.

© Springer Nature Singapore Pte Ltd. 2019

Orhan GaziA Tutorial Introduction to VHDL Programminghttps://doi.org/10.1007/978-981-13-2309-6_6

6. VHDL Implementation of Logic Circuits Involving Registers and Counters

Orhan Gazi1  

(1)

Department of Electronics and Communication Engineering, Çankaya University, Ankara, Turkey

Orhan Gazi

Email: o.gazi@cankaya.edu.tr

In this chapter we will explain the implementation of logic circuits involving registers and counters. In the previous chapter we focused on the implementation of simpler units, such as flip-flops, however, in this chapter, we will solve exercises for the implementation of more complex logic circuits.

6.1 Shift Registers

Shift registers are constructed from flip-flops . Such type of registers is usually employed in serial communication operations. They can also be used in arithmetic units employing serial addition, subtraction, multiplication, etc. In this section we will consider logic circuits employing shift registers.

Example 6.1

Four-bit shift register is shown in Fig. 6.1. Implement the 4-bit shift register shown in Fig. 6.1 in VHDL.

Fig. 6.1

Shift register with D-type flip-flops

Solution 6.1

The internal signals of the shift register in Fig. 6.1 are explicitly depicted in Fig. 6.2.

Fig. 6.2

Shift register with internal signals labeled

Considering Fig. 6.2, we can define the internal signals in the declarative part of the architecture unit and input-output ports in the entity part as in PR 6.1.

PR 6.1

Program 6.1

Considering the operations of the D flip-flops, we can write a procedure for the operation of the shift register in the body of the architecture unit as in PR 6.2.

PR 6.2

Program 6.2

We can implement the shift register in Fig. 6.1 in an alternative way. In this implementation, we declare the internal signals using std_logic_vector as in PR 6.3.

PR 6.3

Program 6.3

The operation of the shift register can be written using the internal signal logic vector as in PR 6.4.

PR 6.4

Program 6.4

6.1.1 Shift Register with Parallel Load

Shift registers with parallel load capability have the ability of loading external data to the binary cells in a parallel manner.

Example 6.2

Implement the 4-bit shift register with parallel load property shown in Fig. 6.3 using VHDL.

Fig. 6.3

Shift register with parallel load property

Solution 6.2

The circuit shown in Fig. 6.3 has both serial shifting and parallel load capability. The outputs are directly taken from the internal signals of the shift registers. Considering this issue, we can define the port and internal signals as in PR 6.5.

PR 6.5

Program 6.5

The parallel load and shifting operations of the circuit can be achieved using the process in PR 6.6.

PR 6.6

Program 6.6

Finally, equating the outputs to the internal signals after process unit in the body part of the architecture, we get the complete program as in PR 6.7.

PR 6.7

Program 6.7

6.1.2 Logic Circuits Involving Shift Registers and Counter

In this subsection we will consider the implementation of logic circuits involving clocked and combinational logic units.

Example 6.3

Implement the digital circuit of Fig. 6.4 in VHDL. The circuit contains two 4-bit shift register, one multiplexer, and one 1-bit counter.

Fig. 6.4

Digital circuit for example 6.3

Solution 6.3

The circuit in Fig. 6.4 has one input and one output. The input is taken from clock source and the output is take from the multiplexer output. The contents of shift registers and output of the 1-bit counter can be considered as internal signals. Then, we can define the port signals and internal signals as in PR 6.8.

PR 6.8

Program 6.8

Although there is no initialization control signal in the circuit, it is logical to define one as an input port as in PR 6.8. Since, the signal initializations in the declarative part of the architecture does not work in hardware implementation. They are valid only for software simulation. For this reason, we need to define a control signal for signal initialization as in PR 6.8. The operation of the counter and initialization process can be achieved using the process unit in PR 6.9.

PR 6.9

Program 6.9

The two shift registers can be implemented using two separate process units as in PR 6.10.

PR 6.10

Program 6.10

Finally, port output values can be obtained from the shift registers in the body part of the architecture after shift register implementations as in PR 6.11.

PR 6.11

Program 6.11

Unifying all the program segments we wrote up to know, we get the full program as in PR 6.12.

PR 6.12

Program 6.12

Exercise

Implement the circuit of Fig. 6.5, where there are three shift registers and one 2 × 1 multiplexer, in VHDL.

Fig. 6.5

Digital circuit for exercise

6.1.3 Serial Transfer Unit

Serial transfer units are used to transfer the contents of one shift register to a second shift register. The logic diagram of the serial transfer unit is depicted in Fig. 6.6.

Fig. 6.6

Serial transfer unit

Example 6.4

Implement the serial transfer unit shown in Fig. 6.6 in VHDL. Assume that shift registers contain 8 bits.

Solution 6.4

The serial transfer unit has two input signals and one output signal. The contents of the shift registers and output of the first shift register can be considered as internal signals. Considering this information, we can implement the ports and internal signals as in PR 6.13.

PR 6.13

Program 6.13

The two shift registers of Fig. 6.6 can be implemented using two process units as in PR 6.14.

PR 6.14

Program 6.14

Finally, outputs of the first and second shift registers can be implemented in the declarative part of the architecture unit using the codes in PR 6.15

PR 6.15

Program 6.15

Overall, our complete program becomes as in PR 6.16.

PR 6.16

Program 6.16

6.1.4 Serial Adder Unit

The serial adder is used to sum the contents of two shift registers, and it is depicted in Fig. 6.7.

Fig. 6.7

Serial adder unit

Example 6.5

Implement the serial adder shown in Fig. 6.7 in VHDL.

Solution 6.5

First, let’s label the internal signals as in Fig. 6.8.

Fig. 6.8

Serial adder unit with internal signals labeled

Considering Fig. 6.8, we can declare the input output ports and internal signals in the entity and declarative part of the architecture unit as in PR 6.17.

PR 6.17

Program 6.17

In the next step, we connect the internal signals to each other in the body of the architecture unit as in PR 6.18.

PR 6.18

Program 6.18

Lastly, we implement the operations of clocked sequential circuits of Fig. 6.7 using processes as in PR 6.19.

PR 6.19

Program 6.19

Problems

(1)

The circuit in Fig. 6.P1 performs the summation of three binary numbers. Implement the circuit in VHDL.

Fig. 6.P1

Digital circuit for the summation of three binary numbers

(2)

The serial subtractor circuit is depicted in Fig. 6.P2. Implement the serial subtractor in VHDL.

Fig. 6.P2

Serial subtractor

(3)

The serial adder and subtractor circuit is shown in Fig. 6.P3. Implement this circuit in VHDL.

Fig. 6.P3

Serial adder and subtractor circuit

(4)

Serial equality checker is shown in Fig. 6.P4. Implement this circuit in VHDL.

Fig. 6.P4

Serial equality checker

(5)

Serial magnitude comparator circuit is shown in Fig. 6.P5. Implement this circuit in VHDL.

Fig. 6.P5

Serial magnitude comparator

(6)

Implement the circuit in Fig. 6.P6 in VHDL.

Fig. 6.P6

Digital circuit for VHDL implementation

(7)

Implement the asynchronous up counter shown in Fig. 6.P7 in VHDL.

Fig. 6.P7

4-bit asynchronous up counter

(8)

Implement the asynchronous down counter shown in Fig. 6.P8 in VHDL.

Fig. 6.P8

4-bit asynchronous down counter

(9)

Implement the synchronous BCD counter shown in Fig. 6.P9 in VHDL.

Fig. 6.P9

Synchronous BCD counter with D flip-flops

(10)

Implement the asynchronous BCD counter shown in Fig. 6.P10 in VHDL.

Fig. 6.P10

Asynchronous BCD counter with D flip-flops

(11)

Implement the asynchronous BCD counter shown in Fig. 6.P11 in VHDL.

Fig. 6.P11

Asynchronous 4-bit BCD counter with JK flip-flops

(12)

Implement the asynchronous Johnson counter shown in Fig. 6.P12 in VHDL.

Fig. 6.P12

Asynchronous 4-bit Johnson counter with D flip-flops

(13)

Implement the modulus counter shown in Fig. 6.P13 in VHDL.

Fig. 6.P13

Modulus counter

(14)

Implement the modulus counter shown in Fig. 6.P14 in VHDL.

Fig. 6.P14

Digital circuit for VHDL implementation

© Springer Nature Singapore Pte Ltd. 2019

Orhan GaziA Tutorial Introduction to VHDL Programminghttps://doi.org/10.1007/978-981-13-2309-6_7

7. Packages, Components, Functions and Procedures

Orhan Gazi1  

(1)

Department of Electronics and Communication Engineering, Çankaya University, Ankara, Turkey

Orhan Gazi

Email: o.gazi@cankaya.edu.tr

In this chapter packages , components , functions and procedures will be explained in details. The repeatedly used parts of program units, such as functions, procedures, components, and data declarations, such as constants and user defined data type declarations are placed into the package unit. In this way, the program units placed inside the package becomes portable, and less space is occupied in the main program window. Packages can be written as a separate program unit or they can be placed before the main program.

7.1 Packages

Packages consist of two sections, one is the declaration part of the package, the other is the body of the package. The declaration part usually contains the data declarations, and function or procedure headers, i.e., declarations. The body part of the package usually contains the implementation part of the functions or procedures. The syntax of the package is shown in PR 7.1. To use the package in our program, we need to include the package file at the header of the main program.

PR 7.1

Program 7.1

This is achieved using the statement

Example 7.1

Package declaration can be made before the main program, i.e., main program and package declaration exists in the same file. In PR 7.2, package declaration is made before the inclusion of ieee library and package.

PR 7.2

Program 7.2

Usually package declarations should be made before the inclusion of any other library or packages. However, this rule may not be valid for some of the newly designed VHDL development platforms of some vendors.

Example 7.2

Package declaration and main program can exist in different files. The previous example can be implemented in two separate files as in PR 7.3 and PR 7.4.

PR 7.3

Program 7.3

PR 7.4

Program 7.4

7.2 Components

If some of the logic units, such as, multiplexers, adders, flip flops etc., are repeatedly used in logic circuits, we can write a library for these units and use them whenever they are needed without over and over again re-implementing these units. This is achieved via the use of component utility.

If we had already implemented some of the logic units, and want to use these units in some other VHDL programs, we can declare these units as components. Components declarations are either done in package unit, or in the declarative part of the architecture. Once components are declared, we can instantiate them in any number in our main program.

Component declaration is the same as entity declaration except for the use of component keyword instead of entity keyword. The declaration and instantiation syntax of the components is as in PR 7.5.

PR 7.5

Program 7.5

Let’s illustrate the subject with an example.

Example 7.3

4-bit shift register is shown in Fig. 7.1. Implement the 4-bit shift register shown in Fig. 7.1 using components.

Fig. 7.1

Shift register for VHDL implementation

Solution 7.3

If Fig. 7.1 is inspected, we see that D flip-flop is repeatedly used. First, we implement the D flip-lop as in PR 7.6.

PR 7.6

Program 7.6

In the next step, we have two ways of implementing the circuit in Fig. 7.1.

First Method: In the first method, create a package unit and declare the component in the package unit, and include the packet in main program where components are instantiated. The package unit where component declaration is made is depicted in PR 7.7.

PR 7.7

Program 7.7

Once, we declare the components, we can use them in any number in our main program. For this purpose, we include the packet in the header of our program as in PR 7.8 and declare the internal signals in the declarative part of the architecture unit.

PR 7.8

Program 7.8

In our circuit, we have 4 flip-flops. Considering the connections between flip-flops, we can declare the D flip-flops using port map function, and make the connections between flip-flop inputs and outputs as in PR 7.9.

PR 7.9

Program 7.9

Second Method: In the second method, we do not use a package unit . Instead, we make component declarations at the declarative part of the architecture, and the rest is the same as in the first method. The alternative implementation is depicted in PR 7.10.

PR 7.10

Program 7.10

Example 7.4

Implement the digital circuit of Fig. 7.2 in VHDL. The circuit contains two 4-bit shift registers, one multiplexer, and one 1-bit counter. Use components is your implementation.

Fig. 7.2

Digital circuit for Example 7.4

Solution 7.4

First, we separately implement each unique unit of Fig. 7.2 in VHDL. The implementation of the loop-backed shift register in VHDL is given in PR 7.11.

PR 7.11

Program 7.11

The implementation of the multiplexer is shown in PR 7.12.

PR 7.12

Program 7.12

And finally, the implementation of the counter is depicted in PR 7.13.

PR 7.13

Program 7.13

Once we have all the implementations of circuit units, we can declare all these units as components in the package unit as shown in PR 7.14.

PR 7.14

Program 7.14

After writing the package unit, we can write our main program. For this purpose, we first include our package at the header part, write the entity part and declare the internal signals at the declarative part of the architecture unit as in PR 7.15.

PR 7.15

Program 7.15

Considering Fig. 7.2, we instantiate two shift registers , one multiplexer , one counter, and relate the input and output of each component to other as in PR 7.16.

PR 7.16

Program 7.16

Solution 2: We can write the main program without using the package. For this purpose, we first write the entity part, and declare the internal signals and components in the declarative part of the architecture unit and instantiate the components as in PR 7.17.

PR 7.17

Program 7.17

Exercise: Implement the circuit of Fig. 7.3, where there are three shift registers and one 2 × 1 multiplexer, in VHDL. Use components in your implementation.

Fig. 7.3

Digital circuit for VHDL implementation

Serial Transfer Unit

Serial transfer units are used to transfer the contents of one shift register to a second shift register. The logic diagram of the serial transfer unit is depicted in Fig. 7.4.

Fig. 7.4

Serial transfer unit

Example 7.5

Implement the serial transfer unit shown in Fig. 7.4 in VHDL. Assume that shift registers contains 8 bits. Use components in your implementation.

Solution 7.5:

First we implement the shift register as in PR 7.18.

PR 7.18

Program 7.18

The implementation of the serial transfer unit using components if depicted in PR 7.19.

PR 7.19

Program 7.19

Serial Adder Unit

The serial adder is used to sum the contents of two shift registers, and it is depicted in Fig. 7.5.

Fig. 7.5

Serial adder unit

Example 7.6

Implement the serial adder shown in Fig. 7.5 in VHDL. Use components in your implementation.

Solution 7.6

The shift registers and D flip-flop can be implemented as in PR 7.18 and PR 7.6. The implementation of the full adder is given in PR 7.20.

PR 7.20

Program 7.20

Once we have the implementations of shift register, D flip-flop and full adder circuits, we can implement the circuit of Fig. 7.5 as in PR 7.21.

PR 7.21

Program 7.21

7.3 Functions and Procedures

Functions and procedures are used to write sequential program segments. The functions and procedures are written for the implementation of frequently used and portable algorithms or circuits. Functions and procedures are similar to that of the processes. However, the processes are usually employed inside the architecture unit, on the other hand, functions and procedures are usually placed into the package unit for general use.

7.3.1 Functions

Functions can be placed into the package unit, or they can be written in the declarative part of the architecture unit. If functions are to be placed into the package unit, then a declarative part and a body part of the function should be written and separately placed into the declarative and body part of the package unit.

The syntax of the function inside a packet is shown in PR 7.22.

PR 7.22

Program 7.22

Example 7.7

The parity calculator function is depicted in PR 7.23. Let’s put this function into a package.

PR 7.23

Program 7.23

To put the function in PR 7.23 into a package, first we write the header of the function in the declarative part of the package as in PR 7.24.

PR 7.24

Program 7.24

In the second step, we place the implementation of the function into the body of the package unit as in PR 7.25.

PR 7.25

Program 7.25

Putting the package header and package body into the same file, we obtain the package unit as in PR 7.26.

PR 7.26

Program 7.26

Function Call

Once a function is written, it can be called in the architecture body, just typing its name and providing the input values. The return value can be assigned to a signal.

Example 7.8

a_logic_vector <= conv_std_logic_vector(an_integer,8);

Example 7.9

The parity calculator function given in PR 7.26 can also be written in the declarative part of the architecture eliminating the use of package at the header of the program. The parity calculator function placed into the architecture part of a VHDL program is depicted in PR 7.27 where it is seen that only function body is placed into the declarative part of the architecture unit. No header declaration of the function as in the packet unit is needed .

PR 7.27

Program 7.27

While writing a function, we have to pay attention the following items:

(1)

Variables are not allowed in the parameter list of the functions, only signals and constants can be used in the parameter list of the functions. Parameter list can be empty as well. Default parameter type is constant.

(2)

Return data types should be one of the synthesizable data types available in VHDL.

(3)

Range specification is allowed in parameter list, but it is not allowed in the “return data_type” statement at the header of the function.

(4)

There is only one return value.

(5)

Functions can be nested.

Example 7.9

We can write a function which finds the sum of two logic vectors as in PR 7.28.

PR 7.28

Program 7.28

To use this function, we can place it into a package as in PR 7.29.

PR 7.29

Program 7.29

The package unit can be written in a separate file or we can use it in the main program before the entity part. If it is used in the main program, then we need to write

after declarations of libraries in the main program. In PR 7.30. the package unit is included in the main program, and the function is called in the body part of the architecture unit.

PR 7.30

Program 7.30

7.3.2 Operator Overloading

To increase the argument variability of the operators, we use the operator overloading approach. For this purpose, we write a function and the name of the function is chosen as “operator” where operator can be $$ + , - , *, $$ and $$ / $$ etc.

The syntax of the operator overloading is depicted in PR 7.31.

PR 7.31

Program 7.31

Example 7.10

The summation operator “+” is overloaded for two logic vectors as in PR 7.32.

PR 7.32

Program 7.32

Example 7.11

In PR 7.33, operator overloading is illustrated for “+” considering different operand data types. However, we did not implement the function bodies inside the package body. Since the aim of the example is to illustrate the concept of overloading rather than implementation.

PR 7.33

Program 7.33

7.4 Procedures

Procedures are program units similar to the functions and they are used for writing sequential program segments. Functions return a single parameter, on the other hand, procedures can return more than one parameter. In addition, in the parameter list of the procedures, we can use variables, signals and constants.

The procedures can be written in the declarative part of the architecture unit, or they can be declared in the declarative part of the package, and their body can be written in the body part of the package unit. The syntax of the procedure unit is shown in PR 7.34.

PR 7.34

Program 7.34

Example 7.12

The procedure, placed into a package, that inputs three integers and finds the minimum and maximum of these three integers is depicted in PR 7.35.

PR 7.35

Program 7.35

Including the package at the header of the main program, we can call the procedure in the body of the architecture unit as in PR 7.36.

PR 7.36

Program 7.36

7.4.1 Differences Between a Function and a Procedure

(1)

A function can return only a single parameter, and input parameter list of a function can contain signals and constants only, variables are not allowed in the parameter list of a function.

(2)

A procedure can accept any number of inputs and can return any number of parameters. The input parameter list of the procedure can contain variables, signals and constants.

(3)

When a function is called, its return value should be assigned to a parameter.

(4)

Both function and procedures can be placed inside a package, or they can be written in the declarative part of the architecture.

Problems

(1)

Implement the 4-bit shift register shown in Fig. 7.P1 in VHDL. Use components in your implementation.

Fig. 7.P1

4-bit shift register

(2)

Implement the circuit which contains 8-bit shift registers shown in Fig. 7.P2 in VHDL. Use components in your implementation.

Fig. 7.P2

Digital circuit for VHDL implementation

(3)

Implement the circuit shown in Fig. 7.P3 where shift registers contain 8-bits in VHDL. Use components in your implementation.

Fig. 7.P3

Digital circuit for VHDL implementation

(4)

Implement the logic module shown in Fig. 7.P4 in VHDL. Use components in your implementation.

Fig. 7.P4

Digital circuit for VHDL implementation

(5)

Write a function that finds the XOR of two 8-bit std_logic_vectors. Put the function into a package and call your function in your main program.

(6)

Write a procedure that sorts three integers in ascending order. Implement your procedure directly in the declarative part of the architecture unit.

(7)

Can I use a variable in the parameter list of a function?

(8)

Can I use a variable in the parameter list of a procedure?

© Springer Nature Singapore Pte Ltd. 2019

Orhan GaziA Tutorial Introduction to VHDL Programminghttps://doi.org/10.1007/978-981-13-2309-6_8

8. Fixed and Floating Point Numbers

Orhan Gazi1  

(1)

Department of Electronics and Communication Engineering, Çankaya University, Ankara, Turkey

Orhan Gazi

Email: o.gazi@cankaya.edu.tr

In this chapter, fixed and floating point number implementations in VHDL will be explained. Fixed and floating number formats enable the VHDL programmer to implement the fractional numbers in an easy manner. Fixed point number format is used to implement the fractional integers; on the other hand, floating point format is used to implement the real numbers in FPGA platform.

8.1 Fixed Point Numbers

Fixed point number format is introduced in VHDL-2008. For this reason, during the project creation, VHDL-2008 language should be chosen for editing. Some of the VHDL development platforms may not support fixed point number formats. Fixed point number format is supported in ISE XILINX platform.

Fixed point numbers can be signed or unsigned. A signed number in base-2 can be expressed in general form

which can be converted to decimal number as

To define the signed fixed and unsigned fixed point numbers, we use the syntax

where a + 1 and |b| indicates the number of bits used for the integer and fractional part of the numbers if a > 0 and b < 0. Signed numbers are represented in 2’s complement form.

To be able to use the fixed point number format in our VHDL code, we need to include the lines

at the header of the VHDL program.

Example 8.1

In the VHDL statement

the parameter ‘num’ represents an 8-bit number in the form

where the first 5-bit is used for the integer part, and the 3-bit after point is used for the fractional part.

Example 8.2

Considering the VHDL statement

find the decimal equivalent of “num”.

Solution 8.2

The binary string

can be converted to decimal as

Example 8.3

Considering the VHDL statement

find the decimal equivalent of “num”.

Solution 8.3

The binary string

represent a negative number in 2’s complement form. To find the negative number in decimal form, we first take the 2’s complement of

resulting in

which can be converted to decimal as

Thus, the binary string

represent the negative number

Example 8.4

In the VHDL statement

the parameter ‘num’ represents a positive number in the form

whose decimal equivalent can be calculated as

Example 8.5

In the VHDL statement

the parameter ‘num’ represents a positive number in the form

whose decimal equivalent can found as

Example 8.6

In the VHDL statement

the parameter ‘num’ represents a negative number in the form

whose decimal equivalent can be found as

Example 8.7

In the VHDL statement

the parameter ‘num’ represents number in the form

whose decimal equivalent can be found as

Example 8.8

In the VHDL statement

the parameter ‘num’ represents a negative number in the form

whose decimal equivalent can be found as

8.1.1 Type Conversion Functions

For fixed point number , the type conversion functions

are available, and these functions are used to convert a fractional number to a binary string which is interpreted according to fixed point number format.

Example 8.9

In PR 8.1, the fractional number $$ 12.25 $$ is represented using fixed point format via two different approach. In the first approach, 12.25 is directly converted to fixed point format. In the second approach, we first convert 12.25 to a binary string, i.e., “01100_010”, and then convert it to fixed point format.

PR 8.1

Program 8.1

Fixed point numbers can be converted to other data formats. For this purpose, we use the conversion functions

to_ slv () $$ \to $$ The binary string representing a signed or an unsigned fixed point number is interpreted as a std_logic_vector.

to_ signed () $$ \to $$ The binary string representing a signed or an unsigned fixed point number is interpreted as a binary string representing a signed integer.

to_unsigned() $$ \to $$ The binary string representing a signed or an unsigned fixed point number is interpreted as a binary string representing an unsigned integer.

to_integer() $$ \to $$ The binary string representing a signed or an unsigned fixed point number is interpreted as a binary string representing an integer.

to_std_logic_vector() $$ \to $$ Same as to_slv().

add_sign() $$ \to $$ An unsigned fixed point number is converted into a signed fixed point number. To achieve this, 2’s complement of the positive number is taken so that the result represents a negative number.

Example 8.10

In PR 8.2, a fixed point number represented by the binary string “11000111” is converted into numbers in data types std_logic_vector, signed, integer. Considering PR 8.2, find the binary strings for num2, num3, and num4.

PR 8.2

Program 8.2

Solution 8.10

The conversion functions given in PR 8.2 does not alter the binary string, just the interpretation of the string changes. So for this reason, the binary strings for num2, num3, and num3 are the same as num1, i.e., “11000111”.

Example 8.11

In PR 8.3, an unsigned fixed point number represented by the binary string “01000111” is converted into a signed fixed point number using the conversion function add_sign(). Considering PR 8.3, find the binary strings for num2.

PR 8.3

Program 8.3

Solution 8.11

In PR 8.3, num1 equals to $$ 24.875 $$. On the other hand, num2 equals to $$ - 24.875. $$ We can find the binary string for num2 as

8.1.2 Operators for Fixed Point Numbers

Since fixed point numbers are represented by binary strings, then logical operations can be performed between fixed point number. The logical operators that can be used for fixed point numbers are:

Arithmetic operators can also be used between fixed point numbers. The arithmetic operators that can be used between fixed point numbers are

The comparison operators that can be used between fixed point numbers are:

The shift functions that can operate on fixed point numbers are

8.1.3 Arithmetic Operations with Fixed Point Numbers and Sizing Rules

Let num1 and num2 be two unsigned fixed point numbers defined as

When arithmetic operations are performed using num1 and num2, the result is a fixed point defined as

To prevent the loss of data, the range values e and f of the res should be chosen properly. The rule to decide on the values of e and f is tabulated in Table 8.1

Table 8.1

Range calculation for fixed point arithmetic operations

Operation

Range of result

num1 + num2

e = max(a,c) + 1

f = min(b,d)

num1 − num2

e = max(a,c) + 1

f = min(b,d)

num1 * num2

e = a+c + 1

f = b+d

num1 rem num2

e = min(a,c)

f = min(b,d)

num1 mod num2 (signed)

e = min(a,c)

f = min(b,d)

num1 mod num2 (unsigned)

e = c

f = min(b,d)

num1/num2 (signed)

e = a − d + 1

f = b − c

num1/num2 (unsigned)

e = a − d

f = b − c − 1

−num1

e = a + 1

f = b

abs(num1)

e = a + 1

f = b

reciprocal(num1) (signed)

e = −b + 1

f = −a

reciprocal(num1) (unsigned)

e = −b

f = −a − 1

Example 8.12

For the two fixed point numbers

the result of x*y is a number with data type

and the result of x + y, or x − y is a number with data type

Similarly, the result of x/y is a number with data type

8.1.4 Automatic Resizing

If you multiply or divide any two fixed point numbers, either you need to calculate the size of the result, or, you need to use a large size for the result to prevent the overflow and loss of information. The size of the result can be estimated using the special functions

Let’s say that we want to multiply and divide two fixed point numbers, and assign results to fixed point parameters. The size of the result can be calculated as illustrated in PR 8.4.

PR 8.4

Program 8.4

Example 8.13

Write a VHDL program that takes two signed fixed point numbers from input ports and calculates the multiplication and division results of these two numbers and sends the results to the output ports.

Solution 8.13

The requested program can be written as in PR 8.5.

PR 8.5

Program 8.5

8.1.5 Resize Function

We know that performing arithmetic operations on fixed point numbers result in another fixed point number with larger size. If we are sure that overflow does now occur after performing arithmetic operations on fixed point numbers, we can make the size of the resulting fixed point number the same as the fixed point numbers involved in operations.

For instance, assume that two 8-bit unsigned fixed point numbers are to be summed, and these numbers can be at most 100, then the sum of these numbers can be at most 200 which can be represented using 8-bit.

The declarative statement for the resize function is as

where round style is a Boolean variable, and when round style is true then fixed round is adapted for argument, otherwise argument is truncated in case of overflow.

In addition, if overflow style is true, then fixed saturate mode is chosen, which implies that the maximum possible number is returned, if the argument is too large to represent via the given size values. Otherwise, fixed wrap mode is adapted, which implies that the top bits are truncated in case of overflow.

Example 8.14

In PR 8.6, we create a number vector consisting of fixed point number, and find the sum of numbers and send the summation result to an output port.

PR 8.6

Program 8.6

8.1.6 Add Cary Procedure

In ieee_proposed library, there are some built-in functions and procedures for fixed point operations. One of the procedure is the add-carry procedure whose declarative statement is

where out1 = inp1 + inp2 + cin and although inputs can be any objects, such as signal, constant, variable, the outputs out1 and cout are variable objects. The complete declarative part of the add_carry procedure have two different forms as shown below

In ieee_proposed library, the data types “unresolved_u/sfixed” and “s/ufixed” are defined as

Example 8.15

In PR 8.7, the use of add_carry() procedure is explained with an example.

PR 8.7

Program 8.7

8.1.7 Divide Function

The divide function has the declarative statement defined as function divide (l, r: unresolved_ufixed; constant round_style: fixed_round_style_type: = fixed_round_style; constant guard_bits: natural: = fixed_guard_bits) return unresolved_ufixed;

When divide function is used for the division of two ufixed numbers as

the result will be an ufixed number as

The divide function for sfixed point numbers has the declarative part given as function divide (l, r: unresolved_sfixed; constant round_style: fixed_round_style_type: = fixed_round_style; constant guard_bits: natural: = fixed_guard_bits) return unresolved_sfixed;

When divide function is used for the division of two sfixed numbers as

the result will be an sfixed number as

8.1.8 Reciprocal Function

The reciprocal function returns the inverse of a number, i.e., return $$ 1/x $$. The reciprocal function for ufixed numbers has the declarative statement defined as

function reciprocal (arg: unresolved_ufixed; constant round_style: fixed_round_style_type := fixed_round_style; constant guard_bits: natural: = fixed_guard_bits) return unresolved_ufixed;

When reciprocal function is used for an ufixed number as

the result will be an ufixed number as

The reciprocal function for sfixed numbers has the declarative statement defined as

function reciprocal (arg: unresolved_sfixed; constant round_style: fixed_round_style_type: = fixed_round_style; constant guard_bits: natural: = fixed_guard_bits) return unresolved_sfixed;

When reciprocal function is used for a sfixed numbers as

the result will be a sfixed number as

8.1.9 Remainder Function

The remainder function is used to find the remainder after division of two fixed point numbes. The declarative statement of the remainder function for ufixed number is as

function remainder(l, r: unresolved_ufixed; constant round_style: fixed_round_style_type: = fixed_round_style; constant guard_bits: natural: = fixed_guard_bits) return unresolved_ufixed;

When remainder function is used for ufixed numbers as

the result will be an ufixed number as

The declarative statement of the remainder function for sfixed numbers is as

function remainder(l, r: unresolved_sfixed; constant round_style: fixed_round_style_type: = fixed_round_style; constant guard_bits: natural: = fixed_guard_bits) return unresolved_sfixed;

When remainder function is used for sfixed numbers as

the result will be an sfixed number as

The implementation of overloaded rem operator is given in PR 8.8.

PR 8.8

Program 8.8

Note that an overloaded operator is different than an overloaded function in terms of input accepting. For instance, the overloaded operator in PR 8.8 is used as “arg1 rem arg2”, on the other hand, the overloaded function remainder is called as “remainder(arg1, arg2)”.

8.1.10 Scalb Function

The scalb function is used to multiply or divide a fixed point number by a number which is power of two. The function has the different overloaded declarations as outlined below:

If x and N are the inputs of the function, then the function output happens to be

The width of the input equals to the width of the output with the binary point moved.

Example 8.16

In PR.9, the use of scalb function is illustrated with an example where an unsigned fixed point number of type

with value “000.10” corresponding to 0.5 is multiplied by $$ 2^{4} $$ using the scalb function yielding 8.0 which can be represented by “1000.0” with the data type

In PR 8.9, we use resize function to change the size of the resulting number. If resize function is not used, then the value of the binary string may not be accurately computed by the programmer.

PR 8.9

Program 8.9

8.1.11 Maximum and Minimum Function

The maximum and minimum functions are used to find the maximum or minimum of two fixed point numbers. The declarative statements of these functions are as

In PR 8.10, the use of the maximum and minimum functions are explained via an example.

PR 8.10

Program 8.10

8.1.12 ‘Find Left Most’ and ‘Find Right Most’ Functions

The functions find_leftmost and find_rightmost are used to find the most and least significant bits of a fixed point number. The declarative statement for these functions are as follows:

function find_leftmost (arg: unresolved_ufixed; y: std_ulogic) return integer;

function find_leftmost (arg: unresolved_sfixed; y: std_ulogic) return integer;

function find_rightmost (arg: unresolved_ufixed; y: std_ulogic) return integer;

function find_rightmost (arg: unresolved_sfixed; y: std_ulogic) return integer;

These functions are used to find the location of ‘y’ in the fixed point number. If ‘y’ is not found in the number, then find_leftmost function returns “arg’low-1”, and find_rightmost function returns “arg’high + 1”. For find_leftmost function, the search starts from the most significant bit and decreases, and similarly for find_rightmost function, the search starts from the least significant bit and increases.

In PR 8.11, the use of the find_leftmost and find_rightmost functions are illustrated with an example.

PR 8.11

Program 8.11

8.1.13 ABS Function

The abs function is used to change the sign of negative numbers. The declarative statement of the abs function is as

The abs function increases the size of the argument as

Example 8.17

Assume that the number x is of type sfixed(3 downto −3), let x be equals to $$ - 16 $$, i.e., x can be represented by the binary string 1000.000. Then, $$ abs\left( x \right) $$ produces $$ + 16 $$ which can be represented by the binary string $$ 01000.000 $$, i.e., length of the integer part increase.

Example 8.18

The use of abs function is illustrated in PR 8.12.

PR 8.12

Program 8.12

8.2 Floating Point Numbers

Floating point numbers enable high precision implementation. However, any hardware constructed using the floating point numbers is at least three times more complex than the hardware constructed using the fixed point numbers implementing the same algorithm or circuit. In addition, the circuits designed using the floating point numbers are much slower than the circuits constructed using the fixed point numbers. Considering these factors, although at the beginning, floating point numbers may be attractive a lot, however, from implementation point of view, they are not too much desirable.

Floating Point Numbers

Floating point number format is introduced in VHDL-2008. For this reason, during the project creation, VHDL-2008 language should be chosen for editing. Some of the VHDL development platforms may not support floating point number formats. Floating point numbers can be signed or unsigned.

To define a signed fixed or an unsigned floating point number, we use the syntax

To be able to use the floating point number format in our VHDL code, we need to include the lines

at the header of the VHDL program.

The format of the 32-bit floating point number is as in

where S indicates the sign bit, $$ E_{i} $$ is used for exponent, and $$ F_{i} $$ is used for fractional part. The value of the floating point number is calculated using

(8.1)

where $$ Exponent\,Base $$ is calculated as

(8.2)

where $$ \left| E \right| $$ indicates the number of bits used in exponent part. The smallest value of the exponent width and fraction width is 3, i.e., float(3 downto -3), the smallest floating point number is a 7-bit number.

Example 8.19

If exponent contains 8 bits, then the exponent base is calculated as

Example 8.20

If exponent contains $$ 12 $$ bits, then the exponent base is calculated as

The formula in (8.1) can also be written as

(8.3)

Example 8.21

To calculate the value of the x in

we first group the bits as

from which it is seen that

And using (8.1), we get

Example 8.22

The value of x in

can be calculated as

and using (8.1), we get

Example 8.23

Express $$ 0.25 $$ in the number format

Solution 8.23

The number $$ 0.25 $$ can be written as

and considering (8.2), we can express $$ 2^{ - 2} $$ as

In VHDL-2008, the following floating point data types are defined in the float packages as

8.2.1 Floating Point Type Conversion Functions

For a floating point number , type conversion functions are available. These functions can be summarized as follows:

resize(float, exponent_width, fraction_width) $$ \to $$ Changes the size of a floating point number.

to_slv(float) $$ \to $$ The binary string representing a floating point number is interpreted as a std_logic_vector.

to_std_logic_vector(float) $$ \to $$ alias of to_slv(float).

to_stdlogicvector(float) $$ \to $$ alias of to_slv(float).

to_sulv(float) $$ \to $$ The binary string representing a floating point number is interpreted as a std_ulogic_vector.

to_std_ulogic_vector(float) $$ \to $$ same as to_sulv(float).

to_stdulogicvector(float) $$ \to $$ same as to_sulv(float).

to_float(real number,exponent_width,fraction_width) $$ \to $$ The input number is converted into a binary string representing a floating point number.

to_float(std_logic_vector,exponent_width,fraction_width) $$ \to $$ The std_logic_vector is interpreted as a floating point number.

to_float(std_ulogic_vector, exponent_width, fraction_width) $$ \to $$ The std_ulogic_vector is interpreted as a floating point number.

to_float(integer, exponent_width, fraction_width) $$ \to $$ The binary string representing an integer is interpreted as a floating point number.

to_float(ufixed, exponent_width, fraction_width) $$ \to $$ The binary string representing an unsigned fixed number is interpreted as a floating point number.

to_float(sfixed, exponent_width, fraction_width) $$ \to $$ The binary string representing a signed fixed number is interpreted as a floating point number.

to_float(signed, exponent_width, fraction_width) $$ \to $$ The binary string representing a signed number is interpreted as a floating point number.

to_float(unsigned, exponent_width, fraction_width) $$ \to $$ The binary string representing an unsigned number is interpreted as a floating point number.

to_signed(float) $$ \to $$ The binary string representing a floating point number is interpreted as a binary string representing a signed integer.

to_unsigned(float, …) $$ \to $$ The binary string representing a floating point number is interpreted as a binary string representing an unsigned integer.

to_integer(float) $$ \to $$ The binary string representing a floating point number is interpreted as a binary string representing an integer.

to_sfixed(float,left_index, right_index) $$ \to $$ The binary string representing a floating point number is interpreted as a binary string representing a signed fixed point number.

to_ufixed (float, left_index, right_index) $$ \to $$ The binary string representing a floating point number is interpreted as a binary string representing an unsigned fixed point number.

Now let’s give some examples to illustrate the type conversion functions.

Example 8.24

The function to_float() can be called as

and the function to_slv() can be used as

The use of the conversion functions to_slv() and to_float() is illustrated in PR 8.13.

PR 8.13

Program 8.13

Example 8.25

The program in PR 8.14 illustrates the use of

PR 8.14

Program 8.14

Example 8.26

The program in PR 8.15 illustrates the use of

PR 8.15

Program 8.15

Example 8.27

Floating point numbers can be converted to signed, unsigned and integer numbers using the functions, to_signed, to_unsigned, to_integer as follows

Example 8.28

Floating point numbers can be converted to signed fixed and to unsigned fixed point numbers using the functions, to_sfixed, to_ufixed as follows

8.2.2 Operators for Floating Point Numbers

Arithmetic Operators

Arithmetic operators can also be used between floating point numbers. The arithmetic operators that can be used between two floating point numbers or between a floating number and an integer are

In addition to these operators, we have the functions

and these function can be used between two floating point numbers or between a floating number and an integer.

Logical operators

Since floating point numbers are represented by binary strings, then logical operations can be performed between floating point numbers. The logical operators that can be used for floating point numbers are:

The shift functions that can operate on floating point numbers are

Comparison operators

The basic comparison operators that can be used between floating point numbers are:

Some functions for floating point numbers.

8.2.3 Copysign Function

The function Copysign with declaration

returns x with the sign of y.

Example 8.29

If the floating point numbers x and y have the values

then Copysign(x,y) returns “11011100”.

Example 8.30

The use of Copysign function is illustrated in PR 8.16.

PR 8.16

Program 8.16

8.2.4 Scalb Function

The function Scalb with declarations

returns $$ x \times 2^{n} $$.

Example 8.31

The use of Scalb function is illustrated in PR 8.17.

PR 8.17

Program 8.17

8.2.5 Logb Function

The function Logb with declarations

returns the unbiased exponent of x.

Example 8.32

The use of Logb function is illustrated in PR 8.18

PR 8.18

Program 8.18

Problems

(1)

Implement two complex numbers using fixed point numbers, and write a function that finds the product of two complex numbers.

(2)

Repeat 1 using floating point numbers.

(3)

Define a complex number vector using signed fixed point number format.

(4)

Why do we use the resize function?

(5)

What is the difference between an overloaded operator and overloaded function?

(6)

Consider the numbers

Determine the sizes of integer and fractional parts of the numbers that result from the following operations

(7)

Explain the scalb() and abs() functions for fixed point numbers.

(8)

Calculate the numerical value of ‘a’ in

Bibliography

1.

V.A. Pedroni, Circuit Design and Simulation with VHDL , 2nd edn. (The MIT Press, Cambridge, 2010)

2.

P.P. Chu, FPGA Prototyping by VHDL Examples: Xilinx Spartan-3 Version (Wiley-Interscience, Hoboken, 2008)

3.

A. Rushton, VHDL for Logic Synthesis (Wiley, Hoboken, 2011) Crossref

4.

D.L. Perry, VHDL: Programming By Example (McGraw-Hill Education, New York, 2002)

5.

P.J. Ashenden, The Designer's Guide to VHDL , 3rd edn. (Morgan Kaufmann, Burlington, 2008) MATH

6.

F. Tappero, B. Mealy, Free Range VHDL . (Free Range Factory, 2013)

Index

A

Abs function

Abs operator

Add Cary Procedure

Architecture

Arithmetic operator

Array data types

Assignment operators

Asynchronous down counter

Asynchronous up counter

Attributes

Automatic resizing

B

BCD code

BCD counter

BCD decoder

BCD to SS converter

Begin

Binary Coded Decimal (BCD)

bit data

bit_vector

Boolean function

Bus inputs

C

Case statement

Clock divider

Clock generator

Combinational circuits

Combinational logic circuits

Comparison operators

Components

Concatenation operator

Conditional generate

Constant

Constant object

Constrained arrays

Copysign function

Counter

D

2D arrays

3D arrays

Data objects

Declarative part

Decoders

Defining PORT arrays

Digital circuit

Divide function

D-type flip flop

E

Entity

Enumerated data types

Equality checker

Examples

Excitation tables

F

Find left most

Find right most

Fixed point numbers

Flip-flops

Floating point numbers

Floating point type conversion functions

Frequency divider

Frequency division

Function call

Functions

G

Generate statement

Generic statement

Grad code

I

IEEE.numeric_std.all

if Statement

Initialization parameters

Integer

Internal signals

L

Logb function

Logical operators

Loop statements

M

Magnitude comparator

Matrix

Maximum and minimum functions

Modulus counter

Multiplexer

N

Natural

Next and exit statements

numeric_std

O

Octal encoder

Operator mod

Operator overloading

Operator rem

P

Package

Package unit

Parallel load

Parity generator

Port

Port map

Positive

Priority encoder

Procedures

Process

R

Reciprocal function

Registers

Relational operators

Remainder function

Resize function

Return value

Rotate Left (ROL)

Rotate Right (ROR)

Row vectors

S

Scalar data type

Scalb function

Select

Select statement

Sequential circuit implementation

Sequential logic circuits

Sequential program units

Serial adder unit

Serial subtractor

Serial transfer unit

Seven segment display

Shift Left Arithmetic (SLA)

Shift Left Logical (SLL)

Shift operators

Shift registers

Shift Right Arithmetic (SRA)

Shift Right Logical (SRL)

Signal

Signal object

Signed

Simulation

Simulation of VHDL programs

Simulation results

Sizing rules

Standard package

std_logic

std_logic_arith

std_logic_vector

std_ulogic

Subtypes

T

Test-bench

Timing waveform

to_signed

to_slv

Type conversion

Type conversion functions

U

Unconditional generate

Unconstrained arrays

Unsigned

User defined data types

V

Variable

Variable object

W

Wait on

Wait statement

Wait until

When and select

When statement

With-select