The document discusses UVM components, objects, and the factory in UVM. It provides answers to questions on:
1. The difference between components and objects and their constructor arguments. Components have a parent argument while objects do not.
2. How the factory knows which constructor to call using the type_id.
3. The different ways of registering a class with the factory using macros like `uvm_component_utils for components.
The document discusses UVM components, objects, and the factory in UVM. It provides answers to questions on:
1. The difference between components and objects and their constructor arguments. Components have a parent argument while objects do not.
2. How the factory knows which constructor to call using the type_id.
3. The different ways of registering a class with the factory using macros like `uvm_component_utils for components.
3 =================================================================================================================== 4 5 create(string ="name",uvm_component parent); 6 7 //QSN.why create accept two argument during building a components but only one during building objects ????? 8 9 ANS. Because componets follow hierarchy so they have name and parent 10 but object did not follow any hierarchy so they dont have parent that is why only one constructor which is of 11 string type name only passed 12 13 //QSN.IN SV we pass the interface handle as an argumnt in new() constructor to connect the driver .and DUT can we 14 .do.this in UVM ????? 15 16 ANS. NO, Because in uvm to create any component we .use create() method which can accept only two arguments we 17 can't give additional arguments 18 19 //QSN.How create() method will know which class constructor it should call ???? 20 21 ANS. Based on the type_id given during creating object .for a component 22 eg. drv=driver::type_id::create("drv",this); 23 24 //QSN.IN How many ways you can implemented standard method inside the Transaction class ????? 25 26 ANS. Two Ways : BY Using field macros by registring the properties 27 : By Using Override Methods 28 Override methods are recommended 29 - do_copy 30 - do_compare 31 - do_print 32 33 //QSN.What is the return type of clone() ????? 34 35 ANS. uvm_object: Clone will first create object then it will copy .and .return destination object. 36 destination object is .return through uvm_object parent handle 37 We need here $cast() 38 //QSN.What is the difference between uvm_object and uvm_component ????? 39 40 ANS. classes which are used to build testbench structure are called components and classes which are used to . 41 .generate stimulus are called object.& object will.not follow any hierarchy. 42 43 44 //QSN.In UVM Liabrary which classes are not virtual classes ??? 45 46 ANS. uvm_driver and uvm_sequencer are non_virtual classes. 47 48 //QSN.Inside the components where did we write executable code ??? 49 50 ANS. In Phases 51 52 //QSN.How to register a class to the factory ???? 53 54 ANS. By using macros : 55 56 `uvm_component_utils() for components 57 `uvm_object_utils() for objects 58 `uvm_component_utils() for parametrized components 59 `uvm_object_utils() for parametrized objects 60 61 these macros will get expended in three parts 62 63 1. wrapper --> uvm_component_registry/uvm_object_registry which typedefed to type_id 64 2. get_type() -->.static method which returns type_id 65 3. get_type_name() --> method which .return component/object name as a string 66 67 //QSN.What is difference between new() and create() ????? 68 69 ANS. 1. create() is the factory method which is used in uvm to create components .and transaction .class objects & 70 it is a .static method defined in registry .class 71 2. create() internally call new() constructor 72 3. new() is the system verilog constructor to create components .and transaction .class objects 73 74 //QSN.How create() method will know which class constructor new() it should call ???? 75 76 ANS. By type_id 77 78 79 80 81 82 83 84 85 86 87 -----------------------------------------------------=============------------------------------------------------ 88 //====================================================UVM FACTORY================================================= 89 -----------------------------------------------------=============------------------------------------------------ 90 class 91 92 1. We have to register the .class to the factory 93 2. It is a .class where it creates the components.and objects. 94 3. from test we can control, configure the factory to create whether parent.class .or child.class 95 for .this we have to register a .class .with the factory 96 4. There are three steps to register the .class .with factory 97 1. Create Wrapper around component registry .class, typedefed to type_id 98 2. static .function to get the type_id 99 3. function to get the .type name 100 101 102 //STEPS TO REGISTER CLASS WITH FACTORY 103 ----------------------------------------- 104 105 class my_component extends uvm_component; 106 //wrapper class around the component/object registry class 107 typedef uvm_component_registry#(my_component) type_id; 108 /*//incase of object 109 typedef uvm_object_registry#(my_object) type_id;*/ 110 111 //used to get the type_id wrapper 112 static function type_id get_type(); 113 return type_id::get(); 114 endfunction : get_type 115 116 //used to get the type_name as string 117 function string get_type_name(); 118 return "my_component"; 119 endfunction : get_type_name 120 121 endclass : my_component 122 123 1. so writing .this much code to register the .class everytime is .bit lengthy 124 2. so .for registering the component/object .with factory we will .use macros 125 126 127 128 129 130 //MACRO FOR COMPONENT CLASSES //MACRO FOR PARAMETRIZED COMPONENT CLASSES 131 ------------------------------ ------------------------------------------- 132 `uvm_component_utils() `uvm_component_param_utils() 133 134 //MACRO FOR OBJECT CLASSES //MACRO FOR PARAMETRIZED OBJECT CLASSES 135 --------------------------- ---------------------------------------- 136 `uvm_object_utils() `uvm_object_param_utils() 137 138 139 140 //CONSTRUCTOR DEFAULTS 141 ------------------------ 142 143 1. The uvm_component and uvm_object constructor are virtual methods 144 2. The defaults are different for components and objects 145 146 //For COMPONENT 147 class my_component extends uvm_component; 148 function new(string name="my_component",uvm_component parent=null) 149 super.new(name,parent); 150 endfunction 151 endclass 152 153 //For OBJECT 154 class my_item extends uvm_sequence_item; 155 function new(string name="my_item") 156 super.new(name); 157 endfunction 158 endclass 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 uvm_top 174 uvm_test_top 175 env 176 SB 177 178 agt 179 drv 180 mon 181 seqr 182 183 ============= 184 //MY_DRIVER 185 ============= 186 187 class my_driver extends uvm_driver; 188 `uvm_component_utils(my_driver) 189 190 function new(string name,uvm_component parent) 191 super.new(name,parent); 192 endfunction 193 194 endclass 195 196 =============== 197 //CHILD_DRIVER 198 =============== 199 200 class child_driver extends my_driver; 201 `uvm_component_utils(child_driver) 202 203 function new(string name,uvm_component parent) 204 super.new(name,parent); 205 endfunction 206 207 endclass 208 209 210 211 212 213 214 215 216 ============ 217 //MY_AGENT 218 ============ 219 220 class my_agent extends uvm_agent; 221 `uvm_component_utils(my_agent) 222 223 function new(string name,uvm_component parent) 224 super.new(name,parent); 225 endfunction 226 227 my_driver drv; 228 my_monitor mon; 229 my_sequencer seqr; 230 231 function void build_phase(uvm_phase phase); 232 super.build_phase(phase); 233 234 /* drv=new("drv",this); 235 mon=new("mon",this); for drv,mon & seqr parent(in which class they enclosed in 236 seqr=new("seqr",this); hierarchy) is agent so we pass this keyword as 237 second argument which refers agent */ 238 239 drv = my_driver::type_id::create("drv",this); //create() is the factory method which will call new(); 240 mon = my_monitor::type_id::create("mon",this); //It is static method defined in registry class 241 seqr= my_sequencer::type_id::create("seqr",this); 242 243 endfunction 244 245 endclass 246 247 248 249 250 251 252 253 254 255 256 257 258 259 ============== 260 //ENVIRONMENT 261 ============== 262 263 class environment extends uvm_env; 264 `uvm_component_utils(environment) 265 266 function new(string name,uvm_component parent) 267 super.new(name,parent); 268 endfunction 269 270 function void build_phase(uvm_phase phase); 271 super.build_phase(phase); 272 273 my_agent agt; //Here for agent parent will be environment 274 275 agt=my_agent::type_id::create("agt",this); 276 endfunction 277 278 endclass 279 280 ============= 281 //TEST CLASS 282 ============= 283 284 class test extends uvm_test; 285 `uvm_component_utils(test) 286 287 function new(string name,uvm_component parent) 288 super.new(name,parent); 289 endfunction 290 291 function void build_phase(uvm_phase phase); 292 super.build_phase(phase); 293 294 environment env; //Here for environment parent will be test 295 296 env=environment::type_id::create("env",this); 297 // set_type_override_by_type(my_driver::get_type(),child_driver::get_type()); 298 endfunction 299 300 endclass 301 302 ============= 303 //TOP MODULE 304 ============= 305 306 module top(); 307 308 initial 309 begin 310 311 run_test("test"); /* It will create uvm_top(uvm_root) which is nothing but handle of 312 uvm_root and inside uvm_top, test will be created and given name 313 uvm_test_top */ 314 end 315 endmodule 316 317 318 319 320 //run_test("test") 321 ------------------- 322 1. It will take test name as an argument which is string .type .for which .instance will be created 323 2. After creating test 324 3. run_test() will call build_phase of 325 |_ env -> agent -> where drv,mon & seqr will be created 326 327 328 ===================== 329 //FACTORY OVERRIDEN 330 ===================== 331 332 //GLOBAL OVERRIDE 333 ------------------ 334 335 1.Make sure both classes should be polymorphically compatible 336 eg. original and substitude should have parent child relation 337 .---------------------------------------------------------------------------------------------------. 338 | set_type_override_by_type(original_type::get_type(),substitude_type::get_type(),bit replace=1); | 339 '---------------------------------------------------------------------------------------------------' 340 341 //EXAMPLE 342 .------------------------------------------------------------------------------. 343 | set_type_override_by_type(my_driver::get_type(),child_driver::get_type()); | 344 '------------------------------------------------------------------------------' 345 346 1. It will override type_id of parent .with type_id of child. 347 2. type_id of driver will be override by type_id of child_driver in entire testbench. 348 so now driver will have type_id of child_driver 349 3. whenever create() method will called by driver it will create object .for child_driver. 350 351 this is how override will happen. 352 353 //INSTANCE OVERRIDE 354 -------------------- 355 356 .----------------------------------------------------------------------------------------------------------. 357 | set_inst_override_by_type("path",original_type::get_type(),substitude_type::get_type(),bit replace=1); | 358 '----------------------------------------------------------------------------------------------------------' 359 /*Why replace=1 here so that if again want to override this instance with other then by checking this value 360 simulator will understand that previous overriding happened so it will first convert it to original type then 361 override again with new type 362 */ 363 364 //EXAMPLE 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 test 389 env 390 agent_top 391 agent1 392 bus_wr_driver 393 monitor 394 sequencer 395 396 agent2 397 bus_wr_driver 398 monitor 399 sequencer 400 401 class test extends uvm_test; 402 403 virtual function build_phase(uvm_phase phase); 404 405 set_inst_override_by_type("*.agent1.*",bus_wr_driver::get_type(),apb_wr_driver::get_type()); 406 407 endfunction 408 409 endclass 410 411 412 test 413 env 414 agent_top 415 agent1 416 apb_wr_driver 417 monitor 418 sequencer 419 420 agent2 421 bus_wr_driver 422 monitor 423 sequencer 424 endclass 425 426 427 428 429 430 431 ---------------------------------------------------===================-------------------------------------------- 432 //==================================================STIMULUS MODELING============================================= 433 ---------------------------------------------------===================-------------------------------------------- 434 class 435 436 1.Transaction .class extends from uvm_sequence_item 437 2.Inside transaction.class we declare properties which is used as.input to the DUT.and valid constraints .and 438 methods required.for the.class variables(properties) eg. copy,clone,compare,print etc. 439 440 441 what is purpose of field macros ???? 442 register the.property.for copy,compare,clone & print method 443 444 There are two ways to implement those methods 445 446 1. Using field macros we can automate the methods by enabling the methods .for all the properties 447 2. By override the.virtual methods eg. do_copy, do_compare, do_print etc. 448 449 450 451 //Using the field macro 452 ------------------------- 453 1. It will not recommended because each field macros will expend in so many lines which affect 454 performance of simulator 455 2. Hard to debug 456 3. Time taken by simulator is more when used field macros 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 class write_xtn extends uvm_sequence_item; 475 476 rand int addr,data; 477 rand bit wr; 478 479 function new(string name); 480 super.new(name); 481 endfunction 482 //constraints 483 484 //post_randomize method 485 486 `uvm_object_utils_begin(write_xtn) 487 488 `uvm_field_int(addr,UVM_ALL_ON) //UVM_ALL_ON ---> all the method will be enabled 489 `uvm_field_int(data,UVM_ALL_ON|UVM_DEC) //UVM_DEC ---> it will display in decimal 490 `uvm_field_int(wr,UVM_ALL_ON|UVM_NOCOMPARE) //UVM_NOCOMPARE ---> all the methods enabled except 491 //compare method 492 `uvm_object_utils_end 493 494 endclass 495 496 .-------------------------------------------------. 497 | write_xtn t1,t2; | 498 | | 499 | initial | 500 | begin | 501 | t1=write_xtn::type_id::create("t1"); | 502 | t2=write_xtn::type_id::create("t2"); | 503 | | 504 | assert(t1.randomize()); | 505 | | 506 | t1.print(); | 507 | t2.copy(t1); |//t2.do_copy(t1) => it will copy object t1 to t2 508 | if(t2.compare(t1)); |//t2.do_compare(t1) =>it will return 1 or 0 509 | end | 510 '-------------------------------------------------' 511 512 513 514 515 516 517 //By OVERRIDE the methods 518 --------------------------- 519 520 copy will call virtual method do_copy so we will override do_copy. 521 print will call virtual method do_print so we will override do_print 522 523 class write_xtn extends uvm_sequence_item; 524 525 `uvm_object_utils(write_xtn) 526 527 rand int addr,data; 528 rand bit wr; 529 530 function new(string name); 531 super.new(name); 532 endfunction 533 //constraints 534 535 //post_randomize method 536 537 //Rules to override virtual method of parent in child 538 /* 1. The return type, function name , argument should be same 539 eg. prototype of function should be same 540 541 2. virtual methods do_copy,do_print,do_compare all are inherited from uvm_object class 542 */ 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 ================== 561 //DO_COPY METHOD 562 ================== 563 564 virtual function void do_copy(uvm_object rhs) //rhs=t1 (though it is a vlid assignment still 565 // parent can't access child class properties) 566 567 write_xtn xtn; 568 569 if(!$cast(xtn,rhs)) //xtn->rhs->t1, => xtn=t1 570 begin 571 `uvm_fatal("do_copy","casting of rhs object failed") 572 end t2 t1 573 super.do_copy(rhs); .----------. .----------. o 574 | data | | data | 575 this.data=xtn.data; /*this -> t2, xtn -> t1*/ | addr | | addr | 576 this.addr=xtn.addr; | wr | | wr | 577 this.wr=xtn.wr; | | | | 578 | | | | 579 endfunction | | | | 580 '----------' '----------' 581 /* so for access the child class properties here we will take another child class handle xtn 582 and cast rhs handle to xtn 583 now xtn will start pointing to rhs which is already pointing to t1 584 now we can access child class properties using xtn handle 585 586 t2.addr=xtn.addr 587 t2.data=xtn.data 588 t2.wr=xtn.wr 589 590 super.do_copy(rhs) 591 ==> It is required in child_xtn class when parent_xtn class have some properties 592 and we create a child_xtn class so in child_xtn class do_copy method we call 593 super.do_copy() so that it will call parent class do_copy method and copy parent class 594 properties also 595 */ 596 597 598 599 600 601 602 603 604 ==================== 605 //DO_COMPARE METHOD 606 ==================== 607 608 virtual function bit do_compare(uvm_object rhs) 609 write_xtn xtn; 610 if(!$cast(xtn,rhs)) 611 begin 612 `uvm_fatal("do_compare","casting of rhs object failed") 613 return 0; 614 end 615 super.do_compare(rhs); 616 return( 617 (this.data==xtn.data) && 618 (this.addr==xtn.addr) && 619 (this.wr ==xtn.wr) && 620 ) 621 endfunction 622 623 endclass 624 625 .-------------------------------------------------------------------------------------------. 626 | write_xtn t1,t2; | 627 | initial | 628 | begin | 629 | t1=write_xtn::type_id::create("t1"); | 630 | t2=write_xtn::type_id::create("t2"); | 631 | | 632 | assert(t1.randomize()); | 633 | | 634 | t1.print(); /*it will print all the properties in table format*/ | 635 | t2.copy(t1); /*it will copy object t1 to t2 */ | 636 | if(t2.compare(t1)); /*it will return 1 or 0 */ | 637 | end | 638 '-------------------------------------------------------------------------------------------' 639 640 641 642 643 644 645 646 647 ================== 648 //CLONE() METHOD 649 ================== 650 651 652 1. While using copy mtheod we will make sure object for destination handle already created 653 but for clone there is no need to create a destination object 654 655 2. clone does two things ---> create+copy 656 1. first it will create object for destination 657 2. then it call the copy method 658 659 after the copy the object which is created it will return that object reference through the parent 660 handle. 661 662 3. The return type of clone is uvm_object 663 664 665 function uvm_object clone(); 666 667 write_xtn t=write_xtn::type_id::create("t1"); 668 t.copy(t1); 669 uvm_object p=t; 670 return p; 671 672 endfunction 673 674 675 .-----------------------------------. 676 | write_xtn t1,t2; |// t1 is of write_xtn type so clone will create a object of 677 | |// write_xtn type and copy all the properties of t1 to that object 678 | initial |// and it pass handle of that object through parent handle. 679 | begin | 680 |/* t2=t1.clone(); */| 681 | $cast(t2,t1.clone()); | 682 | end | 683 '-----------------------------------' 684 685 686 //t2=t1.clone(); ===> //t2.copy(t1) --> t2.do_copy(t1) 687 /*it is returning through parent handle so we can't directly assign 688 parent handle to child ,we use $cast here.*/ 689 690 ================== 691 //DO_PRINT METHOD 692 ================== 693 694 1. It accept an argument which is uvm_printer type printer & it has a default value 695 uvm_default_table_printer 696 which will tell us in which format the transaction .class properties should be displayed 697 698 1. line printer 699 2. table printer 700 3. tree printer 701 702 so .for that .inside the printer .class we have method 703 print_field("variable_name",variable_name,width,Radix); 704 705 eg. printer.print_field("data",data,32,UVM_DEC); 706 707 708 virtual function void do_print(uvm_printer printer=uvm_default_table_printer); 709 710 printer.print_field("data",data,32,UVM_DEC); 711 printer.print_field("addr",addr,12,UVM_HEX); 712 printer.print_field("wr",wr,1,UVM_BIN); 713 714 endfunction 715 716 .-----------------------. 717 | write_xtn xtn; | 718 | | 719 | initial | 720 | begin | 721 | xtn.print(); | //It will print all the properties in table format 722 | end | 723 '-----------------------' 724 725 726 727 728 729 730 731 732 733 // TABLE VIEW TREE VIEW 734 ========== ========== 735 736 ------------------------------------------- xtn:(write_xtn@1150) 737 Name Type Size Value { data:'d15 738 ------------------------------------------- addr:'h26 739 xtn Packet - @1150 wr :'b1 } 740 data integral 32 'd15 741 addr integral 12 'h26 742 wr integral 1 'b1 743 ------------------------------------------- 744 745 746 // LINE VIEW 747 ========= 748 749 xtn: (write_xtn@1150) {data:'d15 addr:'h26 wr:'b1} 750 751 752 .===========================================================================. 753 |/* RADIX | DESCRIPTION */| 754 .===========================================================================. 755 | UVM_BIN | Print the given variable in binary format | 756 | UVM_DEC | Print the given variable in decimal format | 757 | UVM_HEX | Print the given variable in hexadecimal format(default) | 758 | UVM_OCT | Print the given variable in octal format | 759 | UVM_STRING | Print the given variable in .string format | 760 | UVM_TIME | Print the given variable in .time format | 761 '---------------------------------------------------------------------------' 762 763 .============================================================================. 764 |/* FLAG | DESCRIPTION */| 765 .============================================================================. 766 | UVM_ALL_ON | All operations are turned on | 767 | UVM_DEFAULT | Enables all operations and equivalent to UVM_ALL_ON | 768 | UVM_NOCOPY | Do not copy the given variable | 769 | UVM_NOCOMPARE | Do not compare the given variable | 770 | UVM_NOPRINT | Do not print the given variable | 771 | UVM_NOPACK | Do not pack or unpack the given variable | 772 | UVM_REFERENCE | Operate only on handles, i.e. for object types | 773 | | do not do deep copy, etc | 774 '----------------------------------------------------------------------------' 775 776 777 778 .=================.================.=============================================================. 779 |/* METHOD CALLED | VIRTUAL | DESCRIPTION */| 780 |/* BY USER | METHOD | */| 781 '.==============================================================================================.' 782 | copy | do_copy | Performs a deep copy of an object | 783 | clone | do_copy | Creates a new object and then does a deep copy of an object | 784 | compare | do_compare | Compares one object to another of the same type | 785 | print | do_print | Prints a the result of convert2string to the screen | 786 | sprint | do_print | Returns the result of convert2string | 787 | record | do_record | Handles transaction recording | 788 | pack | do_pack | Compresses object contents into a bit format | 789 | unpack | do_unpack | Converts a bit format into the data object format | 790 | convert2string | - | Returns a string representation of the object | 791 '------------------------------------------------------------------------------------------------' 792 793 endclass 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 ------------------------------------------------------============------------------------------------------------ 820 //=====================================================UVM PHASES================================================= 821 ------------------------------------------------------============------------------------------------------------ 822 class 823 / 824 //ORDER OF EXECUTION OF PHASES 825 ------------------------------- 826 1. build_phase } 827 2. connect_phase } // PRE-RUN PHASES 828 3. end_of_elaboration_phase } 829 4. start_of_simulation_phase } 830 5. run_phase --------------------------------------- 831 6. extract_phase } 832 7. check_phase } // POST-RUN PHASES 833 8. report_phase } 834 9. final_phase } 835 836 //All above phases automatically called by run_test() method 837 838 //SUB-RUN PHASES 839 ------------------ 840 841 run_phase 842 | 843 | //pre_reset 844 |--> 1.reset : In .this phase drive reset 845 | //post_reset 846 | 847 | //pre_configure 848 |--> 2.configure : In .this phase configure the DUT 849 | //post_configure 850 | 851 | //pre_main 852 |--> 3.main : In .this phase we drive the data 853 | //post_main 854 | 855 | //pre_shutdown 856 |--> 4.shutdown : In .this phase will .do .final adjustments 857 | //post_shutdown 858 859 860 861 862 //EXECUTION OF PHASES 863 864 865 run_test(); 866 867 time=0 ns | | time=100 ns 868 | | 869 | | 870 | | 871 | | 872 |---------------------------------->>>>| 873 | | 874 | | 875 build_phase | ---->>>> |extract_phase 876 connect_phase | TIME |check_phase 877 end_of_elaboration_phase | |report_phase 878 start_of_simulation_phase| |final_phase 879 880 <--------------run_phase---------------> 881 882 883 //BUILD_PHASE 884 -------------- 885 1.It is used to construct sub-components 886 2.Component hierarchy is therefore build top-down 887 888 //CONNECT_PHASE 889 ---------------- 890 1.It is used to connect the components .or any connection like connecting static and virtual interface 891 2.It follow bottom-up approach 892 3.First connect_phase of driver,monitor,sequencer executed then agents--->env 893 894 //END_OF_ELABORATION_PHASE 895 --------------------------- 896 1.It is used to make any .final adjustments to the structure,configuration .or connectivity of the 897 testbench .before simulation starts 898 2.It follow bottom-up approach 899 900 //START_OF_SIMULATION_PHASE 901 ---------------------------- 902 1.It is used to display banners: testbench topology,.or configuration information 903 2.It follow bottom-up approach 904 905 //RUN_PHASE 906 ------------ 907 1. It is the only phase which is task remaining all phases is function. 908 2. It consumes simulation .time remaining phases completes in zero simulation .time 909 3. run tasks are executed in parallel, run_phases of all components executed in parallel. 910 4. 12 Sub phases are added in parallel with run_phase 911 5. It is recommended either .use run_phase .or sub-run_phases don't .use both coz multiple driver 912 issue can happen like multiple driver driving same bus 913 914 DRIVER 915 ,---------------------------------, 916 | fork | 917 | run_phase(); | 918 | begin | 919 | reset_phase(); | 920 | configure_phase(); | 921 | main_phase(); | 922 | shutdown_phase(); | 923 | end | 924 | join | 925 '---------------------------------' 926 927 6. driver.and monitor should .use run_phase 928 7. don't.use phase domain .or jumping 929 930 931 //PHASE SYNCHRONIZATION 932 ------------------------- 933 / 934 935 By default, all components allow all other components to complete a phase before all components move to next 936 phase 937 938 1. Like there are three drivers in which we are using run_phase 939 So each driver may take different .time to complete sub-run_phases 940 941 2. Like DRV1 reset_phase taking less .time 942 DRV2 reset_phase taking little more.time 943 But Configure_phase of all drivers will start at same.time 944 945 3. Like reset_phase , configure_phase may take different .time to complete its execution 946 But Main_phase will start at same .time in all drivers. 947 948 4. Like all other phases shutdown_phase may take different .time as soon as shutdown_phase of all drivers 949 completed then start post-run_phases 950 951 */ || 952 .---------------------------.--------------. .-------------. .---------------.|| 953 DRV1: | Reset | Configure | | Main | | Shutdown ||| 954 '---------------------------'--------------' '-------------' '---------------'|| 955 ||//POST 956 .---------------. .-------------------. .--------------------.---------------.||//RUN 957 DRV2: | Reset | | Configure | | Main | Shutdown |||//PHASES 958 '---------------' '-------------------' '--------------------'---------------'|| 959 || 960 .-------------------. .------------------------.----------. .---------------.|| 961 DRV3: | Reset | | Configure | Main | | Shutdown ||| 962 '-------------------' '------------------------'----------' '---------------'|| 963 || 964 ===================================================================>>>>>>>>>>>>>>>>>>>>>>>> 965 TIME 966 967 968 or 969 || 970 .--------------------------------------. || 971 DRV1: | run_phase | || 972 '--------------------------------------' || 973 || 974 .-----------------------------------------------------------------------.|| 975 DRV2: | run_phase ||| //post-run_phases 976 '-----------------------------------------------------------------------'|| 977 || 978 .---------------------------------------------------. || 979 DRV3: | run_phase | || 980 '---------------------------------------------------' || 981 || 982 ======================================================>>>>>>>>>>>>>>>>>>> 983 TIME 984 985 986 987 988 989 990 991 //PHASE DOMAINS 992 --------------- 993 1. By creating domains,each components can complete a phase independent of the other components. 994 2. It is .not recommended 995 996 997 .===================================================================================. 998 |/* .---------------------------.--------------.-------------.---------------. */| 999 DRV1: |/* | Reset | Configure | Main | Shutdown | */| 1000 |/* '---------------------------'--------------'-------------'---------------' */| 1001 '===================================================================================' 1002 1003 .====================================================================================. 1004 |/* .---------------.-----------------.-----------------.---------------. */| 1005 DRV2: |/* | Reset | Configure | Main | Shutdown | */| 1006 |/* '---------------'-----------------'-----------------'---------------' */| 1007 '====================================================================================' 1008 1009 .====================================================================================. 1010 |/* .-------------------.------------------------.----------.---------------. */| 1011 DRV3: |/* | Reset | Configure | Main | Shutdown | */| 1012 |/* '-------------------'------------------------'----------'---------------' */| 1013 '====================================================================================' 1014 1015 ===============================================================>>>>>>>>>>>>>>>>> 1016 TIME 1017 1018 / 1019 //EXTRACT_PHASE 1020 ---------------- 1021 1. It retrieves and processes information from scoreboards and functional coverage monitors 1022 2. It also follows bottom-up approach 1023 1024 //CHECK_PHASE 1025 --------------- 1026 1. It checks it the DUT behaved correctly and identifies errors that may have occurred during the 1027 execution 1028 2. It follows bottom-up approach 1029 1030 //REPORT_PHASE 1031 --------------- 1032 1. It is used to displays the results of the simulation,informations 1033 2. It follows bottom-up approach 1034 1035 //FINAL_PHASE 1036 --------------- 1037 1. It performs all the .final adjustments,outstanding works,wrapping the simulation 1038 2. It follows top-down approach same as build_phase 1039 1040 */ 1041 ==================== 1042 //ENVIRONMENT CLASS 1043 ==================== 1044 1045 class ram_env extends uvm_env; 1046 1047 // Factory Registration 1048 `uvm_component_utils(ram_env) 1049 1050 // Declare the ram_wr_agent handle 1051 ram_wr_agent wr_agnth; 1052 1053 1054 //------------------------------------------ 1055 // METHODS 1056 //------------------------------------------ 1057 1058 // Standard UVM Methods: 1059 extern function new(string name = "ram_env",uvm_component parent); 1060 extern function void build_phase(uvm_phase phase); 1061 extern function void connect_phase(uvm_phase phase); 1062 extern function void end_of_elaboration_phase(uvm_phase phase); 1063 extern function void start_of_simulation_phase(uvm_phase phase); 1064 extern task run_phase(uvm_phase phase); 1065 extern function void extract_phase(uvm_phase phase); 1066 extern function void check_phase(uvm_phase phase); 1067 extern function void report_phase(uvm_phase phase); 1068 1069 endclass 1070 1071 1072 1073 1074 1075 1076 1077 ========================= 1078 //constructor new method 1079 ========================= 1080 1081 function ram_env::new(string name="ram_env",uvm_component parent); 1082 super.new(name,parent); 1083 endfunction 1084 1085 1086 1087 // Add UVM phases 1088 // NOTE : Call super.*_phase() in every phase method ,* indicates build,connect,etc 1089 // Hint : `uvm_info(“RAM_ENV”,”This is Build Phase ”, UVM_LOW) 1090 1091 ================ 1092 //build() phase 1093 ================ 1094 1095 function void ram_env::build_phase(uvm_phase phase); 1096 super.build_phase(phase); 1097 // Create the instance of agent in the build phase 1098 wr_agnth=ram_wr_agent::type_id::create("wr_agnth",this); 1099 `uvm_info("RAM_ENV","THIS IS BUILD PHASE OF ram_env",UVM_LOW) 1100 endfunction 1101 1102 1103 ================== 1104 //connect() phase 1105 ================== 1106 1107 function void ram_env::connect_phase(uvm_phase phase); 1108 super.connect_phase(phase); 1109 `uvm_info("RAM_ENV","THIS IS CONNECT PHASE OF ram_env",UVM_LOW) 1110 endfunction 1111 1112 ============================= 1113 //end_of_elaboration() phase 1114 ============================= 1115 1116 function void ram_env::end_of_elaboration_phase(uvm_phase phase); 1117 super.end_of_elaboration_phase(phase); 1118 `uvm_info("RAM_ENV","THIS IS AN END OF ELABORATION OF ram_env",UVM_LOW) 1119 endfunction 1120 1121 =============================== 1122 //start_of_simulation() phase 1123 =============================== 1124 1125 function void ram_env::start_of_simulation_phase(uvm_phase phase); 1126 super.start_of_simulation_phase(phase); 1127 `uvm_info("RAM_ENV","THIS IS START OF SIMULATION OF ram_env",UVM_LOW) 1128 endfunction 1129 1130 ============== 1131 //run() phase 1132 ============== 1133 // Raise and drop objections 1134 // With in raising ans dropping the objections add 100 delay in the run phase before printing 1135 1136 task ram_env::run_phase(uvm_phase phase); 1137 super.run(); 1138 phase.raise_objection(this); 1139 #100; 1140 `uvm_info("RAM_ENV ","THIS IS RUN PHASE OF ram_env",UVM_LOW) 1141 phase.drop_objection(this); 1142 endtask 1143 1144 1145 //This is the only phase which is task and it is time consuming remaining all other phases are functions & completes 1146 in zero simulation time. 1147 // 1148 ================== 1149 //extract() phase 1150 ================== 1151 1152 function void ram_env::extract_phase(uvm_phase phase); 1153 super.extract_phase(phase); 1154 `uvm_info("RAM_ENV","THIS IS EXTRACT PHASE OF ram_env",UVM_LOW) 1155 endfunction 1156 1157 1158 1159 1160 1161 1162 1163 ================ 1164 //check() phase 1165 ================ 1166 1167 function void ram_env::check_phase(uvm_phase phase); 1168 super.check_phase(phase); 1169 `uvm_info("RAM_ENV","THIS IS CHECK PHASE OF ram_env",UVM_LOW) 1170 endfunction 1171 1172 ================= 1173 //report() phase 1174 ================= 1175 1176 function void ram_env::report_phase(uvm_phase phase); 1177 super.report_phase(phase); 1178 `uvm_info("RAM_ENV","THIS IS REPORT PHASE OF ram_env",UVM_LOW) 1179 endfunction 1180 1181 1182 1183 1184 endclass 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 -----------------------------------------------------============------------------------------------------------- 1207 //====================================================OBJECTIONS================================================== 1208 -----------------------------------------------------============------------------------------------------------- 1209 class 1210 1211 1212 / 1213 1. Components and Objects can raise and drop the objections 1214 2. It remains in same phase till all the objections are dropped 1215 3. Used in the run_phase 1216 1217 1218 //OBJECTIONS 1219 -------------- 1220 1. IN COMPONENTS 1221 -> Phase.raise_objection(this); 1222 -> Phase.drop_objection(this); 1223 1224 2. IN OBJECTS 1225 -> Starting_phase.raise_objection(this); 1226 -> Starting_phase.drop_objection(this); 1227 1228 1229 Component which is using run_phase should tell the simulator that I'm using the run_phase by raising a 1230 objections 1231 1232 once it complete all the.task.or functionalities in run_phase then it should drop the objection 1233 1234 Simulator will track the objections , It will done via variable count, .this count variable will increment 1235 every .time when a component raise_objection.and will decrement every.time when component drop the 1236 objection.. 1237 1238 So when all the raise_objection will droped the count will become zero at that.time simulator will 1239 understand that all the components have completed the run_phase,.and then it will terminate the run_phase 1240 .and move to post run_phases 1241 1242 1243 uvm_objection::raise_objection(uvm_object null,string description="",int count=1); 1244 1245 uvm_objection::raise_objection(uvm_object null,string description="",int count=1); 1246 1247 1. uvm_object ---> only.this argument we have to passed 1248 2. description ---> default value ="" 1249 3. count ---> default value = 1 1250 1251 */ 1252 1253 //EXAMPLES 1254 ------------ 1255 1256 class agent extends uvm_agent; 1257 1258 virtual task run_phase(uvm_phase phase); 1259 phase.raise_objection(this); //this keyword will tell which component raised the objection 1260 #100; //phase will tell phase eg. reset,configure,main,shutdown 1261 phase.drop_objection(this); //this keyword will tell which component droped the objection 1262 endtask 1263 1264 endclass 1265 1266 1267 class driver extends uvm_driver; 1268 1269 virtual task run_phase(uvm_phase phase); 1270 phase.raise_objection(this); 1271 #10; 1272 phase.drop_objection(this); 1273 endtask 1274 1275 endclass 1276 1277 1278 /* 1279 at time= 0 ns both agent and driver will raise objection,so the value of count will get incremented two times 1280 1281 time= 0 ns count=2; //both agent,driver raise_objection 1282 time= 10 ns count=1; //driver drop_objection 1283 time= 100 ns count=0; //agent drop_objection & run_phase terminated 1284 */ 1285 1286 1287 1288 1289 1290 1291 1292 1293 test 1294 ---------------------------------------------------- ------------------------------------------------- 1295 | virtual task run_phase(uvm_phase phase); | | virtual task run_phase(uvm_phase phase); | 1296 | | | | 1297 | phase.raise_objection(this); | | phase.raise_objection(this); | 1298 | #10; | |/* #10; */ | 1299 | /* #5; */ | | #5; | 1300 | phase.drop_objection(this); | | phase.drop_objection(this); | 1301 | endtask | | endtask | 1302 | | | | 1303 | | | | 1304 driver | | | | 1305 | | | | 1306 | virtual task run_phase(uvm_phase phase); | | virtual task run_phase(uvm_phase phase); | 1307 | #6 */ | | #6 | 1308 | phase.raise_objection(this); | | phase.raise_objection(this); | 1309 | #15; */ | | #15; | 1310 | phase.drop_objection(this); | | phase.drop_objection(this); | 1311 | endtask | | endtask | 1312 ----------------------------------------------------- ------------------------------------------------- 1313 1314 class solution 1315 1316 time = 0 ns count=1 time = 0 ns count=1 1317 time = 6 ns count=2 time = 5 ns count=0 1318 time = 10 ns count=1 run_phase will get terminated time = 5 ns 1319 time = 21 ns count=0 driver run_phase suspended 1320 1321 run_phase terminated time = 21 ns 1322 1323 endclass 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 test 1337 ----------------------------------------------------- ------------------------------------------------- 1338 | virtual task run_phase(uvm_phase phase); | | virtual task run_phase(uvm_phase phase); | 1339 | | |/* #1 */ | 1340 | phase.raise_objection(this); | |/* phase.raise_objection(this); */ | 1341 | #10; | | | 1342 | /* #5; */ | | #5; | 1343 |/* phase.drop_objection(this); */ | |/* phase.drop_objection(this); */ | 1344 | endtask | | endtask | 1345 | | | | 1346 | | | | 1347 driver | | | | 1348 | | | | 1349 | virtual task run_phase(uvm_phase phase); | | virtual task run_phase(uvm_phase phase); | 1350 | #6 */ | | #6 | 1351 | phase.raise_objection(this); | |/* phase.raise_objection(this); */ | 1352 | #15; */ | | #15; | 1353 | phase.drop_objection(this); | |/* phase.drop_objection(this); */ | 1354 | endtask | | endtask | 1355 ----------------------------------------------------- ------------------------------------------------- 1356 1357 class solution 1358 1359 /*Suppose a component raise a objection | simulator will terminate run_phase at zero 1360 but not droped that objection ????? | simulation time */ 1361 in that .case simulator will give fatal error | at time = 0 ns atleast one component should raise 1362 after certain time that is timeout condition | an objection 1363 1364 endclass 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 test 1380 ----------------------------------------------------- 1381 | virtual task run_phase(uvm_phase phase); | 1382 | #1; | 1383 | phase.raise_objection(this); | 1384 | #10; | 1385 | /* #5; */ | 1386 |/* phase.drop_objection(this); */ | 1387 | endtask | 1388 | | 1389 | | 1390 driver | | 1391 | | 1392 | virtual task run_phase(uvm_phase phase); | 1393 | #6 */ | 1394 | phase.raise_objection(this); | 1395 | #15; */ | 1396 | phase.drop_objection(this); | 1397 | endtask | 1398 ----------------------------------------------------- 1399 1400 1401 class solution 1402 1403 simulator will terminate run_phase at zero simulation .time 1404 1405 at time = 0 ns atleast one component should raise an 1406 objection 1407 1408 endclass 1409 1410 endclass 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 ------------------------------------------------=====================--------------------------------------------- 1421 //===============================================REPORTING MECHANISM============================================== 1422 ------------------------------------------------=====================--------------------------------------------- 1423 class 1424 1425 1. IT is used to display message on terminal according to verbosity level 1426 1427 //Why Reporting Mechanism over $display ????? 1428 ============================================= 1429 1.It can filter display message manually 1430 2.We can enable/disable certain message from MakeFile without going back to tb.and change it in code 1431 3.We can give severity here 1432 eg. fatal,error,warning,info etc. 1433 4.We can call reporting mechanism by.function or UVM Macros(recommended). 1434 5.During developing tb we want certain messages and after completing TB, We don't want these messages so we 1435 can simply filter out using verbosity levels. 1436 1437 1438 /* virtual function void uvm_report_info(string id, 1439 string message, 1440 int verbosity=UVM_HIGH, 1441 string filename="", 1442 int line=0); 1443 */ 1444 $display("THIS IS DRIVER CLASS"); 1445 1446 Instead of using $display we use 1447 1448 uvm_report_info("DRIVER","THIS IS DRIVER CLASS",UVM_MEDIUM,driver,20); 1449 1450 ID: We can give any string here 1451 MESSAGE: We can give any message 1452 VERBOSITY: verbosity to filter out 1453 FILENAME: .class name 1454 LINE NO: line no 1455 1456 It is very tough to track line no. everytime as an argument here, so coz of this we use uvm_macros. 1457 1458 `uvm_info("DRIVER","THIS IS DRIVER CLASS",UVM_MEDIUM) 1459 1460 this macro again call method ----> uvm_report_info only 1461 1462 but whenever it is calling it is able to provide the.class name and line no. 1463 1464 / 2. uvm_report_warning 3. uvm_report_error 4.uvm_report_fatal 1465 1466 virtual function void uvm_report_warning(string id, 1467 string message, 1468 int verbosity=UVM_NONE, 1469 string filename="", 1470 int line=0); 1471 1472 virtual function void uvm_report_error(string id, 1473 string message, 1474 int verbosity=UVM_NONE, 1475 string filename="", 1476 int line=0); 1477 1478 virtual function void uvm_report_fatal(string id, 1479 string message, 1480 int verbosity=UVM_NONE, 1481 string filename="", 1482 int line=0); 1483 1484 */ 1485 1486 =================== 1487 //SEVERITY MACROS: 1488 =================== 1489 1490 It is very tough to track line no. everytime as an argument here, so coz of this we use uvm_macros. 1491 1492 In Macros only 3 arguments we need to pass 1493 1.id 1494 2.message 1495 3.verbosity 1496 1497 UVM Reporting provides Macros to embed report messages. Followings are the Macros to be used: 1498 1499 `uvm_info (string ID, string MSG, verbosity); 1500 `uvm_error (string ID, string MSG); 1501 `uvm_warning(string ID, string MSG); 1502 `uvm_fatal (string ID, string MSG); 1503 1504 1. It is not recommended to filter out warning,fatal and error messages 1505 2. By default for warning,fatal,error verbosity is UVM_NONE So third argument verbosity no need to pass 1506 1507 `uvm_info(string ID, string MSG, verbosity=UVM_MEDIUM); 1508 1509 Example: `uvm_info("DRIVER","Driver data",UVM_MEDIUM); 1510 1511 1512 //OUTPUT: 1513 .==========================================================================================. 1514 |/* file_name time scope ID Message */| 1515 | _____________|_____________ _|_ ________|__________ ___|____ ____|______ | 1516 | UVM_INFO../wr_agt_top/ram_wr_driver.sv(50)@0:top.wr_agt_agth.drvh [DRIVER] Driver data | 1517 | | | | 1518 |/* severity line_no*/ | 1519 '==========================================================================================' 1520 1521 TIP: get_type_name() --> returns id of the .class type 1522 instead of giving type id which is .class name generally we can use method get_type_name(). 1523 1524 TO DISABLE File name and Line no we use command ---> +define+UVM_REPORT_DISABLE_FILE_LINE in command line 1525 1526 //OUTPUT: 1527 // time scope ID Message 1528 _|_ ________|__________ ___|____ ____|______ 1529 UVM_INFO../@0:top.wr_agt_agth.drvh [DRIVER] Driver data 1530 | 1531 // severity 1532 ============= 1533 //VERBOSITY: 1534 ============= 1535 1536 Printing message can be controlled by giving different verbosity 1537 1538 by default verbosity is UVM_MEDIUM 1539 It is an enum data type defined in liabrary .class itself. 1540 1541 typedef enum{UVM_NONE=0, UVM_LOW=100, UVM_MEDIUM=200, UVM_HIGH=300, UVM_FULL=400, UVM_DEBUG=500} 1542 uvm_verbosity; 1543 1544 .***********************************************************************************************************. 1545 |/* IMPORTANT: We are not suppossed to use verbosity UVM_DEBUG it used for debugging UVM liabrary classes */| 1546 |/* if we give this as verbosity so many messages will get displayed. */| 1547 '***********************************************************************************************************' 1548 1549 .============. 1550 | VERBOSITY | 1551 |============| 1552 | UVM_NONE | 1553 | UVM_LOW | 1554 | UVM_MEDIUM |-------> Set the verbosity 1555 | UVM_HIGH | UVM_MEDIUM,UVM_LOW & UVM_NONE will print 1556 | UVM_FULL | UVM_HIGH & UVM_FULL will be ignored 1557 '------------' 1558 1559 Suppose we set default verbosity UVM_LOW so it will display only UVM_LOW and UVM_NONE but in scoreboard we 1560 want to display messages with UVM_MEDIUM verbosity also 1561 then it can be done by 1562 1563 //set_report_verbosity_level(verbosity); 1564 ======================================= 1565 1566 env.sb.set_report_verbosity_level(UVM_MEDIUM); 1567 1568 1569 ================================== 1570 //MODIFY SIMULATOR DEFAULT ACTION: 1571 ================================== 1572 1573 As mentioned above, UVM allows to bind a Reporting Severity with a particular valid Simulator Action. 1574 Usually its done inside the start_of_simulation() phase. 1575 1576 Actions can be assigned using set_report_*_action() functions. 1577 These can be done for one or all in the priority order from lowest to highest. 1578 1579 .---------------------------------------------------------. 1580 /*BY SEVERITY:*/ | set_report_severity_action(Severity, Action); | //[Lowest Priority] 1581 /*BY ID*/ | set_report_id_action(ID, Action); | 1582 /*BY BOTH*/ | set_report_severity_id_action(Severity, ID, Action); | //[Highest Priority] 1583 '---------------------------------------------------------' 1584 //EXAMPLE: 1585 1586 1587 1588 1589 1590 1591 1592 ============================== 1593 //LOGGING INTO SEPERATE FILE: 1594 ============================== 1595 1596 For suppose in driver.class want to display all the message of severity as an UVM_ERROR 1597 instead of showing them in terminal we want to log into a seperate file 1598 1599 drv.set_report_severity_action(UVM_ERROR,UVM_LOG+UVM_EXIT); 1600 1601 SEVERITY: UVM_ERROR 1602 ACTION : UVM_LOG+UVM_EXIT ---> log into seperate file and exit 1603 1604 So for Log into seperate file 1605 1606 1. First we need to open a file 1607 default_fd = $fopen("default_file","w"); // w --> write permission 1608 1609 1610 TEST 1611 BUILD_PHASE 1612 1613 warning_fd = $fopen("warning_file","w"); 1614 1615 // BASED ON SEVERITY: 1616 ------------------ 1617 env.sb.set_report_severity_file(UVM_WARNING,warning_fd); 1618 1619 env.sb.set_report_severity_action(UVM_WARNING,UVM_LOG); 1620 1621 // BASED ON ID: 1622 ------------- 1623 env.sb.set_report_id_file("SB",warning_fd); 1624 1625 env.sb.set_report_id_action("SB",UVM_LOG); 1626 1627 // BASED ON SEVERITY_ID: 1628 --------------------- 1629 env.sb.set_report_severity_id_file(UVM_WARNING,"SB",warning_fd); 1630 1631 env.sb.set_report_severity_id_action(UVM_WARNING,"SB",UVM_LOG); 1632 1633 1634 1635 ======================================== 1636 //SETTING VERBOSITY FROM COMMAND LINE: 1637 ======================================== 1638 One of the biggest advantage of the controlling Verbosity level from the command line is that we don’t need to re- 1639 compile the Design & Testbench if we want to change the .generate different log information from our next simulation 1640 run. 1641 1642 The simplest option is the command line switch: 1643 1644 +UVM_VERBOSITY=<verbosity> 1645 1646 eg. 1647 1648 % simv +UVM_VERBOSITY=UVM_HIGH 1649 1650 //NOW LETS SEE BELOW SOME MORE ADVANCED VERBOSITY SETTING FROM THE COMMAND LINE: 1651 1652 If you find the messages from a simulation run is extremely verbose, the simulation can be re-run with command line 1653 switches to filter some of the noise that appears on the our screen and log: 1654 1655 +uvm_set_verbosity=<comp>,<id>,<verbosity>,<phase> 1656 1657 eg. 1658 1659 To change the verbosity level to UVM_LOW for the uvm_test_top.env.agnt.drv instance with ID as DRV during the run 1660 phase, which would suppress all the messages with verbosity setting of UVM_MEDIUM or higher, execute the following 1661 command: 1662 1663 % simv +UVM_TESTNAME=test1 +uvm_set_verbosity=uvm_test_top.env.agnt.drv,DRV,UVM_LOW,run 1664 1665 1666 .=========================================. .=======================================================. 1667 |/* Severity ||Default Simulator Action*/| | Simulator Action | Description | 1668 .=========================================. .===================.===================================. 1669 | UVM_FATAL | UVM_DISPLAY + UVM_EXIT | | UVM_EXIT | Exit from simulation immediately | 1670 | UVM_ERROR | UVM_DISPLAY + UVM_COUNT | | UVM_COUNT | Increment globar error count | 1671 | UVM_WARNING | UVM_DISPLAY | | UVM_DISPLAY | Display message on console | 1672 | UVM_INFO | UVM_DISPLAY | | UVM_LOG | Capture message in a named file | 1673 '--------------'--------------------------' | UVM_CALLBACK | Calls callback methods | 1674 | UVM_NO_ACTION | Do nothing | 1675 '-------------------'-----------------------------------' 1676 1677 endclass 1678 ---------------------------------------------===========================------------------------------------------ 1679 //============================================TRANSACTION LEVEL MODELING========================================== 1680 ---------------------------------------------===========================------------------------------------------ 1681 class 1682 1683 //WHY TLM ????? 1684 ================ 1685 1686 1. TLM Stands for Transaction Level MODELING 1687 2. TLM Promoted Re-usability as they have same .interface 1688 3. Interoperability for mixed language verification environment 1689 4. Maximizes reuse and minimize the time and effort 1690 1691 1692 1693 //WHAT IS TLM ?? 1694 ================ 1695 1696 1. Messsage passing system 1697 2. TLM Interface 1698 1. Ports- set of methods Ex. Get(), Put(), Peek() etc 1699 2. Exports/Imp- Implementation for the METHODS 1700 1701 1702 1703 1704 1705 PORT: 1.In a initiator you will have a port with port we call the method. 1706 eg. get_port or put_port 1707 1708 -> Denoted by square 1709 -> If component is initiator and sending the data then it should have put_port 1710 -> If component is initiator and recieving the data then it should have get_port 1711 -> Port always parametrize by single parameter which is transaction type 1712 (write_xtn) 1713 1714 IMPLEMENTATION PORT: 2.get(),put() methods are implemented by the implementation port inside the target 1715 eg. get_imp or put_imp 1716 -> put()/get() method should be implemented by imp_ports otherwise it will give 1717 error. 1718 -> Denoted by circle(O) 1719 -> imp_port always parametrize by two parameter which is transaction type 1720 (write_xtn) & .class name in which put/get method is implemented 1721 1722 EXPORT: 3. It will not implement any method 1723 1724 TLM FIFO: 4. Both are initiator here and Generator sending the data so it should have put_port 1725 -> Driver recieving the data so it should have get_port 1726 -> TLM_FIFO have put_export & get_export 1727 -> Methods like get(), put(), peek() etc are implemented inside TLM_FIFO 1728 1729 ANALYSIS PORT: 4. Denoted by diamond/rhombus symbol 1730 --> One to Many connection 1731 --> It acts like a Broadcaster 1732 --> Analysis port may be connected to zero, one or many analysis_export 1733 --> Analysis port has single write() method 1734 --> If analysis_export not implemented write() method in target then it won't 1735 give any error 1736 1737 ANALYSIS FIFO: 5. Analysis fifo have analysis_imp port and write() method is implemented here 1738 1739 1740 //It does not matter who is initiator wether driver or generator data always come from generator 1741 1742 RE-USABILITY:- 1743 -------------- 1744 /*Let's suppose we want to call the put method which is inside the driver, 1745 what we can do is declare handle of driver inside generator and call it, but by doing this 1746 we can't use same generator for another driver, so here we use this put_port method*/ 1747 1748 //Port and Implementation Port should parametrized by same transaction otherwise compatiblity issue occur, 1749 it will not work. 1750 1751 1752 // In SV MAILBOX is Target and GENERATOR, DRIVER both are initiator because mailbox have put and get 1753 methods. 1754 1755 /*Soppose here in UVM Both are initiator what we will do then ?????? 1756 -> We use TLM_FIFO 1757 */ 1758 1759 1760 1761 1762 1763 1764 ---------------------------------------------------=============-------------------------------------------------- 1765 //===================================================TLM PORTS=================================================== 1766 ---------------------------------------------------=============-------------------------------------------------- 1767 class 1768 ===================== 1769 // BLOCKING GET PORT: 1770 ===================== 1771 //AHB GENERATOR:(Target) 1772 ------------------------- 1773 1774 class ahb_gen extends uvm_component; 1775 1776 uvm_blocking_get_imp 1777 #(write_xtn,ahb_gen) get_imp; 1778 //2 parameter 1779 virtual task get(output write_xtn t); 1780 write_xtn tmp = new(); 1781 //assign value to tmp 1782 t=temp; 1783 endtask 1784 endclass 1785 1786 //AHB DRIVER:(Initiator) 1787 ------------------------- 1788 1789 class ahb_driver extends uvm_component; 1790 uvm_blocking_get_port#(write_xtn) get_port; 1791 // 1 parameter 1792 function new(string name,uvm_component parent); 1793 super.new(name,parent); 1794 get_port = new("get_port",this); 1795 endfunction 1796 1797 virtual task run_phase(uvm_phase phase); 1798 write_xtn t; 1799 for(int i=0;i<N;i++); 1800 begin 1801 //generate t 1802 get_port.get(t); //It invoke get method inside generator 1803 end 1804 endtask 1805 endclass 1806 1807 //How driver will know that from which generator class the get() method should it call ?????? 1808 --> Through the connection between driver and generator which we did in environment 1809 1810 ===================== 1811 // BLOCKING PUT PORT: 1812 ===================== 1813 1814 //APB GENERATOR:(Initiator) 1815 ---------------------------- 1816 class apb_gen extends uvm_component; 1817 uvm_blocking_put_port#(write_xtn) put_port; 1818 //1 parameter 1819 function new(string name,uvm_component parent); 1820 super.new(name,parent); 1821 put_port = new("put_port",this); 1822 endfunction 1823 1824 virtual task run_phase(uvm_phase phase); 1825 write_xtn t; 1826 for(int i=0;i<N;i++); 1827 begin 1828 //generate t 1829 put_port.put(t); //It invoke put method inside driver 1830 end 1831 endtask 1832 endclass 1833 1834 //APB DRIVER:(Target) 1835 ---------------------- 1836 1837 class apb_driver extends uvm_component; 1838 uvm_blocking_put_imp 1839 #(write_xtn,apb_driver) put_imp; 1840 //2 parameter 1841 virtual task put(input write_xtn t); 1842 1843 case(t.kind) 1844 READ: //Do read 1845 WRITE: //Do write 1846 endcase 1847 endtask 1848 1849 endclass 1850 ======================== 1851 //CONNECTING TLM PORTS: 1852 ======================== 1853 1854 --> When connecting components at the same level of hierarchy, port are always connected to export 1855 eg. ___.port.connect(___.export) 1856 1857 --> When connecting port to implementation port ,port are always connected to implementation port 1858 eg. ___.port.connect(___.imp_port) 1859 1860 1861 class my_env extends uvm_env; 1862 //GET 1863 ahb_gen ahb_genh; 1864 ahb_driver ahb_drvh; 1865 1866 //PUT 1867 apb_gen apb_genh; 1868 apb_driver apb_drvh; 1869 1870 function void connect(uvm_phase phase); 1871 1872 ahb_drvh.get_port.connect(ahb_genh.get_imp); //Driver(Initiator)--->Generator(Target) 1873 apb_genh.put_port.connect(apb_drvh.put_imp); //Generator(Initiator)--->Driver(Target) 1874 1875 endfunction 1876 1877 endclass 1878 1879 1880 endclass 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 ---------------------------------------------------============--------------------------------------------------- 1894 //===================================================TLM FIFO:=================================================== 1895 ---------------------------------------------------============--------------------------------------------------- 1896 class 1897 1898 1. Both are initiator here and Generator sending the data so it should have put_port 1899 2. Driver recieving the data so it should have get_port 1900 3. TLM_FIFO have put_export & get_export 1901 4. Methods like get(), put(), peek() etc are implemented inside TLM_FIFO 1902 1903 Producer puts the transaction into uvm_tlm_fifo, while consumer gets the transaction from fifo. 1904 1905 uvm_tlm_fifo#(write_xtn) fifoh; 1906 1907 1908 1909 //APB GENERATOR:(Initiator) 1910 ---------------------------- 1911 1912 class apb_gen extends uvm_component; 1913 uvm_blocking_put_port#(write_xtn) put_port; 1914 1915 function new(string name,uvm_component parent); 1916 super.new(name,parent); 1917 put_port = new("put_port",this); 1918 endfunction 1919 1920 virtual task run_phase(uvm_phase phase); 1921 write_xtn t; 1922 for(int i=0;i<N;i++); 1923 begin 1924 put_port.put(t); 1925 end 1926 endtask 1927 endclass 1928 1929 1930 1931 1932 1933 1934 1935 1936 //APB DRIVER:(Initiator) 1937 ------------------------- 1938 1939 class apb_driver extends uvm_component; 1940 uvm_blocking_get_port#(write_xtn) get_port; 1941 1942 function new(string name,uvm_component parent); 1943 super.new(name,parent); 1944 get_port = new("get_port",this); 1945 endfunction 1946 1947 virtual task run_phase(uvm_phase phase); 1948 write_xtn t; 1949 for(int i=0;i<N;i++); 1950 begin 1951 //generate t 1952 get_port.get(t); //It invoke get method inside TLM FIFO 1953 end 1954 endtask 1955 endclass 1956 1957 //APB_AGENT:(CONNECTION) 1958 -------------------------- 1959 class apb_agent extends uvm_component; 1960 1961 apb_gen apb_genh; 1962 apb_driver apb_drvh; 1963 1964 uvm_tlm_fifo#(write_xtn) fifoh; 1965 1966 function new(string name, uvm_component parent); 1967 super.new(name,parent); 1968 fifoh = new("fifoh",this); 1969 endfunction 1970 1971 function void connect_phase(uvm_phase phase); 1972 1973 apb_genh.put_port.connect(fifoh.put_export); 1974 apb_drvh.get_port.connect(fifoh.get_export); 1975 1976 endfunction 1977 1978 endclass 1979 1980 INCASE WE DON'T WANT TO USE FIFO THEN: 1981 1982 //TARGET CLASS 1983 --------------- 1984 1985 class target extends uvm_component; 1986 1987 uvm_blocking_get_imp#(write_xtn,target) get_imp; 1988 uvm_blocking_put_imp#(write_xtn,target) put_imp; 1989 1990 virtual task put(input write_xtn t); 1991 1992 case(t.kind) 1993 READ: //Do read 1994 WRITE: //Do write 1995 endcase 1996 1997 endtask 1998 1999 virtual task get(output write_xtn t); 2000 write_xtn tmp = new(); 2001 //assign value to temp 2002 tmp.addr = 15; 2003 tmp.data = 16; 2004 2005 t = tmp; 2006 endtask 2007 2008 endclass 2009 2010 **********WARNING******* 2011 //These get and put method in target should implemented in such a way data should be first in first out 2012 //We declare handle of target class in a class in which driver and initiator enclosed and do connection 2013 //we do not need to write those methods It is already defined inside uvm_tlm_fifo class 2014 2015 2016 2017 2018 2019 2020 2021 2022 //TLM FIFO METHODS 2023 ==================== 2024 2025 1. new() 2026 This is a constructor method used for the creation of TLM FIFO 2027 2028 function new (string name, 2029 uvm_component parent, 2030 int size=1 2031 ); 2032 endfunction 2033 2034 The name and parent are the normal uvm_component constructor arguments 2035 The size indicates the maximum size of the FIFO; a value of zero indicates no upper bound 2036 2037 2. size() --> Calling size() returns the size of the FIFO 2038 A return value of 0 indicates the FIFO capacity has no limit 2039 2040 3. used() --> Returns the number of entries put into the FIFO 2041 2042 4. is_empty() --> Returns 1 when there are no entries in the FIFO, 0 otherwise 2043 2044 5. is_full() --> Returns 1 when the number of entries in the FIFO is equal to its size, 0 otherwise 2045 2046 6. flush() --> Calling flush method will Remove all entries from the FIFO 2047 after the flush method call used method returns 0 and the is_empty method returns 1 2048 2049 endclass 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 -------------------------------------------------=================------------------------------------------------ 2066 //=================================================ANALYSIS PORT================================================= 2067 -------------------------------------------------=================------------------------------------------------ 2068 class 2069 2070 --> Denoted by diamond/rhombus symbol 2071 --> One to Many connection 2072 --> It acts like a Broadcaster 2073 --> Analysis port may be connected to zero, one or many analysis_export 2074 --> Analysis port has single write() method 2075 --> If analysis_export not implemented write() method in target then it won't get any error 2076 2077 2078 2079 2080 2081 //APB MONITOR: 2082 --------------- 2083 2084 class apb_mon extends uvm_component; 2085 uvm_analysis_port#(write_xtn) ap_h; 2086 2087 function new(string name, uvm_component parent); 2088 super.new(name,parent); 2089 2090 ap_h = new("ap_h",this); 2091 2092 endfunction 2093 2094 task run_phase(uvm_phase phase); 2095 2096 write_xtn t; 2097 forever 2098 begin 2099 //Sample interface signals 2100 t.addr = vif.addr; 2101 t.data = vif.data; 2102 t.wr = vif.wr; 2103 2104 ap_h.write(t); //write transaction 2105 end 2106 endtask 2107 endclass 2108 //SCOREBOARD: 2109 ------------- 2110 2111 class scoreboard extends uvm_scoreboard; 2112 uvm_analysis_imp#(write_xtn,scoreboard) analysis_imph; 2113 2114 function void write(write_Xtn xtn); 2115 //record coverage information of xtn 2116 endfunction 2117 2118 endclass 2119 2120 2121 2122 //ENVIRONMENT(CONNECTION): 2123 ---------------------------- 2124 2125 class my_env extends uvm_env; 2126 2127 apb_mon apb_monh; 2128 scoreboard sbh; 2129 cov_collector covh; 2130 2131 function void connect_phase(uvm_phase phase); 2132 2133 apb_monh.ap_h.connect(sbh.analysis_imph); 2134 apb_monh.ap_h.connect(covh.analysis_imph); 2135 2136 endfunction 2137 endclass 2138 2139 endclass 2140 2141 -------------------------------------------------=================------------------------------------------------ 2142 //=================================================ANALYSIS FIFO================================================= 2143 -------------------------------------------------=================------------------------------------------------ 2144 class 2145 2146 -> Many situations require synchronization between the transaction streams, so that data is not lost 2147 -> Example: an in-order Comparator(SB) has two streams, one from the predictor and one from the monitor 2148 -> Must wait until it has a matching pair of transaction, one from each streams, to compare 2149 2150 2151 //SCOREBOARD: 2152 -------------- 2153 2154 class scoreboard extends uvm_scoreboard; 2155 2156 tlm_analysis_fifo#(write_xtn) a_fifoh; 2157 2158 function new(string name, uvm_component parent); 2159 super.new(name,parent); 2160 2161 a_fifoh = new("a_fifoh",this); 2162 2163 endfunction 2164 2165 endclass 2166 2167 //APB MONITOR: 2168 --------------- 2169 2170 class apb_mon extends uvm_component; 2171 uvm_analysis_port#(write_xtn); ap_h; 2172 2173 function new(string name, uvm_component parent); 2174 super.new(name,parent); 2175 2176 ap_h = new("ap_h",this); 2177 2178 endfunction 2179 2180 task run_phase(uvm_phase phase); 2181 2182 write_xtn t; 2183 forever 2184 begin 2185 //Sample interface signals 2186 t.addr = vif.addr; 2187 t.data = vif.data; 2188 t.wr = vif.wr; 2189 2190 ap_h.write(t); //write transaction 2191 end 2192 endtask 2193 endclass 2194 //ENVIRONMENT(CONNECTION): 2195 ---------------------------- 2196 2197 class my_env extends uvm_env; 2198 2199 apb_mon apb_monh; 2200 scoreboard sbh; 2201 2202 function void connect_phase(uvm_phase phase); 2203 2204 apb_monh.ap_h.connect(sbh.a_fifoh.analysis_export); 2205 2206 endfunction 2207 endclass 2208 2209 endclass 2210 2211 2212 ----------------------------------------------------===========--------------------------------------------------- 2213 //====================================================METHODS==================================================== 2214 ----------------------------------------------------===========--------------------------------------------------- 2215 class 2216 2217 ================================== 2218 //BLOCKING VS NON-BLOCKING METHODS 2219 ================================== 2220 2221 --> Blocking Methods- 2222 It will block the execution untill gets the data 2223 It will recommended 2224 -> Put() 2225 -> Get() 2226 -> Peek 2227 2228 -->Non-Blocking Methods- 2229 1. It will not block the execution , 2230 2. It will return 0 - fail, target is busy 2231 return 1 - Successful 2232 3. these functions return bit type 2233 2234 -> Try_put() 2235 -> Try_get() 2236 -> Try_peek() 2237 2238 class consumer extends uvm_component 2239 uvm_get_port#(write_xtn) get_port; 2240 2241 task run_phase(uvm_phase phase); 2242 2243 for(int i=0;i<N;i++) 2244 begin 2245 if(get_port.try_get(xtn)) 2246 //Do something with xtn 2247 end 2248 endtask 2249 endclass 2250 2251 2252 2253 endclass 2254 2255 2256 ---------------------------------------------=========================-------------------------------------------- 2257 //============================================HIERARCHICAL CONNECTION============================================ 2258 ---------------------------------------------=========================-------------------------------------------- 2259 class 2260 2261 ============ 2262 //PRODUCER: 2263 ============ 2264 2265 class producer extends uvm_component; 2266 uvm_put_port#(trans) put_port; 2267 2268 conv c_h; 2269 Stim s_h; 2270 uvm_tlm_fifo#(trans) fifo_h; 2271 2272 function void connect_phase(uvm_phase); 2273 2274 s_h.put_port.connect(fifo_h.put_export); 2275 c_h.get_port.connect(fifo_h.get_export); 2276 c_h.put_port.connect(this.put_port); 2277 2278 endfunction 2279 endclass 2280 ============ 2281 //CONSUMER: 2282 ============ 2283 2284 class producer extends uvm_component; 2285 uvm_put_export#(trans) put_exportport; 2286 2287 drive d_h 2288 uvm_tlm_fifo#(trans) fifo_h; 2289 2290 function void connect_phase(uvm_phase); 2291 2292 d_h.get_port.connect(fifo_h.get_export); 2293 this.put_export.connect(fifo_h.put_export); 2294 2295 endfunction 2296 2297 endclass 2298 2299 2300 1. port to imp 2301 2302 2. port to port to imp 2303 2304 3. port to port to export to export to imp 2305 2306 4. port to export to imp 2307 2308 2309 In between port to imp there may be multiple port and export 2310 2311 Finally connection terminates in implementation port and it will implement methods which is called by the 2312 port 2313 2314 2315 port-to-port : sub_component.port.connect(main_component.port); 2316 2317 port-to-export/imp: comp1.port.connect(comp2.export); 2318 2319 export-t-export/imp: main_component.export.connect(sub_component.export); 2320 2321 endclass 2322 2323 -----------------------------------------------=======================-------------------------------------------- 2324 //==============================================SETTING CONFIGURATION============================================= 2325 -----------------------------------------------=======================-------------------------------------------- 2326 class BASE 2327 / 2328 Configuration is used to configure our testbench, to configure agents ,environment etc.. 2329 2330 We.use set().and get() method is used to configure these methods are defined in uvm_config_db class.and of 2331 static.type. 2332 2333 set method will create a database in which the variable which is last argument stored in that. 2334 set() performs write operation in associative array. 2335 get() performs read operation in associative array. 2336 2337 CONFIGURATION DATABASE is implemented using associative array where 2338 starting three arguments works as INDEX(address) which is of string.type.for associative array in which configured 2339 variable is stored 2340 2341 //Examples of inst_name(VISIBILITY) 2342 ==================================== 2343 top 2344 test 2345 env 2346 agent[0] 2347 drv 2348 mon 2349 seqr 2350 agent[1] 2351 drv 2352 mon 2353 seqr 2354 agent[2] 2355 drv 2356 mon 2357 seqr 2358 2359 top.test.env* – Visible to environment all below componets 2360 top.* – Visible to all componets whose top-level component is top 2361 top.test.env.*.mon – Visible to all the components in env that .end in the mon(all agent monitor) 2362 2363 *.agent[2].* – Visible to all componets whose top-level component is agent 2364 *.agent[2]* – Visible to agent[2] all below componets 2365 *.agent* – Visible to all agents all below components 2366 *************************************************************************************************************** 2367 void uvm_config_db#(type T = int)::set(uvm_component cntxt, string inst_name, string field_name, variable); 2368 2369 set() performs write operation in associative array. 2370 2371 Where, 2372 1. T is the.type of element being configured. 2373 (Type can be scalar objects,class handles, queues, lists, .or even virtual interfaces) 2374 2375 2. cntxt is the hierarchical starting point of where the database entry is accessible .or we can say current scope 2376 (Commonly we.use this keyword here) 2377 2378 3. inst_name is a hierarchical path that limits the accessibility of the database entry. 2379 2380 4. field_name is the label used as a lookup .for the database entry, It works as a pointer 2381 (Commonly we.use.type of element name as string here) 2382 2383 5. variable is the value to be stored in the database 2384 2385 bit uvm_config_db#(type T=int)::get(uvm_component cntxt, string inst_name, string field_name, variable); 2386 2387 get() performs read operation in associative array. 2388 2389 1. T is the .type of element being configured. 2390 (Type can be scalar objects,class handles, queues, lists, .or even virtual interfaces) 2391 2. cntxt is the hierarchical starting point of where the database entry is accessible .or we can say current scope 2392 (Commonly we .use this keyword here) 2393 3. inst_name ===> Commonly we .use empty string "" here. it will automatically fetch the hierarchy. 2394 4. field_name ===> It should be same as used .while setting the database otherwise get will get failed.. 2395 5. variable - is the .local variable through which the value is to be retrieved from the database 2396 . 2397 2398 The method returns 1 .if it is successful .and 0 .if failed. 2399 so it is recommended to .use get .with if .or .with assert. 2400 2401 //CONDITION WHEN GET WILL FAIL 2402 ================================ 2403 1. Second argument(IF Visibility is .not given properly) 2404 2. Third argument which is string should we same in both set() .and get(). 2405 2406 Because these two arguments are the part of INDEX(address) .for associative array. 2407 IF address is different .while getting the database then it will fail 2408 **************************************************************************************************************** 2409 =============== 2410 //TEST CLASS 2411 =============== 2412 2413 class test extends uvm_test; 2414 int no_of_agents=4; 2415 int verbosity=UVM_HIGH; 2416 bit is_active=UVM_ACTIVE; 2417 2418 task build_phase(uvm_phase phase); 2419 2420 uvm_config_db#(int)::set(this,"envh.agt_top","int",no_of_agents); 2421 2422 //assoc["uvm_test_top.envh.agt_top.int"]=no_of_agents(4) 2423 2424 2425 uvm_config_db#(int)::set(this,"envh.agt_top","int",verbosity); 2426 //assoc["uvm_test_top.envh.agt_top.int"]=UVM_HIGH 2427 2428 envh=environment::type_id::create("envh",this); 2429 2430 //IF we set multiple configuration database from same level of hierarchy the second set will win coz it will 2431 override first configuration, 2432 2433 //IT is like writing again in same location in associative array 2434 2435 //IF we want to set multiple variable then we can use different pointer name, 2436 2437 uvm_config_db#(int)::set(this,"envh.agt_top","int_1",verbosity); 2438 //assoc["uvm_test_top.envh.agt_top.int_1"]=UVM_HIGH 2439 2440 //but it is recommended to use type name as pointer. 2441 //so to overcome this problem we will use configuration class inside that class we will declare all the 2442 variables 2443 2444 endtask 2445 endclass 2446 2447 2448 2449 2450 2451 2452 ====================== 2453 //ENVIRONMENT CLASS 2454 ====================== 2455 2456 class environment extends uvm_env; 2457 2458 int no_of_agents=2; 2459 2460 task build_phase(uvm_phase phase); 2461 2462 agt_top=agent_top::type_id::create("agt_top",this); 2463 2464 uvm_config_db#(int)::set(this,"agt_top","int",no_of_agents); 2465 //assoc["envh.agt_top,int"]=no_of_agents(2) 2466 2467 /*QSN.Suppose we are seeting no_of_agents from environment also and giving visiblity to agent_top then from which 2468 database agent_top will fetch the value of no_of_agents. 2469 2470 //ANS. : from test , and the value is 4 2471 2472 //BECAUSE, 2473 2474 1. while setting from test the index(address) for associative array is array[uvm_test_top.envh.agt_top.int] 2475 2476 2. while setting from environment the index(address) for associative array is array[envh.agt_top.int] 2477 2478 3. while getting the value of no_of_agents in agnt top the empty string will start fetching the address from top 2479 hierarchy(uvm_test_top.envh.agt_top) if not matched then it will fetch(envh.agt_top) 2480 array[uvm_test_top.envh.agt_top.int] 2481 4.It is recommended to set the configuration from test 2482 */ 2483 endtask 2484 2485 endclass 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 =================== 2496 //AGENT TOP CLASS 2497 =================== 2498 2499 class agent_top extends uvm_env; 2500 2501 agent agt[]; 2502 2503 int no_of_agts; 2504 2505 task build_phase(uvm_phase phase); 2506 2507 if(!uvm_config_db#(int)::get(this,"","int",no_of_agts)); 2508 //no_of_agts=assoc["uvm_test_top.envh.agt_top.int"] 2509 `uvm_fatal("AGENT_TOP","Can not get config data") 2510 2511 /Here using get method agent_top can access the variable no_of_agents which is inside test. 2512 /for storing no_of_agents value here in agent top we can use different variable name(no_of_agts) 2513 2514 //but the third agrument that is string should be same as used during set. 2515 agt=new[no_of_agts]; 2516 2517 foreach(agt[i]) 2518 agt=agent::type_id::create($sformatf("AGENT[%d]",i),this); 2519 endtask 2520 2521 endclass 2522 2523 =============================== 2524 //CONFIGURATION_DATABASE CLASS 2525 =============================== 2526 2527 class config_database extends uvm_object; 2528 `uvm_object_utils(config_database) 2529 2530 int no_of_agents=3; //These are the default values 2531 int verbosity=UVM_LOW; //we can change any variable from test during setting the configuration 2532 bit is_active=UVM_PASSIVE; 2533 2534 endclass 2535 2536 2537 2538 =============== 2539 //TEST CLASS 2540 =============== 2541 2542 class test extends uvm_test; 2543 2544 config_database cfg; 2545 2546 int no_of_agents=4; 2547 bit is_active=UVM_ACTIVE; 2548 2549 task build_phase(uvm_phase phase); 2550 //create the object of config_database 2551 cfg=config_database::type_id::create("cfg"); 2552 //assign all the variables to config_database variables 2553 2554 cfg.no_of_agents=no_of_agents; 2555 cfg.is_active=is_active; 2556 2557 //set the config_database 2558 2559 uvm_config_db#(config_database)::set(this,"*","config_database",cfg); 2560 2561 //Here in second argument we can use wildcard character(*) it can match any string. 2562 2563 //assoc["uvm_test_top.*.config_database"]=cfg 2564 2565 envh=environment::type_id::create("envh",this); 2566 2567 endtask 2568 endclass 2569 2570 2571 2572 endclass 2573 class CONFIGURATION_SEQUENCES AND VIRTUAL_INTERFACE 2574 2575 2576 2577 2578 2579 2580 2581 ================================================================================================================== 2582 //====================================SETTING CONFIGURATION FOR VIRTUAL INTERFACE================================= 2583 ================================================================================================================== 2584 class 2585 2586 =================== 2587 //RAM_CONFIG CLASS 2588 =================== 2589 2590 class ram_config extends uvm_object; 2591 2592 virtual ram_if vif; 2593 - 2594 - 2595 - 2596 2597 endclass 2598 2599 ============= 2600 //TOP MODULE 2601 ============= 2602 2603 module top; 2604 2605 ram_if in0(clock); 2606 2607 ram_chip DUV (in0); 2608 2609 initial 2610 begin 2611 uvm_config_db#(virtual ram_if)::set(null,"*","ram_if",in0); 2612 2613 //there is no higher level component so we use null as first argument.. 2614 run_test(); 2615 end 2616 2617 endmodule 2618 2619 2620 2621 2622 2623 2624 ============= 2625 //TEST CLASS 2626 ============= 2627 2628 class test extends uvm_test; 2629 `uvm_component_utils(test) 2630 2631 ram_config tb_cfg; 2632 2633 function void build_phase(uvm_phase phase); 2634 super.build_phase(phase); 2635 2636 tb_cfg=ram_config::type_id::create("tb_cfg"); 2637 2638 //get the static interface from top and assign it to virtual interface handle vif inside ram_config 2639 //so now vif start pointing to static interface inside top 2640 2641 if(!uvm_config_db#(virtual ram_if)::get(this,"","ram_if",tb_cfg.vif)) 2642 `uvm_fatal("TEST","Can not get interface from config database") 2643 2644 //set the ram_config for all other components 2645 uvm_config_db#(ram_config)::set(this,"*","ram_config",tb_cfg); 2646 2647 endfunction 2648 2649 endclass 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 =============== 2668 //DRIVER CLASS 2669 =============== 2670 2671 class driver extends uvm_driver; 2672 2673 ram_config tb_cfg; 2674 virtual ram_if vif; 2675 2676 function void build_phase(uvm_phase phase); 2677 2678 super.build_phase(phase); 2679 //get the tb_cfg object 2680 if(!uvm_config_db#(ram_config)::get(this,"","ram_config",tb_cfg);) 2681 `uvm_fatal("DRIVER","Can not get the tb_config database") 2682 endfunction 2683 //assign virtual interface handle which is inside tb_config to local vif handle 2684 //So vif inside driver start pointing to vif which is inside tb_config 2685 2686 function void connect_phase(uvm_phase phase); 2687 vif=tb_cfg.vif; 2688 endfunction 2689 2690 endclass 2691 2692 ..=======================================================.. 2693 ||/* DRIVER TEST TOP */ || 2694 || vif("DRIVER")--->vif("TB_CONFIG")--->in0("TOP") || 2695 || || 2696 ''======================================================='' 2697 2698 2699 2700 endclass 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 ================================================================================================================== 2711 //============================================CONFIGURATION IN SEQUENCES========================================== 2712 ================================================================================================================== 2713 class 2714 2715 class wr_seq extends uvm_sequence#(write_xtn); 2716 2717 task body 2718 2719 if(!uvm_config_db#(ram_config)::get(null,get_full_name(),"ram_config",m_cfg)) 2720 `uvm_fatal("RAM_SEQ","Can not get the config") 2721 2722 /*1.sequence is a object so it has not any hierarchy 2723 that is why we use get_full_name method to get config object.. 2724 get_full_name fetch the path based on sequencer on which this sequence is started.. 2725 2726 FOR SETTING CONFIGURATION*/ 2727 2728 set(this,"env.agt.seqr.*","config_name",cfg) 2729 2730 /*env.agt.seqr.* => only visible to sequence 2731 env.agt.* => visible to driver,monitor,sequencer and sequence */ 2732 endtask 2733 endclass 2734 2735 2736 endclass 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 ================================================================================================================== 2754 //================================SETTING CONFIGURATION IN CASE OF MULTIPLE AGENTS================================ 2755 ================================================================================================================== 2756 class 2757 2758 uvm_test_top 2759 | 2760 |_env 2761 | 2762 |_ahb_agt_top 2763 | | 2764 | |_agt1 2765 | | |_drv 2766 | | |_mon 2767 | | |_seqr 2768 | | 2769 | |_agt2 2770 | |_drv 2771 | |_mon 2772 | |_seqr 2773 | 2774 |_apb_agt_top 2775 | | 2776 | |_agt 2777 | |_drv 2778 | |_mon 2779 | |_seqr 2780 | 2781 |_sb 2782 | 2783 | 2784 |_vseqr 2785 2786 /*In above hierarchy if configuration for each agent is different then how can we set configuration 2787 eg. for agt1 is active 2788 for agt2 is passive 2789 2790 with one configuration object we can not achieve it. 2791 2792 so for this we have seperate configuration class for each agent.*/ 2793 2794 2795 2796 =========================== 2797 //AHB_CONFIGURATION CLASS 2798 =========================== 2799 2800 class ahb_config extends uvm_object; 2801 `uvm_object_utils(ahb_config) 2802 2803 virtual ahb_if vif; 2804 uvm_active_passive_enum is_active; 2805 2806 function new(string name="AHB_CONFIG"); 2807 super.new(name); 2808 endfunction 2809 endclass 2810 2811 ========================== 2812 //APB_CONFIGURATION CLASS 2813 ========================== 2814 2815 class apb_config extends uvm_object; 2816 `uvm_object_utils(apb_config) 2817 2818 virtual apb_if vif; 2819 uvm_active_passive_enum is_active; 2820 2821 function new(string name="APB_CONFIG"); 2822 super.new(name); 2823 endfunction 2824 endclass 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 ========================== 2840 //ENV_CONFIGURATION CLASS 2841 ========================== 2842 2843 class env_config extends uvm_object; 2844 `uvm_object_utils(env_config) 2845 2846 int no_of_ahb_agent; 2847 int no_of_apb_agent; 2848 int has_ahb_agent; 2849 int has_apb_agent; 2850 int has_scoreboard; 2851 int has_virtual_sequencer; 2852 2853 ahb_config ahb_cfg[]; 2854 apb_config apb_cfg[]; 2855 2856 function new(string name="ENV_CONFIG"); 2857 super.new(name); 2858 endfunction 2859 2860 endclass 2861 2862 ============= 2863 //TOP MODULE 2864 ============= 2865 2866 module top; 2867 2868 ahb_if hif1,hif2; 2869 apb_if pif; 2870 2871 initial 2872 begin 2873 uvm_config_db#(virtual ahb_if)::set(null,"*","ahb_if1",hif1); 2874 uvm_config_db#(virtual ahb_if)::set(null,"*","ahb_if2",hif2); 2875 uvm_config_db#(virtual apb_if)::set(null,"*","apb_if",pif); 2876 2877 run_test(); 2878 end 2879 2880 endmodule 2881 2882 ============= 2883 //CLASS TEST 2884 ============= 2885 2886 class test extends uvm_test; 2887 `uvm_component_utils(test) 2888 2889 ahb_config hcfg[]; 2890 apb_config pcfg[]; 2891 env_config ecfg; 2892 2893 int no_of_ahb_agent=2; 2894 int no_of_apb_agent=1; 2895 int has_ahb_agent=1; 2896 int has_apb_agent=1; 2897 int has_scoreboard=1; 2898 int has_virtual_sequencer=1; 2899 2900 function void build_phase(uvm_phase phase); 2901 hcfg=new[no_of_ahb_agent]; 2902 pcfg=new[no_of_apb_agent]; 2903 ecfg=env_config::type_id::create("ENV_CONFIG"); 2904 2905 ecfg.ahb_cfg=new[no_of_ahb_agent]; 2906 ecfg.apb_cfg=new[no_of_apb_agent]; 2907 2908 //Creating configuration database object for ahb_agent 2909 foreach(hcfg[i]) 2910 begin 2911 hcfg[i]=ahb_config::type_id::create($sformatf("AHB_AGENT_CONFIG[%0d]",i)); 2912 //Getting interface from top module to hcfg database 2913 if(!uvm_config_db #(virtual ahb_if)::get(this,"",$sformatf("ahb_if%d",i+1),hcfg[i].vif)) 2914 `uvm_fatal("TEST","can not get config data"); 2915 hcfg[i].is_active=UVM_ACTIVE; 2916 ecfg.ahb_cfg[i]=hcfg[i]; 2917 //Setting the ahb_configuration only visible to agt1 and agt2 and lower components 2918 uvm_config_db#(ahb_config)::set(this,$sformatf("envh.ahb_agt_top.agt%d",i+1),"ahb_config",hcfg[i]); 2919 end 2920 2921 //Creating configuration database object for apb_agent 2922 2923 foreach(pcfg[i]) 2924 begin 2925 pcfg[i]=apb_config::type_id::create($sformatf("APB_AGENT_CONFIG[%0d]",i)); 2926 //Getting interface from top module to pcfg database 2927 if(!uvm_config_db #(virtual apb_if)::get(this,"","apb_if",pcfg[i].vif)) 2928 `uvm_fatal("TEST","can not get config data"); 2929 pcfg[i].is_active=UVM_ACTIVE; 2930 ecfg.apb_cfg[i]=pcfg[i]; 2931 2932 //Setting the ahb_configuration only visible to agt and lower 2933 uvm_config_db#(apb_config)::set(this,"envh.apb_agt_top.agt*","apb_config",pcfg[i]); 2934 end 2935 //Assigning values of 1.ahb_agent 2.apb_agent 3.scoreboard 4.virtual_sequencer to env config class. 2936 ecfg.no_of_ahb_agent=no_of_ahb_agent; 2937 ecfg.no_of_apb_agent=no_of_apb_agent; 2938 ecfg.has_ahb_agent=has_ahb_agent; 2939 ecfg.has_apb_agent=has_apb_agent; 2940 ecfg.has_scoreboard=has_scoreboard; 2941 ecfg.has_virtual_sequencer=has_virtual_sequencer; 2942 //Setting env configuration database 2943 uvm_config_db#(env_config)::set(this,"*","env_config",ecfg); 2944 super.build_phase(phase); 2945 //Creating object for environment class 2946 envh=env::type_id::create("ENVh",this); 2947 endfunction 2948 2949 endclass 2950 2951 2952 ================================================================================================================= 2953 /***********************************************/*******WARNING*******/*****************************************/ 2954 ================================================================================================================= 2955 Incase of multiple agent be careful while setting configuration 2956 2957 //WRONG WAY OF SETTING 2958 ----------------------- 2959 2960 foreach(hcfg[i]) 2961 uvm_config_db#(ahb_config)::set(this,"envh.ahb_agt_top.agt*","ahb_config",hcfg[i]); 2962 2963 //envh.ahb_agt_top.agt* -----> this string is same for all agents so here hcfg[1] will override hcfg[0] 2964 2965 //RIGHT WAY OF SETTING 2966 ----------------------- 2967 2968 foreach(hcfg[i]) 2969 uvm_config_db#(ahb_config)::set(this,$sformatf("envh.ahb_agt_top.agt%d",i+1),"ahb_config",hcfg[i]); 2970 2971 2972 /*INSTEAD of Setting agent configuration from test you can also set it from environment. 2973 2974 declare handle of all agent config in environment config class 2975 */ 2976 ================================================= 2977 //SETTING AGENT CONFIGURATION FROM ENVIRONMENT 2978 ================================================= 2979 2980 class env extends uvm_env; 2981 `uvm_component_utils(router_env); 2982 2983 env_config ecfg; 2984 2985 ahb_agt_top ahb_top; 2986 apb_agt_top apb_top; 2987 2988 2989 2990 function new(string name="ENV",uvm_component parent); 2991 super.new(name,parent); 2992 endfunction 2993 2994 function void build_phase(uvm_phase phase); 2995 if(!uvm_config_db#(env_config)::get(this,"","env_config",ecfg)) 2996 `uvm_fatal("ENV","can not get config data") 2997 super.build_phase(phase); 2998 2999 if(ecfg.has_ahb_agent) 3000 ahb_top=ahb_agt_top::type_id::create("AHB_TOP"); 3001 foreach(ecfg.ahb_cfg[i]) 3002 uvm_config_db#(ahb_config)::set(this,$sformatf("ahb_top.agt%d",i+1),"ahb_config",ecfg.ahb_cfg[i]); 3003 3004 if(ecfg.has_apb_agent) 3005 apb_top=apb_agt_top::type_id::create("APB_TOP"); 3006 foreach(ecfg.apb_cfg[i]) 3007 uvm_config_db#(aPb_config)::set(this,"apb_top.agt*","apb_config",ecfg.apb_cfg[i]); 3008 3009 endfunction 3010 endclass 3011 -----------------------------------------------------==========--------------------------------------------------- 3012 //====================================================SEQUENCE==================================================== 3013 -----------------------------------------------------==========--------------------------------------------------- 3014 class 3015 =============== 3016 //UVM_SEQUENCE 3017 =============== 3018 3019 class uvm_sequence #(type REQ=uvm_sequence_item, RSP=REQ) extends uvm_sequence_base; 3020 3021 uvm_sequencer_base m_sequencer; 3022 3023 task start(uvm_sequence_base seqr,,,,); 3024 m_sequencer=seqr; //m_sequencer=env.wagt.seqr 3025 this.body(); 3026 endtask 3027 3028 virtual task body(); 3029 3030 endtask 3031 3032 endclass : uvm_sequence 3033 3034 3035 ========================= 3036 //USER_DEFINED_SEQUENCE 3037 ========================= 3038 3039 class wr_seq extends uvm_sequence#(write_xtn); 3040 //uvm_sequencer_base m_sequencer; 3041 3042 `uvm_object_utils(wr_seq) 3043 3044 function new (string "name"); 3045 3046 endfunction 3047 3048 task body(); 3049 3050 //repeat(10) 3051 //begin 3052 req=write_xtn::type_id::create("req"); 3053 //repeat(10) 3054 begin 3055 start_item(req); //wait for driver request (get_next_item) 3056 req.randomize(); 3057 finish_item(req); //give req(data) to driver and wait for acknowledgment through item_done 3058 end 3059 endtask 3060 3061 endclass : wr_seq 3062 3063 ============== 3064 //TEST CLASS 3065 ============== 3066 3067 class test extends uvm_test; 3068 3069 task run_phase(uvm_phase phase); 3070 wr_seq wseq=create("wseq"); 3071 phase.raise_objection(this); 3072 3073 wseq.start(env.wagt.seqr); /*Start method make parent sequencer which is m_sequencer 3074 point to the sequencer which is passed as an argument to the start method and then 3075 it will call the task body which is defined in user defined(extented) sequence class*/ 3076 phase.drop_objection(this); 3077 endtask : run_phase 3078 endclass : test 3079 3080 /*====================================================================================== 3081 when the objection will drop 3082 ==>> after task body completed which is inside sequence 3083 means after all transaction recieved by driver through finish_item and after item_done send 3084 acknowledgment.*/ 3085 ==>> 3086 3087 3088 3089 3090 3091 3092 endclass 3093 3094 3095 3096 3097 -----------------------------------------------=====================---------------------------------------------- 3098 //==============================================NESTING_OF_SEQUENCE=============================================== 3099 -----------------------------------------------=====================---------------------------------------------- 3100 class 3101 =============== 3102 //WR_SEQ CLASS 3103 =============== 3104 3105 class wr_seq extends uvm_sequence#(write_xtn); 3106 //uvm_sequencer_base m_sequencer; 3107 3108 `uvm_object_utils(wr_seq) 3109 3110 function new (string "name"); 3111 3112 endfunction 3113 3114 task body(); 3115 3116 repeat(10) 3117 begin 3118 req=write_xtn::type_id::create("req"); 3119 start_item(req); 3120 assert(req.randomize()); 3121 finish_item(req); 3122 end 3123 3124 endtask 3125 3126 endclass : wr_seq 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 ================== 3141 //MAIN SEQ CLASS 3142 ================== 3143 3144 class main_seq extends uvm_sequence#(write_xtn); 3145 wr_seq wseq; 3146 3147 task body(); 3148 repeat(10) 3149 begin 3150 wseq = create("wseq"); 3151 wseq.start(m_sequencer); 3152 end 3153 endtask 3154 endclass 3155 3156 ============= 3157 //TEST CLASS 3158 ============= 3159 3160 class test extends uvm_test; 3161 3162 task run_phase(uvm_phase phase); 3163 main_seq mseq=create("wseq"); 3164 3165 phase.raise_objection(this); 3166 mseq.start(env.wagt.seqr); 3167 phase.drop_objection(this); 3168 3169 endtask : run_phase 3170 endclass : test 3171 3172 //by nesting sequence we can generate multiple transaction repeat(10) x repeat(10) = 100 transaction 3173 //===================================================================================== 3174 uvm_sequence extends uvm_sequence_base extends uvm_sequence_item extends uvm_transaction extends uvm_object extends 3175 uvm_void 3176 3177 //====================================================================================== 3178 3179 write_sequencer extends uvm_sequencer extends uvm_sequencer_base 3180 3181 3182 3183 ------------------------------------------------=====================--------------------------------------------- 3184 //===============================================EXTENDING RUN PHASE============================================== 3185 ------------------------------------------------=====================--------------------------------------------- 3186 class 3187 3188 class monitor extends uvm_monitor 3189 int busy=1; 3190 task run_phase(uvm_phase phase); 3191 forever 3192 begin 3193 .... 3194 collect_data(); 3195 if(ending) 3196 begin 3197 ... 3198 busy=0; 3199 phase.drop_objection(this); 3200 end 3201 end 3202 endtask : run_phase 3203 3204 virtual function void phase_ready_to_end(uvm_phase phase); 3205 //before the end of run phase this method will be called from run phase 3206 if(phase.get_name=="run") 3207 begin 3208 ending=1; 3209 if(busy) 3210 phase.raise_objection(this); 3211 end 3212 endfunction 3213 endclass : monitor 3214 3215 3216 endclass 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 ------------------------------------------=================================--------------------------------------- 3227 //=========================================DRIVER AND SEQUENCE HANDSHAKING======================================== 3228 ------------------------------------------=================================--------------------------------------- 3229 class 3230 / 3231 sequence sequencer driver 3232 || 3233 task body(); || task run_phase(uvm_phase phase); 3234 || forever 3235 begin || begin 3236 start_item(req); || seq_item_port.get_next_item(req); 3237 || 3238 req.randomize(); || drive(req); 3239 || 3240 finish_item(req); || seq_item_port.item_done(); 3241 end || end 3242 endtask || endtask 3243 3244 3245 task drive(); 3246 3247 //drive the DUT i/p 3248 //collect DUT o/p 3249 3250 rsp.data_out=vif.cb.data_out; 3251 3252 endtask 3253 3254 class driver extends uvm_driver#(write_xtn); 3255 3256 task run_phase(uvm_phase phase); 3257 forever 3258 begin 3259 seq_item_port.get_next_item(req); 3260 drive(req); 3261 seq_item_port.item_done(); 3262 // seq_item_port.put_response(rsp); // this response send back to the sequence using 3263 // rsp_port.write(rsp); //item_done,put_response,rsp_port.write 3264 3265 end 3266 endtask 3267 3268 endclass 3269 /*this response stored in response fifo whose depth is 8. 3270 and sequence will get the response by calling the method get_response(); 3271 3272 if we are using put_response(rsp) then in sequence it is must to get response using get_response(rsp) method 3273 otherwise sequence will not initiate next transaction*/ 3274 3275 class wr_seq extends uvm_sequence#(write_xtn); 3276 //uvm_sequencer_base m_sequencer; 3277 3278 `uvm_object_utils(wr_seq) 3279 3280 function new (string "name"); 3281 3282 endfunction 3283 3284 task body(); 3285 3286 //repeat(10) 3287 //begin 3288 req=write_xtn::type_id::create("req"); 3289 //repeat(10) 3290 begin 3291 start_item(req); //wait for driver request (get_next_item) 3292 req.randomize(); 3293 finish_item(req); //give req(data) to driver and wait for acknowledgment through item_done 3294 end 3295 endtask 3296 3297 get_response(rsp); 3298 3299 //if the next transaction object depend on data_out of DUT , 3300 if(rsp.data_out == ......(some logic)) /*here we can decide how data should we generated bassed on DUT response*/ 3301 begin 3302 start_item(req); /*wait for driver request (get_next_item)*/ 3303 req.randomize()with {........}; /*inline constraint*/ 3304 finish_item(req); /*give req(data) to driver and wait for acknowledgment through item_done*/ 3305 end 3306 endclass : wr_seq 3307 3308 3309 3310 endclass 3311 3312 ---------------------------------------------==========================------------------------------------------- 3313 //============================================SETTING DEFAULT SEQUENCE============================================ 3314 ---------------------------------------------==========================------------------------------------------- 3315 class 3316 //Using WRAPPER 3317 ---------------- 3318 uvm_config_db#(uvm_object_wrapper)::set(this,"agent.seqr.run_phase","default_sequence",seq1::type_id::get()); 3319 3320 /* //this(first argument) => current scope 3321 //agent.seqr.run_phase(second argument) => in which seqr and phase sequence will start 3322 //third argument => default_sequence string 3323 //fourth argument(type_id) => we can get type id by using static get() method or by calling get_type( 3324 3325 //Using INSTANCE 3326 ----------------- 3327 seq1_h=seq1::type_id::create("seq1_h"); 3328 3329 uvm_config_db#(uvm_sequence_base)::set(this,"agent.seqr.main_seq","default_sequence",seq1_h); 3330 3331 /*fourth argument(handle) => provide sequence handle as last argument remaining all three are same as above*/ 3332 /* if we are using default sequence then no need to write code for run_phase in test run_phase 3333 //just set default sequence in start_of_simulation_phase or end_of_elaboration_phase */ 3334 3335 class test extends uvm_test; 3336 3337 function void start_of_simulation_phase(uvm_phase phase) 3338 uvm_top.print_topology(); 3339 uvm_config_db#(uvm_object_wrapper)::set(this,"agent.seqr.run_phase","default_sequence",wr_seq::get_type()); 3340 endfunction 3341 3342 /*task run_phase(uvm_phase phase); 3343 3344 wr_seq wseq=create("wseq"); 3345 phase.raise_objection(this); 3346 wseq.start(env.wagt.seqr); 3347 phase.drop_objection(this); 3348 3349 endtask : run_phase 3350 3351 here test is not raising any objection so run_phase will immediately get ended so in that case sequence itself 3352 raise and drop the objection*/ 3353 3354 endclass : test 3355 class wr_seq extends uvm_sequence#(write_xtn); 3356 /* uvm_sequencer_base m_sequencer; */ 3357 3358 `uvm_object_utils(wr_seq) 3359 3360 function new (string "name"); 3361 3362 endfunction 3363 3364 task body(); 3365 3366 if(starting_phase!=null) 3367 starting_phase.raise_objection(this); 3368 3369 repeat(10) 3370 begin 3371 req=write_xtn::type_id::create("req"); 3372 start_item(req); 3373 assert(req.randomize()); 3374 finish_item(req); 3375 end 3376 3377 if(starting_phase!=null) 3378 starting_phase.drop_objection(this); 3379 endtask 3380 3381 endclass 3382 3383 /* 1. phases is defined inside uvm_component but sequence is an object so here we can not get the phase so to 3384 raise and drop a objection we use here starting_phase... 3385 2. when we set a default sequence then this starting_phase will get a value which is phase we provided during 3386 setting the default sequence.. 3387 3. May be we start sequence in sub_run_phases so here instead of checking the starting_phase value with any 3388 phases like run_phase or any sub_run_phases we check it with null ...means if sequence is running in any phase 3389 then it should raise and drop objection.. 3390 4. if we are starting the sequence in test using start method at that time starting_phase will get the null 3391 value and then sequence will not raise and drop the objection , test will only raise and drop the 3392 objections... 3393 5. Using default sequence is not recommended because like we set two, three default sequence we can't predict 3394 the order of execution of sequences...*/ 3395 3396 endclass 3397 3398 ------------------------------------------------===================----------------------------------------------- 3399 //===============================================SEQUENCE LIABRARY================================================ 3400 ------------------------------------------------===================----------------------------------------------- 3401 class 3402 /*1. It is used when we have multiple test cases and multiple sequences and suppose we can to check all the 3403 sequences so it that case we make sequence liabrary all start that liabrary. 3404 2. We pick sequences as per arbitration mechanism.. 3405 3. It is not recommended because we are not sure wether all sequences started or not in liabrary... 3406 */ 3407 3408 class my_seq_lib extends uvm_sequence_library#(write_xtn); 3409 `uvm_object_utils(my_seq_lib) 3410 `uvm_sequence_library_utils(my_seq_lib) 3411 function new(string name="") 3412 super.new(name); 3413 init_sequence_library(); 3414 endfunction 3415 endclass 3416 3417 //Using `uvm_add_to_seq_lib Macro we can add seq to liabrary 3418 3419 my_seq_lib 3420 class seq1 extends uvm_sequence#(write_xtn); ========================= 3421 `uvm_object_utils(seq1) | seq1 | 3422 `uvm_add_to_seq_lib(seq1,my_seq_lib) | | 3423 endclass | seq2 | 3424 | | 3425 class seq2 extends uvm_sequence#(write_xtn); | seq3 | 3426 `uvm_object_utils(seq2) | , | 3427 `uvm_add_to_seq_lib(seq2,my_seq_lib) | , | 3428 endclass | , | 3429 | , | 3430 class seq2 extends uvm_sequence#(write_xtn); | , | 3431 `uvm_object_utils(seq2) | seqN | 3432 `uvm_add_to_seq_lib(seq2,my_seq_lib) ========================= 3433 endclass 3434 3435 //if we don't want to use macro inside sequences then We can ADD SEQUENCE to liabrary by using method 3436 add_typewide_sequences(); also 3437 3438 class my_seq_lib extends uvm_sequence_library#(write_xtn); 3439 `uvm_object_utils(my_seq_lib) 3440 `uvm_sequence_library_utils(my_seq_lib) 3441 function new(string name="") 3442 super.new(name); 3443 3444 add_typewide_sequences( { 3445 seq1::get_type(), 3446 seq2::get_type(), 3447 seq3::get_type() 3448 } 3449 ); 3450 init_sequence_library(); 3451 endfunction 3452 endclass 3453 3454 3455 //SEQUENCE LIABRARY MODES ==> In which manner we want to start our sequences 3456 ----------------------------- 3457 /* 3458 typedef enum 3459 {UVM_SEQ_LIB_RAND, ---> Random sequence selection 3460 UVM_SEQ_LIB_RANDC, ---> Random cyclic sequence selection 3461 UVM_SEQ_LIB_ITEM, ---> Emit only items, no sequence execution 3462 UVM_SEQ_LIB_USER, ---> User defined random selection algorithm 3463 } uvm_sequence_lib_mode; 3464 3465 /*UVM_SEQ_LIB_ITEM,---> Emit only items, no sequence execution(liabrary itself behave like sequence and 3466 generate transaction and give it to the driver)*/ 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 class test extends uvm_test; 3485 3486 task run_phase(); 3487 3488 phase.raise_objection(this); 3489 3490 my_seq_lib seq_lib=my_seq_lib::type_id::create("seq_lib"); 3491 seq_lib.min_random_count=5; //min no of sequence that can be picked from library 3492 seq_lib.max_random_count=15; //max no of sequence that can be picked from library 3493 seq_lib.selection_mode=UVM_SEQ_LIB_RANDC; 3494 //seq_lib.add_sequence(err_seq::get_type()); //if we want to add some more sequences we can add here 3495 3496 assert(seq_lib.randomize()); 3497 seq_lib.start(envh.agth.seqr); 3498 3499 phase.drop_objection(this); 3500 endtask 3501 endclass 3502 3503 //By default library can start 10 sequences 3504 endclass 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 ---------------------------------------=======================================------------------------------------ 3528 //======================================SETTING THE DEFAULT SEQUENCE LIABRARY===================================== 3529 ---------------------------------------=======================================------------------------------------ 3530 class 3531 3532 //1. Using WRAPPER 3533 ------------------- 3534 3535 uvm_config_db#(uvm_object_wrapper)::set(null,"agent.seqr.run_phase","default_sequence",my_seq_lib::get_type()); 3536 3537 uvm_config_db#(uvm_sequence_lib_mode)::set(null,"agent.seqr.run_phase","default_sequence.selection_mode",UVM_SEQ_LIB 3538 _RANDC); 3539 3540 3541 //2. Using INSTANCE 3542 -------------------- 3543 3544 my_seq_lib seq_lib_h=my_seq_lib::type_id::create("seq_lib_h"); 3545 seq_lib_h.min_random_count=5; 3546 seq_lib_h.max_random_count=15; 3547 seq_lib_h.selection_mode=UVM_SEQ_LIB_RANDC; 3548 seq_lib_h.add_sequence(err_seq::get_type()); 3549 3550 void'(seq_lib.randomize()); 3551 3552 uvm_config_db#(uvm_sequence_base)::set(null,"agent.seqr.run_phase","default_sequence",seq_lib_h); 3553 3554 endclass 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 -----------------------------------------------======================--------------------------------------------- 3571 //==============================================SEQUENCE ARBITRATION============================================== 3572 -----------------------------------------------======================--------------------------------------------- 3573 class 3574 /* 3575 /*it comes in picture When we run multiple sequences in same sequencer within fork join 3576 3577 at the same time all sequences can not give the data to driver 3578 3579 Based on the arbitration ,priority sequencer will select sequences 3580 3581 */ 3582 task test::run_phase(phase) 3583 3584 `uvm_info(get_type_name,$sformatf("The current arbitration set is %s",envh.agth.seqr.get_arbitration()),UVM_MEDIUM) 3585 3586 phase.raise_objection(this); 3587 fork 3588 seq1.start(envh.agth.seqr,,100); 3589 seq2.start(envh.agth.seqr,,200); 3590 seq3.start(envh.agth.seqr,,300); 3591 seq4.start(envh.agth.seqr,,400); 3592 join 3593 phase.drop_objection(this); 3594 endtask 3595 3596 3597 //ARBITRATION SCHEMES 3598 ---------------------- 3599 SEQ_ARB_FIFO ---> Request are granted in FIFO order(DEFAULT ARBITRATION) 3600 SEQ_ARB_WEIGHTED ---> Request are granted randomly by weight 3601 SEQ_ARB_RANDOM ---> Request are granted randomly 3602 SEQ_ARB_STRICT_FIFO ---> Request at highest priority granted in FIFO order 3603 SEQ_ARB_STRICT_RANDOM ---> Request at highest priority granted randomly 3604 SEQ_ARB_USER ---> User defined arbitration 3605 3606 //function void set arbitration(SEQ_ARB_TYPE val="SEQ_ARB_FIFO"); 3607 3608 virtual task start(uvm_sequencer_base sequencer, 3609 uvm_sequence_base parent_sequence=null, 3610 integer this_priority=100, 3611 bit call_pre_post=1); 3612 endtask 3613 . 3614 //function void set_priority(int value); 3615 3616 all the request which are waiting for the grant will be stored in a fifo 3617 FIFO 3618 ================================== 3619 || seq1 || seq2 || seq3 || seq4 || 3620 || || || || || 3621 ================================== 3622 3623 / 3624 SEQ_ARB_FIFO : (Default if none specified). If this arbitration mode is specified, then the sequencer 3625 picks sequence items in a FIFO order from all sequences running on the sequencer. 3626 3627 Example: if seq1, seq2 ,seq3 and seq4 are running on a sequencer, it will pick an item from seq1 3628 first,followed by seq2, seq3 and then seq4 if available, and continue. 3629 3630 SEQ_ARB_WEIGHTED: If this arbitration mode is selected, sequence items from the highest priority sequence 3631 are always picked first until none available, then the sequence items from next priority 3632 sequence, and so on. If two sequences have equal priority, then the items from them are 3633 picked in a random order. 3634 3635 SEQ_ARB_RANDOM: If this arbitration mode is selected, sequence items from different sequences are picked 3636 in a random order by ignoring all priorities. 3637 3638 SEQ_ARB_STRICT_FIFO: This is similar to SEQ_ARB_WEIGHTED except that if two sequences have the same priority, 3639 then the items from those sequences are picked in a FIFO order rather than in a random 3640 order. 3641 3642 SEQ_ARB_STRICT_RANDOM: This is similar to SEQ_ARB_RANDOM except that the priorities are NOT ignored. The items 3643 are picked randomly from sequences with highest priority first followed by next and in that 3644 order. 3645 3646 SEQ_ARB_USER: This algorithm allows a user to define a custom algorithm for arbitration between 3647 sequences. This is done by extending the uvm_sequencer class and overriding the 3648 user_priority_arbitration() method. 3649 3650 3651 3652 3653 3654 3655 3656 ***************************************************************************************************************//=== 3657 ==================================Lock & GRAB METHODS===================================================== 3658 /* 3659 1. If sequencer is doing some sequence and based on some external events if user wants sequencer to pause the 3660 current sequence, he/she can grab/lock sequencer and start another sequence. Once the started sequence finishes 3661 sequencer can resume the normal operation, upon ungrab/unlock. 3662 2. This mechanism is generally used to mimic CPU behavior, where CPU is doing a normal bus operation and when 3663 interrupt comes, CPU needs to suspend the normal operation and start interrupt handling. Once interrupt handling 3664 is over, CPU should resume the normal operation from where it was suspended 3665 */ 3666 //SEQUENCE1 3667 ------------ 3668 class sequence1 extends uvm_sequence#(write_xtn); 3669 //uvm_sequencer_base m_sequencer; 3670 `uvm_object_utils(sequence1) 3671 function new (string "name"); 3672 3673 endfunction 3674 3675 task body(); 3676 3677 m_sequencer.lock(this); 3678 3679 req=write_xtn::type_id::create("req"); 3680 3681 start_item(req); 3682 assert(req.randomize()with{a==10;}); 3683 `uvm_info("SEQUENCE1",$sformatf("a=%d",req.a),UVM_MEDIUM); 3684 finish_item(req); 3685 3686 start_item(req); 3687 assert(req.randomize()with {a==15;}); 3688 `uvm_info("SEQUENCE1",$sformatf("a=%d",req.a),UVM_MEDIUM); 3689 finish_item(req); 3690 3691 m_sequencer.unlock(this); 3692 3693 endtask 3694 3695 endclass 3696 3697 3698 3699 //SEQUENCE2 3700 ------------ 3701 class sequence2 extends uvm_sequence#(write_xtn); 3702 //uvm_sequencer_base m_sequencer; 3703 `uvm_object_utils(sequence2) 3704 function new (string "name"); 3705 3706 endfunction 3707 3708 task body(); 3709 3710 m_sequencer.grab(this); 3711 req=write_xtn::type_id::create("req"); 3712 3713 start_item(req); 3714 assert(req.randomize()with{a==20;}); 3715 `uvm_info("SEQUENCE1",$sformatf("a=%d",req.a),UVM_MEDIUM); 3716 finish_item(req); 3717 3718 m_sequencer.ungrab(this); 3719 3720 endtask 3721 endclass 3722 3723 //SEQUENCE3 3724 ------------ 3725 class sequence3 extends uvm_sequence#(write_xtn); 3726 //uvm_sequencer_base m_sequencer; 3727 `uvm_object_utils(sequence3) 3728 function new (string "name"); 3729 3730 endfunction 3731 3732 task body(); 3733 req=write_xtn::type_id::create("req"); 3734 3735 start_item(req); 3736 assert(req.randomize()with{a==30;}); 3737 `uvm_info("SEQUENCE1",$sformatf("a=%d",req.a),UVM_MEDIUM); 3738 finish_item(req); 3739 3740 endtask 3741 endclass 3742 //TEST 3743 ------- 3744 class test extends uvm_test; 3745 task run_phase(uvm_phase phase); 3746 sequence1 seq1; 3747 sequence2 seq2; 3748 sequence3 seq3; 3749 seq1=sequence1::type_id::create("seq1"); 3750 seq2=sequence2::type_id::create("seq2"); 3751 seq3=sequence3::type_id::create("seq3"); 3752 phase.raise_objection(this); 3753 fork 3754 seq1.start(envh.agth.seqr); 3755 begin 3756 wait(e.triggered); 3757 seq2.start(envh.agth.seqr); 3758 end 3759 seq3.start(envh.agth.seqr); 3760 join 3761 phase.drop_objection(this); 3762 endtask 3763 endclass 3764 3765 //TOP MODULE 3766 ------------- 3767 module top; 3768 3769 initial 3770 begin 3771 #20; 3772 ->e; 3773 end 3774 3775 endmodule 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 //without using lock and grab (driver taking 100 time to complete the drive) 3786 ---------------------------------------------------------------------------- 3787 FIFO 3788 3789 ============== 3790 || || 3791 0 time <--- || seq1 || order of execution 3792 || a==10 || 1. seq1 with a==10 3793 ============== 2. seq3 3794 || || 3. seq2 3795 0 time <--- || seq3 || 4. seq1 with a==15 3796 || || 3797 ============== 3798 || || 3799 20 time <--- || seq2 || #20 event triggered in top module 3800 || || 3801 ============== 3802 || || 3803 100 time <--- || seq1 || 3804 || a==15 || 3805 ============== 3806 3807 //with lock method only (driver taking 100 time to complete the drive) 3808 ---------------------------------------------------------------------- 3809 FIFO 3810 3811 ============== 3812 || || 3813 0 time <--- || seq1 || order of execution 3814 || a==10 || 1. seq1 with a==10 3815 ============== 2. seq1 with a==15 3816 || || 3. seq3 3817 0 time <--- || seq3 || 4. seq2 3818 || || 3819 ============== 3820 || || 3821 20 time <--- || seq2 || #20 event triggered in top module 3822 || || 3823 ============== 3824 || || 3825 100 time <--- || seq1 || 3826 || a==15 || 3827 ============== 3828 //with lock and grab methods (driver taking 100 time to complete the drive) 3829 --------------------------------------------------------------------------- 3830 FIFO 3831 3832 ============== 3833 || || 3834 0 time <--- || seq1 || order of execution 3835 || a==10 || 1. seq1 with a==10 3836 ============== 2. seq1 with a==15 3837 || || 3. seq2 3838 0 time <--- || seq3 || 4. seq3 3839 || || 3840 ============== 3841 || || 3842 20 time <--- || seq2 || #20 event triggered in top module 3843 || || 3844 ============== 3845 || || 3846 100 time <--- || seq1 || 3847 || a==15 || 3848 ============== 3849 3850 //with grab method only (driver taking 100 time to complete the drive) 3851 ---------------------------------------------------------------------- 3852 FIFO 3853 3854 ============== 3855 || || 3856 0 time <--- || seq1 || order of execution 3857 || a==10 || 1. seq1 with a==10 3858 ============== 2. seq2 3859 || || 3. seq3 3860 0 time <--- || seq3 || 4. seq1 with a==15 3861 || || 3862 ============== 3863 || || 3864 20 time <--- || seq2 || #20 event triggered in top module 3865 || || 3866 ============== 3867 || || 3868 100 time <--- || seq1 || 3869 || a==15 || 3870 ============== 3871 //Lock() 3872 3873 1) A lock() request is put in back of the arbitration queue . A lock request will be arbitrated the same as any 3874 other request. 3875 2) A lock is granted after all earlier requests are completed and no other locks or grabs are blocking this 3876 sequence. 3877 3) A lock() is blocking task and when access is granted, it will unblock. 3878 4) If no argument is supplied, then current default sequencer is chosen. 3879 3880 //Grab() 3881 3882 1) A grab() request is put in front of the arbitration queue. A grab() request will be arbitrated before any other 3883 requests. 3884 2) A grab() is granted when no other grabs or locks are blocking this sequence. (The only thing that stops a 3885 sequence from grabbing a sequencer is a pre-existing lock() or grab() condition.) 3886 3) A grab() is blocking task and when access is granted, it will unblock. 3887 4) If no argument is supplied, then current default sequencer is chosen. 3888 3889 //Unlock() 3890 3891 The unlock sequencer function is called from within a sequence to give up its lock or grab. A locking sequence must 3892 call unlock before completion; otherwise the sequencer will remain locked. 3893 3894 //Ungrab() 3895 An alias of function unlock(). 3896 */ 3897 endclass 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 -------------------------------------------==============================----------------------------------------- 3915 //==========================================VIRTUAL SEQUENCE & SEQUENCER========================================== 3916 -------------------------------------------==============================----------------------------------------- 3917 class 3918 /* 3919 1. sequence is parametrized by user defined transaction but virtual sequence is parametrized by uvm_sequence_item. 3920 2. sequences which is parametrizedby user define transaction class are called subsequences or physical sequences. 3921 3922 3923 suppose we have three sequences reset,configure,main sequence . 3924 we will start all sequences in test class in order 3925 it is ok if we have single agent.*/ 3926 3927 //RESET_SEQ 3928 ------------ 3929 3930 class reset_seq extends uvm_sequence; 3931 task body; 3932 begin 3933 req=reset_seq::type_id::create("reset_seq"); 3934 start_item(req); 3935 req.randomize() with{}; 3936 finish_item(req); 3937 end 3938 endtask 3939 endclass 3940 3941 //CONFIG_SEQ 3942 ------------- 3943 3944 class config_seq extends uvm_sequence; 3945 task body; 3946 begin 3947 req=config_seq::type_id::create("config_seq"); 3948 start_item(req); 3949 req.randomize() with{}; 3950 finish_item(req); 3951 end 3952 endtask 3953 endclass 3954 3955 3956 3957 //MAIN_SEQ 3958 ----------- 3959 3960 class main_seq extends uvm_sequence; 3961 task body; 3962 begin 3963 req=main_seq::type_id::create("main_seq"); 3964 start_item(req); 3965 req.randomize() with{}; 3966 finish_item(req); 3967 end 3968 endtask 3969 endclass 3970 3971 //TEST 3972 ------- 3973 3974 class test extends uvm_test; 3975 3976 task run_phase(uvm_phase phase); 3977 reset_seq rseq=create("rseq"); 3978 config_seq cseq=create("cseq"); 3979 main_seq mseq=create("mseq"); 3980 3981 phase.raise_objection(this); 3982 begin 3983 rseq.start(envh.agt.seqr); 3984 cseq.start(envh.agt.seqr); 3985 mseq.start(envh.agt.seqr); 3986 end 3987 phase.drop_objection(this); 3988 3989 endtask 3990 endclass 3991 3992 3993 /*Suppose we have multiple agents and multiple sequences 3994 3995 1. read_agent 3996 2. write_agent 3997 3998 reset_wr_seq,odd_wr_seq,even_wr_seq,rndm_wr_seq 3999 reset_rd_seq,odd_rd_seq,even_rd_seq,rndm_rd_seq 4000 //FOR RESET DUT 4001 ----------------- 4002 4003 test1 4004 fork 4005 wrst.start(envh.wr_agt.seqr); 4006 rrst.start(envh.rd_agt.seqr); 4007 join 4008 4009 //FOR ODD WRITE READ DUT 4010 ------------------------- 4011 4012 test2 4013 fork 4014 wrst.start(envh.wr_agt.seqr); 4015 rrst.start(envh.rd_agt.seqr); 4016 join 4017 o_wseq.start(envh.wr_agt.seqr); 4018 o_rseq.start(envh.rd_agt.seqr); 4019 4020 //FOR EVEN WRITE READ DUT 4021 -------------------------- 4022 4023 test3 4024 fork 4025 wrst.start(envh.wr_agt.seqr); 4026 rrst.start(envh.rd_agt.seqr); 4027 join 4028 e_wseq.start(envh.wr_agt.seqr); 4029 e_rseq.start(envh.rd_agt.seqr); 4030 4031 //FOR ODD , EVEN WRITE READ DUT 4032 --------------------------------- 4033 4034 test4 4035 fork 4036 wrst.start(envh.wr_agt.seqr); 4037 rrst.start(envh.rd_agt.seqr); 4038 join 4039 o_wseq.start(envh.wr_agt.seqr); 4040 o_rseq.start(envh.rd_agt.seqr); 4041 e_wseq.start(envh.wr_agt.seqr); 4042 e_rseq.start(envh.rd_agt.seqr); 4043 IF we see here reset sequence is starting again and again 4044 So test in becoming too lengthy 4045 as agent get increased complexity and length of code become huge. 4046 4047 Instead of writing again nd again we make virtual sequence 4048 and declare all sequence handles and declare sequencer handles 4049 4050 class virtual_sequence extends uvm_sequence#(uvm_sequence_item); 4051 `uvm_object_utils(virtual_sequence) 4052 4053 reset_wr_seq wrst; 4054 odd_wr_seq o_wseq; 4055 even_wr_seq e_wseq; 4056 rndm_wr_seq rn_wseq; 4057 4058 reset_rd_seq rrsr; 4059 odd_rd_seq o_rseq; 4060 even_rd_seq e_rseq; 4061 rndm_rd_seq rn_rseq; 4062 4063 wr_sequencer wr_seqr; 4064 rd_sequencer rd_seqr; 4065 4066 endclass 4067 4068 /*1. Now we will declare reset virtual sequence class extended from virtual_sequence 4069 2.create reset sequence and start*/ 4070 //likewise we will create for all odd,even,random 4071 4072 //RESET_VSEQ 4073 -------------- 4074 class reset_vseq extends virtual_sequence; 4075 4076 task body(); 4077 wrst = create("wrst"); 4078 rrst = create("rrst"); 4079 4080 fork 4081 wrst.start(wr_seqr); 4082 rrst.start(rd_seqr); 4083 join 4084 endtask 4085 endclass 4086 //for odd_sequence 4087 -------------------- 4088 4089 class odd_vseq extends virtual_sequence; 4090 4091 task body(); 4092 o_wseq = create("o_wseq"); 4093 o_rseq = create("o_rseq"); 4094 4095 fork 4096 o_wseq.start(wr_seqr); 4097 o_rseq.start(rd_seqr); 4098 join 4099 endtask 4100 endclass 4101 4102 //for even_sequence 4103 --------------------- 4104 4105 class even_vseq extends virtual_sequence; 4106 4107 task body(); 4108 e_wseq = create("e_wseq"); 4109 e_rseq = create("e_rseq"); 4110 4111 fork 4112 e_wseq.start(wr_seqr); 4113 e_rseq.start(rd_seqr); 4114 join 4115 endtask 4116 endclass 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 //for random_sequence 4130 ---------------------- 4131 4132 class rand_vseq extends virtual_sequence; 4133 4134 task body(); 4135 rn_wseq = create("rn_wseq"); 4136 rn_rseq = create("rn_rseq"); 4137 4138 fork 4139 rn_wseq.start(wr_seqr); 4140 rn_rseq.start(rd_seqr); 4141 join 4142 endtask 4143 endclass 4144 4145 //Inside test we will create virtual sequences and start 4146 4147 //TEST 4148 -------- 4149 4150 class test extends uvm_test; 4151 4152 task run_phase(uvm_phase phase); 4153 4154 reset_vseq r_vseq=reset_vseq::type_id::create("r_vseq"); 4155 //odd_vseq o_vseq=odd_vseq::type_id::create("o_vseq"); 4156 //even_vseq e_vseq=even_vseq::type_id::create("e_vseq"); 4157 //rand_vseq rn_vseq=rand_vseq::type_id::create("rn_vseq"); 4158 4159 phase.raise_objection(this); 4160 begin 4161 4162 r_vseq.start(null); 4163 //o_vseq.start(null); 4164 //e_vseq.start(null); 4165 //rn_vseq.start(null); 4166 4167 end 4168 phase.drop_objection(this); 4169 4170 endtask 4171 endclass 4172 =============================================== 4173 //========STAND ALONE VIRTUAL SEQUENCE========= 4174 =============================================== 4175 /* 4176 1. A stand alone virtual sequence contains handles for the sequencers on which its sub-sequences will run 4177 4178 2. It relies on the test case to create it and then assign the handles to the sub-sequencers 4179 4180 3. The sequence is started using the sequence start method, but passing a null as the sequencer argument 4181 */ 4182 4183 class virtual_sequence extends uvm_sequence#(uvm_sequence_item); 4184 `uvm_object_utils(virtual_sequence) 4185 4186 wr_sequence wseq; 4187 rd_sequence rseq; 4188 4189 wr_sequencer wr_seqr; 4190 rd_sequencer rd_seqr; 4191 4192 task body(); 4193 4194 wseq=wr_sequence::type_id::create("wseq"); 4195 rseq=rd_sequence::type_id::create("rseq"); 4196 4197 wseq.start(wr_seqr); 4198 rseq.start(rd_seqr); 4199 4200 endtask 4201 endclass 4202 4203 class test extends uvm_test; 4204 `uvm_component_utils(test) 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 //constructor 4216 4217 virtual_sequence vseq; 4218 4219 task run_phase(uvm_phase phase); 4220 4221 phase.raise_objection(this); 4222 4223 vseq=virtual_sequence::type_id::create(vseq); 4224 4225 vseq.wr_seqr=envh.wr_agt.seqr; //assign sequencer which is inside agent to sequencer handles 4226 vseq.rd_seqr=envh.rd_agt.seqr; //which is inside virtual sequences 4227 4228 vseq.start(null); 4229 4230 phase.drop_objection(this); 4231 4232 endtask 4233 4234 endclass 4235 4236 *************************************************************************************** 4237 //Q. Why we are passing null in virtual sequence start method. 4238 /a sequence should be start on a sequencer parametrized by same transaction object. 4239 eg. rd_sequence#(read_xtn) -> rd_sequencer#(read_xtn) 4240 here virtual_sequence is parametrized by uvm_sequence_item 4241 but we don't have sequencer which is parametrized by uvm_sequence_item 4242 that is why we pass null as an argument.*/ 4243 **************************************************************************************** 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 =============================================== 4259 //=============VIRTUAL SEQUENCER=============== 4260 Virtual sequencer is used in the stimulus generation process to allow a single sequence to control activity via 4261 several agents 4262 4263 1. It is not attached to any driver 4264 2. Does not process items itself 4265 3. Has reference to multiple sequencer in an agent env 4266 4267 Virtual sequence invokes sequences only on virtual sequencer 4268 If we have virtual sequencer then we should have virtual sequence 4269 but Virtual sequence can we use with or without virtual sequencer(standalone virtual sequences) 4270 4271 class virtual_sequencer extends uvm_sequencer#(uvm_sequence_item); 4272 `uvm_component_utils(virtual_sequencer) 4273 4274 wr_sequencer wr_seqr; 4275 rd_sequencer rd_seqr; 4276 function new(string name="virtual_sequencer",uvm_component parent=null); 4277 super.new(name,parent); 4278 endfunction 4279 endclass 4280 4281 //SUB-SEQUENCER CONNECTION 4282 ---------------------------- 4283 class ram_tb extends uvm_env; 4284 //factory registration 4285 //agents handles 4286 virtual_sequencer v_seqr; 4287 //constructor 4288 4289 function void build_phase(uvm_phase phase); 4290 super.build_phase(phase); 4291 //build all agents 4292 v_seqr=virtual_sequencer::type_id::create("v_seqr",this); 4293 endfunction 4294 //connect virtual_sequencer to sub-sequencers 4295 function void connect_phase(uvm_phase phase); 4296 v_seqr.wr_seqr=wr_agt_top.wr_agt.seqr; 4297 v_seqr.rd_seqr=rd_agt_top.rd_agt.seqr; 4298 endfunction 4299 endclass 4300 //VIRTUAL SEQUENCE BASE CLASS 4301 ------------------------------- 4302 4303 class virtual_sequence_base extends uvm_sequence#(uvm_sequence_item); 4304 `uvm_object_utils(virtual_sequence_base) 4305 4306 virtual_sequencer v_seqr; 4307 4308 wr_sequencer wr_seqr_h; 4309 rd_sequencer rd_seqr_h; 4310 4311 function new(string name="virtual_sequence_base"); 4312 super.new(name); 4313 endfunction 4314 4315 task body(); 4316 if(!$cast(v_seqr,m_sequencer)) 4317 begin 4318 `uvm_error(get_full_name(),"virtual_sequencer pointer cast failed"); 4319 end 4320 4321 wr_seqr_h=v_seqr.wr_seqr; 4322 rd_seqr_h=v_seqr.rd_seqr; 4323 4324 endtask 4325 4326 endclass 4327 4328 //VIRTUAL SEQUENCE 4329 -------------------- 4330 4331 class virtual_sequence extends uvm_sequence#(uvm_sequence_item); 4332 `uvm_object_utils(virtual_sequence) 4333 4334 wr_sequence wseq; 4335 rd_sequence rseq; 4336 4337 task body(); 4338 super.body; 4339 4340 wseq=wr_sequence::type_id::create("wseq"); 4341 rseq=rd_sequence::type_id::create("rseq"); 4342 4343 repeat(20) 4344 begin 4345 wseq.start(wr_seqr_h); 4346 rseq.start(rd_seqr_h); 4347 end 4348 endtask 4349 endclass 4350 4351 //TEST 4352 -------- 4353 4354 class test extends uvm_test; 4355 `uvm_component_utils(test) 4356 4357 //constructor 4358 4359 virtual_sequence vseq; 4360 4361 task run_phase(uvm_phase phase); 4362 4363 vseq=virtual_sequence::type_id::create(vseq); 4364 4365 phase.raise_objection(this); 4366 4367 vseq.start(envh.v_seqr); 4368 4369 phase.drop_objection(this); 4370 4371 endtask 4372 endclass 4373 4374 4375 endclass 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 -------------------------------------------------==================----------------------------------------------- 4387 //===============================================CALLBACKs & EVENTS=============================================== 4388 -------------------------------------------------==================----------------------------------------------- 4389 class 4390 4391 class //CALLBACK 4392 4393 ---> To add the additional functionality to a component without changing its behavior 4394 ---> without changing component type_id(overriding) 4395 ---> eg. injecting the errors, droping the transaction 4396 4397 1. In below driver lets suppose we want to give some additional delay after driving a packet or before driving 4398 next packet 4399 2. But i don't want to override the driver we want to use same driver in agents 4400 4401 class driver extends uvm_driver; 4402 `uvm_component_utils(driver) 4403 4404 function new(string name,uvm_component parent=null); 4405 super.new(name,parent); 4406 endfunction 4407 4408 virtual task run_phase(uvm_phase phase); 4409 phase.raise_objection(this); 4410 repeat(2) 4411 begin 4412 $display("driver: starting driver the packet ......%d",$time); 4413 //logic to drive the packet goes here//let's consider that it takes 40 time units to drive the 4414 packet 4415 #40; 4416 $display("driver: Finished driving the packet ....%d",$time); 4417 4418 end 4419 phase.drop_objection(this); 4420 endtask 4421 4422 endclass 4423 4424 4425 4426 4427 4428 4429 //CALLBACK CLASS 4430 ================= 4431 4432 TO Add additional functionality we use callback .class 4433 Testbench developer write this callback_class 4434 4435 //DRIVER_CALLBACK 4436 ================== 4437 4438 class driver_callback extends uvm_callback; 4439 4440 function new(string name ="driver_callback"); 4441 super.new(name); 4442 endfunction 4443 4444 static string type_name="driver_callback"; 4445 4446 virtual function string get_type_name(); 4447 return type_name; 4448 endfunction 4449 4450 virtual task pre_send(); //user_defined methods empty task 4451 endtask 4452 4453 virtual task post_send(); //we can give any name 4454 endtask 4455 4456 endclass 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 //EXAMPLE TO DESCRIBE CALLBACK 4473 =============================== 4474 4475 class driver extends uvm_driver; 4476 `uvm_component_utils(driver) 4477 `uvm_register_cb(driver,driver_callback) //macro to register callback class, it should be added 4478 function new(string name,uvm_component parent=null); 4479 super.new(name,parent); 4480 endfunction 4481 4482 virtual task run_phase(uvm_phase phase); 4483 phase.raise_objection(this); 4484 repeat(2) 4485 begin 4486 `uvm_do_callbacks(driver,driver_callback,pre_send()); 4487 $display("driver: starting driver the packet ......%d",$time); 4488 //logic to drive the packet goes here//let's consider that it takes 40 time units to drive the 4489 packet 4490 #40; 4491 $display("driver: Finished driving the packet ....%d",$time); 4492 `uvm_do_callbacks(driver,driver_callback,post_send()); 4493 end 4494 phase.drop_objection(this); 4495 endtask 4496 4497 endclass 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 //CUSTOM_DRIVER_CALLBACK 4516 ========================= 4517 4518 1. Test .case writer can define another cal back ,.class by extending from driver_callback .class 4519 4520 2. And he can override the pre/post send depending on requirement 4521 4522 class custom_driver_callback_1 extends driver_callback; 4523 4524 function new(string name ="custom_driver_callback_1"); 4525 super.new(name); 4526 endfunction 4527 4528 virtual function string get_type_name(); 4529 return type_name; 4530 endfunction 4531 4532 //Override the pre_send of driver_callback method 4533 4534 virtual task pre_send(); 4535 $display("CB_1:PRE_SEND:DELAY THE PACKET DRIVING BY 20 TIME UNITS %d",$time); 4536 #20; 4537 endtask 4538 4539 //Override the pre_send of driver_callback method 4540 4541 virtual task post_send(); 4542 $display("CB_1:POST_SEND:JUST A MESSAGE FROM POST_SEND CALLBACK METHOD\n"); 4543 endtask 4544 4545 endclass 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 If we want this new scenario in perticular testcase so, in end_of_elaboration_phase or in start_of_simulation_phase 4559 od that testcase we will add below logic 4560 4561 function void end_of_elaboration_phase(uvm_phase phase); 4562 super.end_of_elaboration_phase(phase); 4563 4564 custom_driver_callback_1 cb_1; 4565 cb_1=new("cb_1"); 4566 4567 uvm_callback#(driver,driver_callback)::add(envh.agth.drv,cb_1); //by default pre/post send method 4568 is inactive by doing add we can 4569 make them active 4570 uvm_callback#(driver,driver_callback)::display; //this display function display in which class 4571 //this call back is on 4572 4573 endfunction 4574 4575 //MODULE 4576 ========== 4577 4578 module test; 4579 4580 initial 4581 begin 4582 driver drvr; 4583 custom_driver_callback_1 cb_1; 4584 4585 drvr=new("drvr"); 4586 cb_1=new("cb_1"); 4587 4588 uvm_callback#(driver,driver_callback)::add(adrv,cb_1); //by default pre/post send method is 4589 //inactive by doing add we can make them active 4590 uvm_callback#(driver,driver_callback)::display; 4591 4592 run_test(); 4593 4594 end 4595 endmodule 4596 endclass 4597 4598 4599 4600 4601 class //EVENTS 4602 4603 //SYSTEM Verilog 4604 4605 wait ---> can catch the event triggered in current simulation time slot and also catch the event triggered in 4606 future simulation time slot 4607 @ ---> can catch the event triggered in future simulation time slot only 4608 4609 //EXAMPLE TO DESCRIBE EVENTS 4610 4611 Lets suppose we want to synchronize driver and monitor using events in UVM 4612 4613 4614 4615 1. Event callbacks like pre_trigger and post_trigger will be called automatically before and after raising the 4616 events 4617 2. Event pool is a singleton_class and can be accessed by multiple components through config_db 4618 3. Singleton_class is a .class for which we can create only one object; 4619 4. We can add any number of events in this event_pool whenever is required 4620 4621 //CONFIG CLASS 4622 =============== 4623 4624 class config_class extends uvm_object; 4625 4626 `uvm_object_utils(config_class) 4627 4628 uvm_active_passive_enum is_active=UVM_ACTIVE; 4629 uvm_event_pool event_pool=uvm_event_pool::get_global_poo(); 4630 4631 function new(string name="config_class"); 4632 super.new(name); 4633 endfunction 4634 4635 endclass 4636 4637 4638 4639 4640 4641 4642 4643 4644 //DRIVER CLASS 4645 =============== 4646 4647 class driver extends uvm_driver#(write_xtn); 4648 4649 config_class cfg; 4650 4651 task build_phase(uvm_phase phase); 4652 4653 if(!uvm_config_db#(config_class)::get(this,"","config_class",cfg)); 4654 `uvm_fatal("DRIVER","Can not get config data") 4655 4656 endtask 4657 4658 task run_phase(uvm_phase phase); 4659 4660 uvm_event e1=cfg.event_pool.get("e1"); //Registering event e1 in event_pool which is in config class 4661 uvm_event e2=cfg.event_pool.get("e2"); 4662 4663 e2.add_callback(eve_cb,0); //Register the callback object eve_cb with event e2 4664 4665 forever 4666 begin 4667 seq_item_port.get_next_item(req); 4668 drive(req); 4669 seq_item_port.item_done(); 4670 end 4671 4672 e1.trigger(); // Triggering the event e1; 4673 $display("event e1 triggered at time %t in driver ",$time); 4674 #30; 4675 4676 e2.trigger(); 4677 $display("event e2 triggered at time %t in driver",$time); 4678 4679 endtask 4680 4681 endclass 4682 4683 4684 4685 4686 4687 //MONITOR CLASS 4688 4689 class monitor extends uvm_monitor#(write_xtn); 4690 4691 config_class cfg; 4692 4693 task build_phase(uvm_phase phase); 4694 4695 if(!uvm_config_db#(config_class)::get(this,"","config_class",cfg)); 4696 `uvm_fatal("DRIVER","Can not get config data") 4697 4698 endtask 4699 4700 task run_phase(uvm_phase phase); 4701 4702 uvm_event e1=cfg.event_pool.get("e1"); //get method Register event e1 in event_pool which is in config class 4703 uvm_event e2=cfg.event_pool.get("e2"); //if already register then it start refering to that event 4704 // IT will not override 4705 4706 fork 4707 begin 4708 e1.wait_ptrigger(); // wait for Triggering the event e1 in driver; 4709 $display("MONITOR: event e1 triggered at time %t",$time); 4710 end 4711 4712 begin 4713 e2.wait_ptrigger(); // wait for Triggering the event e2 in driver; 4714 $display("MONITOR: event e2 triggered at time %t",$time); 4715 end 4716 join 4717 4718 `uvm_info(get_name(),"PRINTING FROM RUN PHASE OF MONITOR",UVM_LOW) 4719 4720 endtask 4721 4722 endclass 4723 4724 4725 4726 4727 4728 4729 4730 One more thing we can do with events is like suppose we want to do something before event is triggered and want 4731 to do after event triggered 4732 4733 1. Event callbacks like pre_trigger and post_trigger will be called automatically before and after raising the 4734 events 4735 4736 class event_cb extends uvm_event_callback; 4737 `uvm_object_utils(event_cb) 4738 4739 function new(string name="event_cb"); 4740 super.new(name); 4741 endfunction 4742 4743 //These methods are virtual and already defined in uvm_event_callback class 4744 //We just override them in user defined class extended from uvm_event_callback 4745 4746 function bit pre_trigger(uvm_event e,uvm_object data=null); //These methods already in uvm_event_callback 4747 $display("pre_trigger function of event callback object :: Time is %t",$time); 4748 return(0); 4749 endfunction 4750 4751 // This pre_trigger will called before event triggered if it return (0) then event will get triggered then 4752 post_trigger will be called 4753 // if it return (1) then event will not be called 4754 4755 function void post_trigger(uvm_event e,uvm_object data=null);// 4756 $display("post_trigger function of event callback object :: Time is %t",$time); 4757 endfunction 4758 4759 endclass 4760 4761 endclass 4762 4763 4764 4765 4766 4767 4768 4769 4770 4771 4772 4773 ---------------------------------------------------===============------------------------------------------------ 4774 //==================================================TB COMPONENTS================================================= 4775 ---------------------------------------------------===============------------------------------------------------ 4776 class 4777 class //SEQUENCER & DRIVER 4778 4779 class uvm_sequencer#(type REQ=uvm_sequence_item, RSP=REQ) extends uvm_component; 4780 4781 uvm_seq_item_pull_export#(REQ,uvm_sequencer) seq_item_export; 4782 4783 uvm_analysis_imp#(REQ,uvm_sequencer) rsp_export; 4784 4785 REQ req; 4786 RSP rsp; 4787 4788 /*Methods inside uvm_sequencer 4789 //No need to worry about implementation these all are implemented in liabrary 4790 4791 4792 task get_next_item(req); 4793 4794 endtask 4795 4796 task get(); 4797 4798 endtask 4799 4800 task try_next_item(req); 4801 4802 endtask 4803 4804 task item_done(rsp); 4805 4806 endtask 4807 4808 task put_response(rsp); 4809 4810 endtask 4811 4812 task write(rsp); 4813 4814 endtask 4815 */ 4816 4817 endclass 4818 4819 class uvm_driver#(type REQ=uvm_sequence_item, RSP=REQ) extends uvm_component; 4820 4821 uvm_seq_item_pull_port#(REQ) seq_item_port; //---> get,get_next_item,try_next_item,item_done,put_response 4822 4823 uvm_analysis_port#(REQ) rsp_port; //---> write 4824 4825 REQ req; 4826 RSP rsp; 4827 4828 endclass 4829 4830 4831 class driver extends uvm_driver#(write_xtn); //Here we override parameter by write_xtn type so REQ and RSP 4832 //handles become write_xtn type 4833 4834 4835 task run_phase(uvm_phase phase); 4836 forever 4837 begin 4838 seq_item_port.get_next_item(req); 4839 drive(req); 4840 seq_item_port.item_done(); 4841 // seq_item_port.put_response(rsp); 4842 // rsp_port.write(rsp); 4843 end 4844 4845 endtask 4846 4847 task drive(); 4848 //drive the DUT i/ps 4849 4850 //collect DUT o/p only if protocol demands collect OUTPUT_data from DUT 4851 4852 //rsp.data_out=vif.cb.data_out; 4853 4854 endtask 4855 4856 endclass 4857 4858 4859 1. get_next_item(req); 4860 -->when we call call get_next_item then we need to call item_done explicitly to send the 4861 acknowledgment after driving the data to DUT 4862 4863 2. get(req); 4864 -->when we call get then we need not to call item_done 4865 -->it will Automatically call item_done before driver drive the data to DUT 4866 3. try_next_item(); 4867 --> it is same as get_next_item but it is non_blocking type 4868 4869 4. item_done(rsp); 4870 --> It send the acknowledgment to the .sequence 4871 4872 5. put_response(rsp); 4873 --> In some cases after driving the data to DUT , DUT may give some output and whatever the data we are 4874 generating may depends on DUT OUTPUT 4875 --> In this situation we send data_out to the .sequence using rsp handle through put_response(rsp); 4876 --> We have 3 methods to send the response back 4877 1. item_done(rsp) 4878 2. put_response(rsp) 4879 3. rsp_port.write(rsp) 4880 4881 class wr_sequencer extends uvm_sequencer#(write_xtn); 4882 // factory registration 4883 4884 //define constructor 4885 4886 endclass 4887 4888 //UVM_DRIVER 4889 -------->> It is non virtual_class in liabrary 4890 4891 //UVM_SEQUENCER 4892 -------->> It is non virtual_class in liabrary 4893 --> All the methods already implemented in uvm_sequencer .class 4894 --> we just extends and no need to write anything in user defined sequencer 4895 --> we can directly use uvm_sequencer in the agent_class and declare handle and create object and use it 4896 4897 4898 endclass 4899 4900 4901 4902 class //MONITOR 4903 4904 4905 4906 4907 endclass 4908 4909 4910