Hello and welcome to lecture number 21. In this lecture, we will discuss two important features that were introduced in 2009 and 2012 LRM namely the lead declarations and a checker. So, let's start with lead declarations what is a lead declaration is basically is used for customization just like not just like but much more powerful than what we have or what we are used to. We take define text substitution macro. so here also we are substituting text but we are doing a lot more. So that is lead.
So the first question that comes to our mind is, well, why can't I just use take define, number one take define is kind of a subset of lead. And take define is global, global in the sense and I will show you an example in the very next slide. It is true compile time global text substitution macro. If you define it in some global file for example, and then someone else for example, does not realize that it's already been defined goes ahead and redefines it. Well guess what the new definition will overwrite everywhere and everything that follows that particular new definition and we we do not want that. So, number one let construct is safer because it has a local scope and as I just said take define is global.
A lead decorate declaration is actually a template expression. What it means is that a lead can be parameterized or as LRM calls it, it can be customized by sports. I take defined cannot do that and this is one of the biggest Advantages of lead, why lead was actually included in the new 2009 2012 LRM and a lead construct maybe instantiated in other expressions. So let's see how this all works. So here's an example of lead declaration and how that expands. Here's a module called example, it has a bunch of variables of type logic.
And let's use let this is the name of lead x def let equal to r one or r two. Then in the always acquisition of clock we are going to say, we are going to redefine x deficit. Now no that is always cause edge. Blog we have given it a name and as you know in Verilog once you give a label a name to a certain procedural block, Then everything inside that remains local to that block. Now, this was not true we take define, which I will show in just a second. So, what we are doing is we are redefining x def let with r one and r two as opposed to r one or r two.
And then we here we are saying r three r equal to x template. So, x def like is going to be expanded quote unquote, into its definition. And here the definition is r one and r two, not r one or r two. So, then r three is going to become r one and r two. Now, let's say in some other procedural block, always at positive edge clock one we are going to say r four equal to x definite. Which definition will it take will it take r one in our tour we'll take our one or two.
This x definitely the first one really definition here is local to this block. So, this is the big advantage of lead versus take define. And so, this particular definition is not visible in this second always add block. And this one will always take the definition from the scope that is visible to it. So, the scope that's visible to this all is blog is the outermost scope. So, after expanding x def lead, you will basically get our for equal to r one or r two.
So, this is just to make the point that x let declarations are local. And that you must be familiar with this. What if you use to define instead of lead. So, same example, instead of lead I'm saying take define. So, I'm saying take define x template r one or r two. And in the first procedural block, I'm going to redefine it saying take define x template r one and r two exactly like what I did with the letter Example.
Okay, then now I say are three equal to x, take x left left, the latest definition of tick defined will come into picture, a wonder it looks local, we'll soon see how this actually does not work. So we'll go ahead and expand r three and r three will be r one and r two, because we redefined x flat with r one and r two. Now let's look at another always work which is the same as in the previous lead example. And here I'm saying that r four equal to take x def left Well guess what? Which definition will it take r one and r two or r one or r two. It will indeed take r one and r two.
Because like I said earlier, take defined is a global substitution macro. The latest definition prevails. And everywhere it says that particular tech define it will replace it with the latest definition. While here The latest definition was local. So it only restricted itself to expanding in the local context. So this is a very good example.
This is one of the main reasons why let was introduced. I just one more example. Here is a module, and I'm saying that let x x or y with the ports X, X comma Y, X, X or Y, and then I'm saying let X or Y to me request or grant. So these are the two different definitions. One is x, x or y, and another is X or Y. Then inside a property, we say assert at positive clock x or y.
And inside the honest Columbia saying assert X, X or Y and now as you notice We are passing two parameters to this X, X or Y. Why? Because here we have two parameters in its definition. Now this is not possible we take define, for example. So let's see what happens after we expand quote unquote the lead body. In the ESET blog, X, X or Y is now going to be replaced with request or grant, which is pretty obvious.
And in the, in the, this is a blog, which he is passing r one and r two, two x x or y x and y x and y are going to be replaced with r one and r two. And we will get basically assert r1 Xr two rather obvious but very important. Again, I'm establishing the reasons for let compared to take define. Okay, let's let's look at One more example. Here, I'm basically showing that inlet length czar, p comma Q equal to zero. So I'm just showing that it's in the parameters, you can also have a default value.
So as as the alarm puts in default on a port and always add pauses of clock, we are saying that for i equal to zero, i less than or equal to 56 i plus plus r1 equal to L x or I. So what is going to do is, this is going to expand into p x or q here, but P is I suppose going to be simply I XOR Q equal to zero. So, the point is since q has a default value you don't need to pass quote unquote queue or the second port definition when you instantiate When you call Alexa, that's the main gist of this simple example. Okay, that's pretty much all for the lead, there's a lot more that you can gather from the LRM. But what I have just presented is sufficient for you to get going with lead. Now let's look at more even more interesting feature called checker that was introduced in 2009 2012 was the checker.
It basically provides a way to group several assertions together into bigger block. And this block acts with its well defined functionality and interfaces, again, providing modularity and reusability. So question number one, if checkup provides a way to group several assertions together, why can't I just use a module or Verilog module I already showed you in the earlier lectures, I can have assertions in a module. And then I bind that assertions module with the design module. And I'm good to go. So why do I need this new concept called checker, I can also do that with the system Verilog interface.
There are some fundamental reasons and differences between a checker in a module. And why check out is a lot more versatile than a module. So number one checker can be instantiated both from a procedural block as well as from outside the procedural block. As you know, that a module can only be instantiated from outside the procedural, we always instantiate a module outside. We never in saying we cannot instantiate a module inside of for example, and always at block. So there's a big advantage of a checker over module.
The other big advantage is the former parameters of checker can be sequences, edges, and sensitive events and properties. Think about it, you can pass a sequence a property or add sensitive events as actual to the forms of a checker. And as we all know, we cannot do this with module IO ports, modular ports or Petrelli module i O. And the third advantage maybe now not such a great advantage, but still very useful when you have thousands of lines of code is that the synthesis tools normally completely ignore the entire checker block, anti checker body checker to an checker. But if you have assertions inside a module that you will have to use conditional compiler directives to prevent sentences from trying to mistakenly go into an assertion and try to synthesize it. So these are the main advantages why a checker was introduced in the new the latest LRM.
Let's look at some examples. What I'm going to show in this slide in the next slide is I'm going to show a checker. And then more importantly, I'm going to show what happens when instantiated. And that's where you will see the difference between instantiating a checker versus engine, shading a module. And then you will know the advantages of checker. So I have a simple checker checker is the keyword is just like module module name, I have a default parameter or birth size and then a bunch of signals.
And the last signal is important important to note is an event clock equal to input clock. So it's an edge sensitive event that basically infers the clock from his higher context. So these are the ports or parameters of a checker. And the inputs are DAC output enable B mode V morning and reset. I have defined a sequence called data transfer. We have actually since seen this property earlier in one of the lectures, a sequence called data transfer, a sequence called check B mode and a property called BB rule.
So, basically I have defined a bunch of sequences and properties, it's not important to know what these sequences and properties do for this particular concept. And here, I'm going to say check burst at some property and I'm going to assert this property. Now let's see what happens when we instantiate this checker into, let's say, Test Range for checker and so test check around again, bunch of signals defined here. The first thing I'm doing here is I'm creating a B mod sequence Be more frequent basically say that the be more should remain low consecutively for two clocks. That's it. It's just a sequence.
Now, I'll show you why it's important. And let me go back here. And, and you will see that be mod in, be more in in this checker is used as an antecedent. So we'll come back to that in a second. So I defined a sequence. And now I'm going to call the checker.
Okay. And we're, purposely I'm calling it from procedural blog because you cannot do that this with a module. So I'm just saying that always it pauses of clock or neglige of reset, asynchronous reset, I'm just going to say bank reset. Reset the signals ELS call this checker ELLs called the checker and execute the probe. All parties that are in now here's the important part, how are we connecting the ports of checker m module with the test checker m signals. So, diac is connected to data which is declared here, who is connected to output enable B mod is connected to B mod, which is this signal B mod and then we mod in is connected directly to the sequence.
That means, I can pass this entire sequence to this checker M and then reset is connected to reset. So, let me There are two main points here. One is the B mod sequence. So, when you go here, the B mod is sequence is used directly as an antecedent and I'm passing it directly from the high level module. This is impossible with a module but it's very possible with checker and This This allows me more important than anything else to modularize and parameterize my code for reusability and debug ability. I am going to have a genetic set of sequences of properties.
And I can pretty much send a different way mode in from a higher level and be more in can be anything here and I don't need to change my checker in it will simply pick up the new sequence coming in and move forward. The second point, if you notice, in the port list of checker, checker m, you have a clock, but I'm saying even clock input clock. When I instantiate the same checker, I'm not passing it any clock. This is another advantage. Basically the clock is not infrared From the earliest outermost scope, which is always at pauses of clock, so, this pauses of clock is now going to be used in the checker. So whenever you see add clock is basically now going to be at positive.
So this is another big advantage in modularization of code, which is my clock can be anything in my testaments, or in wherever I instantiate the checker from it can be anything and, and the checker is simply going to infer it from where it's being instantiated. So, I can keep changing my clock I might show clock and be positive or negative clock. It can be something else get a clock, but this checker and remains quote unquote, generic and you don't need to change it. So, that's another big advantage of checker em. You can also nest the checkers. So This is one example where I'm going to nest one checker into another and then make a few points here.
So here's a checker seeker one with a bunch of signals. Again even clock as input clock, but I'm also doing event reset to be in for disabled. So whenever I use the reset for example, in this checker, it can be inferred from the high level block from from where it was called just like the clock was input. So that gives another big modularization advantage. And inside this block, I have a default rocking block. And I would default disable if block and these reset and this block will be quote unquote invert with SNC events from the high level block.
Then inside here, I'm getting a couple of properties And what I'm doing is inside of checker ck one, I'm declaring another checker. This is the nested checker, checker ck two. So, the first point is that the inferred or deferred clock and reset of checkers ck one, which are these guys are visible to checker secret. So that's good. I don't want to redefine the clock and reset or anything. Even though it's a completely new different checker.
It inherits it from checker one because it's nested inside checker one. Now what I'm doing is in checker ck one, I have a property called check one. I'm redefining it in the neset checker ck two. I'm redefining it. And then I'm declaring another new property called check three. So here's the point that you can redefine a property that was different In a high level checker, so to say, and the, the new definition of the property will be visible only to this checker secret to Why?
Because inside checker ck one, we are instantiating ck two with an instance name. So like I'm making the point here when you instantiate ck two from checker ck one, the property check one out, checker ck two is not directly visible to everyone, which makes sense. You know, it's not backward the definition doesn't go backward, it can only go forward. And, and what I'm doing inside this checker is I'm asserting property check one which is this check one, a setting property check three, which is this check three both defined within the checker ck two but I'm also Setting property check to which was not defined inside checker ck do but it was defined in checker ck one. The reason for that possibility is that the ck one properties are visible to check a security. So, the properties are visible the infer clock and reset are visible.
So the nessus checkers can be very useful without redefining the properties of high level checker or or wherever is being instantiated from. So this is a very brief introduction to Knesset checkers. So that's pretty much it for lead declarations and checker. These are very important new features that I'm sure will come very useful to you. And thanks a lot for attending the lecture and I'll see you soon in the next lecture