在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

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

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

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

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

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

前言

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

為什么將這個內(nèi)容寫出來?

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

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

正文

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

圖片

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

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

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

仿真平臺

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

圖片

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

圖片

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

圖片

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

圖片

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

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

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

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

PIO_TO_CTRL:這個模塊的作用呢?是管理cfg_turnoff_ok這個信號的,具體什么用?需要斟酌!

例程手冊程序概括

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

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

圖片

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

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

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

當(dāng)CPU通過MMIO地址命令發(fā)出加載寄存器時,數(shù)據(jù)將向上游移動。Root Complex通常會生成具有適當(dāng)MMIO位置地址的存儲器讀TLP包和字節(jié)使能。Endpoint在收到“內(nèi)存讀取” TLP后會生成“數(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)用程序中的接收模塊:

圖片

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

假如接收到了Root端的讀請求TLP,則輸出信號如下:

圖片

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

如果EP接收到的包是寫請求包,則EP_RX會生成另外一些信號:

圖片

輸出給存儲器訪問模塊,對存儲器模塊進(jìn)行寫數(shù)據(jù)。

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

圖片

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

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

圖片

圖片

無論是讀還是寫,總得有個存儲器寫進(jìn)入或者讀出來才行,這就是這個模塊:

圖片

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

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

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

對于寫請求包,其接口如下:

圖片

對與讀,其接口如下:

圖片

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

圖片

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

下面是寫事物請求TLP的時序關(guān)系:

圖片

首先接收一個寫請求事務(wù)包,然后寫入存儲器,寫入的過程中,拉高wr_busy,表明正在寫。寫入完成之后,令wr_busy無效,表明寫入完成。之后再接收另一個寫事務(wù)包。

這個例程的用戶程序消耗的資源為:

圖片

這表明使用了4個BRAM,就是用來寫入以及讀出來自Root請求的數(shù)據(jù)的存儲器。

例程仿真分析

PIO_RX_ENGINE.v 分析:

首先,定義了一個變量in_packet_q,高有效,用來表示接收一個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表示包的開始,sop有效的條件自然是in_packet_q無效且valid有效;即:

assign sop = !in_packet_q && m_axis_rx_tvalid;

包什么時候有效呢?可以看出是sop有效且ready有效,這時候有人可能就有點(diǎn)暈了,到底是in_packet_q決定sop呢?還是sop決定in_packet_q呢?那必然是in_packet_q決定sop呀,因為sop的含義是包的開始呀。將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í)這段程序的作用(請允許我用程序來代表硬件描述語言)就是判斷包有效的標(biāo)志。valid和ready有效,這packet有效,一直持續(xù)到valid,ready,以及l(fā)ast都有效,last表示最后一個數(shù)據(jù)。可以從仿真圖中來觀察:

圖片

有了包的起始標(biāo)志,就可以通過判斷這個信號有效,進(jìn)入了包的解析狀態(tài)機(jī);這里使用了一個狀態(tài)機(jī)來處理接收的TLP,對其進(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ī),寫的很不錯。使用了如下幾個大的狀態(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),而是一些匹配項,稍后你就知道。

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:

下面一個狀態(tài)一個狀態(tài)的分析,在第一個狀態(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;

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

圖片

我們需要知道的預(yù)先知識是TLP包的各個位代表著什么,這樣才能對其解析,提取需要的信息。PIO_RX_RST_STATE狀態(tài)下一直在判斷m_axis_rx_tdata[30:24]和如下哪一個參數(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ù)手冊里講到TLP包的fmt以及type決定了TLP包的類型:

圖片

具體含義為:

圖片

圖片

可見:

localparam PIO_RX_MEM_RD32_FMT_TYPE = 7'b00_00000; 表示:存儲器讀TLP,而且讀3個雙字;

圖片

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

圖片

localparam PIO_RX_MEM_RD64_FMT_TYPE = 7'b01_00000;

表示存儲器讀,且讀4個雙字:

圖片

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

圖片

localparam PIO_RX_IO_RD32_FMT_TYPE = 7'b00_00010;

圖片

localparam PIO_RX_IO_WR32_FMT_TYPE = 7'b10_00010;

圖片

如果接收的TLP包匹配的是存儲器讀且讀3個DW,對應(yīng)的程序為:

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

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

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位是什么意思呢?翻開數(shù)據(jù)手冊看是Length:

圖片

表示的含義是:

圖片

意思就是這個PIO程序只處理一個DW的TLP包,如果超過了,則丟棄;注意,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];

圖片

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

除了上面的存儲器讀TLP包,還有存儲器寫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

它的工作相對而言就更簡練了。

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

疑問記錄處2?

這個需要在后面的程序中找答案!

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

上面已經(jīng)列舉了讀存儲器TLP以及寫存儲器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

不在話下。

除了存儲器讀寫,還有IO讀寫,例如 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寫:

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è)接收到了存儲器寫TLP,且是3DW的,則進(jìn)入了下一個狀態(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

提取要寫的數(shù)據(jù),以及令寫使能有效,這個階段ready無效,因為整個包的處理還未完成,之后進(jìn)入了下一個狀態(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

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

這里有一個問題,busy是從哪里來的?肯定是從PIO_EP_MEM_ACCESS模塊來的,這個模塊的作用就是處理TLP包的數(shù)據(jù),寫入BRAM,寫完了給一個busy不使能信號。

圖片

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

    關(guān)注

    9

    文章

    428

    瀏覽量

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

    關(guān)注

    31

    文章

    5425

    瀏覽量

    123565
  • 存儲器
    +關(guān)注

    關(guān)注

    38

    文章

    7637

    瀏覽量

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

    關(guān)注

    0

    文章

    34

    瀏覽量

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

    關(guān)注

    0

    文章

    121

    瀏覽量

    10071
收藏 人收藏

    評論

    相關(guān)推薦
    熱點(diǎn)推薦

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

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

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

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

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

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

    淺析邏輯分析儀的原理

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

    PCIE XDMA IP核介紹

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

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

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

    體驗紫光PCIE之使用WinDriver驅(qū)動紫光PCIE

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

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

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

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

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

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

    孕龍邏輯分析儀在數(shù)字訊號中提供了多種串行總線譯碼模塊,本篇文章將針對USB藍(lán)牙接收器(Blue tooth dongle )進(jìn)行訊號實(shí)際測量。 USB測量治具 首先,先把
    發(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è)計,大大提
    的頭像 發(fā)表于 09-21 14:26 ?1.2w次閱讀

    如何加速PCIe仿真

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

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

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

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

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

    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>
    主站蜘蛛池模板: 深夜动态福利gif动态进 | 日本xxxx色视频在线观看免费 | tube性欧美另类 | 免费日本黄色网址 | 在线看片成人免费视频 | 日本韩国做暖暖小视频 | 天天做天天爱天天做天天吃中 | 国产精品三级在线播放 | 美女视频黄又黄又免费高清 | 国产精品亚洲色图 | 婷婷中文网| 中文字幕在线观看你懂的 | 日日做夜夜做 | 亚洲一二三四区 | 男人天堂综合网 | 成人免费的性色视频 | 在线视免费频观看韩国aaa | 九九免费久久这里有精品23 | 四虎影院在线播放 | 五月激情六月 | 国产精品麻豆va在线播放 | 国内一级毛片 | 久久国产热| 国模鲍鱼 | 免费视频在线观看1 | 欧美xxxx日本 | 草逼网址 | 天天操天天玩 | 亚洲欧美日韩在线精品2021 | 浓厚な接吻と肉体の交在线观看 | 亚洲国产福利精品一区二区 | 成人性色生活片免费看爆迷你毛片 | 性猛交xxxx乱大交孕妇 | 你懂的在线免费视频 | 色妞导航 | 欧美黄色片免费看 | ts人妖国产一区 | 免费人成在观看 | 免费大片av手机看片 | www网站在线观看 | 天天爱天天干天天 |