最近被這么一個(gè)工作折騰了好幾天:一個(gè)非IPI的Vivado工程(需要全部Verilog手寫),在Artix-7 FPGA中實(shí)現(xiàn)了一個(gè)ARM Cortex-M0 DesignStart軟核(老版,沒有debug模塊),存放ARM程序的存儲(chǔ)器是實(shí)現(xiàn)在FPGA片上RAM上的;ARM程序用Keil MDK編寫,我希望在測(cè)試這個(gè)程序時(shí),不用每次都重新綜合一遍FPGA。
總體來說這個(gè)需求是:
Vivado;
全部HDL,非IPI;
無處理器(在Vivado看來M0 DesignStart不是處理器);
存儲(chǔ)器放在BRAM上;
替換Bitstream中的BRAM初始化,而不用重新綜合整個(gè)邏輯。
這件事看上去肯定是能做到的嘛。然而Vivado要用新的updatemem命令來替換以前ISE中的data2mem,我發(fā)現(xiàn)在無處理器的工程上,相關(guān)資料比較少……
這里總結(jié)一下整個(gè)實(shí)現(xiàn)過程。使用環(huán)境是Vivado 2015.2。
先把Vivado多線程開了……
參考資料:
[Xilinx AR# 53090] Vivado - Is it possible to run Tcl commands during initialization of the Vivado or PlanAhead tools?
在Vivado安裝文件夾Vivadoversionscripts中新建一個(gè)init.tcl,里面寫
set_param general.maxThreads 8
這樣下次運(yùn)行Vivado是自動(dòng)開啟8線程,綜合實(shí)現(xiàn)比較快……
將寄存器定義在BRAM上
參考資料:?
[Xilinx AR# 54778] Design Assistant for Vivado Synthesis - Help with Synthesis HDL Attribute Support - keep, keep_hierarchy, ram_style, rom_style
這個(gè)頁(yè)面的附件中給出了ram_style屬性的例子,以verilog為例:
module ram_inf_64x1d_2 (a, dpra, clk, din, we, spo, dpo);
parameter ADDRESSWIDTH = 6;
parameter BITWIDTH = 1;
parameter DEPTH = 34;
input clk, din, we;
input [ADDRESSWIDTH-1:0] a, dpra;
output spo, dpo;
(* ram_style = "block" *)
reg [BITWIDTH-1:0] ram [DEPTH-1:0];
reg [ADDRESSWIDTH-1:0] read_dpra;
reg [ADDRESSWIDTH-1:0] read_a;
always @(posedge clk) begin
if (we) begin
ram [a] <= din;
end
read_a <= a;
read_dpra <= dpra;
end
assign spo = ram [read_a];
assign dpo = ram [read_dpra];
endmodule
上面代碼展示了如何將寄存器數(shù)組reg ram強(qiáng)制定義在Block RAM上,并展示了兩種訪問方式:
單口訪問:地址a、輸入數(shù)據(jù)din、輸出數(shù)據(jù)spo;
輸入、輸出分別訪問:輸入地址a、輸入數(shù)據(jù)din、輸出地址dpra、輸出數(shù)據(jù)dpo。
實(shí)際使用中可根據(jù)需要選擇保留其中一組引腳。
綜合后可檢查Project Summary和warning看是否成功綜合成BRAM。建議這段module直接使用,不做邏輯上的修改。
查看BRAM模塊的實(shí)現(xiàn)情況
參考資料:?
[Xilinx AR# 59259] 2013.4 - Vivado IPI - write_bmm Support with non-processor Based Designs?
這個(gè)帖子是針對(duì)bmm的,但其中提到了如何查看實(shí)現(xiàn)出的BRAM模塊的位置,以及怎樣知道每個(gè)模塊分配的行、列地址范圍。
把工程Implement一下,然后打開Implemented Design。
在打開的Implemented Design里面Ctrl+F搜索所有的BMEM:
搜索結(jié)果長(zhǎng)這樣:
每一行就是綜合出的一個(gè)BRAM模塊。選中其中一行,在它的屬性里可以看到:
其中比較重要的是模塊的名字(比如xxxxx/ram_reg_0)、位置(比如X1Y7)、行和列的地址范圍([0:16383]和[0:1])。
為BRAM cell添加bmm屬性
參考資料:?
[Xilinx論壇] A method to fix poor combination LBM of IPI Microblaze design?
我們需要做的是在Vivado工程里添加一個(gè)xdc約束文件,包含類似下面的內(nèi)容:
create_property bmm_info_memory_device cell -type string
set_property bmm_info_memory_device {[ 0: 1][0:16383]} [get_cells u_block_ram/ram_reg_0]
set_property bmm_info_memory_device {[ 2: 3][0:16383]} [get_cells u_block_ram/ram_reg_1]
set_property bmm_info_memory_device {[ 4: 5][0:16383]} [get_cells u_block_ram/ram_reg_2]
set_property bmm_info_memory_device {[ 6: 7][0:16383]} [get_cells u_block_ram/ram_reg_3]
# 后面還有好幾個(gè),最后是ram_reg_15
除了第一行定義屬性之外,后面每一行都對(duì)應(yīng)上面搜索到的一個(gè)BRAM模塊(當(dāng)然不需要初始化的BRAM就不用寫了)。
這里有兩個(gè)字段需要根據(jù)實(shí)際工程來改寫:一個(gè)是類似[ 0: 1][0:16383]這樣的地址范圍,另一個(gè)是u_block_ram/ram_reg_0這樣的cell名字。其他都是不用動(dòng)的。
我的工程里用到了64KBytes的RAM,總共使用了16個(gè)RAMB36模塊,所以我的xdc文件中有16行,最后到{[30:31][0:16383]} [get_cells u_block_ram/ram_reg_15]。
添加xdc文件之后把工程再次綜合實(shí)現(xiàn)一遍。
添加mmi文件
參考資料:
[Xilinx UG898] Vivado Design Suite User Guide: Embedded Processor Hardware Design?
[Xilinx AR# 63041] 2015.1 - Vivado IP Integrator - write_mem_info does not create MMI file?
上面一個(gè)文檔里有一章專門講mmi文件和updatemem命令。
下面帖子里描述了如何在有Memory Controller IP的Block Design中生成mmi文件,并附了一個(gè)tcl腳本。雖然我的系統(tǒng)中既沒有Memory Controller、也沒有Block Design,但資料還是有很大的參考意義。
實(shí)際上我把這個(gè)例子做了一遍,然后改寫了它生成的mmi。
mmi文件大概是這個(gè)模樣:
又是XML,現(xiàn)在不寫幾個(gè)XML都不好意思說自己用過Vivado……
這段代碼主要需要修改的是:
里面:Name是自己隨便起的;0和65535是分別是最小和最大地址,這里面地址的單位是字節(jié),總共64KBytes,與總線是32位無關(guān);另外這個(gè)地址應(yīng)該是可以不從0起始的。
每一個(gè)里面:MSB、LSB、Begin、End這些和上面xdc約束文件中的每一項(xiàng)是對(duì)應(yīng)的,Placement根據(jù)Implemented Design中搜索的結(jié)果來定。
里面:根據(jù)自己的FPGA型號(hào)修改,這個(gè)不用多說。
P.S. 在以前做bmm文件的時(shí)候,像Placement這種值是可以綜合器自動(dòng)幫助填寫的,暫時(shí)還沒發(fā)現(xiàn)如何在自定義bram時(shí)在mmi文件上實(shí)現(xiàn)類似功能。
合成Bitstream
參考資料:?
[Xilinx AR# 63041] 2015.1 - Vivado IP Integrator - write_mem_info does not create MMI file?
首先生成要往BRAM里燒寫的數(shù)據(jù),mem或elf格式。我這里是Keil MDK編譯的可執(zhí)行文件,直接把a(bǔ)xf擴(kuò)展名改成elf就能用。
把mmi、elf文件都放在Vivado工程的.runsimpl_1文件夾下,在Vivado中運(yùn)行tcl命令:
cd {C:
on_processor_mmiproject_1.runsimpl_1}
updatemem -force --meminfo mmi文件名.mmi --data elf文件名.elf --bit 原始的bit文件.bit --proc dummy --out download.bit
其中C:
on_processor_mmiproject_1.runsimpl_1改成自己的工程文件夾。
updatemem后面跟著的是一行命令,比較長(zhǎng)。
祈禱沒有錯(cuò)誤吧,然后可以看到impl_1文件夾中多了一個(gè)download.bit文件。
這一段可以看到Vivado重新launch_runs了write_bitstream,生成了一個(gè)新的bit文件,但并沒有再次綜合實(shí)現(xiàn)。
最后用Hardware Manager把Bitstream下載到FPGA中。
如何更新數(shù)據(jù)
比如說我用Keil MDK重新編譯出了一個(gè)elf,那么只需要再次運(yùn)行
updatemem -force --meminfo xxx.mmi --data yyy.elf --bit zzz.bit --proc dummy --out download.bit
就可以得到合成后的Bitstream,不需要再次綜合。
總結(jié)
編寫HDL文件,將寄存器強(qiáng)制定義在BRAM上;
綜合實(shí)現(xiàn)一遍;
在xdc約束文件中添加bmm屬性;
編寫mmi文件;
運(yùn)行updatemem合成Bitstream。
關(guān)于data2mem
這里記錄一下在查找資料過程中查到的利用bmm合成bit的資料,待之后嘗試。
[Xilinx UG658] Data2MEM User Guide?
Xilinx的data2mem使用手冊(cè),支持到ISE 14.7。
[Xilinx Answer 46945] Data2Mem Usage and Debugging Guide?
Xilinx整理的Data2Mem相關(guān)問答,相當(dāng)于上面手冊(cè)的補(bǔ)充說明,更實(shí)用一些的內(nèi)容。
Using Data2Mem in a Non-EDK design?
Xilinx的另一篇文檔,內(nèi)容如其名。
Loading BRAM data?
這個(gè)wiki中作者記錄了用data2mem合成AVR核的存儲(chǔ)器數(shù)據(jù)的各種方法,使用的環(huán)境是ISE 12.4。
spartan3 picoblaze how to make .bmm file work?
這個(gè)帖子下面Walter Dvorak的回復(fù)提到了ISE可以自動(dòng)生成bmm文件中的PLACED字段,使用的環(huán)境是ISE9.1.3。
Using Xilinx Data2MEM to Patch Block RAMs?
這個(gè)帖子把生成bmm到使用data2mem的過程總結(jié)的比較完整,其中也提到了上面那個(gè)Walter Dvorak的回復(fù)。
評(píng)論