Reading Note of “SystemVerilog for Design” (Chapter 10: SystemVerilog Interfaces)

Concepts

  • How Verilog models connects between blocks
    • Directly on physical connections in actual hardware level
    • Disadvantage
      • Port connection must be duplicated in several modules
      • Communication protocols must be duplicated also
      • Duplication leads to mistakes that is hard to debug
      • Changes in spec involves lots of modification
      • Details of connection must be defined in early design cycle (not good for top-down design paradigm)
  • “interface” keyword
    • Several signals grouped together to represent as a single port
    • And modules use interface as a single port
  • Interface contents
    • Discrete signals and port
    • Communication protocol, defined as task/function
    • Protocol checker and verification routines
  • Interface vs. module
    • Interface doesn’t have hierarchy
    • Interface can be used as module port
    • Interface can contain “modport” which can represent different usage env.

How to declare an interface?

  • Similar to module, with “interface … endinterface” keyword
    • Can have ports: external signals to interface
    • Can use “.name” and “.*” for connection abbreviation
  • Declaration order
    • Just as module, no order needed
  • Global vs. local
    • Just as module, global definition can be used anywhere, local definition can be used in certain scope (for IP)

How to use interface?

  • As module ports
    • Explicitly named vs. generic
      • Explicitly named interface port can only connect to an interface with the same name
        • “module <module_name> ( <interface_name> <port_name);”
      • Generic interface can connec to any interface port
        • “module <module_name> ( interface <port_name);”
      • Both are synthesizable
  • Instantiate and connect interface
    • ILLEGAL leave an interface port unconnected
    • “.name” and “.*” can be used to connect interface
  • Referencing interface’s signals
    • Use dot: <port_name>.<internal_signal_name>

Modport

  • Differnet views of interface
    • Ex. a interrupt sub-signal could be input to CPU, but output to peripheral modules
  • “modport” means module port
    • Contains only direction and signal names, not vector size or types
  • Selecting which modport to use
    • In module instance
      • “<module_name> <instance_name> ( .<port_name>(<interface_instance_name>.<modport_name>) );”
    • In module delcaration (better because of consistency)
      • “module <module_name> ( <interface_name>.<modport_name> <port_name> );”
    • NOT use both methods above
    • If no modport is specified
      • all nets have “inout” direction, by default
      • all variables have “ref” type, by default
    • Synthesizable for both
      • Some synthesis tool will convert (expand) interface modport to normal ports automatically
  • To define different sets of connections
    • Hide certain signals in different modport: incompleleted signal list while defining one modport
    • Internal signals that are not accessable from any modport
      • Might be used for protocol checkers or other functionality
  • Example
interface cpu_bus (input
logic clk, rstb, test_en);

wire [15:0] data;

wire [15:0] addr;

logic [ 7:0] slave_cmd;

logic slave_req;

logic bus_grant;

logic bus_req;

logic slave_ready;

logic data_ready;

logic mem_ren;

logic mem_wen;

 

modport master (


inout data,


output addr,


output slave_cmd,


output slave_req,


output bus_grant,


output mem_ren,


output mem_wen,


input bus_req,


input slave_ready,


input data_ready,


input clk,


input rstb,


input test_en

);

 

modport slave (


inout data,


inout addr,


output mem_ren,


output mem_wen,


output bus_req,


output slave_ready,


input slave_cmd,


input slave_req,


input bus_grant,


input data_ready,


input clk,


input rstb,


input test_en

);

 

modport mem (


inout data,


output data_ready,


input addr,


input mem_ren,


inout mem_wen

);

 

endinterface

 

module top ();

 

// instance of an interface

cpu_bus bus ( .* );

 

processor proc1 ( .bus(bus.master), .* );

slave1 slave1 ( .bus(bus.slave), .* );

slave2 slave2 ( .bus(bus.slave), .* );

dual_port_ram mem ( .bus(bus.mem), .data_b(next_instruction), .* );

 

// test generator need to access everything in inside “bus”

test_generator test_gen ( .bus(bus), .* );

endmodule

 

Task/function in interface

  • Implement the details of communication protocol
    • Written once, shared by all modules connected using the same interface
  • Values are passed to interface methods as input argument
  • “import” when defining “modport”
    • Either use the name only, or the full prototype
      • Latter is useful when task is defined somewhere else
  • Access using <interface_port_name>.<method_name>
  • Task/function must be automatic to be synthesizable
  • Exporting task/function are not synthesizable
    • Define task/function in module, then export it to interface, and use it in other modules
    • Export from module’s all instances
      • “extern forkjoin”
      • Useful when you want to broadcast signals, such ask counting one module’s instances

 

 

 

 

 

Leave a comment