Designing generic hardware in Cx

In the previous post, I explained what generic hardware is and what it is used for. In this post, I show how to create generic hardware with Cx.

How to make code generic

First, let's take a simple 8-bit counter example:

task Counter {
  out u8 dout;
  u8 count;
  void loop() {
    count++;
    dout.write(count);
  }
}

Note that this code is specific, i.e. the fact that it is "8-bit" is hard coded in the type of the "count" state variable and the "dout" port.

To make it generic, all we need to do is to replace those hard coded types by a type definition whose size is specified by a constant:

task Counter {
  const int size = 8;
  typedef uint<size> count_t;

  out count_t dout;
  count_t count;
  void loop() {
    count++;
    dout.write(count);
  }
}

We still have an 8-bit counter, but it is now written in a generic way. There is no special syntax required to make an entity generic. We used a "typedef", but this is not necessary either.

Instantiation and specialization

To create an instance of a counter that we can use in a design, we instantiate it:

counter = new Counter();

The "counter" instance is a 8-bit counter, since the default value of the "size" constant is 8. To create a 10-bit counter, what we need to do is override the size:

counter2 = new Counter({size: 10});

And voila, we have a 10-bit counter! This creates a specialized version of the entity.

Inheritance of values

Values specified at instantiation are passed down the hierarchy. This means that if you define such a network:

network N {
  cnt = new Counter();
}

You can instantiate as follows:

instN = new N({size: 10});

And the "cnt" instance inside will be specialized.

Conclusion

As we have seen it is very easy to design generic hardware in Cx. Now all you have to do is start designing something and experiment with this!