Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Functions

Functions

Like SV and Chisel, Nail has functions.

Nail

function logic[32] ax_plus_b(
    logic[32] a,
    logic[32] x,
    logic[32] b);
  return a * x + b;
endfunction
Chisel

def axPlusB(a: UInt, x: UInt, b: UInt): UInt = {
    a * x + b
}
SystemVerilog

function logic [31:0] ax_plus_b(logic [31:0] a, x, b);
  return a * x + b;
endfunction

Parametric Functions

Nail also provides parametric functions.

Nail

template<int N>
function logic[N] ax_plus_b(
    logic[N] a,
    logic[N] x,
    logic[N] b);
  return a * x + b;
endfunction
Chisel

def axPlusB(a: UInt, x: UInt, b: UInt): UInt = {
    a * x + b
}
SystemVerilog

function logic [N-1:0] ax_plus_b(logic [N-1:0] a, x, b);
  return a * x + b;
endfunction

Struct Functions

Nail allows functions to be defined within a struct. These functions are translated to functions with the struct name as a prefix in SystemVerilog.

Nail

structdef Foo {
  logic[32] x;
  function logic[32] Bar(logic[32] y);
    return x + y;
  endfunction
}
Chisel

class Foo extends Bundle {
  val x = UInt(32.W)
  def Bar(y: UInt): UInt = {
    x + y
  }
}
SystemVerilog

function logic [31:0] Foo_Bar(
    Foo self,
    logic [31:0] y);
  return self.x + y;
endfunction

Actions

Nail introduces a concept called “actions” to a struct. Functionally, we can think of an action as monadic function of type S -> X -> S where S is a struct type and X is an input type. In more laymans terms, an action in naive Nail will look like the following:

structdef Foo {
  function Foo ExampleAction(logic x)
      // Compute and return a new Foo
      ...
  endfunction
}

As we will see in later tutorials, actions are useful abstractions for formal verification. Because of this, Nail defines the action keyword which can be used in structs.

structdef Foo {
  action Example(logic x)
    // Compute new Foo
  endaction
}

The action keywork implicitly infers the return type of the function. Additionally, member variables of the struct are assumed to be preserved across an action unless assigned to.

structdef ValidCommand {
  logic valid;
  DataStruct data;

  action Gate(logic x)
    // The `valid` field of the result is updated.
    valid = valid & x;
    // The `data` field is preserved in the result.
  endaction
}

Importantly to note: actions do not imply the result will be stored in a register. Actions define combinatorial functions where the output is the same type as the first inpute.