Don't allocate large LZ4 buffers on stack; use some dedicated RAM. (#1670)

This commit is contained in:
Martin Ling
2026-02-11 19:13:32 +00:00
committed by GitHub
parent 43fb9fec3c
commit cc63a764ab
5 changed files with 62 additions and 16 deletions

View File

@@ -22,5 +22,5 @@
MEMORY
{
ram (rwx) : ORIGIN = 0x00000000, LENGTH = 28K
ram (rwx) : ORIGIN = 0x00000000, LENGTH = 20K
}

View File

@@ -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));

View File

@@ -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)

View File

@@ -23,6 +23,7 @@
#include <libopencm3/lpc43xx/scu.h>
#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]);
}
}

35
firmware/common/lz4_buf.h Normal file
View File

@@ -0,0 +1,35 @@
/*
* Copyright 2026 Great Scott Gadgets <info@greatscottgadgets.com>
*
* 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 <stdint.h>
#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 */