For the 8b -> 10b encoder, we need to count 1
bits in the data word. For fun, we implement the 'gate level' model using half and full adders as shown below:
from cyhdl import *
import myirl
def half_adder(a, b, q, c):
return [
q.set(a ^ b), c.set(a & b)
]
def full_adder(a, b, cin, q, c):
x = a ^ b
return [
q.set(x ^ cin), c.set((a & b) | (cin & x))
]
Data8 = Signal.Type(intbv, 8)
Sum4 = Signal.Type(intbv, 4)
@myirl.block
def bit_count8(v : Data8, sum_ones : Sum4.Output):
s = [ Signal(bool()) for _ in range(8)]
c = [ Signal(bool()) for _ in range(8)]
logic = [
# (0) (1) (2)
# | | |
*full_adder(v[0], v[1], v[2], s[0], c[0]),
*full_adder(v[3], v[4], v[5], s[1], c[1]),
*half_adder(v[6], v[7], s[2], c[2]),
# | |
# (0) (1)
*full_adder(s[0], s[1], s[2], s[3], c[3]), # (0)
# | | |
*full_adder(c[0], c[1], c[2], s[4], c[4]), # (1)
# | | |
*half_adder(c[3], s[4], s[5], c[5]),
# | |
*half_adder(c[4], c[5], s[6], c[6]),
]
# | | | |
bits = [ s[3], s[5], s[6], c[6] ]
logic += [ sum_ones.set(concat(*reversed(bits))) ]
return logic
from myirl.kernel.components import LibraryModule, DesignModule
from myirl.kernel.sensitivity import process as logic_process
Bool = Signal.Type(bool)
Data10 = Signal.Type(intbv()[10:])
Data8 = Signal.Type(intbv()[8:])
Ctrl = Signal.Type(intbv()[2:])
# Reusable cascaded XOR/XNOR generator
def gen_scrambler(q, a, b, xnor):
@logic_process()
def assign_data(logic):
R = range(len(b)-1)
gen_xor = [ q[i+1].set(a[i] ^ b[i+1]) for i in R ]
gen_xnor = [ q[i+1].set(~(a[i] ^ b[i+1])) for i in R ]
logic += [
logic.If(xnor == True).Then(
*gen_xnor
).Else(
*gen_xor
)
]
return assign_data
class DVI10b8b(cyrite_factory.Module):
def __init__(self, arch, CONTROL_WORDS = [
0x354, 0x0ab, 0x154, 0x2ab
]):
self.CONTROL_WORDS = CONTROL_WORDS
super().__init__("dvilib", arch)
@cyrite_factory.block_component
def decoder(self,
clk : ClkSignal,
enable : Bool,
din : Data10,
dout : Data8.Output,
ctrl : Ctrl.Output,
de : Bool.Output
):
data = Data8()
data1 = Signal(intbv()[8:])
d = [ Bool() for _ in range(8) ]
wires = [
data1.wireup((concat(*reversed(d)))),
d[0].wireup(data[0])
]
@always_comb
def assign():
if din[9] == 1:
data.next = ~din[8:]
else:
data.next = din[8:]
# Create a gen_assign instance:
a = gen_scrambler(d, data, data, False)
@always(clk.posedge)
def worker():
if enable == True:
if din == self.CONTROL_WORDS[0]:
ctrl.next = 0
de.next = 0
elif din == self.CONTROL_WORDS[1]:
ctrl.next = 1
de.next = 0
elif din == self.CONTROL_WORDS[2]:
ctrl.next = 2
de.next = 0
elif din == self.CONTROL_WORDS[3]:
ctrl.next = 3
de.next = 0
else:
if din[8] == True:
dout.next = data1
else:
dout.next = concat(~data1[:1], d[0])
de.next = 1
else: # not enable
dout.next = 0
ctrl.next = 0
de.next = 0
return instances()
@cyrite_factory.block_component
def encoder(self,
clk : ClkSignal,
enable : Bool,
din : Data8,
dout : Data10.Output,
ctrl : Ctrl,
de : Bool.Output
):
ones_din = Signal(intbv(0, min=0, max=9))
ones_tmp = Signal(intbv(0, min=0, max=9))
diff_tmp = Signal(intbv(0, min=-8, max=9))
disp = Signal(modbv(0, min=-16, max=16))
switch = Bool()
dm, dp = [ Signal(intbv(min=-16, max=16)) for _ in range(2) ]
tmp = Signal(intbv(0)[9:])
msb, nmsb = [ Bool() for _ in range(2) ]
t = [ Bool() for _ in range(9) ]
wires = [
t[0].wireup(din[0]),
nmsb.wireup(~tmp[8]),
msb.wireup(tmp[8]),
tmp.wireup(concat(*reversed(t)))
]
# Generate another XOR/XNOR scrambler:
a = gen_scrambler(t, t, din, switch)
@always_comb
def switch_xnor():
if ones_din > 4 or (ones_din == 4 and t[0] == 0):
switch.next = True
t[8].next = False
else:
switch.next = False
t[8].next = True
# Instance '1' counters for 8 bit of the work register and data in
c1 = bit_count8(tmp[8:], ones_tmp)
c2 = bit_count8(din, ones_din)
@always(ones_tmp)
def count_ones_tmp():
diff_tmp.next = ones_tmp + (ones_tmp - 8).signed()
@always_comb
def diff():
dp.next = disp + diff_tmp
dm.next = disp - diff_tmp
@always(clk.posedge)
def worker():
de.next = enable
if enable == True:
if disp == 0 or ones_tmp == 4:
if t[8] == True:
dout.next = concat(nmsb, tmp[9:])
disp.next = dp
else:
dout.next = concat(nmsb, msb, ~tmp[8:])
disp.next = dm
else:
if (disp > 0 and ones_tmp > 4) or (disp < 0 and ones_tmp < 4):
dout.next = concat(True, msb, ~tmp[8:])
if t[8] == 1:
disp.next = (dm + 2)
else:
disp.next = dm
else:
dout.next = concat(False, tmp[9:])
if t[8] == 1:
disp.next = dp
else:
disp.next = (dp - 2)
else:
if ctrl == 0:
dout.next = self.CONTROL_WORDS[0]
elif ctrl == 1:
dout.next = self.CONTROL_WORDS[1]
elif ctrl == 2:
dout.next = self.CONTROL_WORDS[2]
else:
dout.next = self.CONTROL_WORDS[3]
disp.next = 0
return instances()
Then we create a function to emit a library:
from cyrite.simulation import ghdl
def create_library(Library):
lib = Library(ghdl.GHDL)
clk = ClkSignal()
enable = Bool()
din = Data8()
dout = Data10()
ctrl = Ctrl()
de = Bool()
libfiles = []
enc = lib.encoder(clk = clk, enable = enable, din = din, dout = dout, ctrl = ctrl, de = de)
libfiles += enc.elab(targets.VHDL, elab_all = True)
dec = lib.decoder(clk = clk, enable = enable, din = dout, dout = din, ctrl = ctrl, de = de)
libfiles += dec.elab(targets.VHDL, elab_all = True)
return libfiles
libfiles = create_library(DVI10b8b)
Declare obj 'encoder' in context '(DVI10b8b 'dvilib')'(<class '__main__.DVI10b8b'>) Module dvilib: Existing instance bit_count8, rename to bit_count8_1 Writing 'bit_count8_1' to file /tmp/myirl_dvilib_r0b76sty/bit_count8_1.vhdl Writing 'bit_count8' to file /tmp/myirl_dvilib_r0b76sty/bit_count8.vhdl Writing 'encoder' to file /tmp/myirl_dvilib_r0b76sty/encoder.vhdl Warning: Implicit truncation of ADD(ones_tmp, SGN(SUB(ones_tmp, C:8))) result Warning: Implicit truncation of ADD(disp, diff_tmp) result Warning: Implicit truncation of SUB(disp, diff_tmp) result Warning: Implicit truncation of ADD(dm, C:2) result Warning: Implicit truncation of SUB(dp, C:2) result Creating library file module_defs.vhdl Declare obj 'decoder' in context '(DVI10b8b 'dvilib')'(<class '__main__.DVI10b8b'>) Writing 'decoder' to file /tmp/myirl_dvilib_r0b76sty/decoder.vhdl Writing 'bit_count8_1' to file /tmp/myirl_dvilib_r0b76sty/bit_count8_1.vhdl Writing 'bit_count8' to file /tmp/myirl_dvilib_r0b76sty/bit_count8.vhdl Writing 'encoder' to file /tmp/myirl_dvilib_r0b76sty/encoder.vhdl Warning: Implicit truncation of ADD(ones_tmp, SGN(SUB(ones_tmp, C:8))) result Warning: Implicit truncation of ADD(disp, diff_tmp) result Warning: Implicit truncation of SUB(disp, diff_tmp) result Warning: Implicit truncation of ADD(dm, C:2) result Warning: Implicit truncation of SUB(dp, C:2) result Creating library file module_defs.vhdl
# !cat {libfiles[1]}
To loop in a known good encoder unit in VHDL, we create a black box stub.
The blackbox_ext
module contains a few @blackbox
descendants that automatically resolve to an existing VHDL or Verilog file.
from myirl.blackbox_ext import blackbox_vhdl
@blackbox_vhdl(path_prefix = 'video', extension = 'vhd')
def tmds_encoder(
clk : ClkSignal,
disp_ena : Bool,
control : Ctrl,
d_in : Data8,
q_out : Data10.Output
):
return []
The test bench for the loop back:
class TMDS_TestDesign(DVI10b8b):
@cyrite_factory.testbench('ns')
def test_tmds(self, PCLK_DURATION_NS = 1, VERIFY = True):
lib = self
clk = ClkSignal()
enable = Signal(bool(0))
de_enc, de_dec = [Signal(bool(0)) for i in range(2) ]
data10 = Data10()
data8 = Data8(0xff)
data8.init = True
ctrl_in, ctrl_out = [Ctrl() for _ in range(2)]
data8_return = Data8()
data10_ref = Data10()
data_delay0, data_delay1 = [ Data8() for _ in range(2) ]
enc_inst0 = lib.encoder(clk, enable, data8, data10, ctrl_in, de_enc)
if VERIFY:
enc_inst = tmds_encoder(clk = clk,
disp_ena = enable,
d_in = data8,
q_out = data10_ref,
control = ctrl_in)
# Verified:
dec_inst = lib.decoder(clk, de_enc, data10, data8_return, ctrl_out, de_dec)
@self.always(delay(1))
def clkgen():
clk.next = ~clk
@self.always(clk.posedge)
def stimulate():
data8.next = (data8 + 43)
data_delay1.next = data_delay0
data_delay0.next = data8
@self.always(clk.posedge)
def verify():
if de_dec == True:
# print(data_delay0, data_delay1, data8)
assert data_delay1 == data8_return
@self.sequence
def start():
enable.next = 0
ctrl_in.next = 0
yield delay(5)
yield delay(100)
enable.next = True
yield delay(10)
yield clk.negedge
yield delay(600)
enable.next = 0
raise StopSimulation
return instances()
from cyrite.simulation import ghdl
d = TMDS_TestDesign(ghdl.GHDL)
tb = d.test_tmds()
tb.run(2000)
Declare obj 'test_tmds' in context '(TMDS_TestDesign 'dvilib')'(<class '__main__.TMDS_TestDesign'>) PCLK_DURATION_NS: use default 1 VERIFY: use default True Declare obj 'encoder' in context '(TMDS_TestDesign 'dvilib')'(<class '__main__.TMDS_TestDesign'>) Module dvilib: Existing instance bit_count8, rename to bit_count8_2 Module dvilib: Existing instance bit_count8, rename to bit_count8_3 Declare obj 'decoder' in context '(TMDS_TestDesign 'dvilib')'(<class '__main__.TMDS_TestDesign'>) Writing 'decoder' to file /tmp/myirl_dvilib_zibtauyh/decoder.vhdl Writing 'bit_count8_3' to file /tmp/myirl_dvilib_zibtauyh/bit_count8_3.vhdl Writing 'bit_count8_2' to file /tmp/myirl_dvilib_zibtauyh/bit_count8_2.vhdl Writing 'encoder' to file /tmp/myirl_dvilib_zibtauyh/encoder.vhdl Warning: Implicit truncation of ADD(ones_tmp, SGN(SUB(ones_tmp, C:8))) result Warning: Implicit truncation of ADD(disp, diff_tmp) result Warning: Implicit truncation of SUB(disp, diff_tmp) result Warning: Implicit truncation of ADD(dm, C:2) result Warning: Implicit truncation of SUB(dp, C:2) result Writing 'test_tmds' to file /tmp/myirl_dvilib_zibtauyh/test_tmds.vhdl Warning: Implicit truncation of ADD(data8, C:43) result Creating library file module_defs.vhdl
0