Adding BPI flash support and YPCB board support
This commit is contained in:
parent
3f3e37909b
commit
98fea26507
|
|
@ -303,6 +303,7 @@ endif()
|
|||
# To be sorted
|
||||
# ===========================
|
||||
list(APPEND OPENFPGALOADER_SOURCE
|
||||
src/bpiFlash.cpp
|
||||
src/spiFlash.cpp
|
||||
src/spiInterface.cpp
|
||||
src/epcq.cpp
|
||||
|
|
@ -310,6 +311,7 @@ list(APPEND OPENFPGALOADER_SOURCE
|
|||
)
|
||||
|
||||
list(APPEND OPENFPGALOADER_HEADERS
|
||||
src/bpiFlash.hpp
|
||||
src/jtag.hpp
|
||||
src/jtagInterface.hpp
|
||||
src/spiFlash.hpp
|
||||
|
|
@ -781,6 +783,8 @@ install(TARGETS openFPGALoader DESTINATION bin)
|
|||
####################################################################################################
|
||||
|
||||
file(GLOB GZ_FILES spiOverJtag/spiOverJtag_*.*.gz)
|
||||
file(GLOB BPI_GZ_FILES bpiOverJtag/bpiOverJtag_*.bit.gz)
|
||||
list(APPEND GZ_FILES ${BPI_GZ_FILES})
|
||||
|
||||
# Compress rbf and bit files present into repository
|
||||
# TODO: test compat with Windows and MacOS
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
tmp_*
|
||||
*.bit
|
||||
*.rbf
|
||||
vivado*.jou
|
||||
vivado*.log
|
||||
.Xil
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
BPI_XILINX_PARTS := xc7k480tffg1156
|
||||
BPI_XILINX_BIT_FILES := $(addsuffix .bit.gz,$(addprefix bpiOverJtag_, $(BPI_XILINX_PARTS)))
|
||||
|
||||
BIT_FILES := $(BPI_XILINX_BIT_FILES)
|
||||
|
||||
all: $(BIT_FILES)
|
||||
|
||||
$(BPI_XILINX_BIT_FILES) : bpiOverJtag_%.bit.gz : tmp_%/bpiOverJtag.bit
|
||||
|
||||
tmp_%/bpiOverJtag.bit : xilinx_bpiOverJtag.v bpiOverJtag_core.v
|
||||
../spiOverJtag/build.py $* bpi
|
||||
|
||||
clean:
|
||||
-rm -rf tmp_* *.jou *.log .Xil
|
||||
|
|
@ -0,0 +1,331 @@
|
|||
`default_nettype none
|
||||
/*
|
||||
* BPI (Parallel NOR) Flash over JTAG core
|
||||
*
|
||||
* Protocol (all in one DR shift):
|
||||
* TX: [start=1][cmd:4][addr:25][wr_data:16] = 46 bits
|
||||
* RX: Response appears after command bits, aligned to read_data position
|
||||
*
|
||||
* Commands:
|
||||
* 0x1 = Write word to flash (addr + data)
|
||||
* 0x2 = Read word from flash (addr), returns data
|
||||
* 0x3 = NOP / get status
|
||||
* 0x4 = Burst write (addr + count + N×data words)
|
||||
*/
|
||||
|
||||
module bpiOverJtag_core (
|
||||
/* JTAG state/controls */
|
||||
input wire sel,
|
||||
input wire capture,
|
||||
input wire update,
|
||||
input wire shift,
|
||||
input wire drck,
|
||||
input wire tdi,
|
||||
output wire tdo,
|
||||
|
||||
/* Version endpoint */
|
||||
input wire ver_sel,
|
||||
input wire ver_cap,
|
||||
input wire ver_shift,
|
||||
input wire ver_drck,
|
||||
input wire ver_tdi,
|
||||
output wire ver_tdo,
|
||||
|
||||
/* BPI Flash physical interface */
|
||||
output reg [25:1] bpi_addr,
|
||||
inout wire [15:0] bpi_dq,
|
||||
output reg bpi_ce_n,
|
||||
output reg bpi_oe_n,
|
||||
output reg bpi_we_n,
|
||||
output reg bpi_adv_n
|
||||
);
|
||||
|
||||
/* Reset on capture when selected */
|
||||
wire rst = (capture & sel);
|
||||
|
||||
/* Start bit detection */
|
||||
wire start_header = (tdi & shift & sel);
|
||||
|
||||
/* State machine */
|
||||
localparam IDLE = 4'd0,
|
||||
RECV_CMD = 4'd1,
|
||||
RECV_ADDR = 4'd2,
|
||||
RECV_DATA = 4'd3,
|
||||
EXEC = 4'd4,
|
||||
SEND_DATA = 4'd5,
|
||||
DONE = 4'd6,
|
||||
BURST_RECV_CNT = 4'd7,
|
||||
BURST_DATA = 4'd8,
|
||||
BURST_EXEC = 4'd9;
|
||||
|
||||
reg [3:0] state, state_d;
|
||||
reg [5:0] bit_cnt, bit_cnt_d;
|
||||
reg [3:0] cmd_reg, cmd_reg_d;
|
||||
reg [24:0] addr_reg, addr_reg_d;
|
||||
reg [15:0] wr_data_reg, wr_data_reg_d;
|
||||
reg [15:0] rd_data_reg, rd_data_reg_d;
|
||||
reg [7:0] wait_cnt, wait_cnt_d;
|
||||
reg [15:0] burst_cnt, burst_cnt_d;
|
||||
|
||||
/* Data bus control */
|
||||
reg dq_oe;
|
||||
reg [15:0] dq_out;
|
||||
assign bpi_dq = dq_oe ? dq_out : 16'hzzzz;
|
||||
|
||||
/* TDO output - shift out read data */
|
||||
assign tdo = rd_data_reg[0];
|
||||
|
||||
/* Command codes */
|
||||
localparam CMD_WRITE = 4'h1,
|
||||
CMD_READ = 4'h2,
|
||||
CMD_NOP = 4'h3,
|
||||
CMD_BURST_WRITE = 4'h4;
|
||||
|
||||
/* Next state logic */
|
||||
always @(*) begin
|
||||
state_d = state;
|
||||
bit_cnt_d = bit_cnt;
|
||||
cmd_reg_d = cmd_reg;
|
||||
addr_reg_d = addr_reg;
|
||||
wr_data_reg_d = wr_data_reg;
|
||||
rd_data_reg_d = rd_data_reg;
|
||||
wait_cnt_d = wait_cnt;
|
||||
burst_cnt_d = burst_cnt;
|
||||
|
||||
case (state)
|
||||
IDLE: begin
|
||||
bit_cnt_d = 3; /* 4 bits for command */
|
||||
if (start_header)
|
||||
state_d = RECV_CMD;
|
||||
end
|
||||
|
||||
RECV_CMD: begin
|
||||
cmd_reg_d = {tdi, cmd_reg[3:1]};
|
||||
bit_cnt_d = bit_cnt - 1'b1;
|
||||
if (bit_cnt == 0) begin
|
||||
bit_cnt_d = 24; /* 25 bits for address */
|
||||
state_d = RECV_ADDR;
|
||||
end
|
||||
end
|
||||
|
||||
RECV_ADDR: begin
|
||||
addr_reg_d = {tdi, addr_reg[24:1]};
|
||||
bit_cnt_d = bit_cnt - 1'b1;
|
||||
if (bit_cnt == 0) begin
|
||||
if (cmd_reg == CMD_WRITE) begin
|
||||
bit_cnt_d = 15; /* 16 bits for data */
|
||||
state_d = RECV_DATA;
|
||||
end else if (cmd_reg == CMD_BURST_WRITE) begin
|
||||
bit_cnt_d = 15; /* 16 bits for burst count */
|
||||
state_d = BURST_RECV_CNT;
|
||||
end else begin
|
||||
wait_cnt_d = 8'd20; /* Wait cycles for read */
|
||||
state_d = EXEC;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
RECV_DATA: begin
|
||||
wr_data_reg_d = {tdi, wr_data_reg[15:1]};
|
||||
bit_cnt_d = bit_cnt - 1'b1;
|
||||
if (bit_cnt == 0) begin
|
||||
wait_cnt_d = 8'd20; /* Wait cycles for write */
|
||||
state_d = EXEC;
|
||||
end
|
||||
end
|
||||
|
||||
EXEC: begin
|
||||
wait_cnt_d = wait_cnt - 1'b1;
|
||||
if (wait_cnt == 8'd10 && cmd_reg == CMD_READ) begin
|
||||
/* Sample read data mid-cycle */
|
||||
rd_data_reg_d = bpi_dq;
|
||||
end
|
||||
if (wait_cnt == 0) begin
|
||||
bit_cnt_d = 15;
|
||||
state_d = SEND_DATA;
|
||||
end
|
||||
end
|
||||
|
||||
SEND_DATA: begin
|
||||
rd_data_reg_d = {1'b1, rd_data_reg[15:1]};
|
||||
bit_cnt_d = bit_cnt - 1'b1;
|
||||
if (bit_cnt == 0)
|
||||
state_d = DONE;
|
||||
end
|
||||
|
||||
BURST_RECV_CNT: begin
|
||||
burst_cnt_d = {tdi, burst_cnt[15:1]};
|
||||
bit_cnt_d = bit_cnt - 1'b1;
|
||||
if (bit_cnt == 0) begin
|
||||
bit_cnt_d = 15;
|
||||
state_d = BURST_DATA;
|
||||
end
|
||||
end
|
||||
|
||||
BURST_DATA: begin
|
||||
wr_data_reg_d = {tdi, wr_data_reg[15:1]};
|
||||
bit_cnt_d = bit_cnt - 1'b1;
|
||||
if (bit_cnt == 0) begin
|
||||
wait_cnt_d = 8'd20;
|
||||
state_d = BURST_EXEC;
|
||||
end
|
||||
end
|
||||
|
||||
BURST_EXEC: begin
|
||||
wait_cnt_d = wait_cnt - 1'b1;
|
||||
if (wait_cnt == 0) begin
|
||||
burst_cnt_d = burst_cnt - 1'b1;
|
||||
if (burst_cnt == 16'd1) begin
|
||||
state_d = DONE;
|
||||
end else begin
|
||||
addr_reg_d = addr_reg + 1'b1;
|
||||
bit_cnt_d = 15;
|
||||
state_d = BURST_DATA;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
DONE: begin
|
||||
/* Stay here until reset */
|
||||
end
|
||||
|
||||
default: state_d = IDLE;
|
||||
endcase
|
||||
end
|
||||
|
||||
/* State register */
|
||||
always @(posedge drck or posedge rst) begin
|
||||
if (rst)
|
||||
state <= IDLE;
|
||||
else
|
||||
state <= state_d;
|
||||
end
|
||||
|
||||
/* Data registers */
|
||||
always @(posedge drck) begin
|
||||
bit_cnt <= bit_cnt_d;
|
||||
cmd_reg <= cmd_reg_d;
|
||||
addr_reg <= addr_reg_d;
|
||||
wr_data_reg <= wr_data_reg_d;
|
||||
rd_data_reg <= rd_data_reg_d;
|
||||
wait_cnt <= wait_cnt_d;
|
||||
burst_cnt <= burst_cnt_d;
|
||||
end
|
||||
|
||||
/* Address output */
|
||||
always @(posedge drck or posedge rst) begin
|
||||
if (rst)
|
||||
bpi_addr <= 25'd0;
|
||||
else if (state == RECV_ADDR && bit_cnt == 0)
|
||||
bpi_addr <= {tdi, addr_reg[24:1]};
|
||||
else if (state == BURST_DATA && bit_cnt == 0)
|
||||
bpi_addr <= addr_reg;
|
||||
end
|
||||
|
||||
/* BPI Flash control signals */
|
||||
always @(posedge drck or posedge rst) begin
|
||||
if (rst) begin
|
||||
bpi_ce_n <= 1'b1;
|
||||
bpi_oe_n <= 1'b1;
|
||||
bpi_we_n <= 1'b1;
|
||||
bpi_adv_n <= 1'b1;
|
||||
dq_oe <= 1'b0;
|
||||
dq_out <= 16'h0000;
|
||||
end else begin
|
||||
case (state_d)
|
||||
EXEC: begin
|
||||
bpi_ce_n <= 1'b0;
|
||||
bpi_adv_n <= 1'b0;
|
||||
if (cmd_reg == CMD_READ) begin
|
||||
bpi_oe_n <= 1'b0;
|
||||
bpi_we_n <= 1'b1;
|
||||
dq_oe <= 1'b0;
|
||||
end else if (cmd_reg == CMD_WRITE) begin
|
||||
bpi_oe_n <= 1'b1;
|
||||
bpi_we_n <= (wait_cnt > 8'd5 && wait_cnt < 8'd15) ? 1'b0 : 1'b1;
|
||||
dq_oe <= 1'b1;
|
||||
dq_out <= wr_data_reg;
|
||||
end
|
||||
end
|
||||
BURST_EXEC: begin
|
||||
bpi_ce_n <= 1'b0;
|
||||
bpi_adv_n <= 1'b0;
|
||||
bpi_oe_n <= 1'b1;
|
||||
bpi_we_n <= (wait_cnt > 8'd5 && wait_cnt < 8'd15) ? 1'b0 : 1'b1;
|
||||
dq_oe <= 1'b1;
|
||||
dq_out <= wr_data_reg;
|
||||
end
|
||||
default: begin
|
||||
bpi_ce_n <= 1'b1;
|
||||
bpi_oe_n <= 1'b1;
|
||||
bpi_we_n <= 1'b1;
|
||||
bpi_adv_n <= 1'b1;
|
||||
dq_oe <= 1'b0;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
/* ------------- */
|
||||
/* Version */
|
||||
/* ------------- */
|
||||
wire ver_rst = (ver_cap & ver_sel);
|
||||
wire ver_start = (ver_tdi & ver_shift & ver_sel);
|
||||
|
||||
localparam VER_VALUE = 40'h30_32_2E_30_30; // "02.00"
|
||||
|
||||
reg [6:0] ver_cnt, ver_cnt_d;
|
||||
reg [39:0] ver_shft, ver_shft_d;
|
||||
reg [2:0] ver_state, ver_state_d;
|
||||
|
||||
localparam VER_IDLE = 3'd0,
|
||||
VER_RECV = 3'd1,
|
||||
VER_XFER = 3'd2,
|
||||
VER_WAIT = 3'd3;
|
||||
|
||||
always @(*) begin
|
||||
ver_state_d = ver_state;
|
||||
ver_cnt_d = ver_cnt;
|
||||
ver_shft_d = ver_shft;
|
||||
case (ver_state)
|
||||
VER_IDLE: begin
|
||||
ver_cnt_d = 6;
|
||||
if (ver_start)
|
||||
ver_state_d = VER_RECV;
|
||||
end
|
||||
VER_RECV: begin
|
||||
ver_cnt_d = ver_cnt - 1'b1;
|
||||
if (ver_cnt == 0) begin
|
||||
ver_state_d = VER_XFER;
|
||||
ver_cnt_d = 39;
|
||||
ver_shft_d = VER_VALUE;
|
||||
end
|
||||
end
|
||||
VER_XFER: begin
|
||||
ver_cnt_d = ver_cnt - 1;
|
||||
ver_shft_d = {1'b1, ver_shft[39:1]};
|
||||
if (ver_cnt == 0)
|
||||
ver_state_d = VER_WAIT;
|
||||
end
|
||||
VER_WAIT: begin
|
||||
/* Wait for reset */
|
||||
end
|
||||
default: ver_state_d = VER_IDLE;
|
||||
endcase
|
||||
end
|
||||
|
||||
always @(posedge ver_drck) begin
|
||||
ver_cnt <= ver_cnt_d;
|
||||
ver_shft <= ver_shft_d;
|
||||
end
|
||||
|
||||
always @(posedge ver_drck or posedge ver_rst) begin
|
||||
if (ver_rst)
|
||||
ver_state <= VER_IDLE;
|
||||
else
|
||||
ver_state <= ver_state_d;
|
||||
end
|
||||
|
||||
assign ver_tdo = ver_shft[0];
|
||||
|
||||
endmodule
|
||||
Binary file not shown.
|
|
@ -0,0 +1,58 @@
|
|||
## BPI Flash over JTAG constraints for xc7k480tffg1156
|
||||
## Pin assignments from YPCB-00338-1P1 board
|
||||
|
||||
set_property CFGBVS GND [current_design]
|
||||
set_property CONFIG_VOLTAGE 1.8 [current_design]
|
||||
set_property BITSTREAM.GENERAL.COMPRESS TRUE [current_design]
|
||||
set_property BITSTREAM.CONFIG.UNUSEDPIN PULLNONE [current_design]
|
||||
|
||||
## Address bus [25:1]
|
||||
set_property -dict {PACKAGE_PIN AD26 IOSTANDARD LVCMOS18} [get_ports {bpi_addr[1]}]
|
||||
set_property -dict {PACKAGE_PIN AC25 IOSTANDARD LVCMOS18} [get_ports {bpi_addr[2]}]
|
||||
set_property -dict {PACKAGE_PIN AC29 IOSTANDARD LVCMOS18} [get_ports {bpi_addr[3]}]
|
||||
set_property -dict {PACKAGE_PIN AC28 IOSTANDARD LVCMOS18} [get_ports {bpi_addr[4]}]
|
||||
set_property -dict {PACKAGE_PIN AD27 IOSTANDARD LVCMOS18} [get_ports {bpi_addr[5]}]
|
||||
set_property -dict {PACKAGE_PIN AC27 IOSTANDARD LVCMOS18} [get_ports {bpi_addr[6]}]
|
||||
set_property -dict {PACKAGE_PIN AB25 IOSTANDARD LVCMOS18} [get_ports {bpi_addr[7]}]
|
||||
set_property -dict {PACKAGE_PIN AB28 IOSTANDARD LVCMOS18} [get_ports {bpi_addr[8]}]
|
||||
set_property -dict {PACKAGE_PIN AB27 IOSTANDARD LVCMOS18} [get_ports {bpi_addr[9]}]
|
||||
set_property -dict {PACKAGE_PIN AB26 IOSTANDARD LVCMOS18} [get_ports {bpi_addr[10]}]
|
||||
set_property -dict {PACKAGE_PIN AA26 IOSTANDARD LVCMOS18} [get_ports {bpi_addr[11]}]
|
||||
set_property -dict {PACKAGE_PIN AA31 IOSTANDARD LVCMOS18} [get_ports {bpi_addr[12]}]
|
||||
set_property -dict {PACKAGE_PIN AA30 IOSTANDARD LVCMOS18} [get_ports {bpi_addr[13]}]
|
||||
set_property -dict {PACKAGE_PIN AB33 IOSTANDARD LVCMOS18} [get_ports {bpi_addr[14]}]
|
||||
set_property -dict {PACKAGE_PIN AB32 IOSTANDARD LVCMOS18} [get_ports {bpi_addr[15]}]
|
||||
set_property -dict {PACKAGE_PIN Y32 IOSTANDARD LVCMOS18} [get_ports {bpi_addr[16]}]
|
||||
set_property -dict {PACKAGE_PIN P32 IOSTANDARD LVCMOS18} [get_ports {bpi_addr[17]}]
|
||||
set_property -dict {PACKAGE_PIN R32 IOSTANDARD LVCMOS18} [get_ports {bpi_addr[18]}]
|
||||
set_property -dict {PACKAGE_PIN U33 IOSTANDARD LVCMOS18} [get_ports {bpi_addr[19]}]
|
||||
set_property -dict {PACKAGE_PIN T31 IOSTANDARD LVCMOS18} [get_ports {bpi_addr[20]}]
|
||||
set_property -dict {PACKAGE_PIN T30 IOSTANDARD LVCMOS18} [get_ports {bpi_addr[21]}]
|
||||
set_property -dict {PACKAGE_PIN U31 IOSTANDARD LVCMOS18} [get_ports {bpi_addr[22]}]
|
||||
set_property -dict {PACKAGE_PIN U30 IOSTANDARD LVCMOS18} [get_ports {bpi_addr[23]}]
|
||||
set_property -dict {PACKAGE_PIN N34 IOSTANDARD LVCMOS18} [get_ports {bpi_addr[24]}]
|
||||
set_property -dict {PACKAGE_PIN P34 IOSTANDARD LVCMOS18} [get_ports {bpi_addr[25]}]
|
||||
|
||||
## Data bus [15:0] - bidirectional
|
||||
set_property -dict {PACKAGE_PIN AA33 IOSTANDARD LVCMOS18} [get_ports {bpi_dq[0]}]
|
||||
set_property -dict {PACKAGE_PIN AA34 IOSTANDARD LVCMOS18} [get_ports {bpi_dq[1]}]
|
||||
set_property -dict {PACKAGE_PIN Y33 IOSTANDARD LVCMOS18} [get_ports {bpi_dq[2]}]
|
||||
set_property -dict {PACKAGE_PIN Y34 IOSTANDARD LVCMOS18} [get_ports {bpi_dq[3]}]
|
||||
set_property -dict {PACKAGE_PIN V32 IOSTANDARD LVCMOS18} [get_ports {bpi_dq[4]}]
|
||||
set_property -dict {PACKAGE_PIN V33 IOSTANDARD LVCMOS18} [get_ports {bpi_dq[5]}]
|
||||
set_property -dict {PACKAGE_PIN W31 IOSTANDARD LVCMOS18} [get_ports {bpi_dq[6]}]
|
||||
set_property -dict {PACKAGE_PIN W32 IOSTANDARD LVCMOS18} [get_ports {bpi_dq[7]}]
|
||||
set_property -dict {PACKAGE_PIN W30 IOSTANDARD LVCMOS18} [get_ports {bpi_dq[8]}]
|
||||
set_property -dict {PACKAGE_PIN V25 IOSTANDARD LVCMOS18} [get_ports {bpi_dq[9]}]
|
||||
set_property -dict {PACKAGE_PIN W25 IOSTANDARD LVCMOS18} [get_ports {bpi_dq[10]}]
|
||||
set_property -dict {PACKAGE_PIN V29 IOSTANDARD LVCMOS18} [get_ports {bpi_dq[11]}]
|
||||
set_property -dict {PACKAGE_PIN W29 IOSTANDARD LVCMOS18} [get_ports {bpi_dq[12]}]
|
||||
set_property -dict {PACKAGE_PIN V28 IOSTANDARD LVCMOS18} [get_ports {bpi_dq[13]}]
|
||||
set_property -dict {PACKAGE_PIN W24 IOSTANDARD LVCMOS18} [get_ports {bpi_dq[14]}]
|
||||
set_property -dict {PACKAGE_PIN Y24 IOSTANDARD LVCMOS18} [get_ports {bpi_dq[15]}]
|
||||
|
||||
## Control signals
|
||||
set_property -dict {PACKAGE_PIN V30 IOSTANDARD LVCMOS18} [get_ports {bpi_ce_n}]
|
||||
set_property -dict {PACKAGE_PIN T33 IOSTANDARD LVCMOS18} [get_ports {bpi_oe_n}]
|
||||
set_property -dict {PACKAGE_PIN T34 IOSTANDARD LVCMOS18} [get_ports {bpi_we_n}]
|
||||
set_property -dict {PACKAGE_PIN M31 IOSTANDARD LVCMOS18} [get_ports {bpi_adv_n}]
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
`default_nettype none
|
||||
/*
|
||||
* BPI Flash over JTAG for Xilinx 7-series FPGAs
|
||||
* Uses BSCANE2 primitive to access USER1 JTAG register
|
||||
*/
|
||||
|
||||
module bpiOverJtag (
|
||||
/* BPI Flash interface */
|
||||
output wire [25:1] bpi_addr,
|
||||
inout wire [15:0] bpi_dq,
|
||||
output wire bpi_ce_n,
|
||||
output wire bpi_oe_n,
|
||||
output wire bpi_we_n,
|
||||
output wire bpi_adv_n
|
||||
);
|
||||
|
||||
wire capture, drck, sel, update, shift;
|
||||
wire tdi, tdo;
|
||||
|
||||
/* Version Interface */
|
||||
wire ver_sel, ver_cap, ver_shift, ver_drck, ver_tdi, ver_tdo;
|
||||
|
||||
bpiOverJtag_core bpiOverJtag_core_inst (
|
||||
/* JTAG state/controls */
|
||||
.sel(sel),
|
||||
.capture(capture),
|
||||
.update(update),
|
||||
.shift(shift),
|
||||
.drck(drck),
|
||||
.tdi(tdi),
|
||||
.tdo(tdo),
|
||||
|
||||
/* Version endpoint */
|
||||
.ver_sel(ver_sel),
|
||||
.ver_cap(ver_cap),
|
||||
.ver_shift(ver_shift),
|
||||
.ver_drck(ver_drck),
|
||||
.ver_tdi(ver_tdi),
|
||||
.ver_tdo(ver_tdo),
|
||||
|
||||
/* BPI Flash physical interface */
|
||||
.bpi_addr(bpi_addr),
|
||||
.bpi_dq(bpi_dq),
|
||||
.bpi_ce_n(bpi_ce_n),
|
||||
.bpi_oe_n(bpi_oe_n),
|
||||
.bpi_we_n(bpi_we_n),
|
||||
.bpi_adv_n(bpi_adv_n)
|
||||
);
|
||||
|
||||
/* BSCANE2 for main data interface (USER1) */
|
||||
BSCANE2 #(
|
||||
.JTAG_CHAIN(1)
|
||||
) bscane2_inst (
|
||||
.CAPTURE(capture),
|
||||
.DRCK(drck),
|
||||
.RESET(),
|
||||
.RUNTEST(),
|
||||
.SEL(sel),
|
||||
.SHIFT(shift),
|
||||
.TCK(),
|
||||
.TDI(tdi),
|
||||
.TMS(),
|
||||
.UPDATE(update),
|
||||
.TDO(tdo)
|
||||
);
|
||||
|
||||
/* BSCANE2 for version interface (USER4) */
|
||||
BSCANE2 #(
|
||||
.JTAG_CHAIN(4)
|
||||
) bscane2_version (
|
||||
.CAPTURE(ver_cap),
|
||||
.DRCK(ver_drck),
|
||||
.RESET(),
|
||||
.RUNTEST(),
|
||||
.SEL(ver_sel),
|
||||
.SHIFT(ver_shift),
|
||||
.TCK(),
|
||||
.TDI(ver_tdi),
|
||||
.TMS(),
|
||||
.UPDATE(),
|
||||
.TDO(ver_tdo)
|
||||
);
|
||||
|
||||
endmodule
|
||||
|
|
@ -987,6 +987,13 @@
|
|||
Memory: OK
|
||||
Flash: OK
|
||||
|
||||
- ID: ypcb003381p1
|
||||
Description: YPCB-00338-1P1 Kintex-7 Accelerator Card
|
||||
URL: https://www.tiferking.cn/index.php/2024/12/19/650/
|
||||
FPGA: Kintex7 xc7k480tffg1156
|
||||
Memory: OK
|
||||
Flash: OK. BPI parallel NOR flash (MT28GU512AAA1EGC)
|
||||
|
||||
- ID: zc702
|
||||
Description: Xilinx ZC702
|
||||
URL: https://www.xilinx.com/products/boards-and-kits/ek-z7-zc702-g.html
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ tmp_efinix_%/efinix_spiOverJtag.bit : efinix_spiOverJtag.v
|
|||
$(XILINX_BIT_FILES) : spiOverJtag_%.bit.gz : tmp_%/spiOverJtag.bit
|
||||
|
||||
tmp_%/spiOverJtag.bit : xilinx_spiOverJtag.v spiOverJtag_core.v
|
||||
./build.py $*
|
||||
./build.py $* spi
|
||||
|
||||
$(ALTERA_BIT_FILES): spiOverJtag_%.rbf.gz: tmp_%/spiOverJtag.rbf
|
||||
gzip -9 -c $< > $@
|
||||
|
|
@ -44,7 +44,7 @@ tmp_%/spiOverJtag.rbf: tmp_%/spiOverJtag.sof
|
|||
quartus_cpf --option=bitstream_compression=off -c $< $@
|
||||
|
||||
tmp_%/spiOverJtag.sof: altera_spiOverJtag.v
|
||||
./build.py $*
|
||||
./build.py $* spi
|
||||
|
||||
clean:
|
||||
-rm -rf tmp_* *.jou *.log .Xil
|
||||
|
|
|
|||
|
|
@ -37,10 +37,14 @@ packages = {
|
|||
},
|
||||
}
|
||||
|
||||
if len(os.sys.argv) != 2:
|
||||
print("missing board param")
|
||||
if len(os.sys.argv) != 3 :
|
||||
print("missing board flash type params")
|
||||
os.sys.exit()
|
||||
part = os.sys.argv[1]
|
||||
part = os.sys.argv[1]
|
||||
flash_type = os.sys.argv[2]
|
||||
|
||||
# Check file type keyword
|
||||
assert flash_type in ["spi", "bpi"]
|
||||
|
||||
build_dir="tmp_" + part
|
||||
if not os.path.isdir(build_dir):
|
||||
|
|
@ -84,7 +88,7 @@ elif subpart == "xc7v":
|
|||
tool = "vivado"
|
||||
elif subpart == "xc7k":
|
||||
device_size = int(part.split('k')[1].split('t')[0])
|
||||
if device_size <= 160:
|
||||
if flash_type == "bpi" or device_size <= 160:
|
||||
family = "Kintex 7"
|
||||
tool = "vivado"
|
||||
else:
|
||||
|
|
@ -214,10 +218,13 @@ if tool in ["ise", "vivado"]:
|
|||
tool_options = {'part': part + '-1'}
|
||||
|
||||
cst_file = currDir + "constr_" + pkg_name + "." + cst_type.lower()
|
||||
files.append({'name': currDir + 'xilinx_spiOverJtag.v',
|
||||
files.append({'name': os.path.join(currDir, f"xilinx_{flash_type}OverJtag.v"),
|
||||
'file_type': 'verilogSource'})
|
||||
files.append({'name': cst_file, 'file_type': cst_type})
|
||||
else:
|
||||
# Altera only support SPI mode.
|
||||
assert flash_type in ["spi"]
|
||||
|
||||
full_part = {
|
||||
"10cl016484" : "10CL016YU484C8G",
|
||||
"10cl025256" : "10CL025YU256C8G",
|
||||
|
|
@ -245,7 +252,7 @@ else:
|
|||
'file_type': 'SDC'})
|
||||
tool_options = {'device': full_part, 'family':family}
|
||||
|
||||
files.append({'name': currDir + 'spiOverJtag_core.v',
|
||||
files.append({'name': os.path.join(currDir, f"{flash_type}OverJtag_core.v"),
|
||||
'file_type': 'verilogSource'})
|
||||
|
||||
parameters[family.lower().replace(' ', '')]= {
|
||||
|
|
@ -254,11 +261,11 @@ parameters[family.lower().replace(' ', '')]= {
|
|||
'description': 'fpga family',
|
||||
'default': 1}
|
||||
|
||||
edam = {'name' : "spiOverJtag",
|
||||
edam = {'name' : f"{flash_type}OverJtag",
|
||||
'files': files,
|
||||
'tool_options': {tool: tool_options},
|
||||
'parameters': parameters,
|
||||
'toplevel' : 'spiOverJtag',
|
||||
'toplevel' : f"{flash_type}OverJtag",
|
||||
}
|
||||
|
||||
backend = get_edatool(tool)(edam=edam, work_root=build_dir)
|
||||
|
|
@ -271,14 +278,14 @@ if tool in ["vivado", "ise"]:
|
|||
import gzip
|
||||
|
||||
# Compress bitstream.
|
||||
with open(f"tmp_{part}/spiOverJtag.bit", 'rb') as bit:
|
||||
with gzip.open(f"spiOverJtag_{part}.bit.gz", 'wb', compresslevel=9) as bit_gz:
|
||||
with open(f"tmp_{part}/{flash_type}OverJtag.bit", 'rb') as bit:
|
||||
with gzip.open(f"{flash_type}OverJtag_{part}.bit.gz", 'wb', compresslevel=9) as bit_gz:
|
||||
shutil.copyfileobj(bit, bit_gz)
|
||||
|
||||
# Create Symbolic links for all supported packages.
|
||||
if family in ["Artix", "Spartan 7"]:
|
||||
in_file = f"spiOverJtag_{part}.bit.gz"
|
||||
in_file = f"{flash_type}OverJtag_{part}.bit.gz"
|
||||
for pkg in packages[family][part]:
|
||||
out_file = f"spiOverJtag_{part}{pkg}.bit.gz"
|
||||
out_file = f"{flash_type}OverJtag_{part}{pkg}.bit.gz"
|
||||
if not os.path.exists(out_file):
|
||||
subprocess.run(["ln", "-s", in_file, out_file])
|
||||
|
|
|
|||
295
src/board.hpp
295
src/board.hpp
|
|
@ -69,6 +69,11 @@ enum {
|
|||
COMM_DFU = (1 << 2),
|
||||
};
|
||||
|
||||
enum {
|
||||
SPI_FLASH = 0,
|
||||
BPI_FLASH = 1,
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief a board has a target cable and optionally a pin configuration
|
||||
* (bitbang mode)
|
||||
|
|
@ -81,6 +86,7 @@ typedef struct {
|
|||
uint16_t done_pin; /*! done pin value */
|
||||
uint16_t oe_pin; /*! output enable pin value */
|
||||
uint16_t mode; /*! communication type (JTAG or SPI) */
|
||||
uint8_t spi_bpi; /*! SPI Only: Flash type (SPI or BPI) */
|
||||
jtag_pins_conf_t jtag_pins_config; /*! for bitbang, provide struct with pins value */
|
||||
spi_pins_conf_t spi_pins_config; /*! for SPI, provide struct with pins value */
|
||||
uint32_t default_freq; /* Default clock speed: 0 = use cable default */
|
||||
|
|
@ -92,195 +98,196 @@ typedef struct {
|
|||
#define CABLE_DEFAULT 0
|
||||
#define CABLE_MHZ(_m) ((_m) * 1000000)
|
||||
|
||||
#define JTAG_BOARD(_name, _fpga_part, _cable, _rst, _done, _freq) \
|
||||
{_name, {"", _cable, _fpga_part, _rst, _done, 0, COMM_JTAG, {}, {}, _freq, 0, 0, -1}}
|
||||
#define JTAG_BITBANG_BOARD(_name, _fpga_part, _cable, _rst, _done, _tms, _tck, _tdi, _tdo, _freq) \
|
||||
{_name, {"", _cable, _fpga_part, _rst, _done, 0, COMM_JTAG, { _tms, _tck, _tdi, _tdo, 0, 0 }, {}, \
|
||||
#define JTAG_BOARD(_name, _fpga_part, _cable, _spi_bpi, _rst, _done, _freq) \
|
||||
{_name, {"", _cable, _fpga_part, _rst, _done, 0, COMM_JTAG, _spi_bpi, {}, {}, _freq, 0, 0, -1}}
|
||||
#define JTAG_BITBANG_BOARD(_name, _fpga_part, _cable, _spi_bpi, _rst, _done, _tms, _tck, _tdi, _tdo, _freq) \
|
||||
{_name, {"", _cable, _fpga_part, _rst, _done, 0, COMM_JTAG, _spi_bpi, { _tms, _tck, _tdi, _tdo, 0, 0 }, {}, \
|
||||
_freq, 0, 0, -1}}
|
||||
#define SPI_BOARD(_name, _manufacturer, _fpga_part, _cable, _rst, _done, _oe, _cs, _sck, _si, _so, _holdn, _wpn, _freq) \
|
||||
{_name, {_manufacturer, _cable, _fpga_part, _rst, _done, _oe, COMM_SPI, {}, \
|
||||
{_name, {_manufacturer, _cable, _fpga_part, _rst, _done, _oe, COMM_SPI, SPI_FLASH, {}, \
|
||||
{_cs, _sck, _so, _si, _holdn, _wpn}, _freq, 0, 0, -1}}
|
||||
#define DFU_BOARD(_name, _fpga_part, _cable, _vid, _pid, _alt) \
|
||||
{_name, {"", _cable, _fpga_part, 0, 0, 0, COMM_DFU, {}, {}, 0, _vid, _pid, _alt}}
|
||||
{_name, {"", _cable, _fpga_part, 0, 0, 0, COMM_DFU, SPI_FLASH, {}, {}, 0, _vid, _pid, _alt}}
|
||||
|
||||
static std::map <std::string, target_board_t> board_list = {
|
||||
JTAG_BOARD("ac701", "xc7a200tfbg676", "digilent", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("acornCle215", "xc7a200tsbg484", "", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("analogMax", "", "ft2232", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("litex-acorn-baseboard-mini", "xc7a200tsbg484", "", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("alchitry_au", "xc7a35tftg256", "ft2232", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("alchitry_au_plus","xc7a100tftg256", "ft2232", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("alinx_ax516", "xc6slx16csg324", "", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("alinx_ax7101", "xc7a100tfgg484", "", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("alinx_ax7102", "xc7a100tfgg484", "", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("alinx_ax7201", "xc7a200tfbg484", "", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("alinx_ax7203", "xc7a200tfbg484", "", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("antmicro_ddr4_tester", "xc7k160tffg676", "ft4232", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("antmicro_ddr5_tester", "xc7k160tffg676", "ft4232", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("antmicro_lpddr4_tester", "xc7k70tfbg484", "ft4232", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("anvyl", "xc6slx45csg484", "digilent", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("ac701", "xc7a200tfbg676", "digilent", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("acornCle215", "xc7a200tsbg484", "", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("analogMax", "", "ft2232", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("litex-acorn-baseboard-mini", "xc7a200tsbg484", "", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("alchitry_au", "xc7a35tftg256", "ft2232", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("alchitry_au_plus","xc7a100tftg256", "ft2232", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("alinx_ax516", "xc6slx16csg324", "", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("alinx_ax7101", "xc7a100tfgg484", "", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("alinx_ax7102", "xc7a100tfgg484", "", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("alinx_ax7201", "xc7a200tfbg484", "", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("alinx_ax7203", "xc7a200tfbg484", "", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("antmicro_ddr4_tester", "xc7k160tffg676", "ft4232", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("antmicro_ddr5_tester", "xc7k160tffg676", "ft4232", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("antmicro_lpddr4_tester", "xc7k70tfbg484", "ft4232", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("anvyl", "xc6slx45csg484", "digilent", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
/* left for backward compatibility, use right name instead */
|
||||
JTAG_BOARD("arty", "xc7a35tcsg324", "digilent", 0, 0, CABLE_MHZ(10)),
|
||||
JTAG_BOARD("arty_a7_35t", "xc7a35tcsg324", "digilent", 0, 0, CABLE_MHZ(10)),
|
||||
JTAG_BOARD("arty_a7_100t", "xc7a100tcsg324", "digilent", 0, 0, CABLE_MHZ(10)),
|
||||
JTAG_BOARD("arty_s7_25", "xc7s25csga324", "digilent", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("arty_s7_50", "xc7s50csga324", "digilent", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("arty_z7_10", "xc7z010clg400", "digilent", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("arty_z7_20", "xc7z020clg400", "digilent", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("axu2cga", "xczu2cg", "", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("basys3", "xc7a35tcpg236", "digilent", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("c5g", "", "usb-blaster",0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("cmod_s7", "xc7s25csga225", "digilent", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("cmoda7_15t", "xc7a15tcpg236", "digilent", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("cmoda7_35t", "xc7a35tcpg236", "digilent", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("colorlight", "", "", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("colorlight-i5", "", "cmsisdap", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("colorlight-i9", "", "cmsisdap", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("colorlight-i9+", "xc7a50tfgg484", "", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("crosslinknx_evn", "", "ft2232", 0, 0, CABLE_MHZ(1)),
|
||||
JTAG_BOARD("certusnx_versa_evn", "", "ft2232", 0, 0, CABLE_MHZ(1)),
|
||||
JTAG_BOARD("certuspronx_evn", "", "ft2232", 0, 0, CABLE_MHZ(1)),
|
||||
JTAG_BOARD("certuspronx_versa_evn", "", "ft2232", 0, 0, CABLE_MHZ(1)),
|
||||
JTAG_BOARD("cyc1000", "10cl025256", "ft2232", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("cyc5000", "5ce215", "ft2232", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("c10lp-refkit", "10cl055484", "ft2232", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("de0", "", "usb-blaster",0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("de0nano", "ep4ce2217", "usb-blaster",0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("de0nanoSoc", "", "usb-blasterII",0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("de10lite", "", "usb-blaster",0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("de10nano", "", "usb-blasterII",0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("de1Soc", "5CSEMA5", "usb-blasterII",0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("deca", "10M50DA", "usb-blasterII",0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("dragonL", "xc6slx25tcsg324", "", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("ecp5_evn", "", "ft2232", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("arty", "xc7a35tcsg324", "digilent", SPI_FLASH, 0, 0, CABLE_MHZ(10)),
|
||||
JTAG_BOARD("arty_a7_35t", "xc7a35tcsg324", "digilent", SPI_FLASH, 0, 0, CABLE_MHZ(10)),
|
||||
JTAG_BOARD("arty_a7_100t", "xc7a100tcsg324", "digilent", SPI_FLASH, 0, 0, CABLE_MHZ(10)),
|
||||
JTAG_BOARD("arty_s7_25", "xc7s25csga324", "digilent", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("arty_s7_50", "xc7s50csga324", "digilent", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("arty_z7_10", "xc7z010clg400", "digilent", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("arty_z7_20", "xc7z020clg400", "digilent", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("axu2cga", "xczu2cg", "", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("basys3", "xc7a35tcpg236", "digilent", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("c5g", "", "usb-blaster", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("cmod_s7", "xc7s25csga225", "digilent", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("cmoda7_15t", "xc7a15tcpg236", "digilent", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("cmoda7_35t", "xc7a35tcpg236", "digilent", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("colorlight", "", "", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("colorlight-i5", "", "cmsisdap", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("colorlight-i9", "", "cmsisdap", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("colorlight-i9+", "xc7a50tfgg484", "", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("crosslinknx_evn", "", "ft2232", SPI_FLASH, 0, 0, CABLE_MHZ(1)),
|
||||
JTAG_BOARD("certusnx_versa_evn", "", "ft2232", SPI_FLASH, 0, 0, CABLE_MHZ(1)),
|
||||
JTAG_BOARD("certuspronx_evn", "", "ft2232", SPI_FLASH, 0, 0, CABLE_MHZ(1)),
|
||||
JTAG_BOARD("certuspronx_versa_evn", "", "ft2232", SPI_FLASH, 0, 0, CABLE_MHZ(1)),
|
||||
JTAG_BOARD("cyc1000", "10cl025256", "ft2232", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("cyc5000", "5ce215", "ft2232", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("c10lp-refkit", "10cl055484", "ft2232", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("de0", "", "usb-blaster", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("de0nano", "ep4ce2217", "usb-blaster", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("de0nanoSoc", "", "usb-blasterII", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("de10lite", "", "usb-blaster", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("de10nano", "", "usb-blasterII", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("de1Soc", "5CSEMA5", "usb-blasterII", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("deca", "10M50DA", "usb-blasterII", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("dragonL", "xc6slx25tcsg324", "", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("ecp5_evn", "", "ft2232", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
SPI_BOARD("ecp5_generic", "lattice", "ecp5", "",
|
||||
0, 0, 0,
|
||||
DBUS3, DBUS0, DBUS1, DBUS2,
|
||||
0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("ecpix5", "", "ecpix5-debug", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("ecpix5_r03", "", "ft4232", 0, 0, CABLE_DEFAULT),
|
||||
SPI_BOARD("fireant", "efinix", "trion", "ft232",
|
||||
JTAG_BOARD("ecpix5", "", "ecpix5-debug", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("ecpix5_r03", "", "ft4232", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
SPI_BOARD("fireant", "efinix", "trion", "ft232",
|
||||
DBUS4, DBUS5, 0, DBUS3, DBUS0, DBUS1, DBUS2, DBUS6, 0, CABLE_DEFAULT),
|
||||
DFU_BOARD("fomu", "", "dfu", 0x1209, 0x5bf0, 0),
|
||||
SPI_BOARD("ft2232_spi", "none", "none", "ft2232",
|
||||
DBUS7, DBUS6, 0,
|
||||
DBUS4, DBUS0, DBUS1, DBUS2,
|
||||
0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("gcm_jtag", "none", "ft4232", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("gcm_jtag", "none", "ft4232", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
SPI_BOARD("gcm_bootflash", "none", "none", "ft4232_b",
|
||||
0, 0, 0,
|
||||
DBUS3, DBUS0, DBUS1, DBUS2,
|
||||
0, 0, CABLE_DEFAULT),
|
||||
SPI_BOARD("gatemate_pgm_spi", "colognechip", "GM1Ax", "gatemate_pgm",
|
||||
SPI_BOARD("gatemate_pgm_spi", "colognechip", "GM1Ax", "gatemate_pgm",
|
||||
DBUS4, DBUS5, CBUS0, DBUS3, DBUS0, DBUS1, DBUS2, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("gatemate_evb_jtag", "", "gatemate_evb_jtag", 0, 0, CABLE_DEFAULT),
|
||||
SPI_BOARD("gatemate_evb_spi", "colognechip", "GM1Ax", "gatemate_evb_spi",
|
||||
JTAG_BOARD("gatemate_evb_jtag", "", "gatemate_evb_jtag", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
SPI_BOARD("gatemate_evb_spi", "colognechip", "GM1Ax", "gatemate_evb_spi",
|
||||
DBUS4, DBUS5, CBUS0, DBUS3, DBUS0, DBUS1, DBUS2, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("genesys2", "xc7k325tffg900", "digilent_b", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("gr740-mini", "", "ft4232hp_b", 0, 0, CABLE_MHZ(1)),
|
||||
JTAG_BOARD("hseda-xc6slx16", "xc6slx16ftg256", "", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("hyvision_opt01", "xc7k70tfbg676", "", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("genesys2", "xc7k325tffg900", "digilent_b", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("gr740-mini", "", "ft4232hp_b", SPI_FLASH, 0, 0, CABLE_MHZ(1)),
|
||||
JTAG_BOARD("hseda-xc6slx16", "xc6slx16ftg256", "", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("hyvision_opt01", "xc7k70tfbg676", "", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
/* most ice40 boards uses the same pinout */
|
||||
SPI_BOARD("ice40_generic", "lattice", "ice40", "ft2232",
|
||||
DBUS7, DBUS6, 0,
|
||||
DBUS4, DBUS0, DBUS1, DBUS2,
|
||||
0, 0, CABLE_DEFAULT),
|
||||
DFU_BOARD("icebreaker-bitsy", "", "dfu", 0x1d50, 0x6146, 0),
|
||||
JTAG_BITBANG_BOARD("icepi-zero", "", "ft231X", 0, 0,
|
||||
JTAG_BITBANG_BOARD("icepi-zero", "", "ft231X", SPI_FLASH, 0, 0,
|
||||
FT232RL_DCD, FT232RL_DSR, FT232RL_RI, FT232RL_CTS, CABLE_DEFAULT),
|
||||
JTAG_BOARD("kc705", "", "digilent", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("kcu105", "xcku040-ffva1156", "jtag-smt2-nc", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("kcu116", "xcku5p-ffvb676", "jtag-smt2-nc", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("LD-SCHOKO", "LFE5U-45F-6CABGA256", "", 0, 0, CABLE_MHZ(6)),
|
||||
DFU_BOARD("LD-SCHOKO-DFU", "", "dfu", 0x16d0, 0x116d, 0),
|
||||
JTAG_BOARD("LD-KONFEKT", "LFE5U-12F-6BG256C", "", 0, 0, CABLE_MHZ(6)),
|
||||
DFU_BOARD("LD-KONFEKT-DFU", "", "dfu", 0x16d0, 0x116d, 0),
|
||||
JTAG_BOARD("licheeTang", "", "anlogicCable", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("lilygo-t-fpga", "", "gwu2x", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("kc705", "", "digilent", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("kcu105", "xcku040-ffva1156", "jtag-smt2-nc", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("kcu116", "xcku5p-ffvb676", "jtag-smt2-nc", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("LD-SCHOKO", "LFE5U-45F-6CABGA256", "", SPI_FLASH, 0, 0, CABLE_MHZ(6)),
|
||||
DFU_BOARD("LD-SCHOKO-DFU", "", "dfu", 0x16d0, 0x116d, 0),
|
||||
JTAG_BOARD("LD-KONFEKT", "LFE5U-12F-6BG256C", "", SPI_FLASH, 0, 0, CABLE_MHZ(6)),
|
||||
DFU_BOARD("LD-KONFEKT-DFU", "", "dfu", 0x16d0, 0x116d, 0),
|
||||
JTAG_BOARD("licheeTang", "", "anlogicCable", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("lilygo-t-fpga", "", "gwu2x", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
/* left for backward compatibility, use tec0117 instead */
|
||||
JTAG_BOARD("littleBee", "", "ft2232", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("machXO2EVN", "", "ft2232", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("machXO3SK", "", "ft2232", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("machXO3EVN", "", "ft2232", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("mlk-s200-eg4d20", "", "anlogicCable", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("mimas_a7", "xc7a50tfgg484", "numato", 0, 0, CABLE_MHZ(30)),
|
||||
JTAG_BOARD("neso_a7", "xc7a100tcsg324", "numato-neso", 0, 0, CABLE_MHZ(30)),
|
||||
JTAG_BOARD("minispartan6", "", "ft2232", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("nexys_a7_50", "xc7a50tcsg324", "digilent", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("nexys_a7_100", "xc7a100tcsg324", "digilent", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("nexysVideo", "xc7a200tsbg484", "digilent_b", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("olimex_gatemateevb", "GM1A1", "dirtyJtag", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("opensourceSDRLabKintex7", "xc7k325tffg676", "ft232", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("littleBee", "", "ft2232", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("machXO2EVN", "", "ft2232", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("machXO3SK", "", "ft2232", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("machXO3EVN", "", "ft2232", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("mlk-s200-eg4d20", "", "anlogicCable", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("mimas_a7", "xc7a50tfgg484", "numato", SPI_FLASH, 0, 0, CABLE_MHZ(30)),
|
||||
JTAG_BOARD("neso_a7", "xc7a100tcsg324", "numato-neso", SPI_FLASH, 0, 0, CABLE_MHZ(30)),
|
||||
JTAG_BOARD("minispartan6", "", "ft2232", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("nexys_a7_50", "xc7a50tcsg324", "digilent", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("nexys_a7_100", "xc7a100tcsg324", "digilent", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("nexysVideo", "xc7a200tsbg484", "digilent_b", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("olimex_gatemateevb", "GM1A1", "dirtyJtag", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("opensourceSDRLabKintex7", "xc7k325tffg676", "ft232", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
DFU_BOARD("orangeCrab", "", "dfu", 0x1209, 0x5af0, 0),
|
||||
DFU_BOARD("orbtrace_dfu", "", "dfu", 0x1209, 0x3442, 1),
|
||||
JTAG_BOARD("papilio_one", "xc3s500evq100", "papilio", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("pipistrello", "xc6slx45csg324", "ft2232", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("pynq_z1", "xc7z020clg400", "ft2232", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("pynq_z2", "xc7z020clg400", "ft2232", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("qmtechCyclone10", "10cl016484", "", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("qmtechCycloneIVGX", "ep4cgx15027", "", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("qmtechCycloneIV", "ep4ce1523", "", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("qmtechCycloneV", "5ce223", "", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("qmtechCycloneV_5ce523", "5ce523", "", 0,0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("qmtechKintex7", "xc7k325tffg676", "", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("redpitaya14", "xc7z010clg400", "", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("runber", "", "ft232", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("spartanEdgeAccelBoard", "", "",0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("spec45", "xc6slx45tfgg484", "", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("spec150", "xc6slx150tfgg484", "", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("stlv7325", "xc7k325tffg676", "ft4232", 0, 0, CABLE_MHZ(3)),
|
||||
JTAG_BOARD("tangconsole", "", "ft2232", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("tangnano", "", "ch552_jtag", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("tangnano1k", "", "ft2232", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("tangnano4k", "", "ft2232", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("tangnano9k", "", "ft2232", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("tangnano20k", "", "ft2232", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("tangprimer20k", "", "ft2232", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("tangprimer25k", "", "ft2232", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("tangmega138k", "", "ft2232", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("te0712_8", "xc7a200tfbg484", "", 0, 0, CABLE_MHZ(15)),
|
||||
JTAG_BOARD("tec0117", "", "ft2232", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("tec0330", "xc7vx330tffg1157", "", 0, 0, CABLE_MHZ(15)),
|
||||
JTAG_BOARD("papilio_one", "xc3s500evq100", "papilio", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("pipistrello", "xc6slx45csg324", "ft2232", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("pynq_z1", "xc7z020clg400", "ft2232", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("pynq_z2", "xc7z020clg400", "ft2232", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("qmtechCyclone10", "10cl016484", "", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("qmtechCycloneIVGX", "ep4cgx15027", "", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("qmtechCycloneIV", "ep4ce1523", "", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("qmtechCycloneV", "5ce223", "", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("qmtechCycloneV_5ce523", "5ce523", "", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("qmtechKintex7", "xc7k325tffg676", "", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("redpitaya14", "xc7z010clg400", "", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("runber", "", "ft232", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("spartanEdgeAccelBoard", "", "", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("spec45", "xc6slx45tfgg484", "", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("spec150", "xc6slx150tfgg484", "", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("stlv7325", "xc7k325tffg676", "ft4232", SPI_FLASH, 0, 0, CABLE_MHZ(3)),
|
||||
JTAG_BOARD("tangconsole", "", "ft2232", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("tangnano", "", "ch552_jtag", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("tangnano1k", "", "ft2232", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("tangnano4k", "", "ft2232", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("tangnano9k", "", "ft2232", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("tangnano20k", "", "ft2232", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("tangprimer20k", "", "ft2232", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("tangprimer25k", "", "ft2232", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("tangmega138k", "", "ft2232", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("te0712_8", "xc7a200tfbg484", "", SPI_FLASH, 0, 0, CABLE_MHZ(15)),
|
||||
JTAG_BOARD("tec0117", "", "ft2232", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("tec0330", "xc7vx330tffg1157", "", SPI_FLASH, 0, 0, CABLE_MHZ(15)),
|
||||
SPI_BOARD("titanium_ti60_f225","efinix", "titanium", "efinix_spi_ft4232",
|
||||
DBUS4, DBUS5, DBUS7, DBUS3, DBUS0, DBUS1, DBUS2, DBUS6, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("titanium_ti60_f225_jtag", "ti60f225","efinix_jtag_ft4232", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("titanium_ti60_f225_jtag", "ti60f225","efinix_jtag_ft4232", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
SPI_BOARD("trion_t20_bga256", "efinix", "trion", "efinix_spi_ft2232",
|
||||
DBUS4, DBUS5, 0, DBUS3, DBUS0, DBUS1, DBUS2, DBUS6, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("trion_t20_bga256_jtag", "t20f256", "efinix_jtag_ft2232", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("trion_t20_bga256_jtag", "t20f256", "efinix_jtag_ft2232", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
SPI_BOARD("trion_t120_bga576", "efinix", "trion", "efinix_spi_ft2232",
|
||||
DBUS4, DBUS5, DBUS7, DBUS3, DBUS0, DBUS1, DBUS2, DBUS6, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("trion_t120_bga576_jtag", "", "ft2232_b", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BITBANG_BOARD("ulx2s", "", "ft232RL", 0, 0,
|
||||
JTAG_BOARD("trion_t120_bga576_jtag", "", "ft2232_b", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BITBANG_BOARD("ulx2s", "", "ft232RL", SPI_FLASH, 0, 0,
|
||||
FT232RL_RI, FT232RL_DSR, FT232RL_CTS, FT232RL_DCD, CABLE_DEFAULT),
|
||||
JTAG_BITBANG_BOARD("ulx3s", "", "ft231X", 0, 0,
|
||||
JTAG_BITBANG_BOARD("ulx3s", "", "ft231X", SPI_FLASH, 0, 0,
|
||||
FT232RL_DCD, FT232RL_DSR, FT232RL_RI, FT232RL_CTS, CABLE_DEFAULT),
|
||||
DFU_BOARD("ulx3s_dfu", "", "dfu", 0x1d50, 0x614b, 0),
|
||||
JTAG_BOARD("ulx3s_esp", "", "esp32s3", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("ulx3s_esp", "", "esp32s3", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
DFU_BOARD("ulx4m_dfu", "", "dfu", 0x1d50, 0x614b, 0),
|
||||
JTAG_BOARD("usrpx300", "xc7k325tffg900", "digilent", 0, 0, CABLE_MHZ(15)),
|
||||
JTAG_BOARD("usrpx310", "xc7k410tffg900", "digilent", 0, 0, CABLE_MHZ(15)),
|
||||
JTAG_BOARD("vec_v6", "xc6vlx130tff784", "ft2232", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("vc709", "xc7vx690tffg1761", "digilent", 0, 0, CABLE_MHZ(15)),
|
||||
JTAG_BOARD("vcu108", "xcvu095-ffva2104", "jtag-smt2-nc", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("vcu118", "xcvu9p-flga2104", "jtag-smt2-nc", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("vcu128", "xcvu37p-fsvh2892", "ft4232", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("vcu1525", "xcvu9p-fsgd2104", "ft4232", 0, 0, CABLE_MHZ(15)),
|
||||
JTAG_BOARD("xem8320", "xcau25p-2ffvb676", "" , 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("xyloni_jtag", "t8f81", "efinix_jtag_ft4232", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("usrpx300", "xc7k325tffg900", "digilent", SPI_FLASH, 0, 0, CABLE_MHZ(15)),
|
||||
JTAG_BOARD("usrpx310", "xc7k410tffg900", "digilent", SPI_FLASH, 0, 0, CABLE_MHZ(15)),
|
||||
JTAG_BOARD("vec_v6", "xc6vlx130tff784", "ft2232", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("vc709", "xc7vx690tffg1761", "digilent", SPI_FLASH, 0, 0, CABLE_MHZ(15)),
|
||||
JTAG_BOARD("vcu108", "xcvu095-ffva2104", "jtag-smt2-nc", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("vcu118", "xcvu9p-flga2104", "jtag-smt2-nc", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("vcu128", "xcvu37p-fsvh2892", "ft4232", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("vcu1525", "xcvu9p-fsgd2104", "ft4232", SPI_FLASH, 0, 0, CABLE_MHZ(15)),
|
||||
JTAG_BOARD("xem8320", "xcau25p-2ffvb676", "" , SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("xyloni_jtag", "t8f81", "efinix_jtag_ft4232", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
SPI_BOARD("xyloni_spi", "efinix", "trion", "efinix_spi_ft4232",
|
||||
DBUS4, DBUS5, DBUS7, DBUS3, DBUS0, DBUS1, DBUS2, DBUS6, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("xtrx", "xc7a50tcpg236", "" , 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("zc702", "xc7z020clg484", "digilent", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("zc706", "xc7z045ffg900", "jtag-smt2-nc", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("zcu102", "xczu9egffvb1156", "jtag-smt2-nc", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("zcu106", "xczu7evffvc1156", "jtag-smt2-nc", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("zedboard", "xc7z020clg484", "digilent_hs2", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("zybo_z7_10", "xc7z010clg400", "digilent", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("zybo_z7_20", "xc7z020clg400", "digilent", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("mini_itx", "xc7z100ffg900", "jtag-smt2-nc", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("vmm3", "xc7s50csga324", "ft2232", 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("step-max10_v1", "10m02scm153c8g", "usb-blaster",0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("step-mxo2_v2", "lcmxo2-4000hc-4mg132cc", "ft232",0, 0, CABLE_DEFAULT)
|
||||
JTAG_BOARD("xtrx", "xc7a50tcpg236", "", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("ypcb003381p1", "xc7k480tffg1156", "", BPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("zc702", "xc7z020clg484", "digilent", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("zc706", "xc7z045ffg900", "jtag-smt2-nc", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("zcu102", "xczu9egffvb1156", "jtag-smt2-nc", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("zcu106", "xczu7evffvc1156", "jtag-smt2-nc", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("zedboard", "xc7z020clg484", "digilent_hs2", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("zybo_z7_10", "xc7z010clg400", "digilent", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("zybo_z7_20", "xc7z020clg400", "digilent", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("mini_itx", "xc7z100ffg900", "jtag-smt2-nc", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("vmm3", "xc7s50csga324", "ft2232", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("step-max10_v1", "10m02scm153c8g", "usb-blaster", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
JTAG_BOARD("step-mxo2_v2", "lcmxo2-4000hc-4mg132cc", "ft232", SPI_FLASH, 0, 0, CABLE_DEFAULT)
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -0,0 +1,583 @@
|
|||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
* Copyright (C) 2024 openFPGALoader contributors
|
||||
* BPI (Parallel NOR) Flash support via JTAG bridge
|
||||
*/
|
||||
|
||||
#include "bpiFlash.hpp"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
|
||||
#include "display.hpp"
|
||||
#include "progressBar.hpp"
|
||||
|
||||
/* Bit-reverse a byte (MSB <-> LSB).
|
||||
* Required for BPI x16: the FPGA's D00 pin is the MSBit of each config byte
|
||||
* (AR#7112), but flash DQ[0] is the LSBit. write_cfgmem applies this
|
||||
* transformation; we must do the same.
|
||||
*/
|
||||
static inline uint8_t reverseByte(uint8_t b)
|
||||
{
|
||||
b = ((b & 0xF0) >> 4) | ((b & 0x0F) << 4);
|
||||
b = ((b & 0xCC) >> 2) | ((b & 0x33) << 2);
|
||||
b = ((b & 0xAA) >> 1) | ((b & 0x55) << 1);
|
||||
return b;
|
||||
}
|
||||
|
||||
BPIFlash::BPIFlash(Jtag *jtag, int8_t verbose)
|
||||
: _jtag(jtag), _verbose(verbose), _irlen(6),
|
||||
_capacity(0), _block_size(256 * 1024),
|
||||
_manufacturer_id(0), _device_id(0),
|
||||
_has_burst(false)
|
||||
{
|
||||
}
|
||||
|
||||
BPIFlash::~BPIFlash()
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* Protocol: Single JTAG DR shift containing:
|
||||
* TX: [start=1][cmd:4][addr:25][wr_data:16] = 46 bits
|
||||
* RX: Data returned after execution delay
|
||||
*
|
||||
* Commands:
|
||||
* 0x1 = Write word
|
||||
* 0x2 = Read word
|
||||
* 0x3 = NOP
|
||||
* 0x4 = Burst write (addr + count + N×data words)
|
||||
*/
|
||||
|
||||
uint16_t BPIFlash::bpi_read(uint32_t word_addr)
|
||||
{
|
||||
/* Build packet: start(1) + cmd(4) + addr(25) + padding for read response */
|
||||
/* Extra bit needed due to pipeline delay in Verilog (data at offset 51, not 50) */
|
||||
const int total_bits = 1 + 4 + 25 + 20 + 16 + 1; /* 67 bits total */
|
||||
const int total_bytes = (total_bits + 7) / 8;
|
||||
|
||||
uint8_t tx[total_bytes];
|
||||
uint8_t rx[total_bytes];
|
||||
memset(tx, 0, total_bytes);
|
||||
memset(rx, 0, total_bytes);
|
||||
|
||||
/* Pack: start=1, cmd=2 (read), addr (LSB first) */
|
||||
uint64_t packet = 1; /* start bit */
|
||||
packet |= ((uint64_t)CMD_READ) << 1; /* cmd at bits [4:1] */
|
||||
packet |= ((uint64_t)(word_addr & 0x1FFFFFF)) << 5; /* addr at bits [29:5] */
|
||||
|
||||
/* Convert to bytes (LSB first for JTAG) */
|
||||
for (int i = 0; i < 5; i++) {
|
||||
tx[i] = (packet >> (i * 8)) & 0xFF;
|
||||
}
|
||||
|
||||
/* Select USER1 instruction */
|
||||
uint8_t user1[] = {0x02};
|
||||
_jtag->shiftIR(user1, NULL, _irlen);
|
||||
|
||||
/* Shift data and get response */
|
||||
_jtag->shiftDR(tx, rx, total_bits);
|
||||
_jtag->flush();
|
||||
|
||||
/* Extract read data from response - it appears after the command execution */
|
||||
/* Data starts at bit 51 (after start+cmd+addr+exec_delay+1 pipeline delay) */
|
||||
int data_offset = 51;
|
||||
uint16_t data = 0;
|
||||
for (int i = 0; i < 16; i++) {
|
||||
int bit_pos = data_offset + i;
|
||||
int byte_idx = bit_pos / 8;
|
||||
int bit_idx = bit_pos % 8;
|
||||
if (rx[byte_idx] & (1 << bit_idx))
|
||||
data |= (1 << i);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
void BPIFlash::bpi_write(uint32_t word_addr, uint16_t data)
|
||||
{
|
||||
/* Build packet: start(1) + cmd(4) + addr(25) + data(16) + exec delay */
|
||||
const int total_bits = 1 + 4 + 25 + 16 + 20;
|
||||
const int total_bytes = (total_bits + 7) / 8;
|
||||
|
||||
uint8_t tx[total_bytes];
|
||||
memset(tx, 0, total_bytes);
|
||||
|
||||
/* Pack: start=1, cmd=1 (write), addr, data (all LSB first) */
|
||||
uint64_t packet = 1; /* start bit */
|
||||
packet |= ((uint64_t)CMD_WRITE) << 1; /* cmd at bits [4:1] */
|
||||
packet |= ((uint64_t)(word_addr & 0x1FFFFFF)) << 5; /* addr at bits [29:5] */
|
||||
packet |= ((uint64_t)data) << 30; /* data at bits [45:30] */
|
||||
|
||||
/* Convert to bytes (LSB first for JTAG) */
|
||||
for (int i = 0; i < 8; i++) {
|
||||
tx[i] = (packet >> (i * 8)) & 0xFF;
|
||||
}
|
||||
|
||||
if (_verbose > 1) {
|
||||
char buf[256];
|
||||
snprintf(buf, sizeof(buf), "bpi_write(0x%06x, 0x%04x) TX:", word_addr, data);
|
||||
std::string msg = buf;
|
||||
for (int i = 0; i < total_bytes; i++) {
|
||||
snprintf(buf, sizeof(buf), " %02x", tx[i]);
|
||||
msg += buf;
|
||||
}
|
||||
printInfo(msg);
|
||||
}
|
||||
|
||||
/* Select USER1 instruction */
|
||||
uint8_t user1[] = {0x02};
|
||||
_jtag->shiftIR(user1, NULL, _irlen);
|
||||
|
||||
/* Shift data */
|
||||
_jtag->shiftDR(tx, NULL, total_bits);
|
||||
_jtag->flush();
|
||||
}
|
||||
|
||||
void BPIFlash::bpi_write_no_flush(uint32_t word_addr, uint16_t data)
|
||||
{
|
||||
/* Same packet as bpi_write() but no shiftIR or flush —
|
||||
* caller sets IR once before the loop and flushes once after.
|
||||
*/
|
||||
const int total_bits = 1 + 4 + 25 + 16 + 20;
|
||||
const int total_bytes = (total_bits + 7) / 8;
|
||||
|
||||
uint8_t tx[total_bytes];
|
||||
memset(tx, 0, total_bytes);
|
||||
|
||||
uint64_t packet = 1; /* start bit */
|
||||
packet |= ((uint64_t)CMD_WRITE) << 1; /* cmd at bits [4:1] */
|
||||
packet |= ((uint64_t)(word_addr & 0x1FFFFFF)) << 5; /* addr at bits [29:5] */
|
||||
packet |= ((uint64_t)data) << 30; /* data at bits [45:30] */
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
tx[i] = (packet >> (i * 8)) & 0xFF;
|
||||
}
|
||||
|
||||
_jtag->shiftDR(tx, NULL, total_bits);
|
||||
}
|
||||
|
||||
void BPIFlash::bpi_burst_write(uint32_t word_addr, const uint16_t *data,
|
||||
uint32_t count)
|
||||
{
|
||||
if (count == 0)
|
||||
return;
|
||||
|
||||
/* Burst packet: start(1) + cmd(4) + addr(25) + count(16) + N×(data(16) + pad(21))
|
||||
* Header: 46 bits. Per word: 37 bits.
|
||||
*/
|
||||
const uint32_t header_bits = 1 + 4 + 25 + 16; /* 46 */
|
||||
const uint32_t per_word_bits = 16 + 21; /* 37: 20 exec cycles + 1 transition */
|
||||
const uint32_t total_bits = header_bits + count * per_word_bits;
|
||||
const uint32_t total_bytes = (total_bits + 7) / 8;
|
||||
|
||||
std::vector<uint8_t> tx(total_bytes, 0);
|
||||
|
||||
/* Helper to set a single bit in the tx buffer */
|
||||
auto set_bit = [&](uint32_t bit_pos) {
|
||||
tx[bit_pos / 8] |= (1 << (bit_pos % 8));
|
||||
};
|
||||
|
||||
/* Pack header LSB-first */
|
||||
uint32_t pos = 0;
|
||||
|
||||
/* start bit = 1 */
|
||||
set_bit(pos);
|
||||
pos++;
|
||||
|
||||
/* cmd = CMD_BURST_WRITE (4 bits) */
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (CMD_BURST_WRITE & (1 << i))
|
||||
set_bit(pos);
|
||||
pos++;
|
||||
}
|
||||
|
||||
/* addr (25 bits) */
|
||||
for (int i = 0; i < 25; i++) {
|
||||
if (word_addr & (1u << i))
|
||||
set_bit(pos);
|
||||
pos++;
|
||||
}
|
||||
|
||||
/* count (16 bits) */
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (count & (1u << i))
|
||||
set_bit(pos);
|
||||
pos++;
|
||||
}
|
||||
|
||||
/* Pack each data word: 16 data bits + 21 padding bits */
|
||||
for (uint32_t w = 0; w < count; w++) {
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (data[w] & (1 << i))
|
||||
set_bit(pos);
|
||||
pos++;
|
||||
}
|
||||
pos += 21; /* 20 exec cycles + 1 transition cycle */
|
||||
}
|
||||
|
||||
uint8_t user1[] = {0x02};
|
||||
_jtag->shiftIR(user1, NULL, _irlen);
|
||||
_jtag->shiftDR(tx.data(), NULL, total_bits);
|
||||
_jtag->flush();
|
||||
}
|
||||
|
||||
bool BPIFlash::detect()
|
||||
{
|
||||
printInfo("Detecting BPI flash...");
|
||||
|
||||
/* Issue Read ID command to flash: write 0x0090 to any address */
|
||||
bpi_write(0, FLASH_CMD_READ_ID);
|
||||
|
||||
/* Small delay for command to take effect */
|
||||
usleep(1000);
|
||||
|
||||
/* Read manufacturer ID at offset 0x00 */
|
||||
_manufacturer_id = bpi_read(0x00);
|
||||
|
||||
/* Read device ID at offset 0x01 */
|
||||
_device_id = bpi_read(0x01);
|
||||
|
||||
/* Return to read array mode */
|
||||
bpi_write(0, FLASH_CMD_READ_ARRAY);
|
||||
usleep(1000);
|
||||
|
||||
if (_verbose) {
|
||||
char buf[64];
|
||||
snprintf(buf, sizeof(buf), "Raw Manufacturer ID: 0x%04x", _manufacturer_id);
|
||||
printInfo(buf);
|
||||
snprintf(buf, sizeof(buf), "Raw Device ID: 0x%04x", _device_id);
|
||||
printInfo(buf);
|
||||
}
|
||||
|
||||
if (_manufacturer_id == 0x0089 || _manufacturer_id == 0x8900) {
|
||||
printInfo("Intel/Micron flash detected");
|
||||
} else if (_manufacturer_id == 0x0020 || _manufacturer_id == 0x2000) {
|
||||
printInfo("Micron flash detected");
|
||||
} else if (_manufacturer_id == 0xFFFF || _manufacturer_id == 0x0000) {
|
||||
char buf[64];
|
||||
snprintf(buf, sizeof(buf), "No BPI flash detected (ID: 0x%04x)", _manufacturer_id);
|
||||
printError(buf);
|
||||
return false;
|
||||
} else {
|
||||
char buf[64];
|
||||
snprintf(buf, sizeof(buf), "Unknown manufacturer: 0x%04x", _manufacturer_id);
|
||||
printWarn(buf);
|
||||
}
|
||||
|
||||
{
|
||||
char buf[64];
|
||||
snprintf(buf, sizeof(buf), "Manufacturer ID: 0x%04x", _manufacturer_id);
|
||||
printInfo(buf);
|
||||
snprintf(buf, sizeof(buf), "Device ID: 0x%04x", _device_id);
|
||||
printInfo(buf);
|
||||
}
|
||||
|
||||
/* MT28GU512AAA = 512Mbit = 64MB */
|
||||
_capacity = 64 * 1024 * 1024;
|
||||
_block_size = 256 * 1024;
|
||||
printInfo("Flash capacity: 64 MB (512 Mbit)");
|
||||
|
||||
/* Enable burst write — assumes v02.00+ JTAG bitstream is loaded.
|
||||
* Future: could auto-detect via USER4 version readback.
|
||||
*/
|
||||
_has_burst = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BPIFlash::wait_ready(uint32_t timeout_ms)
|
||||
{
|
||||
uint32_t elapsed = 0;
|
||||
const uint32_t poll_interval = 10;
|
||||
|
||||
/* Issue read status command */
|
||||
bpi_write(0, FLASH_CMD_READ_STATUS);
|
||||
usleep(100);
|
||||
|
||||
while (elapsed < timeout_ms) {
|
||||
uint16_t status = bpi_read(0);
|
||||
|
||||
/* Intel CFI status register is 8 bits, upper byte undefined */
|
||||
uint8_t sr = status & 0xFF;
|
||||
|
||||
if (sr & SR_READY) {
|
||||
if (sr & (SR_ERASE_ERR | SR_PROG_ERR | SR_VPP_ERR)) {
|
||||
char buf[64];
|
||||
snprintf(buf, sizeof(buf), "BPI Flash error: status = 0x%02x", sr);
|
||||
printError(buf);
|
||||
bpi_write(0, FLASH_CMD_CLEAR_STATUS);
|
||||
return false;
|
||||
}
|
||||
/* Return to read array mode */
|
||||
bpi_write(0, FLASH_CMD_READ_ARRAY);
|
||||
return true;
|
||||
}
|
||||
|
||||
usleep(poll_interval * 1000);
|
||||
elapsed += poll_interval;
|
||||
}
|
||||
|
||||
printError("BPI Flash timeout");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BPIFlash::unlock_block(uint32_t word_addr)
|
||||
{
|
||||
bpi_write(word_addr, FLASH_CMD_UNLOCK_BLOCK);
|
||||
usleep(100);
|
||||
bpi_write(word_addr, FLASH_CMD_UNLOCK_CONF);
|
||||
usleep(100);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BPIFlash::erase_block(uint32_t addr)
|
||||
{
|
||||
uint32_t word_addr = addr >> 1;
|
||||
|
||||
if (_verbose) {
|
||||
char buf[64];
|
||||
snprintf(buf, sizeof(buf), "Erasing block at 0x%06x", addr);
|
||||
printInfo(buf);
|
||||
}
|
||||
|
||||
unlock_block(word_addr);
|
||||
|
||||
/* Block erase command sequence */
|
||||
bpi_write(word_addr, FLASH_CMD_BLOCK_ERASE);
|
||||
usleep(100);
|
||||
bpi_write(word_addr, FLASH_CMD_CONFIRM);
|
||||
|
||||
if (!wait_ready(30000)) {
|
||||
printError("Block erase failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Verify erase by reading first few words */
|
||||
if (_verbose) {
|
||||
/* Send READ_ARRAY to the erased block's address (not addr 0),
|
||||
* because multi-bank flash requires per-bank mode commands */
|
||||
bpi_write(word_addr, FLASH_CMD_READ_ARRAY);
|
||||
usleep(100);
|
||||
char buf[128];
|
||||
snprintf(buf, sizeof(buf), "Verify erase at 0x%06x:", addr);
|
||||
printInfo(buf);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
uint16_t val = bpi_read(word_addr + i);
|
||||
snprintf(buf, sizeof(buf), " [0x%06x] = 0x%04x %s",
|
||||
addr + i*2, val, (val == 0xFFFF) ? "(OK)" : "(NOT ERASED!)");
|
||||
printInfo(buf);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BPIFlash::bulk_erase()
|
||||
{
|
||||
printInfo("Bulk erasing BPI flash...");
|
||||
|
||||
uint32_t num_blocks = _capacity / _block_size;
|
||||
ProgressBar progress("Erasing", num_blocks, 50, _verbose > 0);
|
||||
|
||||
for (uint32_t i = 0; i < num_blocks; i++) {
|
||||
uint32_t block_addr = i * _block_size;
|
||||
if (!erase_block(block_addr)) {
|
||||
progress.fail();
|
||||
return false;
|
||||
}
|
||||
progress.display(i + 1);
|
||||
}
|
||||
|
||||
progress.done();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BPIFlash::read(uint8_t *data, uint32_t addr, uint32_t len)
|
||||
{
|
||||
if (_verbose)
|
||||
printInfo("Reading " + std::to_string(len) + " bytes from 0x" +
|
||||
std::to_string(addr));
|
||||
|
||||
/* Ensure read array mode */
|
||||
bpi_write(0, FLASH_CMD_READ_ARRAY);
|
||||
usleep(100);
|
||||
|
||||
ProgressBar progress("Reading", len, 50, _verbose > 0);
|
||||
|
||||
for (uint32_t i = 0; i < len; i += 2) {
|
||||
uint32_t word_addr = (addr + i) >> 1;
|
||||
uint16_t word = bpi_read(word_addr);
|
||||
|
||||
data[i] = reverseByte((word >> 8) & 0xFF);
|
||||
if (i + 1 < len)
|
||||
data[i + 1] = reverseByte(word & 0xFF);
|
||||
|
||||
if ((i & 0xFFF) == 0)
|
||||
progress.display(i);
|
||||
}
|
||||
|
||||
progress.done();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BPIFlash::write(uint32_t addr, const uint8_t *data, uint32_t len)
|
||||
{
|
||||
char buf[128];
|
||||
snprintf(buf, sizeof(buf), "Writing %u bytes to BPI flash at 0x%06x", len, addr);
|
||||
printInfo(buf);
|
||||
|
||||
/* Calculate blocks to erase */
|
||||
uint32_t start_block = addr / _block_size;
|
||||
uint32_t end_block = (addr + len - 1) / _block_size;
|
||||
|
||||
/* Erase required blocks */
|
||||
printInfo("Erasing " + std::to_string(end_block - start_block + 1) +
|
||||
" blocks...");
|
||||
for (uint32_t block = start_block; block <= end_block; block++) {
|
||||
if (!erase_block(block * _block_size)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Program data using buffered programming (0x00E9)
|
||||
* Sequence: Setup(0xE9) -> WordCount(N-1) -> N data words -> Confirm(0xD0)
|
||||
*/
|
||||
printInfo("Programming (buffered mode)...");
|
||||
ProgressBar progress("Writing", len, 50, _verbose > 0);
|
||||
|
||||
/* MT28GU512AAA has 1KB programming regions - must program entire region at once
|
||||
* to avoid object mode issues. Buffer size = 512 words = 1KB = one programming region.
|
||||
*/
|
||||
const uint32_t BUFFER_WORDS = 512; /* 512 words = 1KB = one programming region */
|
||||
const uint32_t BUFFER_BYTES = BUFFER_WORDS * 2;
|
||||
|
||||
uint32_t last_block = 0xFFFFFFFF; /* Track which block is unlocked */
|
||||
|
||||
uint32_t offset = 0;
|
||||
while (offset < len) {
|
||||
uint32_t byte_addr = addr + offset;
|
||||
uint32_t word_addr = byte_addr >> 1;
|
||||
|
||||
/* Calculate block address (word address of block start) */
|
||||
uint32_t block_word_addr = (byte_addr / _block_size) * (_block_size >> 1);
|
||||
|
||||
/* Unlock only when entering a new block */
|
||||
uint32_t current_block = byte_addr / _block_size;
|
||||
if (current_block != last_block) {
|
||||
unlock_block(block_word_addr);
|
||||
last_block = current_block;
|
||||
}
|
||||
|
||||
/* Calculate how many words to write in this buffer */
|
||||
uint32_t remaining_bytes = len - offset;
|
||||
uint32_t chunk_bytes = (remaining_bytes > BUFFER_BYTES) ? BUFFER_BYTES : remaining_bytes;
|
||||
uint32_t chunk_words = (chunk_bytes + 1) / 2;
|
||||
|
||||
/* Don't cross block boundaries */
|
||||
uint32_t bytes_to_block_end = _block_size - (byte_addr % _block_size);
|
||||
if (chunk_bytes > bytes_to_block_end)
|
||||
chunk_bytes = bytes_to_block_end;
|
||||
chunk_words = (chunk_bytes + 1) / 2;
|
||||
|
||||
if (_verbose > 1) {
|
||||
char buf[128];
|
||||
snprintf(buf, sizeof(buf), "Buffered write: addr=0x%06x, words=%u, block=0x%06x",
|
||||
byte_addr, chunk_words, block_word_addr << 1);
|
||||
printInfo(buf);
|
||||
}
|
||||
|
||||
/* Write data words for BPI x16 boot.
|
||||
* Two transformations (same as Vivado write_cfgmem -interface BPIx16):
|
||||
* 1. Bit reversal within each byte: FPGA D00=MSBit, flash DQ[0]=LSBit
|
||||
* 2. Byte swap: first bitstream byte → upper flash byte D[15:8]
|
||||
*/
|
||||
std::vector<uint16_t> word_buf(chunk_words);
|
||||
for (uint32_t w = 0; w < chunk_words; w++) {
|
||||
uint32_t data_offset = offset + w * 2;
|
||||
uint8_t b0 = data[data_offset];
|
||||
uint8_t b1 = 0xFF; /* pad with 0xFF if odd length */
|
||||
if (data_offset + 1 < len)
|
||||
b1 = data[data_offset + 1];
|
||||
word_buf[w] = (reverseByte(b0) << 8) | reverseByte(b1);
|
||||
}
|
||||
|
||||
/* Buffered Program Setup - sent to block/colony base address */
|
||||
bpi_write(0, FLASH_CMD_CLEAR_STATUS);
|
||||
bpi_write(block_word_addr, FLASH_CMD_BUFFERED_PRG);
|
||||
bpi_write(block_word_addr, chunk_words - 1);
|
||||
|
||||
if (_has_burst) {
|
||||
bpi_burst_write(word_addr, word_buf.data(), chunk_words);
|
||||
} else {
|
||||
/* Software-only fallback: one IR, no per-word flush */
|
||||
uint8_t user1[] = {0x02};
|
||||
_jtag->shiftIR(user1, NULL, _irlen);
|
||||
for (uint32_t w = 0; w < chunk_words; w++) {
|
||||
bpi_write_no_flush(word_addr + w, word_buf[w]);
|
||||
}
|
||||
_jtag->flush();
|
||||
}
|
||||
|
||||
/* Confirm - sent to block address */
|
||||
bpi_write(block_word_addr, FLASH_CMD_CONFIRM);
|
||||
|
||||
/* Wait for program to complete */
|
||||
if (!wait_ready(5000)) {
|
||||
char buf[64];
|
||||
snprintf(buf, sizeof(buf), "Buffered program failed at address 0x%06x", byte_addr);
|
||||
printError(buf);
|
||||
progress.fail();
|
||||
return false;
|
||||
}
|
||||
|
||||
offset += chunk_words * 2;
|
||||
|
||||
if ((offset & 0xFFF) == 0 || offset >= len)
|
||||
progress.display(offset);
|
||||
}
|
||||
|
||||
/* Return to read array mode */
|
||||
bpi_write(0, FLASH_CMD_READ_ARRAY);
|
||||
|
||||
progress.done();
|
||||
|
||||
/* Verify first 32 words */
|
||||
printInfo("Verifying first 32 words...");
|
||||
usleep(1000);
|
||||
bpi_write(0, FLASH_CMD_READ_ARRAY);
|
||||
usleep(100);
|
||||
|
||||
bool verify_ok = true;
|
||||
for (uint32_t i = 0; i < 64 && i < len; i += 2) {
|
||||
uint8_t b0 = data[i];
|
||||
uint8_t b1 = 0xFF;
|
||||
if (i + 1 < len)
|
||||
b1 = data[i + 1];
|
||||
uint16_t expected = (reverseByte(b0) << 8) | reverseByte(b1);
|
||||
|
||||
uint16_t actual = bpi_read(i >> 1);
|
||||
if (actual != expected) {
|
||||
char buf[128];
|
||||
snprintf(buf, sizeof(buf), "Verify FAIL at 0x%04x: expected 0x%04x, got 0x%04x",
|
||||
i, expected, actual);
|
||||
printError(buf);
|
||||
verify_ok = false;
|
||||
} else if (_verbose) {
|
||||
char buf[128];
|
||||
snprintf(buf, sizeof(buf), "Verify OK at 0x%04x: 0x%04x", i, actual);
|
||||
printInfo(buf);
|
||||
}
|
||||
}
|
||||
|
||||
if (verify_ok) {
|
||||
printInfo("Verification passed for first 32 words");
|
||||
} else {
|
||||
printError("Verification FAILED!");
|
||||
}
|
||||
|
||||
printInfo("BPI flash programming complete");
|
||||
return true;
|
||||
}
|
||||
|
|
@ -0,0 +1,140 @@
|
|||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
* Copyright (C) 2024 openFPGALoader contributors
|
||||
* BPI (Parallel NOR) Flash support via JTAG bridge
|
||||
*/
|
||||
|
||||
#ifndef SRC_BPIFLASH_HPP_
|
||||
#define SRC_BPIFLASH_HPP_
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
#include "jtag.hpp"
|
||||
|
||||
/*!
|
||||
* \class BPIFlash
|
||||
* \brief Intel CFI parallel NOR flash programming via JTAG bridge
|
||||
*/
|
||||
class BPIFlash {
|
||||
public:
|
||||
BPIFlash(Jtag *jtag, int8_t verbose);
|
||||
~BPIFlash();
|
||||
|
||||
/*!
|
||||
* \brief Read device ID and manufacturer info
|
||||
* \return true if device detected
|
||||
*/
|
||||
bool detect();
|
||||
|
||||
/*!
|
||||
* \brief Read flash content
|
||||
* \param[out] data: buffer to store read data
|
||||
* \param[in] addr: start address (word address)
|
||||
* \param[in] len: number of bytes to read
|
||||
* \return true on success
|
||||
*/
|
||||
bool read(uint8_t *data, uint32_t addr, uint32_t len);
|
||||
|
||||
/*!
|
||||
* \brief Write data to flash (handles erase internally)
|
||||
* \param[in] addr: start address (word address)
|
||||
* \param[in] data: data to write
|
||||
* \param[in] len: number of bytes to write
|
||||
* \return true on success
|
||||
*/
|
||||
bool write(uint32_t addr, const uint8_t *data, uint32_t len);
|
||||
|
||||
/*!
|
||||
* \brief Erase a block
|
||||
* \param[in] addr: address within the block to erase
|
||||
* \return true on success
|
||||
*/
|
||||
bool erase_block(uint32_t addr);
|
||||
|
||||
/*!
|
||||
* \brief Bulk erase entire flash
|
||||
* \return true on success
|
||||
*/
|
||||
bool bulk_erase();
|
||||
|
||||
/*!
|
||||
* \brief Get flash capacity in bytes
|
||||
*/
|
||||
uint32_t capacity() const { return _capacity; }
|
||||
|
||||
/*!
|
||||
* \brief Get block size in bytes
|
||||
*/
|
||||
uint32_t block_size() const { return _block_size; }
|
||||
|
||||
private:
|
||||
/* BPI bridge command codes (match bpiOverJtag_core.v) */
|
||||
static const uint8_t CMD_WRITE = 0x1;
|
||||
static const uint8_t CMD_READ = 0x2;
|
||||
static const uint8_t CMD_NOP = 0x3;
|
||||
static const uint8_t CMD_BURST_WRITE = 0x4;
|
||||
|
||||
/* Intel CFI flash commands */
|
||||
static const uint16_t FLASH_CMD_READ_ARRAY = 0x00FF;
|
||||
static const uint16_t FLASH_CMD_READ_ID = 0x0090;
|
||||
static const uint16_t FLASH_CMD_READ_CFI = 0x0098;
|
||||
static const uint16_t FLASH_CMD_READ_STATUS = 0x0070;
|
||||
static const uint16_t FLASH_CMD_CLEAR_STATUS = 0x0050;
|
||||
static const uint16_t FLASH_CMD_PROGRAM = 0x0041; /* Single-word program (MT28GU512AAA) */
|
||||
static const uint16_t FLASH_CMD_BUFFERED_PRG = 0x00E9;
|
||||
static const uint16_t FLASH_CMD_CONFIRM = 0x00D0;
|
||||
static const uint16_t FLASH_CMD_BLOCK_ERASE = 0x0020;
|
||||
static const uint16_t FLASH_CMD_UNLOCK_BLOCK = 0x0060;
|
||||
static const uint16_t FLASH_CMD_UNLOCK_CONF = 0x00D0;
|
||||
|
||||
/* Status register bits */
|
||||
static const uint16_t SR_READY = 0x0080;
|
||||
static const uint16_t SR_ERASE_ERR = 0x0020;
|
||||
static const uint16_t SR_PROG_ERR = 0x0010;
|
||||
static const uint16_t SR_VPP_ERR = 0x0008;
|
||||
static const uint16_t SR_BLOCK_LOCK = 0x0002;
|
||||
|
||||
/*!
|
||||
* \brief Read a 16-bit word from flash at word address
|
||||
*/
|
||||
uint16_t bpi_read(uint32_t word_addr);
|
||||
|
||||
/*!
|
||||
* \brief Write a 16-bit word to flash at word address
|
||||
*/
|
||||
void bpi_write(uint32_t word_addr, uint16_t data);
|
||||
|
||||
/*!
|
||||
* \brief Write a 16-bit word without IR shift or flush (for batched writes)
|
||||
*/
|
||||
void bpi_write_no_flush(uint32_t word_addr, uint16_t data);
|
||||
|
||||
/*!
|
||||
* \brief Burst write multiple 16-bit words in a single DR shift
|
||||
*/
|
||||
void bpi_burst_write(uint32_t word_addr, const uint16_t *data,
|
||||
uint32_t count);
|
||||
|
||||
/*!
|
||||
* \brief Wait for operation to complete
|
||||
* \return true if completed successfully
|
||||
*/
|
||||
bool wait_ready(uint32_t timeout_ms = 10000);
|
||||
|
||||
/*!
|
||||
* \brief Unlock a block for programming/erase
|
||||
*/
|
||||
bool unlock_block(uint32_t word_addr);
|
||||
|
||||
Jtag *_jtag;
|
||||
int8_t _verbose;
|
||||
int _irlen;
|
||||
uint32_t _capacity;
|
||||
uint32_t _block_size;
|
||||
uint16_t _manufacturer_id;
|
||||
uint16_t _device_id;
|
||||
bool _has_burst;
|
||||
};
|
||||
|
||||
#endif // SRC_BPIFLASH_HPP_
|
||||
|
|
@ -100,6 +100,7 @@ struct arguments {
|
|||
unsigned int file_size;
|
||||
string target_flash;
|
||||
bool external_flash;
|
||||
bool spi_flash_type;
|
||||
int16_t altsetting;
|
||||
uint16_t vid;
|
||||
uint16_t pid;
|
||||
|
|
@ -150,8 +151,8 @@ int main(int argc, char **argv)
|
|||
-1, 0, false, "-", false, false, false, false, Device::PRG_NONE, false,
|
||||
/* spi dfu file_type fpga_part bridge_path probe_firmware */
|
||||
false, false, "", "", "", "",
|
||||
/* index_chain file_size target_flash external_flash altsetting */
|
||||
-1, 0, "primary", false, -1,
|
||||
/* index_chain file_size target_flash external_flash spi_flash_type altsetting */
|
||||
-1, 0, "primary", false, true, -1,
|
||||
/* vid, pid, index bus_addr, device_addr */
|
||||
0, 0, -1, 0, 0,
|
||||
"127.0.0.1", 0, false, false, false, false, "", false, false,
|
||||
|
|
@ -223,6 +224,7 @@ int main(int argc, char **argv)
|
|||
*/
|
||||
if (args.freq == 0)
|
||||
args.freq = board->default_freq;
|
||||
args.spi_flash_type = board->spi_bpi == SPI_FLASH;
|
||||
}
|
||||
|
||||
if (args.cable[0] == '-') { /* if no board and no cable */
|
||||
|
|
@ -656,7 +658,7 @@ int main(int argc, char **argv)
|
|||
if (fab == "xilinx") {
|
||||
#ifdef ENABLE_XILINX_SUPPORT
|
||||
fpga = new Xilinx(jtag, args.bit_file, args.secondary_bit_file,
|
||||
args.file_type, args.prg_type, args.fpga_part, args.bridge_path,
|
||||
args.file_type, args.prg_type, args.fpga_part, args.spi_flash_type, args.bridge_path,
|
||||
args.target_flash, args.verify, args.verbose, args.skip_load_bridge, args.skip_reset,
|
||||
args.read_dna, args.read_xadc);
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -272,7 +272,9 @@ Xilinx::Xilinx(Jtag *jtag, const std::string &filename,
|
|||
const std::string &secondary_filename,
|
||||
const std::string &file_type,
|
||||
Device::prog_type_t prg_type,
|
||||
const std::string &device_package, const std::string &spiOverJtagPath,
|
||||
const std::string &device_package,
|
||||
const bool spi_flash_type,
|
||||
const std::string &spiOverJtagPath,
|
||||
const std::string &target_flash,
|
||||
bool verify, int8_t verbose,
|
||||
bool skip_load_bridge, bool skip_reset, bool read_dna, bool read_xadc):
|
||||
|
|
@ -281,7 +283,7 @@ Xilinx::Xilinx(Jtag *jtag, const std::string &filename,
|
|||
skip_reset),
|
||||
_device_package(device_package), _spiOverJtagPath(spiOverJtagPath),
|
||||
_irlen(6), _secondary_filename(secondary_filename), _soj_is_v2(false),
|
||||
_jtag_chain_len(1)
|
||||
_jtag_chain_len(1), _is_bpi_board(~spi_flash_type)
|
||||
{
|
||||
if (prg_type == Device::RD_FLASH) {
|
||||
_mode = Device::READ_MODE;
|
||||
|
|
@ -654,17 +656,22 @@ void Xilinx::program(unsigned int offset, bool unprotect_flash)
|
|||
}
|
||||
|
||||
if (_mode == Device::SPI_MODE) {
|
||||
if (_flash_chips & PRIMARY_FLASH) {
|
||||
select_flash_chip(PRIMARY_FLASH);
|
||||
program_spi(bit, _file_extension, offset, unprotect_flash);
|
||||
}
|
||||
if (_flash_chips & SECONDARY_FLASH) {
|
||||
select_flash_chip(SECONDARY_FLASH);
|
||||
program_spi(secondary_bit, _secondary_file_extension, offset, unprotect_flash);
|
||||
}
|
||||
|
||||
reset();
|
||||
/* Check for BPI flash boards */
|
||||
if (_is_bpi_board) {
|
||||
program_bpi(bit, offset);
|
||||
reset();
|
||||
} else {
|
||||
if (_flash_chips & PRIMARY_FLASH) {
|
||||
select_flash_chip(PRIMARY_FLASH);
|
||||
program_spi(bit, _file_extension, offset, unprotect_flash);
|
||||
}
|
||||
if (_flash_chips & SECONDARY_FLASH) {
|
||||
select_flash_chip(SECONDARY_FLASH);
|
||||
program_spi(secondary_bit, _secondary_file_extension, offset, unprotect_flash);
|
||||
}
|
||||
|
||||
reset();
|
||||
}
|
||||
} else {
|
||||
if (_fpga_family == SPARTAN3_FAMILY)
|
||||
xc3s_flow_program(bit);
|
||||
|
|
@ -744,6 +751,68 @@ bool Xilinx::load_bridge()
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Xilinx::load_bpi_bridge()
|
||||
{
|
||||
std::string bitname;
|
||||
|
||||
if (_device_package.empty()) {
|
||||
printError("Can't program BPI flash: missing device-package information");
|
||||
return false;
|
||||
}
|
||||
|
||||
bitname = get_shell_env_var("OPENFPGALOADER_SOJ_DIR", DATA_DIR "/openFPGALoader");
|
||||
bitname += "/bpiOverJtag_" + _device_package + ".bit.gz";
|
||||
|
||||
#if defined (_WIN64) || defined (_WIN32)
|
||||
bitname = PathHelper::absolutePath(bitname);
|
||||
#endif
|
||||
|
||||
/* Load BPI over JTAG bridge */
|
||||
try {
|
||||
BitParser bridge(bitname, true, _verbose);
|
||||
printSuccess("Use: " + bridge.getFilename());
|
||||
|
||||
bridge.parse();
|
||||
program_mem(&bridge);
|
||||
} catch (std::exception &e) {
|
||||
printError(e.what());
|
||||
throw std::runtime_error(e.what());
|
||||
}
|
||||
|
||||
/* Initialize BPI flash instance */
|
||||
_bpi_flash.reset(new BPIFlash(_jtag, _verbose));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Xilinx::program_bpi(ConfigBitstreamParser *bit, unsigned int offset)
|
||||
{
|
||||
if (!bit)
|
||||
throw std::runtime_error("called with null bitstream");
|
||||
|
||||
/* Load BPI bridge if not already loaded */
|
||||
if (!_bpi_flash) {
|
||||
if (!load_bpi_bridge()) {
|
||||
throw std::runtime_error("Failed to load BPI bridge");
|
||||
}
|
||||
}
|
||||
|
||||
/* Detect flash */
|
||||
if (!_bpi_flash->detect()) {
|
||||
throw std::runtime_error("BPI flash detection failed");
|
||||
}
|
||||
|
||||
/* Program the flash */
|
||||
const uint8_t *data = bit->getData();
|
||||
int length = bit->getLength() / 8;
|
||||
|
||||
if (!_bpi_flash->write(offset, data, length)) {
|
||||
throw std::runtime_error("BPI flash programming failed");
|
||||
}
|
||||
|
||||
printInfo("BPI flash programming complete");
|
||||
}
|
||||
|
||||
float Xilinx::get_spiOverJtag_version()
|
||||
{
|
||||
uint8_t jtx[6] = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
|
|
@ -807,11 +876,11 @@ void Xilinx::program_mem(ConfigBitstreamParser *bitfile)
|
|||
* the TLR (Test-Logic-Reset) state.
|
||||
*/
|
||||
_jtag->shiftIR(get_ircode(_ircode_map, "JPROGRAM"), NULL, _irlen);
|
||||
/* test */
|
||||
/* Poll INIT_B (bit 4 of IR capture) until config memory is cleared */
|
||||
tx_buf = get_ircode(_ircode_map, "BYPASS");
|
||||
do {
|
||||
_jtag->shiftIR(tx_buf, rx_buf, _irlen);
|
||||
} while (!(rx_buf[0] &0x01));
|
||||
} while (!(rx_buf[0] & 0x10));
|
||||
/*
|
||||
* 8: Move into the RTI state. X 0 10,000(1)
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -7,9 +7,11 @@
|
|||
#define SRC_XILINX_HPP_
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "bpiFlash.hpp"
|
||||
#include "configBitstreamParser.hpp"
|
||||
#include "device.hpp"
|
||||
#include "jedParser.hpp"
|
||||
|
|
@ -23,6 +25,7 @@ class Xilinx: public Device, SPIInterface {
|
|||
const std::string &file_type,
|
||||
Device::prog_type_t prg_type,
|
||||
const std::string &device_package,
|
||||
const bool spi_flash_type,
|
||||
const std::string &spiOverJtagPath,
|
||||
const std::string &target_flash,
|
||||
bool verify, int8_t verbose,
|
||||
|
|
@ -33,6 +36,7 @@ class Xilinx: public Device, SPIInterface {
|
|||
void program(unsigned int offset, bool unprotect_flash) override;
|
||||
void program_spi(ConfigBitstreamParser * bit, std::string extention,
|
||||
unsigned int offset, bool unprotect_flash);
|
||||
void program_bpi(ConfigBitstreamParser * bit, unsigned int offset);
|
||||
void program_mem(ConfigBitstreamParser *bitfile);
|
||||
bool dumpFlash(uint32_t base_addr, uint32_t len) override;
|
||||
|
||||
|
|
@ -220,6 +224,17 @@ class Xilinx: public Device, SPIInterface {
|
|||
*/
|
||||
bool load_bridge();
|
||||
|
||||
/*!
|
||||
* \brief load BPI flash bridge for parallel NOR flash access
|
||||
* \return false if failed, true otherwise
|
||||
*/
|
||||
bool load_bpi_bridge();
|
||||
|
||||
/*!
|
||||
* \brief check if board uses BPI flash
|
||||
*/
|
||||
bool is_bpi_board() const { return _is_bpi_board; }
|
||||
|
||||
/*!
|
||||
* \brief read SpiOverJtag version to select between v1 and v2
|
||||
* \return 2.0 for v2 or 1.0 for v1
|
||||
|
|
@ -262,6 +277,8 @@ class Xilinx: public Device, SPIInterface {
|
|||
std::string _user_instruction; /* which USER bscan instruction to interface with SPI */
|
||||
bool _soj_is_v2; /* SpiOverJtag version (1.0 or 2.0) */
|
||||
uint32_t _jtag_chain_len; /* Jtag Chain Length */
|
||||
bool _is_bpi_board; /* true if board uses BPI parallel flash */
|
||||
std::unique_ptr<BPIFlash> _bpi_flash; /* BPI flash instance */
|
||||
};
|
||||
|
||||
#endif // SRC_XILINX_HPP_
|
||||
|
|
|
|||
Loading…
Reference in New Issue