Skip to content

Commit bde52d6

Browse files
committed
Major rework of rtllib's documentation, lots of changes:
* Discourage use of many functions and stop publishing their documentation: * MultiSelector (use conditional assignment) * Matrix.multiply (use Matrix.__mul__) * libutil.match_bitwidth (use pyrtl.match_bitwidth) * partition_wire (use wire_matrix or chop) * str_to_int_array (use a list comprehension) * rev_twos_comp_repr (use val_to_signed_integer) * _shifted_reg_next (use shift_left_logical, shift_right_logical) * sim_and_ret_out, sim_and_ret_outws (use step_multiple) * Fix `shift_left_logical`, `shift_right_logical`, `shift_right_arithmetic` so they work when the integer shift amount is greater than or equal to the bitwidth. Previously they would raise an exception while attempting to slice the input. * Define a `Direction` enum for `barrel_shifter` to improve readability. * Don't explicitly instantiate `SimulationTrace()` since `Simulation` will do it for us. * Add references to basic hardware implementations available in PyRTL's core library. * Add documentation for Matrix's dunder methods. * Add documentation for PRNGs. * Move AES documentation from module level to class level. * Add type annotations. * Fix formatting. * Add links.
1 parent a2ae4c5 commit bde52d6

39 files changed

+1279
-1101
lines changed

docs/index.rst

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -106,15 +106,14 @@ different classes help you do that: :class:`.Simulation`,
106106
interchangeably. Typically one starts with :class:`.Simulation` and then moves
107107
up to :class:`.FastSimulation` when performance begins to matter.
108108

109-
Both :class:`.Simulation` and :class:`.FastSimulation` take an instance of
110-
:class:`.SimulationTrace` as an argument (or makes an empty
111-
:class:`.SimulationTrace` by default), which stores a list of the signals as
112-
they are simulated. This trace can then be rendered to the terminal with
113-
:meth:`~.SimulationTrace.render_trace`.
109+
Both :class:`.Simulation` and :class:`.FastSimulation` store a list of each
110+
wire's value in each cycle in :attr:`.Simulation.tracer`, which is an instance
111+
of :class:`.SimulationTrace`. Traces can then be rendered to the terminal with
112+
:meth:`.SimulationTrace.render_trace`.
114113
:class:`SimulationTraces<.SimulationTrace>` can be handled in other ways, for
115-
example they can be extracted as a test bench
116-
(:func:`.output_verilog_testbench`) or exported to a VCD file
117-
(:meth:`~.SimulationTrace.print_vcd`).
114+
example they can be extracted as a test bench with
115+
:func:`.output_verilog_testbench`, or exported to a VCD file with
116+
:meth:`~.SimulationTrace.print_vcd`.
118117

119118
Optimization
120119
------------

docs/rtllib.rst

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
1-
.. PyRTL rtllib master file
2-
31
RTL Library
42
===========
53

6-
Useful circuits, functions, and testing utilities.
4+
Useful circuits, functions, and utilities.
5+
6+
Multiplexers
7+
------------
8+
9+
.. automodule:: pyrtl.rtllib.muxes
10+
:members:
11+
:exclude-members: MultiSelector
712

813
Adders
914
------
@@ -12,47 +17,42 @@ Adders
1217
:members:
1318
:undoc-members:
1419

15-
AES-128
16-
-------
20+
Multipliers
21+
-----------
1722

18-
.. automodule:: pyrtl.rtllib.aes
23+
.. automodule:: pyrtl.rtllib.multipliers
1924
:members:
20-
:undoc-members:
2125

22-
Barrel
23-
------
26+
Barrel Shifter
27+
--------------
2428

2529
.. automodule:: pyrtl.rtllib.barrel
2630
:members:
2731
:undoc-members:
2832

29-
Library Utilities
30-
-----------------
31-
32-
.. automodule:: pyrtl.rtllib.libutils
33-
:members:
34-
35-
Multipliers
36-
-----------
33+
Matrix
34+
------
3735

38-
.. automodule:: pyrtl.rtllib.multipliers
36+
.. automodule:: pyrtl.rtllib.matrix
3937
:members:
38+
:special-members: __init__, __len__, __getitem__, __reversed__, __add__, __sub__, __mul__, __matmul__, __pow__
39+
:exclude-members: multiply
4040

41-
Muxes
42-
-----
41+
Pseudo-Random Numbers
42+
---------------------
4343

44-
.. automodule:: pyrtl.rtllib.muxes
44+
.. automodule:: pyrtl.rtllib.prngs
4545
:members:
4646

47-
Matrix
48-
------
47+
AES-128
48+
-------
4949

50-
.. automodule:: pyrtl.rtllib.matrix
50+
.. autoclass:: pyrtl.rtllib.aes.AES
5151
:members:
52-
:special-members: __init__
5352

5453
Testing Utilities
5554
-----------------
5655

5756
.. automodule:: pyrtl.rtllib.testingutils
5857
:members:
58+
:exclude-members: generate_in_wire_and_values, sim_and_ret_out, sim_and_ret_outws, sim_multicycle, multi_sim_multicycle

examples/example1-combologic.py

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,9 @@
6565

6666
# --- Step 2: Simulate Design -----------------------------------------------
6767

68-
# Okay, let's simulate our one-bit adder. To keep track of the output of
69-
# the simulation we need to make a new "SimulationTrace" and a "Simulation"
70-
# that then uses that trace.
68+
# Okay, let's simulate our one-bit adder.
7169

72-
sim_trace = pyrtl.SimulationTrace()
73-
sim = pyrtl.Simulation(tracer=sim_trace)
70+
sim = pyrtl.Simulation()
7471

7572
# Now all we need to do is call "sim.step" to simulate each clock cycle of our
7673
# design. We just need to pass in some input each cycle, which is a dictionary
@@ -89,7 +86,7 @@
8986
# Now all we need to do is print the trace results to the screen. Here we use
9087
# "render_trace" with some size information.
9188
print('--- One Bit Adder Simulation ---')
92-
sim_trace.render_trace(symbol_len=2)
89+
sim.tracer.render_trace(symbol_len=2)
9390

9491
a_value = sim.inspect(a)
9592
print("The latest value of 'a' was: " + str(a_value))
@@ -105,13 +102,13 @@
105102
for cycle in range(15):
106103
# Note that we are doing all arithmetic on values, NOT wirevectors, here.
107104
# We can add the inputs together to get a value for the result
108-
add_result = (sim_trace.trace['a'][cycle]
109-
+ sim_trace.trace['b'][cycle]
110-
+ sim_trace.trace['c'][cycle])
105+
add_result = (sim.tracer.trace['a'][cycle]
106+
+ sim.tracer.trace['b'][cycle]
107+
+ sim.tracer.trace['c'][cycle])
111108
# We can select off the bits and compare
112109
python_sum = add_result & 0x1
113110
python_cout = (add_result >> 1) & 0x1
114-
if (python_sum != sim_trace.trace['sum'][cycle]
115-
or python_cout != sim_trace.trace['carry_out'][cycle]):
111+
if (python_sum != sim.tracer.trace['sum'][cycle]
112+
or python_cout != sim.tracer.trace['carry_out'][cycle]):
116113
print('This Example is Broken!!!')
117114
exit(1)

examples/example2-counter.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,8 @@ def ripple_add(a, b, carry_in=0):
7474
# Now let's run the bugger. No need for inputs, as it doesn't have any.
7575
# Finally we'll print the trace to the screen and check that it counts up correctly.
7676

77-
sim_trace = pyrtl.SimulationTrace()
78-
sim = pyrtl.Simulation(tracer=sim_trace)
77+
sim = pyrtl.Simulation()
7978
for cycle in range(15):
8079
sim.step()
8180
assert sim.value[counter] == cycle % 8
82-
sim_trace.render_trace()
81+
sim.tracer.render_trace()

examples/example3-statemachine.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,7 @@ class State(enum.IntEnum):
101101

102102
# Now let's build and test our state machine.
103103

104-
sim_trace = pyrtl.SimulationTrace()
105-
sim = pyrtl.Simulation(tracer=sim_trace)
104+
sim = pyrtl.Simulation()
106105

107106
# Rather than just give some random inputs, let's specify some specific 1-bit
108107
# values. To make it easier to simulate it over several steps, we'll use
@@ -119,7 +118,7 @@ class State(enum.IntEnum):
119118
# Also, to make our input/output easy to reason about let's specify an order to
120119
# the traces. We also use `enum_name` to display the state names (WAIT, TOK1,
121120
# ...) rather than their numbers (0, 1, ...).
122-
sim_trace.render_trace(
121+
sim.tracer.render_trace(
123122
trace_list=['token_in', 'req_refund', 'state', 'dispense', 'refund'],
124123
repr_per_name={'state': pyrtl.enum_name(State)})
125124

examples/example4-debuggingtools.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,7 @@
5151
vals2 = [int(2**random.uniform(1, 8) - 2) for _ in range(20)]
5252
vals3 = [int(2**random.uniform(1, 8) - 2) for _ in range(20)]
5353

54-
sim_trace = pyrtl.SimulationTrace()
55-
sim = pyrtl.Simulation(tracer=sim_trace)
54+
sim = pyrtl.Simulation()
5655
sim.step_multiple({
5756
'in1': vals1,
5857
'in2': vals2,
@@ -62,16 +61,18 @@
6261
# In order to get the result data, you do not need to print a waveform of the trace.
6362
# You always have the option to just pull the data out of the tracer directly
6463
print("---- Inputs and debug_out ----")
65-
print("in1: ", str(sim_trace.trace['in1']))
66-
print("in2: ", str(sim_trace.trace['in2']))
67-
print("debug_out: ", str(sim_trace.trace['debug_out']))
64+
print("in1: ", str(sim.tracer.trace['in1']))
65+
print("in2: ", str(sim.tracer.trace['in2']))
66+
print("debug_out: ", str(sim.tracer.trace['debug_out']))
6867
print('\n')
6968

7069
# Below, I am using the ability to directly retrieve the trace data to
7170
# verify the correctness of the first adder
7271

7372
for i in range(len(vals1)):
74-
assert sim_trace.trace['debug_out'][i] == sim_trace.trace['in1'][i] + sim_trace.trace['in2'][i]
73+
actual = sim.tracer.trace['debug_out'][i]
74+
expected = sim.tracer.trace['in1'][i] + sim.tracer.trace['in2'][i]
75+
assert actual == expected
7576

7677

7778
# --- Probe ----
@@ -118,8 +119,7 @@
118119
vals1 = [int(2**random.uniform(1, 8) - 2) for _ in range(10)]
119120
vals2 = [int(2**random.uniform(1, 8) - 2) for _ in range(10)]
120121

121-
sim_trace = pyrtl.SimulationTrace()
122-
sim = pyrtl.Simulation(tracer=sim_trace)
122+
sim = pyrtl.Simulation()
123123
sim.step_multiple({
124124
'in1': vals1,
125125
'in2': vals2,
@@ -128,8 +128,8 @@
128128
# Now we will show the values of the inputs and probes
129129
# and look at that, we didn't need to make any outputs!
130130
# (although we did, to demonstrate the power and convenience of probes)
131-
sim_trace.render_trace()
132-
sim_trace.print_trace()
131+
sim.tracer.render_trace()
132+
sim.tracer.print_trace()
133133

134134
print("--- Probe w/ debugging: ---")
135135
# Say we wanted to have gotten more information about

examples/example5-introspection.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,6 @@ def stage4(self):
7171
simplepipeline = SimplePipelineExample()
7272
print(pyrtl.working_block())
7373
# Simulation of the core
74-
sim_trace = pyrtl.SimulationTrace()
75-
sim = pyrtl.Simulation(tracer=sim_trace)
74+
sim = pyrtl.Simulation()
7675
sim.step_multiple({}, nsteps=15)
77-
sim_trace.render_trace()
76+
sim.tracer.render_trace()

examples/example6-memory.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -90,10 +90,9 @@
9090
# value map.
9191
print("---------memories----------")
9292
print(pyrtl.working_block())
93-
sim_trace = pyrtl.SimulationTrace()
94-
sim = pyrtl.Simulation(tracer=sim_trace, memory_value_map=memvals)
93+
sim = pyrtl.Simulation(memory_value_map=memvals)
9594
sim.step_multiple(simvals)
96-
sim_trace.render_trace()
95+
sim.tracer.render_trace()
9796

9897
# Cleanup in preparation for the ROM example
9998
pyrtl.reset_working_block()
@@ -164,7 +163,6 @@ def rom_data_func(address):
164163
# supply a memory value map because ROMs are defined with the values
165164
# predefined.
166165

167-
sim_trace = pyrtl.SimulationTrace()
168-
sim = pyrtl.Simulation(tracer=sim_trace)
166+
sim = pyrtl.Simulation()
169167
sim.step_multiple(simvals)
170-
sim_trace.render_trace()
168+
sim.tracer.render_trace()

examples/example8-verilog.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -70,17 +70,16 @@
7070
io_vectors = pyrtl.working_block().wirevector_subset((pyrtl.Input, pyrtl.Output))
7171

7272
# We are only going to trace the input and output vectors for clarity
73-
sim_trace = pyrtl.SimulationTrace(wires_to_track=io_vectors)
7473
# Now simulate the logic with some random inputs
75-
sim = pyrtl.Simulation(tracer=sim_trace)
74+
sim = pyrtl.Simulation(tracer=pyrtl.SimulationTrace(wires_to_track=io_vectors))
7675
for i in range(15):
7776
# here we actually generate random booleans for the inputs
7877
sim.step({
7978
'x': random.choice([0, 1]),
8079
'y': random.choice([0, 1]),
8180
'cin': random.choice([0, 1])
8281
})
83-
sim_trace.render_trace(symbol_len=2)
82+
sim.tracer.render_trace(symbol_len=2)
8483

8584

8685
# ---- Exporting to Verilog ----
@@ -115,11 +114,10 @@
115114
print(vfile.getvalue())
116115

117116
print("--- Simulation Results ---")
118-
sim_trace = pyrtl.SimulationTrace([counter_output, zero])
119-
sim = pyrtl.Simulation(tracer=sim_trace)
117+
sim = pyrtl.Simulation(tracer=pyrtl.SimulationTrace([counter_output, zero]))
120118
for cycle in range(15):
121119
sim.step({'zero': random.choice([0, 0, 0, 1])})
122-
sim_trace.render_trace()
120+
sim.tracer.render_trace()
123121

124122
# We already did the "hard" work of generating a test input for this simulation, so
125123
# we might want to reuse that work when we take this design through a Verilog toolchain.
@@ -128,7 +126,7 @@
128126

129127
print("--- Verilog for the TestBench ---")
130128
with io.StringIO() as tbfile:
131-
pyrtl.output_verilog_testbench(dest_file=tbfile, simulation_trace=sim_trace)
129+
pyrtl.output_verilog_testbench(dest_file=tbfile, simulation_trace=sim.tracer)
132130
print(tbfile.getvalue())
133131

134132

examples/introduction-to-hardware.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -175,14 +175,13 @@ def attempt4_hardware_fibonacci(n, req, bitwidth):
175175
fib_out <<= output[0]
176176
done_out <<= output[1]
177177

178-
sim_trace = pyrtl.SimulationTrace()
179-
sim = pyrtl.Simulation(tracer=sim_trace)
178+
sim = pyrtl.Simulation()
180179

181180
sim.step({'n_in': 7, 'req_in': 1})
182181

183182
sim.step({'n_in': 0, 'req_in': 0})
184183
while not sim.inspect('done_out'):
185184
sim.step({'n_in': 0, 'req_in': 0})
186185

187-
sim_trace.render_trace(
186+
sim.tracer.render_trace(
188187
trace_list=['n_in', 'req_in', 'i', 'fib_out', 'done_out'], repr_func=int)

0 commit comments

Comments
 (0)