SV: What is the proper way to instantiate a class?

M

mrfirmware

Guest
Forgive a poor C programmer but I'm having a hard time figuring some
of the mundane linkage rules with SystemVerilog. I would expect to do
something like this:

// top_tb.sv:
module top;
Thing thing;
thing.test();
....
endmodule : top;

// thing.sv
class Thing;
task test
....
endtask : test
endclass : Thing

Then compile them both together via something like: vlog top_tb.sv
thing.sv. Later, vsim'ing my little testbench demo code vsim complains
** Error: Failed to find 'test' in hierarchical name. If I wrap the
class within a module/endmodule I can access the methods but this
seems clumsy. E.g.

// thing.sv
module Thing;
class obj;
task test
....
endtask : test
endclass : obj
endmodule : Thing

I can now invoke test() via thing.obj.test() but yuck.

Also, I seem unable to pass a ref to test() when it is a class, vsim
complains, Fatal: (SIGSEGV) Bad pointer access. Same exact code but
strip the class from the file so that it's a plain module and all is
well. I can pass a reference to my typedef to test() no problem. What
am clearly not understanding?

Thanks,
--
- Mark
 
On Mon, 27 Aug 2007 22:45:01 -0000, mrfirmware <mrfirmware@gmail.com>
wrote:

Forgive a poor C programmer
Why? :)

// top_tb.sv:
module top;
Thing thing;
thing.test();
...
endmodule : top;
Did you forget to put the procedural code in an "initial"
construct? (though that's not the main problem)

module top;
initial begin
Thing thing;
thing.test();
end
....
endmodule : top;

// thing.sv
class Thing;
task test
...
endtask : test
endclass : Thing

Then compile them both together via something like: vlog top_tb.sv
thing.sv. Later, vsim'ing my little testbench demo code vsim complains
** Error: Failed to find 'test' in hierarchical name.
You've fallen foul of the "compilation unit" rules, which are
somewhat tool-specific (the LRM defines them to be so).
If you say to ModelSim

vlog top_tb.sv thing.sv

then it runs two completely separate compilations, one for each
file. Consequently, class Thing is not known in either the
compilation or the elaboration of top. However, the compilation
of top cannot choke on the reference to Thing, because it might
be the name of a *module* that would need to be resolved
at elaboration rather than compile time. Module (and program,
and interface, and package) names go into a truly global
design-unit namespace; classes, on the other hand, are a
species of user-defined type and their names are confined to
within a design unit. In your case, the name Thing is known
only within the implicit file-scope design unit of the
compilation of thing.sv (the name of this implied package is
$unit, but that needn't bother us here or most anywhere else).

So, there are two fixes - one tacky, the other nice and clean:

(1) (tacky) Use ModelSim's -mfcu (multi file compilation unit)
option so that all your files are compiled as though concatenated
into a single piece of source code - and, while you're at it,
try to do define-before-use:

vlog -sv -mfcu thing.sv top_tb.sv

Now the name of class Thing is injected into the compilation-unit
scope ($unit) for the ENTIRE compile, and module top can see it.

(2) (hygienic) Put the class definition into a package,
and import that package where you need it:

[file thing.sv]
package thing_pkg;
class Thing;
...
endclass
endpackage : thing_pkg

[file top_tb.sv]
module top;
import thing_pkg::*;
initial begin
Thing thing;
thing.test();
end
endmodule

Also, I seem unable to pass a ref to test()
do you mean you can't pass an argument of "ref" direction?
I'm not sure I understand your problem here. Could you post
a bit more code?
--
Jonathan Bromley, Consultant

DOULOS - Developing Design Know-how
VHDL * Verilog * SystemC * e * Perl * Tcl/Tk * Project Services

Doulos Ltd., 22 Market Place, Ringwood, BH24 1AW, UK
jonathan.bromley@MYCOMPANY.com
http://www.MYCOMPANY.com

The contents of this message may contain personal views which
are not the views of Doulos Ltd., unless specifically stated.
 
On Tue, 28 Aug 2007 09:11:02 +0100,
<jonathan.bromley@MYCOMPANY.com> wrote:

Forgive a poor C programmer

Why? :)
Oops, I should have thought more carefully before being frivolous.
You've also slipped-up on the C++ programmer's big mistake in
SystemVerilog (and, indeed, in just about any other OO language
except C++):

module top;
initial begin
Thing thing;
thing.test();
end
...
endmodule : top;
This won't work, because the declaration
Thing thing;
gives us only a REFERENCE to a Thing - unlike C++ where we
would get a real live genuine Thing. So
thing.test();
is an access through a null reference, and will fail.
Instead you need

Thing thing = new;
thing.test();

All my other comments are still relevant.

Apologies for missing that
--
Jonathan Bromley, Consultant

DOULOS - Developing Design Know-how
VHDL * Verilog * SystemC * e * Perl * Tcl/Tk * Project Services

Doulos Ltd., 22 Market Place, Ringwood, BH24 1AW, UK
jonathan.bromley@MYCOMPANY.com
http://www.MYCOMPANY.com

The contents of this message may contain personal views which
are not the views of Doulos Ltd., unless specifically stated.
 
On Aug 28, 4:11 am, Jonathan Bromley <jonathan.brom...@MYCOMPANY.com>
wrote:

Did you forget to put the procedural code in an "initial"
construct? (though that's not the main problem)
No. I have an initial block.

module top;
initial begin
Thing thing;
thing.test();
end
...
endmodule : top;

// thing.sv
class Thing;
task test
...
endtask : test
endclass : Thing

Then compile them both together via something like: vlog top_tb.sv
thing.sv. Later, vsim'ing my little testbench demo code vsim complains
** Error: Failed to find 'test' in hierarchical name.

You've fallen foul of the "compilation unit" rules, which are
somewhat tool-specific (the LRM defines them to be so).
If you say to ModelSim

vlog top_tb.sv thing.sv

then it runs two completely separate compilations, one for each
file. Consequently, class Thing is not known in either the
compilation or the elaboration of top. However, the compilation
of top cannot choke on the reference to Thing, because it might
be the name of a *module* that would need to be resolved
at elaboration rather than compile time. Module (and program,
and interface, and package) names go into a truly global
design-unit namespace; classes, on the other hand, are a
species of user-defined type and their names are confined to
within a design unit. In your case, the name Thing is known
only within the implicit file-scope design unit of the
compilation of thing.sv (the name of this implied package is
$unit, but that needn't bother us here or most anywhere else).

So, there are two fixes - one tacky, the other nice and clean:

(1) (tacky) Use ModelSim's -mfcu (multi file compilation unit)
option so that all your files are compiled as though concatenated
into a single piece of source code - and, while you're at it,
try to do define-before-use:
I'm not so keen on -mfcu. That's analogous to placing all my classes
in separate files and then `including them from top.sv. Gross.

(2) (hygienic) Put the class definition into a package,
and import that package where you need it:
Package? This I like. Reminds me of Perl which I speak in addition to
C.

package thing_pkg;
class Thing;
...
endclass
endpackage : thing_pkg

[file top_tb.sv]
module top;
import thing_pkg::*;
initial begin
Thing thing;
thing.test();
end
endmodule
Ah, elaboration is something like linking then. I get your point about
classes being non-global. So I tried your example, thank you BTW, and
got this:

vlog -quiet -nologo -noincr -lint -source -hazards -sv -libmap ./out/
top -work ./out/top -timescale 1ns/1ps top.sv thing.sv
###### top.sv(5): import thing_pkg::*;
** Error: top.sv(5): Could not find the package (thing_pkg).
###### top.sv(8): Thing thing = new;
** Error: top.sv(8): Undefined variable: Thing.
** Error: top.sv(8): near "thing": syntax error, unexpected
"IDENTIFIER"

I added -noincr since I only get this error the first time I run this
command but -noincr didn't seem to help. The -sv seems dangerous to me
since I think it treats all sources like SV source but I tried it
anyway. I have added the Thing thing = new; to your example code but
clearly we're not even getting that far here. This is frustrating to
the limit for me so I really appreciate your help.

Regards,
--
- Mark
 
On Tue, 28 Aug 2007 13:54:20 -0000,
mrfirmware <mrfirmware@gmail.com> wrote:

Ah, elaboration is something like linking then.
Somewhat, but of course it does all the static construction of the
instantiated module hierarchy.

I get your point about classes being non-global. So I tried
your example, thank you BTW, and got this:

vlog -quiet -nologo -noincr -lint -source -hazards -sv -libmap ./out/
top -work ./out/top -timescale 1ns/1ps top.sv thing.sv
###### top.sv(5): import thing_pkg::*;
** Error: top.sv(5): Could not find the package (thing_pkg).
###### top.sv(8): Thing thing = new;
** Error: top.sv(8): Undefined variable: Thing.
** Error: top.sv(8): near "thing": syntax error, unexpected
"IDENTIFIER"

I added -noincr since I only get this error the first time I run this
command but -noincr didn't seem to help.
Ah, yes, but note that you've compiled thing.sv AFTER you tried to
import its package in top.sv! Once again: *a package is a design
unit*; it must be compiled before you can import it. So try
again, with thing.sv and top.sv swapped on the compile command
line, and it should be OK.

The -sv seems dangerous to me
since I think it treats all sources like SV source
There are plenty of ways around that. In ModelSim,
using a .sv extension instead of .v teaches the tool to
use SystemVerilog. There are also some compiler directives
you can embed in your code (read up on `begin_keywords)
to control somewhat the style of compilation.

Don't forget that it's OK to do the compiles separately:

vlog -work lib thing.sv ; # compiles package thing into lib
vlog -work lib top.sv ; # compiles module top into lib
vsim lib.top ; # elaborates top + thing

So you can easily apply quite different options to
various files that go to make up a model.
--
Jonathan Bromley, Consultant

DOULOS - Developing Design Know-how
VHDL * Verilog * SystemC * e * Perl * Tcl/Tk * Project Services

Doulos Ltd., 22 Market Place, Ringwood, BH24 1AW, UK
jonathan.bromley@MYCOMPANY.com
http://www.MYCOMPANY.com

The contents of this message may contain personal views which
are not the views of Doulos Ltd., unless specifically stated.
 
On Aug 28, 10:16 am, Jonathan Bromley <jonathan.brom...@MYCOMPANY.com>
wrote:
On Tue, 28 Aug 2007 13:54:20 -0000,

mrfirmware <mrfirmw...@gmail.com> wrote:
Ah, elaboration is something like linking then.

Somewhat, but of course it does all the static construction of the
instantiated module hierarchy.
That's just a bit over my head.

I get your point about classes being non-global. So I tried
your example, thank you BTW, and got this:

vlog -quiet -nologo -noincr -lint -source -hazards -sv -libmap ./out/
top -work ./out/top -timescale 1ns/1ps top.sv thing.sv
###### top.sv(5): import thing_pkg::*;
** Error: top.sv(5): Could not find the package (thing_pkg).
###### top.sv(8): Thing thing = new;
** Error: top.sv(8): Undefined variable: Thing.
** Error: top.sv(8): near "thing": syntax error, unexpected
"IDENTIFIER"

I added -noincr since I only get this error the first time I run this
command but -noincr didn't seem to help.

Ah, yes, but note that you've compiled thing.sv AFTER you tried to
import its package in top.sv! Once again: *a package is a design
unit*; it must be compiled before you can import it. So try
again, with thing.sv and top.sv swapped on the compile command
line, and it should be OK.
Oh for Pete's sake. So my top.sv file has to be the last file
specified? What a PITA but okay, now I know. Thank you for that bit of
knowledge as it will save me hours of futzing around. I never would
have guessed the order in which you specified independent source files
to a compiler would matter but then again I've been doing embedded
software for the last 20 years so what do I know about SV? :)

The -sv seems dangerous to me
since I think it treats all sources like SV source

There are plenty of ways around that. In ModelSim,
using a .sv extension instead of .v teaches the tool to
use SystemVerilog. There are also some compiler directives
you can embed in your code (read up on `begin_keywords)
to control somewhat the style of compilation.

Don't forget that it's OK to do the compiles separately:

vlog -work lib thing.sv ; # compiles package thing into lib
vlog -work lib top.sv ; # compiles module top into lib
vsim lib.top ; # elaborates top + thing

So you can easily apply quite different options to
various files that go to make up a model.
Now this is interesting. Here you're not specifying all the files at
once yet top.sv will be able to "see" class Thing. Is this because
you've compiled top.sv after (in time) thing.sv? So it's not an
invocation order of source files, per se, it's a time order. As long
as I compile top.sv last, I can compile my packages independently and
in any order? That's not so bad.

Thanks again for your help. Now on to my ref problem:

** Error: (vsim-8282) top.sv(85): Actual argument expression for ref
formal "(null)" is not an equivalent type.

This is caused by a dynamic array ref. I want my class to expand my
supplied dynamic array ref as needed and fill it with data parsed from
an arbitrary length data field found in a file. I got this to work
when I didn't have packages or classes, e.g. thing.sv contained only a
module. I have this:

[top.sv]
module top
import thing_pkg::*;

initial begin : main // Yes, a C programmer I am

byte data[];
Thing thing = new;

thing.test(data);

end

[thing.sv]
package thing_pkg;
class Thing;
task automatic test(ref data[]); <- I've forgotten ; too many times to
count
data = new[4];
data[0] = 0;
data[1] = 1;
data[2] = 2;
data[3] = 3;
endtask
endclass
endpackage

So what's this ref formal "(null)" not equivalent type mean?

Thanks,

- Mark
 
On Tue, 28 Aug 2007 14:44:32 -0000, mrfirmware wrote:

On Aug 28, 10:16 am, Jonathan Bromley wrote:
On Tue, 28 Aug 2007 13:54:20 -0000,

mrfirmware <mrfirmw...@gmail.com> wrote:
Ah, elaboration is something like linking then.

Somewhat, but of course it does all the static construction of the
instantiated module hierarchy.

That's just a bit over my head.
Nope. It's the dynamic construction that you OOP guys do that
goes over *our* heads. You see, it's kinda tough to build
hardware on-the-fly, so wee need a language that can specify
the static structure of the program in some detail...

Oh for Pete's sake. So my top.sv file has to be the last file
specified? What a PITA but okay, now I know. Thank you for that bit of
knowledge as it will save me hours of futzing around. I never would
have guessed the order in which you specified independent source files
Independent? When the second one uses a data type (class)
that was defined by the first? I don't think so. If you really
want that independence, at any cost, we can talk about type
parameters. But that is in bandit country...

to a compiler would matter but then again I've been doing embedded
software for the last 20 years so what do I know about SV? :)
No, it's just that you're stuck with C's palaeolithic
textual-include mechanism for grabbing existing bits of Stuff.
Most SV tools proceed by compiling design units (=packages,
modules, interfaces, programs) into one or more libraries.
Once a package is compiled into a library, you can import
it into other compilations at any future time. As you said,

As long as I compile top.sv last, I can compile my
packages independently and in any order? That's not so bad.
"In any order" as long as they don't import one another,
of course.

Thanks again for your help. Now on to my ref problem:

** Error: (vsim-8282) top.sv(85): Actual argument expression for ref
formal "(null)" is not an equivalent type.

This is caused by a dynamic array ref. I want my class to expand my
supplied dynamic array ref as needed and fill it with data parsed from
an arbitrary length data field found in a file. I got this to work
when I didn't have packages or classes, e.g. thing.sv contained only a
module.
I think this is just trouble with type syntax...

module top
import thing_pkg::*;

initial begin : main // Yes, a C programmer I am

byte data[];
Thing thing = new;

thing.test(data);

end
That looks fine to me.

package thing_pkg;
class Thing;
task automatic test(ref data[]);
At the very least this should be (ref byte data[]).
I would be a lot more comfortable if you had created
a typedef:

package thing_pkg;
typedef byte dab[]; // dynamic array of bytes
class Thing;
task automatic test(ref dab data);
data = new[4];
data[0] = 0;
data[1] = 1;
data[2] = 2;
data[3] = 3;
endtask
endclass
endpackage

and then, in your module,

module top;
import thing_pkg::*; // get "typedef dab" and "class Thing"
initial begin : main
dab data; // same effect as "byte data[];"
Thing thing = new;
thing.test(data);
$display("data has %0d elements", data.size());
foreach (data)
$display("data[%0d] = %0d", i, data);
end
endmodule

But it works for me, with or without the typedef.

By the way: tasks and functions in a class have automatic
lifetime by default, so your "automatic" keyword is harmless
but redundant. And while we're on that issue, please don't
ever fall into the trap of confusing

class Mumble;
static task ST()... // class-wide task
task static TS()... // method with static lifetime

Oh, and one last thing: Your task "test" does not block -
it never consumes simulated time - so it would be better
coded as a void function. Try to reserve tasks for
activity that blocks by waiting for time delays or events.
--
Jonathan Bromley, Consultant

DOULOS - Developing Design Know-how
VHDL * Verilog * SystemC * e * Perl * Tcl/Tk * Project Services

Doulos Ltd., 22 Market Place, Ringwood, BH24 1AW, UK
jonathan.bromley@MYCOMPANY.com
http://www.MYCOMPANY.com

The contents of this message may contain personal views which
are not the views of Doulos Ltd., unless specifically stated.
 
On Aug 28, 11:30 am, Jonathan Bromley <jonathan.brom...@MYCOMPANY.com>
wrote:
On Tue, 28 Aug 2007 14:44:32 -0000, mrfirmware wrote:
On Aug 28, 10:16 am, Jonathan Bromley wrote:
On Tue, 28 Aug 2007 13:54:20 -0000,

mrfirmware <mrfirmw...@gmail.com> wrote:
Ah, elaboration is something like linking then.

Somewhat, but of course it does all the static construction of the
instantiated module hierarchy.

That's just a bit over my head.

Nope. It's the dynamic construction that you OOP guys do that
goes over *our* heads. You see, it's kinda tough to build
hardware on-the-fly, so wee need a language that can specify
the static structure of the program in some detail...

Oh for Pete's sake. So my top.sv file has to be the last file
specified? What a PITA but okay, now I know. Thank you for that bit of
knowledge as it will save me hours of futzing around. I never would
have guessed the order in which you specified independent source files

Independent? When the second one uses a data type (class)
that was defined by the first? I don't think so. If you really
want that independence, at any cost, we can talk about type
parameters. But that is in bandit country...
Okay, point taken.

to a compiler would matter but then again I've been doing embedded
software for the last 20 years so what do I know about SV? :)

No, it's just that you're stuck with C's palaeolithic
textual-include mechanism for grabbing existing bits of Stuff.
Most SV tools proceed by compiling design units (=packages,
modules, interfaces, programs) into one or more libraries.
Once a package is compiled into a library, you can import
it into other compilations at any future time. As you said,
Palaeolithic!? Well I never. :)
How else do you tell a compiler how a particular function looks w/o a
prototype?

As long as I compile top.sv last, I can compile my
packages independently and in any order? That's not so bad.

"In any order" as long as they don't import one another,
of course.
Yup.

I think this is just trouble with type syntax...
???

module top
import thing_pkg::*;

initial begin : main // Yes, a C programmer I am

byte data[];
Thing thing = new;

thing.test(data);

end

That looks fine to me.

[thing.sv]
package thing_pkg;
class Thing;
task automatic test(ref data[]);

At the very least this should be (ref byte data[]).
I would be a lot more comfortable if you had created
a typedef:
It was, typo here only.

package thing_pkg;
typedef byte dab[]; // dynamic array of bytes
class Thing;
task automatic test(ref dab data);
data = new[4];
data[0] = 0;
data[1] = 1;
data[2] = 2;
data[3] = 3;
endtask
endclass
endpackage

and then, in your module,

module top;
import thing_pkg::*; // get "typedef dab" and "class Thing"
initial begin : main
dab data; // same effect as "byte data[];"
Thing thing = new;
thing.test(data);
$display("data has %0d elements", data.size());
foreach (data)
$display("data[%0d] = %0d", i, data);
end
endmodule

But it works for me, with or without the typedef.

Using your code exactly (well I use top_tb and have an empty top
module to fit my make template), it doesn't. It's not a vlog problem,
he's happy. It's vsim. Vsim comes up and loads top and thing and then
states:

vlog -nologo -noincr -lint -source -hazards -libmap ./out/top -work ./
out/top -timescale 1ns/1ps thing.sv top.sv
-- Compiling package thing_pkg
-- Compiling module top
-- Compiling module top_tb
-- Importing package thing_pkg

Top level modules:
top
top_tb
vsim -lib ./out/top -title top -l ./out/top.vsim.log -t 1ns -c top_tb

Reading /fpga_tools/modelsim/questa6.2c/questasim/tcl/vsim/pref.tcl
PathSeparator must be a single character <-- I hate this.

# 6.2c

PathSeparator must be a single character
# vsim -l ./out/top.vsim.log -lib ./out/top -c -t 1ns top_tb
# ** Note: (vsim-3812) Design is being optimized...
# ** Note: (vsim-3865) Due to PLI being present, full design access is
being specified.
# Loading /fpga_tools/xilinx/9.2/Xilinx/smartmodel/lin/installed_lin:/
lib/linux.lib/swiftpli_mti.so
# // QuestaSim 6.2c Aug 26 2006 Linux 2.6.22.4-65.fc7
# //
# // Copyright 2006 Mentor Graphics Corporation
# // All Rights Reserved.
# //
# // THIS WORK CONTAINS TRADE SECRET AND
# // PROPRIETARY INFORMATION WHICH IS THE PROPERTY
# // OF MENTOR GRAPHICS CORPORATION OR ITS LICENSORS
# // AND IS SUBJECT TO LICENSE TERMS.
# //
# Loading /fpga_tools/modelsim/questa6.2c/questasim/linux/../
sv_std.std
# Loading ./out/top.thing_pkg(fast)
# Loading ./out/top.top_tb(fast)
# ** Error: (vsim-8282) top.sv(8): Actual argument expression for ref
formal "(null)" is not an equivalent type.
# Region: /top_tb
# Error loading design

This it very frustrating. I can't tell if it's the class side or the
caller side that has the problem.

By the way: tasks and functions in a class have automatic
lifetime by default, so your "automatic" keyword is harmless
but redundant. And while we're on that issue, please don't
ever fall into the trap of confusing

class Mumble;
static task ST()... // class-wide task
task static TS()... // method with static lifetime
Good to know, I've removed automatic. Thanks for the excellent tip
about word order with 'static'. That would have tripped me up to be
sure.

Oh, and one last thing: Your task "test" does not block -
it never consumes simulated time - so it would be better
coded as a void function. Try to reserve tasks for
activity that blocks by waiting for time delays or events.
Agreed.

Thanks,

- Mark
 
On Tue, 28 Aug 2007 16:01:41 -0000, mrfirmware wrote:

PathSeparator must be a single character <-- I hate this.
I think you're doing something a little odd with the -libmap
and -work options, but I'm not sure... check out the vlib
and vmap commands to save yourself some typing and hassle.

hmmm, I wonder if this is a limitation in 6.2c. I'm using
6.3 and it works just fine. Time for an upgrade? MTI
have been fixing errata and adding SV feature coverage at
a dizzying rate over the past year or so...
--
Jonathan Bromley, Consultant

DOULOS - Developing Design Know-how
VHDL * Verilog * SystemC * e * Perl * Tcl/Tk * Project Services

Doulos Ltd., 22 Market Place, Ringwood, BH24 1AW, UK
jonathan.bromley@MYCOMPANY.com
http://www.MYCOMPANY.com

The contents of this message may contain personal views which
are not the views of Doulos Ltd., unless specifically stated.
 
On Aug 28, 12:29 pm, Jonathan Bromley <jonathan.brom...@MYCOMPANY.com>
wrote:
On Tue, 28 Aug 2007 16:01:41 -0000, mrfirmware wrote:
PathSeparator must be a single character <-- I hate this.

I think you're doing something a little odd with the -libmap
and -work options, but I'm not sure... check out the vlib
and vmap commands to save yourself some typing and hassle.

# 6.2c

hmmm, I wonder if this is a limitation in 6.2c. I'm using
6.3 and it works just fine. Time for an upgrade? MTI
have been fixing errata and adding SV feature coverage at
a dizzying rate over the past year or so...
Will do on both counts. Thanks so much for all your help.

Cheers,
- Mark
 

Welcome to EDABoard.com

Sponsor

Back
Top