Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
#
# This file is part of LiteX.
#
# Copyright (c) 2026 Florent Kermarrec <florent@enjoy-digital.fr>
# SPDX-License-Identifier: BSD-2-Clause
import unittest
import random
from migen import *
from litex.soc.cores.code_tmds import TMDSEncoder, control_tokens
# Reference Model ----------------------------------------------------------------------------------
def tmds_encode(d, c, de, cnt):
"""Pure-Python reference TMDS encoder (DVI 1.0).
Returns (out10, new_cnt).
"""
if not de:
return control_tokens[c & 0x3], 0
d = d & 0xff
n1d = bin(d).count("1")
# Stage 1: q_m = XOR or XNOR chain, q_m[8] signals which.
q_m = [d & 1] + [0]*8
if n1d > 4 or (n1d == 4 and (d & 1) == 0):
for i in range(1, 8):
q_m[i] = q_m[i-1] ^ ((d >> i) & 1) ^ 1
q_m[8] = 0
else:
for i in range(1, 8):
q_m[i] = q_m[i-1] ^ ((d >> i) & 1)
q_m[8] = 1
n1 = sum(q_m[:8])
n0 = 8 - n1
# Stage 2: DC-balance.
if cnt == 0 or n1 == n0:
out9 = 1 ^ q_m[8]
out8 = q_m[8]
if q_m[8]:
out07 = q_m[:8]
new_cnt = cnt + n1 - n0
else:
out07 = [1 ^ b for b in q_m[:8]]
new_cnt = cnt + n0 - n1
elif (cnt > 0 and n1 > n0) or (cnt < 0 and n0 > n1):
out9 = 1
out8 = q_m[8]
out07 = [1 ^ b for b in q_m[:8]]
new_cnt = cnt + 2*q_m[8] + n0 - n1
else:
out9 = 0
out8 = q_m[8]
out07 = q_m[:8]
new_cnt = cnt - 2*(1 - q_m[8]) + n1 - n0
out = (out9 << 9) | (out8 << 8)
for i, b in enumerate(out07):
out |= (b & 1) << i
return out, new_cnt
# Helpers ------------------------------------------------------------------------------------------
# The hardware TMDSEncoder has a 4-stage pipeline (d → q_m → q_m_r → out, and a matching 3-stage
# pipeline on c/de before the final stage).
TMDS_LATENCY = 4
def run_encoder(items, flush=TMDS_LATENCY + 4):
"""Drive `items` = list of (d, c, de) through a TMDSEncoder and return sampled `out` per cycle."""
dut = TMDSEncoder()
outputs = []
def pump():
for d, c, de in items:
yield dut.d.eq(d)
yield dut.c.eq(c)
yield dut.de.eq(de)
yield
outputs.append((yield dut.out))
yield dut.de.eq(0)
for _ in range(flush):
yield
outputs.append((yield dut.out))
run_simulation(dut, pump())
return outputs
# Tests --------------------------------------------------------------------------------------------
class TestCodeTMDS(unittest.TestCase):
def test_control_tokens(self):
# Drive each of the 4 control codes with de=0 for a few cycles and check the matching
# token appears on the output after the pipeline latency.
items = []
for c in range(4):
items += [(0, c, 0)]*6
outputs = run_encoder(items)
for i in range(TMDS_LATENCY, len(items)):
_, c, _ = items[i - TMDS_LATENCY]
self.assertEqual(outputs[i], control_tokens[c],
f"i={i} c={c}: got 0b{outputs[i]:010b}, want 0b{control_tokens[c]:010b}")
def test_against_reference(self):
# Fuzz 1000 random bytes against the reference model.
prng = random.Random(42)
items = [(prng.randrange(256), 0, 1) for _ in range(1000)]
# Prime pipeline with a few control cycles so the initial cnt is zero and well defined.
priming = [(0, 0, 0)]*TMDS_LATENCY
outputs = run_encoder(priming + items)
cnt = 0
expected = []
for d, c, de in priming + items:
e, cnt = tmds_encode(d, c, de, cnt)
expected.append(e)
for i in range(TMDS_LATENCY, len(priming + items)):
src = priming + items
self.assertEqual(outputs[i], expected[i - TMDS_LATENCY],
f"i={i} d=0x{src[i - TMDS_LATENCY][0]:02x}: "
f"got 0b{outputs[i]:010b}, want 0b{expected[i - TMDS_LATENCY]:010b}")
def test_de_transition(self):
# Exiting the control region should reset cnt to 0, so a sequence starting from a
# control→data transition must match the reference model starting at cnt=0.
prng = random.Random(7)
datas = [(prng.randrange(256), 0, 1) for _ in range(64)]
items = [(0, 0, 0)]*8 + datas
outputs = run_encoder(items)
cnt = 0
expected = []
for d, c, de in items:
e, cnt = tmds_encode(d, c, de, cnt)
expected.append(e)
for i in range(TMDS_LATENCY, len(items)):
self.assertEqual(outputs[i], expected[i - TMDS_LATENCY])
if __name__ == "__main__":
unittest.main()
d66325f4eThis file is pinned to the selected release. Download the original to open it in your design tool.