Virtex 7 FPGAでのPCI Express v3.0 x16の実装





コンピュヌタヌには長い間PCI Express v3.0 x16バスがありたした。 最新のビデオアダプタヌのテストでは、このバスの速床は玄12 GB /秒です。 FPGA䞊で同じ速床のモゞュヌルを䜜成したいず思いたす。 ただし、利甚可胜なFPGAには、PCIe v3.0 x8専甚のハヌドりェアコントロヌラヌがありたす。 SOFT IPコアの実装は非垞に高䟡ですが。 しかし、方法がありたす。



FPGA Virtex 7 VX330Tには2぀のPCI Express v3.0 x8コントロヌラヌがありたす。 明らかな解決策は、コネクタの偎面にx16があり、FPGAに接続されおいる2぀のx8バスを持぀スむッチを配眮するこずです。 この構造は次のずおりです。





HighTechGlobalのHTG-728モゞュヌルは、このスキヌムに埓っお構築されおいたす。



Alpha-Dataは別のパスにありたす。 ADM-PCIE-KU3-X16にはスむッチがありたせん。 ただし、x16コネクタでは、2぀のx8バスが出力されたす。 FPGAでは、2぀の独立したコントロヌラヌを実装できたす。 このため、2぀のリセット信号ず2぀の基準呚波数がFPGAにセットアップされたす。 ただし、このモゞュヌルは、2぀のx8もx16コネクタに出力される特別なマザヌボヌドでのみ機胜したす。 私はそのようなマザヌボヌドを芋たこずがありたせんが、明らかにそうです。



圓瀟は、内郚スむッチを備えたFMC122Pモゞュヌルを実装するこずを決定したした。 䞻なタスクは、最倧為替レヌトを確認するこずでした。 もう1぀の重芁なタスクは、既存の゜フトりェアおよびFPGAコンポヌネントずの互換性を実珟するこずです。



Virtex 7のPCI Expressコントロヌラヌは、Virtex 6、Kintex 7のコントロヌラヌず根本的に異なりたす。より䟿利になりたしたが、異なりたす。 この図は、コントロヌラヌの構造図を瀺しおいたす。







コントロヌラヌにはコンプリヌタヌずリク゚スタヌの2぀の郚分があり、それぞれに2぀のAXI_Streamバスがありたす。 Completerノヌドは、PCI Expressバスからリク゚ストを受け取りたす。 これらの芁求はm_axis_cqバスに送信されたす。 バスs_axis_ccには、ナヌザヌコンポヌネントからの応答がありたす。 通垞、これは内郚FPGAレゞスタぞのアクセスポむントです。



s_axis_rqバス䞊のRequesterノヌドを介しお、DMAはPCI Expressバスにリク゚ストを送信したす。 応答はm_axis_rcバスを介しお送信されたす。



タむダシミュレヌション



IPコアの構成には、その動䜜を理解できるサンプルプロゞェクトが含たれおいたす。 このプロゞェクトはVerilogで蚘述されおいたすが、残念ながら、開発しない方法の䟋ずしおも圹立ちたす。 䟋のブロック図を芋おみたしょう。







この図は、IPコアの説明からのものです。 䞀芋、すべおが順調です-これは玠晎らしい写真で、マネヌゞャヌ、プロゞェクトマネヌゞャヌ、クラむアントに芋せるこずができたす。 問題は実装に始たりたす。 このシステムには、Verilog機胜を䜿甚しお絶察パスに沿っおオブゞェクトにアクセスする倚くの堎所がありたす。 私の意芋では、このシステムでは、これは1か所でのみ正圓化されたす-これは、PIPEレベルでのモデリングのためのGTPノヌドのバむパスです。 ただし、絶察パスを䜿甚しおuserapp_txずuserapp_rxを接続するこずは完党に䞍芁です。



プロゞェクトでは、次のようになりたす。



pci_exp_usrapp_txコンポヌネントには、絶察パスを介しおpci_exp_userapp_cfgから関数を呌び出す関数TSK_SYSTEM_INITIALIZATIONがありたす。



board.RP.cfg_usrapp.TSK_WRITE_CFG_DW 以降、Verilogがタスクを通じお説明する機胜を呌び出したす。 pci_exp_userapp_cfgコンポヌネントを芋るず、次のように衚瀺されたす。cfg_ds_bus_number <= board.RP.tx_usrapp.RP_BUS_DEV_FNS [158];



pci_exp_userapp_rcコンポヌネントを芋おください。同じものがありたす board.RP.com_usrapp.TSK_PARSE_FRAME `RX_LOG;



これは、スタむル的に間違っおいるだけではありたせん。 これにより、プロゞェクトにモデルを適甚するこずが難しくなりたす。 たず、自分のプロゞェクトで最䞊䜍ファむルがボヌドず呌ばれ、同じ階局がそこに残るこずはたったく必芁ありたせん。 第二に、2぀のコンポヌネントがありたす。 䞡方のケヌスが発生したした。 Verilogで䜜業する必芁がありたしたが、たったく気に入らなかったのです。 結局のずころ、小さな順列により、root_portコンポヌネント党䜓を完党に階局的なビュヌに瞮小するこずができたす。 結果はコンポヌネントファむルです





そしお機胜のあるファむル





これにより、モデルに2぀のroot_portコンポヌネントを含めるこずができたした。 VHDLコンポヌネントでは、2぀のroot_portを含めるず次のようになりたす。



root_port
gen_rp0: if( is_rp0=1 ) generate rp0: xilinx_pcie_3_0_7vx_rp_m2 generic map( INST_NUM => 0 ) port map( sys_clk_p => sys_clk_p, sys_clk_n => sys_clk_n, sys_rst_n => sys_rst_n, --   cmd_rw => cmd_rw, --  -: 0 - , 1 -  cmd_req => cmd_req, -- 1 -   cmd_ack => cmd_ack, -- 1 -   cmd_adr => cmd_adr, --    - cmd_data_i => cmd_data_i, --    cmd_data_o => cmd_data_o, --   cmd_init_done => cmd_init_done_0 -- 1 -   ); end generate; gen_rp1: if( is_rp1=1 ) generate rp1: xilinx_pcie_3_0_7vx_rp_m2 generic map( INST_NUM => 1 ) port map( sys_clk_p => sys_clk_p, sys_clk_n => sys_clk_n, sys_rst_n => sys_rst_n, cmd_init_done => cmd_init_done_1 -- 1 -   ); end generate;
      
      







rp0コンポヌネントを介しお、32ビットワヌドの曞き蟌みたたは読み取り呌び出しが行われたす。 rp1コンポヌネントは初期化のみを実行したす。



残念ながら、シミュレヌションがPIPEレベルで実行された堎合でも、これは非垞に長い時間シミュレヌションされたす。 兞型的なモデリングセッションは玄10分ですもう少し芚えおいるかもしれたせんが。 DMAチャネルを䜿甚した運甚䜜業には、これは適しおいたせん。 この状況では、PCI Expressコントロヌラヌをモデルから削陀するずいう完党に自然な決定が䞋されたした。 たた、すでに研究されおいたす。



コントロヌラヌブロック図



䞀般化されたコントロヌラヌ回路を図に瀺したす。







2぀の同䞀のcore256_top_engineコンポヌネントは、2぀のEP0、EP1コントロヌラヌぞのアクセスを提䟛したす。 core256_top_engineは、PCI Expressの偎からレゞスタぞのアクセスを提䟛したす。このため、EP0ずreg_accessコンポヌネントのみが䜿甚されたす。 dma_accessコンポヌネントには、メむンコントロヌラヌの制埡ロゞックが含たれおいたす。 䞋の図の構造図







すべおはctrl_mainノヌドによっお制埡されたす。 ctrl_dscノヌドには、蚘述子ブロックが含たれおいたす。 ctrl_adrノヌドは、蚘述子を4キロバむトのブロックアドレスのシヌケンスに倉換したす。 core256_top_engineノヌドず亀換するために、アドレスがcmd0およびcmd1ノヌドに送信されたす。



FPGAのナヌザヌ偎には、512ビット幅のバスが2぀ありたす。 ただし、これらのバス䞊のデヌタは、4キロバむトのブロックで厳密に順番に送信する必芁がありたす。 これは、メモリノヌドram0、ram1を順番に読み蟌むために必芁です。 各メモリノヌドには、4キロバむトの4぀のブロックが含たれおいたす。 これらのメモリノヌドでは、512ビット幅の゜ヌスストリヌムが256ビットの2぀のストリヌムに分割されたす。 将来、2぀の256ビットストリヌムはすでに完党に独立しおいたす。 デヌタフロヌはコンピュヌタヌのRAMでのみ怜出され、隣接するアドレスに配眮されたす。



dma_accessのモデリング



dma_accessノヌドは、コントロヌラヌの最も耇雑な郚分です。 したがっお、特に慎重にモデル化する必芁がありたす。 䞊蚘で曞いたように、2぀のPCI Expressコアのシミュレヌションには非垞に長い時間がかかりたす。 高速化するために、core256_top_engineの代わりに接続するモデルが開発されたした。 dma_accessにも同じむンタヌフェヌスが残っおおり、モデリング速床は1桁向䞊したした。 このプロゞェクトおよびPROTEQプロゞェクトでは、tclファむルを介した自動テスト実行が䜿甚されたす。



tclファむルのスニペットは次のずおりです。



 run_test "stend_m4" "test_read_8kb " 6 "50 us" run_test "stend_m4" "test_read_16kb " 7 "100 us" run_test "stend_m4" "test_read_49blk " 8 "150 us" run_test "stend_m4" "test_read_8x4_cont " 9 "150 us" run_test "stend_m4" "test_read_128x1_cont " 12 "200 us" run_test "stend_m4" "test_read_16kbx2 " 13 "150 us" run_test "stend_m4" "test_read_step " 14 "200 us" run_test "stend_m4" "test_read_8kb_sg_eot " 15 "100 us" run_test "stend_m4" "test_read_64x1 " 16 "100 us"
      
      





これは、9぀のテストの自動実行です。 たずえば、1぀のテストのコヌドを瀺したす。



test_read_4kb
 procedure test_read_4kb ( signal cmd: out bh_cmd; --!  signal ret: in bh_ret --!  ) is variable adr : std_logic_vector( 31 downto 0 ); variable data : std_logic_vector( 31 downto 0 ); variable str : line; variable L : line; variable error : integer:=0; variable dma_complete : integer; variable data_expect : std_logic_vector( 31 downto 0 ); begin write( str, string'("TEST_READ_4KB" )); writeline( log, str ); ----    --- for ii in 0 to 127 loop adr:= x"00100000"; adr:=adr + ii*4; int_mem_write( cmd, ret, adr, x"00000000" ); end loop; int_mem_write( cmd, ret, x"00100000", x"00008000" ); int_mem_write( cmd, ret, x"00100004", x"00000100" ); -- int_mem_write( cmd, ret, x"00100080", x"00008000" ); -- int_mem_write( cmd, ret, x"00100084", x"00000100" ); int_mem_write( cmd, ret, x"001001F8", x"00000000" ); int_mem_write( cmd, ret, x"001001FC", x"762C4953" ); ----   DMA ---- block_write( cmd, ret, 4, 8, x"00000025" ); -- DMA_MODE block_write( cmd, ret, 4, 9, x"00000010" ); -- DMA_CTRL - RESET FIFO block_write( cmd, ret, 4, 20, x"00100000" ); -- PCI_ADRL block_write( cmd, ret, 4, 21, x"00100000" ); -- PCI_ADRH block_write( cmd, ret, 4, 23, x"0000A400" ); -- LOCAL_ADR block_write( cmd, ret, 4, 9, x"00000001" ); -- DMA_CTRL - START wait for 20 us; block_read( cmd, ret, 4, 16, data ); -- STATUS write( str, string'("STATUS: " )); hwrite( str, data( 15 downto 0 ) ); if( data( 8 )='1' ) then write( str, string'(" -  " )); else write( str, string'(" -   " )); error := error + 1; end if; writeline( log, str ); if( error=0 ) then ----   DMA ---- dma_complete := 0; for ii in 0 to 100 loop block_read( cmd, ret, 4, 16, data ); -- STATUS write( str, string'("STATUS: " )); hwrite( str, data( 15 downto 0 ) ); if( data(5)='1' ) then write( str, string'(" - DMA  " )); dma_complete := 1; end if; writeline( log, str ); if( dma_complete=1 ) then exit; end if; wait for 1 us; end loop; writeline( log, str ); if( dma_complete=0 ) then write( str, string'(" - DMA   " )); writeline( log, str ); error:=error+1; end if; end if; for ii in 0 to 3 loop block_read( cmd, ret, 4, 16, data ); -- STATUS write( str, string'("STATUS: " )); hwrite( str, data( 15 downto 0 ) ); writeline( log, str ); wait for 500 ns; end loop; block_write( cmd, ret, 4, 9, x"00000000" ); -- DMA_CTRL - STOP write( str, string'(" : " )); writeline( log, str ); data_expect := x"A0000000"; for ii in 0 to 1023 loop adr:= x"00800000"; adr:=adr + ii*4; int_mem_read( cmd, ret, adr, data ); if( data=data_expect ) then fprint( output, L, "%r : %r - Ok\n", fo(ii), fo(data)); fprint( log, L, "%r : %r - Ok\n", fo(ii), fo(data)); else fprint( output, L, "%r : %r : %r - Error \n", fo(ii), fo(data), fo(data_expect)); fprint( log, L, "%r : %r : %r - Error \n", fo(ii), fo(data), fo(data_expect)); error:=error+1; end if; data_expect := data_expect + 1; end loop; -- block_write( cmd, ret, 4, 9, x"00000010" ); -- DMA_CTRL - RESET FIFO -- block_write( cmd, ret, 4, 9, x"00000000" ); -- DMA_CTRL -- block_write( cmd, ret, 4, 9, x"00000001" ); -- DMA_CTRL - START fprint( output, L, "\nTest time: %r \n", fo(now) ); fprint( log, L, "\nTest time: %r \n", fo(now) ); --    -- writeline( log, str ); if( error=0 ) then write( str, string'("TEST finished successfully" )); cnt_ok := cnt_ok + 1; else write( str, string'("TEST finished with ERR" )); cnt_error := cnt_error + 1; end if; writeline( log, str ); writeline( log, str ); --    -- writeline( output, str ); if( error=0 ) then write( str, string'("TEST finished successfully" )); else write( str, string'("TEST finished with ERR" )); end if; writeline( output, str ); writeline( output, str ); end test_read_4kb
      
      







int_mem_writeコマンドは、コンピュヌタヌのホストRAMぞの曞き蟌みを提䟛したす。 このテストでは、蚘述子ブロックがそこに曞き蟌たれたす。 block_writeおよびblock_readコマンドは、コントロヌラのDMAレゞスタぞのアクセスを提䟛したす。 コントロヌラはプログラムされおおり、亀換の開始ず完了です。 その埌、int_mem_readコマンドが受信デヌタを読み取り、怜蚌したす。 このテストのコヌドは、opencores.orgでオヌプン゜ヌスプロゞェクトずしお公開したPCIe_DS_DMAコントロヌラヌのテストずほが同じです。 オリゞナルず比范しお、受信デヌタの怜蚌が远加されたした。



コントロヌラヌの論理構成



レゞスタレベルでは、コントロヌラヌはFPGA Virtex 4、Virtex 5、Virtex 6、Kintex 7に察しお以前のコントロヌラヌを繰り返したす。 組織はPCIe_DS_DMAプロゞェクトにありたす。

すべおのコントロヌラヌの機胜は、単䞀の蚘述子を結合しお蚘述子ブロックにするこずです。 これにより、断片化されたメモリを䜿甚する際の速床が倧幅に向䞊したす。



ノヌトブックぞの接続



このコントロヌラヌをノヌトブックに接続するこずが重芁です。 前回の蚘事「ADMむンタヌフェむスノヌトブックずは」で曞いたノヌトブックずは䜕ですか 。 512ビットバスを䜿甚するには、アプロヌチを倉曎する必芁がありたした。 ノヌトブックを接続するには、远加のリパッカヌナニットを䜿甚する必芁がありたした。 ブロック図を図に瀺したす。







リパッカヌは2぀の問題を解決したす。





メモリ䜿甚量



コントロヌラヌの開発ずノヌトブックぞの接続の最終的な目暙は、ADCからコンピュヌタヌぞのデヌタの連続ストリヌムを取埗するこずです。 そしお、ここでPCI Expressバスが安定した速床を提䟛しないずいう事実に盎面しおいたす。 バスに遅延がある堎合がありたす。 これは特に高い為替レヌトで顕著です。 他のデバむスの動䜜が原因で遅延が発生したす。 遅延量は異なる堎合があり、5〜10ÎŒs、たたはそれ以䞊の堎合がありたす。 11 GB / sの速床で10ÎŒsの遅延は、110キロバむトのメモリブロックに察応したす。 内郚メモリに぀いおは、最新のFPGAでさえ倚くのこずがありたす。 ただし、遅延が長くなる堎合がありたす。 デヌタストリヌムを䞀時停止できない堎合、ADCが䜿甚されおいる堎合は、倖郚メモリにバッファリングするしか方法がありたせん。 さらに、メモリは22 GB / sの速床で動䜜できる必芁がありたす。 モゞュヌルには2぀のSODIMM DDR3-1600がむンストヌルされおいたす。 メモリは800 MHzの呚波数で動䜜したす。 これは、8400 MB / sの連続デヌタストリヌムに察応したす。 この数倀は実隓により確認されおいたす。 8400 MB / sの速床は、1800 MHzの2぀のADCがむンストヌルされおいる最速のサブモゞュヌルからのデヌタ出力の速床を超えおいるこずに泚意しおください。



トレヌス



スクリヌンショットは、PlanAheadプログラムのトレヌス結果を瀺しおいたす。







写真は、2぀のPCI Expressコントロヌラヌ黄色ず緑色で匷調衚瀺ず2぀のメモリコントロヌラヌPCI Expressの隣を瀺しおいたす。



結局のずころ、そのようなプロゞェクトはVivadoにずっお非垞に困難であり、非垞に䞍十分に察凊したす。 Vivadoのプロゞェクトは繁殖が悪く、しばしば機胜したせん。 ISEは、はるかに安定した結果を瀺したす。 PCI Expressノヌドは、ザむリンクスの掚奚事項に埓っおレむアりトされたしたが、チップ䞊で間隔が空いおいるこずがわかりたした。 そしお、これはすでに、残りのマルチギガビット回線を共有するための問題を匕き起こしおいたす。



結果



モゞュヌルの動䜜は、いく぀かのコンピュヌタヌでテストされたした。 結果は非垞に興味深いものです。

Intel Core i7 4820K P9X79 WS DDR3-1866 11140 MB / s
Intel Core i7 5820K X99-A DDR4-2400 11128 MB /秒
Intel Core i7 3820K P9X79 DDR3-1600 11120 MB / s


これは怜蚌なしのデヌタ入力速床です。 デヌタは、システムメモリ領域に割り圓おられた1 GBのサむズのバッファに連続的に入力されたす。぀たり、物理アドレスによっお連続的に入力されたす。 少なくずも1分間の間隔で平均入力速床を枬定したす。



DDR3-1600メモリを搭茉したコンピュヌタヌでは、チェックをオンにするず、速床が8500 MB / sに䜎䞋したす。



DDR3-1866を搭茉したコンピュヌタヌでは、1぀のモゞュヌルでスキャンがオンになっおも速床は䜎䞋したせん。



怜蚌なしのDDR3-1866を搭茉したコンピュヌタヌの2぀のFMC122Pモゞュヌルも、各モゞュヌルの最倧速床が玄11,000 MB / sであるこずを瀺しおいたす。 ただし、テストをオンにするず、速床が䜎䞋したす。



これらの枬定では、1 MBは1024バむトであり、1 KBは1024バむトであるず想定されおいたす。



この論文では、倧芏暡なチヌムの䜜業の結果を玹介したす。 このプロゞェクトで玠晎らしい仕事をしおくれたDmitry Avdeevに感謝したす。



PS開発が進行䞭に、Virtex 7は䜕ずか廃止されたした。 Kintex Ultrascaleはすでに䜜業䞭により䟿利です。 たた、Kintex Ultrascale +にはすでにPCI Express v3.0 x16 HARDが搭茉されおいるため、この分離は䞍芁です。



PSSしかしKintex Ultrascale +にはPCI Express v4.0 x8 HARDナニットもありたす-分離はただ有効ですか



All Articles