From f61e2b42e80bbfa5f4142860e20ffdf6291847c3 Mon Sep 17 00:00:00 2001 From: Stefan Holst Date: Sat, 24 Jun 2023 13:34:35 +0900 Subject: [PATCH] support more cells in logic sim --- src/kyupy/logic.py | 63 ++++++++++++++++++++++++++++---- src/kyupy/logic_sim.py | 83 ++++++++++++++++++++++++++++++++++++++---- tests/test_logic.py | 12 +++--- 3 files changed, 137 insertions(+), 21 deletions(-) diff --git a/src/kyupy/logic.py b/src/kyupy/logic.py index 6625a17..b0a82a3 100644 --- a/src/kyupy/logic.py +++ b/src/kyupy/logic.py @@ -279,7 +279,14 @@ def bp_to_mv(bpa): return packbits(np.unpackbits(bpa, axis=-1, bitorder='little').swapaxes(-1,-2)) -def bp_buf(out, inp): +def bp4v_buf(out, inp): + unknown = inp[..., 0, :] ^ inp[..., 1, :] + out[..., 0, :] = inp[..., 0, :] | unknown + out[..., 1, :] = inp[..., 1, :] & ~unknown + return out + + +def bp8v_buf(out, inp): unknown = (inp[..., 0, :] ^ inp[..., 1, :]) & ~inp[..., 2, :] out[..., 0, :] = inp[..., 0, :] | unknown out[..., 1, :] = inp[..., 1, :] & ~unknown @@ -287,16 +294,34 @@ def bp_buf(out, inp): return out -def bp_not(out, inp): +def bp4v_not(out, inp): unknown = inp[..., 0, :] ^ inp[..., 1, :] - unknown &= ~inp[..., 2, :] + out[..., 0, :] = ~inp[..., 0, :] | unknown + out[..., 1, :] = ~inp[..., 1, :] & ~unknown + return out + + +def bp8v_not(out, inp): + unknown = (inp[..., 0, :] ^ inp[..., 1, :]) & ~inp[..., 2, :] out[..., 0, :] = ~inp[..., 0, :] | unknown out[..., 1, :] = ~inp[..., 1, :] & ~unknown out[..., 2, :] = inp[..., 2, :] & ~unknown return out -def bp_or(out, *ins): +def bp4v_or(out, *ins): + out[...] = 0 + any_unknown = ins[0][..., 0, :] ^ ins[0][..., 1, :] + for inp in ins[1:]: any_unknown |= inp[..., 0, :] ^ inp[..., 1, :] + any_one = ins[0][..., 0, :] & ins[0][..., 1, :] + for inp in ins[1:]: any_one |= inp[..., 0, :] & inp[..., 1, :] + for inp in ins: + out[..., 0, :] |= inp[..., 0, :] | any_unknown + out[..., 1, :] |= inp[..., 1, :] & (~any_unknown | any_one) + return out + + +def bp8v_or(out, *ins): out[...] = 0 any_unknown = (ins[0][..., 0, :] ^ ins[0][..., 1, :]) & ~ins[0][..., 2, :] for inp in ins[1:]: any_unknown |= (inp[..., 0, :] ^ inp[..., 1, :]) & ~inp[..., 2, :] @@ -309,7 +334,19 @@ def bp_or(out, *ins): return out -def bp_and(out, *ins): +def bp4v_and(out, *ins): + out[...] = 0xff + any_unknown = ins[0][..., 0, :] ^ ins[0][..., 1, :] + for inp in ins[1:]: any_unknown |= inp[..., 0, :] ^ inp[..., 1, :] + any_zero = ~ins[0][..., 0, :] & ~ins[0][..., 1, :] + for inp in ins[1:]: any_zero |= ~inp[..., 0, :] & ~inp[..., 1, :] + for inp in ins: + out[..., 0, :] &= inp[..., 0, :] | (any_unknown & ~any_zero) + out[..., 1, :] &= inp[..., 1, :] & ~any_unknown + return out + + +def bp8v_and(out, *ins): out[...] = 0xff any_unknown = (ins[0][..., 0, :] ^ ins[0][..., 1, :]) & ~ins[0][..., 2, :] for inp in ins[1:]: any_unknown |= (inp[..., 0, :] ^ inp[..., 1, :]) & ~inp[..., 2, :] @@ -323,7 +360,19 @@ def bp_and(out, *ins): return out -def bp_xor(out, *ins): +def bp4v_xor(out, *ins): + out[...] = 0 + any_unknown = ins[0][..., 0, :] ^ ins[0][..., 1, :] + for inp in ins[1:]: any_unknown |= inp[..., 0, :] ^ inp[..., 1, :] + for inp in ins: + out[..., 0, :] ^= inp[..., 0, :] + out[..., 1, :] ^= inp[..., 1, :] + out[..., 0, :] |= any_unknown + out[..., 1, :] &= ~any_unknown + return out + + +def bp8v_xor(out, *ins): out[...] = 0 any_unknown = (ins[0][..., 0, :] ^ ins[0][..., 1, :]) & ~ins[0][..., 2, :] for inp in ins[1:]: any_unknown |= (inp[..., 0, :] ^ inp[..., 1, :]) & ~inp[..., 2, :] @@ -337,7 +386,7 @@ def bp_xor(out, *ins): return out -def bp_latch(out, d, t, q_prev): +def bp8v_latch(out, d, t, q_prev): any_unknown = (t[..., 0, :] ^ t[..., 1, :]) & ~t[..., 2, :] any_unknown |= ((d[..., 0, :] ^ d[..., 1, :]) & ~d[..., 2, :]) & (t[..., 0, :] | t[..., 1, :] | t[..., 2, :]) out[..., 1, :] = (d[..., 1, :] & t[..., 1, :]) | (q_prev[..., 0, :] & ~t[..., 1, :]) diff --git a/src/kyupy/logic_sim.py b/src/kyupy/logic_sim.py index 1eca7fa..6a3ce94 100644 --- a/src/kyupy/logic_sim.py +++ b/src/kyupy/logic_sim.py @@ -78,26 +78,81 @@ class LogicSim(sim.SimOps): if op == sim.BUF1: self.c[o0]=self.c[i0] elif op == sim.INV1: self.c[o0] = ~self.c[i0] elif op == sim.AND2: self.c[o0] = self.c[i0] & self.c[i1] + elif op == sim.AND3: self.c[o0] = self.c[i0] & self.c[i1] & self.c[i2] + elif op == sim.AND4: self.c[o0] = self.c[i0] & self.c[i1] & self.c[i2] & self.c[i3] elif op == sim.NAND2: self.c[o0] = ~(self.c[i0] & self.c[i1]) + elif op == sim.NAND3: self.c[o0] = ~(self.c[i0] & self.c[i1] & self.c[i2]) + elif op == sim.NAND4: self.c[o0] = ~(self.c[i0] & self.c[i1] & self.c[i2] & self.c[i3]) elif op == sim.OR2: self.c[o0] = self.c[i0] | self.c[i1] + elif op == sim.OR3: self.c[o0] = self.c[i0] | self.c[i1] | self.c[i2] + elif op == sim.OR4: self.c[o0] = self.c[i0] | self.c[i1] | self.c[i2] | self.c[i3] elif op == sim.NOR2: self.c[o0] = ~(self.c[i0] | self.c[i1]) + elif op == sim.NOR3: self.c[o0] = ~(self.c[i0] | self.c[i1] | self.c[i2]) + elif op == sim.NOR4: self.c[o0] = ~(self.c[i0] | self.c[i1] | self.c[i2] | self.c[i3]) elif op == sim.XOR2: self.c[o0] = self.c[i0] ^ self.c[i1] + elif op == sim.XOR3: self.c[o0] = self.c[i0] ^ self.c[i1] ^ self.c[i2] + elif op == sim.XOR4: self.c[o0] = self.c[i0] ^ self.c[i1] ^ self.c[i2] ^ self.c[i3] elif op == sim.XNOR2: self.c[o0] = ~(self.c[i0] ^ self.c[i1]) + elif op == sim.XNOR3: self.c[o0] = ~(self.c[i0] ^ self.c[i1] ^ self.c[i2]) + elif op == sim.XNOR4: self.c[o0] = ~(self.c[i0] ^ self.c[i1] ^ self.c[i2] ^ self.c[i3]) elif op == sim.AOI21: self.c[o0] = ~((self.c[i0] & self.c[i1]) | self.c[i2]) else: print(f'unknown op {op}') inject_cb(o0, self.s[o0]) + elif self.m == 4: + for op, o0, i0, i1, i2, i3 in self.ops: + o0, i0, i1, i2, i3 = [self.c_locs[x] for x in (o0, i0, i1, i2, i3)] + if op == sim.BUF1: self.c[o0]=self.c[i0] + elif op == sim.INV1: logic.bp4v_not(self.c[o0], self.c[i0]) + elif op == sim.AND2: logic.bp4v_and(self.c[o0], self.c[i0], self.c[i1]) + elif op == sim.AND3: logic.bp4v_and(self.c[o0], self.c[i0], self.c[i1], self.c[i2]) + elif op == sim.AND4: logic.bp4v_and(self.c[o0], self.c[i0], self.c[i1], self.c[i2], self.c[i3]) + elif op == sim.NAND2: logic.bp4v_and(self.c[o0], self.c[i0], self.c[i1]); logic.bp4v_not(self.c[o0], self.c[o0]) + elif op == sim.NAND3: logic.bp4v_and(self.c[o0], self.c[i0], self.c[i1], self.c[i2]); logic.bp4v_not(self.c[o0], self.c[o0]) + elif op == sim.NAND4: logic.bp4v_and(self.c[o0], self.c[i0], self.c[i1], self.c[i2], self.c[i3]); logic.bp4v_not(self.c[o0], self.c[o0]) + elif op == sim.OR2: logic.bp4v_or(self.c[o0], self.c[i0], self.c[i1]) + elif op == sim.OR3: logic.bp4v_or(self.c[o0], self.c[i0], self.c[i1], self.c[i2]) + elif op == sim.OR4: logic.bp4v_or(self.c[o0], self.c[i0], self.c[i1], self.c[i2], self.c[i3]) + elif op == sim.NOR2: logic.bp4v_or(self.c[o0], self.c[i0], self.c[i1]); logic.bp4v_not(self.c[o0], self.c[o0]) + elif op == sim.NOR3: logic.bp4v_or(self.c[o0], self.c[i0], self.c[i1], self.c[i2]); logic.bp4v_not(self.c[o0], self.c[o0]) + elif op == sim.NOR4: logic.bp4v_or(self.c[o0], self.c[i0], self.c[i1], self.c[i2], self.c[i3]); logic.bp4v_not(self.c[o0], self.c[o0]) + elif op == sim.XOR2: logic.bp4v_xor(self.c[o0], self.c[i0], self.c[i1]) + elif op == sim.XOR3: logic.bp4v_xor(self.c[o0], self.c[i0], self.c[i1], self.c[i2]) + elif op == sim.XOR4: logic.bp4v_xor(self.c[o0], self.c[i0], self.c[i1], self.c[i2], self.c[i3]) + elif op == sim.XNOR2: logic.bp4v_xor(self.c[o0], self.c[i0], self.c[i1]); logic.bp4v_not(self.c[o0], self.c[o0]) + elif op == sim.XNOR3: logic.bp4v_xor(self.c[o0], self.c[i0], self.c[i1], self.c[i2]); logic.bp4v_not(self.c[o0], self.c[o0]) + elif op == sim.XNOR4: logic.bp4v_xor(self.c[o0], self.c[i0], self.c[i1], self.c[i2], self.c[i3]); logic.bp4v_not(self.c[o0], self.c[o0]) + elif op == sim.AOI21: + logic.bp4v_and(self.c[self.c_locs[self.tmp_idx]], self.c[i0], self.c[i1]) + logic.bp4v_or(self.c[o0], self.c[self.c_locs[self.tmp_idx]], self.c[i2]) + logic.bp4v_not(self.c[o0], self.c[o0]) + else: print(f'unknown op {op}') else: for op, o0, i0, i1, i2, i3 in self.ops: o0, i0, i1, i2, i3 = [self.c_locs[x] for x in (o0, i0, i1, i2, i3)] if op == sim.BUF1: self.c[o0]=self.c[i0] - elif op == sim.INV1: logic.bp_not(self.c[o0], self.c[i0]) - elif op == sim.AND2: logic.bp_and(self.c[o0], self.c[i0], self.c[i1]) - elif op == sim.NAND2: logic.bp_and(self.c[o0], self.c[i0], self.c[i1]); logic.bp_not(self.c[o0], self.c[o0]) - elif op == sim.OR2: logic.bp_or(self.c[o0], self.c[i0], self.c[i1]) - elif op == sim.NOR2: logic.bp_or(self.c[o0], self.c[i0], self.c[i1]); logic.bp_not(self.c[o0], self.c[o0]) - elif op == sim.XOR2: logic.bp_xor(self.c[o0], self.c[i0], self.c[i1]) - elif op == sim.XNOR2: logic.bp_xor(self.c[o0], self.c[i0], self.c[i1]); logic.bp_not(self.c[o0], self.c[o0]) - elif op == sim.AOI21: logic.bp_and(self.c[self.tmp_idx], self.c[i0], self.c[i1]); logic.bp_or(self.c[o0], self.c[self.tmp_idx], self.c[i2]); logic.bp_not(self.c[o0], self.c[o0]) + elif op == sim.INV1: logic.bp8v_not(self.c[o0], self.c[i0]) + elif op == sim.AND2: logic.bp8v_and(self.c[o0], self.c[i0], self.c[i1]) + elif op == sim.AND3: logic.bp8v_and(self.c[o0], self.c[i0], self.c[i1], self.c[i2]) + elif op == sim.AND4: logic.bp8v_and(self.c[o0], self.c[i0], self.c[i1], self.c[i2], self.c[i3]) + elif op == sim.NAND2: logic.bp8v_and(self.c[o0], self.c[i0], self.c[i1]); logic.bp8v_not(self.c[o0], self.c[o0]) + elif op == sim.NAND3: logic.bp8v_and(self.c[o0], self.c[i0], self.c[i1], self.c[i2]); logic.bp8v_not(self.c[o0], self.c[o0]) + elif op == sim.NAND4: logic.bp8v_and(self.c[o0], self.c[i0], self.c[i1], self.c[i2], self.c[i3]); logic.bp8v_not(self.c[o0], self.c[o0]) + elif op == sim.OR2: logic.bp8v_or(self.c[o0], self.c[i0], self.c[i1]) + elif op == sim.OR3: logic.bp8v_or(self.c[o0], self.c[i0], self.c[i1], self.c[i2]) + elif op == sim.OR4: logic.bp8v_or(self.c[o0], self.c[i0], self.c[i1], self.c[i2], self.c[i3]) + elif op == sim.NOR2: logic.bp8v_or(self.c[o0], self.c[i0], self.c[i1]); logic.bp8v_not(self.c[o0], self.c[o0]) + elif op == sim.NOR3: logic.bp8v_or(self.c[o0], self.c[i0], self.c[i1], self.c[i2]); logic.bp8v_not(self.c[o0], self.c[o0]) + elif op == sim.NOR4: logic.bp8v_or(self.c[o0], self.c[i0], self.c[i1], self.c[i2], self.c[i3]); logic.bp8v_not(self.c[o0], self.c[o0]) + elif op == sim.XOR2: logic.bp8v_xor(self.c[o0], self.c[i0], self.c[i1]) + elif op == sim.XOR3: logic.bp8v_xor(self.c[o0], self.c[i0], self.c[i1], self.c[i2]) + elif op == sim.XOR4: logic.bp8v_xor(self.c[o0], self.c[i0], self.c[i1], self.c[i2], self.c[i3]) + elif op == sim.XNOR2: logic.bp8v_xor(self.c[o0], self.c[i0], self.c[i1]); logic.bp8v_not(self.c[o0], self.c[o0]) + elif op == sim.XNOR3: logic.bp8v_xor(self.c[o0], self.c[i0], self.c[i1], self.c[i2]); logic.bp8v_not(self.c[o0], self.c[o0]) + elif op == sim.XNOR4: logic.bp8v_xor(self.c[o0], self.c[i0], self.c[i1], self.c[i2], self.c[i3]); logic.bp8v_not(self.c[o0], self.c[o0]) + elif op == sim.AOI21: + logic.bp8v_and(self.c[self.c_locs[self.tmp_idx]], self.c[i0], self.c[i1]) + logic.bp8v_or(self.c[o0], self.c[self.c_locs[self.tmp_idx]], self.c[i2]) + logic.bp8v_not(self.c[o0], self.c[o0]) else: print(f'unknown op {op}') if inject_cb is not None: inject_cb(o0, self.s[o0]) @@ -139,10 +194,22 @@ def _prop_cpu(ops, c_locs, c): if op == sim.BUF1: c[o0]=c[i0] elif op == sim.INV1: c[o0] = ~c[i0] elif op == sim.AND2: c[o0] = c[i0] & c[i1] + elif op == sim.AND3: c[o0] = c[i0] & c[i1] & c[i2] + elif op == sim.AND4: c[o0] = c[i0] & c[i1] & c[i2] & c[i3] elif op == sim.NAND2: c[o0] = ~(c[i0] & c[i1]) + elif op == sim.NAND3: c[o0] = ~(c[i0] & c[i1] & c[i2]) + elif op == sim.NAND4: c[o0] = ~(c[i0] & c[i1] & c[i2] & c[i3]) elif op == sim.OR2: c[o0] = c[i0] | c[i1] + elif op == sim.OR3: c[o0] = c[i0] | c[i1] | c[i2] + elif op == sim.OR4: c[o0] = c[i0] | c[i1] | c[i2] | c[i3] elif op == sim.NOR2: c[o0] = ~(c[i0] | c[i1]) + elif op == sim.NOR3: c[o0] = ~(c[i0] | c[i1] | c[i2]) + elif op == sim.NOR4: c[o0] = ~(c[i0] | c[i1] | c[i2] | c[i3]) elif op == sim.XOR2: c[o0] = c[i0] ^ c[i1] + elif op == sim.XOR3: c[o0] = c[i0] ^ c[i1] ^ c[i2] + elif op == sim.XOR4: c[o0] = c[i0] ^ c[i1] ^ c[i2] ^ c[i3] elif op == sim.XNOR2: c[o0] = ~(c[i0] ^ c[i1]) + elif op == sim.XNOR3: c[o0] = ~(c[i0] ^ c[i1] ^ c[i2]) + elif op == sim.XNOR4: c[o0] = ~(c[i0] ^ c[i1] ^ c[i2] ^ c[i3]) elif op == sim.AOI21: c[o0] = ~((c[i0] & c[i1]) | c[i2]) else: print(f'unknown op {op}') diff --git a/tests/test_logic.py b/tests/test_logic.py index 9e74ec8..b87f1fc 100644 --- a/tests/test_logic.py +++ b/tests/test_logic.py @@ -63,13 +63,13 @@ def test_bparray(): out_8v = np.empty((64, 3, 1), dtype=np.uint8) - assert_equal_shape_and_contents(bp_to_mv(lg.bp_buf(out_8v, x1_8v))[:,0], mvarray('00000000XXXXXXXXXXXXXXXX11111111PPPPPPPPRRRRRRRRFFFFFFFFNNNNNNNN')) - assert_equal_shape_and_contents(bp_to_mv(lg.bp_or(out_8v, x1_8v, x2_8v))[:,0], mvarray('0XX1PRFNXXX1XXXXXXX1XXXX11111111PXX1PRFNRXX1RRNNFXX1FNFNNXX1NNNN')) - assert_equal_shape_and_contents(bp_to_mv(lg.bp_and(out_8v, x1_8v, x2_8v))[:,0], mvarray('000000000XXXXXXX0XXXXXXX0XX1PRFN0XXPPPPP0XXRPRPR0XXFPPFF0XXNPRFN')) - assert_equal_shape_and_contents(bp_to_mv(lg.bp_xor(out_8v, x1_8v, x2_8v))[:,0], mvarray('0XX1PRFNXXXXXXXXXXXXXXXX1XX0NFRPPXXNPRFNRXXFRPNFFXXRFNPRNXXPNFRP')) + assert_equal_shape_and_contents(bp_to_mv(lg.bp8v_buf(out_8v, x1_8v))[:,0], mvarray('00000000XXXXXXXXXXXXXXXX11111111PPPPPPPPRRRRRRRRFFFFFFFFNNNNNNNN')) + assert_equal_shape_and_contents(bp_to_mv(lg.bp8v_or(out_8v, x1_8v, x2_8v))[:,0], mvarray('0XX1PRFNXXX1XXXXXXX1XXXX11111111PXX1PRFNRXX1RRNNFXX1FNFNNXX1NNNN')) + assert_equal_shape_and_contents(bp_to_mv(lg.bp8v_and(out_8v, x1_8v, x2_8v))[:,0], mvarray('000000000XXXXXXX0XXXXXXX0XX1PRFN0XXPPPPP0XXRPRPR0XXFPPFF0XXNPRFN')) + assert_equal_shape_and_contents(bp_to_mv(lg.bp8v_xor(out_8v, x1_8v, x2_8v))[:,0], mvarray('0XX1PRFNXXXXXXXXXXXXXXXX1XX0NFRPPXXNPRFNRXXFRPNFFXXRFNPRNXXPNFRP')) x30_8v = bparray('0000000000000000000000000000000000000000000000000000000000000000') x31_8v = bparray('1111111111111111111111111111111111111111111111111111111111111111') - assert_equal_shape_and_contents(bp_to_mv(lg.bp_latch(out_8v, x1_8v, x2_8v, x30_8v))[:,0], mvarray('0XX000000XXXXXXX0XXXXXXX0XX10R110XX000000XXR0R0R0XXF001F0XX10R11')) - assert_equal_shape_and_contents(bp_to_mv(lg.bp_latch(out_8v, x1_8v, x2_8v, x31_8v))[:,0], mvarray('1XX01F001XXXXXXX1XXXXXXX1XX111111XX01F001XXR110R1XXF1F1F1XX11111')) + assert_equal_shape_and_contents(bp_to_mv(lg.bp8v_latch(out_8v, x1_8v, x2_8v, x30_8v))[:,0], mvarray('0XX000000XXXXXXX0XXXXXXX0XX10R110XX000000XXR0R0R0XXF001F0XX10R11')) + assert_equal_shape_and_contents(bp_to_mv(lg.bp8v_latch(out_8v, x1_8v, x2_8v, x31_8v))[:,0], mvarray('1XX01F001XXXXXXX1XXXXXXX1XX111111XX01F001XXR110R1XXF1F1F1XX11111'))