Cコード例 - 1個ずつn回入力して和を1回出力する回路

[] [] []


非パイプライン型トップ階層の例として、num個のデータをストリーム入力して和を出力する回路のCコードを示す。

ストリーム入力は固定長ならdin[N]と書けるが、ここでは可変長(numN)にするためstreamクラスを使う。

streamクラスにハンドシェーク信号をつけるにはap_hsでなくap_fifoを指定する。(信号名が違うだけで意味は同じ)

合成対象のCコード

/* dut.h */

#ifndef DUT_H

#define DUT_H

#include <ap_int.h>

#include <hls_stream.h>

static const int N=10; // max. number of din

static const int WN=4; // bit width of N

typedef ap_uint<WN>  num_t;

typedef ap_int<8> din_t;

typedef ap_int<8+WN> dout_t;

void dut_hls

  (num_t  num           // (i) number of din

  ,hls::stream<din_t> &din // (i) input data

  ,dout_t *dout         // (o) output data

);

#endif

/* dut.cpp */

#include "dut.h"

void dut_hls

  (num_t  num           // (i) number of din

  ,hls::stream<din_t> &din // (i) input data

  ,dout_t *dout         // (o) output data

) {

  #pragma HLS interface ap_ctrl_none port=return

  #pragma HLS interface ap_fifo port=din

  #pragma HLS interface ap_hs register port=dout

  dout_t acc = 0;

  for(int i=0; i<num; i++) {

    acc += din.read();

  }

  *dout = acc;

}

◇◇

Cのテストベンチ

/* main.cpp */

#include <iostream>

#include "dut.h"

using namespace std;

/************************

 * サブルーチン - 期待値比較

 ************************/

void dut_golden(din_t din[N],dout_t dout) {

  int acc = 0;

  for(int i=0; i<N; i++) {

    acc += din[i];

  }

  cout << "-- dout= " << dout;

  if(dout==acc) {

    cout << "[PASS]" << endl;

  } else {

    cout << "[FAIL]" << endl;

  }

}

/************************

 * メインルーチン

 ************************/

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

  num_t num;

  hls::stream<din_t> din;

  din_t  din_val[N];

  dout_t dout;

  for(num=1; num<=N; num++) {

    for(int i=0; i<num; i++) {

      din_val[i] = i+1;

      din.write(din_val[i]);

    }

    dut_hls(num,din,&dout);

    dut_golden(num,din_val,dout);

  }

  return 0;

}

◇◇

合成後RTLのテストベンチ

/* tb.sv */

`timescale 1ns/1ps

module tb;

parameter N=10;                 // number of din

parameter WN=$clog2(N);         // bit width of N

reg clk;

reg rst;

reg[WN-1:0] num;

reg          din_vld = 1'b0;

reg[7:0]    din;

wire[7+WN:0] dout;

 

dut_hls dut

  (.ap_clk(clk)

  ,.ap_rst(rst)

  ,.num           (num)           // (i)

  ,.din_read     (din_ack)      // (o)

  ,.din_empty_n (din_vld)       // (i)

  ,.din_dout     (din)           // (i)

  ,.dout_ap_ack (1'b1)          // (i)

  ,.dout_ap_vld (dout_vld)      // (o)

  ,.dout          (dout)         // (o)

  );

/* クロック生成 */

initial begin

  clk = 1'b1;

  forever #(5) clk = ~clk;      // 10ns

end

/* ドライバタスク */

task din_burst

  (input[7:0] base      // din[i]=base+i

  ,input int num_val    // 連続入力数

  );

  begin

  @(posedge clk);

  num     <= num_val;

  din_vld <= 1'b1;

  for(int i=0; i<num_val; i++) begin

    din <= base+i;

    do @(posedge clk); while(din_ack!==1'b1);

  end

  din_vld <= 1'b0;

  din <= 'bx;

  while(dout_vld===1'b1) @(posedge clk);

  end

endtask

/* モニタ */

always @(negedge clk) begin

  if(~rst)

    $display("--(%t) din_vld=%b din=%h dout_vld=%b dout=%h"

              ,$time,din_vld,din,dout_vld,dout);

end

/* シナリオ */

initial begin

  $timeformat(-6,3," us",10);

  rst = 1'b1;

  #(15)

  rst = 1'b0;

  din_burst(.base(8'd2),.num_val(1)); // 1連続入力

  din_burst(.base(8'd1),.num_val(N-1)); // N-1連続入力

  repeat(5) @(posedge clk);

  $finish;

end

endmodule

これを実行してみるとわかるが、出力が完了するまで次の入力が受け付けられない(vld=1にしてもack=1にならない)


[] [] []