0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

PCIe例程理解之用戶邏輯接收模塊仿真分析

冬至子 ? 來(lái)源:FPGA LAB ? 作者:李銳博恩 ? 2023-06-21 15:43 ? 次閱讀

前言

本文從例子程序細(xì)節(jié)上(語(yǔ)法層面)去理解PCIe對(duì)于事物層數(shù)據(jù)的接收及解析。參考數(shù)據(jù)手冊(cè):PG054;例子程序有Vivado生成;

為什么將這個(gè)內(nèi)容寫(xiě)出來(lái)?

通過(guò)寫(xiě)博客,可以檢驗(yàn)自己理解了這個(gè)設(shè)計(jì)沒(méi)有,這像是一個(gè)提問(wèn)題并自我解讀的過(guò)程,如果你提出了問(wèn)題,但發(fā)現(xiàn)自己解決不了,那問(wèn)題就在這里。

例程是入門(mén)某一個(gè)IP核的最好途徑,它可以作為你進(jìn)一步設(shè)計(jì)的基礎(chǔ)。你的后續(xù)設(shè)計(jì)都可以基于此。

正文

理解一個(gè)新的設(shè)計(jì)的最好方法是仿真,Aurora如此,PCIe也是如此,自己定制一個(gè)PCIe的IP核,之后右擊生成相應(yīng)的例程。

圖片

該例程是一個(gè)PIO例程,所謂的PIO,其全稱為:The Programmed Input/Output (PIO) ,即可編程輸入輸出。

編程輸入/輸出(PIO)事務(wù)通常由PCI Express系統(tǒng)主機(jī)CPU用于訪問(wèn)PCI Express邏輯中的內(nèi)存映射輸入/輸出(MMIO)和配置映射輸入/輸出(CMIO)位置。PCI Express的端點(diǎn)接受內(nèi)存和I/O寫(xiě)事務(wù),并以帶有數(shù)據(jù)的完成事務(wù)來(lái)響應(yīng)內(nèi)存和I/O讀事務(wù)。

FPGA端作為Endpoint,PC端作為Root,其對(duì)FPGA的存儲(chǔ)空間進(jìn)行讀寫(xiě),讀寫(xiě)分為很多類別,可以是存儲(chǔ)器讀寫(xiě),也可以是I/O讀寫(xiě),細(xì)節(jié)可在數(shù)據(jù)手冊(cè)上進(jìn)行學(xué)習(xí)。

仿真平臺(tái)

仿真平臺(tái)的結(jié)構(gòu)圖如下:

圖片

上面的部分為用戶邏輯,我們這里面接收并解析PCIe IP核收到的請(qǐng)求,例如讀請(qǐng)求包,我們就會(huì)返還一個(gè)完成包,或者是一個(gè)寫(xiě)請(qǐng)求包,我們負(fù)責(zé)將寫(xiě)數(shù)據(jù)寫(xiě)入FPGA RAM空間等等。如:

圖片

下面部分是PCIe IP經(jīng)過(guò)例程包裝后的部分,它與Root端進(jìn)行高速串行通信。通信速率以及數(shù)據(jù)帶寬根據(jù)PCIe IP的配置有關(guān),例如是Gen2 X1就是單通道且鏈路速率是5Gbps的PCIe;Gen1 X1則是單通道且鏈路速率為2.5Gbps的 PCIe.

圖片

下圖是例程中的用戶邏輯部分的模塊結(jié)構(gòu)圖:

圖片

我們常??吹紼P作為前綴的命名,其意思就是Endpoint,指的就是FPGA這端。我們都知道PCIe是端對(duì)端通信,協(xié)議規(guī)定的就是PC端為Root,而FPGA端為Endpoint。

可見(jiàn),上面有如下幾個(gè)模塊:EP_RX:該模塊是接收來(lái)自PCIe IP核收到的請(qǐng)求,該請(qǐng)求肯定是來(lái)自于PC端或者叫Root端,讀請(qǐng)求或者是寫(xiě)請(qǐng)求;一般而言,收到一個(gè)請(qǐng)求包之后,RX會(huì)對(duì)其進(jìn)行解析,如果是讀請(qǐng)求,則需要通過(guò)另一個(gè)發(fā)送模塊回復(fù)一個(gè)讀完成包。

EP_TX:該模塊用來(lái)向Root端發(fā)送數(shù)據(jù)包,該包在這個(gè)模塊組裝,然后通過(guò)AXI-S協(xié)議發(fā)送給IP核,進(jìn)而與Root進(jìn)行通信。

EP_MEM:該模塊的作用很簡(jiǎn)單,就是一個(gè)存儲(chǔ)結(jié)構(gòu),由于Root向EP發(fā)送讀寫(xiě)請(qǐng)求,例如讀,從哪里讀數(shù)據(jù)呢?就在這個(gè)模塊里呀,寫(xiě)到哪里去呢?也是從這個(gè)模塊里呀。

PIO_TO_CTRL:這個(gè)模塊的作用呢?是管理cfg_turnoff_ok這個(gè)信號(hào)的,具體什么用?需要斟酌!

例程手冊(cè)程序概括

PIO設(shè)計(jì)是一個(gè)簡(jiǎn)單的只針對(duì)目標(biāo)的應(yīng)用程序,它與PCIe核心事務(wù)(AXI4-Stream)的端點(diǎn)接口相連接,并被提供作為構(gòu)建自己設(shè)計(jì)的起點(diǎn)。

為了直觀地理解Root Complex與Endpoint之間的區(qū)別,我們以下面的PCIe系統(tǒng)結(jié)構(gòu)圖為例,來(lái)說(shuō)明數(shù)據(jù)的傳輸情況:

圖片

上圖中多了一個(gè)PCIe Switch結(jié)構(gòu),不過(guò)沒(méi)關(guān)系,我們可以把它當(dāng)成中間的過(guò)渡結(jié)構(gòu),它不影響我們Endpoint端以及Root complex端的數(shù)據(jù)處理。

圖5-3說(shuō)明了PCI Express系統(tǒng)結(jié)構(gòu)組件,由一個(gè)Root Complex、一個(gè)PCI Express交換設(shè)備和一個(gè)PCIe的Endpoint組成。PIO操作將數(shù)據(jù)從Root Complex(CPU寄存器)向下游移動(dòng)到Endpoint,和/或從Endpoint向上游移動(dòng)到Root Complex(CPU寄存器)。在這兩種情況下,移動(dòng)數(shù)據(jù)的PCI Express協(xié)議請(qǐng)求都是由主機(jī)CPU發(fā)起的。

當(dāng)CPU向MMIO地址命令發(fā)出存儲(chǔ)寄存器時(shí),數(shù)據(jù)將向下游移動(dòng)。Root Complex通常會(huì)生成一個(gè)具有適當(dāng)MMIO地址的存儲(chǔ)器寫(xiě)TLP包和字節(jié)使能。當(dāng)Endpoint接收到存儲(chǔ)器寫(xiě)TLP并更新相應(yīng)的本地寄存器時(shí),事務(wù)終止。

當(dāng)CPU通過(guò)MMIO地址命令發(fā)出加載寄存器時(shí),數(shù)據(jù)將向上游移動(dòng)。Root Complex通常會(huì)生成具有適當(dāng)MMIO位置地址的存儲(chǔ)器讀TLP包和字節(jié)使能。Endpoint在收到“內(nèi)存讀取” TLP后會(huì)生成“數(shù)據(jù)TLP完成包”。將完成操作引導(dǎo)到Root Complex,并將有效負(fù)載加載到目標(biāo)寄存器中,從而完成事務(wù)。

此兩端較為生澀,放入英文原文:

Data is moved downstream when the CPU issues a store register to a MMIO address command. The Root Complex typically generates a Memory Write TLP with the appropriate MMIO location address, byte enables, and the register contents. The transaction terminates when the Endpoint receives the Memory Write TLP and updates the corresponding local register.

Data is moved upstream when the CPU issues a load register from a MMIO address command. The Root Complex typically generates a Memory Read TLP with the appropriate MMIO location address and byte enables. The Endpoint generates a Completion with Data TLP after it receives the Memory Read TLP. The Completion is steered to the Root Complex and payload is loaded into the target register, completing the transaction.

例程用戶邏輯包括如下文件:

圖片

應(yīng)用程序內(nèi)部數(shù)據(jù)寬度,即AXI-Stream數(shù)據(jù)總線寬度根據(jù)鏈路通道數(shù)不同而不同,其關(guān)系為:

圖片

則在程序里也有體現(xiàn),例如我使用的是X1模式,因此:

圖片

該例程的所有模塊組件:

圖片

則從文件結(jié)構(gòu)也能看出:

圖片

應(yīng)用程序,也即用戶邏輯的接口關(guān)系為:

圖片

這里是以X1為例。

應(yīng)用程序中的接收模塊:

圖片

接收來(lái)自于PCIe IP核的數(shù)據(jù),該模塊與PCIe IP模塊之間的接口為AXI-Stream,后面就不在贅述,對(duì)來(lái)自Root Complex端的讀寫(xiě)請(qǐng)求包(TLP)進(jìn)行接收并解析。

假如接收到了Root端的讀請(qǐng)求TLP,則輸出信號(hào)如下:

圖片

這都是對(duì)接收的數(shù)據(jù)包進(jìn)行解析出來(lái)的結(jié)果,我們都知道PCIe是以包的形式來(lái)發(fā)送數(shù)據(jù)或者接收數(shù)據(jù)。TLP包的結(jié)構(gòu)可見(jiàn)PCIe的事務(wù)處包(TLP)的組成,則在數(shù)據(jù)手冊(cè)PG054上也是詳細(xì)描述的。對(duì)這個(gè)包的輸出發(fā)送給TX模塊,把讀出來(lái)的數(shù)據(jù)一同組成一個(gè)完成包,發(fā)送給PCIe IP核進(jìn)而發(fā)送給Root Complex,這個(gè)過(guò)程是一個(gè)響應(yīng),對(duì)讀請(qǐng)求的一個(gè)響應(yīng),這需要另一個(gè)模塊,也即TX模塊進(jìn)行配合。下面會(huì)講到。

如果EP接收到的包是寫(xiě)請(qǐng)求包,則EP_RX會(huì)生成另外一些信號(hào):

圖片

輸出給存儲(chǔ)器訪問(wèn)模塊,對(duì)存儲(chǔ)器模塊進(jìn)行寫(xiě)數(shù)據(jù)。

發(fā)送模塊的接口示意圖:

圖片

右端為輸出的接口,為AXI-stream接口,與PCIe IP核連接,送出IP核需要的完成包。

其輸入與RX的輸入對(duì)應(yīng):

圖片

圖片

無(wú)論是讀還是寫(xiě),總得有個(gè)存儲(chǔ)器寫(xiě)進(jìn)入或者讀出來(lái)才行,這就是這個(gè)模塊:

圖片

其輸入輸出關(guān)系一目了然,不在話下。

按照數(shù)據(jù)手冊(cè)得說(shuō)法就是:

這個(gè)模塊就是處理來(lái)自于存儲(chǔ)器以及IO寫(xiě)得TLP包得數(shù)據(jù),將其寫(xiě)入存儲(chǔ)器,或者呢?用來(lái)響應(yīng)存儲(chǔ)器或者IO讀TLP包,從存儲(chǔ)器中讀出數(shù)據(jù);

對(duì)于寫(xiě)請(qǐng)求包,其接口如下:

圖片

對(duì)與讀,其接口如下:

圖片

下面講下對(duì)于讀請(qǐng)求事務(wù)包及其響應(yīng)完成包的時(shí)序關(guān)系:

圖片

如圖所示,先是接收到一個(gè)讀請(qǐng)求事務(wù)包,但第一個(gè)TLP包完成接收的時(shí)候,立刻令ready無(wú)效,并響應(yīng)一個(gè)完成包。等完成包響應(yīng)完成之后,拉高信號(hào)compl_done,表明響應(yīng)完成,之后再接收下一個(gè)事務(wù)包。

下面是寫(xiě)事物請(qǐng)求TLP的時(shí)序關(guān)系:

圖片

首先接收一個(gè)寫(xiě)請(qǐng)求事務(wù)包,然后寫(xiě)入存儲(chǔ)器,寫(xiě)入的過(guò)程中,拉高wr_busy,表明正在寫(xiě)。寫(xiě)入完成之后,令wr_busy無(wú)效,表明寫(xiě)入完成。之后再接收另一個(gè)寫(xiě)事務(wù)包。

這個(gè)例程的用戶程序消耗的資源為:

圖片

這表明使用了4個(gè)BRAM,就是用來(lái)寫(xiě)入以及讀出來(lái)自Root請(qǐng)求的數(shù)據(jù)的存儲(chǔ)器。

例程仿真分析

PIO_RX_ENGINE.v 分析:

首先,定義了一個(gè)變量in_packet_q,高有效,用來(lái)表示接收一個(gè)TLP包。

如下:

wire               sop;                   // Start of packet
reg                in_packet_q;
always@(posedge clk)
      begin
        if(!rst_n)
          in_packet_q <= #   TCQ 1'b0;
        else if (m_axis_rx_tvalid && m_axis_rx_tready && m_axis_rx_tlast)
          in_packet_q <= #   TCQ 1'b0;
        else if (sop && m_axis_rx_tready)
          in_packet_q <= #   TCQ 1'b1;

      end

      assign sop = !in_packet_q && m_axis_rx_tvalid;

sop表示包的開(kāi)始,sop有效的條件自然是in_packet_q無(wú)效且valid有效;即:

assign sop = !in_packet_q && m_axis_rx_tvalid;

包什么時(shí)候有效呢?可以看出是sop有效且ready有效,這時(shí)候有人可能就有點(diǎn)暈了,到底是in_packet_q決定sop呢?還是sop決定in_packet_q呢?那必然是in_packet_q決定sop呀,因?yàn)閟op的含義是包的開(kāi)始呀。將sop代入in_packet_q有效的條件中去:

always@(posedge clk)
      begin
        if(!rst_n)
          in_packet_q <= #   TCQ 1'b0;
        else if (m_axis_rx_tvalid && m_axis_rx_tready && m_axis_rx_tlast)
          in_packet_q <= #   TCQ 1'b0;
        else if (!in_packet_q && m_axis_rx_valid && m_axis_rx_tready)
          in_packet_q <= #   TCQ 1'b1;

      end

這就很明白了,其實(shí)這段程序的作用(請(qǐng)?jiān)试S我用程序來(lái)代表硬件描述語(yǔ)言)就是判斷包有效的標(biāo)志。valid和ready有效,這packet有效,一直持續(xù)到valid,ready,以及l(fā)ast都有效,last表示最后一個(gè)數(shù)據(jù)??梢詮姆抡鎴D中來(lái)觀察:

圖片

有了包的起始標(biāo)志,就可以通過(guò)判斷這個(gè)信號(hào)有效,進(jìn)入了包的解析狀態(tài)機(jī);這里使用了一個(gè)狀態(tài)機(jī)來(lái)處理接收的TLP,對(duì)其進(jìn)行解析,解析數(shù)據(jù):

always @ ( posedge clk ) begin

        if (!rst_n )
        begin

          m_axis_rx_tready <= #TCQ 1'b0;

          req_compl    <= #TCQ 1'b0;
          req_compl_wd <= #TCQ 1'b1;

          req_tc       <= #TCQ 3'b0;
          req_td       <= #TCQ 1'b0;
          req_ep       <= #TCQ 1'b0;
          req_attr     <= #TCQ 2'b0;
          req_len      <= #TCQ 10'b0;
          req_rid      <= #TCQ 16'b0;
          req_tag      <= #TCQ 8'b0;
          req_be       <= #TCQ 8'b0;
          req_addr     <= #TCQ 13'b0;

          wr_be        <= #TCQ 8'b0;
          wr_addr      <= #TCQ 11'b0;
          wr_data      <= #TCQ 32'b0;
          wr_en        <= #TCQ 1'b0;

          state        <= #TCQ PIO_RX_RST_STATE;
          tlp_type     <= #TCQ 8'b0;

        end
        else
        begin

          wr_en        <= #TCQ 1'b0;
          req_compl    <= #TCQ 1'b0;

          case (state)

            PIO_RX_RST_STATE : begin

              m_axis_rx_tready <= #TCQ 1'b1;
              req_compl_wd     <= #TCQ 1'b1;


              if (sop)
              begin

                case (m_axis_rx_tdata[30:24])

                  PIO_RX_MEM_RD32_FMT_TYPE : begin

                    tlp_type     <= #TCQ m_axis_rx_tdata[31:24];
                    req_len      <= #TCQ m_axis_rx_tdata[9:0];
                    m_axis_rx_tready <= #TCQ 1'b0;


                    if (m_axis_rx_tdata[9:0] == 10'b1)
                    begin

                      req_tc     <= #TCQ m_axis_rx_tdata[22:20];
                      req_td     <= #TCQ m_axis_rx_tdata[15];
                      req_ep     <= #TCQ m_axis_rx_tdata[14];
                      req_attr   <= #TCQ m_axis_rx_tdata[13:12];
                      req_len    <= #TCQ m_axis_rx_tdata[9:0];
                      req_rid    <= #TCQ m_axis_rx_tdata[63:48];
                      req_tag    <= #TCQ m_axis_rx_tdata[47:40];
                      req_be     <= #TCQ m_axis_rx_tdata[39:32];
                      state      <= #TCQ PIO_RX_MEM_RD32_DW1DW2;

                    end // if (m_axis_rx_tdata[9:0] == 10'b1)
                    else
                    begin

                      state        <= #TCQ PIO_RX_RST_STATE;

                    end // if !(m_axis_rx_tdata[9:0] == 10'b1)

                  end // PIO_RX_MEM_RD32_FMT_TYPE

                  PIO_RX_MEM_WR32_FMT_TYPE : begin

                    tlp_type     <= #TCQ m_axis_rx_tdata[31:24];
                    req_len      <= #TCQ m_axis_rx_tdata[9:0];
                    m_axis_rx_tready <= #TCQ 1'b0;

                    if (m_axis_rx_tdata[9:0] == 10'b1)
                    begin

                      wr_be      <= #TCQ m_axis_rx_tdata[39:32];
                      state      <= #TCQ PIO_RX_MEM_WR32_DW1DW2;

                    end // if (m_axis_rx_tdata[9:0] == 10'b1)
                    else
                    begin

                      state      <= #TCQ PIO_RX_RST_STATE;

                    end // if !(m_axis_rx_tdata[9:0] == 10'b1)

                  end // PIO_RX_MEM_WR32_FMT_TYPE

                  PIO_RX_MEM_RD64_FMT_TYPE : begin

                    tlp_type     <= #TCQ m_axis_rx_tdata[31:24];
                    req_len      <= #TCQ m_axis_rx_tdata[9:0];
                    m_axis_rx_tready <= #TCQ 1'b0;

                    if (m_axis_rx_tdata[9:0] == 10'b1)
                    begin

                      req_tc     <= #TCQ m_axis_rx_tdata[22:20];
                      req_td     <= #TCQ m_axis_rx_tdata[15];
                      req_ep     <= #TCQ m_axis_rx_tdata[14];
                      req_attr   <= #TCQ m_axis_rx_tdata[13:12];
                      req_len    <= #TCQ m_axis_rx_tdata[9:0];
                      req_rid    <= #TCQ m_axis_rx_tdata[63:48];
                      req_tag    <= #TCQ m_axis_rx_tdata[47:40];
                      req_be     <= #TCQ m_axis_rx_tdata[39:32];
                      state        <= #TCQ PIO_RX_MEM_RD64_DW1DW2;

                    end // if (m_axis_rx_tdata[9:0] == 10'b1)
                    else
                    begin

                      state      <= #TCQ PIO_RX_RST_STATE;

                    end // if !(m_axis_rx_tdata[9:0] == 10'b1)

                  end // PIO_RX_MEM_RD64_FMT_TYPE

                  PIO_RX_MEM_WR64_FMT_TYPE : begin

                    tlp_type     <= #TCQ m_axis_rx_tdata[31:24];
                    req_len      <= #TCQ m_axis_rx_tdata[9:0];

                    if (m_axis_rx_tdata[9:0] == 10'b1) begin

                      wr_be      <= #TCQ m_axis_rx_tdata[39:32];
                      state      <= #TCQ PIO_RX_MEM_WR64_DW1DW2;

                    end // if (m_axis_rx_tdata[9:0] == 10'b1)
                    else
                    begin

                      state      <= #TCQ PIO_RX_RST_STATE;

                    end // if !(m_axis_rx_tdata[9:0] == 10'b1)

                  end // PIO_RX_MEM_WR64_FMT_TYPE


                  PIO_RX_IO_RD32_FMT_TYPE : begin

                    tlp_type     <= #TCQ m_axis_rx_tdata[31:24];
                    req_len      <= #TCQ m_axis_rx_tdata[9:0];
                    m_axis_rx_tready <= #TCQ 1'b0;


                    if (m_axis_rx_tdata[9:0] == 10'b1)
                    begin

                      req_tc     <= #TCQ m_axis_rx_tdata[22:20];
                      req_td     <= #TCQ m_axis_rx_tdata[15];
                      req_ep     <= #TCQ m_axis_rx_tdata[14];
                      req_attr   <= #TCQ m_axis_rx_tdata[13:12];
                      req_len    <= #TCQ m_axis_rx_tdata[9:0];
                      req_rid    <= #TCQ m_axis_rx_tdata[63:48];
                      req_tag    <= #TCQ m_axis_rx_tdata[47:40];
                      req_be     <= #TCQ m_axis_rx_tdata[39:32];
                      state      <= #TCQ PIO_RX_MEM_RD32_DW1DW2;

                    end // if (m_axis_rx_tdata[9:0] == 10'b1)
                    else
                    begin

                      state      <= #TCQ PIO_RX_RST_STATE;

                    end // if !(m_axis_rx_tdata[9:0] == 10'b1)

                  end // PIO_RX_IO_RD32_FMT_TYPE

                  PIO_RX_IO_WR32_FMT_TYPE : begin

                    tlp_type     <= #TCQ m_axis_rx_tdata[31:24];
                    req_len      <= #TCQ m_axis_rx_tdata[9:0];
                    m_axis_rx_tready <= #TCQ 1'b0;

                    if (m_axis_rx_tdata[9:0] == 10'b1)
                    begin

                      req_tc     <= #TCQ m_axis_rx_tdata[22:20];
                      req_td     <= #TCQ m_axis_rx_tdata[15];
                      req_ep     <= #TCQ m_axis_rx_tdata[14];
                      req_attr   <= #TCQ m_axis_rx_tdata[13:12];
                      req_len    <= #TCQ m_axis_rx_tdata[9:0];
                      req_rid    <= #TCQ m_axis_rx_tdata[63:48];
                      req_tag    <= #TCQ m_axis_rx_tdata[47:40];
                      req_be     <= #TCQ m_axis_rx_tdata[39:32];
                      wr_be      <= #TCQ m_axis_rx_tdata[39:32];
                      state      <= #TCQ PIO_RX_IO_WR_DW1DW2;

                    end //if (m_axis_rx_tdata[9:0] == 10'b1)
                    else
                    begin

                      state        <= #TCQ PIO_RX_RST_STATE;

                    end //if !(m_axis_rx_tdata[9:0] == 10'b1)

                  end // PIO_RX_IO_WR32_FMT_TYPE


                  default : begin // other TLPs

                    state        <= #TCQ PIO_RX_RST_STATE;

                  end // default

                endcase

              end // if (sop)
              else
                  state <= #TCQ PIO_RX_RST_STATE;

            end // PIO_RX_RST_STATE

            PIO_RX_MEM_RD32_DW1DW2 : begin

              if (m_axis_rx_tvalid)
              begin

                m_axis_rx_tready <= #TCQ 1'b0;
                req_addr     <= #TCQ {region_select[1:0],m_axis_rx_tdata[10:2], 2'b00};
                req_compl    <= #TCQ 1'b1;
                req_compl_wd <= #TCQ 1'b1;
                state        <= #TCQ PIO_RX_WAIT_STATE;

              end // if (m_axis_rx_tvalid)
              else
                state        <= #TCQ PIO_RX_MEM_RD32_DW1DW2;

            end // PIO_RX_MEM_RD32_DW1DW2


            PIO_RX_MEM_WR32_DW1DW2 : begin

              if (m_axis_rx_tvalid)
              begin

                wr_data      <= #TCQ m_axis_rx_tdata[63:32];
                wr_en        <= #TCQ 1'b1;
                m_axis_rx_tready <= #TCQ 1'b0;
                wr_addr      <= #TCQ {region_select[1:0],m_axis_rx_tdata[10:2]};
                state        <= #TCQ  PIO_RX_WAIT_STATE;

              end // if (m_axis_rx_tvalid)
              else
                state        <= #TCQ PIO_RX_MEM_WR32_DW1DW2;

            end // PIO_RX_MEM_WR32_DW1DW2


            PIO_RX_MEM_RD64_DW1DW2 : begin

              if (m_axis_rx_tvalid)
              begin

                req_addr     <= #TCQ {region_select[1:0],m_axis_rx_tdata[42:34], 2'b00};
                req_compl    <= #TCQ 1'b1;
                req_compl_wd <= #TCQ 1'b1;
                m_axis_rx_tready <= #TCQ 1'b0;
                state        <= #TCQ PIO_RX_WAIT_STATE;

              end // if (m_axis_rx_tvalid)
              else
                state        <= #TCQ PIO_RX_MEM_RD64_DW1DW2;

            end // PIO_RX_MEM_RD64_DW1DW2


            PIO_RX_MEM_WR64_DW1DW2 : begin

              if (m_axis_rx_tvalid)
              begin

                m_axis_rx_tready <= #TCQ 1'b0;
                wr_addr        <= #TCQ {region_select[1:0],m_axis_rx_tdata[42:34]};
                state          <= #TCQ  PIO_RX_MEM_WR64_DW3;

              end // if (m_axis_rx_tvalid)
              else
                state          <= #TCQ PIO_RX_MEM_WR64_DW1DW2;

            end // PIO_RX_MEM_WR64_DW1DW2


            PIO_RX_MEM_WR64_DW3 : begin

              if (m_axis_rx_tvalid)
              begin

                wr_data      <= #TCQ m_axis_rx_tdata[31:0];
                wr_en        <= #TCQ 1'b1;
                m_axis_rx_tready <= #TCQ 1'b0;
                state        <= #TCQ PIO_RX_WAIT_STATE;

              end // if (m_axis_rx_tvalid)
              else
                 state        <= #TCQ PIO_RX_MEM_WR64_DW3;

            end // PIO_RX_MEM_WR64_DW3


            PIO_RX_IO_WR_DW1DW2 : begin

              if (m_axis_rx_tvalid)
              begin

                wr_data         <= #TCQ m_axis_rx_tdata[63:32];
                wr_en           <= #TCQ 1'b1;
                m_axis_rx_tready  <= #TCQ 1'b0;
                wr_addr         <= #TCQ {region_select[1:0],m_axis_rx_tdata[10:2]};
                req_compl       <= #TCQ 1'b1;
                req_compl_wd    <= #TCQ 1'b0;
                state             <= #TCQ  PIO_RX_WAIT_STATE;

              end // if (m_axis_rx_tvalid)
              else
                state             <= #TCQ PIO_RX_IO_WR_DW1DW2;
            end // PIO_RX_IO_WR_DW1DW2

            PIO_RX_WAIT_STATE : begin

              wr_en      <= #TCQ 1'b0;
              req_compl  <= #TCQ 1'b0;

              if ((tlp_type == PIO_RX_MEM_WR32_FMT_TYPE) && (!wr_busy))
              begin

                m_axis_rx_tready <= #TCQ 1'b1;
                state        <= #TCQ PIO_RX_RST_STATE;

              end // if ((tlp_type == PIO_RX_MEM_WR32_FMT_TYPE) && (!wr_busy))
              else if ((tlp_type == PIO_RX_IO_WR32_FMT_TYPE) && (!wr_busy))
              begin

                m_axis_rx_tready <= #TCQ 1'b1;
                state        <= #TCQ PIO_RX_RST_STATE;

              end // if ((tlp_type == PIO_RX_IO_WR32_FMT_TYPE) && (!wr_busy))
              else if ((tlp_type == PIO_RX_MEM_WR64_FMT_TYPE) && (!wr_busy))
              begin

                m_axis_rx_tready <= #TCQ 1'b1;
                state        <= #TCQ PIO_RX_RST_STATE;

              end // if ((tlp_type == PIO_RX_MEM_WR64_FMT_TYPE) && (!wr_busy))
              else if ((tlp_type == PIO_RX_MEM_RD32_FMT_TYPE) && (compl_done))
              begin

                m_axis_rx_tready <= #TCQ 1'b1;
                state        <= #TCQ PIO_RX_RST_STATE;

              end // if ((tlp_type == PIO_RX_MEM_RD32_FMT_TYPE) && (compl_done))
              else if ((tlp_type == PIO_RX_IO_RD32_FMT_TYPE) && (compl_done))
              begin

                m_axis_rx_tready <= #TCQ 1'b1;
                state        <= #TCQ PIO_RX_RST_STATE;

              end // if ((tlp_type == PIO_RX_IO_RD32_FMT_TYPE) && (compl_done))
              else if ((tlp_type == PIO_RX_MEM_RD64_FMT_TYPE) && (compl_done))
              begin

                m_axis_rx_tready <= #TCQ 1'b1;
                state        <= #TCQ PIO_RX_RST_STATE;

              end // if ((tlp_type == PIO_RX_MEM_RD64_FMT_TYPE) && (compl_done))
              else
                state        <= #TCQ PIO_RX_WAIT_STATE;

            end // PIO_RX_WAIT_STATE

            default : begin
              // default case stmt
              state        <= #TCQ PIO_RX_RST_STATE;
            end // default

          endcase

        end

      end
    end

一段式狀態(tài)機(jī),寫(xiě)的很不錯(cuò)。使用了如下幾個(gè)大的狀態(tài):

localparam PIO_RX_MEM_RD32_FMT_TYPE = 7'b00_00000;
  localparam PIO_RX_MEM_WR32_FMT_TYPE = 7'b10_00000;
  localparam PIO_RX_MEM_RD64_FMT_TYPE = 7'b01_00000;
  localparam PIO_RX_MEM_WR64_FMT_TYPE = 7'b11_00000;
  localparam PIO_RX_IO_RD32_FMT_TYPE  = 7'b00_00010;
  localparam PIO_RX_IO_WR32_FMT_TYPE  = 7'b10_00010;

  localparam PIO_RX_RST_STATE            = 8'b00000000;
  localparam PIO_RX_MEM_RD32_DW1DW2      = 8'b00000001;
  localparam PIO_RX_MEM_WR32_DW1DW2      = 8'b00000010;
  localparam PIO_RX_MEM_RD64_DW1DW2      = 8'b00000100;
  localparam PIO_RX_MEM_WR64_DW1DW2      = 8'b00001000;
  localparam PIO_RX_MEM_WR64_DW3         = 8'b00010000;
  localparam PIO_RX_WAIT_STATE           = 8'b00100000;
  localparam PIO_RX_IO_WR_DW1DW2         = 8'b01000000;
  localparam PIO_RX_IO_MEM_WR_WAIT_STATE = 8'b10000000;

大的狀態(tài)機(jī)狀態(tài)是下面的一部分,即:

localparam PIO_RX_RST_STATE            = 8'b00000000;
  localparam PIO_RX_MEM_RD32_DW1DW2      = 8'b00000001;
  localparam PIO_RX_MEM_WR32_DW1DW2      = 8'b00000010;
  localparam PIO_RX_MEM_RD64_DW1DW2      = 8'b00000100;
  localparam PIO_RX_MEM_WR64_DW1DW2      = 8'b00001000;
  localparam PIO_RX_MEM_WR64_DW3         = 8'b00010000;
  localparam PIO_RX_WAIT_STATE           = 8'b00100000;
  localparam PIO_RX_IO_WR_DW1DW2         = 8'b01000000;
  localparam PIO_RX_IO_MEM_WR_WAIT_STATE = 8'b10000000;

上面的一部分參數(shù),不是狀態(tài)機(jī)的狀態(tài),而是一些匹配項(xiàng),稍后你就知道。

localparam PIO_RX_MEM_RD32_FMT_TYPE = 7'b00_00000;
  localparam PIO_RX_MEM_WR32_FMT_TYPE = 7'b10_00000;
  localparam PIO_RX_MEM_RD64_FMT_TYPE = 7'b01_00000;
  localparam PIO_RX_MEM_WR64_FMT_TYPE = 7'b11_00000;
  localparam PIO_RX_IO_RD32_FMT_TYPE  = 7'b00_00010;
  localparam PIO_RX_IO_WR32_FMT_TYPE  = 7'b10_00010;

PIO_RX_RST_STATE:

下面一個(gè)狀態(tài)一個(gè)狀態(tài)的分析,在第一個(gè)狀態(tài),即PIO_RX_RST_STATE下,做了如下處理:

if (sop)
              begin

                case (m_axis_rx_tdata[30:24])

                  PIO_RX_MEM_RD32_FMT_TYPE : begin

                    tlp_type     <= #TCQ m_axis_rx_tdata[31:24];
                    req_len      <= #TCQ m_axis_rx_tdata[9:0];
                    m_axis_rx_tready <= #TCQ 1'b0;


                    if (m_axis_rx_tdata[9:0] == 10'b1)
                    begin

                      req_tc     <= #TCQ m_axis_rx_tdata[22:20];
                      req_td     <= #TCQ m_axis_rx_tdata[15];
                      req_ep     <= #TCQ m_axis_rx_tdata[14];
                      req_attr   <= #TCQ m_axis_rx_tdata[13:12];
                      req_len    <= #TCQ m_axis_rx_tdata[9:0];
                      req_rid    <= #TCQ m_axis_rx_tdata[63:48];
                      req_tag    <= #TCQ m_axis_rx_tdata[47:40];
                      req_be     <= #TCQ m_axis_rx_tdata[39:32];
                      state      <= #TCQ PIO_RX_MEM_RD32_DW1DW2;

                    end // if (m_axis_rx_tdata[9:0] == 10'b1)
                    else
                    begin

                      state        <= #TCQ PIO_RX_RST_STATE;

                    end // if !(m_axis_rx_tdata[9:0] == 10'b1)

                  end // PIO_RX_MEM_RD32_FMT_TYPE

                  PIO_RX_MEM_WR32_FMT_TYPE : begin

                    tlp_type     <= #TCQ m_axis_rx_tdata[31:24];
                    req_len      <= #TCQ m_axis_rx_tdata[9:0];
                    m_axis_rx_tready <= #TCQ 1'b0;

                    if (m_axis_rx_tdata[9:0] == 10'b1)
                    begin

                      wr_be      <= #TCQ m_axis_rx_tdata[39:32];
                      state      <= #TCQ PIO_RX_MEM_WR32_DW1DW2;

                    end // if (m_axis_rx_tdata[9:0] == 10'b1)
                    else
                    begin

                      state      <= #TCQ PIO_RX_RST_STATE;

                    end // if !(m_axis_rx_tdata[9:0] == 10'b1)

                  end // PIO_RX_MEM_WR32_FMT_TYPE

                  PIO_RX_MEM_RD64_FMT_TYPE : begin

                    tlp_type     <= #TCQ m_axis_rx_tdata[31:24];
                    req_len      <= #TCQ m_axis_rx_tdata[9:0];
                    m_axis_rx_tready <= #TCQ 1'b0;

                    if (m_axis_rx_tdata[9:0] == 10'b1)
                    begin

                      req_tc     <= #TCQ m_axis_rx_tdata[22:20];
                      req_td     <= #TCQ m_axis_rx_tdata[15];
                      req_ep     <= #TCQ m_axis_rx_tdata[14];
                      req_attr   <= #TCQ m_axis_rx_tdata[13:12];
                      req_len    <= #TCQ m_axis_rx_tdata[9:0];
                      req_rid    <= #TCQ m_axis_rx_tdata[63:48];
                      req_tag    <= #TCQ m_axis_rx_tdata[47:40];
                      req_be     <= #TCQ m_axis_rx_tdata[39:32];
                      state        <= #TCQ PIO_RX_MEM_RD64_DW1DW2;

                    end // if (m_axis_rx_tdata[9:0] == 10'b1)
                    else
                    begin

                      state      <= #TCQ PIO_RX_RST_STATE;

                    end // if !(m_axis_rx_tdata[9:0] == 10'b1)

                  end // PIO_RX_MEM_RD64_FMT_TYPE

                  PIO_RX_MEM_WR64_FMT_TYPE : begin

                    tlp_type     <= #TCQ m_axis_rx_tdata[31:24];
                    req_len      <= #TCQ m_axis_rx_tdata[9:0];

                    if (m_axis_rx_tdata[9:0] == 10'b1) begin

                      wr_be      <= #TCQ m_axis_rx_tdata[39:32];
                      state      <= #TCQ PIO_RX_MEM_WR64_DW1DW2;

                    end // if (m_axis_rx_tdata[9:0] == 10'b1)
                    else
                    begin

                      state      <= #TCQ PIO_RX_RST_STATE;

                    end // if !(m_axis_rx_tdata[9:0] == 10'b1)

                  end // PIO_RX_MEM_WR64_FMT_TYPE


                  PIO_RX_IO_RD32_FMT_TYPE : begin

                    tlp_type     <= #TCQ m_axis_rx_tdata[31:24];
                    req_len      <= #TCQ m_axis_rx_tdata[9:0];
                    m_axis_rx_tready <= #TCQ 1'b0;


                    if (m_axis_rx_tdata[9:0] == 10'b1)
                    begin

                      req_tc     <= #TCQ m_axis_rx_tdata[22:20];
                      req_td     <= #TCQ m_axis_rx_tdata[15];
                      req_ep     <= #TCQ m_axis_rx_tdata[14];
                      req_attr   <= #TCQ m_axis_rx_tdata[13:12];
                      req_len    <= #TCQ m_axis_rx_tdata[9:0];
                      req_rid    <= #TCQ m_axis_rx_tdata[63:48];
                      req_tag    <= #TCQ m_axis_rx_tdata[47:40];
                      req_be     <= #TCQ m_axis_rx_tdata[39:32];
                      state      <= #TCQ PIO_RX_MEM_RD32_DW1DW2;

                    end // if (m_axis_rx_tdata[9:0] == 10'b1)
                    else
                    begin

                      state      <= #TCQ PIO_RX_RST_STATE;

                    end // if !(m_axis_rx_tdata[9:0] == 10'b1)

                  end // PIO_RX_IO_RD32_FMT_TYPE

                  PIO_RX_IO_WR32_FMT_TYPE : begin

                    tlp_type     <= #TCQ m_axis_rx_tdata[31:24];
                    req_len      <= #TCQ m_axis_rx_tdata[9:0];
                    m_axis_rx_tready <= #TCQ 1'b0;

                    if (m_axis_rx_tdata[9:0] == 10'b1)
                    begin

                      req_tc     <= #TCQ m_axis_rx_tdata[22:20];
                      req_td     <= #TCQ m_axis_rx_tdata[15];
                      req_ep     <= #TCQ m_axis_rx_tdata[14];
                      req_attr   <= #TCQ m_axis_rx_tdata[13:12];
                      req_len    <= #TCQ m_axis_rx_tdata[9:0];
                      req_rid    <= #TCQ m_axis_rx_tdata[63:48];
                      req_tag    <= #TCQ m_axis_rx_tdata[47:40];
                      req_be     <= #TCQ m_axis_rx_tdata[39:32];
                      wr_be      <= #TCQ m_axis_rx_tdata[39:32];
                      state      <= #TCQ PIO_RX_IO_WR_DW1DW2;

                    end //if (m_axis_rx_tdata[9:0] == 10'b1)
                    else
                    begin

                      state        <= #TCQ PIO_RX_RST_STATE;

                    end //if !(m_axis_rx_tdata[9:0] == 10'b1)

                  end // PIO_RX_IO_WR32_FMT_TYPE


                  default : begin // other TLPs

                    state        <= #TCQ PIO_RX_RST_STATE;

                  end // default

                endcase

              end // if (sop)
              else
                  state <= #TCQ PIO_RX_RST_STATE;

首先判斷包的開(kāi)始,如果開(kāi)始有效,則代表接收到TLP包,我們可以對(duì)其進(jìn)行解析:

圖片

我們需要知道的預(yù)先知識(shí)是TLP包的各個(gè)位代表著什么,這樣才能對(duì)其解析,提取需要的信息。PIO_RX_RST_STATE狀態(tài)下一直在判斷m_axis_rx_tdata[30:24]和如下哪一個(gè)參數(shù)匹配:

localparam PIO_RX_MEM_RD32_FMT_TYPE = 7'b00_00000;
  localparam PIO_RX_MEM_WR32_FMT_TYPE = 7'b10_00000;
  localparam PIO_RX_MEM_RD64_FMT_TYPE = 7'b01_00000;
  localparam PIO_RX_MEM_WR64_FMT_TYPE = 7'b11_00000;
  localparam PIO_RX_IO_RD32_FMT_TYPE  = 7'b00_00010;
  localparam PIO_RX_IO_WR32_FMT_TYPE  = 7'b10_00010;

如果和PIO_RX_MEM_RD32_FMT_TYPE匹配,則執(zhí)行如下程序:

PIO_RX_MEM_RD32_FMT_TYPE : begin

                    tlp_type     <= #TCQ m_axis_rx_tdata[31:24];
                    req_len      <= #TCQ m_axis_rx_tdata[9:0];
                    m_axis_rx_tready <= #TCQ 1'b0;


                    if (m_axis_rx_tdata[9:0] == 10'b1)
                    begin

                      req_tc     <= #TCQ m_axis_rx_tdata[22:20];
                      req_td     <= #TCQ m_axis_rx_tdata[15];
                      req_ep     <= #TCQ m_axis_rx_tdata[14];
                      req_attr   <= #TCQ m_axis_rx_tdata[13:12];
                      req_len    <= #TCQ m_axis_rx_tdata[9:0];
                      req_rid    <= #TCQ m_axis_rx_tdata[63:48];
                      req_tag    <= #TCQ m_axis_rx_tdata[47:40];
                      req_be     <= #TCQ m_axis_rx_tdata[39:32];
                      state      <= #TCQ PIO_RX_MEM_RD32_DW1DW2;

                    end // if (m_axis_rx_tdata[9:0] == 10'b1)
                    else
                    begin

                      state        <= #TCQ PIO_RX_RST_STATE;

                    end // if !(m_axis_rx_tdata[9:0] == 10'b1)

                  end // PIO_RX_MEM_RD32_FMT_TYPE

數(shù)據(jù)手冊(cè)里講到TLP包的fmt以及type決定了TLP包的類型:

圖片

具體含義為:

圖片

圖片

可見(jiàn):

localparam PIO_RX_MEM_RD32_FMT_TYPE = 7'b00_00000; 表示:存儲(chǔ)器讀TLP,而且讀3個(gè)雙字;

圖片

localparam PIO_RX_MEM_WR32_FMT_TYPE = 7'b10_00000; 表示:存儲(chǔ)器寫(xiě)TLP,而且寫(xiě)三個(gè)雙字?jǐn)?shù)據(jù):

圖片

localparam PIO_RX_MEM_RD64_FMT_TYPE = 7'b01_00000;

表示存儲(chǔ)器讀,且讀4個(gè)雙字:

圖片

localparam PIO_RX_MEM_WR64_FMT_TYPE = 7'b11_00000; 從上面的規(guī)律也應(yīng)該知道,這是存儲(chǔ)器寫(xiě),寫(xiě)4個(gè)雙字(DW);

圖片

localparam PIO_RX_IO_RD32_FMT_TYPE = 7'b00_00010;

圖片

localparam PIO_RX_IO_WR32_FMT_TYPE = 7'b10_00010;

圖片

如果接收的TLP包匹配的是存儲(chǔ)器讀且讀3個(gè)DW,對(duì)應(yīng)的程序?yàn)椋?/p>

PIO_RX_MEM_RD32_FMT_TYPE : begin

                    tlp_type     <= #TCQ m_axis_rx_tdata[31:24];
                    req_len      <= #TCQ m_axis_rx_tdata[9:0];
                    m_axis_rx_tready <= #TCQ 1'b0;


                    if (m_axis_rx_tdata[9:0] == 10'b1)
                    begin

                      req_tc     <= #TCQ m_axis_rx_tdata[22:20];
                      req_td     <= #TCQ m_axis_rx_tdata[15];
                      req_ep     <= #TCQ m_axis_rx_tdata[14];
                      req_attr   <= #TCQ m_axis_rx_tdata[13:12];
                      req_len    <= #TCQ m_axis_rx_tdata[9:0];
                      req_rid    <= #TCQ m_axis_rx_tdata[63:48];
                      req_tag    <= #TCQ m_axis_rx_tdata[47:40];
                      req_be     <= #TCQ m_axis_rx_tdata[39:32];
                      state      <= #TCQ PIO_RX_MEM_RD32_DW1DW2;

                    end // if (m_axis_rx_tdata[9:0] == 10'b1)
                    else
                    begin

                      state        <= #TCQ PIO_RX_RST_STATE;

                    end // if !(m_axis_rx_tdata[9:0] == 10'b1)

                  end // PIO_RX_MEM_RD32_FMT_TYPE

掃一眼程序,大概都是提取信息,其中有這么一個(gè)判斷條件:

if (m_axis_rx_tdata[9:0] == 10'b1)
                    begin

                      req_tc     <= #TCQ m_axis_rx_tdata[22:20];
                      req_td     <= #TCQ m_axis_rx_tdata[15];
                      req_ep     <= #TCQ m_axis_rx_tdata[14];
                      req_attr   <= #TCQ m_axis_rx_tdata[13:12];
                      req_len    <= #TCQ m_axis_rx_tdata[9:0];
                      req_rid    <= #TCQ m_axis_rx_tdata[63:48];
                      req_tag    <= #TCQ m_axis_rx_tdata[47:40];
                      req_be     <= #TCQ m_axis_rx_tdata[39:32];
                      state      <= #TCQ PIO_RX_MEM_RD32_DW1DW2;

                    end // if (m_axis_rx_tdata[9:0] == 10'b1)

接收的TLP包的低10位是什么意思呢?翻開(kāi)數(shù)據(jù)手冊(cè)看是Length:

圖片

表示的含義是:

圖片

意思就是這個(gè)PIO程序只處理一個(gè)DW的TLP包,如果超過(guò)了,則丟棄;注意,Length以DW為單位。

這就很清晰了,如果Length為1,則處理,否則不處理。怎么處理呢?提取信息唄:

req_tc     <= #TCQ m_axis_rx_tdata[22:20];
                      req_td     <= #TCQ m_axis_rx_tdata[15];
                      req_ep     <= #TCQ m_axis_rx_tdata[14];
                      req_attr   <= #TCQ m_axis_rx_tdata[13:12];
                      req_len    <= #TCQ m_axis_rx_tdata[9:0];
                      req_rid    <= #TCQ m_axis_rx_tdata[63:48];
                      req_tag    <= #TCQ m_axis_rx_tdata[47:40];
                      req_be     <= #TCQ m_axis_rx_tdata[39:32];

圖片

還有一個(gè)就是狀態(tài)轉(zhuǎn)移,如果Length為1,則下一個(gè)狀態(tài)就進(jìn)入了PIO_RX_MEM_RD32_DW1DW2;否則繼續(xù)在此狀態(tài),也就是:PIO_RX_RST_STATE,等待另一個(gè)TLP包的開(kāi)始;

除了上面的存儲(chǔ)器讀TLP包,還有存儲(chǔ)器寫(xiě)TLP包,

PIO_RX_MEM_WR32_FMT_TYPE : begin

                    tlp_type     <= #TCQ m_axis_rx_tdata[31:24];
                    req_len      <= #TCQ m_axis_rx_tdata[9:0];
                    m_axis_rx_tready <= #TCQ 1'b0;

                    if (m_axis_rx_tdata[9:0] == 10'b1)
                    begin

                      wr_be      <= #TCQ m_axis_rx_tdata[39:32];
                      state      <= #TCQ PIO_RX_MEM_WR32_DW1DW2;

                    end // if (m_axis_rx_tdata[9:0] == 10'b1)
                    else
                    begin

                      state      <= #TCQ PIO_RX_RST_STATE;

                    end // if !(m_axis_rx_tdata[9:0] == 10'b1)

                  end // PIO_RX_MEM_WR32_FMT_TYPE

它的工作相對(duì)而言就更簡(jiǎn)練了。

需要提取處字節(jié)使能wr_be,這個(gè)字節(jié)使能是什么含義呢?

疑問(wèn)記錄處2?

這個(gè)需要在后面的程序中找答案!

另一個(gè)就是指定下一個(gè)狀態(tài):PIO_RX_MEM_WR32_DW1DW2;

上面已經(jīng)列舉了讀存儲(chǔ)器TLP以及寫(xiě)存儲(chǔ)器TLP,且都是3DW情況。同理還有,4DW的情況:

PIO_RX_MEM_RD64_FMT_TYPE : begin

                    tlp_type     <= #TCQ m_axis_rx_tdata[31:24];
                    req_len      <= #TCQ m_axis_rx_tdata[9:0];
                    m_axis_rx_tready <= #TCQ 1'b0;

                    if (m_axis_rx_tdata[9:0] == 10'b1)
                    begin

                      req_tc     <= #TCQ m_axis_rx_tdata[22:20];
                      req_td     <= #TCQ m_axis_rx_tdata[15];
                      req_ep     <= #TCQ m_axis_rx_tdata[14];
                      req_attr   <= #TCQ m_axis_rx_tdata[13:12];
                      req_len    <= #TCQ m_axis_rx_tdata[9:0];
                      req_rid    <= #TCQ m_axis_rx_tdata[63:48];
                      req_tag    <= #TCQ m_axis_rx_tdata[47:40];
                      req_be     <= #TCQ m_axis_rx_tdata[39:32];
                      state        <= #TCQ PIO_RX_MEM_RD64_DW1DW2;

                    end // if (m_axis_rx_tdata[9:0] == 10'b1)
                    else
                    begin

                      state      <= #TCQ PIO_RX_RST_STATE;

                    end // if !(m_axis_rx_tdata[9:0] == 10'b1)

                  end // PIO_RX_MEM_RD64_FMT_TYPE

                  PIO_RX_MEM_WR64_FMT_TYPE : begin

                    tlp_type     <= #TCQ m_axis_rx_tdata[31:24];
                    req_len      <= #TCQ m_axis_rx_tdata[9:0];

                    if (m_axis_rx_tdata[9:0] == 10'b1) begin

                      wr_be      <= #TCQ m_axis_rx_tdata[39:32];
                      state      <= #TCQ PIO_RX_MEM_WR64_DW1DW2;

                    end // if (m_axis_rx_tdata[9:0] == 10'b1)
                    else
                    begin

                      state      <= #TCQ PIO_RX_RST_STATE;

                    end // if !(m_axis_rx_tdata[9:0] == 10'b1)

                  end // PIO_RX_MEM_WR64_FMT_TYPE

不在話下。

除了存儲(chǔ)器讀寫(xiě),還有IO讀寫(xiě),例如 IO讀:PIO_RX_IO_RD32_FMT_TYPE

PIO_RX_IO_RD32_FMT_TYPE : begin

                    tlp_type     <= #TCQ m_axis_rx_tdata[31:24];
                    req_len      <= #TCQ m_axis_rx_tdata[9:0];
                    m_axis_rx_tready <= #TCQ 1'b0;


                    if (m_axis_rx_tdata[9:0] == 10'b1)
                    begin

                      req_tc     <= #TCQ m_axis_rx_tdata[22:20];
                      req_td     <= #TCQ m_axis_rx_tdata[15];
                      req_ep     <= #TCQ m_axis_rx_tdata[14];
                      req_attr   <= #TCQ m_axis_rx_tdata[13:12];
                      req_len    <= #TCQ m_axis_rx_tdata[9:0];
                      req_rid    <= #TCQ m_axis_rx_tdata[63:48];
                      req_tag    <= #TCQ m_axis_rx_tdata[47:40];
                      req_be     <= #TCQ m_axis_rx_tdata[39:32];
                      state      <= #TCQ PIO_RX_MEM_RD32_DW1DW2;

                    end // if (m_axis_rx_tdata[9:0] == 10'b1)
                    else
                    begin

                      state      <= #TCQ PIO_RX_RST_STATE;

                    end // if !(m_axis_rx_tdata[9:0] == 10'b1)

                  end // PIO_RX_IO_RD32_FMT_TYPE

IO寫(xiě):

PIO_RX_IO_WR32_FMT_TYPE : begin

                    tlp_type     <= #TCQ m_axis_rx_tdata[31:24];
                    req_len      <= #TCQ m_axis_rx_tdata[9:0];
                    m_axis_rx_tready <= #TCQ 1'b0;

                    if (m_axis_rx_tdata[9:0] == 10'b1)
                    begin

                      req_tc     <= #TCQ m_axis_rx_tdata[22:20];
                      req_td     <= #TCQ m_axis_rx_tdata[15];
                      req_ep     <= #TCQ m_axis_rx_tdata[14];
                      req_attr   <= #TCQ m_axis_rx_tdata[13:12];
                      req_len    <= #TCQ m_axis_rx_tdata[9:0];
                      req_rid    <= #TCQ m_axis_rx_tdata[63:48];
                      req_tag    <= #TCQ m_axis_rx_tdata[47:40];
                      req_be     <= #TCQ m_axis_rx_tdata[39:32];
                      wr_be      <= #TCQ m_axis_rx_tdata[39:32];
                      state      <= #TCQ PIO_RX_IO_WR_DW1DW2;

                    end //if (m_axis_rx_tdata[9:0] == 10'b1)
                    else
                    begin

                      state        <= #TCQ PIO_RX_RST_STATE;

                    end //if !(m_axis_rx_tdata[9:0] == 10'b1)

                  end // PIO_RX_IO_WR32_FMT_TYPE

假設(shè)接收到了存儲(chǔ)器寫(xiě)TLP,且是3DW的,則進(jìn)入了下一個(gè)狀態(tài):PIO_RX_MEM_WR32_DW1DW2

PIO_RX_MEM_WR32_DW1DW2

PIO_RX_MEM_WR32_DW1DW2 : begin

              if (m_axis_rx_tvalid)
              begin

                wr_data      <= #TCQ m_axis_rx_tdata[63:32];
                wr_en        <= #TCQ 1'b1;
                m_axis_rx_tready <= #TCQ 1'b0;
                wr_addr      <= #TCQ {region_select[1:0],m_axis_rx_tdata[10:2]};
                state        <= #TCQ  PIO_RX_WAIT_STATE;

              end // if (m_axis_rx_tvalid)
              else
                state        <= #TCQ PIO_RX_MEM_WR32_DW1DW2;

            end // PIO_RX_MEM_WR32_DW1DW2

提取要寫(xiě)的數(shù)據(jù),以及令寫(xiě)使能有效,這個(gè)階段ready無(wú)效,因?yàn)檎麄€(gè)包的處理還未完成,之后進(jìn)入了下一個(gè)狀態(tài):PIO_RX_WAIT_STATE

PIO_RX_WAIT_STATE:

PIO_RX_WAIT_STATE : begin

              wr_en      <= #TCQ 1'b0;
              req_compl  <= #TCQ 1'b0;

              if ((tlp_type == PIO_RX_MEM_WR32_FMT_TYPE) && (!wr_busy))
              begin

                m_axis_rx_tready <= #TCQ 1'b1;
                state        <= #TCQ PIO_RX_RST_STATE;

              end // if ((tlp_type == PIO_RX_MEM_WR32_FMT_TYPE) && (!wr_busy))
              else if ((tlp_type == PIO_RX_IO_WR32_FMT_TYPE) && (!wr_busy))
              begin

                m_axis_rx_tready <= #TCQ 1'b1;
                state        <= #TCQ PIO_RX_RST_STATE;

              end // if ((tlp_type == PIO_RX_IO_WR32_FMT_TYPE) && (!wr_busy))
              else if ((tlp_type == PIO_RX_MEM_WR64_FMT_TYPE) && (!wr_busy))
              begin

                m_axis_rx_tready <= #TCQ 1'b1;
                state        <= #TCQ PIO_RX_RST_STATE;

              end // if ((tlp_type == PIO_RX_MEM_WR64_FMT_TYPE) && (!wr_busy))
              else if ((tlp_type == PIO_RX_MEM_RD32_FMT_TYPE) && (compl_done))
              begin

                m_axis_rx_tready <= #TCQ 1'b1;
                state        <= #TCQ PIO_RX_RST_STATE;

              end // if ((tlp_type == PIO_RX_MEM_RD32_FMT_TYPE) && (compl_done))
              else if ((tlp_type == PIO_RX_IO_RD32_FMT_TYPE) && (compl_done))
              begin

                m_axis_rx_tready <= #TCQ 1'b1;
                state        <= #TCQ PIO_RX_RST_STATE;

              end // if ((tlp_type == PIO_RX_IO_RD32_FMT_TYPE) && (compl_done))
              else if ((tlp_type == PIO_RX_MEM_RD64_FMT_TYPE) && (compl_done))
              begin

                m_axis_rx_tready <= #TCQ 1'b1;
                state        <= #TCQ PIO_RX_RST_STATE;

              end // if ((tlp_type == PIO_RX_MEM_RD64_FMT_TYPE) && (compl_done))
              else
                state        <= #TCQ PIO_RX_WAIT_STATE;

            end // PIO_RX_WAIT_STATE

此時(shí)根據(jù)tlp_type的類型,來(lái)彈斷執(zhí)行哪一些操作。很明顯這里是存儲(chǔ)器寫(xiě),我們來(lái)通過(guò)wr_busy是否有效來(lái)一起判斷,如果wr_busy無(wú)效了,則表示寫(xiě)完了,此時(shí)就可以接收下一個(gè)TLP包了。同時(shí)下一個(gè)時(shí)鐘,狀態(tài)又轉(zhuǎn)入了PIO_RX_RST_STATE。

這里有一個(gè)問(wèn)題,busy是從哪里來(lái)的?肯定是從PIO_EP_MEM_ACCESS模塊來(lái)的,這個(gè)模塊的作用就是處理TLP包的數(shù)據(jù),寫(xiě)入BRAM,寫(xiě)完了給一個(gè)busy不使能信號(hào)。

圖片

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • FPGA設(shè)計(jì)
    +關(guān)注

    關(guān)注

    9

    文章

    428

    瀏覽量

    26562
  • 寄存器
    +關(guān)注

    關(guān)注

    31

    文章

    5360

    瀏覽量

    120864
  • 存儲(chǔ)器
    +關(guān)注

    關(guān)注

    38

    文章

    7522

    瀏覽量

    164128
  • TLP
    TLP
    +關(guān)注

    關(guān)注

    0

    文章

    32

    瀏覽量

    15649
  • PCIe接口
    +關(guān)注

    關(guān)注

    0

    文章

    121

    瀏覽量

    9762
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    關(guān)于PCIe協(xié)議中FPGA的實(shí)現(xiàn)

    PCIe鏈路協(xié)議使用“端到端的數(shù)據(jù)傳送方式”,發(fā)送端和接收端中都含有TX(發(fā)送邏輯)和RX(接收邏輯)。
    發(fā)表于 06-19 17:44 ?6879次閱讀
    關(guān)于<b class='flag-5'>PCIe</b>協(xié)議中FPGA的實(shí)現(xiàn)

    淺談PCIe分析解擾器模塊的輸出數(shù)據(jù)

    用戶不多。隨協(xié)議鏈接分析器提供的包分析工具很廣泛,可對(duì)鏈接流量進(jìn)行深入分析。 賽靈思 UltraScale+ 器件的 PCIe Expre
    的頭像 發(fā)表于 11-29 10:29 ?4207次閱讀
    淺談<b class='flag-5'>PCIe</b>包<b class='flag-5'>分析</b>解擾器<b class='flag-5'>模塊</b>的輸出數(shù)據(jù)

    如何將串口接收來(lái)的數(shù)據(jù),先邏輯分析,然后在XY圖中顯示?

    先擬單片機(jī)送到電腦的數(shù)據(jù)是5B BD BD DA 并不斷重復(fù)。這32位數(shù)據(jù),每一位都表示為低電平或者高電平,就像邏輯分析儀那樣。目前的狀況是LabVIEW接收的數(shù)據(jù) 沒(méi)問(wèn)題,也會(huì)從接收
    發(fā)表于 12-04 16:22

    淺析邏輯分析儀的原理

    邏輯分析儀是常用的電子儀器之一,主要應(yīng)用于做數(shù)字電路測(cè)試,F(xiàn)PGA調(diào)試,CPU/DSP調(diào)試,數(shù)字IQ/IF分析,無(wú)線通信/雷達(dá)接收機(jī)測(cè)試等場(chǎng)合。邏輯
    發(fā)表于 06-28 07:51

    PCIE XDMA IP核介紹

    1.PCIE的發(fā)送和接收數(shù)據(jù)本工程的目的是在XC7K325tffg的平臺(tái)上實(shí)現(xiàn)pcie的數(shù)據(jù)發(fā)送和接收,速率8通道2.5GB/s,首先看下本工程的P
    發(fā)表于 12-26 10:46

    對(duì)硬件虛擬化及其相關(guān)邏輯進(jìn)行羅列與理解

    為通過(guò)PCIe接口連接的設(shè)備。設(shè)備虛擬化,也即是一個(gè)物理設(shè)備,對(duì)上層軟件系統(tǒng)呈現(xiàn)為多個(gè)邏輯設(shè)備,可以被虛擬機(jī)及其進(jìn)程直接使用。在數(shù)據(jù)傳輸一文有描述,設(shè)備工作需要接收其余模塊的配置請(qǐng)求,
    發(fā)表于 07-04 15:48

    體驗(yàn)紫光PCIE之使用WinDriver驅(qū)動(dòng)紫光PCIE

    的TLP協(xié)議,至于如何解析接收到TLP和組成發(fā)送TLP,需要往例程DMA模塊深入解讀。 如何利用起來(lái)官方例程中的DMA傳輸數(shù)據(jù)呢?下回分析。
    發(fā)表于 11-17 14:35

    NRF24L01_無(wú)線模塊收發(fā)例程

    arduino 中NRF24L01無(wú)線模塊發(fā)送和接收例程.
    發(fā)表于 02-16 11:22 ?27次下載

    基于Xilinx PCIe例程附帶Linux驅(qū)動(dòng)的修改

    本文檔內(nèi)容介紹了基于Xilinx PCIe例程附帶Linux驅(qū)動(dòng)的修改,供參考。
    發(fā)表于 09-15 16:38 ?23次下載

    邏輯分析儀在USB藍(lán)牙接收器上的實(shí)際應(yīng)用分析

    孕龍邏輯分析儀在數(shù)字訊號(hào)中提供了多種串行總線譯碼模塊,本篇文章將針對(duì)USB藍(lán)牙接收器(Blue tooth dongle )進(jìn)行訊號(hào)實(shí)際測(cè)量。 USB測(cè)量治具 首先,先把
    發(fā)表于 10-20 11:33 ?0次下載

    PCIe Gen 4協(xié)議分析儀的竟然那么強(qiáng)大!

    分析革命性創(chuàng)新的領(lǐng)導(dǎo)者,SerialTek公司的PCIe Gen 4和Gen 5協(xié)議分析儀不僅顛覆了傳統(tǒng)的PCIe協(xié)議分析儀架構(gòu)設(shè)計(jì),大大提
    的頭像 發(fā)表于 09-21 14:26 ?1.1w次閱讀

    如何加速PCIe仿真

    ? 我們?cè)谶M(jìn)行PCIe RTL仿真時(shí),由于PCIe ltssm協(xié)商過(guò)程比較復(fù)雜,導(dǎo)致PCIe ltssm進(jìn)入L0狀態(tài)所花費(fèi)的時(shí)間比較長(zhǎng)(大概在20~60分鐘,因代碼復(fù)雜度、服務(wù)器性能、
    的頭像 發(fā)表于 08-17 09:42 ?1532次閱讀
    如何加速<b class='flag-5'>PCIe</b><b class='flag-5'>仿真</b>

    Vivado設(shè)計(jì)套件用戶指南:邏輯仿真

    電子發(fā)燒友網(wǎng)站提供《Vivado設(shè)計(jì)套件用戶指南:邏輯仿真.pdf》資料免費(fèi)下載
    發(fā)表于 09-13 15:46 ?0次下載
    Vivado設(shè)計(jì)套件<b class='flag-5'>用戶</b>指南:<b class='flag-5'>邏輯</b><b class='flag-5'>仿真</b>

    邏輯分析儀multisim的應(yīng)用

    電子電路。 邏輯分析儀是一種用于測(cè)試和分析數(shù)字電路的儀器,它可以捕獲和顯示數(shù)字信號(hào)的波形,幫助用戶診斷電路問(wèn)題。Multisim中也包含了邏輯
    的頭像 發(fā)表于 07-18 09:13 ?986次閱讀

    Vivado Design Suite用戶指南:邏輯仿真

    電子發(fā)燒友網(wǎng)站提供《Vivado Design Suite用戶指南:邏輯仿真.pdf》資料免費(fèi)下載
    發(fā)表于 01-15 15:25 ?0次下載
    Vivado Design Suite<b class='flag-5'>用戶</b>指南:<b class='flag-5'>邏輯</b><b class='flag-5'>仿真</b>