SystemVerilog Interfaceを使用して回路を作成する modport

Systemverilog

はじめに

Interfaceのmodportの機能を使用して回路を作成してみます。

バスのプロトコルは、validがHighのとき、スレーブに設定したアドレスとaddrが等しいときのdataが有効になります。

サンプルコード

tb.sv

テストベンチです。DUTをインスタンスしています。

クロック・リセット・入力データを生成しています。

module tb;
    // クロックとリセットを生成
    bit clk = 0;
    bit rst_n = 0;
    always #5 clk = ~clk;

    initial begin
        #10 rst_n = 1;
        #200 $finish;
    end

    class data_gen;
        randc bit [3:0] addr;
        randc bit [3:0] din;
    endclass

    bit [3:0] addr;
    bit [3:0] din;

    data_gen a = new();

    // 入力データを生成
    always @(posedge clk) begin
        a.randomize();
        addr = a.addr;
        din = a.din;
    end

    dut#(
        .address0(1),
        .address1(2)
    ) i_dut(
        .clk(clk),
        .rst_n(rst_n),
        .addr(addr),
        .din(din),
        .dout0(),
        .dout1()
    );
endmodule
sample_if.sv

interfaceを定義します。modportでマスタとスレーブのポートを宣言します。

interface sample_if;
    logic [3:0] addr;
    logic [3:0] data;
    logic valid;

    modport master(  // master側
        input addr,
        input data,
        input valid
    );
    modport slave(  // slave側
        output addr,
        output data,
        output valid
    );
endinterface
dut.sv

DUTのトップです。

module dut #(
    parameter [3:0] address0 = '0, 
    parameter [3:0] address1 = '0
)(
    input clk,
    input rst_n,
    input [3:0] addr,
    input [3:0] din,
    output logic [3:0] dout0,
    output logic [3:0] dout1
);

    sample_if dut_if();  // Interfaceをインスタンス

    master i_master(
        .clk(clk),
        .rst_n(rst_n),
        .addr(addr),
        .din(din),
        .master(dut_if.master)  // sample_ifのmasterポートを接続
    );

    slave #(
        .address(address0)
    ) i_slave_0(
        .clk(clk),
        .rst_n(rst_n),
        .dout(dout0),
        .slave(dut_if.slave)  // sample_ifのslaveポートを接続
    );

    slave #(
        .address(address1)
    ) i_slave_1(
        .clk(clk),
        .rst_n(rst_n),
        .dout(dout1),
        .slave(dut_if.slave)  // sample_ifのslaveポートを接続
    );
endmodule
master.sv

マスタです。テストベンチから入力されたデータをスレーブに与えます。

module master(
    input clk,
    input rst_n,
    input [3:0] addr,
    input [3:0] din,

    sample_if.master master
);
    assign master.valid = '1;
    always_ff @(posedge clk, negedge rst_n) begin
        if (!rst_n) begin
            master.addr <= '0;
            master.data <= '0;
        end
        else begin
            master.addr <= addr;
            master.data <= din;
        end
    end
endmodule
slave.sv

スレーブです。parameterのaddressがaddrと等しいときdataが有効となります。

module slave #(
    parameter address = 0
)(
    input clk,
    input rst_n,
    output logic [3:0] dout,

    sample_if.slave slave
);
    always_ff @(posedge clk, negedge rst_n) begin
        if (!rst_n) begin
            dout <= '0;
        end
        else begin
            if (slave.valid & (slave.addr == address)) begin
                dout <= slave.data;
            end
        end
    end
endmodule

実行結果

slave0のアドレスは1、slave1のアドレスは2に設定しています。

addrが1のとき、dinの値がdout0から出力されています。

addrが2のとき、dinの値がdout1から出力されています。

コメント

タイトルとURLをコピーしました