Files
proxmark3/tools/fpga_compress
iceman1001andClaude Opus 5 (1M context) f0b569b507 fpga_compress: pad a single bitstream to the interleave boundary
zlib_decompress() walks its output in whole FPGA_INTERLEAVE_SIZE chunks:

  for (long k = 0; k < *outsize / (FPGA_INTERLEAVE_SIZE * num_outfiles); k++)

so a stream that is not a whole number of chunks loses its trailing partial one.
With two or more inputs the read loop zero-pads each stream past EOF and the
total lands on a boundary, but the padding was guarded by 'num_infiles > 1', so
the single input case was left ragged. 42172 bytes of fpga_pm3_hf.bit is 146.43
chunks, and -d handed back 39788 - a clean looking prefix, short by 2384 bytes,
22 of them real bitstream data.

Gate the padding on single_block instead. It must not be 'always pad': -s is the
.data section, and start.c's uncompress_data_section() sizes the decompression
with __data_end__ - __data_start__. Rounding .data from 14944 up to 14976 makes
LZ4_decompress_safe() return an error, and that path is the LED panic loop, so
the firmware would never reach AppMain().

  1 bitstream   42172 in -> 42336 packed, -d round trip byte identical,
                archive 28730 -> 28731
  4 bitstreams  archive byte identical to 43fe6c3eb, round trip exact
  -s .data      byte identical to 43fe6c3eb on the same input, unpadded

The 164 padding bytes never reach the FPGA: DownloadFPGA() shifts out only
bitstream_length bytes, taken from the .bit 'e' section header.

Also simulated the ARM decoder over the new archive - LZ4_decompress_safe_continue()
block by block into a FPGA_RING_BUFFER_BYTES buffer - 3 blocks of 16384/16384/9568,
none over the ring buffer.

Co-Authored-By: Claude Opus 5 (1M context)
2026-09-13 08:27:53 +02:00
..