Skip to content

Repository files navigation

AV1 RTL Encoder

This repository is the main implementation tree for a full RTL AV1 encoder. The sibling ../SVT-AV1/ repository is reference-only and is used to validate feature behavior against a mature software encoder.

Project Goal

The goal is a full end-to-end AV1 encoder whose final output is:

  • generated by the RTL encoder byte path itself
  • decodable in FFmpeg or another standards-compliant AV1 decoder
  • visually verified against the source
  • delivered as playable outputs for representative proofs derived from the RTL-generated AV1 stream

Proof target:

  • Big Buck Bunny at 1280x720 @ 24 fps is a useful natural-video reference source, not a mandatory fixed-duration milestone
  • normally use the smallest clip that proves the behavior, even 1 frame for intra/residual or 2 frames when a KEY→INTER transition is enough
  • use more frames only when the feature itself needs reference/GOP/quality behavior; longer runs such as 240 frames / 10 seconds are optional soak/regression evidence, not the required proof size
  • AV1 bitstream generated by RTL, not software fallback assembly
  • remove/archive generated or garbled artifacts that slow ASIC progress without adding proof

Living Document

This README.md is a living status document and must be updated continuously while the encoder is being implemented. Official external debug references pulled from the web are tracked in av1-reference-docs/external/README.md.

  • Do not wait until project completion to refresh this file.
  • Update it after meaningful implementation, simulation, decode, or verification changes.
  • Update it for milestones, discoveries, blocker changes, ownership changes, validation results, and any feature movement worth preserving.
  • Keep it aligned with AGENTS.md and av1-reference-docs/svt-av1-feature-inventory.md.
  • It must reflect the current supported feature subset, current verification status, known gaps, active blockers, and the currently recommended run flow.
  • Important findings must not live only in terminal output, replies, or commit messages. If they affect what is true about the encoder, record them here.

Current Program Scope

The active program goal is full feature-complete RTL AV1.

  • The reduced pre-ASIC freeze on canonical main at 8994490d209a745fb157e999af616b49de2c6ce1 is a historical checkpoint, not project completion.
  • The exact active source of truth is FULL_RTL_SCOPE.md.
  • The exact matrix is derived from av1-reference-docs/svt-av1-feature-inventory.md plus the prior gap audit.
  • Historical checkpoint details live in PRE_ASIC_HANDOFF.md and P7_REFERENCE_BOUNDARY.md.

Full AV1 / ASIC Implementation Gap Checklist

This is the README-level feature inventory for reaching a real full RTL AV1 encoder and then an ASIC-ready implementation. A green smoke test, a reduced checkpoint, or a software-writer-matching debug run is not completion unless the item is owned by the RTL path and independently decoded/verified.

Codec features still required for full AV1

  • Bitstream ownership and headers: complete OBU, sequence header, frame header, tile group, metadata, packetization, and final IVF/container wrapping from RTL-owned bytes; remove dependency on the C++ debug writer for finished syntax.
  • Entropy and CDF state: complete symbol/CDF coverage, adaptive CDF update and refresh semantics, frame-context carryover, and context reset rules across key/inter frames and GOP boundaries.
  • Input/output surfaces: raw YUV and Y4M input, 8-bit and 10-bit 4:2:0, Main/High/Professional profile signaling, automatic/explicit level signaling, reconstructed-frame output, PSNR/SSIM reporting, still-picture/AVIF-style support, and representative 1280x720 @ 24 fps outputs.
  • Partitioning and transforms: full recursive partition coverage, square and non-square block sizes, transform-size/type selection, lossless qindex=0 / TX_4X4, delta-q, and reconstruction parity for every enabled transform.
  • Intra tools: complete luma/chroma intra prediction, CfL, filter intra, palette/screen-content decisions if kept in scope, and natural-keyframe proof cases beyond the current reduced probes.
  • Coefficient syntax: full luma and chroma coefficient syntax across EOB ranges, coefficient magnitudes, transform sizes, transform types, qindex ranges, and dense/high-energy natural-content distributions.
  • Chroma tools: non-flat Cb/Cr residual coding, chroma intra-neighbor ownership, chroma inter prediction/residual integration, and decoder-to-recon parity on natural chroma clips.
  • Inter prediction and motion: multi-reference frames beyond LAST-only, complete MV predictor/context classes, fractional/subpel coverage, compound references, global/warped motion, OBMC, inter-intra, wedge/compound modes, MFMV/order-hint behavior, and broader natural-motion validation.
  • Reference/GOP control: full reference-frame lifecycle, refresh-map management, random access, open/closed GOP behavior, overlays/show-existing frame handling if enabled, hierarchical layers, and long-sequence stability.
  • Post-reconstruction filters: loop filter, CDEF, restoration, superres/film grain policy, and filtered-reference writeback before any filtered tool is advertised in the bitstream.
  • Rate/quality control: CQP/CRF/VBR/CBR-style control as scoped, AQ/ROI, mode-decision/RD search, recode loops as needed, and quality/bitrate regression evidence against representative clips.
  • Advanced/deferred AV1 tools: screen-content tools, segmentation, global metadata/signaling, and any remaining advanced AV1 tool that is not explicitly de-scoped in a future standards-backed decision.

ASIC-readiness work still required after codec feature closure

  • lint-clean synthesizable RTL with simulation-only code guarded or removed;
  • explicit SRAM/DRAM/frame-buffer interfaces instead of testbench-owned memory assumptions;
  • hierarchy-preserving synthesis scripts, constraints, and module-level gates;
  • clock/reset strategy, CDC review if multiple clocks are introduced, and scan / DFT planning;
  • timing, area, power, and gate-level simulation evidence on the chosen ASIC flow; and
  • repo hygiene suitable for handoff: no generated build trees, stale worktrees, debug dumps, or software-authored final-bitstream shortcuts in the source tree.

Bitstream Ownership Rule

The RTL must own the final AV1 syntax generation needed for completion. The testbench may feed raw YUV, capture RTL bytes, decode output, compute metrics, and package a playable container, but it must not author the final AV1 syntax on behalf of the RTL for project completion.

P9 Disabled Filter / Reference Ownership Policy

Historical reduced-freeze note: the checkpoint below intentionally disabled post-reconstruction AV1 filters; that is not the active program goal. Sequence headers signal enable_cdef=0 and enable_restoration=0, and every supported frame header keeps loop_filter_level[0..1]=0. With loop filter, CDEF, restoration, superres, and film grain disabled, the post-filter reference frame is identical to the unfiltered RTL reconstruction, so the harness may promote reconstructed luma/chroma buffers directly as LAST references.

This contract is tracked in P9_DISABLED_FILTER_POLICY.md and guarded by make bitstream-check, which parses sequence/key/inter headers and includes negative filter-enabled guard cases. If a future lane enables any of those filters, add real RTL post-recon filter/restoration writeback before dumping recon.yuv or promoting reference buffers; do not repair filtered references in the C++ testbench.

Validation record: the post-merge proof was rechecked on canonical commit 55850d927f4f6018bcc00d7556fef2029d2404c7 from origin/main in a clean detached worktree at /tmp/t_3754b875_clean. Local main is currently 11021fac2ca7644e3acda4e38931663bea4cb49a and is ahead of origin/main by 1 commit. Under THREADS=1 BUILD_JOBS=1, make -C tb bitstream-check, make -C tb top-public-matrix-check (FFmpeg/libdav1d and aomdec both matched recon.yuv on the 32x32 natural-ish fractional NEWMV proof), and make -C tb standalone-matrix-check all passed.

Simulation Threads

Simulation and Verilator builds should use the right thread count for the task at hand.

  • For historical pre-ASIC AV1 Kanban validation matrix reruns and any doc/handoff checks, default to THREADS=1 BUILD_JOBS=1.
  • For routine smoke/debug work on this host, use the host's detected thread count unless a task says otherwise.
  • Do not force THREADS above the host's real thread count; Verilator 5.020 aborts at runtime if the model is built for more threads than the VerilatedContext can create.

Routine smoke/debug commands on this machine:

THREADS=16 BUILD_JOBS=16 bash docker_run.sh
THREADS=16 BUILD_JOBS=16 bash run.sh
cd tb
make THREADS=16 BUILD_JOBS=16

Historical pre-ASIC validation matrix: see PRE_ASIC_HANDOFF.md for the canonical single-thread command and gate list; see FULL_RTL_SCOPE.md for the active scope.

References

Always use primary references before making codec decisions.

  • av1-reference-docs/av1-spec.pdf
  • FULL_RTL_SCOPE.md
  • ASIC_READINESS.md
  • ../SVT-AV1/
  • local or mirrored libaom sources under av1-reference-docs/external/
  • official blocker notes in av1-reference-docs/external/README.md

Download and keep needed spec sheets and reference material locally. Prefer primary references over memory and verify temporary inferences quickly.

Verification Inputs

The repo-local test assets are stored under data/:

  • bigbuckbunny.mp4
  • raw_frames.yuv
  • ffmpeg_reference.ivf

These are used for RTL encode, decode, and comparison against an ffmpeg AV1 reference encode.

Current Status

Inventory of the current repo state:

  • Implemented:
    • 8-bit 4:2:0 low-delay bring-up flow
    • fixed 8x8 luma blocks inside 64x64 superblocks
    • luma intra search across DC, directional, SMOOTH, and PAETH
    • luma transform, quantization, coefficient coding, inverse transform, and reconstruction
    • reduced single-reference inter decision capture with integer-pel MVs
    • ME candidate SAD accumulation fixed to include the final sample before best-match update
    • bounded ME candidate raster seeded from (0,0) before the valid search window
    • software-side debug writer for AV1 headers, tiles, and reduced block syntax
    • testbench-side preservation of the raw RTL byte stream into per-frame rtl_frames/*.obu files plus a concatenated *_rtl_raw.obu
    • testbench-side direct capture of the RTL byte-valid path into *_rtl_raw.obu and *_rtl.ivf ownership artifacts, instead of relying only on the debug memory-write side effects
    • RTL reduced still-picture sequence header and keyframe header emission now matches the software writer's header prefix on the fast all-key debug case
    • RTL raw frame OBU size byte is now back-patched to the actual emitted raw payload length at frame completion
    • Chud PC 2 generated 16x16 smoke ownership is back in sync on the RTL byte path:
      • rtl/av1_encoder_top.v now uses the append address (bs_wr_addr) rather than the drift-prone debug total when back-patching the frame OBU size and reporting bs_bytes_written
      • the testbench defaults to static-CDF / disable_cdf_update=1, matching the current RTL entropy subset that does not yet own adaptive CDF updates
      • the sequence writer no longer forces the first IP-frame bootstrap packet through a software-only INTRA_ONLY_FRAME header that the RTL header generator does not emit
    • rtl/av1_entropy.v now uses a real AV1-style range coder for the existing bool, literal, and generic symbol interface instead of the old debug bit-packer
    • standalone entropy reference-check harness in tb/test_entropy.cpp and make entropy-check
    • RTL top-level now tracks writer-style 8x8 neighborhood syntax state (part_ctx, skip, mode) as groundwork for tile ownership
    • RTL raw payload now emits a real AV1 skip symbol per block before the older placeholder coefficient-bool stream
    • RTL raw payload now also emits intra-block y_mode, zero angle_delta, and deterministic UV_DC_PRED syntax for keyframe and intra-only blocks before the placeholder coefficient stream
    • RTL raw payload now emits the luma txb_skip=0 entry symbol and the deterministic zero-chroma txb_skip=1 symbols before reconstruction, while still using the older placeholder luma coefficient-presence stream behind them
    • RTL raw payload now emits a first real luma coefficient syntax slice for intra DC-only 8x8 blocks with eob=1 and |qcoeff[0]| <= 14: intra tx_type, eob, coeff_base_eob, bounded coeff_br, and neighbor-aware DC sign
    • RTL raw payload now emits the first verified sparse low-order AC luma slice for intra 8x8 blocks where only qcoeff[0] and qcoeff[1] are nonzero, qcoeff[8] == 0, |qcoeff[0]| <= 2, and |qcoeff[1]| == 1: full eob_multi64 symbol 2, eob_extra=0, coeff_base_eob at scan c=2, zero base at scan c=1, DC base, DC sign, and AC sign
    • RTL raw payload now also emits the first verified dense low-order AC luma slice for intra 8x8 blocks where only flat indices 0, 8, 1, and 10 are nonzero with magnitudes 1, 1, 2, and 1: full eob_multi64 symbol 4 for eob=9, eob_extra=0 including the trailing direct bits, zero bases through scan positions 7..3, the context-2 bases at scan 2 and 1, the DC base, and all three AC signs
    • software-writer coefficient scan order now matches the official libaom default_scan_8x8 table
    • RTL luma reconstruction now transposes the dequantized 8x8 coefficient matrix into the decoder-consistent flat-index orientation before the inverse 2D transform
    • non-directional intra prediction now matches AV1's one-sided edge fallback rules for left-only and top-only blocks instead of forcing both missing sides to 128
    • directional intra prediction now has a real top-right extension path for the current 8x8 raster-order subset instead of always repeating the last top sample
    • RTL raw block syntax on non-key frames now emits the real intra_inter symbol before block-mode syntax instead of falling straight from skip to keyframe-style y_mode
    • rtl/av1_bitstream.v no longer emits a placeholder non-key frame header; it now writes a reduced video INTER_FRAME header matching the current software reference subset
    • the raw-path reduced inter subset now owns real single-reference LAST-frame motion syntax instead of only the earlier zero-motion scaffold:
      • the ME decision is no longer clamped to zero-MV matches on the RTL-owned path
      • the top-level now derives a reduced LAST-ref MV candidate stack from neighboring blocks, stores per-block integer MVs, and emits the real newmv, zeromv, refmv, drl, mv_joint, sign, class, class0, and class-bit syntax on the RTL byte path
      • coefficient-bearing inter blocks continue through the real generic coefficient syntax path and use the inter DCT_DCT tx_type CDF on the RTL path instead of falling back to the old placeholder / intra-coded entry
    • rtl/av1_me.v now preserves the already-tested zero MV when it is also the final legal raster-search candidate:
      • the old helper always skipped zero after the dedicated zero-MV probe, which pushed bottom-right blocks past the legal search window and could leave TS_WAIT_ME spinning on longer clips
      • the scan now skips zero only when another in-range candidate still follows it
    • standalone rtl/av1_bitstream.v regression harness in tb/test_rtl_bitstream.cpp and make bitstream-check
    • the P7 reference boundary checkpoint is a historical reduced LAST-only boundary documented in P7_REFERENCE_BOUNDARY.md and frozen on canonical main at 8994490d209a745fb157e999af616b49de2c6ce1 (already pushed to origin/main); compound / multi-ref tools were disabled for that checkpoint, and FULL_RTL_SCOPE.md defines the active program scope
  • Validated:
    • small still-picture and selected small video-path debug cases decode successfully
    • official external debug references have been pulled into av1-reference-docs/external/
    • Chud PC 2 generated 16x16 all-key and 2-frame IP smoke cases now pass the full ownership/decode gate with THREADS=16 BUILD_JOBS=16:
      • encoded.obu == encoded_rtl_raw.obu
      • encoded.ivf == encoded_rtl.ivf
      • ffmpeg/libdav1d and aomdec decoded output both match recon.yuv
    • 16x16 2-frame IP output decodes in both ffmpeg/libdav1d and aomdec
    • decoded output matches recon.yuv exactly on that 16x16 inter case
    • the pre-ASIC freeze on canonical main at 8994490d209a745fb157e999af616b49de2c6ce1 passed the single-threaded current matrix on Chud PC 2 with THREADS=1 BUILD_JOBS=1: 21/21 gates, raw RTL OBU/IVF equality, FFmpeg/libdav1d parity, and aomdec parity all held, and no testbench or packaging repair masked RTL bugs
    • the strict 16x16 2-frame zero-motion IP ownership repro is now exact on the raw RTL path, not just decoder-clean:
      • encoded.obu and encoded_rtl_raw.obu now match byte-for-byte
      • encoded.ivf and encoded_rtl.ivf now match byte-for-byte
      • the decoded raw RTL IVF now matches both recon.yuv and the flat repeated-frame source exactly
      • the last frame-1 tile-data drift was the reduced single-ref cmp_ctx=2 / branch-0 CDF entry on the RTL path; it now matches the software reference at 3024
    • make entropy-check THREADS=$(nproc) BUILD_JOBS=$(nproc) passes in WSL and matches the C++ AV1RangeCoder byte-for-byte for bool, literal, and symbol cases
    • make bitstream-check THREADS=$(nproc) BUILD_JOBS=$(nproc) WIDTH=16 HEIGHT=16 now passes in WSL:
      • sequence header bytes match the reduced reference model exactly
      • video keyframe header bytes match the reduced reference model exactly
      • the new video inter-frame header bytes match the reduced reference model exactly
    • after adding non-key intra_inter, reduced inter-header ownership, and zero-motion inter scaffolding, the 16x16 top-level build still advances cleanly on the small all-key smoke path
    • the 16x16 1-frame all-key top-level smoke still decodes and matches recon.yuv exactly after the entropy-core upgrade
    • the same 16x16 smoke still decodes and matches recon.yuv after moving the skip symbol onto the RTL raw path
    • the same 16x16 smoke still decodes and matches recon.yuv after moving intra y_mode, zero angle_delta, and uv_mode=DC symbols onto the RTL raw path
    • the preserved RTL raw payload on that smoke case increased from 52 to 53 bytes after the intra-mode syntax move, confirming the raw path changed while the software decode path stayed stable
    • the same 16x16 smoke still decodes and matches recon.yuv after moving luma/chroma txb_skip entry symbols onto the RTL raw path
    • the preserved RTL raw payload on that smoke case increased again from 53 to 56 bytes after the txb_skip move, confirming the clean rebuild picked up the new raw syntax
    • a 16x16 1-frame all-key smoke at qindex=255 still decodes and matches recon.yuv after moving the first real DC-only luma coefficient syntax slice onto the RTL raw path
    • on that qindex=255 smoke, the preserved RTL raw payload dropped from 28 bytes to 20, which is consistent with replacing the old placeholder coefficient-presence stream for the lone non-skip block
    • a 16x16 1-frame all-key smoke at qindex=128 still decodes and matches recon.yuv after extending that DC-only slice through the bounded coeff_br path
    • on that qindex=128 smoke, the preserved RTL raw payload dropped from 48 bytes to 28, which indicates all four current DC-only luma blocks moved off the placeholder coefficient stream and onto the real DC-only coefficient path
    • the focused 16x16 data/ac_probe_16x16_1f.yuv still-picture check at qindex=240 now decodes and matches recon.yuv exactly after:
      • correcting tb/av1_bitstream_writer.h to libaom's real default_scan_8x8
      • transposing the RTL inverse-path 8x8 coefficient matrix before IDCT
      • fixing left-only / top-only non-directional intra edge fallback in rtl/av1_intra_pred.v
    • the same focused 16x16 data/ac_probe_16x16_1f.yuv check at qindex=240 still decodes and matches recon.yuv exactly after moving the first sparse low-order AC subset onto the RTL raw path
    • on that sparse-AC check, the preserved RTL raw payload is now 35 bytes and both aomdec and ffmpeg decode outputs match recon.yuv bit-for-bit
    • the same focused 16x16 data/ac_probe_16x16_1f.yuv check at qindex=240 still decodes and matches recon.yuv exactly after moving the first dense low-order eob=9 subset onto the RTL raw path
    • on that exact-match probe, the preserved RTL raw payload dropped again from 35 bytes to 29, which indicates the last remaining dense luma block on that clip moved off the placeholder coefficient bool stream and onto the real coefficient path
    • after the current mux fix, the isolated highdc_16x16_1f ownership repro no longer corrupts the raw RTL byte stream:
      • encoded.obu and encoded_rtl_raw.obu match byte-for-byte again
      • the written entropy byte sequence now matches the shadow AV1RangeCoder output exactly on the same run
    • the current qindex=1 failing repros are shared bugs, not writer-vs-RTL drift:
      • output/highdc_q1/encoded.obu and output/highdc_q1/encoded_rtl_raw.obu match byte-for-byte
      • output/crop560_q1/encoded.obu and output/crop560_q1/encoded_rtl_raw.obu match byte-for-byte
    • a local upstream AOM reference decoder build with CONFIG_ACCOUNTING=1 and CONFIG_INSPECTION=1 is now available for stricter syntax validation alongside ffmpeg/libdav1d
    • the video-keyframe path on that same 16x16 data/ac_probe_16x16_1f.yuv probe is now exact again, not just the reduced still-picture path:
      • the missing refresh_frame_context bit in the non-still frame header was restored before tile_info
      • the remaining 22-byte luma drift was traced to a predictor/config mismatch, not coefficients: the sequence header advertises enable_intra_edge_filter=0, so libaom disables both directional edge filtering and directional edge upsampling
      • the RTL directional predictor now keeps edge upsampling disabled on the current bitstream configuration, which restores bit-exact decoded-vs-recon.yuv matching on both the still-picture and video-keyframe outputs of the focused AC probe
    • the current 16x16 data/tmp_probe_16x16_1f.yuv local fallback still packages the captured RTL byte path directly into encoded_rtl.ivf
    • on that local fallback, software-owned and RTL-owned outputs still decode cleanly to recon.yuv, but they are not byte-exact in this checkout:
      • encoded.obu vs encoded_rtl_raw.obu first differ at byte 14
      • a temporary rtl/av1_encoder_top.v revert shows the same 34 vs 35 byte drift, so do not treat that clip as a regression caused by the new inter-path change
    • the strict 16x16 single-frame q sweeps remain exact on the natural DC-only crop, while the original data/ac_probe_16x16_1f.yuv exact-match gate is currently unavailable in this checkout:
      • output/natural_focus_x640_y360_q128/input.yuv now matches byte-for-byte between encoded.obu and encoded_rtl_raw.obu from qindex=1 through qindex=240
      • decoded output matches recon.yuv on representative low and high q cases for that crop after the DC-base fix
    • the raw RTL path now follows the same partition-tree leaf order as the software writer inside each superblock:
      • rtl/av1_encoder_top.v advances blocks in Morton / recursive split order instead of plain raster order
      • this cleared the first larger-frame ownership drift that appeared after the 16x16 fixes
    • single-frame natural-content ownership now scales beyond the 16x16 probes:
      • a 32x32 qindex=128 Big Buck Bunny crop now matches byte-for-byte between encoded.obu and encoded_rtl_raw.obu
      • a 64x64 qindex=128 Big Buck Bunny crop now matches byte-for-byte between encoded.obu and encoded_rtl_raw.obu
      • on both of those larger single-frame checks, software-owned and RTL-owned IVF outputs decode back to recon.yuv exactly
    • the first larger natural-content repeated-frame zero-motion inter checkpoint is now exact on the RTL byte path:
      • data/natural_repeat64_x640_y360_2f.yuv is a 64x64 repeated-frame crop built from frame 0 of data/raw_frames.yuv at (640,360)
      • at qindex=128, encoded.obu and encoded_rtl_raw.obu now match byte-for-byte
      • at that same checkpoint, encoded.ivf and encoded_rtl.ivf now match byte-for-byte and the decoded RTL IVF matches recon.yuv
      • the last drift on that clip was zero-motion inter blocks still taking the placeholder coefficient path and the intra tx_type CDF; rtl/av1_encoder_top.v now routes them through the real generic coefficient path and the inter DCT_DCT CDF
    • reduced single-reference natural-motion ownership now extends beyond the repeated-frame zero-motion cases:
      • data/natural_motion64_x640_y360_2f.yuv at 64x64, qindex=128, and 2 frames is byte-exact between software-owned and RTL-owned OBU/IVF outputs, and the decoded RTL IVF matches recon.yuv
      • data/natural_motion64_x640_y360_3f.yuv at 64x64, qindex=128, and 3 frames is byte-exact between software-owned and RTL-owned OBU/IVF outputs, and the decoded RTL IVF matches recon.yuv
      • data/natural_motion32_x640_y360_3f.yuv at 32x32, qindex=128, and 3 frames is byte-exact between software-owned and RTL-owned OBU/IVF outputs, and the decoded RTL IVF matches recon.yuv
      • the first motion-path drift on that bring-up was not MV payload packing; it was mis-ported raw refmv / drl probabilities instead of the actual AV1 ICDF entries, and correcting those ICDF values restored exactness on the motion clips
    • the longer-motion exactness guards now extend past the earlier 3-frame limit after the ME bottom-right zero-skip fix:
      • output/natural_motion32_x640_y360_5f_fix1/: 32x32, 5 frames, qindex=128, byte-exact between software-owned and RTL-owned OBU/IVF outputs, decoded RTL IVF matches recon.yuv
      • output/natural_motion64_x640_y360_5f_fix1/: 64x64, 5 frames, qindex=128, byte-exact between software-owned and RTL-owned OBU/IVF outputs, decoded RTL IVF matches recon.yuv
      • output/natural_motion64_x640_y360_6f_fix1/: 64x64, 6 frames, qindex=128, byte-exact between software-owned and RTL-owned OBU/IVF outputs, decoded RTL IVF matches recon.yuv
      • output/natural_motion64_x640_y360_7f_fixmvref64/: 64x64, 7 frames, qindex=128, byte-exact between software-owned and RTL-owned OBU/IVF outputs, strict aomdec output matches recon.yuv
      • output/natural_motion64_x640_y360_10f_progress70m/: 64x64, 10 frames, qindex=128, byte-exact between software-owned and RTL-owned OBU/IVF outputs, strict aomdec output matches recon.yuv
      • the first longer-sequence drift was not MV payload packing; the reduced ref-MV stack was reaching one row and one column farther than AOM's MVREF_ROW_COLS == 3 scan and was overweighting a later NEWMV candidate by +4
  • earlier 64x64 repeated-frame and debug_64x64_2f decoder-corruption cases were cleared on the reduced video path before the ME core update
  • the first real non-zero fractional-pel translational checkpoint on the reduced single-reference LAST path is now exact:
    • make THREADS=1 BUILD_JOBS=1 me-check passes and confirms the half-pel refine search is active
    • make THREADS=1 BUILD_JOBS=1 WIDTH=32 HEIGHT=32 natural32-ip-fractional-syntax-check natural32-ip-newmv-syntax-check natural32-ip-syntax-check passes with encoded.obu == encoded_rtl_raw.obu, encoded.ivf == encoded_rtl.ivf, and FFmpeg/libdav1d plus aomdec decode-vs-recon.yuv parity on the named 32x32 fixtures
    • make THREADS=1 BUILD_JOBS=1 natural32-chroma-syntax-check nonzero-chroma16-syntax-check nonzero-chroma-syntax-check passes with the same raw-byte and public-decoder parity on the named chroma fixtures
    • make THREADS=1 BUILD_JOBS=1 natural64-ip-fractional-syntax-check passes with encoded.obu == encoded_rtl_raw.obu, encoded.ivf == encoded_rtl.ivf, and FFmpeg/libdav1d plus aomdec parity on the 64x64 natural-motion guard
    • this is the first real non-zero fractional-pel translational motion on the reduced single-reference LAST path; it does not yet prove full AV1, multi-reference inter, arbitrary natural-motion coverage, or final 1280x720@24fps Big Buck Bunny validation, and the software writer/testbench still serves as the oracle where applicable
  • Broken:
    • decoded output is not yet verified as coming from a fully RTL-owned final AV1 syntax path
  • Placeholder or debug-only:
    • the current AV1 writer in tb/ is still being used as a software debug assembly path
    • chroma handling is still simplified relative to full AV1 completion
  • Missing:
    • full RTL-owned AV1 byte generation for completion
    • remaining roadmap items from av1-reference-docs/svt-av1-feature-inventory.md
    • final target clip validation at 1280x720 @ 24 fps
  • Not RTL-owned yet:
    • final sequence header / frame header / tile / block syntax generation is still not fully emitted by the RTL byte path in the completion-ready form required by this project

Latest Chud PC 2 RTL proof progress

Reduced P5 lossy TX_8X8 coefficient-syntax checkpoint

  • Added a public-decoder proof for the fixed large-DC lossy path at qindex=1:
    • make THREADS=1 BUILD_JOBS=1 p5-highdc-q1-public-check builds a 16x16 all-key probe, prints a per-block coefficient summary, and requires RTL raw OBU equality, RTL IVF equality, FFmpeg/libdav1d decode-to-recon.yuv, and aomdec parity.
  • Scope note: broader multi-block / wider-geometry coefficient diversity remains future work.

Multi-block non-zero chroma TX_4X4 syntax checkpoint

  • Added the next dynamic public-decoder proof for RTL-owned multi-block non-zero Cb/Cr coefficient syntax:

    • make THREADS=16 BUILD_JOBS=16 nonzero-chroma16-syntax-check builds a 16x16 all-key frame with flat luma and non-neutral chroma, forcing multiple 4x4 chroma transform blocks.
    • The gate verifies RTL raw OBU equals the software oracle OBU, then verifies FFmpeg/libdav1d and aomdec decode the RTL IVF back to RTL recon.yuv.
  • Root-cause fixes from this checkpoint:

    • Top-level intra chroma prediction now reads already-reconstructed current-frame Cb/Cr neighbors, matching the luma ref_rd_is_neigh pattern instead of falling back to constant 128 for every block.
    • The testbench chroma reference read mux now selects current-frame reconstructed chroma memory for neighbor reads and previous-frame chroma memory for inter prediction reads.
    • RTL now mirrors the oracle's Cb/Cr entropy context state for chroma txb_skip and DC-sign contexts across neighboring blocks.
    • New chroma-neighbor fetch states use unique state encodings so they do not collide with the chroma-only TX-type states.
  • The earlier one-block nonzero-chroma-syntax-check remains as the isolated 8x8 syntax gate; the new 16x16 gate closes the first multi-block non-flat chroma blocker.

  • Added the next 32x32 natural-ish all-key gate:

    • make THREADS=16 BUILD_JOBS=16 natural32-chroma-syntax-check builds a 32x32 deterministic gradient probe with non-flat luma and chroma.
    • Root cause fixed here: TS_TXB_SKIP_CB / TS_TXB_SKIP_CR selected cur_txb_chr_icdf while updating chr_syntax_plane in the same cycle, so multi-block frames could swap Cb/Cr txb contexts. Those states now select the Cb/Cr plane explicitly.
    • The 32x32 gate verifies RTL raw OBU equality plus FFmpeg/libdav1d and aomdec decode-vs-recon.yuv parity.
  • Added a 32x32 two-frame zero-MV inter residual gate:

    • make THREADS=16 BUILD_JOBS=16 natural32-ip-syntax-check builds two repeated natural-ish 32x32 frames with +all_key=0 and RTL me_zero_mv_only_in enabled.
    • This proves the reduced LAST-frame inter path can emit RTL-owned P-frame bytes with natural-ish non-zero residuals while keeping motion-vector syntax deterministic.
    • The gate verifies concatenated RTL raw OBU equality plus FFmpeg/libdav1d and aomdec decode-vs-recon.yuv parity across both frames.
    • Parallel scouting found unconstrained 32x32 non-zero-MV natural IP still exposes a public-decoder/recon mismatch; that remains the next motion-specific blocker rather than mixing it into this zero-MV residual checkpoint.
  • Added the first top-level chroma residual plumbing slice after the TX_4X4 table checkpoint:

    • av1_encoder_top now instantiates av1_chroma_residual and runs it for each 4x4 Cb/Cr block before chroma reference write-back.
    • The top-level stores public Verilator-visible chr_cb_qcoeff[], chr_cr_qcoeff[], chr_cb_has_coeff, and chr_cr_has_coeff for the software oracle / ownership path.
    • tb/av1_bitstream_writer.h BlockInfo and tb/tb_av1_encoder.cpp now carry/capture those Cb/Cr qcoeff fields.
    • tb/test_top_chroma_integration.py plus make top-chroma-integration-check guard that the top-level does not regress to predictor-only chroma.
  • Important fix from this slice: raw chroma fetch and chroma inter prediction complete on different cycles, so TS_CHR_WAIT latches their done pulses (chr_fetch_seen / chr_pred_seen) instead of requiring same-cycle completion. The old same-cycle wait caused the 16x16 2-frame IP smoke to hang in state 30.

  • Verified after the fix: generated 16x16 all-key and 2-frame IP smoke still pass raw OBU exactness, IVF exactness, FFmpeg/libdav1d decode-vs-recon.yuv, and aomdec decode-vs-recon.yuv.

  • The first constrained non-zero Cb/Cr TX_4X4 syntax proof is now in place for a one-block 8x8 all-key probe; broader 16x16+ non-flat chroma proof still needs decoder-matching chroma intra-neighbor prediction.

Known Gaps

  • The final AV1 bitstream is not yet fully generated by the RTL byte path.
  • The current tb/ writer remains a debug and bring-up tool, not the acceptable final ownership model.
  • The preserved *_rtl_raw.obu artifacts and the new *_rtl.ivf packaging are ownership checkpoints only; they are not yet completion-ready AV1 streams.
  • The current generated 16x16 all-key and 2-frame IP Chud PC 2 smoke cases are byte-exact between software-owned and RTL-owned raw/IVF artifacts and decode to recon.yuv; larger final-target/full-syntax ownership is still incomplete.
  • The entropy foundation is no longer the active blocker for tile ownership:
    • av1_entropy.v can now encode reference-matching bools, literals, and generic CDF symbols
    • the raw RTL path now also owns the block skip symbol
    • the raw RTL path now also owns the non-key intra_inter block symbol
    • the raw RTL path now also owns keyframe and intra-only y_mode, zero angle_delta, and deterministic uv_mode
    • the raw RTL path now also owns luma/chroma txb_skip entry symbols for the current reduced 8x8/4x4 transform subset
    • the raw RTL path now also owns a real DC-only luma coefficient slice for intra blocks with eob=1, bounded coeff_br, and neighbor-conditioned DC-sign context
    • the raw RTL path now also owns the first sparse low-order AC subset for the exact-match qindex=240 still-picture probe: eob=3, eob_extra=0, EOB coeff at flat index 1, zero base at flat index 8, and the corresponding DC/AC signs
    • the raw RTL path now also owns the first dense low-order AC subset on that same probe: eob=9, eob_extra=0, nonzeros at flat indices 0, 8, 1, and 10, the intervening zero bases, and the corresponding DC/AC signs
    • the current software-owned exact-match path now also has its video-keyframe header and directional predictor configuration back in sync with the decoder on the verified qindex=240 probe:
      • non-still frame headers now emit refresh_frame_context before tile_info
      • the predictor no longer applies directional edge upsampling while the bitstream still advertises enable_intra_edge_filter=0
    • the direct RTL-owned byte capture path is now aligned with the software-owned payload on the focused 16x16 ownership probe:
      • tb/tb_av1_encoder.cpp now records bs_byte_valid, ec_byte_valid, and explicit manual_bs_wr back-patches directly from the RTL top-level mux when building encoded_rtl_raw.obu / encoded_rtl.ivf
      • on the current 16x16 probe, that direct capture matches the software-owned encoded.obu payload byte-for-byte and decodes successfully once wrapped in IVF
    • the larger single-frame ownership drift is now fixed through the first natural-content 32x32 and 64x64 cases:
      • the raw RTL path now advances blocks in the same recursive partition-tree / Morton order that the writer and decoder expect inside each superblock
      • this removed the first 32x32 payload divergence that appeared once the frame needed more than the original 16x16 exact-match traversal
    • the remaining ownership gap is extending that reduced non-DC path and matching syntax ownership beyond the current single-frame keyframe subset:
      • full multi-frame / non-key ownership beyond the current reduced non-key header and the verified reduced LAST-ref motion checkpoints
      • full inter syntax and motion signaling on the RTL path beyond the current reduced single-reference LAST GLOBALMV / NEARESTMV / NEWMV ownership subset with integer MV payloads
      • less constrained dense and higher-energy coefficient shapes beyond the current regression clips
  • The current active exactness regression is now reference-decoder-backed:
    • the strict output/highdc_q1/ first-block bug is now fixed:
      • the software debug writer and the RTL-owned raw path now both select the correct official TX_8X8 qctx tables from qindex
      • AOM inspection now parses all four intended large-DC blocks at qindex=1 as tx_size=1, eob=1, with the expected Golomb tail
      • ffmpeg now decodes output/highdc_q1/encoded.ivf, and decoded.yuv matches recon.yuv bit-for-bit on that repro
    • the current P5 reduced-subset coefficient probes now have decoder-backed guards:
      • make p5-highdc-q1-public-check proves the high-DC / non-zero-AC qindex=1 lane through raw OBU equality, IVF equality, and ffmpeg / aomdec decode-to-recon parity
    • qindex=0 remains a deferred lossless / TX_4X4 feature, not part of the current supported reduced subset:
      • AOM reference inspection shows the decoder entering the lossless TX_4X4 path (tx_size=0) when base_q_idx=0
      • until that separate lossless path is implemented, the testbench and RTL clamp requested qindex=0 runs to effective qindex=1 so the current subset does not emit invalid streams
  • Full P-frame/inter-frame AV1 syntax support is still incomplete.
  • The current raw-path inter subset now covers reduced single-reference LAST GLOBALMV, NEARESTMV, and NEWMV with reduced neighboring ref-MV stack derivation plus the first syntax-only subpel ownership slice:
    • the reduced inter frame header now signals force_integer_mv=0 and allow_high_precision_mv=1
    • reduced NEWMV components now emit the real mv_fr and mv_hp symbols on both the software debug writer path and the RTL-owned syntax path
  • The strict raw-path inter checkpoints are now cleared on both the zero-motion repeated-frame cases and the first natural-motion cases:
    • the 16x16 2-frame flat repeated-frame IP repro is byte-exact between software-owned and RTL-owned OBU/IVF outputs
    • the 64x64 2-frame data/natural_repeat64_x640_y360_2f.yuv crop is byte-exact between software-owned and RTL-owned OBU/IVF outputs, and the decoded RTL IVF matches recon.yuv
    • the 64x64 2-frame and 3-frame data/natural_motion64_x640_y360_*f.yuv crops are byte-exact between software-owned and RTL-owned OBU/IVF outputs, and the decoded RTL IVF matches recon.yuv
    • the 32x32 3-frame data/natural_motion32_x640_y360_3f.yuv crop is byte-exact between software-owned and RTL-owned OBU/IVF outputs, and the decoded RTL IVF matches recon.yuv
    • output/natural_motion32_x640_y360_5f_fix1/ and output/natural_motion64_x640_y360_5f_fix1/ are byte-exact at 5 frames, output/natural_motion64_x640_y360_6f_fix1/ is byte-exact at 6 frames, output/natural_motion64_x640_y360_7f_fixmvref64/ is byte-exact at 7 frames, and output/natural_motion64_x640_y360_10f_progress70m/ is byte-exact at 10 frames
    • output/natural_motion64_x640_y360_2f_subpel2/, output/natural_motion64_x640_y360_7f_subpel2/, and output/natural_motion64_x640_y360_10f_subpel2/ now keep that same exactness after the syntax-only subpel header / payload move, and strict aomdec output still matches recon.yuv
    • the 64x64 full-coeff low-delay LAST gradient gate is currently public-decoder clean through the first 40 requested non-zero integer motion blocks under the reduced cap (39 NEWMV payload blocks plus one stack-hit NEARESTMV block): RTL raw OBU and IVF match the software oracle, and FFmpeg/libdav1d plus aomdec decode back to recon.yuv
    • the repaired longer-motion root cause was the reduced ref-MV stack reach, not the MV payload encoder itself: matching AOM's MVREF_ROW_COLS == 3 scan removed the extra far-neighbor weight that had been flipping later NEWMV references
    • the first strict decoder corruption after enabling subpel syntax was shared writer/RTL syntax, not ownership drift:
      • mv_hp was missing after mv_fr on reduced NEWMV components
      • allow_high_precision_mv was missing in the reduced inter frame header after force_integer_mv=0
    • the next remaining inter ownership work is widening beyond the current reduced single-reference LAST syntax-only subpel subset into broader natural-motion clips and reference-MV-context debugging
  • Real chroma residual coding and fuller chroma tool coverage remain incomplete.
  • The old 17/18-block NEWMV threshold is no longer the active blocker.
  • The current active blockers are:
    • unrestricted 64x64+ full-coeff NEWMV / reference-stack / MV-prediction parity beyond the current reduced cap; do not treat cap raises as final completion
    • moving final AV1 syntax ownership out of tb/av1_bitstream_writer.h and onto the RTL byte path
    • extending the verified qindex=1+ reduced subset beyond the current single-frame coefficient, partition, and syntax checkpoints
    • implementing the separate deferred qindex=0 / lossless TX_4X4 path instead of clamping it to the supported floor
    • widening beyond the current reduced single-reference LAST motion subset into multi-reference/reference-MV-context coverage on broader natural clips
    • restoring the original data/ac_probe_16x16_1f.yuv local asset in this checkout, because data/tmp_probe_16x16_1f.yuv is decode-clean but not a byte-exact substitute ownership gate
  • A lightweight debug probe now exists in the testbench:
    • +dump_inter_summary=1 prints captured inter blocks, MVs, and nonzero counts after each frame
    • +dump_blocks=1 on output/highdc_q1/ and the local AOM inspect build are now the fastest strict large-DC regression guard for the fixed qctx-selected TX_8X8 path
    • data/ac_probe_16x16_1f.yuv remains the first exact-match regression gate at the verified qindex=240 subset
  • Larger roadmap phases in av1-reference-docs/svt-av1-feature-inventory.md are still open:
    • stronger inter syntax and motion signaling
    • better partitioning and mode decision
    • rate control beyond fixed QP
    • deblock, CDEF, restoration, and later quality tools
    • advanced deferred AV1 tools
  • The final target clip has not been completed from the RTL-generated AV1 path.

Completion Criteria

Do not treat this project as complete until all of the following are true:

  • the AV1 stream is produced by the RTL byte path
  • the stream decodes correctly end to end
  • the decoded output has been visually verified against the source
  • the final target clip has been produced at 1280x720 @ 24 fps
  • the remaining major gaps against full AV1 standard support are closed, or the repo clearly and honestly documents any still-open non-completion blockers

Recommended Run Flow

Use the repo scripts for broad runs, and use a small 64x64 focused check when validating bitstream, syntax, and reconstruction changes quickly.

Broad run (use the live CPU count; on Chud PC 2 this is currently 16):

THREADS=$(nproc) BUILD_JOBS=$(nproc) bash run.sh

Focused verification flow on Chud PC 2:

cd tb
make THREADS=16 BUILD_JOBS=16 WIDTH=64 HEIGHT=64
./Vav1_encoder_top +frames=1 +qindex=128 +dc_only=0 +ownership_strict=1 +input=../data/raw_frames.yuv +output=../output/encoded.obu
python3 test_rtl_obu_ivf_integrity.py --output-dir ../output --frames 1

Fast header regression:

cd tb
make THREADS=16 BUILD_JOBS=16 WIDTH=16 HEIGHT=16 bitstream-check

Standalone entropy verification:

cd tb
make entropy-check THREADS=16 BUILD_JOBS=16

Strict bitstream ownership gate:

cd tb
make THREADS=16 BUILD_JOBS=16 bitstream-ownership-check

For exact reconstruction checks, decode the generated RTL IVF (encoded_rtl.ivf) and compare it against output/recon.yuv. For RTL ownership debug, inspect rtl_frames/frame_XXXX_rtl_raw.obu and the concatenated *_rtl_raw.obu written beside the software-oracle encoded.obu / encoded.ivf outputs. In +ownership_strict=1, the testbench also writes *_sw_oracle.obu / *_sw_oracle.ivf aliases and refuses byte-count mismatches or writer-only repair knobs.

For inter bring-up, use the repeated-frame 64x64 clip first to clear the zero-motion gate, then move to data/natural_motion64_x640_y360_2f.yuv or data/natural_motion64_x640_y360_3f.yuv for the reduced motion subset. If a syntax blocker appears, check av1-reference-docs/external/README.md first and refresh that folder from official sources before guessing. For ref-MV / NEWMV bring-up, use +dump_inter_summary=1 together with RTL-owned controls such as +me_newmv_limit= so the first decoder-failing MV threshold can be isolated quickly. Do not use writer-only reducers such as +limit_newmv_blocks= in ownership gates. The reduced motion guards now extend cleanly through the repaired 64x64 7-frame and 10-frame natural-motion cases. Use output/natural_motion64_x640_y360_10f_progress70m/ as the long exact guard and budget +timeout=70000000 or higher when rerunning it. For raw-path syntax moves, keep a 16x16 1-frame all-key smoke in the loop first so decoded output vs recon.yuv can be rechecked quickly after each block-syntax change. For sparse AC bring-up, keep data/ac_probe_16x16_1f.yuv in the loop as the first exact-match regression check at the verified qindex=240 subset. Use output/highdc_q1/ plus make p5-highdc-q1-public-check as the strict large-DC regression guard for the fixed qctx-selected TX_8X8 path, and treat requested qindex=0 runs as a deferred lossless / TX_4X4 task that currently clamps to effective qindex=1.

Chud PC 2 Verilator Check - 2026-05-02

Verified directly on Chud PC 2 (chudpc2-MS-7C91, Verilator 5.020, nproc=16):

  • make THREADS=16 BUILD_JOBS=16 entropy-check passes.
  • make THREADS=16 BUILD_JOBS=16 WIDTH=16 HEIGHT=16 bitstream-check passes.
  • make THREADS=16 BUILD_JOBS=16 inv-xform-check passes.
  • The top-level 16x16 Verilator build now compiles on Chud PC 2 after removing function-call result slicing that Verilator 5.020 rejects and avoiding mixed blocking/nonblocking assignments to intra_cand_sad.
  • A generated 16x16 flat all-key RTL IVF decodes in both FFmpeg/libdav1d and aomdec, and decoded output matches recon.yuv.

Current Chud PC 2 ownership status:

  • The earlier generated non-flat 16x16 all-key and flat 16x16 2-frame IP raw-stream drift has been fixed in the RTL byte path.
  • Keep THREADS=16 BUILD_JOBS=16 on Chud PC 2 and run make bitstream-ownership-check for the strict no-repair gate. The gate requires raw RTL OBU equality against the software oracle, RTL IVF payload equality against raw RTL OBU bytes, FFmpeg/libdav1d decode-vs-recon.yuv, and aomdec decode-vs-recon.yuv.
  • The current operating point remains static CDF / disable_cdf_update=1; do not claim adaptive CDF ownership until RTL owns CDF update state and a dedicated gate covers it.

Verification Rules

  • The RTL-generated stream must decode successfully.
  • Visual verification matters, not just parser acceptance.
  • Compare decoded RTL output against the source clip.
  • Use PSNR / SSIM where useful, but do not treat metrics alone as completion.
  • Preserve simulator logs and cycle counts for repeatable validation runs.
  • Always sanity-check behavior against a software AV1 encode of the same source.
  • Keep the decoded output on a valid path toward the final RTL-generated bitstream requirement.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages