litex/milkymist/framebuffer/dvi.py

147 lines
3.3 KiB
Python
Raw Normal View History

from migen.fhdl.std import *
from migen.genlib.misc import optree
control_tokens = [0b1101010100, 0b0010101011, 0b0101010100, 0b1010101011]
class Encoder(Module):
def __init__(self):
self.d = Signal(8)
self.c = Signal(2)
self.de = Signal()
self.out = Signal(10)
###
# stage 1 - count number of 1s in data
d = Signal(8)
n1d = Signal(max=9)
self.sync += [
n1d.eq(optree("+", [self.d[i] for i in range(8)])),
d.eq(self.d)
]
# stage 2 - add 9th bit
q_m = Signal(9)
q_m8_n = Signal()
self.comb += q_m8_n.eq((n1d > 4) | ((n1d == 4) & ~d[0]))
for i in range(8):
if i:
curval = curval ^ d[i] ^ q_m8_n
else:
curval = d[0]
self.sync += q_m[i].eq(curval)
self.sync += q_m[8].eq(~q_m8_n)
# stage 3 - count number of 1s and 0s in q_m[:8]
q_m_r = Signal(9)
n0q_m = Signal(max=9)
n1q_m = Signal(max=9)
self.sync += [
n0q_m.eq(optree("+", [~q_m[i] for i in range(8)])),
n1q_m.eq(optree("+", [q_m[i] for i in range(8)])),
q_m_r.eq(q_m)
]
# stage 4 - final encoding
cnt = Signal((6, True))
s_c = self.c
s_de = self.de
for p in range(3):
new_c = Signal(2)
new_de = Signal()
self.sync += new_c.eq(s_c), new_de.eq(s_de)
s_c, s_de = new_c, new_de
self.sync += If(s_de,
If((cnt == 0) | (n1q_m == n0q_m),
self.out[9].eq(~q_m_r[8]),
self.out[8].eq(q_m_r[8]),
If(q_m_r[8],
self.out[:8].eq(q_m_r[:8]),
cnt.eq(cnt + n1q_m - n0q_m)
).Else(
self.out[:8].eq(~q_m_r[:8]),
cnt.eq(cnt + n0q_m - n1q_m)
)
).Else(
If((~cnt[5] & (n1q_m > n0q_m)) | (cnt[5] & (n0q_m > n1q_m)),
self.out[9].eq(1),
self.out[8].eq(q_m_r[8]),
self.out[:8].eq(~q_m_r[:8]),
cnt.eq(cnt + Cat(0, q_m_r[8]) + n0q_m - n1q_m)
).Else(
self.out[9].eq(0),
self.out[8].eq(q_m_r[8]),
self.out[:8].eq(q_m_r[:8]),
cnt.eq(cnt - Cat(0, ~q_m_r[8]) + n1q_m - n0q_m)
)
)
).Else(
self.out.eq(Array(control_tokens)[s_c]),
cnt.eq(0)
)
class _EncoderTB(Module):
def __init__(self, inputs):
self.outs = []
self._iter_inputs = iter(inputs)
self._end_cycle = None
self.submodules.dut = Encoder()
self.comb += self.dut.de.eq(1)
def do_simulation(self, s):
if self._end_cycle is None:
try:
nv = next(self._iter_inputs)
except StopIteration:
self._end_cycle = s.cycle_counter + 4
else:
s.wr(self.dut.d, nv)
if s.cycle_counter == self._end_cycle:
s.interrupt = True
if s.cycle_counter > 4:
self.outs.append(s.rd(self.dut.out))
def _bit(i, n):
return (i >> n) & 1
def _decode_tmds(b):
try:
c = control_tokens.index(b)
de = False
except ValueError:
c = 0
de = True
vsync = bool(c & 2)
hsync = bool(c & 1)
value = _bit(b, 0) ^ _bit(b, 9)
for i in range(1, 8):
value |= (_bit(b, i) ^ _bit(b, i-1) ^ (~_bit(b, 8) & 1)) << i
return de, hsync, vsync, value
if __name__ == "__main__":
from migen.sim.generic import Simulator
from random import Random
rng = Random(788)
test_list = [rng.randrange(256) for i in range(500)]
tb = _EncoderTB(test_list)
Simulator(tb).run()
check = [_decode_tmds(out)[3] for out in tb.outs]
assert(check == test_list)
nb0 = 0
nb1 = 0
for out in tb.outs:
for i in range(10):
if _bit(out, i):
nb1 += 1
else:
nb0 += 1
print("0/1: {}/{} ({:.2f})".format(nb0, nb1, nb0/nb1))