From cc63a764ab67cf5f06d74460e3cddd0aa06ae478 Mon Sep 17 00:00:00 2001 From: Martin Ling Date: Wed, 11 Feb 2026 19:13:32 +0000 Subject: [PATCH] Don't allocate large LZ4 buffers on stack; use some dedicated RAM. (#1670) --- firmware/common/LPC43xx_M0_memory.ld | 2 +- firmware/common/LPC43xx_M4_memory.ld | 17 ++++++++++---- firmware/common/fpga_image.c | 18 ++++++++------ firmware/common/ice40_spi.c | 6 ++--- firmware/common/lz4_buf.h | 35 ++++++++++++++++++++++++++++ 5 files changed, 62 insertions(+), 16 deletions(-) create mode 100644 firmware/common/lz4_buf.h diff --git a/firmware/common/LPC43xx_M0_memory.ld b/firmware/common/LPC43xx_M0_memory.ld index cbf04d5e..5a873132 100644 --- a/firmware/common/LPC43xx_M0_memory.ld +++ b/firmware/common/LPC43xx_M0_memory.ld @@ -22,5 +22,5 @@ MEMORY { - ram (rwx) : ORIGIN = 0x00000000, LENGTH = 28K + ram (rwx) : ORIGIN = 0x00000000, LENGTH = 20K } diff --git a/firmware/common/LPC43xx_M4_memory.ld b/firmware/common/LPC43xx_M4_memory.ld index b49e8cb9..933fa854 100644 --- a/firmware/common/LPC43xx_M4_memory.ld +++ b/firmware/common/LPC43xx_M4_memory.ld @@ -23,16 +23,23 @@ MEMORY { /* Physical address in Flash used to copy Code from Flash to RAM */ - rom_flash (rx) : ORIGIN = 0x80000000, LENGTH = 1M - ram_m0 (rwx) : ORIGIN = 0x20000000, LENGTH = 28K - ram_shared (rwx) : ORIGIN = 0x20007000, LENGTH = 4K - ram_usb (rwx) : ORIGIN = 0x20008000, LENGTH = 32K - /* ram_usb: USB buffer. Straddles two blocks of RAM + rom_flash (rx) : ORIGIN = 0x80000000, LENGTH = 1M + /* Buffers for LZ4 decompression */ + ram_lz4_in (rwx) : ORIGIN = 0x20000000, LENGTH = 4K + ram_lz4_out (rwx) : ORIGIN = 0x20001000, LENGTH = 4K + /* RAM for M0 code */ + ram_m0 (rwx) : ORIGIN = 0x20002000, LENGTH = 20K + /* RAM shared between M0 and M4 */ + ram_shared (rwx) : ORIGIN = 0x20007000, LENGTH = 4K + /* USB buffer. Straddles two blocks of RAM * to get performance benefit of having two USB buffers addressable * simultaneously (on two different buses of the AHB multilayer matrix) */ + ram_usb (rwx) : ORIGIN = 0x20008000, LENGTH = 32K } usb_bulk_buffer = ORIGIN(ram_usb); +lz4_in_buf = ORIGIN(ram_lz4_in); +lz4_out_buf = ORIGIN(ram_lz4_out); m0_state = ORIGIN(ram_shared); PROVIDE(__ram_m0_start__ = ORIGIN(ram_m0)); diff --git a/firmware/common/fpga_image.c b/firmware/common/fpga_image.c index ddac8595..a70906b8 100644 --- a/firmware/common/fpga_image.c +++ b/firmware/common/fpga_image.c @@ -21,6 +21,7 @@ #include "hackrf_core.h" #include "lz4_blk.h" +#include "lz4_buf.h" #include "selftest.h" // FPGA bitstreams blob. @@ -32,7 +33,6 @@ struct fpga_image_read_ctx { uint32_t addr; size_t next_block_sz; uint8_t init_flag; - uint8_t buffer[4096 + 2]; }; static size_t fpga_image_read_block_cb(void* _ctx, uint8_t* out_buffer) @@ -41,10 +41,12 @@ static size_t fpga_image_read_block_cb(void* _ctx, uint8_t* out_buffer) struct fpga_image_read_ctx* ctx = _ctx; size_t block_sz = ctx->next_block_sz; + uint8_t block_sz_buf[2]; + // first iteration: read first block size if (ctx->init_flag == 0) { - w25q80bv_read(&spi_flash, ctx->addr, 2, ctx->buffer); - block_sz = ctx->buffer[0] | (ctx->buffer[1] << 8); + w25q80bv_read(&spi_flash, ctx->addr, 2, block_sz_buf); + block_sz = block_sz_buf[0] | block_sz_buf[1] << 8; ctx->addr += 2; ctx->init_flag = 1; } @@ -54,12 +56,14 @@ static size_t fpga_image_read_block_cb(void* _ctx, uint8_t* out_buffer) return 0; // Read compressed block (and the next block size) from flash. - w25q80bv_read(&spi_flash, ctx->addr, block_sz + 2, ctx->buffer); - ctx->addr += block_sz + 2; - ctx->next_block_sz = ctx->buffer[block_sz] | (ctx->buffer[block_sz + 1] << 8); + w25q80bv_read(&spi_flash, ctx->addr, block_sz, lz4_in_buf); + ctx->addr += block_sz; + w25q80bv_read(&spi_flash, ctx->addr, 2, block_sz_buf); + ctx->next_block_sz = block_sz_buf[0] | block_sz_buf[1] << 8; + ctx->addr += 2; // Decompress block. - return lz4_blk_decompress(ctx->buffer, out_buffer, block_sz); + return lz4_blk_decompress(lz4_in_buf, out_buffer, block_sz); } bool fpga_image_load(unsigned int index) diff --git a/firmware/common/ice40_spi.c b/firmware/common/ice40_spi.c index 241d9cd9..344bb0e6 100644 --- a/firmware/common/ice40_spi.c +++ b/firmware/common/ice40_spi.c @@ -23,6 +23,7 @@ #include #include "hackrf_core.h" +#include "lz4_buf.h" #include "delay.h" void ice40_spi_target_init(ice40_spi_driver_t* const drv) @@ -104,14 +105,13 @@ bool ice40_spi_syscfg_program( // Send configuration image serially on SPI_SI to iCE40, most-significant bit // first, on falling edge of SPI_SCK. - uint8_t out_buffer[4096] = {0}; gpio_clear(drv->gpio_select); for (;;) { - size_t read_sz = read_block_cb(read_ctx, out_buffer); + size_t read_sz = read_block_cb(read_ctx, lz4_out_buf); if (read_sz == 0) break; for (size_t j = 0; j < read_sz; j++) { - spi_ssp1_transfer_word(out_buffer[j]); + spi_ssp1_transfer_word(lz4_out_buf[j]); } } diff --git a/firmware/common/lz4_buf.h b/firmware/common/lz4_buf.h new file mode 100644 index 00000000..b9dec589 --- /dev/null +++ b/firmware/common/lz4_buf.h @@ -0,0 +1,35 @@ +/* + * Copyright 2026 Great Scott Gadgets + * + * This file is part of HackRF. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __LZ4_BUF_H +#define __LZ4_BUF_H + +#include + +#define LZ4_BUFFER_SIZE 0x1000 + +/* Addresses of these buffers are set in linker script. If you change the name + * of these buffers, you must also adjust the linker script. */ + +extern uint8_t lz4_in_buf[LZ4_BUFFER_SIZE]; +extern uint8_t lz4_out_buf[LZ4_BUFFER_SIZE]; + +#endif /*__LZ4_BUF_H */