Uvm Code Examples

You might also like

Download as pdf or txt
Download as pdf or txt
You are on page 1of 115

1 ===================================================================================================================

2 //================================================QUESTION & ANSWERS===============================================


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

You might also like