Source code for hwtLib.logic.binToBcd
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from math import ceil, log10
from hwt.code import If, Switch, Concat
from hwt.hdl.types.bits import Bits
from hwt.hdl.types.defs import BIT
from hwt.hdl.types.enum import HEnum
from hwt.interfaces.std import Handshaked
from hwt.interfaces.utils import addClkRstn
from hwt.math import log2ceil
from hwt.synthesizer.param import Param
from hwt.synthesizer.unit import Unit
[docs]class BinToBcd(Unit):
"""
Convert binary to BCD (Binary coded decimal) format
(BCD is a format where each 4 bites represents a single decimal digit 0-9)
based on https://github.com/kb000/bin2bcd/blob/master/rtl/bin2bcd32.v
.. hwt-autodoc::
"""
def _config(self):
self.INPUT_WIDTH = Param(64)
def _declr(self):
addClkRstn(self)
assert self.INPUT_WIDTH > 0, self.INPUT_WIDTH
self.DECIMAL_DIGITS = self.decadic_deciamls_for_bin(self.INPUT_WIDTH)
self.din = Handshaked()
self.din.DATA_WIDTH = self.INPUT_WIDTH
self.dout = Handshaked()._m()
self.dout.DATA_WIDTH = self.DECIMAL_DIGITS * 4
[docs] @staticmethod
def decadic_deciamls_for_bin(bin_width: int):
return ceil(log10(2 ** bin_width))
def _impl(self):
INPUT_WIDTH, DECIMAL_DIGITS, din, dout = \
self.INPUT_WIDTH, self.DECIMAL_DIGITS, self.din, self.dout
bin_r = self._reg("bin_r", Bits(INPUT_WIDTH, signed=False))
bitcount = self._reg("bitcount", Bits(log2ceil(INPUT_WIDTH), signed=False), def_val=0)
st_t = HEnum("st_t", ["idle", "busy", "fin"])
state = self._reg("state", st_t, def_val=st_t.idle)
din.rd(state._eq(st_t.idle))
dout.vld(state._eq(st_t.fin))
Switch(state)\
.Case(st_t.idle,
If(din.vld,
state(st_t.busy)
))\
.Case(st_t.busy,
If(bitcount._eq(INPUT_WIDTH - 1),
state(st_t.fin)
))\
.Case(st_t.fin,
If(dout.rd,
state(st_t.idle),
)
)
Switch(state)\
.Case(st_t.idle,
If(din.vld,
bin_r(din.data)
))\
.Case(st_t.busy,
bin_r(bin_r[INPUT_WIDTH - 1:]._concat(BIT.from_py(0)))) # bin_r <<= 1
Switch(state)\
.Case(st_t.busy,
bitcount(bitcount + 1))\
.Default(
bitcount(0))
bcdp = [self._sig(f"bcdp{i:d}", Bits(4, signed=False)) for i in range(DECIMAL_DIGITS)]
bcd_digits = []
for g in range(DECIMAL_DIGITS):
bcd = self._reg(f"bcd_{g:d}", Bits(4, signed=False), def_val=0)
bcdp[g]((bcd >= 5)._ternary(bcd + 3, bcd)),
prev = self._sig(f"prev_{g:d}", Bits(4))
if g != 0:
prev(bcdp[g - 1])
else:
prev(bin_r[INPUT_WIDTH-1]._concat(Bits(3).from_py(0)))
s = self._sig(f"s_{g:d}", Bits(4))
s(bcdp[g] << 1 | prev >> 3),
Switch(state)\
.Case(st_t.idle,
bcd(0))\
.Case(st_t.busy,
bcd(s))
bcd_digits.append(bcd)
dout.data(Concat(*reversed(bcd_digits)))
if __name__ == "__main__":
from hwt.synthesizer.utils import to_rtl_str
u = BinToBcd()
print(to_rtl_str(u))