Skip to content

Commit

Permalink
Merge pull request #14 from leonardt/migrate-magma-testing
Browse files Browse the repository at this point in the history
Migrate magma testing infrastructure to fault
  • Loading branch information
leonardt committed Jul 24, 2018
2 parents ea52b2b + 1f93ecc commit 2c2cf5e
Show file tree
Hide file tree
Showing 4 changed files with 141 additions and 2 deletions.
122 changes: 122 additions & 0 deletions fault/test_vectors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
from magma import BitType, ArrayType, SIntType
from magma.simulator.python_simulator import PythonSimulator
from magma.bitutils import seq2int
from bit_vector import BitVector
from inspect import signature
from itertools import product
import pytest


# check that number of function arguments equals number of circuit inputs
def check(circuit, func):
sig = signature(func)
nfuncargs = len(sig.parameters)

# count circuit inputs
ncircargs = 0
for name, port in circuit.interface.ports.items():
if port.isoutput():
ncircargs += 1

assert nfuncargs == ncircargs


@pytest.mark.skip(reason="Not a test")
def generate_function_test_vectors(circuit, func, input_ranges=None,
mode='complete'):
check(circuit, func)

args = []
for i, (name, port) in enumerate(circuit.interface.ports.items()):
if port.isoutput():
if isinstance(port, BitType):
args.append([0, 1])
elif isinstance(port, ArrayType):
num_bits = type(port).N
if isinstance(port, SIntType):
if input_ranges is None:
input_range = range(-2**(num_bits-1), 2**(num_bits-1))
else:
input_range = input_ranges[i]
else:
if input_ranges is None:
input_range = range(1 << num_bits)
else:
input_range = input_ranges[i]
args.append(input_range)
else:
assert True, "can't test Tuples"

tests = []
for test in product(*args):
test = list(test)
result = func(*test)
if isinstance(result, tuple):
test.extend(result)
else:
test.append(result)
tests.append(test)

return tests


def generate_simulator_test_vectors(circuit, input_ranges=None,
mode='complete'):
ntest = len(circuit.interface.ports.items())

simulator = PythonSimulator(circuit)

args = []
for i, (name, port) in enumerate(circuit.interface.ports.items()):
if port.isoutput():
if isinstance(port, BitType):
args.append([BitVector(0), BitVector(1)])
elif isinstance(port, ArrayType):
num_bits = type(port).N
if isinstance(port, SIntType):
if input_ranges is None:
start = -2**(num_bits - 1)
# We don't subtract one because range end is exclusive
end = 2**(num_bits - 1)
input_range = range(start, end)
else:
input_range = input_ranges[i]
args.append([BitVector(x, num_bits=num_bits, signed=True)
for x in input_range])
else:
if input_ranges is None:
input_range = range(1 << num_bits)
else:
input_range = input_ranges[i]
args.append([BitVector(x, num_bits=num_bits)
for x in input_range])
else:
assert True, "can't test Tuples"

tests = []
for test in product(*args):
test = list(test)
testv = ntest*[0]
j = 0
for i, (name, port) in enumerate(circuit.interface.ports.items()):
# circuit defn output is an input to the idefinition
if port.isoutput():
testv[i] = test[j].as_int()
val = test[j].as_bool_list()
if len(val) == 1:
val = val[0]
simulator.set_value(getattr(circuit, name), val)
j += 1

simulator.evaluate()

for i, (name, port) in enumerate(circuit.interface.ports.items()):
# circuit defn input is an input of the definition
if port.isinput():
val = simulator.get_value(getattr(circuit, name))
val = BitVector(val, signed=isinstance(port, SIntType)).as_int()
testv[i] = val

tests.append(testv)

return tests
4 changes: 2 additions & 2 deletions fault/verilator_target.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from .target import Target
from magma.testing.function import testvectors
from fault.test_vectors import generate_function_test_vectors
import magma.config as config
import inspect
import os
Expand Down Expand Up @@ -165,7 +165,7 @@ def compile_verilator_harness(basename, circuit, tests, input_ranges=None):
filename = basename

if callable(tests):
tests = testvectors(circuit, tests, input_ranges)
tests = generate_function_test_vectors(circuit, tests, input_ranges)
verilatorcpp = harness(circuit, tests)

with open(filename, "w") as f:
Expand Down
3 changes: 3 additions & 0 deletions tests/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

def define_simple_circuit(T, circ_name, has_clk=False):
class _Circuit(m.Circuit):
__test__ = False # Disable pytest discovery
name = circ_name
IO = ["I", m.In(T), "O", m.Out(T)]
if has_clk:
Expand All @@ -16,6 +17,8 @@ def definition(io):


TestBasicCircuit = define_simple_circuit(m.Bit, "BasicCircuit")
TestArrayCircuit = define_simple_circuit(m.Array(3, m.Bit), "ArrayCircuit")
TestSIntCircuit = define_simple_circuit(m.SInt(3), "SIntCircuit")
TestNestedArraysCircuit = define_simple_circuit(m.Array(3, m.Bits(4)),
"NestedArraysCircuit")
TestBasicClkCircuit = define_simple_circuit(m.Bit, "BasicClkCircuit", True)
14 changes: 14 additions & 0 deletions tests/test_test_vectors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from fault.test_vectors import generate_function_test_vectors, \
generate_simulator_test_vectors
from common import TestBasicCircuit, TestArrayCircuit, TestSIntCircuit
import pytest


@pytest.mark.parametrize("Circuit", [TestBasicCircuit, TestArrayCircuit,
TestSIntCircuit])
def test_circuit(Circuit):
def fn(I):
return I
function_test_vectors = generate_function_test_vectors(Circuit, fn)
simulator_test_vectors = generate_simulator_test_vectors(Circuit)
assert function_test_vectors == simulator_test_vectors

0 comments on commit 2c2cf5e

Please sign in to comment.