Skip to content

Commit 8d2a3e2

Browse files
committed
Rewrap comments and docstrings to 88 columns.
1 parent 34aeda7 commit 8d2a3e2

44 files changed

Lines changed: 1101 additions & 1157 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

examples/example1-combologic.py

Lines changed: 46 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,62 @@
1-
"""Example 1: A simple combination logic block example.
2-
3-
This example declares a block of hardware with three one-bit inputs,
4-
(a,b,c) and two one-bit outputs (sum, cout). The logic declared is a
5-
simple one-bit adder and the definition uses some of the most common
6-
parts of PyRTL. The adder is then simulated on random data, the
7-
wave form is printed to the screen, and the resulting trace is
8-
compared to a "correct" addition. If the result is correct then a 0
9-
is returned, else 1.
1+
"""
2+
Example 1: A simple combination logic block example.
3+
4+
This example declares a block of hardware with three one-bit inputs, (a,b,c) and two
5+
one-bit outputs (sum, cout). The logic declared is a simple one-bit adder and the
6+
definition uses some of the most common parts of PyRTL. The adder is then simulated on
7+
random data, the wave form is printed to the screen, and the resulting trace is compared
8+
to a "correct" addition. If the result is correct then a 0 is returned, else 1.
109
"""
1110

1211
import random
1312

1413
import pyrtl
1514

16-
# The basic idea of PyRTL is to specify the component of a some hardware block
17-
# through the declaration of wires and operations on those wires. The current
18-
# working block, an instance of a class devilishly named "Block", is implicit
19-
# in all of the below code -- it is easiest to start with the way wires work.
15+
# The basic idea of PyRTL is to specify the component of a some hardware block through
16+
# the declaration of wires and operations on those wires. The current working block, an
17+
# instance of a class devilishly named "Block", is implicit in all of the below code --
18+
# it is easiest to start with the way wires work.
2019

2120
# --- Step 1: Define Logic -------------------------------------------------
2221

23-
# One of the most fundamental types in PyRTL is the "WireVector" which acts
24-
# very much like a Python list of 1-bit wires. Unlike a normal list, though, the
25-
# number of bits is explicitly declared.
22+
# One of the most fundamental types in PyRTL is the "WireVector" which acts very much
23+
# like a Python list of 1-bit wires. Unlike a normal list, though, the number of bits is
24+
# explicitly declared.
2625
temp1 = pyrtl.WireVector(bitwidth=1, name="temp1")
2726

28-
# Both arguments are in fact optional and default to a bitwidth of 1 and a unique
29-
# name generated by PyRTL starting with 'tmp'
27+
# Both arguments are in fact optional and default to a bitwidth of 1 and a unique name
28+
# generated by PyRTL starting with 'tmp'
3029
temp2 = pyrtl.WireVector()
3130

32-
# Two special types of WireVectors are Input and Output, which are used to specify
33-
# an interface to the hardware block.
31+
# Two special types of WireVectors are Input and Output, which are used to specify an
32+
# interface to the hardware block.
3433
a, b, c = pyrtl.Input(1, "a"), pyrtl.Input(1, "b"), pyrtl.Input(1, "c")
3534
sum, carry_out = pyrtl.Output(1, "sum"), pyrtl.Output(1, "carry_out")
3635

37-
# Okay, let's build a one-bit adder. To do this we need to use the assignment
38-
# operator, which is '<<='. This takes an already declared wire and "connects"
39-
# it to some other already declared wire. Let's start with the sum bit, which is
40-
# of course just the xor of the three inputs
36+
# Okay, let's build a one-bit adder. To do this we need to use the assignment operator,
37+
# which is '<<='. This takes an already declared wire and "connects" it to some other
38+
# already declared wire. Let's start with the sum bit, which is of course just the xor
39+
# of the three inputs
4140
sum <<= a ^ b ^ c
4241

4342
# The carry_out bit would just be "carry_out <<= a & b | a & c | b & c" but let's break
44-
# than down a bit to see what is really happening. What if we want to give names
45-
# to the partial signals in the middle of that computation? When you take
46-
# "a & b" in PyRTL, what that really means is "make an AND gate, connect one input
47-
# to 'a' and the other to 'b' and return the result of the gate". The result of
48-
# that AND gate can then be assigned to temp1 or it can be used like any other
49-
# Python variable.
43+
# than down a bit to see what is really happening. What if we want to give names to the
44+
# partial signals in the middle of that computation? When you take "a & b" in PyRTL,
45+
# what that really means is "make an AND gate, connect one input to 'a' and the other to
46+
# 'b' and return the result of the gate". The result of that AND gate can then be
47+
# assigned to temp1 or it can be used like any other Python variable.
5048

5149
temp1 <<= a & b # connect the result of a & b to the pre-allocated wirevector
5250
temp2 <<= a & c
5351
temp3 = b & c # temp3 IS the result of b & c (this is the first mention of temp3)
5452
carry_out <<= temp1 | temp2 | temp3
5553

56-
# You can access the working block through pyrtl.working_block(), and for most
57-
# things one block is all you will need. Example 2 discusses this in more detail,
58-
# but for now we can just print the block to see that in fact it looks like the
59-
# hardware we described. The format is a bit weird, but roughly translates to
60-
# a list of gates (the 'w' gates are just wires). The ins and outs of the gates
61-
# are printed 'name'/'bitwidth''WireVectorType'
54+
# You can access the working block through pyrtl.working_block(), and for most things
55+
# one block is all you will need. Example 2 discusses this in more detail, but for now
56+
# we can just print the block to see that in fact it looks like the hardware we
57+
# described. The format is a bit weird, but roughly translates to a list of gates (the
58+
# 'w' gates are just wires). The ins and outs of the gates are printed
59+
# 'name'/'bitwidth''WireVectorType'
6260

6361
print("--- One Bit Adder Implementation ---")
6462
print(pyrtl.working_block())
@@ -70,12 +68,11 @@
7068

7169
sim = pyrtl.Simulation()
7270

73-
# Now all we need to do is call "sim.step" to simulate each clock cycle of our
74-
# design. We just need to pass in some input each cycle, which is a dictionary
75-
# mapping inputs (the *names* of the inputs, not the actual Input instances)
76-
# to their value for that signal each cycle. In this simple example, we
77-
# can just specify a random value of 0 or 1 with Python's random module. We
78-
# call step 15 times to simulate 15 cycles.
71+
# Now all we need to do is call "sim.step" to simulate each clock cycle of our design.
72+
# We just need to pass in some input each cycle, which is a dictionary mapping inputs
73+
# (the *names* of the inputs, not the actual Input instances) to their value for that
74+
# signal each cycle. In this simple example, we can just specify a random value of 0 or
75+
# 1 with Python's random module. We call step 15 times to simulate 15 cycles.
7976

8077
for _cycle in range(15):
8178
sim.step(
@@ -92,19 +89,19 @@
9289
sim.tracer.render_trace(symbol_len=2)
9390

9491
a_value = sim.inspect(a)
95-
print("The latest value of 'a' was: " + str(a_value))
92+
print("The latest value of 'a' was: ", a_value)
9693

9794
# --- Step 3: Verification of Simulated Design ---------------------------------------
9895

9996
# Now finally, let's check the trace to make sure that sum and carry_out are actually
100-
# the right values when compared to Python's addition operation. Note that
101-
# all the simulation is done at this point and we are just checking the waveform,
102-
# but there is no reason you could not do this at simulation time if you had a
103-
# really long-running design.
97+
# the right values when compared to Python's addition operation. Note that all the
98+
# simulation is done at this point and we are just checking the waveform, but there is
99+
# no reason you could not do this at simulation time if you had a really long-running
100+
# design.
104101

105102
for cycle in range(15):
106-
# Note that we are doing all arithmetic on values, NOT wirevectors, here.
107-
# We can add the inputs together to get a value for the result
103+
# Note that we are doing all arithmetic on values, NOT wirevectors, here. We can add
104+
# the inputs together to get a value for the result
108105
add_result = (
109106
sim.tracer.trace["a"][cycle]
110107
+ sim.tracer.trace["b"][cycle]

examples/example2-counter.py

Lines changed: 42 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
"""Example 2: A Counter with Ripple Carry Adder.
1+
"""
2+
Example 2: A Counter with Ripple Carry Adder.
23
3-
This next example shows how you make stateful things with registers
4-
and more complex hardware structures with functions. We generate
5-
a 3-bit ripple carry adder building off of the 1-bit adder from
6-
the prior example, and then hook it to a register to count up modulo 8.
4+
This next example shows how you make stateful things with registers and more complex
5+
hardware structures with functions. We generate a 3-bit ripple carry adder building off
6+
of the 1-bit adder from the prior example, and then hook it to a register to count up
7+
modulo 8.
78
"""
89

910
import pyrtl
@@ -18,18 +19,18 @@ def one_bit_add(a, b, carry_in):
1819
return sum, carry_out
1920

2021

21-
# A function in PyRTL is nothing special -- it just so happens that the statements
22-
# it encapsulate tell PyRTL to build some hardware. If we call "one_bit_add"
23-
# above with the arguments "x", "y", and "z", it will make a one-bit adder to add
24-
# those values together and return the wires for sum and carry_out as applied to "x",
25-
# "y", and "z". If I call it again on "i", "j", and "k" it will build a new one-bit
26-
# adder for those inputs and return the resulting sum and carry_out for that adder.
22+
# A function in PyRTL is nothing special -- it just so happens that the statements it
23+
# encapsulate tell PyRTL to build some hardware. If we call "one_bit_add" above with the
24+
# arguments "x", "y", and "z", it will make a one-bit adder to add those values together
25+
# and return the wires for sum and carry_out as applied to "x", "y", and "z". If I call
26+
# it again on "i", "j", and "k" it will build a new one-bit adder for those inputs and
27+
# return the resulting sum and carry_out for that adder.
2728

2829

29-
# While PyRTL actually provides an "+" operator for WireVectors which generates
30-
# adders, a ripple carry adder is something people can understand easily but has
31-
# enough structure to be mildly interesting. Let's define an adder of arbitrary
32-
# length recursively and (hopefully) Pythonically. More comments after the code.
30+
# While PyRTL actually provides an "+" operator for WireVectors which generates adders,
31+
# a ripple carry adder is something people can understand easily but has enough
32+
# structure to be mildly interesting. Let's define an adder of arbitrary length
33+
# recursively and (hopefully) Pythonically. More comments after the code.
3334

3435

3536
def ripple_add(a, b, carry_in=0):
@@ -45,18 +46,21 @@ def ripple_add(a, b, carry_in=0):
4546
return sumbits, carry_out
4647

4748

48-
# The above code breaks down into two cases. 1) If the size of the inputs
49-
# is one-bit just do one_bit_add. 2) If they are more than one bit, do
50-
# a one-bit add on the least significant bits, a ripple carry on the rest,
51-
# and then stick the results back together into one WireVector. A couple
52-
# interesting features of PyRTL can be seen here: WireVectors can be indexed
53-
# like lists, with [0] accessing the least significant bit and [1:] being an
54-
# example of the use of Python slicing syntax. While you can add two lists
55-
# together in Python, a WireVector + WireVector means "make an adder", so to
56-
# concatenate the bits of two vectors one needs to use "concat". Finally,
57-
# if we look at "carry_in" it seems to have a default value of the integer "0" but
58-
# is a WireVector at other times. Python supports polymorphism throughout
59-
# and PyRTL will cast integers and some other types to WireVectors when it can.
49+
# The above code breaks down into two cases:
50+
#
51+
# 1) If the size of the inputs is one-bit just do one_bit_add.
52+
# 2) If they are more than one bit, do a one-bit add on the least significant bits, a
53+
# ripple carry on the rest, and then stick the results back together into one
54+
# WireVector.
55+
#
56+
# A couple interesting features of PyRTL can be seen here: WireVectors can be indexed
57+
# like lists, with [0] accessing the least significant bit and [1:] being an example of
58+
# the use of Python slicing syntax. While you can add two lists together in Python, a
59+
# WireVector + WireVector means "make an adder", so to concatenate the bits of two
60+
# vectors one needs to use "concat". Finally, if we look at "carry_in" it seems to have
61+
# a default value of the integer "0" but is a WireVector at other times. Python supports
62+
# polymorphism throughout and PyRTL will cast integers and some other types to
63+
# WireVectors when it can.
6064

6165

6266
# Now let's build a 3-bit counter from our N-bit ripple carry adder.
@@ -65,17 +69,17 @@ def ripple_add(a, b, carry_in=0):
6569
sum, carry_out = ripple_add(counter, pyrtl.Const("1'b1"))
6670
counter.next <<= sum
6771

68-
# A couple new things in the above code. The two remaining types of basic
69-
# WireVectors, Const and Register, both appear. Const, unsurprisingly, is just for
70-
# holding constants (such as the 0 in ripple_add), but here we create one directly
71-
# from a Verilog-like string which includes both the value and the bitwidth.
72-
# Registers are just like wires, except their updates are delayed to the next
73-
# clock cycle. This is made explicit in the syntax through the property '.next'
74-
# which should always be set for registers. In this simple example, we make the
75-
# counter's value on the next cycle equal to the counter's value this cycle plus one.
76-
77-
# Now let's run the bugger. No need for inputs, as it doesn't have any.
78-
# Finally we'll print the trace to the screen and check that it counts up correctly.
72+
# A couple new things in the above code. The two remaining types of basic WireVectors,
73+
# Const and Register, both appear. Const, unsurprisingly, is just for holding constants
74+
# (such as the 0 in ripple_add), but here we create one directly from a Verilog-like
75+
# string which includes both the value and the bitwidth. Registers are just like wires,
76+
# except their updates are delayed to the next clock cycle. This is made explicit in the
77+
# syntax through the property '.next' which should always be set for registers. In this
78+
# simple example, we make the counter's value on the next cycle equal to the counter's
79+
# value this cycle plus one.
80+
81+
# Now let's run the bugger. No need for inputs, as it doesn't have any. Finally we'll
82+
# print the trace to the screen and check that it counts up correctly.
7983

8084
sim = pyrtl.Simulation()
8185
for cycle in range(15):

0 commit comments

Comments
 (0)