Skip to content

Commit

Permalink
Merge ddaf517 into 5d3ad36
Browse files Browse the repository at this point in the history
  • Loading branch information
leonardt committed Jul 20, 2018
2 parents 5d3ad36 + ddaf517 commit 98c00fd
Show file tree
Hide file tree
Showing 8 changed files with 184 additions and 24 deletions.
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ python:
install:
- wget https://raw.githubusercontent.com/phanrahan/magma/master/.travis/install_coreir.sh
- source install_coreir.sh

- pip install python-coveralls
- pip install pytest-cov pytest-pep8
- pip install -r requirements.txt
Expand Down
28 changes: 28 additions & 0 deletions fault/array.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
class Array:
def __init__(self, value, N):
self.value = value
self.N = N

def __setitem__(self, index, value):
self.value[index] = value

def __eq__(self, other):
if not isinstance(other, Array):
return False
return self.N == other.N and self.value == other.value

def __len__(self):
return self.N

@property
def flattened_length(self):
if isinstance(self.value, Array):
return self.N * self.value.flattened_length
else:
return self.N

def flattened(self):
if isinstance(self.value, Array):
return self.value.flattened()
else:
return self.value
45 changes: 39 additions & 6 deletions fault/tester.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
import magma as m
import functools
from .verilator_target import VerilatorTarget
from fault.array import Array
import copy


def convert_value(fn):
Expand All @@ -27,27 +29,58 @@ def __init__(self, circuit, clock=None):
if value is clock:
self.clock_index = i
# Initialize first test vector to all Nones
self.test_vectors.append(
[BitVector(None, 1 if isinstance(port, m._BitType) else len(port))
for port in self.ports.values()])
initial_vector = []
for port in self.ports.values():
if isinstance(port, m._BitType):
val = BitVector(None, 1)
elif isinstance(port, m.ArrayType):
val = self.get_array_val(port)
else:
raise NotImplementedError(port)
initial_vector.append(val)
self.test_vectors.append(initial_vector)

def get_array_val(self, arr):
if isinstance(arr.T, m._BitKind):
val = BitVector(None, len(arr))
elif isinstance(arr, m.ArrayType) and isinstance(arr.T, m.ArrayKind):
val = Array([self.get_array_val(x) for x in arr], len(arr))
else:
raise NotImplementedError(arr, type(arr), arr.T)
return val

def get_index(self, port):
return self.port_index_mapping[port]

def add_test_vector(self, port, value):
if isinstance(port.name, m.ref.ArrayRef):
parent = port
indices = []
# Get the outer most port
while isinstance(parent.name, m.ref.ArrayRef):
indices.insert(0, parent.name.index)
parent = parent.name.array
vector = self.test_vectors[-1][self.get_index(parent)]
for idx in indices[:-1]:
vector = vector[idx]
vector[indices[-1]] = value
else:
self.test_vectors[-1][self.get_index(port)] = value

@convert_value
def poke(self, port, value):
if port.isinput():
raise ValueError(f"Can only poke an input: {port} {type(port)}")
self.test_vectors[-1][self.get_index(port)] = value
self.add_test_vector(port, value)

@convert_value
def expect(self, port, value):
if port.isoutput():
raise ValueError(f"Can only expect an output: {port} {type(port)}")
self.test_vectors[-1][self.get_index(port)] = value
self.add_test_vector(port, value)

def eval(self):
self.test_vectors.append(self.test_vectors[-1][:])
self.test_vectors.append(copy.deepcopy(self.test_vectors[-1]))

def step(self):
if self.clock_index is None:
Expand Down
89 changes: 72 additions & 17 deletions fault/verilator_target.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,33 @@
import os
import subprocess
import magma as m
from .array import Array


def flattened_names(arr):
if isinstance(arr.T, m.ArrayKind):
names = [f"_{i}" for i in range(len(arr))]
prod_names = []
for name_0 in flattened_names(arr.T):
for name_1 in names:
prod_names.append(f"{name_1}{name_0}")
return prod_names

elif not isinstance(arr.T, m._BitKind):
raise NotImplementedError()
return [""]


def harness(circuit, tests):

assert len(circuit.interface.ports.keys()) == len(tests[0])

test_vector_length = len(tests[0])
test_vector_length = 0
for item in tests[0]:
if isinstance(item, Array):
test_vector_length += item.flattened_length
else:
test_vector_length += 1

source = '''\
#include "V{name}.h"
Expand Down Expand Up @@ -43,7 +63,8 @@ def harness(circuit, tests):
value_t tests[{}][{}] = {{
'''.format(len(tests), test_vector_length)

for test in tests:
for i, test in enumerate(tests):
testvector = []

def to_string(t):
if t is None or t._value is None:
Expand All @@ -54,11 +75,26 @@ def to_string(t):
X = "false"
return f"{{{val}, {X}}}"

testvector = ', '.join([to_string(t) for t in test])
for t in test:
if isinstance(t, Array):
testvector.extend(t.flattened())
else:
testvector.append(t)
names = []
for name, port in circuit.interface.ports.items():
if isinstance(port, m.ArrayType):
names.extend(f"{name}{x}" for x in flattened_names(port))
else:
names.append(name)
testvector = '\n '.join(
[f"{to_string(t)}, // {name}"
for t, name in zip(testvector, names)])
# testvector += ', {}'.format(int(func(*test[:nargs])))
source += '''\
{{ {} }},
'''.format(testvector)
source += f'''\
{{ // {i}
{testvector}
}},
'''
source += '''\
};
'''
Expand All @@ -69,24 +105,43 @@ def to_string(t):
'''.format(len(tests))

i = 0
output_str = ""
for name, port in circuit.interface.ports.items():
if port.isoutput():
source += f'''\
top->{name} = test[{i}].value;
if isinstance(port, m.ArrayType) and \
not isinstance(port.T, m._BitType):
for _name in flattened_names(port):
source += f'''\
top->{name}{_name} = test[{i}].value;
std::cout << "top->{name}{_name} = " << test[{i}].value << ", ";
'''
i += 1
i += 1

source += '''\
top->eval();
else:
source += f'''\
top->{name} = test[{i}].value;
std::cout << "top->{name} = " << test[{i}].value << ", ";
'''

i = 0
for name, port in circuit.interface.ports.items():
if port.isinput():
source += f'''\
i += 1
else:
if isinstance(port, m.ArrayType) and \
not isinstance(port.T, m._BitType):
for _name in flattened_names(port):
output_str += f'''\
check(\"{name}{_name}\", top->{name}{_name}, test[{i}], i);
'''
i += 1
else:
output_str += f'''\
check(\"{name}\", top->{name}, test[{i}], i);
'''
i += 1
i += 1

source += f'''\
std::cout << std::endl;
top->eval();
{output_str}
'''
source += '''\
}
'''
Expand Down
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[pytest]
[tool:pytest]
pep8ignore =
fault/prototype.py ALL
tests/_test_cgra.py ALL
Expand Down
9 changes: 9 additions & 0 deletions tests/common.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import magma as m


class TestNestedArraysCircuit(m.Circuit):
IO = ["I", m.In(m.Array(3, m.Bits(4))), "O", m.Out(m.Array(3, m.Bits(4)))]

@classmethod
def definition(io):
m.wire(io.I, io.O)
16 changes: 16 additions & 0 deletions tests/test_tester.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import magma as m
import fault
from bit_vector import BitVector
import random
import common


def test_tester_basic():
Expand Down Expand Up @@ -37,3 +39,17 @@ def test_tester_clock():
[BitVector(0, 1), BitVector(0, 1), BitVector(0, 1)],
[BitVector(0, 1), BitVector(0, 1), BitVector(1, 1)]
]


def test_tester_nested_arrays():
circ = common.TestNestedArraysCircuit
tester = fault.Tester(circ)
expected = []
for i in range(3):
val = random.randint(0, (1 << 4) - 1)
tester.poke(circ.I[i], val)
tester.expect(circ.O[i], val)
expected.append(val)
assert tester.test_vectors == [
[fault.array.Array(expected, 3), fault.array.Array(expected, 3)]
]
18 changes: 18 additions & 0 deletions tests/test_verilator_target.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
import magma as m
import fault
from bit_vector import BitVector
import common
import random


def test_verilator_target():
Expand All @@ -25,3 +27,19 @@ def definition(io):
target = fault.verilator_target.VerilatorTarget(
Foo, test_vectors, directory=f"{tempdir}/")
target.run()


def test_tester_nested_arrays():
circ = common.TestNestedArraysCircuit
tester = fault.Tester(circ)
for i in range(3):
val = random.randint(0, (1 << 4) - 1)
tester.poke(circ.I[i], val)
tester.expect(circ.O[i], val)

with tempfile.TemporaryDirectory() as tempdir:
m.compile(f"{tempdir}/{circ.name}", circ, output="coreir-verilog")

target = fault.verilator_target.VerilatorTarget(
circ, tester.test_vectors, directory=f"{tempdir}/")
target.run()

0 comments on commit 98c00fd

Please sign in to comment.