Browse Source

support more cells in logic sim

devel
Stefan Holst 1 year ago
parent
commit
f61e2b42e8
  1. 63
      src/kyupy/logic.py
  2. 83
      src/kyupy/logic_sim.py
  3. 12
      tests/test_logic.py

63
src/kyupy/logic.py

@ -279,7 +279,14 @@ def bp_to_mv(bpa): @@ -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): @@ -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): @@ -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): @@ -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): @@ -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, :])

83
src/kyupy/logic_sim.py

@ -78,26 +78,81 @@ class LogicSim(sim.SimOps): @@ -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): @@ -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}')

12
tests/test_logic.py

@ -63,13 +63,13 @@ def test_bparray(): @@ -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'))

Loading…
Cancel
Save