You might have read the neat article posted by Wei-Hua about the class factory in this forum. You may wonder what could be the best way to code this in an implicitly-phased environment. In this article I will be discussing how transactions based on vmm_data can be made factory enabled using VMM-1.2 based factory utility in an implicitly-phased environment. We will see how transaction objects can be replaced using these factory utilities. I’ve deliberately attempted not to introduce too many concepts such as macros to implement default methods. I will post an article on replacing transactors shortly.
As a test bed let us take a simple concept of generating raw pixels using generators. These raw pixels are modeled as vmm_data objects. This pixel object contains RGB color information in the variable clr which is a rand property. A discriminant member called type_e determines the color that this pixel object can take.
/* 1 */ `include “vmm.sv”
/* 2 */ program main ;
/* 3 */
/* 4 */ //// Class: Pixel ////
/* 5 */
/* 6 */ class Pixel extends vmm_data ;
/* 7 */ `vmm_typename(Pixel)
/* 8 */ static vmm_log log = new(“Pixel”, “class”) ;
/* 9 */ typedef enum {Red, Green, Blue, ANY} clr_type_e ;
/* 10 */
/* 11 */ typedef enum {
/* 12 */ R1, R2, R3, R4, R5,
/* 13 */ G1, G2, G3, G4, G5,
/* 14 */ B1, B2, B3, B4, B5
/* 15 */ } clrcode_e ;
/* 16 */ rand clrcode_e clr ;
/* 17 */ clr_type_e type_e = ANY ;
/* 18 */
/* 19 */ constraint con
/* 20 */ {
/* 21 */ if(type_e == Red)
/* 22 */ clr inside {R1, R2, R3} ;
/* 23 */ if(type_e == Green)
/* 24 */ clr inside {G1, G2, G3} ;
/* 25 */ if(type_e == Blue)
/* 26 */ clr inside {B1, B2, B3} ;
/* 27 */ }
In addition to the constructor, the factory override methods needs to implement two predefined methods of vmm_data class, copy() and allocate(). These methods return the right type of the object that was enabled as factory. This can also be implemented using vmm_data short-hand macros, but for the purpose of clarity the full implementation is shown.
/* 28 */
/* 29 */ /// Function: new()
/* 30 */ function new(string name = “”, vmm_object parent = null) ;
/* 31 */ super.new(log) ;
/* 32 */ endfunction: new
/* 33 */
/* 34 */ /// Function: copy()
/* 35 */ virtual function vmm_data copy(vmm_data to = null) ;
/* 36 */ Pixel me ;
/* 37 */ if(to == null)
/* 38 */ me = new (this.get_object_name(), this.get_parent_object()) ;
/* 39 */ else if(!$cast(me, to))
/* 40 */ `vmm_fatal(log, “Can’t copy to non-Pixel instance”) ;
/* 41 */
/* 42 */ /// Copy members here
/* 43 */ me.clr = this.clr ;
/* 44 */ me.type_e = this.type_e ;
/* 45 */ return me ;
/* 46 */ endfunction: copy
/* 47 */
/* 48 */ /// Function: allocate()
/* 49 */ virtual function vmm_data allocate() ;
/* 50 */ Pixel me = new () ;
/* 51 */ return me ;
/* 52 */ endfunction: allocate
It is a good practice to have the psdisplay() method implemented. This will be handy for debugging the simulation and/or for a better report log.
/* 53 */
/* 54 */ /// psdisplay()
/* 55 */ virtual function string psdisplay(string prefix = “”);
/* 56 */ $sformat(psdisplay, “%s clr = %s, type_e = %s”,
/* 57 */ prefix, clr.name(),type_e.name()) ;
/* 58 */ endfunction: psdisplay
Finally make this Pixel class to be factory enabled by using the factory utility macro as shown below.
/* 59 */
/* 60 */ `vmm_class_factory(Pixel) // Introduce factory API
/* 61 */
/* 62 */ endclass: Pixel
This base pixel class can be customized to different variants by forcing the discriminant type as shown below. Objects of these types can be later used to override the factory. These class extensions should also be enabled as factories using the factory utilities as shown below.
/* 63 */
/* 64 */ //// GreenPixel ////
/* 65 */
/* 66 */ class GreenPixel extends Pixel ;
/* 67 */ /// new()
/* 68 */ function new(string name = “”, vmm_object parent = null) ;
/* 69 */ super.new(name, parent) ;
/* 70 */ type_e = Green ;
/* 71 */ endfunction: new
/* 72 */
/* 73 */ constraint con_GreenPixel
/* 74 */ {
/* 75 */ type_e == Green ;
/* 76 */ }
/* 77 */
/* 78 */ /// copy()
/* 79 */ virtual function vmm_data copy(vmm_data to = null) ;
/* 80 */ GreenPixel me ;
/* 81 */
/* 82 */ if(to == null)
/* 83 */ me = new ;
/* 84 */ else if(!$cast(me, to))
/* 85 */ `vmm_fatal(log, “Can’t copy to non-Green Pixel instance”) ;
/* 86 */
/* 87 */ /// Copy members here
/* 88 */ return super.copy(me) ;
/* 89 */ endfunction: copy
/* 90 */
/* 91 */ /// allocate()
/* 92 */ virtual function vmm_data allocate() ;
/* 93 */ GreenPixel me = new() ;
/* 94 */ return me ;
/* 95 */ endfunction: allocate
/* 96 */
/* 97 */ `vmm_class_factory(GreenPixel)
/* 98 */
/* 99 */ endclass: GreenPixel
In real environment, pixels streams are generated using a custom pixel generators based of vmm_xactors or use one of the pre-defined generators. I will not discuss the generators in this article for the sake of simplicity. However a simplistic approach is taken here to show the generation in an implicit environment by utilizing the run_ph() of a timeline class. The driver logic is mimicked in the run_ph() method of PixelTimeline which is an extension of vmm_timeline. This method it is implicitly triggered during the run phase of the timeline. Transaction object tr which is a Pixel object, is instanced at run-time using the create_instance() method rather than the traditional constructor new(). Although the object instantiation via the factory can also be carried out in the constructor of the transactor or the build phase of the generator (timeline here), this has a disadvantage. With the create_instance() called inside pre-run phase of the generator, it allows only one opportunity for effectively replacing the factory instance before it is created. By calling the create_instance() factory method repeatedly at run-time, it allows the factory to override dynamically as required by testcases.
/* 100 */
/* 101 */ //// PixelTimeline ////
/* 102 */
/* 103 */ class PixelTimeline extends vmm_timeline ;
/* 104 */ `vmm_typename(PixelTimeline)
/* 105 */ Pixel tr ;
/* 106 */ bit done = 0 ;
/* 107 */
/* 108 */ /// Function: new()
/* 109 */
/* 110 */ function new(string name = “”, string inst = “”, vmm_object parent = null) ;
/* 111 */ super.new(get_typename(), name) ;
/* 112 */ //tr = Pixel::create_instance(this, “Fact”) ; // Not advisable
/* 113 */ endfunction : new
/* 114 */
/* 115 */ virtual function void build_ph() ;
/* 116 */ // Not recommended to call create_instace
/* 117 */ endfunction: build_ph
/* 118 */
/* 119 */ /// Task: myrun
/* 120 */
/* 121 */ task run_ph() ;
/* 122 */ tr = Pixel::create_instance(this, “Fact”) ; // This is recommended
/* 123 */ repeat(5)
/* 124 */ begin
/* 125 */ tr.randomize() ;
/* 126 */ tr.display(“::”) ;
/* 127 */ end
/* 128 */ $display(“”);
/* 129 */ endtask: run_ph
/* 130 */
/* 131 */ endclass: PixelTimeline
Having the environment ready, let us see how the objects can be replaced using the factory utility. A typical environment will be created by extending vmm_group. Environment creation is out of scope of this topic and will not be discussed here; instead a simple program block is shown creating the relevant blocks.
/* 132 */
/* 133 */ //// Program
/* 134 */ initial
/* 135 */ begin
/* 136 */ PixelTimeline tl ;
/* 137 */ Pixel tr = new ;
/* 138 */ GreenPixel gpxl ;
/* 139 */ vmm_log log = new(“A”, “B”) ;
/* 140 */
/* 141 */ tl = new (“tl”, “Main”, null) ;
Following code shows a free running generator with no customization on the pixels.
/* 142 */
/* 143 */ /// Free running simulation, any color
/* 144 */ tl.run_phase() ;
The above code will generate pixels of all colors and the output will be as follows
:: clr = R3 :: type_e = ANY
:: clr = G3 :: type_e = ANY
:: clr = B3 :: type_e = ANY
:: clr = G3 :: type_e = ANY
:: clr = B5 :: type_e = ANY
Factory replacement can be done in two ways,
- override by transaction copy using a reference object or
- override by transaction type
While overriding by transaction copy the factory method override_with_copy() should be used. This will call the copy() method to return the right type to be overridden. Here one needs to have a reference copy that will be passed as an argument while replacing factory. In the following code snippet it is shown that a local transaction copy is pixilated to Red using the type discriminant. This copy is used to override the transaction object as shown below.
/* 145 */
/* 146 */ /// Override with a transaction object copy of type Red
/* 147 */ tr.type_e = Pixel::Red ;
/* 148 */ Pixel::override_with_copy(“@%*”, tr, tr.log, `__FILE__, `__LINE__) ;
/* 149 */ tl.reset_to_phase(“start_of_sim”) ;
/* 150 */ tl.run_phase() ;
/* 151 */
This part of the code will generate the red pixels and the output will be as follows
:: clr = R1 :: type_e = Red
:: clr = R3 :: type_e = Red
:: clr = R2 :: type_e = Red
:: clr = R3 :: type_e = Red
:: clr = R1 :: type_e = Red
While overriding by transaction type the factory method override_with_new() should be used. This will call the allocate() method to return the right type. To specify the type of object to be manufactured one can use the predefined method this_type() which returns the type of the specified object. Here in the following example GreenPixel type is used to override the factory.
/* 152 */
/* 153 */ /// Override with new type-Green
/* 154 */ Pixel::override_with_new(“@%*”, GreenPixel::this_type,
/* 155 */ log, `__FILE__, `__LINE__) ; // Strongly typed
/* 156 */ tl.reset_to_phase(“configure”) ;
/* 157 */ tl.run_phase() ;
/* 158 */
/* 159 */ #100 $finish ;
/* 160 */ end
/* 161 */ endprogram: main
/* 162 */
The above code will generate the green pixels and the output will be as follows
:: clr = G2 :: type_e = Green
:: clr = G2 :: type_e = Green
:: clr = G1 :: type_e = Green
:: clr = G3 :: type_e = Green
:: clr = G3 :: type_e = Green
It is worthwhile to notice that the factory override methods are strongly typed. There isn’t any room for accidental type mismatch. Tool will automatically error out during compilation. For example, the following code is illegal and the tool throws a compilation error.
Data::override_with_new(“@%*”, GreenPixel::this_type,
log, `__FILE__, `__LINE__) ; // Strongly typed
Where Data is not an extension of type Pixel.
Hope you all will have a colorful experience with VMM-1.2 factory utility (no pun intended).