學(xué)習(xí)目標(biāo)為:
- 如何使用高級綜合生成流水線
- 如何使用Stratus進(jìn)行層次化設(shè)計
1.生成流水線
Stratus允許指定一個主循環(huán)(while(1)
)中的內(nèi)容為流水線方式實現(xiàn),即每個時鐘周期均可以進(jìn)入數(shù)據(jù)執(zhí)行靠闭,需要在主循環(huán)開始時添加如下語句指定使用流水線實現(xiàn):
HLS_PIPELINE_LOOP(<STALL_TYPE>, <cycle>, <name>);
上述指定該loop為流水線實現(xiàn)愧膀,具有三個參數(shù),分別如下所示:
- STALL_TYPE:實現(xiàn)類型矿咕,包括
HARD_STALL
和SOFT_STALL
兩種 - cycle:數(shù)據(jù)進(jìn)入間隔狼钮,即“每隔多少個時鐘周期可進(jìn)入一個數(shù)據(jù)”熬芜,當(dāng)cycle=1時表示每個周期均可進(jìn)入數(shù)據(jù)
- name:流水線配置名稱,每個循環(huán)流水線名稱不同即可
對于STALL_TYPE中的兩種瑞侮,具有以下的區(qū)別:
-
HARD_STALL
:當(dāng)流水線的某一級阻塞時,整條流水線停止運行 -
SOFT_STALL
:當(dāng)流水線的某一級阻塞時半火,僅阻塞級之前的流水線停止運行钮糖,阻塞級之后的流水線繼續(xù)運行
對于要生成流水線的代碼片(循環(huán)體),Stratus有以下的要求:
- 循環(huán)展開(Nested Loops):循環(huán)體中僅可以嵌套次數(shù)指定的循環(huán)阎抒,且被指定生成流水線的循環(huán)要么為無限循環(huán)消痛,要么為指定次數(shù)循環(huán)
- 數(shù)據(jù)依賴(Data Dependencies):需要保證每一級需要的數(shù)據(jù)在運行這一級之前已經(jīng)生成秩伞,即數(shù)據(jù)流向固定向前,不存在反向數(shù)據(jù)流(產(chǎn)生數(shù)據(jù)沖突)掰担,若發(fā)生這種情況Stratus會報錯:
Unable to satisfy HLS_HLS_PIPELINE_LOOP directive "main_pipeline",possibly because of a statement in this line.
- 端口訪問(Port Access Conflicts):對于端口的訪問需要謹(jǐn)慎怒炸,需要避免連續(xù)兩個周期訪問一個端口的寫法毡代,因為會產(chǎn)生對端口的訪問沖突(前一次進(jìn)入loop和后一次loop在同一周期需要訪問同一個接口)教寂,這種情況會報出Warning:
Pipelining forces multiple assignments to output data_out
- 非平衡流水線(Unbalanced Protocol Blocks):避免在展開為流水線的循環(huán)中使用消耗時鐘周期不同的條件判斷。即若在循環(huán)中使用if-else語句导梆,兩個代碼塊消耗的時鐘周期必須一致迂烁。
- 循環(huán)跳出(Conditional Exits in Pipelined Loops):允許使用break語句跳出循環(huán)盟步,但用于判斷是否跳出循環(huán)的邏輯消耗的時間必須少于數(shù)據(jù)進(jìn)入間隔時鐘周期
學(xué)習(xí)過程使用上一次使用的+1功能電路,將其執(zhí)行線程改為以下按流水線展開:
void dut_template::t() {
{
HLS_DEFINE_PROTOCOL("reset");
x_in.reset();
y_out.reset();
wait();
}
while(1) {
// HLS_PIPELINE_LOOP(HARD_STALL, 1, "main_loop");
HLS_PIPELINE_LOOP(SOFT_STALL, 1, "main_loop");
DT x_val = x_in.get();
DT out_val = x_val + 1;
y_out.put(out_val);
}
}
這里使用了輸入間隔為1個周期(每個周期均可輸入)的SOFT_STALL形式的流水線狰域。
2.層次化設(shè)計
為了觀察流水線功能,這次將兩個+1功能模塊dut_template
連在一起進(jìn)行仿真屈溉,頂層為pipeline_test
抬探,代碼如下所所示:
#ifndef _DUT_PIPE
#define _DUT_PIPE
#include "cynw_p2p.h"
#include "cynw_fifo.h"
#include "defines.h"
#include "dut_template_wrap.h"
SC_MODULE(pipeline_test) {
public:
cynw_p2p<DT, ioConfig>::base_in x_in;
cynw_p2p<DT, ioConfig>::base_out y_out;
cynw_p2p<DT, ioConfig> tmp;
sc_in_clk clk;
sc_in<bool> rst;
dut_template_wrapper *ut0;
dut_template_wrapper *ut1;
SC_CTOR(pipeline_test):
x_in("x_in"),y_out("y_out"),tmp("tmp"),
clk("clk"),rst("rst") {
ut0 = new dut_template_wrapper("ut0");
ut0->clk(clk);
ut0->rst(rst);
ut0->x_in(x_in);
ut0->y_out(tmp);
ut1 = new dut_template_wrapper("ut1");
ut1->clk(clk);
ut1->rst(rst);
ut1->x_in(tmp);
ut1->y_out(y_out);
}
// void t(); 不可調(diào)用函數(shù)進(jìn)行連線J荒馈3『健!
};
#endif
首先關(guān)注使用的p2p接口如下所示:
cynw_p2p<DT, ioConfig>::base_in x_in;
cynw_p2p<DT, ioConfig>::base_out y_out;
需要注意的是本次使用了base_in
和base_out
而不是in
和out
(參考筆記1)僻造,因為這兩個端口的目的僅僅為連接使用孩饼,相當(dāng)于連線,因此不需要使用in
和out
立膛,也不需要指定時鐘與復(fù)位信號梯码。隨后關(guān)注調(diào)用部分:
dut_template_wrapper *ut0;
dut_template_wrapper *ut1;
這里的調(diào)用方式為調(diào)用dut_template_wrapper
而不是dut_template
轩娶,這是Stratus的區(qū)別,若要在高級綜合中保留層次結(jié)構(gòu)闯捎,則需要在這里調(diào)用wrapper
而不是本身许溅,對應(yīng)的,也需要在tcl中指定子模塊dut_template
為待綜合模塊娱仔。最后一點需要注意的是牲迫,SC_CTOR
中連線部分需要在本函數(shù)中編寫,不可像system中一樣調(diào)用函數(shù)進(jìn)行連線筛峭,否則會在仿真過程中產(chǎn)生問題陪每。該設(shè)計對應(yīng)的project.tcl如下所示:
...
use_tech_lib "$LIB_PATH/$LIB_LEAF"
set_attr clock_period 10.0
set_attr message_detail 3
set_attr default_input_delay 0.1
set_attr cc_options " -g --std=c++0x"
enable_waveform_logging -vcd
set_attr end_of_sim_command "make saySimPassed"
define_system_module basic_ut/main.cpp
define_system_module basic_ut/system.cpp
define_system_module basic_ut/tb.cpp
define_hls_module pipeline_test dut_module/pipeline_test.cpp
define_hls_module dut_template dut_module/dut_template.cpp # 子模塊也需要指定為待綜合模塊
define_io_config * TLM
define_io_config * PIN
define_hls_config pipeline_test BASIC
define_hls_config dut_template BASIC # 子模塊也需要指定綜合等級
define_sim_config T -io_config TLM
define_sim_config B -io_config PIN
define_sim_config H {pipeline_test RTL_V BASIC}
3.仿真結(jié)果
仿真結(jié)束后使用verdi查看波形檩禾,未添加流水線的波形如下所示:
可以發(fā)現(xiàn)這種情況下每兩個周期才能輸入一個數(shù)據(jù)盼产,添加了流水線的波形如下所示:
添加了流水線展開后戏售,可以發(fā)現(xiàn)每個時鐘周期均可輸入新的數(shù)據(jù)。