Array, loops and selection

Complex datapath designs are often designed with array of simpler cells. The following example show how to create array of simple cells and connect them using loop constructs in ACT.

import "adder.act";

defproc  adder8b ( bool? a[8],b[8],ci; bool! s[8],co)
{
  bool c[9];
  fulladder fa[8];
  
  c[0] = ci;
  co = c[8];
  ( i : 8 : fa[i](a[i], b[i], c[i], s[i], c[i+1]);)  
}

The statement fulladder fa[8]; creates an array with 8 instances of full adder and the carry chain between adders is connected by bool array c. The statement (i:8: ….) implements a loop with index i and its value runs from 0 to 7.

Here are different ways of writing the same loop using another variant of signal connection.

(i : 8 : fa[i].a=a[i]; fa[i].b=b[i]; fa[i].ci=c[i]; fa[i].s=s[i]; fa[i].co=fa[i+1].ci; )
(i : 8 : fa[i](.a=a[i], .b=b[i], .ci=c[i], .s=s[i], .co=fa[i+1].ci) )

An instance of this adder is then created in a separate file as:

import “adder8b.act”;

adder8b fa8; 

Script for simulating large array in prsim

As you can see, the number of input/output increases significantly with each new bit added to the adder. The 8-bit adder has 17 boolean inputs and 9 boolean outputs. To simplify the process of assigning inputs and observing outputs, a group of nodes can be combined as a virtual node using keyword vector in prsim.

An example simulation script to combine nodes and simulate in prsim is shown below:

initialize
set fa8.ci 0
vector fa fa8.a[7] fa8.a[6] fa8.a[5] fa8.a[4] fa8.a[3] fa8.a[2] fa8.a[1] fa8.a[0]
vector fb fa8.b[7] fa8.b[6] fa8.b[5] fa8.b[4] fa8.b[3] fa8.b[2] fa8.b[1] fa8.b[0]
vector fs fa8.co fa8.s[7] fa8.s[6] fa8.s[5] fa8.s[4] fa8.s[3] fa8.s[2] fa8.s[1] fa8.s[0]

vset fa 10
vset fb 12
cycle
vget fa
vget fb
vget fs

vset fa 255
vset fb 121
cycle
vget fa
vget fb
vget fs

Here, command vector fa fa8.a[7] … fa8.a[0] is used to combine 8 bits of input a as vector fa. The command vset and vget are used to set and get values for the vector.

Selection

The example below shows how selection statement is used for conditional execution.

import "gates.act";

defproc select (bool x0[8], x1[8]; bool y[8], z[8])
{
    ( i : 8 : [  (i%2) = 0 -> x0[i] = y[i]; x1[i] = z[i];
                [] (i%2) = 1 -> x0[i] = z[i]; x1[i] = y[i];
                ]
    )
}

Depending on the value of index i, input x0/x1 are assigned to output y or z. If i is even, x0 is assigned to y and x1 is assigned to z. If i is odd, x0 is assigned to z and x1 is assigned to y.

Checking library dependencies

For a hierarchical design with many imported libraries, it could be useful to get dependency information and see if all the libraries are present in the directories where ACT can find them. The command adepend is used to check dependencies.

$ adepend adder8b.act
adder8b.act:  adder.act   gates.act

Here, running adepend on adderb8.act shows that it depends on the adder.act and gates.act.