====== Creating a library of building blocks ======
A library can be created using pre-designed building blocks and use them in hierarchical designs. This can be achieved using keyword ''import''. In this case, ACT file begins with a sequence of "import" statements. The "import" looks for file in the current directory first, then in the colon-separated path specified by ''$ACT_PATH'', and finally in ''$ACT_HOME/act''.
ACT files can be imported in two ways:
(a) For simple projects, design files containing building blocks can be imported using keyword ''import''. For example, the ''gates.act'' file contains basic logic gates.
defproc nand2 (bool? a,b; bool! y)
{
prs {
a & b => y-
}
}
defproc and2 (bool? a,b; bool! y)
{
bool _y;
prs {
a & b => _y-
_y => y-
}
}
defproc or2 (bool? a,b; bool! y)
{
bool _y;
prs {
a | b => _y-
_y => y-
}
}
This file can be imported in a new ACT file ''xor2.act'' for creating XOR gate using basic logic gates.
import "gates.act";
defproc xor2 (bool? a,b; bool! y)
{
bool y1, y2;
nand2 N1 (a,b,y1);
or2 O1 (a,b,y2);
and2 A1 (y1,y2,y);
}
xor2 x;
(b) For complex projects involving a large number of ACT files, importing libraries can become complicated. For example, a project can have multiple ACT files containing different implementation of a design with same process name or different channels with same name. To keep names of process, channel, and types separate in such cases, ACT provides the option of namespace ([[language:introduction#namespaces|ACT namespaces]]).
The following example creates a namespace gates in file ''gates.act'' and defines process for basic logic gates within the namespace.
namespace gates
{
export defproc xor2 (bool? a,b; bool! y)
{
bool _a, _b;
prs{
a => _a-
b => _b-
(a & b) | (_a & _b) => y-
}
}
export defproc and2 (bool? a,b; bool! y)
{
bool _y;
prs {
a & b => _y-
_y => y-
}
}
export defproc or2 (bool? a,b; bool! y)
{
bool _y;
prs {
a | b => _y-
_y => y-
}
}
}
Note the use of the ''export'' keyword. By default, anything defined in a namespace is only visible within the namespace; it must be explicitly ''export''ed for it to be visible outside the namespace.
As shown below, this library is imported in a new ACT file ''adder.act'' to design full adder using logic gates defined in the library.
import "gates.act";
defproc adder (bool? a,b,ci; bool! s,co)
{
bool y1,y2,y3;
gates::xor2 X1(a, b, y1);
gates::and2 A1(a,b,y2);
gates::xor2 X2 (y1,ci,s);
gates::and2 A2(y1,ci,y3);
gates::or2 O1(y2,y3,co);
}
adder fa;
Finally, ACT supports another import format that is similar to those provided by object-oriented languages like Python and Java. Since ''gates.act'' defines the namespace ''gates'', it can be imported as follows:
import gates;
defproc adder (bool? a,b,ci; bool! s,co)
{
bool y1,y2,y3;
gates::xor2 X1(a, b, y1);
gates::and2 A1(a,b,y2);
gates::xor2 X2 (y1,ci,s);
gates::and2 A2(y1,ci,y3);
gates::or2 O1(y2,y3,co);
}
adder fa;
The ''import'' statement looks for ''gates.act'' (details are in [[language:namespaces|Namespaces]]), and imports it if it is found. It also checks that the namespace ''gates'' exists after the import.
Finally, if you are going to be using the ''gates'' namespace a lot, it can be added to the search path used to find type definitions as follows.
import gates;
open gates;
defproc adder (bool? a,b,ci; bool! s,co)
{
bool y1,y2,y3;
xor2 X1(a, b, y1);
and2 A1(a,b,y2);
xor2 X2 (y1,ci,s);
and2 A2(y1,ci,y3);
or2 O1(y2,y3,co);
}
adder fa;
===== Simulating with prsim script =====
Run simulation in prsim with script as:
$ aflat adder.act > adder.prs
$ prsim adder.prs < adder.scr
You could also run ''prsim'' and then source script as:
$ prsim adder.prs
(Prsim) source adder.scr
where ''adder.scr'' file contains the following commands:
initialize
set fa.a 0
set fa.b 0
set fa.ci 0
cycle
get fa.a
get fa.b
get fa.ci
get fa.s
get fa.co
set fa.a 0
set fa.b 0
set fa.ci 1
cycle
get fa.a
get fa.b
get fa.ci
get fa.s
get fa.co