Transcript for:
Systematic Object Oriented Programming

hello welcome to this course systematic object oriented programming an example of converting a module-based response to a class-based test bench this is a short course showing only an example and in the example first you will be writing a simple system value test bench based on modules and then you will be converting that into a class based response so if you are somebody new to system hello you can watch the playlist that i have given in the i button which is an introduction of system below and which will help you to start learning system vlog and also you can watch the two basic level test punch coding courses in system vlog which is again you can find in the i button and links in the description below so before we start on please do subscribe us if you haven't and also visit our website at systemacademy.com now let's try to go into the problem before starting off with the example this is what we are going to model we have a duty and a test bench and we are going to write system below code for this test bench the duty have a simple axi interface and to make it very simple we are just assuming that it has only one axi interface which is the right address interface if you are not familiar with axi protocol don't worry about it just understand that it's a protocol based on violet and ready it has got five channels and we are only worried about one channel which is the right address channel here and also to make this example symbol we are only worried about few signals in this right address channel which are the id address and length field which are of length three down to zero 31 down to zero and three down to zero and also it has got a violent and ready signals and note that the name of all these signals are starting with the prefix of aw and also every channel has got a clock and reset signal in that now to start writing the test punch you need to write the duty code as well because if without the duty you won't be able to write at a sponge in systematic but if your intention is to just to learn system velocity coding there's a simple technique for that you can just write a dummy duty or dummy dot and straight away jump into writing stressbench code in the dummy duty you just write the minimal code which even may not be synthesizable you can even write sponge constructs in the demo dot and start coding your attachment directly so this is a very good technique to start learn system velocity coding irrespective of what kind of tb you wanted to write like whether it has a simple module-based test bench or whether it is a class based test bench or even whether it is a uv-based test bench this will be our approach in this case so first we will be writing a simple system where like interface to write this axi right address channel then we will be writing a simple dummy dot or dummy duty and then we will be writing the test punch code for this the method which is module based or the old verilog style test bench and finally we will be converting the test bench into a system window class based test bench so we'll be starting with the interface and duty so i'll be using the eda playground platform to write code and simulate it and if you're not sure how to do that watch the video in the i button which will describe you how to use this platform in the design.sp file we will be writing the interface and the dummy duty and in the testbench note sv file we will be writing the test bench code so we are defining a systematic interface by using the interface keyword and the end interface keyword the name of the interface is x or write addr interface it has got the input of clock and reset and these are the signals in that which are id address length violet and ready and those are the ones which are described in the axi right address channel description again if you are not familiar with system by log interfaces you can watch the video in the description which will teach you the theory of interface and system will have more ports but for now in simple words a mod port in system analog interface is something that can be used to define the direction of signals in the interface so that the same interface can be used in multiple module instances like in the master and in the slave there are two mod ports here a master and a slave an xa protocol is a master slave protocol and when it is acting as the master the signals id address length and violent will be driven by the masters and they will be output and ready will be driven by the slave and it will be input and when it is safe the vice versa so next is our dummy duty so i'm just giving it as a name like symbol. it has got input which are clock and reset and the system will log interface which you have defined here which is xa right address interface and when you use interface within the port list of the system relay module there itself we can define the direction of the signals by using the appropriate mode ports so here the duty will be a slave therefore we will be making this interface a slave in the middle by declaring like the interface name dot the mod port name and this is the port name now the code in the dummy duty is very simple it just need to drive the ready signal so we am just using a you random function it will give appropriate random values to the left hand side variable or signal to which it is assigned limited by the width of the variable or the signal here in an always block i am just assigning this interface dot ready will be equal to u random next we will be writing the test bench code the testbench is writing the testbench.sv file and here is your tv code i'm using a module named testpench with no argument so my intention is to drive some random values to the interface or some random values to the signals since the duty is a demi duty i'm not doing any kind of checks here i'm just doing the driving part so that we will be able to see some signals in the interface for that these are my internal signals i need to use a clock and reset signal to drive the clock and reset and i'm using an internal variable name number of transaction is equal to 10 so that i can send 10 transaction in a loop and next is the instantiation of the duty and the interface you can see that the sample that is instantiated with the name symbol that want into that the clock and reset signal will be passed by using the dot star as we are using the same name for the internal variables and this x i write addr indf1 will be passed as m underscore interface which is nothing but an instance of the same interface here so what all you need to do in the test punch is to drive signals into this m underscore indf instance of this ax right address interface definition and this is how you use a system will log interface in the module port list and next these slides are for seeing the waveforms and here is a clock and reset generation and after that i am writing the testbench functional code here in an initial begin also our intention is to convert this stress bench into class based aspect instead of writing everything in within the initial begin straight away i am structuring this test page in a nice manner so that it will be easy to compare this one with the actual class based test bench so i'll be writing tasks here instead of directly writing all the code here in the initial begin and even if you're writing a simple system like module-based test bench it is always a good practice to use tasks or functions to separate some functionality so that it will be easy to reuse and even understand way third person before the reason you need to initialize the sequence at least you need to initialize the valid signal so i'll be using a task called init signal and then i'm waiting for the reset and then in a for loop i'm driving 10 transactions into the duty by using another task called drive right led and finally after waiting for a clock i am calling the dollar finish function to end the simulation and if you are not adding this clock weight here you won't be able to see the last transaction in the simulation now let's see the tasks here which are init signal and drive addr so first is init signal so this is the init signal task here i am just driving the violet to a zero and when the violet is zero as per the protocol other signals have done case if you want you can drive zero to other signals as well and the last part of this stress punch is this drive hdr task so within the task before driving some value to the interface just wait for the ready signal in the interface so we'll be waiting in a loop until the ready is asserted by the slave when the slave is ready drive all the signals with some random values as we said earlier the dollar you random function will return a random value which will be limited by the width of the signal to which it is assigned so here id length address will be assigned with some random values and while it will be asserted as fun next we will wait for a clock cycle and make violet f0 and finally add a nice logo message into the log files by using the dollar display function i'm just printing like drive added here at time i'm sending this transaction with these values you can see that the first argument is dollar time and next are the values which we had given already this is a non-blocking assignment in systemvelo and if you are not familiar with this you can again watch the video in the i button or the same link is given in the description as well so here we have written a simple system village test punch and next let's run and see the result save run so the waveform video has opened up and let's see some waveforms get signal in the interface let's add all you can see that after the reset is the asserted the id address length are driven with some random values and also you can note that whenever the ready is low it will wait until the radius high and then only the next set of values are driven so here it is waiting for one clock cycle for the ready and here is again three clock cycle for the ready so just to show you all the transaction i am just zooming out you can see that all 10 transactions are driven into the interface and also have to look at the log file here it is printing whatever we have added in the dollar display there are 10 display messages here you can see um let me just zoom in here at six thousand sending a try transaction with these values and at seven thousand and again at nine thousand at time eleven thousand and so on so that is the end of this session here you have seen how to write a simple system by like interface with a set of mod ports in that and also you are told about the concept of using a dummy dot which will help you to start writing testbench code immediately and also you have seen simple system value of module based test bench and next you will be converting the same test bench into a class based test bench now let's convert the same test bench into a class space test bench for that instead of writing everything into a class based response again here let's take a step-by-step approach first we will be only writing a simple transaction class and use the same system analog a module based test bench to drive transaction into the duty and then in the next example we will be converting the whole test punch into a class based test bench so let's go through the bare minimum theory part which is need to start learning class-based test bench in a class-based response first you need to model transactions as a class a transaction is an entity that is going into an interface to drive these transactions into the directory again you need to write another set of classes which are generally called as a driver class in this example we will be writing the transaction class for that the design part of your code will be the same as that of the previous case and in the test page part there will be some modification and we will come to that and before that here i'm adding another file named x8 txm.sph and also i am including that file in the beginning of the file so that this code will be available here and first let's take a look at the axi transaction class file so within the axitx and dot svg file i am writing it x i transaction class so you will write the system value classes in a class and n class keyword and this is name of your class here which is ax underscore txn this class has got three data members in it which are id length and address with appropriate width that is defined in the actual except protocol id and length are of width 4 and address is length of 32 and note that all these are defined not just a simple bitter logic they are defined as a run bit or a rant logic so you can even use a logic here it doesn't matter so this is again systematic specific random constructs when you add a random keyword to a data member you can randomize the object of this class by using the dot randomize function which we will use in the test bench again if you are not familiar with this anode just make all the data members as random by using the rand keyword this is a constructor function the new function and i have used this assignment of 0 just a word hinge in the function when it is used in the monitor class but as we are not writing a monitor you can just make it as an empty function here the next is adding a constraint this is again system where log specific random constructs concepts and if you're not familiar just understand that you can add constraint to a random variable by using the constrain keyword and this is the name of the constraint you can give it any name and within a set of curly brackets give the appropriate constraint you want to give followed by a semicolon within the bracket here i'm making a constraint which is the length should be always greater than or equal to 1 because the length cannot be zero and next there are two functions in the class which are copy function and a convert to string function for this example you don't need to write this copy function it will even work without the copy function but this is a general practice and i would say these are the two bare minimal functions which you might want to add to every transaction class a copy function is required to do a deep copy instead of a shallow copy and this will be generalized structure of every copy function the transaction to which you wanted to copy will be passed to this copy function and first you will do a typecast and check whether you are getting the correct type of transaction and if it is the correct type copy each and every field of this casted transaction into this transaction by using this keyword so you can skip this copy function you don't need to write the copy function for this example but i have added this here purposefully because this will be very much similar to a uvm transaction if in case in future if you are going to a uvm based test punch and also there is another function called convert to string so this is actually print function the intention of this function is to call this function to get a nicely formatted string from this function with the current values of this transaction usually the transaction could have many data fields in that and you might want to print this transaction multiple times in your test bench in different places and to add debug messages we wanted to print the actual value of this transaction into the log files and instead of adding the code to explicitly print the individual data member value just call a function there so that it will return a nicely formatted string with the current values here i'm using a local string named rpt and using dollars format i'm passing a nicely formatted string to this rpt and returning this string here this will be more clear when we actually use this function in the code now if you want to make this example very simple you can even delete this copy function so this will be the bare minimum class which we need to simulate this example next let's see how do we use this transaction in the test bench code in the testbench.sv file don't forget to include this file and all this part are exactly same of that as the previous example and in the functional part we'll be initializing the signals and waiting for a reset then drive 10 transaction in a loop this time there's a change in the drive adida function we are passing a transaction argument into this task and whatever is the value getting as the argument here that transaction dot id length and address are driven into the interface within this drive right adida task instead of the uranum here for that you need to use an object of this transaction locally here within the initial block so we are defining an object of the x i underscore txn class with an empty action in the for loop before passing this transaction into the task you need to create the object by using the new function and also you need to randomize by using dot randomize function so first you need to create the object by using direction equal to new then write like dxn dot randomize when an object dot randomize is called all the random data members of this object will get random values and therefore when this line is executed the transaction object will have random values for its id length and address field and we are passing that transaction into the drive right added here task and therefore these values will be random here so this function is exactly same except that we are using the transaction values instead of your random values now let's run and see the result you can see that the same set of results are appearing here and also have a look at the display messages and drive write added here at time 0 we are sending the transaction but there is a slight change in the code here in the display message instead of listing down the individual transaction values we were just using the transaction dot convert to string function when this dx and dot convert to string function is called it will return a nicely formatted string messages with the current value of this transaction as you can see here and just by using that function you will be able to add display messages in this example we were using only one display so you might think it doesn't matter at all but in an actual complex testbench you might want to print the values of the transaction multiple times and then it will be convenient to use a function to return a readable formatted string with the current values of the data members of the class after summary in this example we have written a transaction class and we have used the transaction class to drive signals into the interface for that you need to create the object and before driving you need to call the randomize function so that all the random data members will be driven with random values and also we have used the convert to string function to display print messages into the log file next we will be writing the actual system will log class based test bench by rewriting all this part in the previous session you have seen how to write a transaction class and as i said earlier that was just an intermediate step and we have to go on and convert the whole test punch into class based test bench this is a generalized block diagram of a system value class based test bench mainly it will have a generator class a driver class and a transaction class and generator class will be generating transactions and sending it to a driver by using a mailbox and the driver will be finally converting these transactions into the actual interface level signals and driving them into the actual dut interface by using an interface so it might look a lot of information but if i am saying in a simplified way you need to write a generated class final driver class and a transaction class as well and finally you need to use all these three set of classes to drive your duty with valid input transactions now we will see the details we have already written the transaction class in the separate file now i am going to write the next class which is an axi generator and another driver in two separate files and i have included these files into the main testpage.tsv file so that everything will be compiled previously you are generating transaction from the module itself but this time they need to be generated from a generator class so here is the axi generator class and it has got a mailbox in it with the name mbox and we will see where we are going to use it and also it has got member variable with name number of right transactions and in the new function or in the constructor function the mailbox has to be created again by using a new this is mandatory otherwise you will get compilers and next is another task named run generally you can give any name to this task but typically it will be named something like a run task when you call the run task of the generator it need to generate n number of transactions and send it into the mail box so here is a code a local transaction object declaration and within a for loop this transaction will be created and it is randomized by using the dot randomize function if you don't know the assert statement don't worry about it you can even delete this assert and just call like transaction.randomize and after randomizing the transaction put the transaction into the mailbox by calling the put function of the mailbox like mbox.put of transaction and finally add some display to the log file by using the dollar display and the transaction node convert to string function or whatever function you have declared for print previously after randomizing the transaction we were directly driving it into the duty within the test bench module itself but when it is writing in a generator class you won't send it directly from the generator but you will add the transaction into the mailbox which is again a member of this generator class next is a driver class in the driver class again it has got another mailbox and the same variable number of flight transactions and also additionally it has got an interface which is same as that of the interface that we have declared here x right addr interface with the name of m underscore indf and note that it has to be a virtual interface so you should always add the virtual keyword here and again don't worry about what is virtual here if you don't know the virtual concept of object-oriented programming but while you declare the interface it has to be a virtual interface and in the new function create the mailbox by using another new and add another task say run which will take the transaction from the mailbox and drive it into the interface so within the run task there is a local transaction declaration and before driving anything it need to be made sure that this interface is assigned correctly or tied up correctly to the final duty interface and check whether it is null or not if it is null flag an error so that you can avoid unwanted debugs and after that you can see that this part of the code is pretty much same as that of the code that you are writing in a module based test bench so this was your first module-based response in the initial begin you can see that you are initially initializing signal and waiting for the reset and driving this and this was your drive adida transaction so we just moved this part of the code from the module based test bench to the driver class here but the slight difference is before driving the transaction first you need to get the transaction from the mailbox in the driver and then drive the transaction now this task is exactly same of that of the previous case where you are modeling the transaction and writing everything in the module and this is the general anatomy of systematic driver class within the generator class we were generating n number of transactions and putting it into a mailbox which is again a member of this generator within the driver class there was another mailbox as a member and we were taking the transaction from the mailbox and driving those transaction into the virtual interface which is another member of the driver class now what we need to do is you need to instantiate the generator and the driver class within your top level test bench module and also you need to connect them together by using the mailbox because there's a mailbox instance within the generator and driver but you need to make sure that they are connected together by using an external mailbox and finally you need to connect the driver virtual interface to the actual duty interface password now let's look into the code now here is the testmesh.sv file and note that even though you are using the class based response there has to be a top level module a test bench module where you will instantiate all the classes all the functional part will be moved into class but there has to be always a top level test punch which will instantiate all the classes and the duty and the interfaces and do the appropriate connections now within the module the xlright address interface is instantiated and it is passed to the duty instantiation as well and additionally you can see that the driver and generator class objects were also declared here with the name m underscore driver and m underscore gen and these parts were exactly same as that of the previous case and now let's see the functional code in the functional part you can see that i am using a local mailbox here the name mbox1 also calling its constructor the new and next i am calling the constructor of the driver and the generator class because if you always call the do function of the object before start using them otherwise you will get null object error the next part is connecting them together there was a mailbox in the driver and in the generator and also there's a mailbox locally here if you just assign this mailbox to those two mailboxes in the classes then both classes will be using the same mailbox and this connection can be made very simple so here m driver dot mbox is equal to inbox one the local one here and m gen dot m box is equal to same mbox one here now the mailboxes are connected and also don't forget to connect the driver virtual interface to the actual interface therefore the m driver dot m interface which was the virtual interface in the driver is equal to the local instance of the interface which is m underscore indf again with these two lines we connected the driver and generator and then the next line we connected the actual duty interface into the driver virtual interface and also note that this m underscore indf is also passed to the duty module instantiation therefore when the driver is driving signals into the interface it will be driven into the duty so all the connections are made now the final part is doing the actual functionality both in the generator and in the driver class the functionalities were written in a separate task we named the task as run therefore to start the functionalities you have to call the run task in those two classes in the main module that is done in a fork join a fork join will wait until all the launch tasks have been finished off and also these two will be started off parallelly driver will be always waiting to see a transaction in the mailbox and when the generator actually sends something into the mailbox in the generator dot run task the driver will get the transaction in its mailbox because we made a connection by using a local mailbox between driver and generator and thus generator will be generating and driver will be getting those transactions or taking this transaction and driving them into the duty so when the generator and the driver have finished off it will unblock the fourth join and execution will continue from the next line here after waiting for a clock cycle just call the dollar finish and the simulation will be ended now let's run and see this let me just zoom out a bit to see everything you can see that 10 transactions has been sent out and also look at the log file messages that we have added in the driver and generated class you can see that the axa generator is generating everything within zero time or before starting anything off and putting it into the mailbox but there is a delay in the driver execution because within the driver there is an actual weight and clock synchronization so the driver code will be advanced along with only the clock signal but within the generator code there was no delay factor so all this execution have been finished off in zero time and that's the reason you are seeing all the 10 messages within the generator first and followed by the messages in the driver finally you have reached the end of this course and here you have seen how to write a simple system below class based expansion you have initially written a dummy duty and a simple systematic interface and a model based response and then you converted it into class based test bench step by step by first modeling transactions in a transaction class when finally using a generator and driver class to complete the whole system below class-based test bench this is a generalized approach and this will be true even if you use uvm or ovm to write a sponge or in other words you might see a lot of similarities even if you convert this test vent into a uv base test bench i have added the links to youtube videos which is teaching the different system value concepts that we have discussed here like systematic interfaces mod pods mailboxes fork join etc and take a look at them if you wanted to learn more about any of them so that's end of this course so before winding up please do subscribe us in youtube if you haven't and also take a look at our website at systemvilleacademy.com to find more system villa courses and training programs thank you for watching happy learning you