新聞中心

EEPW首頁 > 網(wǎng)絡(luò)與存儲(chǔ) > 設(shè)計(jì)應(yīng)用 > Vivado HLS推動(dòng)協(xié)議處理系統(tǒng)蓬勃發(fā)展(下)

Vivado HLS推動(dòng)協(xié)議處理系統(tǒng)蓬勃發(fā)展(下)

作者:KimonKarras JamesHrica 時(shí)間:2015-04-29 來源:電子產(chǎn)品世界 收藏

  5 流分割和合并

本文引用地址:http://www.butianyuan.cn/article/273295.htm

  在協(xié)議處理中,根據(jù)協(xié)議棧特定字段轉(zhuǎn)發(fā)數(shù)據(jù)包給不同模塊,然后在發(fā)送前將不同的流重新組合,是一項(xiàng)關(guān)鍵功能。 HLS允許使用高級(jí)架構(gòu)來推動(dòng)這一轉(zhuǎn)發(fā)過程,具體如例4中所示的流合并。

  例4:簡(jiǎn)單的流合并情況

  1 void merge(stream inData[NUM_MERGE_
  STREAMS], stream&outData) {
  2 #pragma HLS INLINE off
  3 #pragma HLS pipeline II=1 enable_flush
  4
  5 static enum mState{M_IDLE = 0, M_STREAM}
  mergeState;
  6 static ap_uint
  rrCtr = 0;
  7 static ap_uint
  streamSource = 0;
  8 axiWord inputWord = {0, 0, 0, 0};
  9
  10 switch(mergeState) {
  11 case M_IDLE:
  12 bool streamEmpty[NUM_MERGE_STREAMS];
  13 #pragma HLS ARRAY_PARTITION variable=stream-
  Empty complete
  14 for (uint8_t i=0;i
  15 streamEmpty[i] = inData[i].empty();
  16 for (uint8_t i=0;i
  17 uint8_t tempCtr = streamSource + 1 + i;
  18 if (tempCtr >= NUM_MERGE_STREAMS)
  19 tempCtr -= NUM_MERGE_STREAMS;
  20 if(!streamEmpty[tempCtr]) {
  21 streamSource = tempCtr;
  22 inputWord = inData[streamSource].
  read();
  23 outData.write(inputWord);
  24 if (inputWord.last == 0)
  25 mergeState = M_STREAM;
  26 break;
  27 }
  28 }
  29 break;
  30 case M_STREAM:
  31 if (!inData[streamSource].empty()) {
  32 inData[streamSource].read(inputWord);
  33 outData.write(inputWord);
  34 if (inputWord.last == 1)
  35 mergeState = M_IDLE;
  36 }
  37 break;
  38 }
  39 }

  本例體現(xiàn)的是模塊合并功能的使用,其中一個(gè)流陣列作為輸入(inData),一個(gè)單流作為輸出(outData)。這個(gè)模塊的功能是以無區(qū)別的方式從輸入流讀取數(shù)據(jù),然后將讀取的數(shù)據(jù)輸出給輸出流。該模塊采用雙級(jí)FSM實(shí)現(xiàn),其結(jié)構(gòu)與前文介紹的結(jié)構(gòu)一致。

  FSM的第一個(gè)狀態(tài)用于確保選擇輸入流的無區(qū)別性(fairness)。實(shí)現(xiàn)的方法是使用循環(huán)算法檢查隊(duì)列。該算法在完成上一隊(duì)列的訪問之后,即從下一隊(duì)列起查找新的數(shù)據(jù)。第17到19行的代碼采用的即是此循環(huán)算法。常量NUM_MERGE_STREAMS用于設(shè)定待合并的流的數(shù)量。接下來的第20行負(fù)責(zé)測(cè)試當(dāng)前的流,其內(nèi)容用tempCntr變量標(biāo)示。如果當(dāng)前流非空,則將其設(shè)置為活躍流(第21行)。然后從該流中讀取數(shù)據(jù)(第22行)。如果讀取的數(shù)據(jù)字不是最后一個(gè)數(shù)據(jù)字(由第24行負(fù)責(zé)檢查),則狀態(tài)機(jī)進(jìn)入M_STREAM狀態(tài),然后輸出來自該流的剩余數(shù)據(jù)字。在處理完成最后一個(gè)數(shù)據(jù)字后,F(xiàn)SM返回M_IDLE狀態(tài),然后重復(fù)上述過程。

  這個(gè)模塊引入了一個(gè)新的編譯指令,稱為“array_partition”。該編譯指令能讓 HLS了解為了提高吞吐量,是否需要把一個(gè)陣列拆分為多個(gè)子陣列。如果未加設(shè)定, HLS會(huì)使用雙端口B來訪問陣列。如果要在一個(gè)時(shí)鐘周期中訪問陣列兩次以上,如果不適當(dāng)?shù)靥岣叱跏蓟g隔(II)的值,該工具將無法調(diào)度這些訪問。在本例中,略去array_partition編譯指令,將NUN_MERGE_STREAMS值設(shè)為8,就可以讓II=4。但因?yàn)橄肽軌蛟诿總€(gè)時(shí)鐘周期內(nèi)訪問steamEmpty陣列的所有元素,讓目標(biāo)II=1,我們需要對(duì)這個(gè)陣列進(jìn)行充分分區(qū)。在本例中,該陣列實(shí)現(xiàn)為一組基于觸發(fā)器的寄存器。

  拆分輸入流的過程耳熟能詳,把來自一個(gè)流的數(shù)據(jù)字正確地路由到一個(gè)流陣列即可。

  6 抽取字段和重新對(duì)齊字段

  在包處理中,抽取字段和重新對(duì)齊字段是最基本的操作之一。由于數(shù)據(jù)包一般是經(jīng)過多個(gè)時(shí)鐘周期內(nèi)通過總線到達(dá)模塊的,常見的情況是需要的字段要么在它們抵達(dá)的數(shù)據(jù)字中未能對(duì)齊,要么分散在多個(gè)數(shù)據(jù)字中(往往兩種情況都有)。因此要處理這些字段,必須將它們從數(shù)據(jù)流中抽取出來,存入緩存然后重新對(duì)齊以便處理。

  例5:源MAC地址抽取示例

  1 if (!inData.empty()) {
  2 inData.read(currWord);
  3 switch(wordCount) {
  4 case 0:
  5 MAC_DST = currWord.data.range(47, 0);
  6 MAC_SRC.range(15, 0) = currWord.data.
  range(63, 48);
  7 break;
  8 case 1:
  9 MAC_SRC.range(47 ,16) = currWord.
  data.range(31, 0);
  10 break;
  11 case 2:
  12 ……

  例5是一個(gè)非常簡(jiǎn)單的字段抽取和再對(duì)齊示例。這個(gè)示例從以太網(wǎng)報(bào)頭中抽取源MAC地址。數(shù)據(jù)通過稱為“inData”的64位流抵達(dá)。在每個(gè)時(shí)鐘周期讀入數(shù)據(jù)(第2行)。隨后根據(jù)讀取的數(shù)據(jù)字執(zhí)行合適的語句。因此在第5行中源MAC地址的頭16位被抽取出來,并移位到MAC_SRC變量的起始部分。在下一時(shí)鐘周期中,MAC地址的其余32位抵達(dá)總線,然后存入MAC_SRC變量的32位更高位中。

c++相關(guān)文章:c++教程




關(guān)鍵詞: Vivado FIFO 存儲(chǔ)器 RAM C/C++

評(píng)論


相關(guān)推薦

技術(shù)專區(qū)

關(guān)閉