以下文章來源于 OpenFPGA,作者 碎碎思
作為一名FPGA工程師,經常需要在多個FPGA設備之間移植項目,核心的問題是IP的管理和移植,今天通過安裝和使用 FuseSoC 在多個 AMD FPGA 之間移植一個簡單的項目。從 AMD Spartan 7 更改為 AMD Artix 7 設備,然后是 AMD Kintex UltraSacle。
FuseSoC 介紹
FuseSoC 是一款IP管理器和一套用于 HDL(硬件描述語言)代碼的構建工具。
其主要目的是增加 IP 核心的重用,有助于創建、構建和仿真 SoC的解決方案。
FuseSoC 具有如下功能:
重復使用現有核心
創建編譯時或運行時配置
針對多個仿真器運行回歸測試
讓其他項目輕松使用你的代碼
FuseSoC 最新可擴展版本支持使用 GHDL、Icarus Verilog、Isim、ModelSim、Verilator 和 Xsim 進行仿真。還支持使用 Altera Quartus、IceStorm、Xilinx ISE 和 Xilinx Vivado 構建 FPGA 映像。支持新的 EDA 工具需要大約 100 行代碼,并且會不斷添加新工具。
FuseSoC 已成功用于構建或仿真 Nyuzi、Pulpino、VScale、OpenRISC SoC、picorv32、osvvm 等項目。
安裝 FuseSoC
FuseSoC 以 Python 包的形式提供,因此我們可以使用 pip 安裝。對于這個項目,將使用 VSCode 作為安裝和使用 FuseSoC 的主要方法。
首先要檢查是否安裝了 Python
python--version
下一步是安裝 FuseSoC
pip3install--upgradefusesoc
要檢查 FuseSoC 是否已正確安裝,可以運行命令
fusesoc--version
可以看到類似下面的內容
FuseSoC 結構
FuseSoC 提供包管理和構建系統功能,因此需要了解一些基本概念才能有效地使用它。
FuseSoC 的關鍵元素是核心,核心就像我們平時熟知的 HDL IP。核心由 FuseSoC 包管理器進行管理,為了能夠管理核心,每個核心都有一個名稱和附加信息,這些附加信息在核心文件中提供。
為了 FuseSoC 管理 IP 核,核心文件的擴展名為.core
FuseSoC 的一個優點是核心可以具有依賴關系,例如,實現圖像直方圖和通過 AXI 接口的核心可以依賴于實現 AXI 接口的核心。
核心可以存儲在本地或遠程服務器上。核心的集合稱為核心庫,核心庫最簡單的實現是包含多個核心的目錄。
FuseSoC 構建系統時能夠解決核心依賴關系,就頂層核心而言。它可以是位于 github 或 bitbucket 上的 git repo 上的遠程庫。
雖然 FuseSoC 構建系統整理了構建設計所需的所有文件,但 AMD Vivado Design Suite 中的實際使用 EDAlize。EDALize 抽象了項目創建過程并執行 AMD Vivado Design Suite 完成綜合、布局和布線以及生成比特流。
我們可以使用頂層的.core文件來整合幾個不同的核心庫,并控制頂層入口點和最終 FPGA 設計的目標。
FuseSoC 能夠與多個不同的庫協同工作,為了向 FuseSoC 提供庫的位置,需要使用名為 fusesoc.conf的文件。FuseSoC 將首先在當前工作目錄中查找 .conf 文件,如果未找到,它將在主目錄 (Linux) 或 Windows %homedirectory% 中查找。
雖然我們可以手動創建此文件,但我們可以使用下面的命令自動創建它。
fusesoclibraryadd/path/to/directory
使用 FuseSoC
上面介紹的比較抽象,我們接下來使用一個實例來介紹FuseSoC的使用。
我們將在該項目中使用的源代碼是 UART to AXI 邏輯(文末提供)。
針對以下主板:Digilent Arty S7、Digilent Arty A7、Alinx KU040進行相同的工程設計。
首相,創建一個名為 SRC 的核心庫,在該庫下添加 HDL 元素的三個源文件。
還展示如何使用 AMD Vivado Design Suite IP 集成器設計并使用 FuseSoC 構建它們。將在 IP 集成器中包含一些設計元素。這種方法可以被視為一種混合方法,IP 集成器設計將映射到頂層 VHDL 設計中。
由于不想在 AMD Vivado Design Suite 中為不同的構建版本創建幾個不同的構建元素,所以將創建一個可由 FuseSoC 運行的 tcl 腳本。
該腳本將實例化 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
該腳本將創建如下所示的框圖。
然后,將創建一個頂層 RTL 文件,將 IP 集成器框圖與自定義 RTL 模塊連接起來完成設計。
協議文件
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;
創建 XDC
將要進行的三個工程之間的唯一區別在于約束文件。需要為每個目標板創建一個約束。
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]
創建 FuseSoC 核心
創建 RTL 和XDC后,下一步是創建.core 文件和.conf 文件。
首先要做的是創建.core 文件,它將被分成幾個部分,第一部分是定義 CAPI 版本和核心庫,提供其名稱和描述
CAPI=2: name:adiuvo:0.1 description:ImplementationforHacksterProject
下一步是創建文件集,這些文件集被分成幾個不同的組。將其中第一個組命名為核心組,這些文件是所有工程中通用的。
對于每個文件,我們還定義了庫和文件類型,在本例中為 vhdl。
下一步是定義創建 IP 集成器設計的 tcl 腳本。由于三個目標板之間的配置沒有差異。此文件在所有實現中也是通用的。
如果我們正在創建需要特定電路板配置的 Zynq 或 Zynq MPSoC 設計,我們將需要為定義 PS 配置的每個電路板提供文件的變體。
下一個文件集是 IO 約束,每個所需的目標板都有一個文件集。
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}
最后一步是定義目標,在這里定義一個包含核心文件集的默認目標。然后再定義三個目標,每個目標板一個。對于每個目標,將工具定義為 AMD Vivado Design Suite,并附加該特定目標所需的文件集。
在這種情況下,它是 IO 文件集和 tcl 腳本,用于演示如果每個目標不同,如何使用 TCL 腳本。
對于每個目標,還需要在 AMD Vivado Design Suite 中定義頂層模塊,當然還有目標設備。
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 文件完成后,可以仔細檢查是否能夠看到剛剛定義的庫。
下一步是定義 fusesoc.conf 文件,定義核心的位置
[library.hackster] location=C:/hdl_projects/hackster_fusesoc sync-uri=C:/hdl_projects/hackster_fusesoc/ sync-type=local auto-sync=false
因為在這個例子中我們只有一個名為 Hackster 的核心庫。
我們可以使用命令來檢查
fusesoccorelist
可以得到以下輸出
FuseSoC 結果
創建源代碼后,可以通過運行命令來構建這三個工程
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
隨著項目的構建,將看到實施過程的記錄滾動過去。
一旦完成后,將看到一條消息,顯示比特流生成已完成。
總結
該項目概述了如何使用 FuseSoC 編寫 FPGA 實現腳本,能夠輕松簡單地定位新的 FPGA 設備。由于 FuseSoC 是一個包管理器和構建系統工具,能夠輕松進行IP管理和不同設別之間工程管理。同時該項目中構建了很多IP可以使用。
這里還有一點,就是使用 FuseSoC 可以進行快速驗證,因為它還支持一系列仿真工具。
-
FPGA
+關注
關注
1629文章
21736瀏覽量
603319 -
amd
+關注
關注
25文章
5468瀏覽量
134149 -
Xilinx
+關注
關注
71文章
2167瀏覽量
121401 -
移植
+關注
關注
1文章
379瀏覽量
28130
原文標題:多平臺FPGA工程快速移植與構建
文章出處:【微信號:HXSLH1010101010,微信公眾號:FPGA技術江湖】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論