以下文章來源于 OpenFPGA,作者 碎碎思
作為一名FPGA工程師,經(jīng)常需要在多個(gè)FPGA設(shè)備之間移植項(xiàng)目,核心的問題是IP的管理和移植,今天通過安裝和使用 FuseSoC 在多個(gè) AMD FPGA 之間移植一個(gè)簡單的項(xiàng)目。從 AMD Spartan 7 更改為 AMD Artix 7 設(shè)備,然后是 AMD Kintex UltraSacle。
FuseSoC 介紹
FuseSoC 是一款I(lǐng)P管理器和一套用于 HDL(硬件描述語言)代碼的構(gòu)建工具。
其主要目的是增加 IP 核心的重用,有助于創(chuàng)建、構(gòu)建和仿真 SoC的解決方案。
FuseSoC 具有如下功能:
重復(fù)使用現(xiàn)有核心
創(chuàng)建編譯時(shí)或運(yùn)行時(shí)配置
針對多個(gè)仿真器運(yùn)行回歸測試
讓其他項(xiàng)目輕松使用你的代碼
FuseSoC 最新可擴(kuò)展版本支持使用 GHDL、Icarus Verilog、Isim、ModelSim、Verilator 和 Xsim 進(jìn)行仿真。還支持使用 Altera Quartus、IceStorm、Xilinx ISE 和 Xilinx Vivado 構(gòu)建 FPGA 映像。支持新的 EDA 工具需要大約 100 行代碼,并且會(huì)不斷添加新工具。
FuseSoC 已成功用于構(gòu)建或仿真 Nyuzi、Pulpino、VScale、OpenRISC SoC、picorv32、osvvm 等項(xiàng)目。
安裝 FuseSoC
FuseSoC 以 Python 包的形式提供,因此我們可以使用 pip 安裝。對于這個(gè)項(xiàng)目,將使用 VSCode 作為安裝和使用 FuseSoC 的主要方法。
首先要檢查是否安裝了 Python
python--version
下一步是安裝 FuseSoC
pip3install--upgradefusesoc
要檢查 FuseSoC 是否已正確安裝,可以運(yùn)行命令
fusesoc--version
可以看到類似下面的內(nèi)容
FuseSoC 結(jié)構(gòu)
FuseSoC 提供包管理和構(gòu)建系統(tǒng)功能,因此需要了解一些基本概念才能有效地使用它。
FuseSoC 的關(guān)鍵元素是核心,核心就像我們平時(shí)熟知的 HDL IP。核心由 FuseSoC 包管理器進(jìn)行管理,為了能夠管理核心,每個(gè)核心都有一個(gè)名稱和附加信息,這些附加信息在核心文件中提供。
為了 FuseSoC 管理 IP 核,核心文件的擴(kuò)展名為.core
FuseSoC 的一個(gè)優(yōu)點(diǎn)是核心可以具有依賴關(guān)系,例如,實(shí)現(xiàn)圖像直方圖和通過 AXI 接口的核心可以依賴于實(shí)現(xiàn) AXI 接口的核心。
核心可以存儲(chǔ)在本地或遠(yuǎn)程服務(wù)器上。核心的集合稱為核心庫,核心庫最簡單的實(shí)現(xiàn)是包含多個(gè)核心的目錄。
FuseSoC 構(gòu)建系統(tǒng)時(shí)能夠解決核心依賴關(guān)系,就頂層核心而言。它可以是位于 github 或 bitbucket 上的 git repo 上的遠(yuǎn)程庫。
雖然 FuseSoC 構(gòu)建系統(tǒng)整理了構(gòu)建設(shè)計(jì)所需的所有文件,但 AMD Vivado Design Suite 中的實(shí)際使用 EDAlize。EDALize 抽象了項(xiàng)目創(chuàng)建過程并執(zhí)行 AMD Vivado Design Suite 完成綜合、布局和布線以及生成比特流。
我們可以使用頂層的.core文件來整合幾個(gè)不同的核心庫,并控制頂層入口點(diǎn)和最終 FPGA 設(shè)計(jì)的目標(biāo)。
FuseSoC 能夠與多個(gè)不同的庫協(xié)同工作,為了向 FuseSoC 提供庫的位置,需要使用名為 fusesoc.conf的文件。FuseSoC 將首先在當(dāng)前工作目錄中查找 .conf 文件,如果未找到,它將在主目錄 (Linux) 或 Windows %homedirectory% 中查找。
雖然我們可以手動(dòng)創(chuàng)建此文件,但我們可以使用下面的命令自動(dòng)創(chuàng)建它。
fusesoclibraryadd/path/to/directory
使用 FuseSoC
上面介紹的比較抽象,我們接下來使用一個(gè)實(shí)例來介紹FuseSoC的使用。
我們將在該項(xiàng)目中使用的源代碼是 UART to AXI 邏輯(文末提供)。
針對以下主板:Digilent Arty S7、Digilent Arty A7、Alinx KU040進(jìn)行相同的工程設(shè)計(jì)。
首相,創(chuàng)建一個(gè)名為 SRC 的核心庫,在該庫下添加 HDL 元素的三個(gè)源文件。
還展示如何使用 AMD Vivado Design Suite IP 集成器設(shè)計(jì)并使用 FuseSoC 構(gòu)建它們。將在 IP 集成器中包含一些設(shè)計(jì)元素。這種方法可以被視為一種混合方法,IP 集成器設(shè)計(jì)將映射到頂層 VHDL 設(shè)計(jì)中。
由于不想在 AMD Vivado Design Suite 中為不同的構(gòu)建版本創(chuàng)建幾個(gè)不同的構(gòu)建元素,所以將創(chuàng)建一個(gè)可由 FuseSoC 運(yùn)行的 tcl 腳本。
該腳本將實(shí)例化 AXI BRAM 控制器和 BRAM 連接到自定義 RTL 模塊。
#StartanewprojectoropenanexistingoneinVivado #OpentheIPIntegratordesigntool create_bd_design"design_1" #AddanAXIBRAMController setaxi_bram_ctrl[create_bd_cell-typeip-vlnvxilinx.comaxi_bram_ctrl:4.1axi_bram_ctrl_0] #ConfiguretheAXIBRAMControllerforAXI4-Liteinterface set_propertyCONFIG.PROTOCOL{AXI4LITE}[get_bd_cells$axi_bram_ctrl] #AddaBlockRAM(BRAM) setbram[create_bd_cell-typeip-vlnvxilinx.comblk_mem_gen:8.4bram_0] #ConnecttheBRAMControllertotheBRAM connect_bd_intf_net-intf_netS_AXI$axi_bram_ctrl/BRAM_PORTA$bram/BRAM_PORTA #MakeAXIinterface,clock,andresetexternal #ExposetheAXIinterfacetoexternalports make_bd_intf_pins_external[get_bd_intf_pins$axi_bram_ctrl/S_AXI] #Exposetheclocktoanexternalport make_bd_pins_external[get_bd_pins$axi_bram_ctrl/s_axi_aclk] #Exposetheresettoanexternalport make_bd_pins_external[get_bd_pins$axi_bram_ctrl/s_axi_aresetn] #Assignaddresses assign_bd_address #Saveandvalidatethedesign validate_bd_design save_bd_design #GeneratetheHDLwrapperforthedesignandcapturethegeneratedfilename setwrapper_file[make_wrapper-files[get_filesdesign_1.bd]-top] #Addthegeneratedwrapperfiletotheproject add_files$wrapper_file #Updatetheprojecthierarchytoincludethenewwrapperfile update_compile_order-filesetsources_1
該腳本將創(chuàng)建如下所示的框圖。
然后,將創(chuàng)建一個(gè)頂層 RTL 文件,將 IP 集成器框圖與自定義 RTL 模塊連接起來完成設(shè)計(jì)。
協(xié)議文件
libraryieee; useieee.std_logic_1164.all; useieee.numeric_std.all; --Declareentity entityaxi_protocolis generic( G_AXIL_DATA_WIDTH:integer:=32;--WidthofAXILitedatabus G_AXI_ADDR_WIDTH:integer:=32;--WidthofAXILiteAddressBu G_AXI_ID_WIDTH:integer:=8;--WidthofAXIIDBus G_AXI_AWUSER_WIDTH:integer:=1--WidthofAXIAWUserbus ); port( --Masterclock&reset clk:instd_ulogic;--Systemclock reset:instd_ulogic;--Systemreset,asyncactivelow --!MasterAXISInterface m_axis_tready:instd_logic; m_axis_tdata:outstd_logic_vector(7downto0); m_axis_tvalid:outstd_logic; --!SlaveAXISInterface s_axis_tready:outstd_logic; s_axis_tdata:instd_logic_vector(7downto0); s_axis_tvalid:instd_logic; --!AXILInterface --!Writeaddress axi_awaddr:outstd_logic_vector(G_AXI_ADDR_WIDTH-1downto0); axi_awprot:outstd_logic_vector(2downto0); axi_awvalid:outstd_logic; --!writedata axi_wdata:outstd_logic_vector(G_AXIL_DATA_WIDTH-1downto0); axi_wstrb:outstd_logic_vector(G_AXIL_DATA_WIDTH/8-1downto0); axi_wvalid:outstd_logic; --!writeresponse axi_bready:outstd_logic; --!readaddress axi_araddr:outstd_logic_vector(G_AXI_ADDR_WIDTH-1downto0); axi_arprot:outstd_logic_vector(2downto0); axi_arvalid:outstd_logic; --!readdata axi_rready:outstd_logic; --writeaddress axi_awready:instd_logic; --writedata axi_wready:instd_logic; --writeresponse axi_bresp:instd_logic_vector(1downto0); axi_bvalid:instd_logic; --readaddress axi_arready:instd_logic; --readdata axi_rdata:instd_logic_vector(G_AXIL_DATA_WIDTH-1downto0); axi_rresp:instd_logic_vector(1downto0); axi_rvalid:instd_logic ); endentityaxi_protocol; architecturertlofaxi_protocolis constantC_SINGLE_READ:std_logic_vector(7downto0):=x"05"; constantC_SINGLE_WRITE:std_logic_vector(7downto0):=x"09"; constantC_NUMB_ADDR_BYTES:integer:=4; constantC_NUMB_LENGTH_BYTES:integer:=1; constantC_NUMB_DATA_BYTES:integer:=4; constantC_NUMB_AXIL_DATA_BYTES:integer:=4; constantC_NUMB_CRC_BYTES:integer:=4; constantC_MAX_NUMB_BYTES:integer:=4;--maxnumberoftheaboveconstantfornumberofbytes constantC_ZERO_PAD:std_logic_vector(7downto0):=(others=>'0'); typet_fsmis(idle,address,length,dummy,write_payload,read_payload,crc,write_axil,write_axi,read_axi,read_axil); typet_op_fsmis(idle,output,check); typet_arrayisarray(0to7)ofstd_logic_vector(31downto0); typeaxil_read_fsmis(IDLE,START,CHECK_ADDR_RESP,READ_DATA,DONE); typeaxil_write_fsmis(IDLE,START,CHECK_ADDR_RESP,WRITE_DATA,RESP_READY,CHECK_RESP,DONE); signalwrite_state:axil_write_fsm; signalread_state:axil_read_fsm; signals_current_state:t_fsm; signals_command:std_logic_vector(7downto0); signals_address:std_logic_vector((C_NUMB_ADDR_BYTES*8)-1downto0); signals_length:std_logic_vector(7downto0); signals_length_axi:std_logic_vector(7downto0); signals_buf_cnt:unsigned(7downto0); signals_byte_pos:integerrange0toC_MAX_NUMB_BYTES; signals_num_bytes:integerrange0toC_MAX_NUMB_BYTES; signals_s_tready:std_logic; signals_write_buffer:t_array:=(others=>(others=>'0')); signals_read_buffer:t_array:=(others=>(others=>'0')); signals_write_buffer_temp:std_logic_vector(31downto0); signals_read_buffer_temp:std_logic_vector(31downto0); --axillitedatainterface signals_axil_data:std_logic_vector(G_AXIL_DATA_WIDTH-1downto0); signals_axil_valid:std_logic; signals_axil_idata:std_logic_vector(G_AXIL_DATA_WIDTH-1downto0); --aximstream signals_opptr:unsigned(7downto0); signals_start:std_logic; signals_op_state:t_op_fsm; signals_op_byte:integerrange0toC_MAX_NUMB_BYTES; signalstart_read:std_logic; signalstart_write:std_logic; signals_m_axis_tvalid:std_logic; begin s_axis_tready<=?s_s_tready; FSM?:?process(clk,?reset?) begin if?(reset?=?'0')?then start_read??<=?'0'; start_write?<=?'0'; s_s_tready??<=?'0'; elsif?rising_edge(clk)?then s_s_tready??<=?'1'; s_start?????<=?'0'; start_read??<=?'0'; start_write?<=?'0'; case?s_current_state?is when?idle?=>--todoneedstocheckthecommandisvalid s_buf_cnt<=?(others?=>'0'); if(s_axis_tvalid='1'ands_s_tready='1')and (s_axis_tdata=C_SINGLE_READors_axis_tdata=C_SINGLE_WRITE)then s_s_tready<=?'0'; s_command?<=?s_axis_tdata; s_current_state?<=?address; s_byte_pos?<=?C_NUMB_ADDR_BYTES; end?if; when?address?=> ifs_byte_pos=0then s_s_tready<=?'0'; s_byte_pos?<=?C_NUMB_LENGTH_BYTES; s_current_state?<=?length; elsif?s_axis_tvalid?=?'1'?and?s_s_tready?=?'1'?then s_address?<=?s_address(s_address'length-8-1?downto?0)?&?s_axis_tdata; s_byte_pos?<=?s_byte_pos?-?1; if?s_byte_pos?=?1?then s_s_tready?<=?'0'; end?if; end?if; when?length?=> ifs_byte_pos=0then s_s_tready<=?'0'; if?s_command?=?C_SINGLE_READ?and?unsigned(s_length)?=?1?then s_current_state?<=?read_axil; start_read??????<=?'1'; s_num_bytes?????<=?C_NUMB_AXIL_DATA_BYTES; elsif?s_command?=?C_SINGLE_WRITE?then s_buf_cnt???????<=?(others?=>'0'); s_byte_pos<=?C_NUMB_AXIL_DATA_BYTES; s_num_bytes?????<=?C_NUMB_AXIL_DATA_BYTES; s_current_state?<=?write_payload; end?if; elsif?s_axis_tvalid?=?'1'?and?s_s_tready?=?'1'?then s_length????????????<=?s_axis_tdata; s_length_axi????????<=?std_logic_vector(unsigned(s_axis_tdata)-1); s_byte_pos??????????<=?s_byte_pos?-?1; s_s_tready?<=?'0'; end?if; when?read_axil?=> ifs_axil_valid='1'then s_start<=?'1'; s_read_buffer(0)(G_AXIL_DATA_WIDTH-1?downto?0)?<=?s_axil_data; end?if; if?(read_state?=?DONE)?then s_current_state?<=?read_payload; end?if; when?write_payload?=> ifs_buf_cnt=unsigned(s_length)then s_s_tready<=?'0'; s_current_state?<=?write_axil; start_write?<=?'1'; else if?s_byte_pos?=?0?then s_s_tready?<=?'0'; s_byte_pos?<=?s_num_bytes; s_write_buffer(to_integer(s_buf_cnt))?<=?s_write_buffer_temp; s_buf_cnt?<=?s_buf_cnt?+?1; elsif?(s_axis_tvalid?=?'1'?and?s_s_tready?=?'1')?then s_write_buffer_temp?<=?s_write_buffer_temp(s_write_buffer_temp'length-8-1?downto?0)?&?s_axis_tdata; s_byte_pos?<=?s_byte_pos?-?1; if?s_byte_pos?=?1?then s_s_tready?<=?'0'; end?if; end?if; end?if; when?write_axil?=> s_s_tready<=?'0'; s_axil_idata?<=?s_write_buffer(0); if?(write_state?=?DONE)?then s_current_state?<=?idle; end?if; when?read_payload?=> s_current_state<=?idle; when?others?=>null; endcase; endif; endprocess; m_axis_tvalid<=?s_m_axis_tvalid; process(clk,?reset) begin if?(reset?=?'0')?then s_m_axis_tvalid??????<=?'0'; m_axis_tdata????????<=?(others?=>'0'); s_opptr<=?(others?=>'0'); s_op_byte<=?C_NUMB_AXIL_DATA_BYTES; elsif?rising_edge(clk)?then case?s_op_state?is when?idle?=> s_m_axis_tvalid<=?'0'; if?s_start?=?'1'?then s_opptr?????<=?(others?=>'0'); s_read_buffer_temp<=?s_read_buffer(0); s_op_byte???<=?s_num_bytes; s_op_state??<=?output; end?if; when?output?=> ifs_opptr=unsigned(s_length)then s_op_state<=?idle; s_m_axis_tvalid?<=?'0'; else s_m_axis_tvalid?<=?'1'; m_axis_tdata?<=?s_read_buffer_temp(7?downto?0); if?s_op_byte?=?0?then s_op_byte???<=?s_num_bytes; s_opptr?????<=?s_opptr?+?1; s_m_axis_tvalid?<=?'0'; elsif?m_axis_tready?=?'1'?then s_m_axis_tvalid?<=?'1'; s_read_buffer_temp?<=?C_ZERO_PAD?&?s_read_buffer_temp(s_read_buffer_temp'length-1?downto?8); s_op_byte?<=?s_op_byte?-?1; s_op_state??<=?check; end?if; end?if; when?check?=> s_m_axis_tvalid<=?'0'; s_op_state??<=?output; end?case; end?if; end?process; process(clk,?reset) begin if?(reset?=?'0')?then write_state?<=?IDLE; axi_awaddr??<=?(others?=>'0'); axi_awprot<=?(others?=>'0'); axi_awvalid<=?'0'; axi_wdata???<=?(others?=>'0'); axi_wstrb<=?(others?=>'0'); axi_wvalid<=?'0'; axi_bready??<=?'0'; elsif?rising_edge(clk)?then axi_wstrb???<=?(others?=>'0'); casewrite_stateis --Sendwriteaddress whenIDLE=> ifstart_write='1'then write_state<=?START; end?if; when?START?=> axi_awaddr<=?s_address; axi_awprot??<=?"010"; axi_awvalid?<=?'1'; axi_wdata???<=?s_axil_idata; axi_wvalid??<=?'1'; axi_wstrb???<=?(others?=>'1'); write_state<=?WRITE_DATA;--CHECK_ADDR_RESP; --Wait?for?slave?to?acknowledge?receipt when?CHECK_ADDR_RESP?=> if(axi_awready='1')then axi_awaddr<=?(others?=>'0'); axi_awprot<=?(others?=>'0'); axi_awvalid<=?'0'; write_state?<=?WRITE_DATA; else write_state?<=?CHECK_ADDR_RESP; end?if; --Send?write?data when?WRITE_DATA?=> if(axi_awready='1')then axi_awaddr<=?(others?=>'0'); axi_awprot<=?(others?=>'0'); axi_awvalid<=?'0'; axi_wstrb???<=?(others?=>'0'); endif; axi_wdata<=?s_axil_idata; axi_wvalid?<=?'1'; axi_wstrb???<=?(others?=>'1'); if(axi_wready='1')then write_state<=?RESP_READY; else write_state?<=?WRITE_DATA; end?if; --Set?response?ready when?RESP_READY?=> axi_wstrb<=?(others?=>'0'); axi_wvalid<=?'0'; axi_bready?<=?'1'; write_state?<=?CHECK_RESP; --Check?the?response when?CHECK_RESP?=> if(axi_bvalid='1')then axi_bready<=?'0'; write_state?<=?DONE; end?if; --Indicate?the?transaction?has?completed when?DONE?=> write_state<=?IDLE; when?others?=> write_state<=?START; end?case; end?if; end?process; process(clk,?reset) begin if?(reset?=?'0')?then read_state?<=?IDLE; axi_araddr??<=?(others?=>'0'); axi_arprot<=?(others?=>'0'); axi_arvalid<=?'0'; axi_rready??<=?'0'; elsif?rising_edge(clk)?then case?read_state?is when?IDLE?=> ifstart_read='1'then read_state<=?START; end?if; --Send?read?address when?START?=> axi_araddr<=?s_address; axi_arprot??<=?"010"; axi_arvalid?<=?'1'; s_axil_valid?<=?'0'; read_state?<=?CHECK_ADDR_RESP; --Wait?for?the?slave?to?acknowledge?receipt?of?the?address when?CHECK_ADDR_RESP?=> if(axi_arready='1')then axi_araddr<=?(others?=>'0'); axi_arprot<=?(others?=>'0'); axi_arvalid<=?'0'; read_state?<=?READ_DATA; else read_state?<=?CHECK_ADDR_RESP; end?if; s_axil_valid?<=?'0'; --Read?data?from?the?slave when?READ_DATA?=> s_axil_data<=?axi_rdata; if?(axi_rvalid?=?'1')?then s_axil_valid?<=?'1'; read_state?<=?DONE; else s_axil_valid?<=?'0'; read_state?<=?READ_DATA; end?if; axi_rready?<=?'1'; --Indicate?the?transaction?has?completed when?DONE?=> axi_rready<=?'0'; s_axil_data??<=?(others?=>'0'); s_axil_valid<=?'0'; read_state?<=?IDLE; when?others?=> read_state<=?START; end?case; end?if; end?process; end?architecture;
UART 及 UART 封裝
libraryieee; useieee.std_logic_1164.all; useieee.numeric_std.all; useieee.math_real.all; usework.adiuvo_uart.all; entityuartisgeneric( reset_level:std_logic:='0';--resetlevelwhichcausesareset clk_freq:natural:=100_000_000;--oscillatorfrequency baud_rate:natural:=115200--baudrate ); port( --!SystemInputs clk:instd_logic; reset:instd_logic; --!ExternalInterfaces rx:instd_logic; tx:outstd_logic; --!MasterAXISInterface m_axis_tready:instd_logic; m_axis_tdata:outstd_logic_vector(7downto0); m_axis_tvalid:outstd_logic; --!SlaveAXISInterface s_axis_tready:outstd_logic; s_axis_tdata:instd_logic_vector(7downto0); s_axis_tvalid:instd_logic ); endentity; architecturertlofuartis constantbit_period:integer:=(clk_freq/baud_rate)-1; typecntrl_fsmis(idle,set_tx,wait_tx); typerx_fsmis(idle,start,sample,check,wait_axis); signalcurrent_state:cntrl_fsm;--:=idle; signalrx_state:rx_fsm;--:=idle; signalbaud_counter:unsigned(vector_size(real(clk_freq),real(baud_rate))downto0):=(others=>'0');--timerforoutgoingsignals signalbaud_en:std_logic:='0'; signalmeta_reg:std_logic_vector(3downto0):=(others=>'0');--fedetectiontoo signalcapture:std_logic_vector(7downto0):=(others=>'0');--dataandparity signalbit_count:integerrange0to1023:=0; signalpos_count:integerrange0to15:=0; signalrunning:std_logic:='0'; signalload_tx:std_logic:='0'; signalcomplete:std_logic:='0'; signaltx_reg:std_logic_vector(11downto0):=(others=>'0'); signaltmr_reg:std_logic_vector(11downto0):=(others=>'0'); signalpayload:std_logic_vector(7downto0):=(others=>'0'); constantzero:std_logic_vector(tmr_reg'range):=(others=>'0'); begin process(reset,clk) begin ifreset=reset_levelthen current_state<=?idle; payload???????<=?(others?=>'0'); load_tx<=?'0'; elsif?rising_edge(clk)?then load_tx?<=?'0'; case?current_state?is when?idle?=> ifs_axis_tvalid='1'then current_state<=?set_tx; load_tx???????<=?'1'; payload???????<=?s_axis_tdata; end?if; when?set_tx?=> current_state<=?wait_tx; when?wait_tx?=> ifcomplete='1'then current_state<=?idle; end?if; when?others?=> current_state<=?idle; end?case; end?if; end?process; s_axis_tready?<=?'1'?when?(current_state?=?idle)?else?'0'; process?(reset,?clk) --!?baud?counter?for?output?TX begin if?reset?=?reset_level?then baud_counter?<=?(others?=>'0'); baud_en<=?'0'; elsif?rising_edge(clk)?then baud_en?<=?'0'; if?(load_tx?=?'1')?then baud_counter?<=?(others?=>'0'); elsif(baud_counter=bit_period)then baud_en<=?'1'; baud_counter?<=?(others?=>'0'); else baud_counter<=?baud_counter?+?1; end?if; end?if; end?process; process?(reset,?clk) --!metastability?protection?rx?signal begin if?reset?=?reset_level?then meta_reg?<=?(others?=>'1'); elsifrising_edge(clk)then meta_reg<=?meta_reg(meta_reg'high?-?1?downto?meta_reg'low)?&?rx; end?if; end?process; process?(reset,?clk) begin if?reset?=?reset_level?then pos_count?<=?0; bit_count?<=?0; capture?????<=?(others?=>'0'); rx_state<=?idle; m_axis_tvalid?<=?'0'; m_axis_tdata?????<=?(others?=>'0'); elsifrising_edge(clk)then caserx_stateis whenidle=> m_axis_tvalid<=?'0'; if?meta_reg(meta_reg'high?downto?meta_reg'high?-?1)?=?fe_det?then pos_count?<=?0; bit_count?<=?0; capture??<=?(others?=>'0'); rx_state<=?start; end?if; when?start?=> ifbit_count=bit_periodthen bit_count<=?0; rx_state??<=?sample; else bit_count?<=?bit_count?+?1; end?if; when?sample?=> bit_count<=?bit_count?+?1; rx_state??<=?sample; if?bit_count?=?(bit_period/2)?and?(pos_count?8)?then capture?<=?meta_reg(meta_reg'high)?&?capture(capture'high?downto?capture'low?+?1); elsif?bit_count?=?bit_period?then if?pos_count?=?8?then rx_state?<=?check; else pos_count?<=?pos_count?+?1; bit_count?<=?0; end?if; end?if; when?check?=> ifparity(capture)='1'then m_axis_tvalid<=?'1'; m_axis_tdata??<=?capture(7?downto?0); rx_state??????<=?wait_axis; else m_axis_tvalid?<=?'1'; m_axis_tdata??<=?capture(7?downto?0); rx_state??????<=?wait_axis; end?if; when?wait_axis?=> ifm_axis_tready='1'then m_axis_tvalid<=?'0'; rx_state??????<=?idle; end?if; end?case; end?if; end?process; op_uart?:?process?(reset,?clk) begin if?reset?=?reset_level?then tx_reg??<=?(others?=>'1'); tmr_reg<=?(others?=>'0'); elsifrising_edge(clk)then ifload_tx='1'then tx_reg<=?stop_bit?&?not(parity(payload))?&?payload?&?start_bit?; tmr_reg?<=?(others?=>'1'); elsifbaud_en='1'then tx_reg<=?'1'?&?tx_reg(tx_reg'high?downto?tx_reg'low?+?1); tmr_reg?<=?tmr_reg(tmr_reg'high?-?1?downto?tmr_reg'low)?&?'0'; end?if; end?if; end?process; tx???????<=?tx_reg(tx_reg'low); complete?<=?'1'?when?(tmr_reg?=?zero?and?current_state?=?wait_tx)?else?'0'; end?architecture; library?ieee; use?ieee.std_logic_1164.all; use?ieee.numeric_std.all; use?ieee.math_real.all; package?adiuvo_uart?is function?vector_size(clk_freq,?baud_rate?:?real)?return?integer; function?parity?(a?:?std_logic_vector)?return?std_logic; constant?fe_det?????:?std_logic_vector(1?downto?0)?:=?"10"; constant?start_bit??:?std_logic?:=?'0'; constant?stop_bit???:?std_logic_vector?:=?"11"; end?package; package?body?adiuvo_uart?is function?vector_size(clk_freq,?baud_rate?:?real)?return?integer?is variable?div?:?real; variable?res?:?real; begin div?:=?(clk_freq/baud_rate); res?:=?CEIL(LOG(div)/LOG(2.0)); return?integer(res?-?1.0); end; function?parity?(a?:?std_logic_vector)?return?std_logic?is variable?y?:?std_logic?:=?'0'; begin for?i?in?a'range?loop y?:=?y?xor?a(i); end?loop; return?y; end?parity; end?package?body?adiuvo_uart;
TOP模塊
LIBRARYieee; USEieee.std_logic_1164.all; USEieee.numeric_std.all; entitytop_levelis port( clk:instd_logic; reset:instd_logic; rx:instd_logic; tx:outstd_logic ); --Declarations endentitytop_level; LIBRARYieee; USEieee.std_logic_1164.all; USEieee.numeric_std.all; libraryUNISIM; useUNISIM.VCOMPONENTS.ALL; useieee.math_real.all; architecturestructoftop_levelis --Architecturedeclarations --Internalsignaldeclarations signalS_AXI_0_arready:STD_LOGIC; signalS_AXI_0_awready:STD_LOGIC; signalS_AXI_0_bresp:STD_LOGIC_VECTOR(1downto0); signalS_AXI_0_bvalid:STD_LOGIC; signalS_AXI_0_rdata:STD_LOGIC_VECTOR(31downto0); signalS_AXI_0_rresp:STD_LOGIC_VECTOR(1downto0); signalS_AXI_0_wready:STD_LOGIC; signalS_AXI_0_wvalid:STD_LOGIC; signalaxi_araddr:std_logic_vector(31downto0); signalaxi_arprot:std_logic_vector(2downto0); signalaxi_arvalid:std_logic; signalaxi_awaddr:std_logic_vector(31downto0); signalaxi_awprot:std_logic_vector(2downto0); signalaxi_awvalid:std_logic; signalaxi_bready:std_logic; signalaxi_rready:std_logic; signalaxi_rvalid:std_logic; signalaxi_wdata:std_logic_vector(31downto0); signalaxi_wstrb:std_logic_vector(3downto0); signalm_axis_tdata:std_logic_vector(7downto0); signalm_axis_tready:std_logic; signalm_axis_tvalid:std_logic; signals_axis_tdata:std_logic_vector(7downto0); signals_axis_tready:std_logic; signals_axis_tvalid:std_logic; --ComponentDeclarations componentaxi_protocol generic( G_AXIL_DATA_WIDTH:integer:=32;--WidthofAXILitedatabus G_AXI_ADDR_WIDTH:integer:=32;--WidthofAXILiteAddressBu G_AXI_ID_WIDTH:integer:=8;--WidthofAXIIDBus G_AXI_AWUSER_WIDTH:integer:=1--WidthofAXIAWUserbus ); port( axi_arready:instd_logic; axi_awready:instd_logic; axi_bresp:instd_logic_vector(1downto0); axi_bvalid:instd_logic; axi_rdata:instd_logic_vector(31downto0); axi_rresp:instd_logic_vector(1downto0); axi_rvalid:instd_logic; axi_wready:instd_logic; clk:instd_ulogic; m_axis_tready:instd_logic; reset:instd_ulogic; s_axis_tdata:instd_logic_vector(7downto0); s_axis_tvalid:instd_logic; axi_araddr:outstd_logic_vector(31downto0); axi_arprot:outstd_logic_vector(2downto0); axi_arvalid:outstd_logic; axi_awaddr:outstd_logic_vector(31downto0); axi_awprot:outstd_logic_vector(2downto0); axi_awvalid:outstd_logic; axi_bready:outstd_logic; axi_rready:outstd_logic; axi_wdata:outstd_logic_vector(31downto0); axi_wstrb:outstd_logic_vector(3downto0); axi_wvalid:outstd_logic; m_axis_tdata:outstd_logic_vector(7downto0); m_axis_tvalid:outstd_logic; s_axis_tready:outstd_logic ); endcomponentaxi_protocol; componentdesign_1_wrapper port( S_AXI_0_araddr:inSTD_LOGIC_VECTOR(11downto0); S_AXI_0_arprot:inSTD_LOGIC_VECTOR(2downto0); S_AXI_0_arvalid:inSTD_LOGIC; S_AXI_0_awaddr:inSTD_LOGIC_VECTOR(11downto0); S_AXI_0_awprot:inSTD_LOGIC_VECTOR(2downto0); S_AXI_0_awvalid:inSTD_LOGIC; S_AXI_0_bready:inSTD_LOGIC; S_AXI_0_rready:inSTD_LOGIC; S_AXI_0_wdata:inSTD_LOGIC_VECTOR(31downto0); S_AXI_0_wstrb:inSTD_LOGIC_VECTOR(3downto0); S_AXI_0_wvalid:inSTD_LOGIC; s_axi_aclk_0:inSTD_LOGIC; s_axi_aresetn_0:inSTD_LOGIC; S_AXI_0_arready:outSTD_LOGIC; S_AXI_0_awready:outSTD_LOGIC; S_AXI_0_bresp:outSTD_LOGIC_VECTOR(1downto0); S_AXI_0_bvalid:outSTD_LOGIC; S_AXI_0_rdata:outSTD_LOGIC_VECTOR(31downto0); S_AXI_0_rresp:outSTD_LOGIC_VECTOR(1downto0); S_AXI_0_rvalid:outSTD_LOGIC; S_AXI_0_wready:outSTD_LOGIC ); endcomponentdesign_1_wrapper; componentuart generic( reset_level:std_logic:='0';--resetlevelwhichcausesareset clk_freq:natural:=100_000_000;--oscillatorfrequency baud_rate:natural:=115200--baudrate ); port( clk:instd_logic; m_axis_tready:instd_logic; reset:instd_logic; rx:instd_logic; s_axis_tdata:instd_logic_vector(7downto0); s_axis_tvalid:instd_logic; m_axis_tdata:outstd_logic_vector(7downto0); m_axis_tvalid:outstd_logic; s_axis_tready:outstd_logic; tx:outstd_logic ); endcomponentuart; --Optionalembeddedconfigurations --pragmasynthesis_off forall:axi_protocoluseentitysrc.axi_protocol; forall:design_1_wrapperuseentitysrc.design_1_wrapper; forall:uartuseentitysrc.uart; --pragmasynthesis_on begin --Instanceportmappings. U_0:axi_protocol genericmap( G_AXIL_DATA_WIDTH=>32,--WidthofAXILitedatabus G_AXI_ADDR_WIDTH=>32,--WidthofAXILiteAddressBu G_AXI_ID_WIDTH=>1,--WidthofAXIIDBus G_AXI_AWUSER_WIDTH=>1--WidthofAXIAWUserbus ) portmap( clk=>clk, reset=>reset, m_axis_tready=>m_axis_tready, m_axis_tdata=>m_axis_tdata, m_axis_tvalid=>m_axis_tvalid, s_axis_tready=>s_axis_tready, s_axis_tdata=>s_axis_tdata, s_axis_tvalid=>s_axis_tvalid, axi_awaddr=>axi_awaddr, axi_awprot=>axi_awprot, axi_awvalid=>axi_awvalid, axi_wdata=>axi_wdata, axi_wstrb=>axi_wstrb, axi_wvalid=>S_AXI_0_wvalid, axi_bready=>axi_bready, axi_araddr=>axi_araddr, axi_arprot=>axi_arprot, axi_arvalid=>axi_arvalid, axi_rready=>axi_rready, axi_awready=>S_AXI_0_wready, axi_wready=>S_AXI_0_awready, axi_bresp=>S_AXI_0_bresp, axi_bvalid=>S_AXI_0_bvalid, axi_arready=>S_AXI_0_arready, axi_rdata=>S_AXI_0_rdata, axi_rresp=>S_AXI_0_rresp, axi_rvalid=>axi_rvalid ); U_1:design_1_wrapper portmap( S_AXI_0_araddr=>axi_araddr(11downto0), S_AXI_0_arprot=>axi_arprot, S_AXI_0_arready=>S_AXI_0_arready, S_AXI_0_arvalid=>axi_arvalid, S_AXI_0_awaddr=>axi_awaddr(11downto0), S_AXI_0_awprot=>axi_awprot, S_AXI_0_awready=>S_AXI_0_awready, S_AXI_0_awvalid=>axi_awvalid, S_AXI_0_bready=>axi_bready, S_AXI_0_bresp=>S_AXI_0_bresp, S_AXI_0_bvalid=>S_AXI_0_bvalid, S_AXI_0_rdata=>S_AXI_0_rdata, S_AXI_0_rready=>axi_rready, S_AXI_0_rresp=>S_AXI_0_rresp, S_AXI_0_rvalid=>axi_rvalid, S_AXI_0_wdata=>axi_wdata, S_AXI_0_wready=>S_AXI_0_wready, S_AXI_0_wstrb=>axi_wstrb, S_AXI_0_wvalid=>S_AXI_0_wvalid, s_axi_aclk_0=>clk, s_axi_aresetn_0=>reset ); U_2:uart genericmap( reset_level=>'0',--resetlevelwhichcausesareset clk_freq=>100_000_000,--oscillatorfrequency baud_rate=>115200--baudrate ) portmap( clk=>clk, reset=>reset, rx=>rx, tx=>tx, m_axis_tready=>s_axis_tready, m_axis_tdata=>s_axis_tdata, m_axis_tvalid=>s_axis_tvalid, s_axis_tready=>m_axis_tready, s_axis_tdata=>m_axis_tdata, s_axis_tvalid=>m_axis_tvalid ); endarchitecturestruct;
創(chuàng)建 XDC
將要進(jìn)行的三個(gè)工程之間的唯一區(qū)別在于約束文件。需要為每個(gè)目標(biāo)板創(chuàng)建一個(gè)約束。
AMD Spartan 7
set_propertyPACKAGE_PINR2[get_portsclk] set_propertyIOSTANDARDLVCMOS33[get_portsclk] create_clock-period10.000-namesys_clk[get_portsclk] set_propertyPACKAGE_PINL17[get_portsreset] set_propertyPACKAGE_PINL18[get_portsrx] set_propertyPACKAGE_PINM14[get_portstx] #setI/Ostandard set_propertyIOSTANDARDLVCMOS33[get_portsreset] set_propertyIOSTANDARDLVCMOS33[get_portsrx] set_propertyIOSTANDARDLVCMOS33[get_portstx]
AMD Artix 7
set_propertyPACKAGE_PINE3[get_portsclk] set_propertyIOSTANDARDLVCMOS33[get_portsclk] create_clock-period10.000-namesys_clk[get_portsclk] set_propertyPACKAGE_PING13[get_portsreset] set_propertyPACKAGE_PINB11[get_portsrx] set_propertyPACKAGE_PINA11[get_portstx] #setI/Ostandard set_propertyIOSTANDARDLVCMOS33[get_portsreset] set_propertyIOSTANDARDLVCMOS33[get_portsrx] set_propertyIOSTANDARDLVCMOS33[get_portstx]
AMD Kintex UltraSacle
set_propertyPACKAGE_PINAF9[get_portsclk] set_propertyIOSTANDARDLVCMOS33[get_portsclk] create_clock-period10.000-namesys_clk[get_portsclk] set_propertyPACKAGE_PINAE8[get_portsreset] set_propertyPACKAGE_PINAE10[get_portsrx] set_propertyPACKAGE_PINAD10[get_portstx] #setI/Ostandard set_propertyIOSTANDARDLVCMOS33[get_portsreset] set_propertyIOSTANDARDLVCMOS33[get_portsrx] set_propertyIOSTANDARDLVCMOS33[get_portstx]
創(chuàng)建 FuseSoC 核心
創(chuàng)建 RTL 和XDC后,下一步是創(chuàng)建.core 文件和.conf 文件。
首先要做的是創(chuàng)建.core 文件,它將被分成幾個(gè)部分,第一部分是定義 CAPI 版本和核心庫,提供其名稱和描述
CAPI=2: name:adiuvo:0.1 description:ImplementationforHacksterProject
下一步是創(chuàng)建文件集,這些文件集被分成幾個(gè)不同的組。將其中第一個(gè)組命名為核心組,這些文件是所有工程中通用的。
對于每個(gè)文件,我們還定義了庫和文件類型,在本例中為 vhdl。
下一步是定義創(chuàng)建 IP 集成器設(shè)計(jì)的 tcl 腳本。由于三個(gè)目標(biāo)板之間的配置沒有差異。此文件在所有實(shí)現(xiàn)中也是通用的。
如果我們正在創(chuàng)建需要特定電路板配置的 Zynq 或 Zynq MPSoC 設(shè)計(jì),我們將需要為定義 PS 配置的每個(gè)電路板提供文件的變體。
下一個(gè)文件集是 IO 約束,每個(gè)所需的目標(biāo)板都有一個(gè)文件集。
filesets: core: files: -src/protocol.vhd:{logical_name:work} -src/uart_pkg.vhd:{logical_name:work} -src/uart.vhd:{logical_name:work} -src/top_level.vhd:{logical_name:work} file_type:vhdlSource vivado_files_tcl: files: -src/build_ip.tcl:{file_type:tclSource} artix_io: files: -constraints/artix7.xdc:{file_type:xdc} kintex_io: files: -constraints/kintexus.xdc:{file_type:xdc} spartan_io: files: -constraints/spartan.xdc:{file_type:xdc}
最后一步是定義目標(biāo),在這里定義一個(gè)包含核心文件集的默認(rèn)目標(biāo)。然后再定義三個(gè)目標(biāo),每個(gè)目標(biāo)板一個(gè)。對于每個(gè)目標(biāo),將工具定義為 AMD Vivado Design Suite,并附加該特定目標(biāo)所需的文件集。
在這種情況下,它是 IO 文件集和 tcl 腳本,用于演示如果每個(gè)目標(biāo)不同,如何使用 TCL 腳本。
對于每個(gè)目標(biāo),還需要在 AMD Vivado Design Suite 中定義頂層模塊,當(dāng)然還有目標(biāo)設(shè)備。
targets: default:&default filesets:[core] artix7: <<:?*default ????default_tool:?vivado ????filesets_append?:?[vivado_files_tcl,?artix_io] ????toplevel?:?top_level ????tools: ??????vivado: ????????part?:?XC7A35TI-CSG324-1L ??spartan7: ????<<:?*default ????default_tool:?vivado ????filesets_append?:?[vivado_files_tcl,?spartan_io] ????toplevel?:?top_level ????tools: ??????vivado: ????????part?:?xc7s50-csga324-1 ??kintexus: ????<<:?*default ????default_tool:?vivado ????filesets_append?:?[vivado_files_tcl,?kintex_io] ????toplevel?:?top_level ????tools: ??????vivado: ????????part?:?xcku040-ffva1156-2-i
.core 文件完成后,可以仔細(xì)檢查是否能夠看到剛剛定義的庫。
下一步是定義 fusesoc.conf 文件,定義核心的位置
[library.hackster] location=C:/hdl_projects/hackster_fusesoc sync-uri=C:/hdl_projects/hackster_fusesoc/ sync-type=local auto-sync=false
因?yàn)樵谶@個(gè)例子中我們只有一個(gè)名為 Hackster 的核心庫。
我們可以使用命令來檢查
fusesoccorelist
可以得到以下輸出
FuseSoC 結(jié)果
創(chuàng)建源代碼后,可以通過運(yùn)行命令來構(gòu)建這三個(gè)工程
AMD Artix 7
fusesoc--verboserun--target=artix7--no-exporthackster
AMD Kintex UltraSacle
fusesoc--verboserun--target=kintexus--no-exporthackster
AMD Spartan 7
fusesoc--verboserun--target=spartan7--no-exporthackster
隨著項(xiàng)目的構(gòu)建,將看到實(shí)施過程的記錄滾動(dòng)過去。
一旦完成后,將看到一條消息,顯示比特流生成已完成。
總結(jié)
該項(xiàng)目概述了如何使用 FuseSoC 編寫 FPGA 實(shí)現(xiàn)腳本,能夠輕松簡單地定位新的 FPGA 設(shè)備。由于 FuseSoC 是一個(gè)包管理器和構(gòu)建系統(tǒng)工具,能夠輕松進(jìn)行IP管理和不同設(shè)別之間工程管理。同時(shí)該項(xiàng)目中構(gòu)建了很多IP可以使用。
這里還有一點(diǎn),就是使用 FuseSoC 可以進(jìn)行快速驗(yàn)證,因?yàn)樗€支持一系列仿真工具。
-
FPGA
+關(guān)注
關(guān)注
1626文章
21665瀏覽量
601799 -
amd
+關(guān)注
關(guān)注
25文章
5441瀏覽量
133932 -
Xilinx
+關(guān)注
關(guān)注
71文章
2163瀏覽量
120998 -
移植
+關(guān)注
關(guān)注
1文章
377瀏覽量
28108
原文標(biāo)題:多平臺(tái)FPGA工程快速移植與構(gòu)建
文章出處:【微信號:HXSLH1010101010,微信公眾號:FPGA技術(shù)江湖】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論