Slice a SystemVerilog interface in the receiving modules

A common use pattern for SystemVerilog interfaces is that one server is connected to N clients, and the interconnect is like an N-element array of structs, where the server uses the entire array, but each client uses only one element of the array. In practice, it’s easier to express the interconnect as several arrays, one for each struct field.

I made this problem too complicated in “How to slice a SystemVerilog interface“, because each of the server and the clients were being passed different interface instances, and the instance passed to the server was even of a different type of interface than the instances passed to the clients.

The more natural way is to pass them all the same instance, and restrict access to single elements inside the clients. As in the earlier entry, this restriction is done with a second interface. But the trick here is that the client must be passed its own index.

`define _ import GLOBAL_PARAMETERS::*;
package GLOBAL_PARAMETERS;
  localparam type requestType = byte;
  localparam type responseType = int;
  localparam int N = 16;
endpackage:GLOBAL_PARAMETERS

module testMod `_ (/*...*/);
  wire clk, rst;
  IFC U(clk, rst);
  for (genvar INDEX = 0; INDEX != N; ++INDEX) begin:GEN
    clientMod#(INDEX) client(U.clientMp);
  end
  serverMod server(U.serverMp);
endmodule:testMod

module clientMod `_ #(INDEX)(IFC.clientMp bigifc);
  IFC_SLICE#(INDEX) U(bigifc);
  always_ff @(posedge U.clk, negedge U.rst) begin
    if (!U.rst) 
      U.requestWrite(0);
    else
      U.requestWrite(1);
  end
  // ...
endmodule:clientMod

module serverMod `_ (IFC.serverMp bigifc);
  // ...
endmodule:serverMod

interface automatic IFC `_ (input clk, rst);
  var requestType Requests[N-1:0];
  var responseType Responses[N-1:0];

  function requestType requestRead(int index);
    return Requests[index];
  endfunction

  function responseType responseRead(int index);
    return Responses[index];
  endfunction

  function void requestWrite(int index, requestType request);
    Requests[index] <= request;
  endfunction

  function void responseWrite(int index, responseType response);
    Responses[index] <= response;
  endfunction

  modport clientMp(output Requests, input Responses,
                   import requestWrite, responseRead,
                   input clk, rst);

  modport serverMp(input Requests, output Responses,
                   import requestRead, responseWrite,
                   input clk, rst);
endinterface:IFC

interface automatic IFC_SLICE `_ #(INDEX)(IFC.clientMp bigifc);
  wire clk = bigifc.clk;
  wire rst = bigifc.rst;

  function void requestWrite(requestType request);
    bigifc.requestWrite(INDEX, request);
  endfunction

  function responseType responseRead();
    return bigifc.responseRead(INDEX);
  endfunction
endinterface:IFC_SLICE

Copyright © 2016 Brad Pierce
Advertisements

2 Comments

  1. Brad, I agree this is simpler code than your previous version, but I find it distasteful that each connected client needs to be aware of its own index and – worse – that it needs to be aware that it’s part of an array. This is poor encapsulation of the client, which otherwise might also be useful in a different situation where it’s connected to a non-array, point-to-point interface. You could implement this new solution as a “gasket” between the interconnect and each client, but that would be clumsier and more verbose than your previous solution, I suspect.

    Like

    • Jonathan, unless you are using generic ‘interface’ ports, or are planning to reuse the same interface name in different interface definitions, I don’t understand the scenario where the same client with the same interface name in the port declaration could be used both as a singleton client and as an element in an array of clients. What’s a code example of doing that?

      On the other hand, a singleton client could be approximated in the style of my example just by seeing it as the 0th element in an array of one clients.

      By the way, wouldn’t a client communicating over a network need to know it’s own address to form packets?

      Like

Tell me (anonymous OK)

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s