SystemVerilog - building multiple file hierarchies: include

D

David Antliff

Guest
I'm exploring the use of SystemVerilog in the context of OVM. I like
to create multiple source files, each dealing with a particular aspect
of the task at hand. I'm familiar with C-style #include & linker
mechanisms, and the Python package mechanism, but SV seems to provide
for both.

I'd like to know what the Best Practice is for managing this hierarchy
of files and layers. It seems to me that there are at least three
options:

1. files that refer to resources in other files simply `include what
they need. Seems to me that could lead to some horrendous 'compilation
unit' issues. A lot of the textbook examples use this system, but I
can't see it working well with large projects.

2. every file declares itself as a package, and other files import
those packages as they need to. However I believe a package
declaration is restricted to a single file, so that makes it difficult
to refactor a package into multiple files without making all of them
packages too.

3. a hybrid approach where a package is defined as being a certain
aspect of functionality, and if this involves multiple files then
these are `included but are not packages themselves. In OVM, such a
scheme might involve an Agent package containing one or more agents,
that `includes the constituent drivers, monitors, etc.

My chief concern is the scalability of these mechanisms. I want the
OVM structure to be as flexible and scalable as possible, so that new
OVC classes can be easily specialised and included with the top level
testbenches. If a particular specialisation is deemed suitable for the
main OVM framework, it would be good to have an easy way to add it to
the existing hierarchy.

What would you suggest?
 
On Dec 4, 5:14 pm, David Antliff <david.antl...@gmai_.com> wrote:
I'd like to know what the Best Practice is for managing this hierarchy
of files and layers.
....
1. files that refer to resources in other files simply `include what
they need.
....
2. every file declares itself as a package, and other files import
those packages as they need to.
....
3. a hybrid approach where a package is defined as being a certain
aspect of functionality, and if this involves multiple files then
these are `included but are not packages themselves.
....
What would you suggest?

I've spent some more time thinking about this problem and in the
absence of any other advice, it seems the best solution is #3, where a
single 'package' file `includes related files.

For example, an Agent utilises a Driver, Monitor and Sequencer, so one
might do:

--- file: top.sv ---
....
import agent_pkg::*;
....
--- EOF ---


--- file: agent_pkg.svh ---
package AgentPkg;
`include driver.sv
`include monitor.sv
`include sequencer.sv
endpackage;
--- EOF ---


Then driver, monitor & sequencer.sv files are all written with
guardians to avoid multiple definition, thus:

--- file: driver.sv ---
`ifndef DRIVER_SV
`define DRIVER_SV
....
`endif
--- EOF ---


So this combination of import and `include allows a level of
abstraction to be placed over the lower-level components.

Does this sound typical or good practice?


What might work better is if there was some way to add multiple files
to the same Package, rather than the current 1-package:1-file
relationship that seems to exist in SV. I guess `include can do this
but it just seems a bit nasty including implementation... it's like
#include-ing a C source (not header) file - not usually a good idea!
 
On Dec 8, 2:46 am, David Antliff <david.antl...@gmail.com> wrote:

I'd like to know what the Best Practice is for managing this hierarchy
of files and layers.
Like C, Verilog doesn't restrict you to "one gizmo per file".
However,
anything in a single file will of course be compiled all together, so
obviously you need to think about the organization of source files
with that in mind.

1. files that refer to resources in other files simply `include what
they need.
Lots of people do this but, as you say, it doesn't scale very well.

2. every file declares itself as a package, and other files import
those packages as they need to.
But that can lead to a plethora of microscopic packages, confusing
the relationship among things and making intelligent OO programming
difficult.

3. a hybrid approach where a package is defined as being a certain
aspect of functionality, and if this involves multiple files then
these are `included but are not packages themselves.
That sounds roughly right. Keep the source files manageably small
(one class definition in each?) but gather them together into
packages of closely related definitions. Importing just one
package then gives you everything you need to use that set of
functionality.

For example, an Agent utilises a Driver, Monitor and Sequencer, so one
might do:

--- file: top.sv ---
...
import agent_pkg::*;
...
--- EOF ---

--- file: agent_pkg.svh ---
package AgentPkg;
`include driver.sv
`include monitor.sv
`include sequencer.sv
endpackage;
--- EOF ---

Then driver, monitor & sequencer.sv files are all written with
guardians to avoid multiple definition, thus:

--- file: driver.sv ---
`ifndef DRIVER_SV
`define DRIVER_SV
...
`endif
--- EOF ---

So this combination of import and `include allows a level of
abstraction to be placed over the lower-level components.

Does this sound typical or good practice?
Yes. To be honest, though, many users doing OO SV (as you do
for OVM, of course) simply write one class or group of classes
per source file, and then write just one mega-package that
`includes all those source files. With sentinels, of course;
and probably with a big list of "typedef class" at the
beginning so you don't need to worry about the right order
to do the `includes.

What might work better is if there was some way to add multiple files
to the same Package, rather than the current 1-package:1-file
relationship that seems to exist in SV. I guess `include can do this
but it just seems a bit nasty including implementation... it's like
#include-ing a C source (not header) file - not usually a good idea!
The hot-off-the-press (actually hot-on-the-press, it's not published
yet)
SV-2009 standard has a nice new "package export" mechanism that allows
you to combine packages into larger packages. The following example
is untried (not surprising, since the tools don't yet support this!)
but should give you the right idea:

package p1;
class C1; ...
endpackage : p1;
<EOF>

package p2;
class C2; ...
endpackage : p2;
<EOF>

package p3;
import p1::*;
import p2::*;
export *::*; // give away p1, p2 contents!
...
... // p3 package items can use stuff from p1, p2
class C3; ...
endpackage
<EOF>

module Top;
import p3::*; // makes C1, C2, C3 all visible
...
endmodule

in other words, you can compose smaller packages into "super-packages"
that allow you to have access to all the smaller packages' contents
just by importing the super-package. This opens the door to many
alternative models of package/class/sourcefile organization.
In SV-2005 you would be obliged to import all three packages
into the client module Top. SV-2009 allows you to use one package
(p3) to hide the organization of a bunch of other packages.

There's a bit more to package export than this, but perhaps this
sketch will whet your appetite enough for you to put pressure on
tool vendors to implement package export sooner rather than later!
--
Jonathan Bromley
 
With apologies for replying to myself, but I need to set the
record straight:

The following example is untried (not surprising, since the
tools don't yet support this!)
The latest version of at least one simulator is already
supporting package export, so I *could* try it; and
I got a small surprise. "export *::*" didn't export
things unless they had been explicitly imported into
the super-package; "import subpackage::*" was not enough.
I'm not 100% sure this is correct.... hmmm. Time to
check... I'll try to report back after I've dug around
a little. Meanwhile, credit to Vendor A for getting
ahead of the game, and time to give Vendors B and C a
gentle shove!
--
Jonathan Bromley
 
On Dec 9, 3:08 am, Jonathan Bromley <s...@oxfordbromley.plus.com>
wrote:
On Dec 8, 2:46 am, David Antliff <david.antl...@gmail.com> wrote:
So this combination of import and `include allows a level of
abstraction to be placed over the lower-level components.

Does this sound typical or good practice?

Yes.  To be honest, though, many users doing OO SV (as you do
for OVM, of course) simply write one class or group of classes
per source file, and then write just one mega-package that
`includes all those source files.  With sentinels, of course;
and probably with a big list of "typedef class" at the
beginning so you don't need to worry about the right order
to do the `includes.

Thank you Jonathan for your reply. You've pretty much addressed my
question perfectly.

Am I right in my assumption that (currently) a SV package declaration
is restricted to a single file? The newer feature you describe does
seem to open the doors to more sensible hierarchies.

-- David.
 
On Dec 8, 11:07 pm, David Antliff <david.antl...@gmail.com> wrote:

Am I right in my assumption that (currently) a SV package declaration
is restricted to a single file?
No, not at all. Traditionally Verilog compilers take little notice
of physical file boundaries. So you can easily create a package
that's distributed across several files, and then do...

<your_compiler> pkg_part1.v pkg_part2.v pkg_last_part.v

However, in SystemVerilog the boundaries of physical files have
become somewhat significant (thanks to the ability to put
declarations outside of any package, module or other scope).
Consequently a compiler that is given more than one file to
compile is able to behave in either of two ways:
either
- concatenate all the files into one big source text, and
compile that in a single hit (traditional Verilog behaviour)
or
- run the compiler individually on each separate file

Tools are expected to offer a command-line switch to select
this behaviour; the LRM does not mandate a default. For
example, in Mentor's tools (Questa/Modelsim) the default
is to compile each file individually, and the switch -mfcu
("multi file compilation unit") enables concatenate-the-sources
behaviour.

Clearly, then, my imaginary compile command with its package
split across three separate source files would need the -mfcu
switch to work properly. Alternatively, as we discussed
earlier, you could write a wrapper file
<file package_top.v>
`include "pkg_part1.v"
`include "pkg_part2.v"
`include "pkg_last_part.v"
<EOF>
and then compile just the wrapper. Either way you get the
ability to split the source code of your package across
multiple files.

It is equally easy and acceptable to put more than one
package, module or whatever in a single file.

Despite all this, my pragmatic advice would remain:
write one class (or a small group of closely related
classes) per source file, and then write a package
that `includes all those class files thereby putting
them all into a single package. And you have only
one file (the top, `include-ing package) to compile,
and its content clearly defines and documents the set
of classes that you are choosing to put into the package.

The newer feature you describe does
seem to open the doors to more sensible hierarchies.
Certainly it allows a somewhat hierarchical use model
for packages. I can easily see that being valuable
to IP vendors who wish to conceal (or abstract) the
internal organisation of their IP deliverable, and
make it available to the user through a single import.
--
Jonathan Bromley
 
On Dec 9, 10:34 pm, Jonathan Bromley <s...@oxfordbromley.plus.com>
wrote:
Despite all this, my pragmatic advice would remain:
write one class (or a small group of closely related
classes) per source file, and then write a package
that `includes all those class files thereby putting
them all into a single package.  And you have only
one file (the top, `include-ing package) to compile,
and its content clearly defines and documents the set
of classes that you are choosing to put into the package.
Thank you Jonathan, I've taken this advice to heart and so far it
seems to be working well.

-- David.
 

Welcome to EDABoard.com

Sponsor

Back
Top