??Xilinx 家的 FPGA 支持多重啟動功能(Multiboot),即可以從多個 bin 文件中進行選擇性加載,從而實現(xiàn)對系統(tǒng)的動態(tài)更新,或系統(tǒng)功能的動態(tài)調(diào)整。
??這一過程可以通過嵌入在 bit 文件里的 IPROG 命令實現(xiàn)上電后的自動加載。而同時 Xilinx 也提供了 ICAP 原語,給用戶提供了訪問配置功能的權(quán)限(對于 7 series 的芯片,需要使用 ICAPE2 原語),從而獲得更加靈活的多重啟動方式。
??本文即介紹 Multiboot 以及這兩種啟動方式,并對兩種 Multiboot 進行實現(xiàn)。
多重啟動(Multiboot)
??首先對 Multiboot 的流程進行一下介紹,
如圖所示,在實現(xiàn)多重啟動時,F(xiàn)LASH 中會保存多個 bin 文件,其中保存在 0 地址的稱為 Golden 鏡像,而其他的被稱為 Multiboot 鏡像(也稱為 Update 鏡像),這里就以 2 個 Image 為例進行說明。
??一般地,對于單個 bin 的情況,可以直接向 FLASH 燒錄 .bin 文件,也可以燒錄對應生成的 .mcs;而如果要燒錄多個版本的鏡像,則可以在生成 .mcs 時在不同地址載入多個不同的 bit 文件,然后下載這個 .mcs 文件。
Golden Image Initial System Setup
??在上圖所示的 Golden Image Initial System Setup 啟動模式下,上電后 FPGA 會自動加載 Golden 鏡像,隨后嘗試加載 Multiboot 鏡像,以重新配置 FPGA,實現(xiàn)代碼的更新/功能的更替。
??在這種啟動方式下:
- IPROG 命令被嵌入在 Golden Image 里(指將 IPROG 命令嵌在比特流文件里),或者通過 Golden Image 里編寫的 ICAPE2 原語程序啟動對 Multiboot Image 的讀??;
- Multiboot Image 應當存儲在熱啟動起始地址寄存器( Warm Boot Start Address Register, WBSTAR )指定的地址處;
- 應當啟動 Watchdog 計時器,以在編程失敗的情況下執(zhí)行恢復操作。
??在回退(fallback)發(fā)生時,嵌入的 IPROG 指令將被忽略,因此不會陷入反復觸發(fā)加載 Multiboot 的死循環(huán)。在回退完成后,WBSTAR 將被 bitstream 重寫。
Initial MultiBoot Image System Setup
??也可以在上電后先啟動 Multiboot 版本鏡像,在啟動失敗的情況下自動回退地址 0 的 Golden 鏡像,流程如下圖所示
在在線更新功能的設(shè)計中,Initial MultiBoot Image System Setup 模式是更加常用的。
??在這種啟動方式下,對于 Golden Image:
- WBSTAR 應當指向 Multiboot Image,同時應當插入一個 IPROG 指令以在上電時觸發(fā)對 Multiboot 的下載(在比特流文件里插入 IPROG 命令);
- 需要啟動 Configuration Timer;
- 如果 Golden Image 有能力修復 FLASH,則也可以實現(xiàn) ICAP 原語以重啟啟動 Multiboot 的加載;
- 對于 SPI 配置模式,在回退 Golden 過程中,始終采用 SPI x1 的模式。
對于 Multiboot Image:
- 需要啟動 Configuration Timer;
- Multiboot Image 也可以實現(xiàn) ICAP 原語以實現(xiàn)對其他 Multiboot Image 的重加載,或?qū)?Golden Image 的受控回退。
IPROG 說明
??IPROG(Internal PROGRAM)命令是 PROGRAM_B 引腳功能的一個子集,該命令可以從 ICAP 原語發(fā)出,也可以直接嵌入到比特流里。當為后者時,WBSTAR 和 IPROG 應當位于 Golden bit file 的開頭,此時在上電后會觸發(fā)從新地址加載 multiboot Image 的事件;如果加載失敗,則將返回地址 0 重新加載比特流,此時會忽略 IPROG,因此加載到的程序?qū)⑹?Golden Image。
WBSTAR 寄存器
??WBSTAR 寄存器保存了 IPROG 命令配置的啟動地址,該寄存器的值可以由嵌入在 bitstream 的 IPROG 配置,也可以由 ICAPE2 發(fā)出的 IPROG 配置。如果 bitstream 中沒有配置 WBSTAR,則地址默認為 0,因此如果從 Golden Image 觸發(fā)了多重啟動,則在加載完 Multiboot Image 后,WBSTAR 將被設(shè)置為 0。
??上電后,設(shè)備將從地址 0 開始讀取 FLASH,在加載了 WBSTAR 并發(fā)出 IPROG 后,將重定向到 WBSTAR 指定地址讀取 Imaeg。
Watchdog 計數(shù)器
??看門狗有兩種模式:配置監(jiān)視器模式、用戶邏輯監(jiān)視器模式。在配置監(jiān)視器模式下,Timer Register 通過比特流設(shè)置,需要在所有 bit File 中啟用這個計數(shù)器。Watchdog 由 FPGA 內(nèi)部鎖相環(huán)產(chǎn)生的 65MHz 時鐘驅(qū)動(這一描述和下表中的描述相悖),當計數(shù)器回到 0 時,將觸發(fā)回退。該計數(shù)器從比特流起始開始計數(shù),在啟動序列結(jié)束時被禁用。
從 ICAPE2 原語啟動 Multiboot 介紹
??當從 ICAPE2 原語觸發(fā) Multiboot 時,命令序列為:1. 發(fā)送同步碼;2. 設(shè)置 WBSTAR;3. 發(fā)送 IPROG 命令。一個通過 ICAPE2 發(fā)送的命令序列如下
ICAPE2 原語
??ICAPE2 原語接口如圖,調(diào)用格式如下
// 7 Series
// Xilinx HDL Language Template, version 2023.2
ICAPE2 #(
.DEVICE_ID (32'h3651093), // Specifies the pre-programmed Device ID value to be used for simulation purposes.
.ICAP_WIDTH ("X32"), // Specifies the input and output data width.
.SIM_CFG_FILE_NAME ("NONE") // Specifies the Raw Bitstream (RBT) file to be parsed by the simulation model.
)
ICAPE2_inst(
.O (O), // 32-bit output: Configuration data output bus
.CLK (CLK), // 1-bit input: Clock Input
.CSIB (CSIB), // 1-bit input: Active-Low ICAP Enable
.I (I), // 32-bit input: Configuration data input bus
.RDWRB (RDWRB) // 1-bit input: Read/Write Select input
);
其中 DEVICE_ID 是設(shè)備 ID,與芯片型號有關(guān),譬如對于 K7-325T,ID 如下
嵌入 IPROG 命令啟動 Multiboot 介紹
??WBSTAR 和 IPROG 命令可以嵌入到一個位流中,如圖所示。在 7 系列 FPGA 的 bitstream 中,WBSTAR 默認填入空白,同時保留了 IPROG 的占位符。我們打開一個 .bin 文件,看看到底是如何組織的
可以看到,在地址 0x30 開始的四個字節(jié),為同步碼 AA995566,隨后是一個 NO OP(20000000),然后是一些其他的命令;在 0x54 開始的 4 個字節(jié),為 Write 1 Word to WBSTAR 命令(30020001),隨后四個字節(jié)為要寫入 WBSTAR 的地址,這里默認是 0;隨后緊跟著 Write 1 Word to CMD 命令(30008001),隨后四字節(jié)為寫入的命令,這里默認是占位符 00000000,可以修改為 IPROG (0000000F)以實現(xiàn) IPROG 命令的嵌入。
??這里我們只是觀察一下 .bin/.bit 文件中 IPROG 是如何嵌入的,通過直接修改 .bit/.mcs 實現(xiàn) Multiboot 理論上也是可行的,但實際上我們不會這么做。在實際操作中我們可以通過在 xdc 中增加約束,生成需要的 .bit,然后再組合成 .mcs,下一節(jié)就介紹如何通過添加約束實現(xiàn)這一過程。
嵌入 IPROG 的操作流程
??在編譯 Golden Image 時,需要在 xdc 中增加如下約束
set_property BITSTREAM.CONFIG.CONFIGFALLBACK ENABLE [current_design]
set_property BITSTREAM.CONFIG.NEXT_CONFIG_ADDR 0x01000000 [current_design]
set_property CONFIG_MODE SPIX1 [current_design]
set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 1 [current_design]
#由于fallback使用SPIx1,因此請確定一定有此配置
# 如果 FLASH 大小大于等于 256Mb,要增加如下約束,否則高于24位的地址會被忽略,導致無法啟動對應的 update 鏡像
set_property BITSTREAM.CONFIG.SPI_32BIT_ADDR YES [current_design]
在編譯 Multiboot Image 時,需要在 xdc 中使用如下約束
set_property BITSTREAM.CONFIG.CONFIGFALLBACK ENABLE [current_design]
set_property CONFIG_MODE SPIX1 [current_design]
set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 1 [current_design]
#由于fallback使用SPIx1,因此請確定一定有此配置
# 如果 FLASH 大小大于等于 256Mb,要增加如下約束,否則高于24位的地址會被忽略,導致無法啟動對應的 update 鏡像
set_property BITSTREAM.CONFIG.SPI_32BIT_ADDR YES [current_design]
??上述約束中,BITSTREAM.CONFIG.CONFIGFALLBACK 用于啟用回退(Fallback)功能,BITSTREAM.CONFIG.NEXT_CONFIG_ADDR 用于設(shè)置 WBSTAR 寄存器,由于 Fallback 要求 SPIx1,因此 BITSTREAM.CONFIG.SPI_BUSWIDTH 要設(shè)為 1。
??編譯完成后,我們還是打開 .bit 看一下,Golden Image 的如下
可以看到 WBSTAR 和 IPROG 命令已經(jīng)被嵌入比特流。
??將兩個 .bit 文件分別載入地址 0 和高位地址,生成 .mcs,注意 Multiboot Image 所載入的高位地址應當與前面 xdc 配置的 NEXT_CONFIG_ADDR 相同。燒錄后,可以看到 update Image 被啟動。
ICAPE2 啟動 Multiboot 代碼示例
Multiboot_ctrl.v
??對于 SPI 設(shè)備,WBSTAR 地址有如下描述,即 Master SPI 模式下,WBSTAR 只會使用低 24 位,這 24 位為 FLASH 地址的 31:8 bits,在實現(xiàn)時應當注意
代碼如下
/*
* file : multiboot_ctrl.v
* author : 今朝無言
* Lab : WHU-EIS-LMSWE
* date : 2023-11-30
* version : v1.0
* description : ICAP 原語實現(xiàn)程控 multiboot(多重啟動),K7需要使用 ICAPE2 原語
* Copyright ? 2023 WHU-EIS-LMSWE, All Rights Reserved.
*/
`default_nettype none
module multiboot_ctrl(
input wire clk,
input wire rst_n,
input wire multiboot_start, //觸發(fā)Multiboot, 上升沿有效
input wire [31:0] multiboot_addr, //要啟動的Muliboot Image的起始地址
output reg busy
);
//-------------------ICAPE2原語-----------------------------
wire ICAPE2_CLK;
wire [31:0] ICAPE2_O;
reg ICAPE2_CSIB;
wire [31:0] ICAPE2_I;
reg ICAPE2_RDWRB;
assign ICAPE2_CLK = clk;
ICAPE2 #(
.DEVICE_ID (32'h3651093), // Specifies the pre-programmed Device ID value to be used for simulation purposes. K7-325T的為32'h3651093
.ICAP_WIDTH ("X32"), // Specifies the input and output data width.
.SIM_CFG_FILE_NAME ("NONE") // Specifies the Raw Bitstream (RBT) file to be parsed by the simulation model.
)
ICAPE2_inst(
.O (ICAPE2_O), // 32-bit output: Configuration data output bus
.CLK (ICAPE2_CLK), // 1-bit input: Clock Input
.CSIB (ICAPE2_CSIB), // 1-bit input: Active-Low ICAP Enable
.I (ICAPE2_I), // 32-bit input: Configuration data input bus
.RDWRB (ICAPE2_RDWRB) // 1-bit input: Read/Write Select input 1對應rd,0對應wr
);
wire [31:0] Dummy = 32'hFFFFFFFF;
wire [31:0] Sync_Word = 32'hAA995566;
wire [31:0] NOOP = 32'h20000000;
wire [31:0] WR_WBSTAR = 32'h30020001;
/*When using ICAPE2 to set the WBSTAR address, the 24 most significant address bits should be written
to WBSTAR[23:0]. For SPI 32-bit addressing mode, WBSTAR[23:0] are sent as address bits [31:8]. The
lower 8 bits of the address are undefined and the value could be as high as 0xFF. Any bitstream
at the WBSTAR address should contain 256 dummy bytes before the start of the bitstream.*/
wire [31:0] WBSTAR = {3'b000, 5'h0, multiboot_addr[31:8]};
wire [31:0] WR_CMD = 32'h30008001;
wire [31:0] IPROG = 32'h0000000F;
//ICAPE2位翻轉(zhuǎn)
reg [31:0] wrdat;
assign ICAPE2_I = {wrdat[24], wrdat[25], wrdat[26], wrdat[27], wrdat[28], wrdat[29], wrdat[30], wrdat[31],
wrdat[16], wrdat[17], wrdat[18], wrdat[19], wrdat[20], wrdat[21], wrdat[22], wrdat[23],
wrdat[8], wrdat[9], wrdat[10], wrdat[11], wrdat[12], wrdat[13], wrdat[14], wrdat[15],
wrdat[0], wrdat[1], wrdat[2], wrdat[3], wrdat[4], wrdat[5], wrdat[6], wrdat[7]};
//------------------------FSM----------------------------------
localparam S_IDLE = 16'h0001;
localparam S_DUMMY = 16'h0002;
localparam S_SYN_WORD = 16'h0004;
localparam S_NOOP1 = 16'h0008;
localparam S_WR_WBSTAR = 16'h0010;
localparam S_WBSTAR = 16'h0020;
localparam S_WR_CMD = 16'h0040;
localparam S_IPROG = 16'h0080;
localparam S_NOOP2 = 16'h0100;
localparam S_STOP = 16'h0200;
wire multiboot_start_pe;
reg multiboot_start_d0;
reg multiboot_start_d1;
assign multiboot_start_pe = multiboot_start_d0 & (~multiboot_start_d1);
always @(posedge clk) begin
multiboot_start_d0 <= multiboot_start;
multiboot_start_d1 <= multiboot_start_d0;
end
reg [15:0] state = S_IDLE;
reg [15:0] next_state;
always @(posedge clk) begin
if(~rst_n) begin
state <= S_IDLE;
end
else begin
state <= next_state;
end
end
always @(*) begin
case(state)
S_IDLE: begin
if(multiboot_start_pe) begin
next_state <= S_DUMMY;
end
else begin
next_state <= S_IDLE;
end
end
S_DUMMY: next_state <= S_SYN_WORD;
S_SYN_WORD: next_state <= S_NOOP1;
S_NOOP1: next_state <= S_WR_WBSTAR;
S_WR_WBSTAR: next_state <= S_WBSTAR;
S_WBSTAR: next_state <= S_WR_CMD;
S_WR_CMD: next_state <= S_IPROG;
S_IPROG: next_state <= S_NOOP2;
S_NOOP2: next_state <= S_STOP;
S_STOP: next_state <= S_IDLE;
default: next_state <= S_IDLE;
endcase
end
always @(posedge clk) begin
case(state)
S_IDLE: begin
wrdat <= 32'd0;
ICAPE2_CSIB <= 1'b1;
ICAPE2_RDWRB <= 1'b1;
end
S_DUMMY: begin
wrdat <= Dummy;
ICAPE2_CSIB <= 1'b0;
ICAPE2_RDWRB <= 1'b0;
end
S_SYN_WORD: begin
wrdat <= Sync_Word;
ICAPE2_CSIB <= 1'b0;
ICAPE2_RDWRB <= 1'b0;
end
S_NOOP1: begin
wrdat <= NOOP;
ICAPE2_CSIB <= 1'b0;
ICAPE2_RDWRB <= 1'b0;
end
S_WR_WBSTAR: begin
wrdat <= WR_WBSTAR;
ICAPE2_CSIB <= 1'b0;
ICAPE2_RDWRB <= 1'b0;
end
S_WBSTAR: begin
wrdat <= WBSTAR;
ICAPE2_CSIB <= 1'b0;
ICAPE2_RDWRB <= 1'b0;
end
S_WR_CMD: begin
wrdat <= WR_CMD;
ICAPE2_CSIB <= 1'b0;
ICAPE2_RDWRB <= 1'b0;
end
S_IPROG: begin
wrdat <= IPROG;
ICAPE2_CSIB <= 1'b0;
ICAPE2_RDWRB <= 1'b0;
end
S_NOOP2: begin
wrdat <= NOOP;
ICAPE2_CSIB <= 1'b0;
ICAPE2_RDWRB <= 1'b0;
end
S_STOP: begin
wrdat <= 32'd0;
ICAPE2_CSIB <= 1'b1;
ICAPE2_RDWRB <= 1'b1;
end
default: begin
wrdat <= 32'd0;
ICAPE2_CSIB <= 1'b1;
ICAPE2_RDWRB <= 1'b1;
end
endcase
end
always @(*) begin
case(state)
S_IDLE: busy <= 1'b0;
default: busy <= 1'b1;
endcase
end
endmodule
測試
??創(chuàng)建兩個工程如下
- Prj_1
//生成2個點燈的程序,使用ICAP來回切換這兩個Image
//本工程作為 Golden Image 存入地址 0
`default_nettype none
module Prj_1(
input wire clk_sys, //OXCO_10M
input wire [3:0] Key,
output wire [3:0] LED
);
assign LED = 4'b0001;
multiboot_ctrl multiboot_ctrl_inst(
.clk (clk_sys),
.rst_n (1'b1),
.multiboot_start (~Key[0]),
.multiboot_addr (32'h01000000), //加載0x01000000處的Multiboot Image
.busy ()
);
endmodule
- Prj_2
//生成2個點燈的程序,使用ICAP來回切換這兩個Image
//本工程作為 Update Image 存入高位地址
`default_nettype none
module Prj_2(
input wire clk_sys, //OXCO_10M
input wire [3:0] Key,
output wire [3:0] LED
);
assign LED = 4'b0010;
multiboot_ctrl multiboot_ctrl_inst(
.clk (clk_sys),
.rst_n (1'b1),
.multiboot_start (~Key[1]),
.multiboot_addr (32'h00000000), //加載0x00000000處的Golden Image
.busy ()
);
endmodule
燒錄后,通過按鍵可以來回切換兩個工程,讀者可自行驗證。文章來源:http://www.zghlxwxcb.cn/news/detail-765311.html
??一個注意事項,在燒錄完成后,必須拔掉 JTAG 再掉電重啟,ICAP 才可以正確啟動 Multiboot Image,如果是不拔掉 JTAG 掉電重啟,ICAP 觸發(fā)后只會加載 Golden Image。(真坑人啊,因為這個調(diào)了好久 (??へ??╬) )文章來源地址http://www.zghlxwxcb.cn/news/detail-765311.html
參考文獻
- ug470_Config.pdf
- ug953-vivado-7series-libraries.pdf
到了這里,關(guān)于K7系列FPGA多重啟動(Multiboot)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!