Sunteți pe pagina 1din 36

Know Your Objects

OOP for Hardware Designers

ALDEC Webinar
Created and Presented by
Jerry Kaczynski,
ALDEC Research Engineer

Rev. 1.0

Agenda
Introduction: Raising Abstraction Level
Benefits of Encapsulation
Why We Need Inheritance
That Mysterious Polymorphism
Decoding Dynamic Dispatch
Summary/Q&A

www.aldec.com

Introduction:

RAISING ABSTRACTION LEVEL


www.aldec.com

Abstraction In Design Domain


When first digital Integrated Circuits were designed,

there was no need to raise abstraction level:


small number of transistors needed to implement
4 NAND gates could be drawn on a piece of paper.
Programming PLDs at the transistor level was not
feasible: schematics and other gate level design
tools were created.
Schematics for CPLDs/FPGAs were getting too
complicated, so RTL and behavioral descriptions
were needed.
Complete systems that can be squeezed into
modern circuits require even higher levels of abstraction: transaction or
even pure algorithmic.

www.aldec.com

Abstraction In Program Domain


First computers were programmed by flipping switches representing

bits of registers no abstraction whatsoever


Assembly languages replaced bit combinations
with easier to comprehend mnemonics.
More abstract, but still tied to the particular
machine.
High-level languages abstracted both control
(procedures, functions, etc.) and data (vectors,
arrays, records, etc.)
Object Oriented Programming (OOP) tied abstracted control and data
together, providing powerful tool for designing large programs/systems.

www.aldec.com

Abstraction in HDLs
Classical Hardware Description Languages (HDLs) VHDL and Verilog

are operating at the procedural level to let you design


at RTL or behavioral level.
ALGORITHM
New, large digital systems require at least
Transaction Level Modeling, which is easiest
to implement in OOP.
TLM
The penalty for using high abstraction level
is inability to control minute details
RTL
of implementation.
Abstract models are gradually refined
down to RTL/gate level, where they can be
GATE
fine-tuned and implemented.

www.aldec.com

Bundling Things In Your Design:

BENEFITS OF ENCAPSULATION
www.aldec.com

Old Style
Classical languages (BASIC, C, Verilog, VHDL) abstract control and data
separately:

Subroutines (procedures/tasks and functions) describe what program can do.


Data types (arrays, records/structures) define data that can be manipulated
by subroutines.

In large designs that extensively use language resources this separation


often leads to confusion:
Can I use to_integer function with STD_LOGIC_VECTOR argument?
Can I read only low byte of memory word?

Wouldnt it be nice if data and operations you can


perform on it were tied together?

www.aldec.com

VHDL Protected Types


VHDL has a mechanism for encapsulating data (in bundles resembling
records) and procedures/functions operating on them in protected types.

Protected types have structure similar to packages:


Public subprograms and data fields are listed in protected type declaration.
Private data fields/subprograms and implementations of public subprograms are listed
in protected type body.

To use protected type, you have to declare shared variable of that type.
To do anything with shared variable, you use notation
similar to accessing record fields:
shared_variable_name.member_name.

Note:
This feature is available in the language since 2002 version.
www.aldec.com

10

VHDL OOP Counter


type base_counter is protected
procedure clear;
procedure count;
impure function show return integer;
end protected base_counter;
type base_counter is protected body
variable contents : integer := -7;
procedure clear is
begin
contents := 0;
end procedure clear;
procedure count is
begin
contents := contents + 1;
end procedure count;
impure function show return integer is
begin
return contents;
end function show;
end protected body base_counter;

www.aldec.com

shared variable my_counter : base_counter;


. . .
-- 'Untimed' use
my_counter.clear;
OUTPUT <= my_counter.show;
. . .
my_counter.count;
OUTPUT <= my_counter.show;
. . .
-- 'Refined' use
process (CLK, RESET)
begin
if RESET then
my_counter.clear;
elsif CLK'event and CLK='1' then
my_counter.count;
end if;
end process;

11

Is it enough?
Protected type approach to bundling data and functions works pretty
well, but there is some room for improvements
To enhance existing protected type, you have to modify
its source code: reuse is not flexible enough.

Shared variables are static, so all you can do with them


is decided at the compilation time.

Some general-purpose languages (C++, Java)


and SystemVerilog support classes and objects
the staple of OOP:
You can create child class that inherits everything from
the original class.

Objects are created in dynamically allocated memory


at runtime.

www.aldec.com

12

Classes and Objects


Class is an abstract idea of grouping together:
Some pieces of data called attributes (or member variables or
properties),
Subroutines that operate on those pieces of data: methods
(a.k.a. member functions).

Class

Based on the idea of class, we can build actual objects


(can you see the analogy with types and variables?)

When we declare object of a certain class in our


program, a handle (or pointer) is created not actual
object.

In the program code we have to call constructor


method of the class to allocate memory for the object
and assign initial values to its properties.
www.aldec.com

Object

13

SystemVerilog OOP Counter


package oop;
class Base_Counter;
int contents;
function new();
contents = -7;
endfunction
task clear();
contents = 0;
endtask
task count();
contents += 1;
endtask
function int show();
return contents;
endfunction
endclass
endpackage

www.aldec.com

module top;
timeprecision 100ps;
timeunit 1ns;
import oop::*;
Base_Counter my_counter = new;
initial begin
$display($stime, my_counter.show);
#10 my_counter.clear;
$display($stime, my_counter.show);
repeat(10) begin
#10 my_counter.count;
$display($stime, my_counter.show);
end
end
endmodule

14

Encapsulation?
One of the main reasons to use classes and objects is
to achieve encapsulation:

Bundling of data (attributes) and procedures operating on it (methods).


Shielding attributes from direct access by end users.

Some scholars prefer only first or second feature of encapsulation


mentioned above; we should be aware of both.

Different languages assume different default level of access


to class members:

If, like in C++, members are private by default (accessible only


within its class), you can make them public by adding public qualifier
in the declaration.
If members are public by default (like in SystemVerilog) you can change
it by using local qualifier (in SV only; C++ uses private qualifier).
www.aldec.com

15

Introducing UML
Universal Modeling Language (UML) is a popular graphical
representation of classes and their relationships.

In UML class diagram a box represents the class:


Top section names the class.
Middle section lists class attributes.
Bottom section describes class methods.

Level of member description detail varies: in general


diagrams only member names are listed (no data types,
argument names, etc.)

Non-default access to the member may be marked by:


+ in front of the name of public member.
in front of the name of private/local member.
www.aldec.com

16

Improving Reuse:

WHY WE NEED INHERITANCE


www.aldec.com

17

Smart Reuse
Lets say that we want to add load functionality to our Base_Counter
class.

In procedural languages we would have to:


Copy description of the original counter.
Add load functionality.
Save modified description as a new counter.

This approach works as long as Base_Counter


never changes:

If somebody changes Base_Counter description but forgets to modify new


counter accordingly we have a problem

Inheritance very important feature of OOP can solve this problem


www.aldec.com

18

Inheritance
We can use inheritance to create new class (called derived class or child
class) based on original class (called base class or parent class).

Inheritance creates is-a relationship: new class objects are also old
class objects and can replace them in the program code.

UML class diagram represents inheritance by empty


triangle arrow pointing from the new to the old class.

Only changes to the old class contents are listed in the new
class box: everything else is inherited.

Arrow points in the direction of generalization and against


the direction of specialization.

In our diagram, new Load_Counter class specializes old


Base_Counter class (which is more general of the two).
www.aldec.com

19

SystemVerilog Child Counter Class


package oop;
class Base_Counter;
int contents;
function new();
contents = -7;
endfunction
task clear();
contents = 0;
endtask
task count();
contents += 1;
endtask
function int show();
return contents;
endfunction
endclass

class Load_Counter extends Base_Counter;


task load(input int val);
contents = val;
endtask
endclass

module top;
timeprecision 100ps;
timeunit 1ns;
import oop::*;
Load_Counter my_counter = new;
initial begin
$display($stime, my_counter.show);
#10 my_counter.clear;
$display($stime, my_counter.show);
repeat(5) begin
#10 my_counter.count;
$display($stime, my_counter.show);
end
#10 my_counter.load(777);
$display($stime, my_counter.show);
end
endmodule

endpackage

We have extended base class functionality by adding method.

www.aldec.com

20

Another Flavor of Inheritance


Our Load_Counter demonstrated how derived class can add members,
but it is not the only way

Child class can also override methods of the parent class


by providing their new definitions.

Lets say that we want to crate newer class that still has
load functionality, but is also parameterized with maximal
count value.

This time we will have to write new count() method that


rolls back to zero after reaching maximal count.

Updated UML class diagram of our class hierarchy is


presented to the right.

www.aldec.com

21

Another Child Counter Class


package oop;
class Base_Counter;
int contents;
function new();
contents = -7;
endfunction
task clear();
contents = 0;
endtask
task count();
contents += 1;
endtask
function int show();
return contents;
endfunction
endclass

class Super_Counter #(parameter max = 31)


extends Load_Counter;
task count();
if (contents == max)
contents = 0;
else
contents += 1;
endtask
endclass

endpackage

class Load_Counter extends Base_Counter;


task load(input int val);
contents = val;
endtask
endclass
>>>>>>>>

We have modified base class functionality by overriding method.

www.aldec.com

22

Side Comment: Aggregation


Inheritance is the preferred method of building new classes if further

extensions are planned.


If we perform final assembly of our design (testbench or top-level
model), we can use aggregation.
Aggregation instantiates lower level class objects inside the container
class.
UML class diagrams represent aggregation using lines with empty
diamonds at the container class end:

www.aldec.com

23

Making Smart Decisions:

THAT MYSTERIOUS POLYMORPHISM


www.aldec.com

24

Manipulating Handles
All examples of code we have seen so far were calling class constructor

to build object. Address of the object returned by


the constructor was stored in the handle, which was
used only to access object attributes and methods.
You can pass objects around by making assignments
of one handle to another. It makes sense since you
can create multiple objects dynamically
OOP always lets you assign object of child class to
the handle of parent class type. Such assignment
triggers automatic upcasting of the object to
the parent class type.
So assigning Super_Counter object to Base_Counter
handle is absolutely legal in our project

www.aldec.com

25

Overridden Method Problem


Lets do some handle passing:
Super_Counter #(15) better_counter = new;
Base_Counter
count_handle;
count_handle = better_counter;

Now we have Super_Counter object accessible via


Base_Counter variable. We have two implementations
of count() method in class hierarchy. What will

happen if we call this method like this:


count_handle.count;

The answer is: implementation of overridden method

is selected based on the handle type, not object type!


It means we have a problem: Base_Counter::count()
that is called does not know how to roll back...

www.aldec.com

26

Virtual Methods
You can declare methods as virtual.
When you override virtual method in a child class, implementation
created for that class will stick with the object no matter what is the type
of the handle!

That type of behavior is called polymorphism and is one of the key


features of OOP.

Lets try it in our class hierarchy:


We have to make count() virtual.
We also have to display some control messages from virtual and non-virtual
methods so we can see who is calling whom

www.aldec.com

27

Counter Class with Virtual Method


package oop;
class Base_Counter;
int contents;
function new();
contents = -7;
endfunction
task clear();
contents = 0;
$display(
"Base_Counter::clear was executed! \n");
endtask
virtual task count();
contents += 1;
$display(
"Base_Counter::count was executed! \n");
endtask
function int show();
return contents;
endfunction
endclass
class Load_Counter extends Base_Counter;
task load(input int val);
contents = val;
endtask
endclass
>>>>>>>>

www.aldec.com

class Super_Counter #(parameter max = 31)


extends Load_Counter;
task clear();
contents = 0;
$display(
"Super_Counter::clear was executed! \n");
endtask
virtual task count();
if (contents == max)
contents = 0;
else
contents += 1;
$display(
"Super_Counter::count was executed! \n");
endtask
endclass
endpackage

28

Using Virtual Methods TB


// Heres the snippet of testbench using our class with virtual method:
Super_Counter #(15) better_counter = new;
Base_Counter
simple_counter = new;
Base_Counter
count_handle;
initial begin
count_handle = better_counter;
$display("Calling non-virtual 'clear' from 'Base_Counter' object with 'Base_Counter' handle...");
simple_counter.clear;
$display("Calling non-virtual 'clear' from 'Super_Counter' object with 'Base_Counter' handle...");
count_handle.clear;
#10;
$display("Calling virtual 'count' from 'Base_Counter' object with 'Base_Counter' handle...");
simple_counter.count;
$display("Calling virtual 'count' from 'Super_Counter' object with 'Base_Counter' handle...");
count_handle.count;
end

www.aldec.com

29

Using Virtual Methods Results


// Heres the console dump from simulation of our class with virtual method:
#
#
#
#
#
#
#
#
#
#
#
#

KERNEL:
KERNEL:
KERNEL:
KERNEL:
KERNEL:
KERNEL:
KERNEL:
KERNEL:
KERNEL:
KERNEL:
KERNEL:
KERNEL:

Calling non-virtual 'clear' from 'Base_Counter' object with 'Base_Counter' handle...


Base_Counter::clear was executed!

Calling non-virtual 'clear' from 'Super_Counter' object with 'Base_Counter' handle...


Base_Counter::clear was executed!
Calling virtual 'count' from 'Base_Counter' object with 'Base_Counter' handle...
Base_Counter::count was executed!
Calling virtual 'count' from 'Super_Counter' object with 'Base_Counter' handle...
Super_Counter::count was executed!

www.aldec.com

30

Making Miracles Happen:

DECODING DYNAMIC DISPATCH


www.aldec.com

31

Things Can Get Complicated


If this presentation is your first encounter with encapsulation,
polymorphism and similar terms, you are justified to think
that they are not exactly trivial

But wait! Developers of simulators have quite


difficult tasks to deal with, too. Especially if they
were handling only Verilog or VHDL before.

If you call a function in classical HDL, compiler knows


its location and can insert proper jump in the executable code.

When compiler encounters virtual method call, compiler usually doesnt


know which implementation to call

www.aldec.com

32

Dynamic Dispatch
In addition to dynamic memory allocation for objects, simulators
have to deal with runtime binding of method calls to proper
implementations.

This process is called dynamic dispatch or


dynamic binding and requires some novel
approach to organizing simulation.

Usually compiler stores virtual method calls in


special virtual table. Simulator fills that table with proper
implementation addresses as objects are created and updates it as
objects are passed around.

Of course this handling is slower than regular method calls thats why
methods are not virtual by default.
www.aldec.com

33

Why All The Trouble?


Objects, encapsulation, polymorphism mixed with Transaction

Level Modeling (TLM) let you create very powerful, yet extremely
flexible verification environments.
You probably heard about OVM or UVM
they are such environments!
Now you should have a little easier task
of understanding them.

www.aldec.com

34

SUMMING UP
www.aldec.com

35

Tools Used
All pieces of code presented in this webinar (VHDL and SystemVerilog)

were tested on Riviera-PRO simulator.


While you can draw UML diagrams by hand, there are free tools that can
make this task easier and faster:

Java-based Violet UML Editor runs on any platform and is ideal solution for
beginners not familiar with UML. All UML diagrams in this presentation were
created in Violet. To download it, google VioletUML.
UMLet is a slightly more advanced UML editor. Google its name to download it.
Popular multi-platform graphing tool Dia (http://dia-installer.de/) can create
UML diagrams, too.

Although there are tools that can generate C++ or Java code from the UML
diagrams, none of them can generate SystemVerilog code

www.aldec.com

36

Conclusion
Feel free to contact ALDEC if you need more info about EDA-related topics
and our design creation and verification tools.
ALDEC Website:
Telephone
USA
Canada:
Europe:
Japan:
India:
China:
Taiwan:
Israel:

http://www.aldec.com
+1-702-990-4400
+1-613-867-8600
+33-6-80-32-60-56
+81-3-5312-1791
+91-80-32551030
+86-21-6875-20-30
+886-2-26599119 ext. 950
+972-52-2573422

Download:
Recorded webinars
White papers
Trial versions of our tools
www.aldec.com

E-mail
sales@aldec.com
sales@aldec.com
sales-eu@aldec.com
sales-jp@aldec.com
sales-sa@aldec.com
info@aldec.com.cn
sales-tw@aldec.com
sales-il@aldec.com

S-ar putea să vă placă și