SystemVeilog|画像処理回路とテストベンチ

Systemverilog
田中太郎
田中太郎

画像を入力して回路で処理し、出力を画像に直すまでを行うテストベンチを作成しました

概要

BMP画像をテストベンチに与えると、8ビットのデータに変換して1クロック毎に回路に与える

回路は画像データを2値化して出力する

出力データが有効のときはvalidがHighになる

入力データをすべて処理し終わるとinterruptがHighになる

テストベンチ

tb.sv

テストベンチ。BMPの画像ファイルを読み込んで回路に与える。

画像処理後のデータを画像データ(BMP)にして保存する

シーケンスは
画像読み込み
→enableを1サイクルHigh
→画像データを1画素ずつ回路に入力
→回路から出力されるvalidがHighのときのデータ(dout)を画像ファイルとして順次書き込み
→回路から出力されるinterruptがHighになったらファイルの書き込みを終了してテストを終了する

module tb;
    initial begin
        $dumpfile("wave.vcd");
        $dumpvars(0, tb);
    end

    localparam IMG_W = 512;
    localparam IMG_H = 512;

    int f;
    bit [7:0] bmp[54+1024];
    bit [7:0] data[IMG_H*IMG_W];
    logic [7:0] din;
    logic [7:0] dout;
    bit enable;
    bit valid;
    bit interrupt;

    bit clk = 0;
    bit rst_n = 0;
    always #5 clk = ~clk;

    initial begin
        f = $fopen("rob.bmp", "rb");
        $fread(bmp, f, 0, 54+1024);
        $fread(data, f, 0, IMG_H*IMG_W);
        $fclose(f);

        f = $fopen("result.bmp", "wb");
        foreach (bmp[i])
            $fwrite(f, "%c", bmp[i]);

        #50 rst_n = 1;

        enable = 1;
        fork
            foreach (data[i]) begin
                din = data[i];
                @(posedge clk);
            end
        join_none

        @(posedge clk);
        enable = 0;

        forever begin
            if (valid) begin
                $fwrite(f, "%c", dout);
            end
            @(posedge clk);
            if (interrupt) begin
                break;
            end
        end
        $fclose(f);

        $finish;
    end

    sample #(
        .IMG_W(IMG_W),
        .IMG_H(IMG_H)
    ) u_sample(
        .clk(clk),
        .rst_n(rst_n),
        .enable(enable),
        .din(din),
        .valid(valid),
        .dout(dout),
        .interrupt(interrupt)
    );
endmodule

画像処理回路

入力されるdinを画像処理してdoutとして出力する

enableがHighになっているときのdinが有効

有効なdoutを出力するときはvalidをHighにする

入力された画像の処理がすべて完了するとinterruptがHighにする

top.sv

DUTのトップ。main.svとctrl.svをインスタンスしている。

module top #(
    parameter IMG_W = 512,
    parameter IMG_H = 512
)(
    input clk,
    input rst_n,
    input enable,
    input [7:0] din,
    output logic valid,
    output logic [7:0] dout,

    output logic interrupt
);
    localparam LATENCY = 1; // main回路のレイテンシを設定する

    ctrl #(
        .IMG_W(IMG_W),
        .IMG_H(IMG_H),
        .LATENCY(LATENCY)
    ) i_ctrl(
        .clk(clk),
        .rst_n(rst_n),
        .enable(enable),
        .valid(valid),
        .interrupt(interrupt)
    );

    main #(
    ) i_main(
        .clk(clk),
        .rst_n(rst_n),
        .din(din),
        .dout(dout)
    );
endmodule
main.sv

画像処理回路。今回の画像処理は2値化。

module main #(
)(
    input clk,
    input rst_n,
    input [7:0] din,
    output logic [7:0] dout
);

    always_ff @(posedge clk, negedge rst_n) begin
        if (!rst_n) begin
            dout <= '0;
        end
        else begin
            if (din > 127) begin
                dout <= '1;
            end
            else begin
                dout <= '0;
            end
        end
    end
endmodule
ctrl.sv

制御回路。入力されるenableからvalid, interruptの出力タイミングを制御する

module ctrl #(
    parameter IMG_W = 512,
    parameter IMG_H = 512,
    parameter LATENCY = 1
)(
    input clk,
    input rst_n,
    input enable,
    output logic valid,

    output logic interrupt
);
    logic [18:0] cnt;
    logic enable_d;

    always_ff @(posedge clk, negedge rst_n) begin
        if (!rst_n) begin
            enable_d <= '0;
        end
        else begin
            enable_d <= enable;
        end
    end

    always_ff @(posedge clk, negedge rst_n) begin
        if (!rst_n) begin
            cnt <= '1;
        end
        else begin
            if (enable & ~enable_d) begin
                cnt <= '0;
            end
            else if (cnt < IMG_W*IMG_H + LATENCY - 1) begin
                cnt <= cnt + 1'b1;
            end
        end
    end

    always_comb begin
        if (cnt == IMG_W*IMG_H + LATENCY - 1) begin
            interrupt = '1;
        end
        else begin
            interrupt = '0;
        end
    end

    always_comb begin
        if (LATENCY <= cnt && cnt < IMG_W*IMG_H + LATENCY - 1) begin
            valid = '1;
        end
        else begin
            valid = '0;
        end
    end
endmodule

動作確認

入力
出力

まとめ

画像処理するテストベンチ、回路を作成しました

水平方向に順次処理するような画像処理であれば、main.svのLATENCYをいじれば流用できると思います

コメント

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