由于之前在基础学习阶段不太重视FPGA的配置,但是在做项目过程中发现需要特别关注这部分内容,而且FPGA自带的配置会给最终设备的操作提供很多便利,尤其是动态配置(通俗讲就是可以做到不断电重启),所以这一篇介绍AMD FPGA此部分内容。
虽然每个系列配置接口都不同,但7系列芯片的配置步骤步骤对于所有芯片都是相同的。如果需要做到在线更新以及动态配置,一般需要准备两个固件,Golden Image(Base Address)和Multiboot Image(Upper Address)。首先,Golden Image从Base Address加载,接下来,Golden Image将触发要加载的MultiBoot Image。如果在Upper Address加载Multiboot Image时出错,将从Base Address加载Golden Image。
IPROG命令是PROGRAM_B引脚功能的一个子集。IPROG命令不会擦除用于启动多启动和回退的WBSTAR、计时器、BSPI和引导寄存器。IPROG命令触发初始化,当发出IPROG命令并尝试配置时,INIT和DONE都变为Low。该命令可以通过用户逻辑控制ICAPE2发出IPROG命令。这允许用户逻辑重新配置芯片。
WBSTAR(热启动启动地址)寄存器保存配置控制器在发出IPROG命令后使用的地址。这个寄存器可以从bit流中加载,或从ICAPE2中加载。如果在bit流中没有设置寄存器,则加载它的默认值为0。因此,在Golden Image设置WBSTAR值并启动MultiBoot Image后。在通电时,设备向闪灯发出读取命令,然后发出一个开始地址为0。在加载WBSTAR命令并发出IPROG命令后,配置控制器从WBSTAR地址指定的地址发出读取命令。
命令的顺序:
在配置逻辑接收到IPROG命令后,FPGA将重置除专用重配置逻辑之外的所有内容,并且INIT_B和DONE引脚变低。在FPGA清除所有配置内存后,INIT_B再次启动。然后将WBSTAR中的值用于起始地址。该配置模式决定了哪些引脚是由WBSTAR控制的。
写入数据需要进行位交换,无论数据的方向如何,每个字节的MSB都指向D0位:
- 在数据的位交换版本中,进入D0的位是最正确的位;
- 在非位交换的数据中,到达D0的位是最左边的位;
数据是否必须进行位交换,这完全依赖于应用程序。位交换适用于Serial, SelectMAP, 或者BPI PROM files文件,以及ICAPE2接口。
重启模块代码
/*
* file : multiboot_ctrl.v
* author : 今朝无言
* Lab : WHU-EIS-LMSWE
* date : 2023-11-30
* version : v1.0
* description : ICAP 原语实现程控 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, //触发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'h362D093), // 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位翻转
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
顶层文件:
//生成2个点灯的程序,使用ICAP来回切换这两个Image
//本工程作为 Golden Image 存入地址 0
`default_nettype none
module Top(
input wire clk_sys, //OXCO_10M
input wire sys_rst_n,
input wire [1:0] Key,
output wire [3:0] LED
);
reg [31:0]start_cnt;
reg start_en;
always@(posedge clk_sys)begin
if(!sys_rst_n)begin
start_cnt <= 32'd0;
start_en <= 0;
end
else if(start_cnt == 32'd49_999_999)begin
start_en <= 1'b1;
end
else if(start_en == 1'b0)begin
start_cnt <= start_cnt + 1'b1;
end
end
reg [31:0]reboot_addr;
reg key_sig;
always@(posedge clk_sys)begin
if(!sys_rst_n)begin
reboot_addr <= 32'h00400000;
key_sig <= 1'b0;
end
else if(~Key[1])begin
reboot_addr <= 32'h00000000;
key_sig <= 1'b1;
end
else if(~Key[0])begin
reboot_addr <= 32'h00400000;
key_sig <= 1'b1;
end
end
Multiboot_Ctrl multiboot_ctrl_inst(
.clk (clk_sys),
.rst_n (1'b1),
.multiboot_start (key_sig),
.multiboot_addr (reboot_addr), //加载0x01000000处的Multiboot Image
.busy ()
);
assign LED = (start_en == 1'b0) ? 4'b1100 : 4'b1111;
endmodule
xdc文件内添加的代码:
set_property CFGBVS VCCO [current_design]
set_property CONFIG_VOLTAGE 3.3 [current_design]
set_property BITSTREAM.GENERAL.COMPRESS true [current_design]
set_property BITSTREAM.CONFIG.CONFIGRATE 50 [current_design]
set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 4 [current_design]
set_property BITSTREAM.CONFIG.SPI_FALL_EDGE Yes [current_design]
参考文章
ug470_7Series_Config.pdf