Custom Field Types

To the spacecraft executable field types are just strings. To the verilog engine, however, a field type needs to translate into a verilog implementation. Hence the verilog engine dictates the set of field types supported, not the spacecraft executable.

The verilog engine has several predefined types, but the engine is built with an object oriented architecture that allows adding custom types by passing a library of derivative classes on the command line.

Introduction

Suppose you wanted a CONST field type that didn’t get optimized or pruned out in synthesis so that you could later ECO the value to identify the metaspin version.

//
// You can just reference the CONST type in your Rocket Fuel because
// it's just a string to spacecraft.  However it does need an implementation
// if you try to generate a verilog module from this file.  You'll get
// an error if the type does not exist.
//
0W  16b   deadh   METAL_VERSION   CONST;

To implement this type in verilog you would need to pass an implemenation of the CONST type to the verilog engine:

$ spacecraft soc.rf verilog.pl -types CONST.pm

Here we name the package CONST.pm, but the package name doesn’t really matter as long as the package contains a CONST class. In fact if you have more than one custom type, they can all be added to the same package, creating a library of custom types.

Now when the verilog engine goes to implement the METAL_VERSION field, it effectively does:

my $Type  = $node->sc_get_type; # Retreive the CONST type
my $Field = new $Type;          # Create an instance of the CONST type
$Field->implementation;         # Add the implemenation to the module

Hence the CONST.pm package contains a CONST class with an implementation method.

Implementation methods use inherited APIs to get or add Signals in the Module and use them in assign statements and always blocks:

package CONST;                  # Implement the CONST type
use base ('Field');             # which is a custom Field type

sub implemenation {             # with an implemenation method.
   my $this = shift;

   # 1) Get Signals from the Module

   my $Clock   = $this->get_bus_clock;
   my $Port    = $this->get_field_port;
   my $Value   = $this->get_field_value;
   my $default = $this->get_field_default;

   # $Clock, $Port and $Value are Signal objects.

   # 2) Configure the Port to be an (internal) wire:

   $Port->wire;

   # 3) Assign the Port the constant value:

   $this->assign($Port,$default);  # i.e. assign $Port = $default;

   # 4) Declare a non-reset register with the CONST_ prefix so that synthesis
   #    can find the register and add a don't touch constraint.

   my $Const = $this->reg("CONST_".$Port, $Clock);

   # 5) Clock the register:

   $this->always($Const,$Port);  # i.e. always @($Const.Clock) $Const <= $Port;

   # 6) Configure the Value to be a wire:

   $Value->wire;

   # 7) Assign the register to the value:

   $this->assign($Value,$Const);  # i.e. assign $Value = $Const;

   # 8) Add the Value to the Return path:

   $this->add_bus_read_data($Value);
	
}

This implementation method will result in the following verilog for the METAL_VERSION field inside the module:

module ...
...
wire [15:0] metal_version;
wire [15:0] metal_version_value;
...
reg  [15:0] CONST_metal_version;
...
assign metal_version       = 16'hdead;
assign metal_version_value = CONST_metal_version;

always @(posedge bus_clock) begin
  CONST_metal_version <= metal_version;
end
...
bus_read_data = metal_version_value |
...
endmodule

The implementation:

The built in types are implemented this way and provide a good demonstration of different implementations.

Verilog Engine Classes

The verilog engine has an object oriented architecture that uses the following naming convention:

The architecture is composed of the following classes:

General verilog structure:

A Module has Blocks of logic that use Signals.

A Signal is reg or wire variable that can optionally be an input or output.

A Block of logic is a group of related always blocks and assign statements.

Specific to accessing fields & regions:

A Slave is a Module that has a Bus that accesses a set of Fields.

A Field is a Block accessed by the Bus that implements a function.

A Bus has a Decoder Block that fans-out bus inputs to Fields and a Return path Block that fans-in and assembles bus outputs.

In this architecture, then, custom field types are derivatives of the Field class, since each type implements a specific function. Fields are Blocks that reside in a Slave that interface with the Bus and use Signals in always blocks and assign statements to implement a function.