#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from hwt.code import If, Switch, Concat
from hwt.code_utils import rename_signal
from hwt.hdl.types.bits import HBits
from hwt.hwIOs.agents.rdVldSync import HwIODataRdVldAgent
from hwt.hwIOs.std import HwIODataRdVld, HwIORdVldSync, HwIOVectSignal
from hwt.hwIOs.utils import addClkRstn
from hwt.hwModule import HwModule
from hwt.hwParam import HwParam
from hwt.math import log2ceil
from hwt.pyUtils.typingFuture import override
from hwtSimApi.hdlSimulator import HdlSimulator
[docs]
class TwoOperandsHsAgent(HwIODataRdVldAgent):
[docs]
@override
def get_data(self):
i = self.hwIO
return i.a.read(), i.b.read()
[docs]
@override
def set_data(self, data):
if data is None:
a = None
b = None
else:
a, b = data
i = self.hwIO
i.a.write(a)
i.b.write(b)
[docs]
class TwoOperandsHs(HwIODataRdVld):
@override
def hwDeclr(self):
self.a = HwIOVectSignal(self.DATA_WIDTH)
self.b = HwIOVectSignal(self.DATA_WIDTH)
HwIORdVldSync.hwDeclr(self)
[docs]
@override
def _initSimAgent(self, sim:HdlSimulator):
self._ag = TwoOperandsHsAgent(sim, self)
[docs]
class MultiplierBooth(HwModule):
"""
An implementation of Booth's multiplication algorithm
.. figure:: ./_static/MultiplierBooth_fsm.png
:attention: The input domain is limited to range specified bellow.
.. code-block:: python
max = 2 ** (DATA_WIDTH - 1) - 1
min = -1 * 2 ** (DATA_WIDTH - 1)
.. hwt-autodoc::
"""
@override
def hwConfig(self) -> None:
self.DATA_WIDTH = HwParam(4)
self.RESULT_WIDTH = HwParam(None)
@override
def hwDeclr(self):
if self.RESULT_WIDTH is None:
self.RESULT_WIDTH = 2 * self.DATA_WIDTH
addClkRstn(self)
self.dataIn = TwoOperandsHs()
self.dataIn.DATA_WIDTH = self.DATA_WIDTH
self.dataOut = HwIODataRdVld()._m()
self.dataOut.DATA_WIDTH = self.RESULT_WIDTH
@override
def hwImpl(self) -> None:
start = self._sig("start")
part_res_t = HBits(self.DATA_WIDTH)
# High-order n bits of product
a = self._reg("a", part_res_t)
# multiplicand
m = self._reg("m", part_res_t)
# Initially holds multiplier, ultimately holds low-order n bits of product
q = self._reg("q", part_res_t)
# previous bit 0 of q
q_1 = self._reg("q_1")
din = self.dataIn
dout = self.dataOut
counter = self._reg(
"counter",
HBits(log2ceil(self.DATA_WIDTH + 1), signed=False),
def_val=0)
done = counter._eq(0)
waitinOnConsumer = self._reg("waitinOnConsumer", def_val=0)
add = rename_signal(self, (a + m)._signed(), "add")
sub = rename_signal(self, (a - m)._signed(), "sub")
If(start,
a(0),
m(din.a),
q(din.b),
q_1(0),
counter(self.DATA_WIDTH),
).Elif(~done,
Switch(Concat(q[0], q_1))
.Case(0b01,
# add multiplicand to left half of product
a((add >> 1)._vec()),
q(Concat(add[0], q[:1])),
).Case(0b10,
# substract multiplicand from left half of product
a((sub >> 1)._vec()),
q(Concat(sub[0], q[:1])),
).Default(
a((a._signed() >> 1)._vec()),
q(Concat(a[0], q[:1])),
),
q_1(q[0]),
counter(counter - 1)
)
If(start,
waitinOnConsumer(1)
).Elif(done & dout.rd,
waitinOnConsumer(0),
)
dout.data(Concat(a, q)._vec())
dout.vld(done & waitinOnConsumer)
start(din.vld & done & ~waitinOnConsumer)
din.rd(done & ~waitinOnConsumer)
if __name__ == "__main__":
from hwt.synth import to_rtl_str
m = MultiplierBooth()
print(to_rtl_str(m))