[MUSIC] Hello everybody, this is the last lecture devoted to the VHDL language. We have seen so far, and of course in a summarized and simplified form, the lexical and syntax of the language, the basic units like "Entities" and "Architectures", and the sequential statements. However, VHDL, was designed to model hardware, to model circuits, and the different parts of a circuit work, by nature, simultaneously. VHDL addresses this challenge through concurrent statements, which are the main focus of this lecture. A previous comment: A VHDL program or VHDL model mainly consist of a "Package" unit that includes in general definitions of data types, objects, functions and others, An "Entity" which describes the circuit as a black box, specifying input and output ports, and an "Architecture" that models the behaviour of the structure of the circuit. Well, all the statements inside the "begin .. end" block of an Architecture must be concurrent. OK? inside the "begin .. end" block of an Architecture must be concurrent. OK? In particular, Processes are concurrent structures and, as such, they can be a part of the Architecture. Well, Processes are also very special structure because they can only contain sequential statement inside. OK? can only contain sequential statement inside. OK? So, this will be the global aspect of a VHDL model. In this lecture, we will focus our attention on concurrent statements and we will devote a couple of slides to seeing how the VHDL is used in practice, how VHDL is used not only to model hardware systems, but also to simulate circuits and to automatically synthesize them. Let's begin with concurrent statements. Concurrent statements may appear in several VHDL units, mainly in Architectures, but also in Entities or Blocks. We won't consider Blocks, in this course. But to satisfy your curiosity, Blocks are structures that allow you to group sets of concurrent statements for later use. In this lesson, we will see the following concurrent statements: The "Process", very important one; several variants of the signal assignment; The declaration and use of components, and the "Generate" statement. One important point is that any concurrent sentence has a Process equivalent and, in fact, when a VHDL model is going to be used to simulate a circuit the compiler translates all concurrent statements to the equivalent Processes, so the simulator sees the Architecture unit as just a set of Processes. [BLANK_AUDIO] Let's see the first of the concurrent statements, the "Process". The Processes too that, remember, contains only sequential statements and that runs continuously; it's a kind of infinite loop controles on one side by "wait" or "stop" statements that control when the Process is stopped or reactivated, and on the other side by the sensitivity list, which reactivates the Process when one event in one of the signals happens. For a proper functioning a Process must contain some way to control when to stop and when and how to reactivate. The sensitivity list is also used for the Process to communicate with the rest of VHDL code. This is the syntax of the Process statement: An optional label, followed by the word "process", optionally followed by the sensitivity list, plus the word "is", then some local declaration if required, and a "begin .. end" block where the functioning of the Process is described. [BLANK_AUDIO] Here we have two alternative ways to control the execution of a Process. In the first case, when an event happens on some signal of the sensitivity list, the Process runs one time and then stops, waiting for a new event. In the second one, there is no sensitivity list but the list of signals controlling the reactivation of the Process has been defined as conditions within a "wait" statement. Let's go to the next statement, the "signal assignment". Well, we saw the signal assignment when describing the sequential statements, and the same conditions apply here. The signal assignment and some other sentences that we will see later on can be used in both sequential and a concurrent environment, but the concurrent signal assignment admits a couple of variants that the sequential statement doesn't. We already know the syntax of the signal assignment statement: An optional label followed by the name of the signal, followed by the special symbol for the assignment, the type of delay if any, and the expression whose value is going to be assigned to the signal, and optionally a delay. This example shows a description of a Full Adder by using these three signal assignment sentences. The only difference with a sequential signal assignment sentence is that, now, they are supposed to be in a concurrent environment, as for instance, an Architecture unit, and thus they will be executed simultaneously. There exist two variants to the concurrent signal assignment statement, the "conditional signal assignment" and the "selected signal assignment". The conditional signal assignment assigns different values to a signal depending on which condition holds. As a matter of fact, the conditional signal assignment is quite similar to an "if" statement in the sequential world. We can see here the syntax of the sentence: An optional label, followed by the signal identifier, plus the special symbol, a delay_type if any, and then if this condition holds then expres_1 or waveform_1 is assigned to signal; if the second conditions holds, then expres_2 is assigned to signal, and so on. It's easy to explain how the conditional signal assignment work over an example. Here if Sel=0 then A is assigned to S and, on the contrary, signal B is assigned to signal S. We said that any concurrent statement has a Process equivalent and that, in fact, to simulate the circuit the compiler sustitutes all the concurrent sentences by Processes. So, here we can see the equivalent Process of these conditional signal assignment sentence. Signals appearing at right of the assignment symbol constitute the sensitivity list of the Process, and in the "begin .. end" block we have this typical "if .. then .. else" structure. If Sel=0, then A is, goes to S; and on the contrary, B goes to S. We can have expressions slightly more complex, like in this second example. Here if Sel2=00, then E1 is assigned to S, if Sel2=11, then E2 is assigned to S, and otherwise the value of S holds (this is the meaning of this word, "unaffected") the value of S holds (this is the meaning of this word, "unaffected") saying that otherwise, just do nothing. OK? saying that otherwise, just do nothing. OK? And again, there exist an equivalent Process where, another time, again, the signals appearing at the right of the symbol, constitute the sensitivity list, and we have in this "begin .. end" block two nested "ifs", this one and this one. Note how this word "unaffected" has been translated here by "null" with just the same meaning, just do nothing. In the Selected Signal Assignment different values are assigned to the signal depending on the value taken by one expression. Here we have the syntax: If this expression takes the value 1, then this expression or waveform is assigned to signal, if this expression takes the value 2, then this second expression or waveform is assigned to signal, and so on. Let's see an example. Let's assume there exists a data type called "opcode" that can take the values "add", "subs", "andL" and "orL", And we have defined a signal opcode, operation, excuse me, with a type "opcode". This selected signal assignment is telling us that when operation="add" then Op1+Op2 is assigned to Result; when operation="subs" Op1-Op2 is assigned to Result, and so on. As in the previous case, the selected signal assignment has an equivalent Process like this one, where we can see that, again, the signals at right of the assignment symbol constitute as the sensitivity list. and where the functioning of the concurrent statement is implemented by a sequential "case". Let's go to a new concurrent sentence, the "Component". The "Component" sentence declares components, and components are blocks or modules, usually hardware gates, memory elements, or more complex pieces of circuitry, which has been defined, has been described, somewhere in the VHDL code, and that will be used to describe the system we are modeling at the structural or hierarchical level. Components are usually defined in the standard user defined libraries, where the Entities and the Architectures of these components are specified. This is the syntax of the "Component" statement: the word Component, followed by an identifier, plus the word "is", an optional list of generic parameters if required, and the list of input output ports. Once declared we can use these components, we can instantiate the component by writing its name, and set another timer of optional generic parameters, and associating the input output ports with the signal that will actually enter to or out from this particular copy, this particular instantiation of the component. Here we have an example. A component named "example" has been declared, having input ports "a", "b", "c", and one output port "d". Here, we are associating input-output ports to signals "X", "Y", "W", and "Z". We are saying that, in this particular instantiation signal "X" will enter to port "a", signal "Y" will enter to port "b", signal "W" will enter to port "c", and the output port "d" will go into signal "Z". In this case, we are associating ports and signals by position, but we can make this instantiation by name, like here: We are telling the same information, specifying that the output port "d" will be assigned to signal "Z", that signal "X" will enter to port "a", signal "Y" will enter into port "b", and so on. Another more complex example: Let's assume we want to model our famous and very well known Full Adder, OK? Let's assume we want to model our famous and very well known Full Adder, OK? We defind the Entity as a black box having 3 1-bit input ports, "X", "Y", and carry-IN. And 2 output ports, carry-OUT and "Sum". We are going to build the Architecture by using two components; component "HalfAdder", and the component "OrG". The component HalfAdder has 2 input ports, I1 and I2, and 2 output ports COut, and Sum. As a matter of fact, HalfAdder is simply an Adder for two 1-bit numbers without any input carry. And here we have the declaration of the OR gate, OrG, Which is a component with 2 inputs I1 and I2, and an output O. Once declared, we can use them in the "begin .. end block" in order to describe this structure. We have a first instantiation of the HalfAdder here, assigning signals X, Y, A and B to the input and output ports. You see X and Y are assigned to the input ports of this HalfAdder, and signals A and B are assigned to the outputs. A second instantiation is describing this second HalfAdder assigning signals B and CarryIn to the input, and C and Sum to the output. And finally we have here a copy, an instantiation of the OrG, having as inputs A and C, and having COut as the output. See how in the two first cases we are using a positional association list and in the third case we are associating signals and ports by name. Somewhere in the VHDL model, there is some library where wee have a definition of the functionality of the HalfAdder and the OrG components in terms of, well, a table like this one. Sentence "Generate" is also very important. It's used to generate arrays of component instances. This is the syntax. There are two variants, one with a "for" plus a range of specification, and another with an "if" plus some condition. Let's see a simple example: let's assume we are building an N-bit register. Remember, this register is just a device capable of storing N bits of information. And we want to build this register as an array of N components called DFF. We have the Entity, defined here with inputs and outputs. Our circuit allows to enter N-bits of information in parallel, and outputs also in parallel N-bits of information, so that's why we have defined output E and output S, as vectors from N-1 to N. Another signal, another input signal "clock" is needed to properly synchronize the functioning of all the DFF blocks. Don't worry right now, because we will discuss the topic of synchronization next week. We declare also a generic value, N, that will allow to resize the registers when we want to. In the Architecture, we define the component, and variable I that will be used as index for the Generate sentence, and here, in the "begin .. end" block you see how we use the Generate to instantiate N times the DFF block connecting, in each step, the clock signal, to all DFF to the port clock with the same name, the signals E from N-1 to 0 to the input ports with the same name,and the signals S from N-1 to 0 to the output port with the same name. Well, see how easy it is to model this circuit by using an only, a unique Generate sentence. Finally sentences "assert", "procedures", and "functions". as the simple version of the signal assignment sentence, are statements identical to their sequential counterparts. That is, they are statements that execute sequentially or concurrently depending on their environment. So, well, nothing to add to what we saw in the lecture devoted to sequential statements. With this, we conclude the topic of the concurrent statements. But, before ending the set of lectures devoted VHDL, I would like to introduce and briefly discourse the last important topic: How VHDL models are used to simulate and synthesize, digital systems. How do we face the design of, let's say, a big digital circuit. Well, we start with the specifications of the system and we, let's say, polish them up to the point in which we can build a model of the circuit using, in general, a hardware description language. I'm using the generic term HDL: "Hardware Description Language", because VHDL is not the only one. Nowadays two languages are widely used to describe the hardware. One is of course the VHDL and the other is Verilog. VHDL is more structured, it ia a more structured and algorithm language than Verilog, and this is the reason why we selected VHDL for this course. Well, we are saying that we refine the specifications and we finally have an HDL model of the system to design. Then we enter this model to the simulator, ... We will have to add to the VHDL model a description of the values, of the input signals, that the system is going to receive along time, what are called the "stimuli" to the system. Simulators compute and display the values that outputs and even internal signals take at any time and, with this, we can check if the output values delivered by the system match with our initial specifications. If no, if there is no match, we will have to check the stimuli and simulate another time, or check the model, or even check our initial specifications. Well, after several passes, we will hopefully get simulation results that match with our specifications, and then we will proceed to synthesize the system. We will synthesize the circuit by using this, let's say, refined VHDL model that matches with our initial specifications. To do so we use automatic synthesis tools capable of building the VHDL model by using a particular component library and a particular technology. The synthesis tool demands the VHDL model, the component library, and a set of synthesis criteria as, for instance, do it prioritice speed, that is, a circuit as quick as quick as possible; or cost, a circuit containing the minimal number of devices; or maybe power consumption. conservation. Now let's see see a small example to try to understand how simulation runs. Here we have the VHDL model of a very simple circuit. The Entity doesn't contain any input-output port, so the circuit is self contained. The Architecture consists of two Processes: The first one describes the function to implement and the second one defines the values that inputs "a", "b", and "opcode" will take during the simulation. The first Process is defining what we name the "function under test", and the second defines what we call the "test vector wavefroms", or the stimuli to the circuit. Lets analyze the the waveforms. See here, that at time t=0, "a" takes the value of 0110, "b" the value of 0101 and "opcode" the value "add", and then this Process stops and waits for 100 nanoseconds. After 100 nanoseconds the value of "opcode" changes to "sub", and the rest of the values of the inputs remains unchanged. And, another time, the Process stops and wait for 100 nsec. After this second 100 nsec "b" takes the value 1001 and wait another time for 100 nsec. See here that finally, "opcode" takes the value "addA" and then the Process goes to unconditional "wait" statement that stops completely the Process and never reactivates. The result of all these input assignments is this wavefrom we see here, OK? See how at t=0 we are here, a=0110, b=0101. See how at t=0 we are here, a=0110, b=0101. thses two values, and "opcode" takes the value "add". Then, 100 nanoseconds later, "opcode" changes to "sub" and the other two inputs remain unchanged, OK?. Let's see what happened with the function under test Pprocess. When one signal "a", "b" or "opcode" change their value and an event on the sensitivity list of the Process happens. The Process is executed and it stops waiting for a new event in the sensitivity list since, as you can see, it doesn't contain any conditional or unconditional "wait" statement. Any Process executes at least once, so the first time we will have here then a=6 (I'm going to use the decimal, the base 10 notation for numbers), b=5 and opcode=add. "a" is greater than "b" so "x" is set to "a", "y" is set to "b", "s" takes the value 0 and that finish the if-condition and then we go to the "case" statement, "opcode" is equal to "add", so "z" takes the value x+y that is 11, which in reality is 1011, and "sign" is set to 0. OK, that's what we have here. Then, the Process function under test stops waiting for a new change in the sensitivity list. And this change happens exactly here, at t=100 nsec, time equal when "opcode" changes its value to "sub". OK? when "opcode" changes its value to "sub". OK? So the Process reanudates and we will have that "a" and "b" have the same value, so "x" and "y" "s" will have also the same values. But, the "opcode" is now "sub". So, when "sub" sets the value x-y, that is, 6-5=1, or 0001 in binary, and "sign" is set to 0, OK?. Another time, again, Process stops and wait for a new change in the sensitivity list that happens at time t=200 nsec and in this case, "a" has the value 6, but "y" has changed to 9. OK? So, excuse me, this is "b", so as now, "b" is greater than "a", we have x=v, y=a, and s=1. x=v, y=a, and s=1. "Opcode" is "sub", so "z" takes the value x-y, 9-6=3, or 0011, "z" takes the value x-y, 9-6=3, or 0011, and "sign" is set to the value of "s", which is 1, OK? This is the next step, again the Process stops and reactivates at the t=300nsec and finally here, what we have is that "a" and "b" don't change. So we have the same value for "a, "b", "x", "y" and "s". The "opcode" is "add", so, I go on here, OK, "z" takes the value x+y, 6+9=15, 0r 1111 in binary, OK, "z" takes the value x+y, 6+9=15, 0r 1111 in binary, and "sign" is set to 0, this situation. And that stops the simulation because this Process, you remember, has a "wait", a conditional "wait" statement here that stops this Process. As this Process stops there is no change in the sensitivity list of the function under test Process. So this second Process also stops. OK, understand?, ... I hope so. Let's see another example, now using actual simulation and synthesis tools. This VHDL code models, again the very well known ParallelAdder that we have discussed several times. And in particular, we are now considering a 4 bit ParallelAdder. This is the screen of one simulation. You can see here input "x", "y" and carry-in, and here the output "z". and, well, you can see all the changes, this waveforms, analyze them and, when we decide that the simulation is correct, that fits with the initial specifications, we will run the synthesis tools that will obtain, in this case, the gate level schematics shown here. The circuit implements the sum of x+y+carry-in, being "x" and "y" 4-bit binary numbers, and carry-in a 1 bit input carry, OK, clear? binary numbers, and carry-in a 1 bit input carry, OK, clear? All of this is done automatically. So, well, this is how VHDL is used in the design process of big digital circuits. So this concludes this session devoted to concurrent statements, where we have introduced also a brief discussion of how VHDL models are used in the design of digital systems. And this concludes also the short, or maybe not too short, introduction to VHDL, which goal, remember, was not to become you a skilled VHDL programmer but to let you know the basics of the language in order to be able to understand simple VHDL descriptions and in particular those VHDL models that we will introduce in the rest of the course. Thank you very much for your attention. [BLANK_AUDIO]