There are cases when it is useful to be able to build more complex types from existing types. ACT provides a mechanism to do so via interfaces and parameter types.
An interface is defined in the following way:
interface linearchain (bool? in; bool! out);
This defines linearchain
to be an interface definition, where the interface has two ports: in
and out
.
Any process can export a list of interfaces. When a process exports an interface, it means that it has I/O ports that correspond to the names in the interface. The port names within the process need not match the port names in the interface; when an interface is exported, a mapping must be provided as part of the interface export specification.
defproc proc1 (bool? a; bool! b) :> linearchain { in -> a, out -> b } { ... }
In this definition, proc1
exports the linearchain
interface, except that the in
port of the interface is mapped to a
, and the out
port of the interface is mapped to b
. If multiple interfaces are exported, they are simply separated by commas.
The special ptype
meta-parameter type is used to pass in types
into a process definition. These types can be used to build a process
using other processes as building blocks. The syntax for using a
ptype
is the following:
ptype(foo) x;
This says that x
is a variable that is a type, with the
constraint that x
must satisfy the type signature specified by
interface foo
. In other words, x
is guaranteed to have the
ports corresponding to interface type foo
.
ptype
parameters can also be used in templates. Consider the
following example:
// A constructor for a datapath with W-bit ripple connections, and // where each component has an additional M inputs and one output // Interface definition template<pint W, pint M> interface bitslice (e1of2? rin[W]; e1of2! rout[W]; e1of2? in[M]; e1of2! out); // the constructor template<pint N, pint M, pint W, ptype(bitslice<W,M>) t> defproc build_dpath (e1of2? rin[W]; e1of2! rout[W]; e1of2? in[M*N]; e1of2! out[N]) { t x[N]; // array of type "t" that exports a bitslice<W,M> interface // ripple connections (i:N-1: x[i].rout=x[i+1].rin;) x[0].rin=rin; x[N-1].rout=rout; // i/o connections (i:N: x[i].in = in[i*M..(i+1)*M-1]; x[i].out=out[i]; ) } // A one-bit adder, that exports the bitslice interface defproc onebit (e1of2? in[2], rin[1]; e1of2! out, rout[1]) :> bitslice<1,2> { in -> in, rin -> rin, out -> out, rout -> rout } { ... } defproc ripple_adder (e1of2? a[32], b[32], cin; e1of2! out[32], cout) { build_dpath<32,2,1,@onebit> dp; (i : 32 : dp.in[2*i] = a[i]; dp.in[2*i+1] = b[i];) dp.out = out; dp.rin[0] = cin; dp.rout[0] = cout; }
Process type (ptype
) parameters for templates use the @
character (as in @onebit
) in the example above.