 In our last lecture on hardware description languages and VHDL in particular, we had started a discussion on the design elements which constitute the language. We had looked at entities, we had looked at architecture, we had seen that an entity architecture pair constitutes a template for a piece of hardware. This template is then fixed as a component type by the term component and then it is actually instantiated as one specific piece of hardware by a component instance. Binding a particular component to an entity architecture pair is done by configuration. In fact, configuration can be in line during the description of a component itself or it could be a standalone unit which binds a particular component type to an entity architecture pair. We had also seen that we can place various definitions, various components and so on in packages and several packages can be put together in a library. We had also seen the syntax and the usage of configurations, packages and libraries. There is one point which we will probably take up in some detail today and that has to do with this somewhat confusing terminology of entity architecture pairs, component types and actual instances. As we had talked about earlier, we had said that modern versions of VHDL permit you to instantiate entity architectures directly. This has weakened somehow the usage of the component type and therefore sometimes this hierarchy of design description is not made very clear. Let us just make it clear with one example. Let us say that we have an entity called filter. This is probably a digital unit which carries out filtering of the input data using whatever algorithm. Now notice that as far as the entity is concerned, it only describes the interconnection of this object with the outside world. It does not care what the insides of this could be. That means it will provide a connection to the input data stream, to the output data stream, set of coefficients and so on. Those will be the items which will be described by the entity in its port list and the generics might for example specify the critical frequencies and so on of this filter. This entity can now have several architectures and let us say that we have three architectures for this entity. These are the architectures for this entity. Notice that an architecture is defined only with respect to an entity. Now our entity is a filter and now we can have separate inside machinations in short of this filter and that may describe the behavior of this filter and you could have an architecture for example which could be low pass. You could have an architecture which is high pass and you could have an architecture which is band pass. Notice that all these architectures are compatible with the interconnection of this piece of hardware with the outside world. What these architectures determine is how is the input data stream handled inside this piece of hardware in order to produce an output stream which is a low pass version, a high pass version or a band pass version of the input data stream. Around which frequencies will low pass, high pass or band pass will occur is in fact decided by the generics of this entity. So this entity has only the generics and the port list. Next you might define components. So for example you bind a particular pair of entity architecture to a component type. So I might have a component called LPF which is then bound to the entity filter with architecture low pass. I could have a different component called HPF which is bound to the same entity but with a different architecture. And finally I could have yet another component called BPF. These are names of components and this is connected to the same entity but with a third architecture which is band pass. So using an entity and its three architectures I have actually described three different component types. These are not yet specific components. Now I can instantiate these components and maybe in my hardware there are six pieces of hardware, six actual instances of components and it is possible that U1 is of type LPF, U2 is of the type HPF, U3 is again LPF, U4 is again HPF and U5 is BPF, U6 is BPF. Now notice the hierarchy of the use of these design elements. The entity is the top unit. It specifies that I am describing a class of hardware called filters. The entity describes only the generics that means the manifest constants which describe the properties of this filter and port list which describes how this class of hardware will be connected to other pieces of hardware. An entity can have several architectures. In this case actually it is somewhat unusual that different architectures actually provide different functionality. A much more common use is when different architectures provide different implementations of the same functionality but to take the most general case we may have different architectures after all our entity is the generic filter and the architectures decides whether it is a low pass filter, a high pass filter or a band pass filter. So we have three architectures and at this stage this entity with three architectures is not specific hardware. It is not an integrated circuit on a board so to speak. It is a template for the kind of hardware that we can use. We now describe component types and LPF, HPF and BPF are component types. These are still not specific pieces of component. These are component types which are available to us and then each component type is then bound in fact this binding is done by configurations. So you have a configuration which binds LPF to entity filter with architecture low pass, HPF to entity filter with architecture high pass and the entity BPF to the entity filter with band pass. It is only after I have declared these component types using a configuration and entity architecture pairs that I can actually use these component types and U1, U2, U3, U4, U5, U6 are the actual pieces of hardware which describe my design. So U1 is then bound to a component type, U2 is also bound to a component type and so on. So each instance of component needs a component type to which it will bind and each component type must then be configured to an entity architecture pair. I hope that explains this somewhat confusing hierarchies which is in fact a bit too detailed if you ask me. But this is the hierarchy that we have in the full blown hierarchy that we have in VHDL. However, most of the time we do not need this full blown hierarchy. Most of the time generally just one level or two are good enough. In that case in modern versions of VHDL you are permitted to skip the component stage altogether. That means a particular instance can be bound not to a component type but directly to an entity architecture pair. That means it will be possible in the modern versions of VHDL to say that component instance U1 is bound in fact to entity filter with architecture low pass. This direct bound binding is a somewhat late addition to VHDL earlier the binding could only be done to an object type component. So only a design unit component could be instantiated in the early versions of VHDL, modern versions of VHDL allow instantiation of entity architecture pairs directly. Once we have this done, now it is relatively easier to see how hardware could be described structurally. You have interconnections defined by signals, you have hardware components which are instances of component types and component types are bound using configurations to entity architecture pairs. So this is the super structure which is assumed in a VHDL based hardware description. Modern versions of VHDL allow short circuiting the component stage if that is considered convenient. It still respects the old hierarchy and therefore if you describe components that is also with the modern versions of architecture but it also allows you to take the shortcut of directly instantiating entity architecture pairs. So this is the hierarchy of design elements in modern version of VHDL. In addition to that of course you have libraries and packages and we had seen this in the last lecture that you have this syntax of library dot package dot component and you can make any component from any package from any library visible to your design by this kind of declaration which first declares the library and then you use what is called a use clause which allows you to select which component of a library package etc will become visible to your design. We had also seen object and data types. Object types are constants, variables, signals, files and in fact there are pointer types as well and then the data types could be of type bit of type std logic defined later in a library and so on. Let us look at data types in much more detail now. Notice now we are talking of data types and not of object types. Different object types can use the same data type for example a constant, a variable or a signal could all be of type bit. Now let us see the classification of the data types which we can handle in VHDL. You have types which are scalar, a scalar is a single object. You have a type which is excess it is this is like pointers in programming languages. You have a data type like file and then you have composite data types which are collections of scalar types. Let us now look at the scalar types. The scalar types could be of the type discrete shown here in blue. They could be floating points that means which are inherently continuous type variables. Of course in actual implementation because the size of the variable is limited these are also somewhat discrete but they are meant to be continuous. And finally you have a scalar type called physical. These are used to describe physical quantities and they have not only a value but also a unit and different size d units can be interrelated in a physical type. So essentially we have three scalar types we have things which are inherently discrete like integers. We have things which are theoretically continuous though in practical implementations with fixed size representations they are also discrete but they are meant to represent continuous quantities like floating point. And finally there are physical types which these two carry only values but you have physical types which carry values as well as units and then the values can be transformed because you can define several units for the same physical unit physical quantity. Now let us look at all three of these one by one. Discrete kind of scalar values can be either of type integer integers are well known to us. These are positive or negative numbers inclusive of 0 they could be of type enumeration in which you enumerate a set of value that this discrete type can take. So for example a scalar could be a discrete type but it cannot take any old value it can take any value out of a list that we shall enumerate. Various enumerated types are inbuilt into the language. As you follow the language you will become familiar with these but at least three of these are quite common and enumerated type Boolean has the value false or true. So if you have a scalar which is discrete and enumeration type then a predefined enumeration type is a Boolean type and the Boolean has enumerated values true and false it can take only these two values. We have an enumerated type called bit the type bit can take values 0 and 1. So this is also a two valued enumerated type the enumerated type is therefore 0 or 1. Notice that the integer 0 or 1 is therefore quite distinct from the enumerated type 0 or 1 in VHDL and VHDL is a very strongly typed language it insists on these distinctions being made. The third built in type which is enumerated is character essentially these are ASCII values or whatever values which represent text characters and these are all enumerated. Therefore the type of characters known to the language is limited by this enumeration and this is a longer list than Boolean or bit that we had seen which are two valued. So these are essentially all the alphabet characters which are enumerated and a scalar type which is of type character can take any one of these specified values. So a character type can take any one of those specified values. Notice that internally all the discrete types and indeed all the floating points are represented using bits that means 0s and 1s but as far as the syntactical structure of the language is concerned the it checks that the value is either false or true in case of Boolean either 0 or 1 in case of bit or any one of the specified text characters in type type of character. What it does internally to represent these is of no concern to the person who is using VHDL. Apart from these three you have other specialized enumeration kinds these are severity level in case of an assertion which is a statement that we shall see later there is a file open kind which essentially is associated with the type file and file open status file open kind could be are you reading a file for read only or for read write etcetera and file open status whether this file is open whether it is successfully open in the specified mode or not etcetera. So the file open status is also of an enumerated type. So these are the predefined enumerated type but the option remains with the user to define enumerated types of your own these are the ones which the language provides to you but you do have the option of defining your own type which is enumerated. For example you might design an ALU and define an enumerated type called ALU command and the ALU command could have any one of the enumerated values add subtract multiply or divide. So enumeration types which are shown here are those which are already built into the language but you can expand these types by defining your own enumerated types. As far as floating points are concerned the built in type for that is called real. As far as physical types are concerned for scalar there is only one predefined physical quantity and that is time of course we have seen that time is crucial to hardware description language and therefore time is predefined in VHDL. So that is the physical type which is predefined in VHDL however as in other cases you can define your own physical type which will carry its values and its units that you can declare. Having looked at scalars it is now meaningful to look at composites. So composites are collections of scalars and you can have unconstrained arrays or constrained arrays. Unconstrained arrays are things which can have any number of scalar quantities which are associated with them. Constrained arrays are those which are restricted to a particular range of scalar values. Two unconstrained arrays are predefined in the language. A bit vector is an unconstrained array of bits which we had earlier seen in the enumerated types. The bit vector can be of any size that is why it is unconstrained and therefore the size has to be defined by the user. So when you use a bit vector which is the collection of bits for example you might have a data bus. It is for you to decide that this bit vector will have 16 elements whose index will run from 15 to 0. Similarly unconstrained array of the type string are predefined strings are collections of the type character which is an enumerated type in VHDL. So in short the bit type and the character type have associated unconstrained arrays declared already in the language. So therefore bit vector is in fact an element of the language. You can directly use and declare some collection of bits to be bit vectors without having to describe a new type. Similarly you can declare a collection of characters to be a string which is an unconstrained array. Whenever you use an unconstrained array then you have to fix the size of this unconstrained array. The type does not constrain the size. The user when invoking that type will fix the size. On the other hand in case of a constrained array the size is previously fixed. For example you might declare a type called byte and byte might be a constrained array of bits and now the size is predefined in the type itself and therefore a byte has to be an a collection of 8 bits. Such arrays are called constrained arrays. So now we have seen the kind of data types which constitute this language. Many data types are predefined. We have had a look at many of the important types. We have not looked at excess in file types which we will see later if we cover this in this lecture but as you use VHDL in actual usage you will become familiar with those types as well but these are more fundamental types which you must be familiar with before you start using VHDL. So enumeration type allows us to define a set of values that a variable of this type can acquire. For example we can define a data type by the following declaration. The keyword type must be used first. You say type INSTR instruction is and then you give a list of values which are enumerated. So for example I might say type instruction is add, subtract, add with carry, subtract with borrow, rotate left, rotate right. This limited set of commands now has been enumerated and now a variable or a signal which is defined to be of type INSTR instruction can only be assigned values enumerated above. That means a particular signal say S which is of type instruction can only acquire values which are add, subtract, add with carry, subtract with borrow, rotate left and rotate right. In actual implementation as I had said earlier these values may be internally mapped to a 3 bit value because we have only 6 possibilities. However, an attempt to assign a 3 bit value say 0 1 0 to a variable of type instruction will result in an error. It is for the VHDL to use 0 1 0 for one of these possibilities internally but externally you must respect the enumeration that you had declared. So if you want the fourth here so assuming that this is 0 1 2 3 4 and 5 and internally rotate left might use the bit combination 0 1 0 but direct assignment of 0 1 0 when you mean rotate left is wrong as far as the language is concerned. You must only assign the value ROTL to this kind of variable. So only the enumerated values can be assigned to a variable of this type. As we had said earlier a few enumeration types are predefined you do not have to define these using a type statement. A few enumeration types are predefined in the language these are this is effectively the declaration that you might have had to use had these not been predefined. Type bit is 0 and 1 notice the quotation marks around 0 and 1. This distinguishes it from the integer 0 and 1. When there is no cause of confusion then you can skip the quotation marks otherwise the quotation marks must be used. Because 0 and 1 can be confused with the integers 0 and 1 the language requires you when you use them for a bit to put these quotation marks around 0 and 1. That Boolean is predefined and it can have the values false and true type severity level is also predefined and it can only take these values note warning error and failure. These are the four severity levels these are severities of failure of assertion which are used by the language type file open kind is also predefined as we had seen earlier and it can have one of these three values read mode right mode or append mode. The difference between right mode and append mode is that right mode begins from the start of the data structure append mode starts adding from the end file open status is also predefined and it can only take values open status error name error or mode error. In addition to these the character type enumerates all the s k characters which exist. So, these are the predefined enumeration types which are available to you now notice that for each type you can define a subtype which does not use all the possible values defined in the main type. For example, if you use the IEEE library it defines a new signal type called STD logic which is quite commonly used STD logic is a signal which can take one of nine possible values it is defined by a statement of the type type STD logic is U which stands for undefined X which is unknown 0 1 obvious binary values Z which is open circuit W which is a weak version of X L low which is a weak version of 0 H or high which is a weak version of 1 and do not care which is represented by a dash. So, a signal can in fact take one of these nine values now suppose we do not want to use all nine of these in our design then you can define a subtype of this kind of signal. The subtype let us say uses only these four values X 0 1 and Z indeed these are the four values which are used in very long as you might learn later this can be defined to be a subtype of STD logic. We might use the statement subtype we must give a name to this new subtype and what we have chosen here is four well logic. So, we will say subtype four well logic is STD logic because it is a subtype it must refer to the parent type which is STD logic range X to Z that means it will take this sub range X to Z of the main type which is STD logic. Similarly, we may want to constrain some integers to a limited range of values this can be defined by a new subtype for example, we might say subtype bit num is integer range 31 down to 0. So, that means bit number is actually an integer bit number is an actual integer subtype which has all the properties of integers with the additional constraint that can only be in this range 31 to 0. When do we describe a new type and when should we describe a new subtype the advantage of using a subtype is that all the procedures which are defined for the main type are then inherited by the subtype otherwise you have to define your own procedures for a new type. For example, and of STD logic is defined by the type now if you define a subtype then the and is inherited from the main type this inheritance is quite convenient and when you want to use this inheritance then it is better to define a subtype. If it is a completely independent type then there is no need to force a subtype declaration then you can declare a new type but now you have the responsibility of declaring all the functions which are valid to operate on this type. So, for example, the bit num that we had seen with the restricted range of 31 to 0 was a subtype of integer and therefore, functions defined on integer like additions of fraction multiplication and so on are directly inherited we do not have to define them all over again. This makes it clear of about when to use a subtype and when to use a type we should now look at physical types we had seen. So, now we know the discrete types which are used the physical types are objects which carry a value as well as a unit. So, physical types are a data type which carry a value as well as a unit these are used to represent physical quantities such as time resistance and capacitance time is predefined but we do have the option of defining our own physical type called resistance or capacitance. The physical type first defines a basic unit for the quantity and then may define other units which are multiples of this unit. Time is the only physical type which is predefined in the language the user may define other physical types. This is the predefined type physical and the predefined unit is femtoseconds. So, you can say type this is how it must have been described internally it is equivalent to a definition of this kind type time is range 0 to some maximum value. Then you have a declaration units and the base unit is declared first this one is compulsory others are optional. So, the base unit then is femtosecond and then we declare that a picosecond is in fact 1000 femtoseconds. A nanosecond is then 1000 picoseconds, a microsecond is 1000 nanoseconds, a millisecond is 1000 microseconds, a second is 1000 milliseconds, a minute is 60 seconds and an hour is 60 minutes and this ends units for time. This is a complete definition of the type time internally again it will be kept as femtoseconds. You may however assign a value to a time type object of let us say 500 microseconds. This declaration makes it possible for the language to establish an equivalence between microseconds and the base unit which is femtoseconds. It will be automatically converted to the base unit and then stored in base units. At the time of reporting it will be reported in the convenient units which you can choose. This is the predefined physical type. The user may define other physical types as and when required. Just to take an example let us say we want to define a new type, new physical type called resistance. We can declare it as saying type resistance is range 0 to 1 E 9 with units ohm that is the base unit and derived units which are k ohm or kilo ohm equal to 1000 ohm and m ohm or mega ohm to be 1000 kilo ohms and units resistance. With this block of declarations we now can use types which are in fact of type resistance. Having done the scalar types let us now look at composite data types. These are the types which consist of a base unit type and then what we declare is a collection of composite types. So composite data types are collections of scalar types. VHDL recognizes records and arrays as composite data types. Records are like structures in C. They permit a collection of heterogeneous kinds of scalars. Arrays are indexed collections of scalar types. The index must be a discrete scalar type. Notice it need not be an integer. It can be any discrete scalar type and arrays may be one-dimensional or multi-dimensional. So essentially if you have to put lots of scalar types together if they are all the same type then you can describe this collection as an array. If they are not of the same type then you have to declare a record and describe what combination of dissimilar types will constitute that record and now you can put scalars of those dissimilar types into composite data types called records. Arrays are particularly important and they can be constrained or unconstrained as we had seen earlier. In constrained arrays the type definition itself places bounds on index values. For example, we might say type byte is array 7 down to 0 of bit or type rotation matrix, rot matrix is array 1 to 3 comma 1 to 3 of real. So it is a two-dimensional array for a rotation matrix which will have sin theta cos theta sin phi cos phi kind of entries therefore those are real and we have defined a 3 by 3 array of these as a rotation matrix. Notice that the size of these objects is now fixed. In unconstrained arrays no bounds are placed on index values. Bounds are established at the time of declaration. For example, we might declare a type bus to be an array unconstrained array of bits. So then we will say type bus is array natural range this empty symbol which is essentially less than any greater than concatenated of bit. So here we are saying that the type bus bus is an array of bits it will be indexed by a natural number that means it the index cannot be negative. However, the range is left undefined in the type when this type will be used the user will declare the range. For example, when using it the declaration could be signal address bus is of type is bus 15 down to 0 that means the address bus is 16 bits wide. However, the same type namely bus can be used for data bus and the declaration will be signal data bus is bus 7 down to 0. So it is at the time of usage that the size of this array has been declared that by intrinsic property this is unconstrained the constraints are placed to when it is actually used such arrays are called unconstrained arrays. There are as we had said earlier built-in array types where bit vector is an unconstrained array of bit and string is an unconstrained array of character. As a result you can directly declare variables or signals of this kind. For example, you might have a declaration which says variable message is a string 1 to 20 notice string is an unconstrained array of characters and here we are saying that message will be a collection of 20 characters whose index will go from 1 to 20. Similarly, we might declare signal a register a range is a bit vector 7 down to 0 bit vector is a type already known to the language and it is an unconstrained array we are putting the constraint here 7 down to 0 and saying that this constraint type should be used for a range. So, this is how we use the built-in array types records are on the other hand collections of different types. So, while an array is a collection of the same type of objects a record can hold components of different types and sizes this is like a structure in C and the syntax of a record declaration contains a semicolon separated list of fields each field having the format name name name subtype. For example, type resource is record and then within brackets p range q range each of which is a bit vector 7 down to 0 and enable which is of the type bit. So, this record resource now will always have two 8 bit registers and a bit called enable. So, these types are in fact of different types and you can connect them together collect them together in a type called a record and you give it a name called resource and now you can declare objects of the type resource where each one of those objects will contain two 8 bit registers and a 1 bit enable. So, these can be used indeed later and we have seen one example of this the port list is in fact a record it has different kinds of signals some are input others are output some could be bits others could be bit vectors and so on. And that collection is in fact a semicolon separated list of different types and each type of the same type is a comma separated list. So, that is how we have used the port list earlier and now we can recognize that in fact a port list is actually a record. With this I think we have reviewed the basic elements which constitute VHDL. We have looked at object types we have looked at data types we have seen the various in built scalar data types we have looked at the collections which are predefined we have looked at physical types and we have also seen how you can declare your own types. The hardware itself we have understood has templates which are entities with their corresponding architectures a specific template can be chosen to define a component. And once you have defined a component then you can instantiate actual instances of these components. Various components can be interconnected using signals and signals can have various kinds they can be of scalar types or they can be of arrays like buses and so on we have seen examples of all of these. So, armed with all these basic types we can now see a few examples of hardware description languages. I must emphasize here that in a brief course of lectures it is impossible to cover all the nuances of a language what we have done here is introduce you to the basic types and it is important to understand what these types represent and what they find distinctions among them is this part is essentially required to be done in a lecture series. We will use a few examples in a very brief survey of the VHDL language but in order to learn VHDL descriptions you must use some standard text and you must use some actual programs which allow you to describe hardware using VHDL and we shall do this in the following lectures.