ECE/CS 314: Computer Organization Fall 2004

Project 3: Logic Design
Cast Reference

CAST and IRSIM

There are manpages for irsim on the student machines. If you want to learn about all the irsim commands, try man irsim.

Here is an example of a CAST file, with comments explaining the different parts. Please read the file that describes 314/parts.cast for information about the building blocks being used below.

/* import standard definitions of two-input NAND, two-input NOR,
   inverter, and flops */
import "314/parts.cast";

/* define two-input And using Nand and inverter */
define And2() (node a, b, out)
{
  node x; // declare intermediate node

  Nand2() (a,b,x); // create two-input nand, output is x
  Inv() (x,out); // invert x to get out
}

/* define two-input Or using Nor and inverter */
define Or2() (node a, b, out)
{
  node x; // declare intermediate node

  Nor2() (a,b,x); // create two-input nor
  Inv() (x,out);
}

While this CAST file defines And2 and Or2, it doesn't create any circuits. Let's say we save this CAST file as foo.cast, and now want to create a circuit with combinational logic that computes out = a AND b OR c. The following file defines this circuit, using the definitions we've just created:

import "foo.cast"; // get my definitions

node a, b, c; // declare boolean-valued inputs
node out; // declare boolean-valued output
node x; // intermediate node

And2() (a,b,x);
Or2() (x,c,out);

If this were saved in file.cast, running

prs2sim file.cast

generates file.sim and file.al, that can be simulated with irsim by running:

irsim.sh file.sim file.al
Some commonly used irsim commands can be found here .

We can instantiate a positive edge-triggered flop by saying;

posFLOP() (inputnode, outputnode);

This instantiates a single flop with input inputnode, and output outputnode. This can be used to create state-holding elements and to build finite-state machines. Don't forget to import 314/parts.cast before trying to create a flop, since this file contains the definitions for posFLOP.

Loops
  Let's say we wanted to define a block that took two sets of 8 one-bit inputs, ANDed the correspond bits of the two inputs, and produced 8 one-bit outputs. A convenient way to group signals together is to use an array. The definition of this block would look like:
import "myparts.cast";  // get my definitions

/* Note the way the array of inputs and outputs is declared. In this
   example, node[8] is the type specifying an array of 8 nodes. */
define BlockAnd() (node[8] a,b, out)
{
   node[8] x;

   Nand2() (a[0],b[0],x[0]);
   Inv() (x[0],out[0]);

   Nand2() (a[1],b[1],x[1]);
   Inv() (x[1],out[1]);

   /* this is getting tedious... */
   ...

   Nand2() (a[7],b[7],x[7]);
   Inv() (x[7],out[7]);
}
To avoid all this typing, CAST supports a syntactic loop construct. Using this construct, the same circuit as the one shown above would be written as:
import "myparts.cast";  // get my definitions

/* Note the way the array of inputs and outputs is declared. In this
   example, node[8] is the type specifying an array of 8 nodes. */
define BlockAnd() (node[8] a,b, out)
{
   node[8] x;

   <i:8: Nand2() (a[i],b[i],x[i]); Inv() (x[i],out[i]); >
}
Note that the two ways to describe the BlockAnd result in identical circuits. The loop construct is just a convenience; the loop would be expanded out before the circuit is created.