Skip to content

Commit

Permalink
Merge 2a5d2a7 into 1b8c00b
Browse files Browse the repository at this point in the history
  • Loading branch information
leonardt committed May 6, 2019
2 parents 1b8c00b + 2a5d2a7 commit 90efc27
Show file tree
Hide file tree
Showing 12 changed files with 123 additions and 116 deletions.
13 changes: 8 additions & 5 deletions fault/actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,18 +46,21 @@ def __init__(self, port, value):


class Print(Action):
def __init__(self, port, format_str="%x"):
def __init__(self, format_str, *args):
super().__init__()
self.port = port
format_str = format_str.replace("\n", "\\n")
self.format_str = format_str
self.ports = args

def __str__(self):
return f"Print({self.port.debug_name}, \"{self.format_str}\")"
ports_str = ", ".join(port.debug_name for port in self.ports)
return f"Print(\"{self.format_str}\", {ports_str})"

def retarget(self, new_circuit, clock):
cls = type(self)
new_port = new_circuit.interface.ports[str(self.port.name)]
return cls(new_port, self.format_str)
new_ports = (new_circuit.interface.ports[str(port.name)] for port in
self.ports)
return cls(self.format_str, *new_ports)


def is_output(port):
Expand Down
19 changes: 11 additions & 8 deletions fault/magma_simulator_target.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,17 @@ def run(self, actions):
value = value.as_uint()
simulator.set_value(action.port, value)
elif isinstance(action, fault.actions.Print):
got = simulator.get_value(action.port)
if isinstance(action.port, m.ArrayType) and \
isinstance(action.port.T, (m._BitType, m._BitKind)):
got = BitVector(got).as_uint()
elif isinstance(action.port, m.ArrayType):
raise NotImplementedError("Printing complex nested arrays")
print(f'{action.port.debug_name} = {action.format_str}' %
got)
got = [simulator.get_value(port) for port in action.ports]
values = ()
for value, port in zip(got, action.ports):
if isinstance(port, m.ArrayType) and \
isinstance(port.T, (m._BitType, m._BitKind)):
value = BitVector(value).as_uint()
elif isinstance(port, m.ArrayType):
raise NotImplementedError("Printing complex nested"
" arrays")
values += (value, )
print(f'{action.format_str}' % values)
elif isinstance(action, fault.actions.Expect):
got = simulator.get_value(action.port)
expected = action.value
Expand Down
31 changes: 17 additions & 14 deletions fault/system_verilog_target.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,17 +73,21 @@ def __init__(self, circuit, circuit_name=None, directory="build/",
self.timescale = timescale
self.clock_step_delay = clock_step_delay

def make_poke(self, i, action):
if isinstance(action.port, SelectPath):
if len(action.port) > 2:
name = f"dut.{action.port.system_verilog_path}"
def make_name(self, port):
if isinstance(port, SelectPath):
if len(port) > 2:
name = f"dut.{port.system_verilog_path}"
else:
# Top level ports assign to the external reg
name = verilog_name(action.port[-1].name)
elif isinstance(action.port, fault.WrappedVerilogInternalPort):
name = f"dut.{action.port.path}"
name = verilog_name(port[-1].name)
elif isinstance(port, fault.WrappedVerilogInternalPort):
name = f"dut.{port.path}"
else:
name = verilog_name(action.port.name)
name = verilog_name(port.name)
return name

def make_poke(self, i, action):
name = self.make_name(action.port)
# For now we assume that verilog can handle big ints
value = action.value
if isinstance(action.port, m.SIntType) and value < 0:
Expand All @@ -94,21 +98,20 @@ def make_poke(self, i, action):
return [f"{name} = {value};", f"#{self.clock_step_delay}"]

def make_print(self, i, action):
name = verilog_name(action.port.name)
return [f'$display("{action.port.debug_name} = '
f'{action.format_str}", {name});']
ports = ", ".join(f"{self.make_name(port)}" for port in action.ports)
if ports:
ports = ", " + ports
return [f'$display("{action.format_str}"{ports});']

def make_expect(self, i, action):
if value_utils.is_any(action.value):
return []
name = self.make_name(action.port)
if isinstance(action.port, SelectPath):
name = f"dut.{action.port.system_verilog_path}"
debug_name = action.port[-1].name
elif isinstance(action.port, fault.WrappedVerilogInternalPort):
name = f"dut.{action.port.path}"
debug_name = name
else:
name = verilog_name(action.port.name)
debug_name = action.port.name
value = action.value
if isinstance(value, actions.Peek):
Expand Down
20 changes: 7 additions & 13 deletions fault/tester.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,20 +44,16 @@ class Tester:

__test__ = False # Tell pytest to skip this class for discovery

def __init__(self, circuit: m.Circuit, clock: m.ClockType = None,
default_print_format_str: str = "%x"):
def __init__(self, circuit: m.Circuit, clock: m.ClockType = None):
"""
`circuit`: the device under test (a magma circuit)
`clock`: optional, a port from `circuit` corresponding to the clock
`default_print_format_str`: optional, this sets the default format
string used for the `print` method
"""
self._circuit = circuit
self.actions = []
if clock is not None and not isinstance(clock, m.ClockType):
raise TypeError(f"Expected clock port: {clock, type(clock)}")
self.clock = clock
self.default_print_format_str = default_print_format_str
self.targets = {}
# For public verilator modules
self.verilator_includes = []
Expand Down Expand Up @@ -99,16 +95,14 @@ def peek(self, port):
"""
return actions.Peek(port)

def print(self, port, format_str=None):
def print(self, format_str, *args):
"""
Print out the current value of `port`.
Prints out `format_str`
If `format_str` is not specified, it will use
`self.default_print_format_str`
`*args` should be a variable number of magma ports used to fill in the
format string
"""
if format_str is None:
format_str = self.default_print_format_str
self.actions.append(actions.Print(port, format_str))
self.actions.append(actions.Print(format_str, *args))

def expect(self, port, value):
"""
Expand Down Expand Up @@ -187,7 +181,7 @@ def retarget(self, new_circuit, clock=None):
# Check that the interface of self._circuit is a subset of new_circuit
check_interface_is_subset(self._circuit, new_circuit)

new_tester = Tester(new_circuit, clock, self.default_print_format_str)
new_tester = Tester(new_circuit, clock)
new_tester.actions = [action.retarget(new_circuit, clock) for action in
self.actions]
return new_tester
Expand Down
12 changes: 8 additions & 4 deletions fault/verilator_target.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,9 +186,11 @@ def make_poke(self, i, action):
return result

def make_print(self, i, action):
name = verilog_name(action.port.name)
return [f'printf("{action.port.debug_name} = '
f'{action.format_str}\\n", top->{name});']
ports = ", ".join(f"top->{verilog_name(port.name)}" for port in
action.ports)
if ports:
ports = ", " + ports
return [f'printf("{action.format_str}"{ports});']

def make_expect(self, i, action):
# For verilator, if an expect is "AnyValue" we don't need to
Expand Down Expand Up @@ -315,7 +317,9 @@ def run(self, actions, verilator_includes=[], num_tests=0,
verilator_make_cmd = verilator_utils.verilator_make_cmd(
self.circuit_name)
assert not self.run_from_directory(verilator_make_cmd)
assert not self.run_from_directory(f"./obj_dir/V{self.circuit_name}")
assert not self.run_from_directory(
f"./obj_dir/V{self.circuit_name} | tee "
f"./obj_dir/{self.circuit_name}.log")

def add_assumptions(self, circuit, actions, i):
main_body = ""
Expand Down
5 changes: 2 additions & 3 deletions fault/verilog_target.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,19 +75,18 @@ def generate_array_action_code(self, i, action):
return flatten(result)

def generate_action_code(self, i, action):
if isinstance(action, (actions.PortAction, actions.Print)) and \
if isinstance(action, (actions.PortAction)) and \
isinstance(action.port, m.ArrayType) and \
not isinstance(action.port.T, m.BitKind):
return self.generate_array_action_code(i, action)
elif isinstance(action, (actions.PortAction, actions.Print)) and \
elif isinstance(action, (actions.PortAction)) and \
isinstance(action.port, SelectPath) and \
isinstance(action.port[-1], m.ArrayType) and \
not isinstance(action.port[-1].T, m.BitKind):
return self.generate_array_action_code(i, action)
if isinstance(action, actions.Poke):
return self.make_poke(i, action)
if isinstance(action, actions.Print):
name = verilog_name(action.port.name)
return self.make_print(i, action)
if isinstance(action, actions.Expect):
return self.make_expect(i, action)
Expand Down
2 changes: 1 addition & 1 deletion tests/test_action.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ def test_action_strs():
assert str(Expect(circ.O, 1)) == 'Expect(BasicClkCircuit.O, 1)'
assert str(Eval()) == 'Eval()'
assert str(Step(circ.CLK, 1)) == 'Step(BasicClkCircuit.CLK, steps=1)'
assert str(Print(circ.O, "%08x")) == 'Print(BasicClkCircuit.O, "%08x")'
assert str(Print("%08x", circ.O)) == 'Print("%08x", BasicClkCircuit.O)'
assert str(Peek(circ.O)) == 'Peek(BasicClkCircuit.O)'
8 changes: 4 additions & 4 deletions tests/test_magma_simulator_target.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,22 +64,22 @@ def test_magma_simulator_target_clock(backend, capfd):
circ = common.TestBasicClkCircuit
actions = [
Poke(circ.I, BitVector(0, 1)),
Print(circ.I),
Print("%d", circ.I),
Expect(circ.O, BitVector(0, 1)),
# TODO(rsetaluri): Figure out how to set clock value directly with the
# coreir simulator. Currently it does not allow this.
# Poke(circ.CLK, BitVector(0, 1)),
Step(circ.CLK, 1),
Poke(circ.I, BitVector(1, 1)),
Eval(),
Print(circ.O),
Print("%d", circ.O),
]
run(circ, actions, circ.CLK, backend)
out, err = capfd.readouterr()
lines = out.splitlines()

assert lines[-2] == "BasicClkCircuit.I = 0", "Print output incorrect"
assert lines[-1] == "BasicClkCircuit.O = 1", "Print output incorrect"
assert lines[-2] == "0", "Print output incorrect"
assert lines[-1] == "1", "Print output incorrect"


def test_magma_simulator_target_peek(backend):
Expand Down
27 changes: 14 additions & 13 deletions tests/test_tester.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,13 @@ def test_tester_basic(target, simulator):
tester.poke(circ.I, 1)
tester.eval()
tester.expect(circ.O, 1)
tester.print(circ.O, "%08x")
tester.print("%08x", circ.O)
check(tester.actions[1], Poke(circ.I, 1))
check(tester.actions[2], Eval())
check(tester.actions[3], Expect(circ.O, 1))
check(tester.actions[4], Print(circ.O, "%08x"))
print(tester.actions[4])
print(Print("%08x", circ.O))
check(tester.actions[4], Print("%08x", circ.O))
tester.eval()
check(tester.actions[5], Eval())
with tempfile.TemporaryDirectory() as _dir:
Expand Down Expand Up @@ -132,28 +134,27 @@ def test_retarget_tester(target, simulator):
Expect(circ.O, 0),
Poke(circ.CLK, 0),
Step(circ.CLK, 1),
Print(circ.O, "%08x")
Print("%08x", circ.O)
]
tester = fault.Tester(circ, circ.CLK, default_print_format_str="%08x")
tester = fault.Tester(circ, circ.CLK)
tester.poke(circ.I, 0)
tester.eval()
tester.expect(circ.O, 0)
tester.poke(circ.CLK, 0)
tester.step()
tester.print(circ.O)
tester.print("%08x", circ.O)
for i, exp in enumerate(expected):
check(tester.actions[i], exp)

circ_copy = common.TestBasicClkCircuitCopy
copy = tester.retarget(circ_copy, circ_copy.CLK)
assert copy.default_print_format_str == "%08x"
copy_expected = [
Poke(circ_copy.I, 0),
Eval(),
Expect(circ_copy.O, 0),
Poke(circ_copy.CLK, 0),
Step(circ_copy.CLK, 1),
Print(circ_copy.O, "%08x")
Print("%08x", circ_copy.O)
]
for i, exp in enumerate(copy_expected):
check(copy.actions[i], exp)
Expand All @@ -175,13 +176,13 @@ def test_run_error():

def test_print_tester(capsys):
circ = common.TestBasicClkCircuit
tester = fault.Tester(circ, circ.CLK, default_print_format_str="%08x")
tester = fault.Tester(circ, circ.CLK)
tester.poke(circ.I, 0)
tester.eval()
tester.expect(circ.O, 0)
tester.poke(circ.CLK, 0)
tester.step()
tester.print(circ.O)
tester.print("%08x", circ.O)
print(tester)
out, err = capsys.readouterr()
assert "\n".join(out.splitlines()[1:]) == """\
Expand All @@ -191,25 +192,25 @@ def test_print_tester(capsys):
2: Expect(BasicClkCircuit.O, 0)
3: Poke(BasicClkCircuit.CLK, 0)
4: Step(BasicClkCircuit.CLK, steps=1)
5: Print(BasicClkCircuit.O, "%08x")
5: Print("%08x", BasicClkCircuit.O)
"""


def test_print_arrays(capsys):
circ = common.TestDoubleNestedArraysCircuit
tester = fault.Tester(circ, default_print_format_str="%08x")
tester = fault.Tester(circ)
tester.poke(circ.I, [[0, 1, 2], [3, 4, 5]])
tester.eval()
tester.expect(circ.O, [[0, 1, 2], [3, 4, 5]])
tester.print(circ.O)
tester.print("%08x", circ.O)
print(tester)
out, err = capsys.readouterr()
assert "\n".join(out.splitlines()[1:]) == """\
Actions:
0: Poke(DoubleNestedArraysCircuit.I, Array([Array([BitVector[4](0), BitVector[4](1), BitVector[4](2)], 3), Array([BitVector[4](3), BitVector[4](4), BitVector[4](5)], 3)], 2))
1: Eval()
2: Expect(DoubleNestedArraysCircuit.O, Array([Array([BitVector[4](0), BitVector[4](1), BitVector[4](2)], 3), Array([BitVector[4](3), BitVector[4](4), BitVector[4](5)], 3)], 2))
3: Print(DoubleNestedArraysCircuit.O, "%08x")
3: Print("%08x", DoubleNestedArraysCircuit.O)
""" # nopep8


Expand Down
2 changes: 1 addition & 1 deletion tests/test_vector_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def test_tester_clock():
circ = common.TestBasicClkCircuit
builder = VectorBuilder(circ)
builder.process(Poke(circ.I, BitVector(0, 1)))
builder.process(Print(circ.O))
builder.process(Print("%x", circ.O))
builder.process(Expect(circ.O, BitVector(0, 1)))
assert builder.vectors == [
[BitVector(0, 1), BitVector(0, 1), fault.AnyValue]
Expand Down
6 changes: 3 additions & 3 deletions tests/test_verilator_target.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,14 @@ def test_verilator_trace():
circ = common.TestBasicClkCircuit
actions = [
Poke(circ.I, 0),
Print(circ.I),
Print("%x", circ.I),
Expect(circ.O, 0),
Poke(circ.CLK, 0),
Print(circ.O),
Print("%x", circ.O),
Step(circ.CLK, 1),
Poke(circ.I, BitVector[1](1)),
Eval(),
Print(circ.O),
Print("%x", circ.O),
]
flags = ["-Wno-lint", "--trace"]

Expand Down
Loading

0 comments on commit 90efc27

Please sign in to comment.