Processes and cells
A process is a user-defined type that corresponds to a circuit entity. Other hardware description languages sometimes call it a module or a subcircuit. The basic syntax of a process definition is shown below.
defproc test (bool n, m; bool p, q) { ... }
The definition above creates a new process, called test
, that has
a port list consisting of four bool
s. This port list cannot
contain any parameter types (pint
, etc).
If the body of the user-defined type is replaced by a single
semi-colon or is empty, the statement corresponds to a type
declaration. Declarations are typically used when defining
mutually recursive types. The declaration corresponding to type
test
is:
defproc test (bool n, m; bool p, q);
If the process is never defined, ACT assumes that it has an empty body. If a process declaration is followed by a definition, the type signature must match exactly.
defproc test (bool n, m; bool p, q); defproc test (bool n, m; bool p) { }
-[ERROR]-> Name `test' previously defined as a different process
A type can only have one definition in a given scope.
defproc test (bool n) { ... } defproc test (bool n) { ... }
-[ERROR]-> Process `test': duplicate definition with the same type signature
The body of a process specifies its implementation. This can use a combination of instances of other processes, connections, and other languages like production rules. Loops and conditional statements can also be used to construct a process.
Port lists have a syntax similar to instantiations. A type specifier can be followed by a list of identifiers rather than just a single identifier, similar to an instantiation. Semicolons are used to separate parameters of differing types, as shown in the example below.
defproc test2(bool n,m; d1of2 p,q) { ... }
In this example we assumed that there was a user-defined type (or
channel) called d1of2
that was used in the port list. Any
user-defined type in the port list must be either a data or channel
type. Processes are supposed to correspond to circuit blocks, and so
cannot be port parameters to other circuit blocks.
Square brackets can also be used following the identifier names to specify array ports. The meaning of these square brackets is identical to the ordinary array instantiation. However, the arrays in port lists are restricted to be dense arrays indexed at zero. This restriction is enforced by syntax, and will be reported as a parse error.
defproc test1 (bool a,b,c, d[10]) { } // success! defproc test2 (bool a,b,c, d[0..9]) { }
-[ERROR]-> Expecting token `]', got `.'
The ports themselves cannot be converted to sparse arrays within the body of a definition. This means that the following is illegal:
defproc test1 (bool a, b, c, d[10]) { bool d[11..12]; ... }
-[ERROR]-> Array instance for `d': cannot extend a port array
Type names and variable names do not share the same name space. Creating a type definition with the same name as an instance variable or vice versa is allowed, but deprecated.
Cells follow the same rules for definition as processes, except the
keyword defcell
is used in place of defproc
. The reason
for separating cells from processes is that processes are supposed to
correspond to logical entities that are meaningful semantic
objects. For example, a process ordinarily has its origins in a CHP
language description. Cells, on the other hand,
can be fragments of logical processes. Examples of cells are standard
gates like C-elements, NAND, or NOR gates, or commonly used circuit
structures like completion detection logic. Cells are distinguished
from processes to make it easier to write automation tools.