A small LZ77 decompressor written in SystemVerilog. This repo includes:
- a decompression core (token-in, byte-out)
- an AXI-Stream wrapper that adds backpressure handling using a small FIFO
- a Python golden model + vector generator
- a self-checking simulation flow in Vivado
LZ77 is a lossless compression idea based on reuse. Instead of writing repeated data again, it writes a reference to bytes that already appeared recently.
A token usually contains:
- distance: how far back to look
- length: how many bytes to copy
- literal: the next byte after the match
Decompression does:
- copy
lengthbytes fromdistancebytes back (history window) - output the final
literalbyte
The core accepts token fields using a simple handshake:
in_valid / in_readyin_distance, in_length, in_literal
It outputs decompressed bytes:
out_validout_byte
Internally it uses a circular history buffer and an FSM:
- if
length == 0→ output only the literal - if
length > 0→ output copied bytes (one per cycle), then output the literal
Important point: the core has no output ready, so it cannot pause if downstream is slow.
The wrapper converts the core into a streaming block with:
- AXI-Stream input for tokens (
s_axis_*) - AXI-Stream output for bytes (
m_axis_*)
Backpressure means the downstream block can say:
“I’m not ready to take data right now.”
In AXI-Stream this is done by deasserting m_axis_tready.
If the producer can’t stop and you don’t buffer, you lose data.
So the wrapper adds a FIFO to absorb output bytes safely.
- The core writes output bytes into an output FIFO
- The AXI output reads bytes from FIFO using
m_axis_tready - The wrapper controls
s_axis_treadyso it only accepts a token when it is safe
Token output size:
- if
len=0→ 1 byte - else →
len+1bytes (copied bytes + final literal)
So before accepting a token, the wrapper checks:
- FIFO has enough free space for the token’s worst-case output
s_axis_tlastmarks the last input tokenm_axis_tlastis asserted on the last output byte produced by that last token
This is the top-level dataflow of lz77_decomp_stream (wrapper).
Data moves left → right. READY/tready flows backward (backpressure).
Blocks
- Unpack + Input Gating: unpacks input
TDATAinto{distance, length, literal}and only accepts a token when it is safe (enough FIFO space for that token’s worst-case output). - LZ77 Core: expands each token into output bytes (copy
lengthbytes from history, then output the finalliteral). - Output FIFO: buffers output bytes so the stream can handle downstream stalls (
m_axis_treadylow) without losing data.
The AXI input token is packed into TDATA as:
{distance, length, literal}
Where:
- literal is always
[7:0] distanceisDIST_WIDTHbitslengthisLEN_WIDTHbits- total width:
TOKEN_W = DIST_WIDTH + LEN_WIDTH + 8
This repo uses a Python script to do two jobs:
- act as a golden reference (software model of the same token rules)
- generate test vectors as
.memfiles used by the Vivado testbench
The script produces:
tokens.mem(packed tokens, hex per line)expected.mem(expected output bytes, hex per line)meta.mem(NUM_TOKENS and EXP_LEN, 32-bit hex)
DIST_WIDTH = 4LEN_WIDTH = 4TOKEN_W = 16- Constraint: 150 MHz (
constraints/lz77_decomp_const.xdc)
This run uses the .mem vectors generated by the Python script and compares the RTL output stream against the expected bytes.
The waveform shows tokens entering on s_axis_* and the decompressed bytes leaving on m_axis_*.
meta.mem drives NUM_TOKENS and EXP_LEN, and the testbench asserts PASS once all expected bytes match.
Implemented design timing summary with the 150 MHz clock constraint.
Device utilization for the implemented design on Xilinx Zynq 7000 ZC702 FPGA Board.
A zoomed-in schematic view around the lz77_decomp_core instance to show how the wrapper connects into the core.
-
The wrapper handles output backpressure using a FIFO, but it does not guarantee “infinite buffering”. If a consumer stalls long enough and the FIFO fills up, the wrapper applies backpressure upstream by deasserting
s_axis_tready(so the source must stop sending tokens). -
This is a clean streaming block, not a full decompression standard (no headers, checksums, error recovery).





