以下文章来源于 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
+关注
关注
1628文章
21728浏览量
602944 -
amd
+关注
关注
25文章
5466浏览量
134077 -
Xilinx
+关注
关注
71文章
2166浏览量
121284 -
移植
+关注
关注
1文章
379浏览量
28124
原文标题:多平台FPGA工程快速移植与构建
文章出处:【微信号:HXSLH1010101010,微信公众号:FPGA技术江湖】欢迎添加关注!文章转载请注明出处。
发布评论请先 登录
相关推荐
评论