import pyrtl
import random
""" testcase_utils
This file (intentionally misspelled) is created to store common utility
functions used for the test cases.
I am documenting this rather well because users have
a good reason to look at it - John Clow
"""
def calcuate_max_and_min_bitwidths(max_bitwidth=None, exact_bitwidth=None):
if max_bitwidth is not None:
min_bitwidth = 1
elif exact_bitwidth is not None:
min_bitwidth = max_bitwidth = exact_bitwidth
else:
raise pyrtl.PyrtlError("A max or exact bitwidth must be specified")
return min_bitwidth, max_bitwidth
def inverse_power_dist(bitwidth):
# Note that this is not uniformly distributed
return int(2**random.uniform(0, bitwidth) - 1)
def uniform_dist(bitwidth):
return random.randrange(2**bitwidth)
# deprecated name
generate_in_wire_and_values = an_input_and_vals
[docs]
def make_consts(num_wires, max_bitwidth=None, exact_bitwidth=None, random_dist=inverse_power_dist):
"""
:return: [Const_wires]; [Const_vals]
"""
min_bitwidth, max_bitwidth = calcuate_max_and_min_bitwidths(max_bitwidth, exact_bitwidth)
bitwidths = [random.randrange(min_bitwidth, max_bitwidth + 1) for i in range(num_wires)]
wires = [pyrtl.Const(random_dist(b), b) for b in bitwidths]
vals = [w.val for w in wires]
return wires, vals
[docs]
def sim_and_ret_out(outwire, inwires, invals):
""" Simulates the net using `inwires` and `invals`, and returns the output array.
Used for rapid test development.
:param outwire: The wire to return the output of
:param inwires: a list of wires to read in from (`[Input, ...]`)
:param invals: a list of input value lists (`[ [int, ...], ...]`)
:return: a list of values from the output wire simulation result
"""
# Pulling the value of outwire straight from the log
return sim_and_ret_outws(inwires, invals)[outwire.name]
[docs]
def sim_and_ret_outws(inwires, invals):
""" Simulates the net using `inwires` and `invals`, and returns the output array.
Used for rapid test development.
:param inwires: a list of wires to read in from (`[Input, ...]`)
:param invals: a list of input value lists (`[[int, ...], ...]`)
:return: a list of values from the output wire simulation result
"""
sim_trace = pyrtl.SimulationTrace() # Creating a logger for the simulator
sim = pyrtl.Simulation(tracer=sim_trace) # Creating the simulation
for cycle in range(len(invals[0])):
sim.step({wire.name: val[cycle] for wire, val in zip(inwires, invals)})
return sim_trace.trace # Pulling the value of wires straight from the trace
[docs]
def sim_multicycle(in_dict, hold_dict, hold_cycles, sim=None):
# TODO: write param and return descriptions
""" Simulation of a circuit that takes multiple cycles to complete.
:param in_dict:
:param hold_dict:
:param hold_cycles:
:param sim:
:return:
"""
if sim is None:
sim = pyrtl.Simulation(tracer=pyrtl.SimulationTrace())
sim.step(in_dict)
for i in range(hold_cycles):
sim.step(hold_dict)
return sim.tracer.trace[-1]
[docs]
def multi_sim_multicycle(in_dict, hold_dict, hold_cycles, sim=None):
# TODO: write param and return descriptions
""" Simulates a circuit that takes multiple cycles to complete multiple times.
:param in_dict: `{in_wire: [in_values, ...], ...}`
:param hold_dict: `{hold_wire: hold_value}` The hold values for the
:param hold_cycles:
:param sim:
:return:
"""
if sim is None:
sim = pyrtl.Simulation(tracer=pyrtl.SimulationTrace())
cycles = len(list(in_dict.values())[0])
for cycle in range(cycles):
current_dict = {wire: values[cycle] for wire, values in in_dict}
cur_result = sim_multicycle(current_dict, hold_dict, hold_cycles, sim)
if cycle == 0:
results = {wire: [result_val] for wire, result_val in cur_result}
else:
for wire, result_val in cur_result:
results[wire].append(result_val)
return results