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.
An interface type can also include function and macro prototypes.
export template<pint N> interface policy() { methods { function idx() : int<N>; macro update(int<N> v); } }
This defines an interface that exports two methods. Note that, unlike port parameters, method names cannot be changed when a type exports an interface.