====== Basic gate-level simulation ====== Gates in the ACT language are specified using production rules, which can specify the Boolean logic for the pull-up and pull-down switching networks for a gate. Since production rules are general enough to specify arbitrary pull-up and pull-down networks, ACT can be used to describe both synchronous and asynchronous circuits. The ACT language contains many constructs that can be used to create design hierarchy, simplifying the description of the circuit. Components can be arrayed, grouped together, or connected to each other using simple constructs. The following ACT file describes a process that corresponds to one inverter: defproc inv (bool? in; bool! out) { prs { in -> out- ~in -> out+ } } The parameters in parentheses are the ports for the process (i.e. what you can connect to externally), and the signals are of type ''bool'' to indicate they are Boolean-valued variables. Direction flags (''!'' and ''?'') are used to specify that ''in'' is an input, and ''out'' is an output. Assuming the file above is called ''inv.act'', the following ACT file can be used to create a single inverter: import "inv.act"; inv i; This program imports the previously defined ACT file, and then creates an /instance/ of an inverter called ''i''. The process ''inv'' (technically ''inv<>'', an inverter without template parameters) can be viewed as the type of the instance ''i''. ===== Simulating with prsim ===== If the file above is called ''test_inv.act'', a production rule file can be created from the ACT file by: % aflat test_inv.act > test_inv.prs The output file is the following: "i.in"->"i.out"- ~"i.in"->"i.out"+ Note that ACT uses ''.'' (like standard programming languages) as a separator between the name of the instance and internal nodes within it. (Note that magic, irsim use ''/'' as a separator; Xyce uses colon). If the file is saved as ''test_inv.prs'', it can be simulated using the production rule simulator called ''[[tools:prsim|prsim]]''. % prsim inv.prs (Prsim) initialize (Prsim) watch i.in (Prsim) watch i.out (Prsim) status X (Prsim) set i.in 0 (Prsim) cycle (Prsim) set i.in 1 (Prsim) cycle ''prsim'' will check if the production rules being run are stable and non-interfering. It doesn't check all possible delay configurations, but just reports errors if it observes unstable or interfering production rules while the simulation is running. Try ''help'' as a ''prsim'' command to see the range of commands supported by ''prsim.'' One of the useful features of ''prsim'' is that it can automatically randomize the delays of production rule firings. To do this, use (Prsim) random After this command, all delays are randomized. This is a useful test to see if your production rules are stable and non-interfering. If ''prsim'' finds that a production rule is unstable, it sets its output to ''X'' (for undefined). These ''X''s can propagate through the circuit. Local variables can be defined in ACT in the usual way. defproc sigbuf (bool? in; bool! out) { bool mid; prs { in -> mid- ~in -> mid+ mid -> out- ~mid -> out+ } } In this example, ''mid'' is a local variable and cannot be accessed from outside the process. Note that all Booleans used in production rules have to be declared before they are used. defproc invarray (bool in[8], out[8]) { inv x[8]; (i : 8 : x[i].in = in[i]; x[i].out = out[i]; ) } This process creates an array of 8 inverters. The second statement is a [[language:controlflow|loop construct]]. The loop index is ''i'', the range is ''0'' to ''7'', and the body of the loop contains two statements: ''x[i].in = in[i]'', and ''x[i].out = out[i]''. Both of them connect two signals to each other.