From a91dd9f628be3b7fb16ad931d0810f7defa3ec52 Mon Sep 17 00:00:00 2001 From: blurbdust Date: Mon, 9 Feb 2026 10:58:24 -0600 Subject: [PATCH] Speed up from 25 minutes to ~6 minutes --- bpiOverJtag/bpiOverJtag_core.v | 77 ++++++++-- .../bpiOverJtag_xc7k480tffg1156.bit.gz | Bin 131812 -> 132452 bytes src/bpiFlash.cpp | 133 +++++++++++++++--- src/bpiFlash.hpp | 19 ++- 4 files changed, 197 insertions(+), 32 deletions(-) diff --git a/bpiOverJtag/bpiOverJtag_core.v b/bpiOverJtag/bpiOverJtag_core.v index 3c76adc..251af03 100644 --- a/bpiOverJtag/bpiOverJtag_core.v +++ b/bpiOverJtag/bpiOverJtag_core.v @@ -10,6 +10,7 @@ * 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 ( @@ -46,21 +47,25 @@ wire rst = (capture & sel); wire start_header = (tdi & shift & sel); /* State machine */ -localparam IDLE = 3'd0, - RECV_CMD = 3'd1, - RECV_ADDR = 3'd2, - RECV_DATA = 3'd3, - EXEC = 3'd4, - SEND_DATA = 3'd5, - DONE = 3'd6; +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 [2:0] state, state_d; +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; @@ -71,9 +76,10 @@ assign bpi_dq = dq_oe ? dq_out : 16'hzzzz; assign tdo = rd_data_reg[0]; /* Command codes */ -localparam CMD_WRITE = 4'h1, - CMD_READ = 4'h2, - CMD_NOP = 4'h3; +localparam CMD_WRITE = 4'h1, + CMD_READ = 4'h2, + CMD_NOP = 4'h3, + CMD_BURST_WRITE = 4'h4; /* Next state logic */ always @(*) begin @@ -84,6 +90,7 @@ always @(*) begin 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 @@ -108,6 +115,9 @@ always @(*) 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; @@ -143,6 +153,38 @@ always @(*) begin 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 @@ -167,6 +209,7 @@ always @(posedge drck) begin 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 */ @@ -175,6 +218,8 @@ always @(posedge drck or posedge rst) begin 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 */ @@ -202,6 +247,14 @@ always @(posedge drck or posedge rst) begin 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; @@ -219,7 +272,7 @@ end wire ver_rst = (ver_cap & ver_sel); wire ver_start = (ver_tdi & ver_shift & ver_sel); -localparam VER_VALUE = 40'h30_31_2E_30_30; // "01.00" +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; diff --git a/bpiOverJtag/bpiOverJtag_xc7k480tffg1156.bit.gz b/bpiOverJtag/bpiOverJtag_xc7k480tffg1156.bit.gz index 82af67f7ca832ab12869fb0811e09fd328c2006a..ad9bf930e6306f472b236026b4625463ac67e46d 100644 GIT binary patch literal 132452 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 F`+v;HytV)U literal 131812 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 #include #include +#include #include "display.hpp" #include "progressBar.hpp" @@ -29,7 +30,8 @@ static inline uint8_t reverseByte(uint8_t 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) + _manufacturer_id(0), _device_id(0), + _has_burst(false) { } @@ -46,6 +48,7 @@ BPIFlash::~BPIFlash() * 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) @@ -133,6 +136,94 @@ void BPIFlash::bpi_write(uint32_t word_addr, uint16_t data) _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 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..."); @@ -189,6 +280,11 @@ bool BPIFlash::detect() _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; } @@ -345,7 +441,6 @@ bool BPIFlash::write(uint32_t addr, const uint8_t *data, uint32_t len) } /* Program data using buffered programming (0x00E9) - * MT28GU512AAA has 512-word buffer, we use 32 words for reliability * Sequence: Setup(0xE9) -> WordCount(N-1) -> N data words -> Confirm(0xD0) */ printInfo("Programming (buffered mode)..."); @@ -374,9 +469,6 @@ bool BPIFlash::write(uint32_t addr, const uint8_t *data, uint32_t len) last_block = current_block; } - /* Clear any pending status before new buffered program */ - bpi_write(0, FLASH_CMD_CLEAR_STATUS); - /* 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; @@ -395,26 +487,36 @@ bool BPIFlash::write(uint32_t addr, const uint8_t *data, uint32_t len) printInfo(buf); } - /* Buffered Program Setup - sent to block/colony base address */ - bpi_write(block_word_addr, FLASH_CMD_BUFFERED_PRG); - usleep(10); - - /* Write word count (N-1) - sent to block address per datasheet */ - bpi_write(block_word_addr, chunk_words - 1); - /* 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 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]; - uint16_t word = (reverseByte(b0) << 8) | reverseByte(b1); - bpi_write(word_addr + w, word); + 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 */ @@ -429,9 +531,6 @@ bool BPIFlash::write(uint32_t addr, const uint8_t *data, uint32_t len) return false; } - /* Small delay before next buffer operation */ - usleep(100); - offset += chunk_words * 2; if ((offset & 0xFFF) == 0 || offset >= len) diff --git a/src/bpiFlash.hpp b/src/bpiFlash.hpp index 858807c..0b03f4c 100644 --- a/src/bpiFlash.hpp +++ b/src/bpiFlash.hpp @@ -70,9 +70,10 @@ class BPIFlash { 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_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; @@ -104,6 +105,17 @@ class BPIFlash { */ 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 @@ -122,6 +134,7 @@ class BPIFlash { uint32_t _block_size; uint16_t _manufacturer_id; uint16_t _device_id; + bool _has_burst; }; #endif // SRC_BPIFLASH_HPP_