Skip to content

Commit 443e47e

Browse files
authored
Clean up Kogge-Stone and carry-lookahead adder implementations so they don't create driven-but-unused LogicNets (#490)
These extra LogicNets were triggering debug-mode warnings from `sanity_check()`, which required a call to `_remove_unused_wires` in `example4` to silence. Clean up `example4` and add a test. Also update `example4` to use `block_to_graphviz_string` instead of `output_to_trivialgraph`.
1 parent 987b09c commit 443e47e

5 files changed

Lines changed: 44 additions & 88 deletions

File tree

examples/example4-debuggingtools.py

Lines changed: 12 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
# PyRTL provides some additional challenges when it comes to debugging, as a problem may
55
# surface long after the error was made. Fortunately, PyRTL comes with various features
66
# to help you find mistakes.
7-
import io
87
import random
98

109
import pyrtl
@@ -130,7 +129,7 @@
130129
print("\n--- Probe w/ debugging: ---")
131130
pyrtl.set_debug_mode()
132131
pyrtl.probe(multout - 16, "debugsubtr_probe")
133-
pyrtl.set_debug_mode(debug=False)
132+
pyrtl.set_debug_mode(False)
134133

135134

136135
# ## `WireVector` Stack Trace
@@ -183,30 +182,17 @@
183182
dummy_wv.my_custom_property_name = "John Clow is great"
184183
dummy_wv.custom_value_028493 = 13
185184

186-
# Remove the `WireVector` from the `Block` to prevent problems with the rest of this
187-
# example.
188-
pyrtl.working_block().remove_wirevector(dummy_wv)
189-
190-
# ## Trivial Graph Format
185+
# ## Graphviz
191186
#
192-
# Finally, there is a handy way to view your hardware creations as a graph. The function
193-
# `output_to_trivialgraph()` will render your hardware in a format that you can then
194-
# open with the free software "yEd" (http://en.wikipedia.org/wiki/YEd). There are
195-
# options under the "hierarchical" rendering to draw something that looks quite like a
196-
# circuit.
187+
# Finally, there is a handy way to view your hardware creations.
188+
# `block_to_graphviz_string()` produces a description of your hardware in the `graphviz`
189+
# language, which can be converted to an image with the `dot` graph drawing tool
190+
# (https://graphviz.org/docs/layouts/dot/).
197191
#
198-
# Also see `block_to_svg()`.
199-
pyrtl.working_block().sanity_check()
200-
201-
# So that `output_to_trivial_graph()` will work.
202-
pyrtl.passes._remove_unused_wires(pyrtl.working_block())
203-
204-
print("\n--- Trivial Graph Format (first 10 lines) ---")
205-
with io.StringIO() as tgf:
206-
pyrtl.output_to_trivialgraph(tgf)
207-
for i, line in enumerate(tgf.getvalue().split("\n")):
208-
if i == 10:
209-
break
210-
print(line)
192+
# Also see `block_to_svg()`, which automates running `dot`.
193+
print("\n--- Graphviz Format (first 10 lines) ---")
194+
graphviz_string = pyrtl.block_to_graphviz_string()
211195

212-
print("...")
196+
for line in graphviz_string.split("\n")[:10]:
197+
print(line)
198+
print("...")

examples/tools/to_ipynb.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,8 @@ def foo(bar):
5959
"kogge_stone()": "https://pyrtl.readthedocs.io/en/latest/rtllib.html#pyrtl.rtllib.adders.kogge_stone",
6060
"mux()": "https://pyrtl.readthedocs.io/en/latest/helpers.html#pyrtl.mux",
6161
"otherwise": "https://pyrtl.readthedocs.io/en/latest/basic.html#pyrtl.otherwise",
62+
"block_to_graphviz_string()": "https://pyrtl.readthedocs.io/en/latest/export.html#pyrtl.block_to_graphviz_string",
6263
"block_to_svg()": "https://pyrtl.readthedocs.io/en/latest/export.html#pyrtl.block_to_svg",
63-
"output_to_trivialgraph()": "https://pyrtl.readthedocs.io/en/latest/export.html#pyrtl.output_to_trivialgraph",
6464
"output_verilog_testbench()": "https://pyrtl.readthedocs.io/en/latest/export.html#pyrtl.output_verilog_testbench",
6565
"probe()": "https://pyrtl.readthedocs.io/en/latest/helpers.html#pyrtl.probe",
6666
"render_trace()": "https://pyrtl.readthedocs.io/en/latest/simtest.html#pyrtl.SimulationTrace.render_trace",

ipynb-examples/example4-debuggingtools.ipynb

Lines changed: 12 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
"source": [
2323
"%pip install pyrtl\n",
2424
"\n",
25-
"import io\n",
2625
"import random\n",
2726
"\n",
2827
"import pyrtl\n",
@@ -374,7 +373,7 @@
374373
"print(\"\\n--- Probe w/ debugging: ---\")\n",
375374
"pyrtl.set_debug_mode()\n",
376375
"pyrtl.probe(multout - 16, \"debugsubtr_probe\")\n",
377-
"pyrtl.set_debug_mode(debug=False)\n"
376+
"pyrtl.set_debug_mode(False)\n"
378377
]
379378
},
380379
{
@@ -521,34 +520,14 @@
521520
"cell_type": "markdown",
522521
"metadata": {},
523522
"source": [
524-
" Remove the [WireVector](https://pyrtl.readthedocs.io/en/latest/basic.html#pyrtl.WireVector) from the [Block](https://pyrtl.readthedocs.io/en/latest/blocks.html#pyrtl.Block) to prevent problems with the rest of this\n",
525-
" example.\n"
526-
]
527-
},
528-
{
529-
"cell_type": "code",
530-
"execution_count": null,
531-
"metadata": {
532-
"collapsed": true
533-
},
534-
"outputs": [],
535-
"source": [
536-
"pyrtl.working_block().remove_wirevector(dummy_wv)\n"
537-
]
538-
},
539-
{
540-
"cell_type": "markdown",
541-
"metadata": {},
542-
"source": [
543-
" ## Trivial Graph Format\n",
523+
" ## Graphviz\n",
544524
"\n",
545-
" Finally, there is a handy way to view your hardware creations as a graph. The function\n",
546-
" [output_to_trivialgraph()](https://pyrtl.readthedocs.io/en/latest/export.html#pyrtl.output_to_trivialgraph) will render your hardware in a format that you can then\n",
547-
" open with the free software \"yEd\" (http://en.wikipedia.org/wiki/YEd). There are\n",
548-
" options under the \"hierarchical\" rendering to draw something that looks quite like a\n",
549-
" circuit.\n",
525+
" Finally, there is a handy way to view your hardware creations.\n",
526+
" [block_to_graphviz_string()](https://pyrtl.readthedocs.io/en/latest/export.html#pyrtl.block_to_graphviz_string) produces a description of your hardware in the `graphviz`\n",
527+
" language, which can be converted to an image with the `dot` graph drawing tool\n",
528+
" (https://graphviz.org/docs/layouts/dot/).\n",
550529
"\n",
551-
" Also see [block_to_svg()](https://pyrtl.readthedocs.io/en/latest/export.html#pyrtl.block_to_svg).\n"
530+
" Also see [block_to_svg()](https://pyrtl.readthedocs.io/en/latest/export.html#pyrtl.block_to_svg), which automates running `dot`.\n"
552531
]
553532
},
554533
{
@@ -559,35 +538,12 @@
559538
},
560539
"outputs": [],
561540
"source": [
562-
"pyrtl.working_block().sanity_check()\n"
563-
]
564-
},
565-
{
566-
"cell_type": "markdown",
567-
"metadata": {},
568-
"source": [
569-
" So that `output_to_trivial_graph()` will work.\n"
570-
]
571-
},
572-
{
573-
"cell_type": "code",
574-
"execution_count": null,
575-
"metadata": {
576-
"collapsed": true
577-
},
578-
"outputs": [],
579-
"source": [
580-
"pyrtl.passes._remove_unused_wires(pyrtl.working_block())\n",
581-
"\n",
582-
"print(\"\\n--- Trivial Graph Format (first 10 lines) ---\")\n",
583-
"with io.StringIO() as tgf:\n",
584-
" pyrtl.output_to_trivialgraph(tgf)\n",
585-
" for i, line in enumerate(tgf.getvalue().split(\"\\n\")):\n",
586-
" if i == 10:\n",
587-
" break\n",
588-
" print(line)\n",
541+
"print(\"\\n--- Graphviz Format (first 10 lines) ---\")\n",
542+
"graphviz_string = pyrtl.block_to_graphviz_string()\n",
589543
"\n",
590-
" print(\"...\")\n"
544+
"for line in graphviz_string.split(\"\\n\")[:10]:\n",
545+
" print(line)\n",
546+
"print(\"...\")\n"
591547
]
592548
}
593549
],

pyrtl/rtllib/adders.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def kogge_stone(
5252
a, b = pyrtl.match_bitwidth(a, b)
5353

5454
prop_orig = a ^ b
55-
prop_bits = list(prop_orig)
55+
prop_bits = [prop_orig[i] if i > 0 else None for i in range(prop_orig.bitwidth)]
5656
gen_bits = list(a & b)
5757
prop_dist = 1
5858

@@ -205,11 +205,13 @@ def _cla_adder_unit(a, b, cin):
205205
their values don't rely on the sum. Every unit generates a cout signal which is used
206206
as cin for the next unit.
207207
"""
208-
gen = a & b
209-
prop = a ^ b
208+
gen = list(a & b)
209+
prop = list(a ^ b)
210210
assert len(prop) == len(gen)
211211

212-
carry = [gen[0] | prop[0] & cin]
212+
carry = None
213+
if len(prop) > 1:
214+
carry = [gen[0] | prop[0] & cin]
213215
sum_bit = prop[0] ^ cin
214216

215217
cur_gen = gen[0]
@@ -218,7 +220,8 @@ def _cla_adder_unit(a, b, cin):
218220
cur_gen = gen[i] | (prop[i] & cur_gen)
219221
cur_prop = cur_prop & prop[i]
220222
sum_bit = pyrtl.concat(prop[i] ^ carry[i - 1], sum_bit)
221-
carry.append(gen[i] | (prop[i] & carry[i - 1]))
223+
if i < len(prop) - 1:
224+
carry.append(gen[i] | (prop[i] & carry[i - 1]))
222225
cout = cur_gen | (cur_prop & cin)
223226
return sum_bit, cout
224227

tests/rtllib/test_adders.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import doctest
2+
import io
23
import random
4+
import sys
35
import unittest
46

57
import pyrtl
@@ -37,6 +39,15 @@ def adder_t_base(self, adder_func, **kwargs):
3739
outwire = pyrtl.Output(name="test")
3840
outwire <<= adder_func(*wires)
3941

42+
# Check that there are no sanity_check errors or warnings in debug_mode.
43+
pyrtl.set_debug_mode()
44+
output = io.StringIO()
45+
sys.stdout = output
46+
pyrtl.working_block().sanity_check()
47+
sys.stdout = sys.__stdout__
48+
pyrtl.set_debug_mode(False)
49+
50+
self.assertEqual("", output.getvalue())
4051
out_vals = utils.sim_and_ret_out(outwire, wires, vals)
4152
true_result = [sum(cycle_vals) for cycle_vals in zip(*vals, strict=True)]
4253
self.assertEqual(out_vals, true_result)

0 commit comments

Comments
 (0)