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_undriven_net(self):
w = pyrtl.WireVector(name='testwire', bitwidth=3)
self.assertRaises(pyrtl.PyrtlError, pyrtl.working_block().sanity_check)
pyrtl.reset_working_block()
r = pyrtl.Register(3)
self.assertRaises(pyrtl.PyrtlError, pyrtl.working_block().sanity_check)
pyrtl.reset_working_block()
o = pyrtl.Output(3)
self.assertRaises(pyrtl.PyrtlError, pyrtl.working_block().sanity_check)
def setUp(self):
pyrtl.reset_working_block()
bitwidth = 3
self.r = pyrtl.Register(bitwidth=bitwidth, name='r')
self.result = _basic_add(self.r, pyrtl.Const(1).zero_extended(bitwidth))
self.r.next <<= self.result
def test_input_out_of_bitwidth(self):
counter = pyrtl.Register(bitwidth=3, name='counter')
i = pyrtl.Input(bitwidth=2, name='i')
counter.next <<= counter + i
sim_trace = pyrtl.SimulationTrace()
sim = self.sim(tracer=sim_trace)
for cycle in range(4):
sim.step({i: cycle})
with self.assertRaises(pyrtl.PyrtlError):
sim.step({i: 5})
def test_one_wirevector(self):
r = pyrtl.Register(3, 'r')
r.next <<= r + 1
o = pyrtl.Output(name='o')
o <<= pyrtl.corecircuits.xor_all_bits(r)
self.check_trace('o 01101001\nr 01234567\n')
def data_buffer(din):
"""
Create a data buffer.
"""
dt_buffer = pyrtl.Register(bitwidth = len(din))
dt_buffer.next <<= din
return dt_buffer
def attempt4_hardware_fibonacci(n, req, bitwidth):
a = pyrtl.Register(bitwidth, 'a')
b = pyrtl.Register(bitwidth, 'b')
i = pyrtl.Register(bitwidth, 'i')
local_n = pyrtl.Register(bitwidth, 'local_n')
done = pyrtl.WireVector(bitwidth=1, name='done')
with pyrtl.conditional_assignment:
with req:
local_n.next |= n
i.next |= 0
a.next |= 0
b.next |= 1
with pyrtl.otherwise:
i.next |= i + 1
a.next |= b
b.next |= a + b
done <<= i == local_n
return a, done
def surfnoc_buffer(bitwidth, addrwidth, data, write_enable, read_enable):
""" """
buffer_memory = pyrtl.MemBlock(bitwidth=bitwidth, addrwidth=addrwidth)
head = pyrtl.Register(addrwidth) # write pointer into the circular buffer
tail = pyrtl.Register(addrwidth) # read pointer into the circular buffer
count = pyrtl.Register(addrwidth+1) # number of elements currently stored in buffer
full = pyrtl.mux(count >= 2**addrwidth, truecase=1, falsecase=0)
do_write = pyrtl.mux(full, truecase=0, falsecase=write_enable)
empty = (~do_write) & (count==0)
do_read = pyrtl.mux(empty, truecase=0, falsecase=read_enable)
buffer_memory[head] <<= pyrtl.MemBlock.EnabledWrite(data, do_write)
head.next <<= pyrtl.mux(do_write, truecase=head+1, falsecase=head)
tail.next <<= pyrtl.mux(do_read, truecase=tail+1, falsecase=tail)
count.next <<= count + do_write - do_read
read_output = pyrtl.mux(do_read & do_write & (head==tail), truecase=data, falsecase=buffer_memory[tail])
return (read_output, do_read, full)
# The above code breaks down into two cases. 1) If the size of the inputs
# 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.
sim_trace = pyrtl.SimulationTrace()
(worst case is len(A) cycles). start is a one-bit input to indicate inputs are ready.
done is a one-bit output signal raised when the multiplication is finished.
:param WireVector A, B: two input wires for the multiplication
:returns: Register containing the product; the "done" signal
"""
triv_result = _trivial_mult(A, B)
if triv_result is not None:
return triv_result, pyrtl.Const(1, 1)
alen = len(A)
blen = len(B)
areg = pyrtl.Register(alen)
breg = pyrtl.Register(blen + alen)
accum = pyrtl.Register(blen + alen)
done = (areg == 0) # Multiplication is finished when a becomes 0
# During multiplication, shift a right every cycle, b left every cycle
with pyrtl.conditional_assignment:
with start: # initialization
areg.next |= A
breg.next |= B
accum.next |= 0
with ~done: # don't run when there's no work to do
areg.next |= areg[1:] # right shift
breg.next |= pyrtl.concat(breg, pyrtl.Const(0, 1)) # left shift
a_0_val = areg[0].sign_extended(len(accum))
# adds to accum only when LSB of areg is 1
accum.next |= accum + (a_0_val & breg)
def attempt2_hardware_fibonacci(n, bitwidth):
a = pyrtl.Register(bitwidth, 'a')
b = pyrtl.Register(bitwidth, 'b')
a.next <<= b
b.next <<= a + b
return a