Help us understand the problem. What is going on with this article?

[SystemC][HLS] ラプラシアンフィルタを SystemCで記述してみる。

More than 5 years have passed since last update.

この記事は HDL Advent Calendar 2013の 19日目の記事です。
まだまだ参加者募集しております!!!

概要

皆さん @marsee1さんが書かれているブログ

FPGAの部屋

をご存知でしょうか?

その中に、 Vivado HLS に関してのトライアルをした記事などがあります。

もう身近に 高位合成 が出来る時代になりましたね!

さて、今回のその記事の中からこちらを引用したいと思います。

SystemC版を作ってみよう

記事では C言語ですが、せっかくなので SystemC版を書いてみました。

※ただし、高位合成出来るかは試していません

  • laplacian_filter.h
#pragma once

#include <stdlib.h> 
#include <systemc.h>

SC_MODULE( laplacian_filter ){
  sc_in_clk   clk;
  sc_in<bool> xreset;
  sc_in<int>  x0y0;
  sc_in<int>  x1y0;
  sc_in<int>  x2y0;
  sc_in<int>  x0y1;
  sc_in<int>  x1y1;
  sc_in<int>  x2y1;
  sc_in<int>  x0y2;
  sc_in<int>  x1y2;
  sc_in<int>  x2y2;
  sc_out<int> out;

  void process();

  int  _x0y0;
  int  _x1y0;
  int  _x2y0;
  int  _x0y1;
  int  _x1y1;
  int  _x2y1;
  int  _x0y2;
  int  _x1y2;
  int  _x2y2;
  int  _exe;

  SC_CTOR( laplacian_filter ):
     clk("clk")
    ,xreset("xreset")
    ,x0y0("x0y0")
    ,x1y0("x1y0") 
    ,x2y0("x2y0") 
    ,x0y1("x0y1") 
    ,x1y1("x1y1") 
    ,x2y1("x2y1") 
    ,x0y2("x0y2") 
    ,x1y2("x1y2") 
    ,x2y2("x2y2") 
    ,out ("out")
  {
    SC_CTHREAD( process, clk.pos() );
    async_reset_signal_is(xreset, false);
  }
};
  • laplacian_filter.cpp
#include "laplacian_filter.h"

void laplacian_filter::process() {
  out.write(0);
  wait();

  while (1) {
    { //input
      _x0y0 = x0y0.read();
      _x1y0 = x1y0.read();
      _x2y0 = x2y0.read();
      _x0y1 = x0y1.read();
      _x1y1 = x1y1.read();
      _x2y1 = x2y1.read();
      _x0y2 = x0y2.read();
      _x1y2 = x1y2.read();
      _x2y2 = x2y2.read();
    }

    { // execute
      _exe = abs(-_x0y0 -_x1y0 -_x2y0 -_x0y1 +8*(_x1y1) -_x2y1 -_x0y2 -_x1y2 -_x2y2);
    }

    { // output
      out.write(_exe);
    }
    wait();
  }
}

さて、ここまでが機能部分のところですが、

検証環境はというとこちらになります。

  • sc_main.cpp
#include <systemc.h>
#include <stdlib.h>

#include "laplacian_filter.h"
#include "testbench.h"

int sc_main(int argc, char* argv[])
{

  sc_clock clk("clk", 10, SC_NS);
  sc_signal<bool> xreset;
  sc_signal<int> x0y0;
  sc_signal<int> x1y0;
  sc_signal<int> x2y0;
  sc_signal<int> x0y1;
  sc_signal<int> x1y1;
  sc_signal<int> x2y1;
  sc_signal<int> x0y2;
  sc_signal<int> x1y2;
  sc_signal<int> x2y2;
  sc_signal<int> y;

  laplacian_filter dut("dut");
  testbench tb("tb");

  dut.clk(clk);
  dut.xreset(xreset);
  dut.x0y0(x0y0);
  dut.x1y0(x1y0);
  dut.x2y0(x2y0);
  dut.x0y1(x0y1);
  dut.x1y1(x1y1);
  dut.x2y1(x2y1);
  dut.x0y2(x0y2);
  dut.x1y2(x1y2);
  dut.x2y2(x2y2);
  dut.out(y);

  tb.clk(clk);
  tb.xreset(xreset);
  tb.x0y0(x0y0);
  tb.x1y0(x1y0);
  tb.x2y0(x2y0);
  tb.x0y1(x0y1);
  tb.x1y1(x1y1);
  tb.x2y1(x2y1);
  tb.x0y2(x0y2);
  tb.x1y2(x1y2);
  tb.x2y2(x2y2);
  tb.y(y);

  xreset = 1;
  sc_start(1, SC_NS);
  xreset = 0;
  sc_start(10, SC_NS);
  xreset = 1;
  sc_start();

}
  • testbench.h
#pragma once

#include <stdlib.h> 
#include <systemc.h>

SC_MODULE( testbench ){
  sc_in_clk   clk;
  sc_in<bool> xreset;
  sc_in<int>  y;
  sc_out<int> x0y0;
  sc_out<int> x1y0;
  sc_out<int> x2y0;
  sc_out<int> x0y1;
  sc_out<int> x1y1;
  sc_out<int> x2y1;
  sc_out<int> x0y2;
  sc_out<int> x1y2;
  sc_out<int> x2y2;

  sc_event _e_comp;
  int      _data[3][3];

  void set_data();
  void process();
  void compere();

  SC_CTOR( testbench ):
     clk("clk")
    ,xreset("xreset")
    ,y ("y")
    ,x0y0("x0y0")
    ,x1y0("x1y0") 
    ,x2y0("x2y0") 
    ,x0y1("x0y1") 
    ,x1y1("x1y1") 
    ,x2y1("x2y1") 
    ,x0y2("x0y2") 
    ,x1y2("x1y2") 
    ,x2y2("x2y2") 
  {
    SC_THREAD( process );
      sensitive << clk.pos();
    SC_METHOD( compere );
      sensitive << _e_comp ;
      dont_initialize();
  }
};
  • testbench.cpp
#include "testbench.h"

void testbench::set_data() {
  _data[0][0] = 1;
  _data[1][0] = 1;
  _data[2][0] = 1;
  _data[0][1] = 1;
  _data[1][1] = 2;
  _data[2][1] = 1;
  _data[0][2] = 1;
  _data[1][2] = 1;
  _data[2][2] = 1;
}

void testbench::process() {
  wait();

  set_data();

  x0y0.write(_data[0][0]);
  x1y0.write(_data[1][0]);
  x2y0.write(_data[2][0]);
  x0y1.write(_data[0][1]);
  x1y1.write(_data[1][1]);
  x2y1.write(_data[2][1]);
  x0y2.write(_data[0][2]);
  x1y2.write(_data[1][2]);
  x2y2.write(_data[2][2]);

  wait(3);
  _e_comp.notify();
  wait(3);
  sc_stop();
}

void testbench::compere() {

  int hw_result, sw_result;

  hw_result = y.read();
  sw_result = abs(-_data[0][0] -_data[1][0] -_data[2][0]
                  -_data[0][1] + 8*(_data[1][1]) -_data[2][1]
                  -_data[0][2] -_data[1][2] -_data[2][2]);

  std::cout << "simulation time = " << sc_time_stamp() << std::endl;
  printf("HW result = %d\n", hw_result);
  printf("SW result = %d\n", sw_result);

  if (hw_result == sw_result){
    printf("Success SW and HW results match\n");
    // return(0);
  } else {
    printf("ERROR SW and HW results mismatch\n");
    // return(1);
  }
}


まとめ

今回は単純に書き換え(AXIインターフェースは抜きにして信号で表現) を行っただけですが、
設計対象および検証環境はまだまだ改善されるべきところがあります。
今後は、こちらをベースにして色々な設計スタイルや検証環境のTopicsについて
書いていきたいと思います。

※次回以降に乞うご期待。

書きたいと思っている内容については以下です。

  • Modular InterfaceやDesign Interface(p2p, AXI)について
  • 高位合成での合成
  • 汎用なデータ入力(検証環境)
  • ランダム検証(検証環境)

上記以外でリクエストあれば、ご連絡ください。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away