Using 20 Classes 20 Factories 20 The 20 and 20 of 20 Verification
Using 20 Classes 20 Factories 20 The 20 and 20 of 20 Verification
siemens.com/software
White Paper – Using parameterized classes and factories: The yin and yang of object-oriented verification
Contents
Abstract
Introduction
Conclusion
References
Abstract
Introduction
Later, the compilation phase reads the is connected to the variable V. The
definition of middle: elaboration phase allocates the static,
module middle #(type T, int N=8) fixed-size array variable top.m1.Fix with
(input T Port1, Port2=5); four elements. It computes the data
T Fix[N]; type vector_t to be a 32-bit integral type
typedef bit [0:N*8] vector_t; and creates the static, dynamically sized
vector_t Dyn[]; array variable top.m1.Dyn with no
initial begin elements.
#25 // move away from time 0
run(); Finally, the runtime phase starts by
end propagating the constant ‘{1,2,3} to
task automatic run(); top.m1.Port1 at time 0. At time 5, top.V
const int C = Port2; is assigned to 10 and propagates to
Fix = `{default:Port1}; top.m1.Port2. Task run is called at time
Dyn = new[C]; 25. The call creates the local const
endtask variable C. The only difference between
endmodule a const variable and a normal variable is
that the only allowed assignment to the
The compilation phase recognizes that T const variable is at the point of its
will be a data type, but each instance declaration.
could result in T having a different type.
The size for the fixed array Fix and the In this case, task run has an automatic
width of vector_t must be declared lifetime, which means that each call to
using constant expressions. The size of the task allocates its local variables. The
the dynamic array Dyncan be any initialization of C occurs on each call.
expression because it will be Therefore, a const variable is not really a
constructed at runtime. constant as far as elaboration or
parameterized types are concerned.
During the elaboration phase, an
instance of middle, named m1, is Classes and paramters with the
created with type T overridden by data SystemVerilog type system
type ABC_t and N overridden by a
constant expression computed with Objects and handles
value 4. Port1 is connected to the A SystemVerilog class declaration is a
constant expression ‘{1,2,3}, and Port2 data type that defines an instance of a
class ApbWriteTrans extends ApbTrans; The factory returns the subtype instance
constraint write_only { cmd == WRITE; } in a handle to the super class, Object, so
virtual function Object create(); ApbDriver must cast it back into the
ApbWriteTrans trans = new(); particular subtype it expects. Before we
return trans; can use the factory, it must be initialized
endfunction externally with a particular instance of
endclass the subtype we want it to produce. This
is because the factory class is designed
class ApbReadTrans extends ApbTrans; to produce objects of type Object, which
constraint read_only { cmd == READ; } is an abstract virtual type that cannot be
virtual function Object create(); allocated directly. We can only allocate
ApbReadTrans trans = new(); concrete subtypes of Object. The
following code configures the factory to
but because the factory and its obj different types. What if we had a
property are both parametrically typed PciDriver and an ApbDriver making
using the same BASE type, the $cast is requests at random times? How would
guaranteed not to fail. you coordinate the factory’s
configuration to produce the correct
When we write our drivers now, we subtype when you cannot know the
have them make requests to the factory caller at any given time?
specialization that is matched to the
base types we want created. We avoid The parameterized factory allows for a
the $cast, and all type errors are caught separate specialized factory for each
during compilation. type being requested, and we avoid
having to create instances of each
class ApbDrv #(type BASE=ApbTrans); specialized factory ourselves. A call to
task run(); the specialized factory’s static set_object
forever begin or create methods cues its allocation on
BASE trans; demand.
trans = Factory #(BASE)::create();
trans.randomize(); Here’s our new top level, which is highly
... execute transaction reconfigurable and reusable. We have
end added a PciDrv component, defined in
endtask the same fashion as ApbDrv.
endclass
// Create drivers that operate on base
Our original factory implementation types
used a global, non-parameterized ApbDrv #(ApbTrans) apb_drv = new;
factory that would presumably be used PciDrv #(PciTrans) pci_drv = new;
by all components making requests for
Conclusion
We have explored the static and within a single environment. All of this
dynamic aspects of type polymorphism has led to improved code reusability by
in SystemVerilog as well as explained reducing the code required for each
the synergies in combining the two specialization.
References
3. “IEEE Standard for SystemVerilog- Unified Hardware Design, Specification, and Verification
Language,” IEEE Std 1800-2005, 2005.
5. “Open Verification Methodology User Guide - Version 2.0.1, Octob er 2008”, Mentor
Graphics, Corp and Cadence Design Systems, Inc.
Europe
Stephenson House
Sir William Siemens Square Frimley,
Camberley
Surrey, GU16 8QD
+44 (0) 1276 413200
Asia-Pacific
Unit 901-902, 9/F
Tower B, Manulife Financial Centre
223-231 Wai Yip Street, Kwun Tong
Kowloon, Hong Kong
+852 2230 3333
10/2023 81184-C2