Modules

Reference 1

Overview

Modules and interfaces form the heart of BSV.

Modules and interfaces turn into actual hardware.

An interface for a module m mediates between m and other, external modules that use the facilities of m, i.e. clients of m.

Module definition vs instantiation

A single module definition of a FIFO, and multiple instantiations of this FIFOs in a design.

Pure hierarchy. In a module definition, mkM, one can specify instantiations of other modules. Every module instance unambiguously has a single parent module instance. The top of the hierarchy as the root module. Every module instance has a unique set of child module instances. If no children, we refer to it as a leaf module.

Interface declarations and instances

A design will contain interface declarations, and each of these ma have multiple instances.

Example: an interface declaration I may have one instance $i_1$ for communication between module instances $a_1$ and $b_1$, and another instance $i_2$ for communication between module instances $a_2$ and $b_2$.

Module in Three Parts

Three parts: state, rules, interface.

  • state elements in hardware,
  • rules that operate on the state of the module. Fundamental means to express behavior in BSV (instead of always blocks in Verilog)
  • interface to the outside world (surrounding hierarchy). Consists of methods that encapsulate the possible transactions that clients can perform. When compiled into RTL, an interface becomes a collection of wires.

Explicit state via module instantiation, not variables

Ambiguity in Verilog/SystemVerilog RTL state elements by variables: variable can be mapped into various kind of state elements by a synthesis tool: a bus, a latch, a flip-flop, or even nothing at all.

BSV removes the ambiguity:

  • all state instances are specified explicitly using module instantiation.

  • an ordinary declared variable in BSV never implies state, i.e. it never holds a value over time.

    • just convenient names for intermiediate values in a computation.
    • variables declared in blocks, formal parameters, pattern variables, loop iterators, and so on.

Interface Declaration

An interface contains methods and subinterfaces as its members.

Each method represents one kind of transaction between a module and its clients. Will be wires in RTL.

Difference between a method and a function: method also carries implicit condition.

Implicit condition: each method has an implicit ready wire, which governs when it is legal to use it.

one of the major advantages of BSV is that the compiler automatically generates all the control circuitry needed to ensure that a method (transaction) is only used when it is legal to use it. –> any hints to system security forging languages/os/hardware???

A stack of integers:

interface IntStack;
    method Action push (int x);
    method Action pop;
    method int top;
endinterface: IntStack

A stack with polymorphic type:

interface Stack#(type a);
    method Action push (a x);
    method Action pop;
    method a top;
endinterface: Stack

// to use:

typedef Stack#(int) IntStack;

Subinterfaces

interface ILookup;
    interface Server#( RequestType, ResponseType ) mif;
    interface RAMclient#( AddrType, DataType ) ram;
    method Bool initialized;
endinterface: ILookup

Methods of subinterfaces are accessed using dot notation to select the desired component, e.g.,

ilookup.mif.request.put(...);

Module definition

mk convention: make, suggesting a module definition is not a module instance. When the module is instantiated, one invokes mkFoo to actually create a module instance.

Parameters –> constants, same as verilog/systemverilog. parameter to generate Verilog parameter; without parameter, a Verilog port is generated.

Interfaces –> argument/port; input/output;

Provisos –> type classes (overloading groups).

Examples:

A module with parameter a and an interface Fifo:

module mkFifo#(Int#(8) a) (Fifo);
...
endmodule

A module with arguments and an interface, but no parameters:

module mkSyncPulse (Clock sClkIn, Reset sRstIn,
                    Clock dClkIn,
                    SyncPulseIfc ifc);
...
endmodule

A module definition with parameters, arguments, and provisos:

module mkSyncReg#(a_type initValue)
                (Clock sClkIn, Reset sRstIn,
                Clock dClkIn,
                Reg#(a_type) ifc)
        provisos (Bits#(a_type, sa));
    ...
endmodule

Can also be written as Parameters and Arguments be combined:

module mkSyncReg (a_type initValue,
        Clock sClkIn, Reset sRstIn,
        Clock dClkIn,
        Reg#(a_type) ifc)
        provisos (Bits#(a_type, sa));
...
endmodule

Module and interface instantiation

Short form instantiation

one line form

[attributeInstances] type identifier <- identifier ( [moduleActualParameterArg {, …}]);

  • parameters listed first, argument next, combined within a single set of parentheses; no # before the list.
  • each module has an implicit clock and reset. can be changed by explicitly specifying a clocked_by or reset_by argument.

    interface ArithIO#(type a); //interface type called ArithIO
    method Action input (a x, a y); //parameterized by type a
    method a output; //contains 2 methods, input and output
    endinterface: ArithIO
    
    module mkGCD#(int n) (ArithIO#(bit [31:0]));
    ... //module definition for mkGCD
    ... //one parameter, an integer n
    endmodule: mkGCD //presents interface of type ArithIO#(bit{31:0])
    
    //declare the interface instance gcdIFC, instantiate the module mkGCD, set n=5
    module mkTest ();
    ...
    ArithIO#(bit [31:0]) gcdIfc <- mkGCD (5, clocked_by dClkIn);
    ...
    endmodule: mkTest

module instantiation using a clocked_by statement:

interface Design_IFC;
    method Action start(Bit#(3) in_data1, Bit#(3) in_data2, Bool select);
    interface Clock clk_out;
    method Bit#(4) out_data();
endinterface : Design_IFC

module mkDesign(Clock prim_clk, Clock sec_clk, Design_IFC ifc);
    ...
    RWire#(Bool) select <- mkRWire (select, clocked_by sec_clk);
    ...
endmodule:mkDesign

Long form instantiation

full form on two consecutive lines, similar to SystemVerilog.

First line: identifier with an interface type.

Second line: instantiates the module and defines the interface.

module mkTest (); //declares a module mkTest
    ... //
    ArithIO#(bit [31:0]) gcdIfc(); //declares the interface instance
    mkGCD#(5) a_GCD (gcdIfc); //instantiates module mkGCD
    ... //sets N=5, names module instance a_GCD
endmodule: mkTest //and interface instance gcdIfc

module mkDesign(Clock prim_clk, Clock sec_clk, Design_IFC ifc);
    ...
    RWire#(Bool) select(); // declare
    mkRWire t_select(select, clocked_by sec_clk); // instantiate module
    ...
endmodule:mkDesign

Interface/methods definition

Definition of methods.

Inside a module definition.

method [type] identifier ( methodFormals ) [implicitCond]; functionBody endmethod [: identifier]

  • Methods must be from an interface of the module.
  • Each methods in the interface must be defined exactly once.
  • Return type and arguments are optional, since compiler knows them from the declaration;

Implicit condition:

  • Every method is ultimately invoked from a rule (might be indirectly invoked through other methods)
  • A method’s implicit condition controls wether the invoking rule is enabled.
  • implicit condition precedes the semicolon that terminates the method definition header.

    // the implicite condition
    // if false, any rule invokes the method will not be fired.
    method ... foo (...) if (expr);
    ...
    endmethod
    
    // a conditonal statement inside the method.
    // condition does no prevent the rule being fired.
    // 
    method ... foo (...); if (expr)
    ...
    endmethod

Method body is exactly like a function body.

Example:

interface GrabAndGive; // interface is declared
    method Action grab(Bit#(8) value); // method grab is declared
    method Bit#(8) give(); // method give is declared
endinterface

module mkExample (GrabAndGive);

    Reg#(Bit#(8)) value_reg <- mkReg(?);
    Reg#(Bool) not_yet <- mkReg(True);

    // method grab is defined
    method Action grab(Bit#(8) value) if (not_yet);
        value_reg <= value;
        not_yet <= False;
    endmethod

    //method give is defined
    method Bit#(8) give() if (!not_yet);
        return value_reg;
    endmethod
endmodule

  1. Bluespec SystemVerilog Reference Guide. July 2017. ↩
Created Mar 9, 2020 // Last Updated Apr 6, 2020

If you could revise
the fundmental principles of
computer system design
to improve security...

... what would you change?