Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
def test_minus_simulationx(self):
self.r.next <<= self.r - pyrtl.Const(3, bitwidth=self.bitwidth)
self.check_trace('r 05274163\n')
# is one-bit just do one_bit_add. 2) if they are more than one bit, do
# a one-bit add on the least significant bits, a ripple carry on the rest,
# and then stick the results back together into one WireVector. A couple
# interesting features of PyRTL can be seen here: WireVectors can be indexed
# like lists, with [0] accessing the least significant bit and [1:] being an
# example of the use of Python slicing syntax. While you can add two lists
# together in python a WireVector + Wirevector means "make an adder" so to
# concatenate the bits of two vectors one need to use "concat". Finally,
# if we look at "cin" it seems to have a default value of the integer "0" but
# is a WireVector at other times. Python supports polymorphism throughout
# and PyRTL will cast integers and some other types to WireVectors when it can.
# Now let's build a 3-bit counter from our N-bit ripple carry adder.
counter = pyrtl.Register(bitwidth=3, name='counter')
sum, carry_out = ripple_add(counter, pyrtl.Const("1'b1"))
counter.next <<= sum
# A couple new things in the above code. The two remaining types of basic
# WireVectors, Const and Register, both appear. Const, unsurprisingly, is just for
# holding constants (such as the 0 in ripple_add), but here we create one directly
# from a Verilog-like string which includes both the value and the bitwidth.
# Registers are just like wires, except their updates are delayed to the next
# clock cycle. This is made explicit in the syntax through the property '.next'
# which should always be set for registers. In this simple example, we take
# counter next cycle equal to counter this cycle plus one.
# Now let's run the bugger. No need for inputs, as it doesn't have any.
# Finally we'll print the trace to the screen and check that it counts up correctly.
print(pyrtl.working_block())
def test_nand_simulation(self):
self.r.next <<= self.r.nand(pyrtl.Const(6, bitwidth=self.bitwidth))
self.check_trace('o 07171717\n')
In this example we describe how conditional_assignment works in the context of
a vending machine that will dispense an item when it has received 4 tokens.
If a refund is requested, it returns the tokens.
"""
import pyrtl
from firrtl_tests import toFirrtl_new
token_in = pyrtl.Input(1, 'token_in')
req_refund = pyrtl.Input(1, 'req_refund')
dispense = pyrtl.Output(1, 'dispense')
refund = pyrtl.Output(1, 'refund')
state = pyrtl.Register(3, 'state')
# First new step, let's enumerate a set of constant to serve as our states
WAIT, TOK1, TOK2, TOK3, DISPENSE, REFUND = [pyrtl.Const(x, bitwidth=3) for x in range(6)]
# Now we could build a state machine using just the registers and logic discussed
# in the earlier examples, but doing operations *conditional* on some input is a pretty
# fundamental operation in hardware design. PyRTL provides an instance "conditional_assignment"
# to provide a predicated update to a registers, wires, and memories.
#
# Conditional assignments are specified with a "|=" instead of a "<<=" operator. The
# conditional assignment is only value in the context of a condition, and update to those
# values only happens when that condition is true. In hardware this is implemented
# with a simple mux -- for people coming from software it is important to remember that this
# is describing a big logic function NOT an "if-then-else" clause. All of these things will
# execute straight through when "build_everything" is called. More comments after the code.
#
# One more thing: conditional_assignment might not always be the best item to use.
# if the update is simple, a regular mux(sel_wire, falsecase=f_wire, truecase=t_wire)
# can be sufficient.
def test_multiply_simulation(self):
self.r.next <<= self.r * pyrtl.Const(2, bitwidth=self.bitwidth) + \
pyrtl.Const(1, bitwidth=self.bitwidth)
self.check_trace('r 01377777\n')
def assert_bad_const(self, *args, **kwargs):
with self.assertRaises(pyrtl.PyrtlError):
c = pyrtl.Const(*args, **kwargs)
def test_dup_consts2(self):
sel = pyrtl.WireVector(3)
c1 = pyrtl.Const(4)
c2 = pyrtl.Const(4)
res = muxes.sparse_mux(sel, {6: c1, 2: c2})
self.assertIsInstance(res, pyrtl.Const)
self.assertEqual(res.val, 4)
def _one_cycle_mult(areg, breg, rem_bits, sum_sf=0, curr_bit=0):
""" returns a WireVector sum of rem_bits multiplies (in one clock cycle)
note: this method requires a lot of area because of the indexing in the else statement """
if rem_bits == 0:
return sum_sf
else:
a_curr_val = areg[curr_bit].sign_extended(len(breg))
if curr_bit == 0: # if no shift
return(_one_cycle_mult(areg, breg, rem_bits-1, # areg, breg, rem_bits
sum_sf + (a_curr_val & breg), # sum_sf
curr_bit+1)) # curr_bit
else:
return _one_cycle_mult(
areg, breg, rem_bits-1, # areg, breg, rem_bits
sum_sf + (a_curr_val &
pyrtl.concat(breg, pyrtl.Const(0, curr_bit))), # sum_sf
curr_bit+1 # curr_bit
)
def _shifted_reg_next(reg, direct, num=1):
"""
Creates a shifted 'next' property for shifted (left or right) register.\n
Use: `myReg.next = shifted_reg_next(myReg, 'l', 4)`
:param string direct: direction of shift, either 'l' or 'r'
:param int num: number of shifts
:return: Register containing reg's (shifted) next state
"""
if direct == 'l':
if num >= len(reg):
return 0
else:
return pyrtl.concat(reg, pyrtl.Const(0, num))
elif direct == 'r':
if num >= len(reg):
return 0
else:
return reg[num:]
else:
raise pyrtl.PyrtlError("direction must be specified with 'direct'"
"parameter as either 'l' or 'r'")
def attempt1_hardware_fibonacci(n, bitwidth):
a = pyrtl.Const(0)
b = pyrtl.Const(1)
for i in range(n):
a, b = b, a + b
return a