back.pysim: implement most operators and add tests.
This commit is contained in:
parent
d9aaf0114b
commit
474d46ced8
|
@ -1,5 +1,7 @@
|
|||
[run]
|
||||
branch = True
|
||||
include =
|
||||
nmigen/*
|
||||
omit =
|
||||
nmigen/test/*
|
||||
*/__init__.py
|
||||
|
|
|
@ -27,13 +27,7 @@ class _State:
|
|||
def get(self, signal):
|
||||
return self.curr[signal]
|
||||
|
||||
def set_curr(self, signal, value):
|
||||
assert isinstance(value, int)
|
||||
if self.curr[signal] != value:
|
||||
self.curr_dirty.add(signal)
|
||||
self.curr[signal] = value
|
||||
|
||||
def set_next(self, signal, value):
|
||||
def set(self, signal, value):
|
||||
assert isinstance(value, int)
|
||||
if self.next[signal] != value:
|
||||
self.next_dirty.add(signal)
|
||||
|
@ -48,11 +42,6 @@ class _State:
|
|||
new_value = self.curr[signal]
|
||||
return old_value, new_value
|
||||
|
||||
def iter_dirty(self):
|
||||
dirty, self.dirty = self.dirty, ValueSet()
|
||||
for signal in dirty:
|
||||
yield signal, self.curr[signal], self.next[signal]
|
||||
|
||||
|
||||
normalize = Const.normalize
|
||||
|
||||
|
@ -82,6 +71,8 @@ class _RHSValueCompiler(ValueTransformer):
|
|||
return lambda state: normalize(~arg(state), shape)
|
||||
if value.op == "-":
|
||||
return lambda state: normalize(-arg(state), shape)
|
||||
if value.op == "b":
|
||||
return lambda state: normalize(bool(arg(state)), shape)
|
||||
elif len(value.operands) == 2:
|
||||
lhs, rhs = map(self, value.operands)
|
||||
if value.op == "+":
|
||||
|
@ -96,11 +87,21 @@ class _RHSValueCompiler(ValueTransformer):
|
|||
return lambda state: normalize(lhs(state) ^ rhs(state), shape)
|
||||
if value.op == "==":
|
||||
return lambda state: normalize(lhs(state) == rhs(state), shape)
|
||||
if value.op == "!=":
|
||||
return lambda state: normalize(lhs(state) != rhs(state), shape)
|
||||
if value.op == "<":
|
||||
return lambda state: normalize(lhs(state) < rhs(state), shape)
|
||||
if value.op == "<=":
|
||||
return lambda state: normalize(lhs(state) <= rhs(state), shape)
|
||||
if value.op == ">":
|
||||
return lambda state: normalize(lhs(state) > rhs(state), shape)
|
||||
if value.op == ">=":
|
||||
return lambda state: normalize(lhs(state) >= rhs(state), shape)
|
||||
elif len(value.operands) == 3:
|
||||
if value.op == "m":
|
||||
sel, val1, val0 = map(self, value.operands)
|
||||
return lambda state: val1(state) if sel(state) else val0(state)
|
||||
raise NotImplementedError("Operator '{}' not implemented".format(value.op))
|
||||
raise NotImplementedError("Operator '{!r}' not implemented".format(value.op)) # :nocov:
|
||||
|
||||
def on_Slice(self, value):
|
||||
shape = value.shape()
|
||||
|
@ -148,7 +149,7 @@ class _StatementCompiler(StatementTransformer):
|
|||
|
||||
def lhs_compiler(self, value):
|
||||
# TODO
|
||||
return lambda state, arg: state.set_next(value, arg)
|
||||
return lambda state, arg: state.set(value, arg)
|
||||
|
||||
def on_Assign(self, stmt):
|
||||
assert isinstance(stmt.lhs, Signal)
|
||||
|
|
|
@ -8,7 +8,7 @@ from ..tools import *
|
|||
|
||||
|
||||
__all__ = [
|
||||
"Value", "Const", "Operator", "Mux", "Part", "Slice", "Cat", "Repl",
|
||||
"Value", "Const", "C", "Operator", "Mux", "Part", "Slice", "Cat", "Repl",
|
||||
"Signal", "ClockSignal", "ResetSignal",
|
||||
"Statement", "Assign", "Switch", "Delay", "Tick", "Passive",
|
||||
"ValueKey", "ValueDict", "ValueSet",
|
||||
|
|
113
nmigen/test/test_sim.py
Normal file
113
nmigen/test/test_sim.py
Normal file
|
@ -0,0 +1,113 @@
|
|||
from .tools import *
|
||||
from ..fhdl.ast import *
|
||||
from ..fhdl.ir import *
|
||||
from ..back.pysim import *
|
||||
|
||||
|
||||
class SimulatorUnitTestCase(FHDLTestCase):
|
||||
def assertOperator(self, stmt, inputs, output):
|
||||
inputs = [Value.wrap(i) for i in inputs]
|
||||
output = Value.wrap(output)
|
||||
|
||||
isigs = [Signal(i.shape(), name=n) for i, n in zip(inputs, "abcd")]
|
||||
osig = Signal(output.shape(), name="y")
|
||||
|
||||
frag = Fragment()
|
||||
frag.add_statements(osig.eq(stmt(*isigs)))
|
||||
frag.drive(osig)
|
||||
|
||||
with Simulator(frag,
|
||||
vcd_file =open("test.vcd", "w"),
|
||||
gtkw_file=open("test.gtkw", "w"),
|
||||
gtkw_signals=[*isigs, osig]) as sim:
|
||||
def process():
|
||||
for isig, input in zip(isigs, inputs):
|
||||
yield isig.eq(input)
|
||||
yield Delay()
|
||||
self.assertEqual((yield osig), output.value)
|
||||
sim.add_process(process)
|
||||
sim.run()
|
||||
|
||||
def test_invert(self):
|
||||
stmt = lambda a: ~a
|
||||
self.assertOperator(stmt, [C(0b0000, 4)], C(0b1111, 4))
|
||||
self.assertOperator(stmt, [C(0b1010, 4)], C(0b0101, 4))
|
||||
self.assertOperator(stmt, [C(0, 4)], C(-1, 4))
|
||||
|
||||
def test_neg(self):
|
||||
stmt = lambda a: -a
|
||||
self.assertOperator(stmt, [C(0b0000, 4)], C(0b0000, 4))
|
||||
self.assertOperator(stmt, [C(0b0001, 4)], C(0b1111, 4))
|
||||
self.assertOperator(stmt, [C(0b1010, 4)], C(0b0110, 4))
|
||||
self.assertOperator(stmt, [C(1, 4)], C(-1, 4))
|
||||
self.assertOperator(stmt, [C(5, 4)], C(-5, 4))
|
||||
|
||||
def test_bool(self):
|
||||
stmt = lambda a: a.bool()
|
||||
self.assertOperator(stmt, [C(0, 4)], C(0))
|
||||
self.assertOperator(stmt, [C(1, 4)], C(1))
|
||||
self.assertOperator(stmt, [C(2, 4)], C(1))
|
||||
|
||||
def test_add(self):
|
||||
stmt = lambda a, b: a + b
|
||||
self.assertOperator(stmt, [C(0, 4), C(1, 4)], C(1, 4))
|
||||
self.assertOperator(stmt, [C(-5, 4), C(-5, 4)], C(-10, 5))
|
||||
|
||||
def test_sub(self):
|
||||
stmt = lambda a, b: a - b
|
||||
self.assertOperator(stmt, [C(2, 4), C(1, 4)], C(1, 4))
|
||||
self.assertOperator(stmt, [C(0, 4), C(1, 4)], C(-1, 4))
|
||||
self.assertOperator(stmt, [C(0, 4), C(10, 4)], C(-10, 5))
|
||||
|
||||
def test_and(self):
|
||||
stmt = lambda a, b: a & b
|
||||
self.assertOperator(stmt, [C(0b1100, 4), C(0b1010, 4)], C(0b1000, 4))
|
||||
|
||||
def test_or(self):
|
||||
stmt = lambda a, b: a | b
|
||||
self.assertOperator(stmt, [C(0b1100, 4), C(0b1010, 4)], C(0b1110, 4))
|
||||
|
||||
def test_xor(self):
|
||||
stmt = lambda a, b: a ^ b
|
||||
self.assertOperator(stmt, [C(0b1100, 4), C(0b1010, 4)], C(0b0110, 4))
|
||||
|
||||
def test_eq(self):
|
||||
stmt = lambda a, b: a == b
|
||||
self.assertOperator(stmt, [C(0, 4), C(0, 4)], C(1))
|
||||
self.assertOperator(stmt, [C(0, 4), C(1, 4)], C(0))
|
||||
self.assertOperator(stmt, [C(1, 4), C(0, 4)], C(0))
|
||||
|
||||
def test_ne(self):
|
||||
stmt = lambda a, b: a != b
|
||||
self.assertOperator(stmt, [C(0, 4), C(0, 4)], C(0))
|
||||
self.assertOperator(stmt, [C(0, 4), C(1, 4)], C(1))
|
||||
self.assertOperator(stmt, [C(1, 4), C(0, 4)], C(1))
|
||||
|
||||
def test_lt(self):
|
||||
stmt = lambda a, b: a < b
|
||||
self.assertOperator(stmt, [C(0, 4), C(0, 4)], C(0))
|
||||
self.assertOperator(stmt, [C(0, 4), C(1, 4)], C(1))
|
||||
self.assertOperator(stmt, [C(1, 4), C(0, 4)], C(0))
|
||||
|
||||
def test_ge(self):
|
||||
stmt = lambda a, b: a >= b
|
||||
self.assertOperator(stmt, [C(0, 4), C(0, 4)], C(1))
|
||||
self.assertOperator(stmt, [C(0, 4), C(1, 4)], C(0))
|
||||
self.assertOperator(stmt, [C(1, 4), C(0, 4)], C(1))
|
||||
|
||||
def test_gt(self):
|
||||
stmt = lambda a, b: a > b
|
||||
self.assertOperator(stmt, [C(0, 4), C(0, 4)], C(0))
|
||||
self.assertOperator(stmt, [C(0, 4), C(1, 4)], C(0))
|
||||
self.assertOperator(stmt, [C(1, 4), C(0, 4)], C(1))
|
||||
|
||||
def test_le(self):
|
||||
stmt = lambda a, b: a <= b
|
||||
self.assertOperator(stmt, [C(0, 4), C(0, 4)], C(1))
|
||||
self.assertOperator(stmt, [C(0, 4), C(1, 4)], C(1))
|
||||
self.assertOperator(stmt, [C(1, 4), C(0, 4)], C(0))
|
||||
|
||||
def test_mux(self):
|
||||
stmt = lambda a, b, c: Mux(c, a, b)
|
||||
self.assertOperator(stmt, [C(2, 4), C(3, 4), C(0)], C(3, 4))
|
||||
self.assertOperator(stmt, [C(2, 4), C(3, 4), C(1)], C(2, 4))
|
Loading…
Reference in a new issue