From dfc2ecd50d15eebf4807c4a042f8a07769ac40c4 Mon Sep 17 00:00:00 2001 From: whitequark Date: Fri, 13 Sep 2019 14:28:43 +0000 Subject: [PATCH] hdl.ast: add Value.xor, mapping to $reduce_xor. Fixes #147. --- nmigen/back/pysim.py | 3 +++ nmigen/hdl/ast.py | 10 ++++++++++ nmigen/test/test_hdl_ast.py | 4 ++++ nmigen/test/test_sim.py | 6 ++++++ 4 files changed, 23 insertions(+) diff --git a/nmigen/back/pysim.py b/nmigen/back/pysim.py index cf4b998..4ff3ed5 100644 --- a/nmigen/back/pysim.py +++ b/nmigen/back/pysim.py @@ -135,6 +135,9 @@ class _RHSValueCompiler(_ValueCompiler): val, = value.operands mask = (1 << len(val)) - 1 return lambda state: normalize(arg(state) == mask, shape) + if value.op == "r^": + # Believe it or not, this is the fastest way to compute a sideways XOR in Python. + return lambda state: normalize(str(arg(state)).count("1") % 2, shape) elif len(value.operands) == 2: lhs, rhs = map(self, value.operands) if value.op == "+": diff --git a/nmigen/hdl/ast.py b/nmigen/hdl/ast.py index b91fb50..51e1d0d 100644 --- a/nmigen/hdl/ast.py +++ b/nmigen/hdl/ast.py @@ -157,6 +157,16 @@ class Value(metaclass=ABCMeta): """ return Operator("r&", [self]) + def xor(self): + """Compute pairwise exclusive-or of every bit. + + Returns + ------- + Value, out + ``1`` if an odd number of bits are set, ``0`` if an even number of bits are set. + """ + return Operator("r^", [self]) + def implies(premise, conclusion): """Implication. diff --git a/nmigen/test/test_hdl_ast.py b/nmigen/test/test_hdl_ast.py index e0c43ca..2b85119 100644 --- a/nmigen/test/test_hdl_ast.py +++ b/nmigen/test/test_hdl_ast.py @@ -259,6 +259,10 @@ class OperatorTestCase(FHDLTestCase): v = Const(0b101).all() self.assertEqual(repr(v), "(r& (const 3'd5))") + def test_xor(self): + v = Const(0b101).xor() + self.assertEqual(repr(v), "(r^ (const 3'd5))") + def test_hash(self): with self.assertRaises(TypeError): hash(Const(0) + Const(0)) diff --git a/nmigen/test/test_sim.py b/nmigen/test/test_sim.py index eb283a2..fae5718 100644 --- a/nmigen/test/test_sim.py +++ b/nmigen/test/test_sim.py @@ -69,6 +69,12 @@ class SimulatorUnitTestCase(FHDLTestCase): self.assertStatement(stmt, [C(0b01, 2)], C(0)) self.assertStatement(stmt, [C(0b11, 2)], C(1)) + def test_xor(self): + stmt = lambda y, a: y.eq(a.xor()) + self.assertStatement(stmt, [C(0b00, 2)], C(0)) + self.assertStatement(stmt, [C(0b01, 2)], C(1)) + self.assertStatement(stmt, [C(0b11, 2)], C(0)) + def test_add(self): stmt = lambda y, a, b: y.eq(a + b) self.assertStatement(stmt, [C(0, 4), C(1, 4)], C(1, 4)) -- 2.30.2