We create a simple parametrizable multiplier element, convert it to RTL and call synthesis and mapping for the Gatemate target architecture.
import sys
sys.path.insert(0, '../../../')
from myirl.emulation.myhdl import *
Bool = Signal.Type(bool)
@block
def aluelement(clk : ClkSignal, en : Bool, a : Signal, b : Signal, dout : Signal.Output, reset : ResetSignal, DEPTH=18, DFF=False):
DEPTH -= 1
res = Signal(intbv(0, min=-2**DEPTH, max=2**DEPTH))
if DFF:
@always_seq(clk.posedge, reset)
def worker():
if en:
res.next = a * b
else:
@always_comb
def worker():
res.next = a * b
@always_comb
def assign():
dout.next = res.signed()
return instances()
from myirl.targets.pyosys import RTLIL
tgt = RTLIL("multest")
def convert(unit, size):
clk = ClkSignal()
en = Signal(bool(0))
reset = ResetSignal(0, 1, False)
s = size - 1
a, b = [ Signal(intbv(0, min=-2**s, max=2**s)) for i in range(2) ]
s = 2 * size - 1
y = Signal(intbv(0, min=-2**s, max=2**s))
unit_to_synthesize = unit(clk, en, a, b, y, reset, DEPTH=size*2, DFF=True)
design = unit_to_synthesize.elab(tgt, elab_all = True)
return design[0]
d = convert(aluelement, 4)
Creating process 'aluelement/worker' with sensitivity (clk'rising, <reset>) Adding module with name `aluelement` DEBUG: SKIP NON-SIGNAL ARGUMENT `DEPTH` : <class 'int'> DEBUG: SKIP NON-SIGNAL ARGUMENT `DFF` : <class 'bool'> FINALIZE implementation `aluelement` of `aluelement`
We simply call the synth_gatemate
script on the design:
d.write_rtlil("pre")
-- Running command `tee -q hierarchy -top \aluelement' -- -- Running command `write_rtlil pre.il' -- 2. Executing RTLIL backend.
For some constructs to sythesize, the yosys-abc
executable is required, otherwise the Notebook kernel may crash without error report.
! [ -e `which yosys-abc` ] || echo "It may be necessary to `sudo apt install yosys`"
d.run("synth_gatemate")
# d.addSource("/usr/share/yosys/gatemate/cells_sim.v")
for cmd in [ 'proc', 'hierarchy -check', 'flatten']:
d.run(cmd)
d.run("opt")
d.write_rtlil("post")
Output filename: pre.il -- Running command `tee -q synth_gatemate' -- -- Running command `tee -q proc' -- -- Running command `tee -q hierarchy -check' -- -- Running command `tee -q flatten' -- -- Running command `tee -q opt' -- -- Running command `write_rtlil post.il' -- 8. Executing RTLIL backend.
! echo "" >multest.log
d.run("stat", capture = True)
Then we dump the result as DOT file:
!cat multest.log
9. Printing statistics. === aluelement === Number of wires: 21 Number of wire bits: 57 Number of public wires: 7 Number of public wire bits: 27 Number of memories: 0 Number of memory bits: 0 Number of processes: 0 Number of cells: 37 CC_BUFG 1 CC_DFF 8 CC_IBUF 11 CC_LUT4 8 CC_MULT 1 CC_OBUF 8
d.display_rtl("*", fmt='dot')
Output filename: post.il -- Running command `tee -q -a multest.log stat' -- -- Running command `show -format dot -prefix multest *' -- 10. Generating Graphviz representation of design. Writing dot description to `multest.dot'. Dumping module aluelement to page 1.
Display the dot schematic for the multiplier:
from yosys import display
display.display_dot("multest")
Let's run this construct through the CXXRTL simulator to see if it behaves as we expect:
from simulation import *
from yosys.simulator import CXXRTL
@sim.testbench(CXXRTL, time_unit = 'ns')
def tb_mul(size, VALUES):
clk = ClkSignal(init = 0)
reset = ResetSignal(1, 1, isasync = False)
en = Signal(bool(0))
reset = ResetSignal(0, 1, False)
s = size - 1
a, b = [ Signal(intbv(0, min=-2**s, max=2**s)) for i in range(2) ]
s = 2 * size - 1
y = Signal(intbv(0, min=-2**s, max=2**s))
uut_mul = aluelement(clk, en, a, b, y, reset, DEPTH=size*2, DFF=True)
@always(delay(5))
def clkgen():
clk.next = ~clk
@sequence
def reset_seq():
reset.next = True
for _ in range(5):
yield clk.posedge
reset.next = False
yield clk.negedge
for va, vb, vy in VALUES:
a.next = va
b.next = vb
en.next = True
yield clk.negedge
en.next = False
yield clk.negedge
print(va, vb, int(y))
assert int(y) == vy
yield delay(200)
return instances()
def test_simulation(size, VALUES):
t = tb_mul(size, VALUES)
t.run_synthcmd("write_ilang test.il")
# t.run_synthcmd("synth_gatemate")
# t.run_synthcmd("read_verilog /usr/share/yosys/gatemate/cells_sim.v")
# t._force_compile = True
t.run(150)
VALUES = [
(4, 5, 20),
(7, 6, 42),
(-1, 2, -2),
(-2, -2, 4)
]
test_simulation(4, VALUES)
DEBUG: Skip non-simulation type <class 'list'> Adding module with name `aluelement` DEBUG: SKIP NON-SIGNAL ARGUMENT `DEPTH` : <class 'int'> DEBUG: SKIP NON-SIGNAL ARGUMENT `DFF` : <class 'bool'> FINALIZE implementation `aluelement` of `aluelement` Tolerate exception: Module with name `aluelement` already existing Compiling /tmp/myirl_top_aluelement_5f6ix9un/aluelement_f7b0.pyx because it changed. [1/1] Cythonizing /tmp/myirl_top_aluelement_5f6ix9un/aluelement_f7b0.pyx running build_ext building 'aluelement_f7b0' extension creating build creating build/temp.linux-x86_64-3.9 creating build/temp.linux-x86_64-3.9/tmp creating build/temp.linux-x86_64-3.9/tmp/myirl_top_aluelement_5f6ix9un x86_64-linux-gnu-gcc -pthread -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O2 -Wall -g -ffile-prefix-map=/build/python3.9-RNBry6/python3.9-3.9.2=. -fstack-protector-strong -Wformat -Werror=format-security -g -fwrapv -O2 -g -ffile-prefix-map=/build/python3.9-RNBry6/python3.9-3.9.2=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -fPIC -I../../../myirl/../ -I/tmp/myirl_top_aluelement_5f6ix9un/ -I/usr/share/yosys/include -I/usr/include/python3.9 -c /tmp/myirl_top_aluelement_5f6ix9un/aluelement_f7b0.cpp -o build/temp.linux-x86_64-3.9/tmp/myirl_top_aluelement_5f6ix9un/aluelement_f7b0.o x86_64-linux-gnu-gcc -pthread -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O2 -Wall -g -ffile-prefix-map=/build/python3.9-RNBry6/python3.9-3.9.2=. -fstack-protector-strong -Wformat -Werror=format-security -g -fwrapv -O2 -g -ffile-prefix-map=/build/python3.9-RNBry6/python3.9-3.9.2=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -fPIC -I../../../myirl/../ -I/tmp/myirl_top_aluelement_5f6ix9un/ -I/usr/share/yosys/include -I/usr/include/python3.9 -c /tmp/myirl_top_aluelement_5f6ix9un/aluelement_f7b0_rtl.cpp -o build/temp.linux-x86_64-3.9/tmp/myirl_top_aluelement_5f6ix9un/aluelement_f7b0_rtl.o creating build/lib.linux-x86_64-3.9 x86_64-linux-gnu-g++ -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions -Wl,-z,relro -g -fwrapv -O2 -Wl,-z,relro -g -fwrapv -O2 -g -ffile-prefix-map=/build/python3.9-RNBry6/python3.9-3.9.2=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 build/temp.linux-x86_64-3.9/tmp/myirl_top_aluelement_5f6ix9un/aluelement_f7b0.o build/temp.linux-x86_64-3.9/tmp/myirl_top_aluelement_5f6ix9un/aluelement_f7b0_rtl.o -o build/lib.linux-x86_64-3.9/aluelement_f7b0.cpython-39-x86_64-linux-gnu.so copying build/lib.linux-x86_64-3.9/aluelement_f7b0.cpython-39-x86_64-linux-gnu.so -> Open for writing: tb_mul.vcd CXXRTL context: SKIP INTERFACE ITEM `DEPTH` CXXRTL context: SKIP INTERFACE ITEM `DFF` 4 5 20 7 6 42 -1 2 -2 -2 -2 4
The commands below display a schematic waveform of the above.
Note: This display is not timing accurate.
import wavedraw; import nbwavedrom
waveform = wavedraw.vcd2wave("tb_mul.vcd", '.clk', None)
nbwavedrom.draw(waveform)