 In the series of lectures, we have looked at the general principles of hardware description languages and gone through the details of VHDL, which is one of the leading hardware description languages. These days, Verilog is also extremely popular indeed in commercial circles perhaps even more popular compared to VHDL. Therefore, we shall have a brief review of Verilog as a hardware description language. The underlying principles remain the same, but there are some differences in how various objects are handled in Verilog as opposed to VHDL. Therefore, we will begin with first understanding these major differences. Otherwise, it is largely a matter of syntax and once you understand how to program in one hardware description language, it should be possible to adapt to the syntax of another one. The additional advantage of Verilog is that its syntax is very similar to C indeed as it just like VHDL is based on the programming language Ada. Verilog is based on C which is familiar to a very large number of people. Verilog unlike VHDL is case sensitive just like C. It uses essentially the same comment markers etc etc. So, in general it looks and feels very much like C of course as we have often remarked. A hardware description language is very different from a programming language and therefore it retains all the characteristics of a hardware description language. So, let us first of all see what are the major differences in the objects which are handled using Verilog. First of all Verilog makes a distinction between two kinds of signals. The position taken by Verilog is the following. Suppose a particular node is say one. The question is who is keeping at one? Who is keeping this node at the value one? There are two possibilities. One there is a driver attached to this node and this node keeps this signal at one. So, it is the duty of the driver should there be any noise or any loss of charge or whatever to make up these losses and to keep this node at one. Such signals are called continuously driven signals and are in general classified as nets. There is another class of signals which hold their value simply because there is an associated memory with them. That means the assignment to these nodes is not continuous. They are not continuously driven. They are given a value at an instant of time and they have the inherent capability of retaining this value because of the memory associated with them. This class of signals are called registers. Unfortunately, this choice of terminology is not very good. Hardware designers tend to think of registers as a static latch or a complicated circuit whereas a particular node might be termed a register simply because it has a capacitance and once you place a 0 or a 1 on this it is likely to hold this value till a new value is written. So, in short the picture that we take is the following. You have a particular node and either you have a driver which keeps this node at the value which is assigned to it. In that case this driver is continuously connected to this wire and therefore this node is continuously driven and such nodes are called simply nets. You might have a node which has notionally it may not be a piece of hardware but you have notionally a memory associated with this node and now you can assign it a value at an instant of time. You are not continuously driving it to that value. The assignment is made at an instant of time and now it is the memory associated with this node which holds the value at this point. Now, this memory could be as simple as just the capacitance associated. So, such nodes are called registers. So, all signals are either nets or registers. Remember if you have a programming language like interface which is what we called a process in VHDL in that case the assignment takes place only at one instant of time and such assignments are permitted only for registers. Nets are much more common for the structural kind of description in which you place hardware and then you connect wires to these. We shall see later what are the sequential and concurrent elements in very long and the kind of things that we choose kind of signals that we choose depends on whether these nodes are inside those sequential elements or outside. So, this is the first major difference you have nets and you have registers in very long whereas, you just had signals in VHDL. The other difference is the basic hardware object in the language. This is now called a module. The module is in fact an amalgamation of the entity architecture combination that we had in VHDL. In VHDL you could have a single entity with possibly many architectures associated with it and that is because entity and architectures were different bodies. In case of very long we do not do this. The entity and architecture are together. So, there has to be only one architecture and you change the entity altogether if you want to change its behavior. So, unlike VHDL you have a module and the module like a C function has a port list associated with it. So, you might have for example, a module D flip flop and now you will have the port signals as in the case of an entity declaration. You will now declare the ports and other local signals and then this is followed by the body of the module which is equivalent to the architecture. Now, one difference from the syntax of C is that in C we use curly brackets to begin and end blocks whereas, in very long we use the keywords begin and end. As in C the statements are terminated by a semicolon. However, begin and end are commands and do not take the semicolon. So, this is roughly the structure of the basic description of a piece of hardware. Now, let us look at the signals like nets and registers in a little more detail. The most common kind of net are the wires and a wire is just that it is like a wire connecting one node to the other. It has to be continuously driven like any net should be. Now, there are other kinds of wires. These are called W and and W or these are things which are wired and and wired or combinations and should the wire be multiply driven then the resultant value on the node is the and or or depending on whether it is wire and or wire or correspondingly the resultant value on the net will be the and or or of all the driving signals. So, this permits essentially the open collector and other kinds of circuit in which you can have multiple drivers on the same wire. For example, a microprocessor bus can have multiple drivers and the resultant value will be decided by a logical function of all the driving signals. There are also in fact the term try is also used for wires and tries are signals which can from which the driver can be removed which can be try stated and just like wired and and wired or you can have tries with and and or associated with that. Now, very long uses a signal value system by default which is four value. Now, if you recall in VHDL the standard thing defined by the language was bit which was two value, but the most commonly used signal type is STD logic which is invoked by including the IEEE standard library and that was nine valued. Very long takes a middle of the road approach and permits four logical values for each node. These four values are you can have 1, 0 these are the standard bit values, but you can also have Z which is a high impedance value that means this node is not being driven currently even though a driver is attached the driver is driving it to Z that means the driver has been try stated and X which is an unknown. For example, a signal simultaneously driven to 1 and 0 will acquire the value X because its value cannot be determined. So, these are the various values which can be assigned to signals in case of in case of variables or in case of signals in case of in very long. So, we will use this four valued logic throughout in our discussion on very long. Now, just like VHDL we have various styles of describing hardware. We have for example, structural descriptions, there is a data flow kind of description and behavior. Now, notice that when you there are various modules which are built in and known to the language this is different from VHDL. So, very long has built in gates. So, the gate level descriptions do not require you to define the behavior of say a NAND gate as we did in case of VHDL. So, it has built in gates and all the standard gates like AND, NAND, NOR, XOR, XNOR etcetera these are all built in. This immediately brings a kind of problem first of all which has a solution. The AND gate can have a variable number of inputs. So, you have a variable number of inputs and one output. Similarly, any NOR or XOR gate could have a multiple number of inputs and a single output. This being the case it is difficult to describe the structure which you will be using. The module is predefined for you by the language, but you have to place the component in your design. Suppose, you want to use a three input AND gate. Now, the AND gate is provided by the language, but how do you specify all the inputs and outputs of this piece of hardware. Now, because for most of these there is a unique and single output. Therefore, in very long it is conventional to put in the signal list. So, you had for example, module say D flip flop and here we have the signal list the port list. Now, in the port list you place the output first and put as many inputs as you like subsequently. Therefore, since the first element is always there the output is identified and depending on how many additional parameters are provided the language knows how many inputs does this gate have. Of course, this is a user defined component D flip flop is not a part of the language, but even for user defined components we tend to follow the same convention so that we are consistent. And essentially what it means is that this signal list is output first. The declaration of these signals can be in line just like C functions. The type of these things can be in line right here or they can be declared immediately afterwards. So, to complete the example that we started with the module D flip flop could have let us say a signal Q as the output and D and clock as the inputs. Now, because you are going to assign to Q inside this module and perhaps only once and this will retain its value. Therefore, it should be a register. So, the main type of register is called reg and therefore, you will say reg Q which is an output signal. Similarly, D and clock will be declared as wires. This completes the declaration of these signals. This will be followed by a begin and end module and here will be all the logic the equivalent of architecture. So, this is the general structure of describing a hardware element in very long. Having got these so now, we have essentially a combination of various hardware modules. Some of this these are predefined. These are all the basic gates and then there are some which you as a programmer as a hardware description language writer will describe. So, these are user developed. For example, you have this particular D flip flop and now, you would like to put all these together and interconnect them. In fact, there is a user defined primitive or a UDP which is defined in very long. The user defined primitive becomes equivalent to the basic gates defined in the language, but the user defines this primitive as a table driven architecture where the output is a function of all the inputs and all possible combinations of inputs are given in a table. These combinations include values as well as transitions. So, therefore, the behavior of a UDP is nothing more than a table lookup. So, the inputs are presented to the UDP and the output is just read from the table from whichever description matches. This is a unique feature of very long and no such thing existed in VHDL. So, now, you have a combination of the basic gates or the primitives, the user defined primitives and the user developed modules. These are primitives, you have user defined primitives and then user developed modules like this. Now, in structural very long, you will put these all together and then the structural very long is very similar to structural VHDL. And in this case, it is just a matter of instantiation of hardware modules and then you simply instantiate them by giving the instance name, what kind of module you are instantiating and what kind of signals you are mapping. Remember, we did this using a port map in VHDL. Once you have described all this using signals which have been predeclared, you have described a interconnected set of known components and that is the style of structural description. We also have a style which is data flow in which we use a continuously assigned signal. That means, you have the keyword assigned followed by r value. This is the recipient of the value to be assigned equal to some expression. So, this expression is evaluated. This expression could be a logical function and that value is then assigned to this signal. This is the target of the assignment and this is a continuously assigned signal. Notice, a continuously assigned signal will then forever drive this node with this value. This expression will be re-evaluated whenever its sensitivity is struck. That means, whatever signals take part in this expression, if there is an event on any one of those, then it will be evaluated and that will then be assigned to this r value. But the model remains the same that you have a driver with this value which is permanently keeping this net at the value of this expression. So, it is a continuously driven signal. On the other hand, there are two kinds of processes in C and these are called initial and always. Initial and always are otherwise equivalent, but initial is run at the start and it is run exactly once. So, this process is started. It is triggered at t equal to 0. That is the trigger point for starting it and then when it terminates, it is never run again. Another thing to remember is that the contents of initial are ignored by most synthesizers and therefore, the contents are not supposed to be synthesized into the circuit that you are describing. Therefore, the purpose of the initial block is to set up the input signals and so on and not really to describe hardware. In general, initial is widely used in test benches which then apply a sequence of inputs to the hardware that you are describing. Always on the other hand is the standard and the most widely used structure in very long for describing sequentially the behavior. And the innards of always are like innards of process. That means, they look very much like a programming language and most of the programming constructs of C are available as programming constructs in always blocks. So, therefore, it is really convenient to use this. Now, notice that in a sequential block, the assignment is made at a particular instant. So, what is this instant at which this assignment is made and therefore, because the assignment is instantaneous, therefore, the assignments in an always block and indeed in the initial block also, they should always be to a register. So, assignments are to a register. It is for this reason that in the D flip flop that we described, we declared Q to be register because we will be depending on whether clock has had an event or not. We would assign to Q a value inside a logical block which would be an always and therefore, Q had to be a register. In general, there is an implied conversion from a register to a wire at the output of a module. So, then you can connect a wire to the output. There are some very strong notional differences between VHDL and Verilog and we must be aware of those. One of these is blocking and unblocking assignments. These make a very big difference and we must understand blocking and unblocking assignments in Verilog in order to make full use of its facilities. The ordinary procedural assignment which is essentially just signal equal to expression, this implies that the next statement will be taken up only after signal has acquired the value of expression. That simply means that the next expression can assume that signal has already been updated to its value. This is equivalent to inserting a weight 0 in VHDL. These are essentially blocking statements. They block until the L value, the signal on the left has acquired its value. There are also non-blocking statements and the syntax for that replaces this equal to sign by an assigned to sign. So, for example, you can have assigned to signal this expression. This kind of assignment, remember all of these will occur inside an always or an initial block. This kind of assignment is the standard VHDL kind of assignment that we discussed. That means only a transaction is placed for making the signal equal to this value and then you move on before the signal has acquired this value. The usual timing analysis that we had done in the tutorial that we did a few lectures ago, that applies only to the non-blocking kind of assignment. The blocking kind of assignment, you place a transaction and this transaction has to rectify before you move on to the next. What this means is that now you have to be aware when this or this assignment is made. And this is done through two kinds of controls. One is a delay control. That means the assignment is made after a certain amount of delay has passed. So, for example, you might have something like this. It simply says wait for 10 units of time and then assign the value of D to Q. This has to acquire the new value. Only then you will go to the next statement. And therefore, if there are delays associated with various statements, so the not operator is actually the tilde operator. So, that means this will be attempted at 15 units of time. That means delays are cumulative in a very long always or initial block. That is because this unit will first wait for 10, assign the value of D to Q. This assignment is complete. Then you will wait for 5 units of time and then assign the value of not D to Q prime. So, therefore, by the time both Q and Q prime are assigned, 15 units of time have passed. Notice by the way that there are no physical types in very long. So, time is just like a 64 bit value and the implied units have to be declared right in the beginning by a statement which is time scale. So, therefore, all design modules begin with a time scale declaration and this gives the time in units resolution format. The implied units are these and these units are maintained with this resolution. For example, you might say that the units are 1 nanosecond and resolution is 100 picoseconds. So, the time will be quantized 200 picoseconds and the values will be reported in nanoseconds. You can choose your units. Now this particular declaration causes all 64 bit values of time to be scaled according to the time scale value given. An interesting combination occurs when different modules which are being combined use a different time scale. In that case internal conversion takes place of all those times and the lowest unit is the unit which is internally used. However, there is no inconsistency. You can freely mix different time scales of resolution and the reasonable thing will be done. There are other features of the language which are different but one particular side effect of blocking and non-blocking assignments must be well understood. Otherwise, you may land into trouble while using very low and this I illustrate by the case of a shift register. So, let us say that you have a shift register and the output of this becomes the D of this. So, this could be Q2, Q1 and Q0. This is the input. All of these are clocked together by the same clock signal. Now we suppose in an always block we say that at posage of clock by the way that even control we will come to in a little bit but let us understand this concept first. So, when there is a positive edge on clock we are going to say that Q2 equal to in Q1 equal to Q2 and Q0 equal to Q1. This seems a reasonably good description of this hardware saying whenever the clock has a positive edge then make Q2 equal to input, make Q1 equal to Q2 and make Q0 equal to Q1. However, this can land you in trouble. Notice that this is a blocking statement. Therefore, Q2 will acquire the value of in before the next statement is executed. Therefore, Q1 will not be assigned the value of old value of Q2. It will in fact be assigned the value of in because by the time you came here Q2 has already acquired the value of in. Similarly, Q0 will also be acquired will also be assigned the value of in because Q1 has completed acquiring the value of Q2 before the next instruction executes. As a result essentially you have Q0 equal to Q1 equal to Q2 equal to in in one clock cycle. That is equivalent to saying that you are describing not this circuit but a circuit in which Q0 Q1 Q2 and in are all shorted. This of course will not do what we want to do is to describe a shift register and the answer is that in this case we must use non-blocking statements which will follow the kind of logic that we had developed during the tutorial. So, in that case you assign Q2 like so assign Q1 and Q0 by these. Now, what happens well a transaction is placed on Q2 to acquire the value of in in the next time cycle here of course the delay is 0. So, therefore, in next delta. However, currently Q2 keeps its old value and because this does not wait for Q2 to acquire the transactions value the next instruction is executed before Q2 value changes. As a result the correct value is then scheduled to be given to Q1 that means the transaction is placed on Q1 for the value Q2 and the same thing for Q0. And this will have the correct shift register behavior just to give you an idea let us say in is 0 and Q2 Q1 Q0 are 101 at t equal to 0 and then these instructions are executed. In the two cases we will see what happens in the first case Q2 is made 0 and indeed acquire the value 0 before we move to the next instruction. So, at t equal to delta Q2 is already 0 and this instruction is executed only in the next delta. Therefore, Q1 becomes 0 because Q2 is 0 and indeed now we must wait till Q1 acquires this value that means we must wait for the entire delta and now Q1 becomes 0. And finally, at t equal to 2 delta Q0 also becomes 0 because Q0 equal to Q1 Q1 is 0. And therefore, at 3 delta all values are 0 in this case. So, it is not a shift register at all. However, in this case let us say that the first statement occurs at t equal to 0 in that case Q2 is scheduled to receive the value of in which is 0 at delta. However, the time is still 0 and we do not wait for Q2 to acquire its new value we go to the next statement in the current delta itself. Therefore, the next statement occurs at t equal to 0 itself not at t equal to delta. Now, when you say assign the current value of Q2 to Q1 the current value of Q2 is in fact 1. That means Q1 is scheduled to receive 1 at delta and then we proceed we place this transaction and we proceed we do not wait for Q1 to acquire this value. And therefore, the next one also takes place at t equal to 0 and now Q0 is scheduled to acquire the old value of Q1 which is 0. And then at delta all these values are assigned and therefore, Q2 becomes 0, Q1 becomes 1, Q0 becomes 0. So, essentially you have 0 1 0 Q2 Q1 and Q0 acquire the new values at delta and that is correct because you had 0 at the input and 1 0 1 in the shift register. When you shift then you will get 0 1 0 and that is what we get. Now, this is all very well this is the very simple case how do we know when to use blocking and non-blocking assignments. So, because the effects can be disastrous if you do not understand what the impact of these is and when it is appropriate to use blocking assignments or non-blocking assignments. This whole business comes about because the blocking assignment which is traditionally used is actually not physical in the sense that hardware does acquire time. And therefore, if we are describing everything together what very long does is to shift the responsibility of properly interpreting this description to this synthesizer. And therefore, the simulation can sometimes lead you to difficulties. Now, in general there is a thumb rule which is fine. So, essentially if you are if a memory is in if there is memory involved then use non-blocking if there is combinational logic then you may use equal. So, this now introduces a new complication in very long which did not exist in VHDL. In VHDL we use the same kind of assignments throughout. And in very long now we must determine whether the assignment is being made to an element with memory. Now, notice that this memory is of a different kind this is the proper register kind of memory the latch kind of memory. Whereas, of course every register had a memory, but assigning to register is not always with non-blocking. So, there is this complication in very long. I think it is difficult to pan the entire language in one lecture. However, as I said before the real understanding of the language will come when you practice it. However, these things are a bit hard to comprehend at the beginning and therefore, I have picked out those things which require special understanding. So, essentially what we have what you need to keep in mind is first of all the difference between nets and registers. And then blocking and non-blocking assignments that nets need continuous assignments that registers are assigned at a particular instant and that instant is determined either by the delay control if you do not give a delay then 0 is assumed or what I did not describe in great detail is an event control. So, for example, you might say at pause edge clock this is called event control. So, there is an implied instance at which every assignment is to be made in a sequential block in very long and that implied instant could be if it is not given could be just hash 0, but hash anything is essentially wait for this much time or wait till this event becomes true and then make the assignment. Because the assignments are made at a sharp instant of time and then the node is supposed to hold that value for future therefore, that has to be a register time. So, it could be typically a reg. As I said you need to practice it and I would like to finish this lecture by giving you a kind of list of resources which you may find useful. Again for very long there is a very large number of good books just to name a few there is one by Samir Palnitkar and another by Bhaskar A. Bhaskar think the Samir Palnitkar book is published by Pearson Education. Bhaskar's book is called a very long primordial. In addition to that there is a public domain program which is excellent which is called Icarus very long. Its versions are available for Linux as well as Windows though it is largely meant for Linux kind of systems. It is a public domain implementation if you do not have access to professional VLSI designs software you can download and install it on any Linux installation. Icarus very long is a fairly complete implementation of the language and it works like GHDL in the sense that it produces an executable by default a.out as is the common practice in Unix. So, it produces an executable a.out and when you execute this executable file then the simulation outputs are reported to you. Icarus very long is then coupled with the same waveform viewers that we had discussed earlier and those waveform viewers are essentially VCD in VCD format which is the value dump format that very long has. And there are many public domain programs for viewing these waveforms. A prominent one is the GTK wave. I think with this we shall bring this lecture to a finish. We have just had a general introduction to very long. I would not call it sufficient for you to even start writing modules in C. However, excellent resources are available in C. By the way, an excellent learning module on very long is available from Siri Pilani and this learning module was developed for the SMDP program special manpower development program for VLSI design. But it might be available in the public domain and this is an excellent step by step tutorial on how to learn very long by yourself in a lab. That assumes the availability of let us say cadence or other kind of VLSI design synopsis very long software. However, it will work equally well with the IKRS very long and GTK wave combinations. What I suggest is that you acquire these learning aids and actually program using either GHDL in case of VHDL or IKRS very long in case of very long and then you will appreciate the concepts that we have discussed in these lectures well. We bring this lecture to an end here.