ACT Library
Loading...
Searching...
No Matches
The ACT Library

This contains the documentation for the APIs provided by the core ACT library, available via github at https://github.com/asyncvlsi/act The top-level API is provided by the Act class. This class is used to read in an ACT design file and provides basic operations such as merging in additional files into the design and expanding the design. After a file is read in, core data structures that represent the entire design are created and available for manipulation. The core data structures represent all aspects of the design in a hierarchical fashion.

The basic usage of the library is the following:

  1. Read in the ACT files to be processed.
  2. Expand the design.
  3. Access and potentially transform the expanded circuit definitions.

Before any of these steps, the Act library should be initialized via the call:

Act::Init (&argc, &argv);
static void Init(int *argc, char ***argv, const char *optional_conf)

Here argc/argv are the standard C command-line arguments. The common ACT command-line arguments are extracted by this process.

Step 1: Reading in files

In this step the ACT files are parsed, and the syntax is type-checked to identify potential errors in the input. Files may be rejected at this stage, in which case the library will exit with a fatal error message along with information to help the user identify the location and cause of the error.

To read in a design contained in the ACT file test.act, use

Act *a = new Act ("test.act");
The main Act class used to read in an ACT file and create basic data structures. All design informati...
Definition: act.h:334

The returned data structure can be used to access the entire design hierarchy. If additional ACT files need to be read in (beyond those imported directly from the original ACT file), then additional files can be merged into the Act data structure using

a->Merge ("extra.act");
void Merge(const char *s)

All instances and user-defined types are associated with a namespace (represented using the ActNamespace class). In the absence of a namespace specifier, instances/types are part of the default global namespace that is always present in the ACT data structures.

ActNamespace *ns = a->Global();
ActNamespace * Global()
Definition: act.h:619
The ActNamespace class holds all the information about a namespace.
Definition: namespaces.h:469

The global namespace can also be accessed using the static method ActNamespace::Global() for convenience in case the Act pointer is unavailable.

If an ACT file contains multiple namespaces, then a specific namespaces can be accessed as follows:

ActNamespace *arith_ns = a->findNamespace ("arithmetic");
ActNamespace * findNamespace(const char *s)

The names of user-defined types (processes, channels, data types) at this stage in the design correspond to the name in their ACT definitions. For example, the process

template<pint N> defproc adder (bool a[N], b[N], out[N]) { ... }

can be found via its name "adder" within the namespace in which the type is defined. If this was defined in the global namespace and included in the test.act, then the data structure for the process can be accessed using

Process *p = a->findProcess ("adder");
Process * findProcess(const char *s, bool allow_expand=false)
User-defined processes.
Definition: types.h:750

If, instead, the adder was defined within the arithmetic namespace, then it can be accessed using

Process *p = a->findProcess (arith_ns, "adder");

Step 2: Expanding the design

In this step, the design is expanded/elaborated. ACT permits designs to be specified in a parameterized fashion. For example, a user could design an N-bit adder. In this step, all parameters are expanded out into their actual values, and the values are substituted throughout the design. At this stage, all array dimensions are finalized, and so any incompatibilities in array sizes/connections can also result in an error being reported. Other errors that can be reported in this stage include assertion failures, as well as type override errors.

To expand the Act data structure, use:

Act *a = new Act("test.act");
a->Expand();
void Expand()

At this stage, the expanded types can be found in the ACT data structures. For example, if the design included an instance of type "adder<8>", then the string "adder<8>" will get added to the namespace definition, and this corresponds to the definition of the adder with the value 8 substituted for N throughout its definition. For a type definition without any template parameters, the expanded definitions will have empty angle brackets after them. For example, an and gate called AND2X1 without any parameters will be expanded to AND2X1<>. Both the unexpanded definitions and expanded definitions can be found in the namespace.

Reading in expanded processes operates in the same way as earlier:

Process *p = a->findProcess ("adder<8>");

This will return an expanded process (or NULL if not found).

Integer template parameters are added to the type name for expanded types as described above. Multiple parameters will be separated by commas. Boolean template parameters are printed as either t or f (for true and false), and real parameters appear as real numbers. Arrays of parameters are specified using curly braces to demarcate the array, followed by a comma-separated list of array element values. This is used for both one-dimensional as well as multi-dimensional arrays, since the number of dimensions and the shape of the array is known.

In addition to substituting values of parameters, the expansion process will also eliminate all conditional and loop constructs from any definitions. This means that an expanded type will contain data structures corresponding to the names of instances and their expanded types, connection information, and expanded sub-language definitions (if any).

Step 3: Access and manipulate designs

Most of the work in manipulating a design operates on the expanded ACT description. This starts with accessing the data structure for a namespace or user-defined type. While findProcess() can be used to find a user-defined process, other user-defined types (channel and data types) can be accessed using

UserDef *u = a->findUserdef ("datatypename");
UserDef * findUserdef(const char *s)
UserDef stores information that is common to all user-defined types. User-defined types are more comp...
Definition: types.h:310

The data structures for user-defined types have APIs that can be used to access/manipulate the design. The primary data structures are namespaces and user-defined types. Namespaces contain global instances and connections, definitions of nested namespaces, and user-defined types. User-defined types contain their port and template parameters, instances within the user-defined type and connections, and any sub-language bodies. The global namespace can also contain sub-language bodies.

A commonly used pattern is to apply some analysis/transformation to every process/user-defined type in the user design, starting from some top-level process name. Act has a built-in notion of an Act pass (supported by the ActPass class) that includes traversal methods/etc.

Unexpanded designs

When a design is unexpanded, the primary data structures hold unexpanded values. The design information is contained within the ActBody data structure associated with each namespace and user-defined type (a UserDef). In addition, names that are associated with instances types are also available in the instance tables in each ActNamespace and UserDef.

Expanded designs

Expanded namespaces and user-defined types no longer contain any ActBody references. Instead, the precise list of instances are available via the ActNamespace or UserDef. The main data type used to represent an instance is a ValueIdx. In addition, each instance and name has an associated act_connection structure. This connection maintains connectivity information and can be used to determine local connectivity information within a user-defined type or namespace.

The ACT library provides a number of iterators (in iter.h) that can be used to walk through elements of a number of different data structures.

ACT Passes

The standard ActPass library contains a collection of pre-defined passes that are used by many of the standard ACT tools. Each pass has an associated class name and a string name. These passes are combined into the ACT pass library (libactpass.a or libactpass_sh.so) and installed with the ACT repository.

The standard passes are:

Pass Name Class
booleanize ActBooleanizePass
sizing ActSizingPass
prs2net ActNetlistPass
prs2cells ActCellPass
collect_state ActStatePass
apply ActApplyPass
finline ActCHPFuncInline
chpmem ActCHPMemory
chparb ActCHPArbiter

Name mangling

Expanded ACT type names can contain characters like <, >, and , (among others). Instances can have names like a[3].b[5].z, including the characters [, ], and .. When exporting an ACT design to another format for use by a third-party tool, names with such characters in them can be potentially problematic. A good example of this is when exporting a SPICE netlist—different versions of SPICE have different syntactic restrictions. To handle this in a disciplined manner, the ACT library has the notion of a //mangled// name. A mangled name is generated by re-writing a user-specified list of special characters with an underscore and a number/character combination. This mapping is invertible, so a name can be unmangled as well. The set of characters to be mangled is specified in the ACT configuration option act.mangle_string.

The standard name mangling prefix character is an underscore. Name mangling operates character-by-character as follows:

  1. An underscore is replaced by two underscores.
  2. A character that is not in the mangle string is a pass-through, so it is not modified.
  3. If a character is at position k in the name mangling string, it is replaced with an underscore followed by k. The position character is 0 to 9 for positions 0 to 9, followed by a-z. Up to 36 characters can be mangled.

Name mangling can at most double the length of the string. Various APIs to mangle and unmangle names are part of the Act class, such as Act::mfprintf() and Act::msnprintf().

Process names have a special case in terms of name mangling. If an expanded process has no parameters, its mangled name is obtained simply be omitting the trailing <>.