Cコード例 - 1個ずつn回入力して和を1回出力する回路
非パイプライン型トップ階層の例として、num個のデータをストリーム入力して和を出力する回路のCコードを示す。
ストリーム入力は固定長ならdin[N]と書けるが、ここでは可変長(num≦N)にするため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にならない)。