From d97555e9e96ff03e2444aac45240c65a9c54cab9 Mon Sep 17 00:00:00 2001 From: Stefan Holst Date: Sat, 8 Jul 2023 18:55:52 +0900 Subject: [PATCH] fix simprim cells, add saed90 --- src/kyupy/logic_sim.py | 140 ++++++++++++++++++----------- src/kyupy/sim.py | 13 ++- src/kyupy/techlib.py | 195 ++++++++++++++++++++++++++++++++++++++++ tests/test_logic_sim.py | 67 ++++++++++++-- 4 files changed, 351 insertions(+), 64 deletions(-) diff --git a/src/kyupy/logic_sim.py b/src/kyupy/logic_sim.py index c3a3455..d2a9dfe 100644 --- a/src/kyupy/logic_sim.py +++ b/src/kyupy/logic_sim.py @@ -69,6 +69,8 @@ class LogicSim(sim.SimOps): """ if sims is None: sims = self.sims nbytes = (sims - 1) // 8 + 1 + t0 = self.c_locs[self.tmp_idx] + t1 = self.c_locs[self.tmp2_idx] if self.m == 2: if inject_cb is None: _prop_cpu(self.ops, self.c_locs, self.c[...,:nbytes]) @@ -103,6 +105,10 @@ class LogicSim(sim.SimOps): elif op == sim.AOI22: self.c[o0] = ~((self.c[i0] & self.c[i1]) | (self.c[i2] & self.c[i3])) elif op == sim.OA22: self.c[o0] = (self.c[i0] | self.c[i1]) & (self.c[i2] | self.c[i3]) elif op == sim.OAI22: self.c[o0] = ~((self.c[i0] | self.c[i1]) & (self.c[i2] | self.c[i3])) + elif op == sim.AO211: self.c[o0] = (self.c[i0] & self.c[i1]) | self.c[i2] | self.c[i3] + elif op == sim.AOI211:self.c[o0] = ~((self.c[i0] & self.c[i1]) | self.c[i2] | self.c[i3]) + elif op == sim.OA211: self.c[o0] = (self.c[i0] | self.c[i1]) & self.c[i2] & self.c[i3] + elif op == sim.OAI211:self.c[o0] = ~((self.c[i0] | self.c[i1]) & self.c[i2] & self.c[i3]) elif op == sim.MUX21: self.c[o0] = (self.c[i0] & ~self.c[i2]) | (self.c[i1] & self.c[i2]) else: print(f'unknown op {op}') inject_cb(o0, self.s[o0]) @@ -130,42 +136,56 @@ class LogicSim(sim.SimOps): 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.AO21: - 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_and(self.c[t0], self.c[i0], self.c[i1]) + logic.bp4v_or(self.c[o0], self.c[t0], self.c[i2]) 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_and(self.c[t0], self.c[i0], self.c[i1]) + logic.bp4v_or(self.c[o0], self.c[t0], self.c[i2]) logic.bp4v_not(self.c[o0], self.c[o0]) elif op == sim.OA21: - logic.bp4v_or(self.c[self.c_locs[self.tmp_idx]], self.c[i0], self.c[i1]) - logic.bp4v_and(self.c[o0], self.c[self.c_locs[self.tmp_idx]], self.c[i2]) + logic.bp4v_or(self.c[t0], self.c[i0], self.c[i1]) + logic.bp4v_and(self.c[o0], self.c[t0], self.c[i2]) elif op == sim.OAI21: - logic.bp4v_or(self.c[self.c_locs[self.tmp_idx]], self.c[i0], self.c[i1]) - logic.bp4v_and(self.c[o0], self.c[self.c_locs[self.tmp_idx]], self.c[i2]) + logic.bp4v_or(self.c[t0], self.c[i0], self.c[i1]) + logic.bp4v_and(self.c[o0], self.c[t0], self.c[i2]) logic.bp4v_not(self.c[o0], self.c[o0]) elif op == sim.AO22: - logic.bp4v_and(self.c[self.c_locs[self.tmp_idx]], self.c[i0], self.c[i1]) - logic.bp4v_and(self.c[self.c_locs[self.tmp2_idx]], self.c[i2], self.c[i3]) - logic.bp4v_or(self.c[o0], self.c[self.c_locs[self.tmp_idx]], self.c[self.c_locs[self.tmp2_idx]]) + logic.bp4v_and(self.c[t0], self.c[i0], self.c[i1]) + logic.bp4v_and(self.c[t1], self.c[i2], self.c[i3]) + logic.bp4v_or(self.c[o0], self.c[t0], self.c[t1]) elif op == sim.AOI22: - logic.bp4v_and(self.c[self.c_locs[self.tmp_idx]], self.c[i0], self.c[i1]) - logic.bp4v_and(self.c[self.c_locs[self.tmp2_idx]], self.c[i2], self.c[i3]) - logic.bp4v_or(self.c[o0], self.c[self.c_locs[self.tmp_idx]], self.c[self.c_locs[self.tmp2_idx]]) + logic.bp4v_and(self.c[t0], self.c[i0], self.c[i1]) + logic.bp4v_and(self.c[t1], self.c[i2], self.c[i3]) + logic.bp4v_or(self.c[o0], self.c[t0], self.c[t1]) logic.bp4v_not(self.c[o0], self.c[o0]) elif op == sim.OA22: - logic.bp4v_or(self.c[self.c_locs[self.tmp_idx]], self.c[i0], self.c[i1]) - logic.bp4v_or(self.c[self.c_locs[self.tmp2_idx]], self.c[i2], self.c[i3]) - logic.bp4v_and(self.c[o0], self.c[self.c_locs[self.tmp_idx]], self.c[self.c_locs[self.tmp2_idx]]) + logic.bp4v_or(self.c[t0], self.c[i0], self.c[i1]) + logic.bp4v_or(self.c[t1], self.c[i2], self.c[i3]) + logic.bp4v_and(self.c[o0], self.c[t0], self.c[t1]) elif op == sim.OAI22: - logic.bp4v_or(self.c[self.c_locs[self.tmp_idx]], self.c[i0], self.c[i1]) - logic.bp4v_or(self.c[self.c_locs[self.tmp2_idx]], self.c[i2], self.c[i3]) - logic.bp4v_and(self.c[o0], self.c[self.c_locs[self.tmp_idx]], self.c[self.c_locs[self.tmp2_idx]]) + logic.bp4v_or(self.c[t0], self.c[i0], self.c[i1]) + logic.bp4v_or(self.c[t1], self.c[i2], self.c[i3]) + logic.bp4v_and(self.c[o0], self.c[t0], self.c[t1]) + logic.bp4v_not(self.c[o0], self.c[o0]) + elif op == sim.AO211: + logic.bp4v_and(self.c[t0], self.c[i0], self.c[i1]) + logic.bp4v_or(self.c[o0], self.c[t0], self.c[i2], self.c[i3]) + elif op == sim.AOI211: + logic.bp4v_and(self.c[t0], self.c[i0], self.c[i1]) + logic.bp4v_or(self.c[o0], self.c[t0], self.c[i2], self.c[i3]) + logic.bp4v_not(self.c[o0], self.c[o0]) + elif op == sim.OA211: + logic.bp4v_or(self.c[t0], self.c[i0], self.c[i1]) + logic.bp4v_and(self.c[o0], self.c[t0], self.c[i2], self.c[i3]) + elif op == sim.OAI211: + logic.bp4v_or(self.c[t0], self.c[i0], self.c[i1]) + logic.bp4v_and(self.c[o0], self.c[t0], self.c[i2], self.c[i3]) logic.bp4v_not(self.c[o0], self.c[o0]) elif op == sim.MUX21: - logic.bp4v_not(self.c[self.c_locs[self.tmp2_idx]], self.c[i2]) - logic.bp4v_and(self.c[self.c_locs[self.tmp_idx]], self.c[i0], self.c[self.c_locs[self.tmp2_idx]]) - logic.bp4v_and(self.c[self.c_locs[self.tmp2_idx]], self.c[i1], self.c[i2]) - logic.bp4v_or(self.c[o0], self.c[self.c_locs[self.tmp_idx]], self.c[self.c_locs[self.tmp2_idx]]) + logic.bp4v_not(self.c[t1], self.c[i2]) + logic.bp4v_and(self.c[t0], self.c[i0], self.c[t1]) + logic.bp4v_and(self.c[t1], self.c[i1], self.c[i2]) + logic.bp4v_or(self.c[o0], self.c[t0], self.c[t1]) else: print(f'unknown op {op}') else: for op, o0, i0, i1, i2, i3 in self.ops[:,:6]: @@ -191,42 +211,56 @@ class LogicSim(sim.SimOps): 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.AO21: - 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_and(self.c[t0], self.c[i0], self.c[i1]) + logic.bp8v_or(self.c[o0], self.c[t0], self.c[i2]) 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_and(self.c[t0], self.c[i0], self.c[i1]) + logic.bp8v_or(self.c[o0], self.c[t0], self.c[i2]) logic.bp8v_not(self.c[o0], self.c[o0]) elif op == sim.OA21: - logic.bp8v_or(self.c[self.c_locs[self.tmp_idx]], self.c[i0], self.c[i1]) - logic.bp8v_and(self.c[o0], self.c[self.c_locs[self.tmp_idx]], self.c[i2]) + logic.bp8v_or(self.c[t0], self.c[i0], self.c[i1]) + logic.bp8v_and(self.c[o0], self.c[t0], self.c[i2]) elif op == sim.OAI21: - logic.bp8v_or(self.c[self.c_locs[self.tmp_idx]], self.c[i0], self.c[i1]) - logic.bp8v_and(self.c[o0], self.c[self.c_locs[self.tmp_idx]], self.c[i2]) + logic.bp8v_or(self.c[t0], self.c[i0], self.c[i1]) + logic.bp8v_and(self.c[o0], self.c[t0], self.c[i2]) logic.bp8v_not(self.c[o0], self.c[o0]) elif op == sim.AO22: - logic.bp8v_and(self.c[self.c_locs[self.tmp_idx]], self.c[i0], self.c[i1]) - logic.bp8v_and(self.c[self.c_locs[self.tmp2_idx]], self.c[i2], self.c[i3]) - logic.bp8v_or(self.c[o0], self.c[self.c_locs[self.tmp_idx]], self.c[self.c_locs[self.tmp2_idx]]) + logic.bp8v_and(self.c[t0], self.c[i0], self.c[i1]) + logic.bp8v_and(self.c[t1], self.c[i2], self.c[i3]) + logic.bp8v_or(self.c[o0], self.c[t0], self.c[t1]) elif op == sim.AOI22: - logic.bp8v_and(self.c[self.c_locs[self.tmp_idx]], self.c[i0], self.c[i1]) - logic.bp8v_and(self.c[self.c_locs[self.tmp2_idx]], self.c[i2], self.c[i3]) - logic.bp8v_or(self.c[o0], self.c[self.c_locs[self.tmp_idx]], self.c[self.c_locs[self.tmp2_idx]]) + logic.bp8v_and(self.c[t0], self.c[i0], self.c[i1]) + logic.bp8v_and(self.c[t1], self.c[i2], self.c[i3]) + logic.bp8v_or(self.c[o0], self.c[t0], self.c[t1]) logic.bp8v_not(self.c[o0], self.c[o0]) elif op == sim.OA22: - logic.bp8v_or(self.c[self.c_locs[self.tmp_idx]], self.c[i0], self.c[i1]) - logic.bp8v_or(self.c[self.c_locs[self.tmp2_idx]], self.c[i2], self.c[i3]) - logic.bp8v_and(self.c[o0], self.c[self.c_locs[self.tmp_idx]], self.c[self.c_locs[self.tmp2_idx]]) + logic.bp8v_or(self.c[t0], self.c[i0], self.c[i1]) + logic.bp8v_or(self.c[t1], self.c[i2], self.c[i3]) + logic.bp8v_and(self.c[o0], self.c[t0], self.c[t1]) elif op == sim.OAI22: - logic.bp8v_or(self.c[self.c_locs[self.tmp_idx]], self.c[i0], self.c[i1]) - logic.bp8v_or(self.c[self.c_locs[self.tmp2_idx]], self.c[i2], self.c[i3]) - logic.bp8v_and(self.c[o0], self.c[self.c_locs[self.tmp_idx]], self.c[self.c_locs[self.tmp2_idx]]) + logic.bp8v_or(self.c[t0], self.c[i0], self.c[i1]) + logic.bp8v_or(self.c[t1], self.c[i2], self.c[i3]) + logic.bp8v_and(self.c[o0], self.c[t0], self.c[t1]) + logic.bp8v_not(self.c[o0], self.c[o0]) + elif op == sim.AO211: + logic.bp8v_and(self.c[t0], self.c[i0], self.c[i1]) + logic.bp8v_or(self.c[o0], self.c[t0], self.c[i2], self.c[i3]) + elif op == sim.AOI211: + logic.bp8v_and(self.c[t0], self.c[i0], self.c[i1]) + logic.bp8v_or(self.c[o0], self.c[t0], self.c[i2], self.c[i3]) + logic.bp8v_not(self.c[o0], self.c[o0]) + elif op == sim.OA211: + logic.bp8v_or(self.c[t0], self.c[i0], self.c[i1]) + logic.bp8v_and(self.c[o0], self.c[t0], self.c[i2], self.c[i3]) + elif op == sim.OAI211: + logic.bp8v_or(self.c[t0], self.c[i0], self.c[i1]) + logic.bp8v_and(self.c[o0], self.c[t0], self.c[i2], self.c[i3]) logic.bp8v_not(self.c[o0], self.c[o0]) elif op == sim.MUX21: - logic.bp8v_not(self.c[self.c_locs[self.tmp2_idx]], self.c[i2]) - logic.bp8v_and(self.c[self.c_locs[self.tmp_idx]], self.c[i0], self.c[self.c_locs[self.tmp2_idx]]) - logic.bp8v_and(self.c[self.c_locs[self.tmp2_idx]], self.c[i1], self.c[i2]) - logic.bp8v_or(self.c[o0], self.c[self.c_locs[self.tmp_idx]], self.c[self.c_locs[self.tmp2_idx]]) + logic.bp8v_not(self.c[t1], self.c[i2]) + logic.bp8v_and(self.c[t0], self.c[i0], self.c[t1]) + logic.bp8v_and(self.c[t1], self.c[i1], self.c[i2]) + logic.bp8v_or(self.c[o0], self.c[t0], self.c[t1]) else: print(f'unknown op {op}') if inject_cb is not None: inject_cb(o0, self.s[o0]) @@ -286,12 +320,16 @@ def _prop_cpu(ops, c_locs, c): 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.AO21: c[o0] = (c[i0] & c[i1]) | c[i2] - elif op == sim.AOI21: c[o0] = ~((c[i0] & c[i1]) | c[i2]) elif op == sim.OA21: c[o0] = (c[i0] | c[i1]) & c[i2] - elif op == sim.OAI21: c[o0] = ~((c[i0] | c[i1]) & c[i2]) elif op == sim.AO22: c[o0] = (c[i0] & c[i1]) | (c[i2] & c[i3]) - elif op == sim.AOI22: c[o0] = ~((c[i0] & c[i1]) | (c[i2] & c[i3])) elif op == sim.OA22: c[o0] = (c[i0] | c[i1]) & (c[i2] | c[i3]) + elif op == sim.AOI21: c[o0] = ~((c[i0] & c[i1]) | c[i2]) + elif op == sim.OAI21: c[o0] = ~((c[i0] | c[i1]) & c[i2]) + elif op == sim.AOI22: c[o0] = ~((c[i0] & c[i1]) | (c[i2] & c[i3])) elif op == sim.OAI22: c[o0] = ~((c[i0] | c[i1]) & (c[i2] | c[i3])) + elif op == sim.AO211: c[o0] = (c[i0] & c[i1]) | c[i2] | c[i3] + elif op == sim.OA211: c[o0] = (c[i0] | c[i1]) & c[i2] & c[i3] + elif op == sim.AOI211: c[o0] = ~((c[i0] & c[i1]) | c[i2] | c[i3]) + elif op == sim.OAI211: c[o0] = ~((c[i0] | c[i1]) & c[i2] & c[i3]) elif op == sim.MUX21: c[o0] = (c[i0] & ~c[i2]) | (c[i1] & c[i2]) else: print(f'unknown op {op}') diff --git a/src/kyupy/sim.py b/src/kyupy/sim.py index 3d5de82..a83c0a9 100644 --- a/src/kyupy/sim.py +++ b/src/kyupy/sim.py @@ -25,15 +25,15 @@ XOR4 = np.uint16(0b0110_1001_1001_0110) XNOR2, XNOR3, XNOR4 = ~XOR2, ~XOR3, ~XOR4 -AO21 = np.uint16(0b1110_1010_1110_1010) # i0 | (i1 & i2) +AO21 = np.uint16(0b1111_1000_1111_1000) # (i0 & i1) | i2 AO22 = np.uint16(0b1111_1000_1000_1000) # (i0 & i1) | (i2 & i3) -OA21 = np.uint16(0b1010_1000_1010_1000) # i0 & (i1 | i2) +OA21 = np.uint16(0b1110_0000_1110_0000) # (i0 | i1) & i2 OA22 = np.uint16(0b1110_1110_1110_0000) # (i0 | i1) & (i2 | i3) AOI21, AOI22, OAI21, OAI22 = ~AO21, ~AO22, ~OA21, ~OA22 -AO211 = np.uint16(0b1111_1110_1110_1110) # i0 | i1 | (i2 & i3) -OA211 = np.uint16(0b1000_1000_1000_0000) # i0 & i1 & (i2 | i3) +AO211 = np.uint16(0b1111_1111_1111_1000) # (i0 & i1) | i2 | i3 +OA211 = np.uint16(0b1110_0000_0000_0000) # (i0 | i1) & i2 & i3 AOI211, OAI211 = ~AO211, ~OA211 @@ -62,6 +62,11 @@ kind_prefixes = { '__const0__': (BUF1, BUF1, BUF1), 'tiel': (BUF1, BUF1, BUF1), + 'ao211': (AO211, AO211, AO211), + 'oa211': (OA211, OA211, OA211), + 'aoi211': (AOI211, AOI211, AOI211), + 'oai211': (OAI211, OAI211, OAI211), + 'ao22': (AO22, AO22, AO22), 'aoi22': (AOI22, AOI22, AOI22), 'ao21': (AO21, AO21, AO21), diff --git a/src/kyupy/techlib.py b/src/kyupy/techlib.py index 7c0ba0e..aac15a6 100644 --- a/src/kyupy/techlib.py +++ b/src/kyupy/techlib.py @@ -1,3 +1,6 @@ +import re +from itertools import product + from .circuit import Node, Line from . import bench @@ -94,3 +97,195 @@ class TechLib: for k, v in tmap.items(): if n.kind.startswith(k): circuit.substitute(n, v) + + +class TechLibNew: + def __init__(self, lib_src): + self.cells = dict() + for c_str in re.split(r';\s+', lib_src): + c_str = re.sub(r'^\s+', '', c_str) + name_len = c_str.find(' ') + if name_len <= 0: continue + c = bench.parse(c_str[name_len:]) + c.name = c_str[:name_len] + c.eliminate_1to1_forks() + i_idx, o_idx = 0, 0 + pin_dict = dict() + for n in c.io_nodes: + if len(n.ins) == 0: + pin_dict[n.name] = (i_idx, False) + i_idx += 1 + else: + pin_dict[n.name] = (o_idx, True) + o_idx += 1 + parts = [s[1:-1].split(',') if s[0] == '{' else [s] for s in re.split(r'({[^}]+})', c.name) if len(s) > 0] + for name in [''.join(item) for item in product(*parts)]: + self.cells[name] = (c, pin_dict) + + def pin_index(self, kind, pin): + return self.cells[kind][1][pin][0] + + def pin_is_output(self, kind, pin): + return self.cells[kind][1][pin][1] + + def resolve(self, circuit): + for n in list(circuit.nodes): + if n.kind in self.cells: + circuit.substitute(n, self.cells[n.kind][0]) + + +nangate = TechLibNew(r""" +FILLCELL_X{1,2,4,8,16,32} ; + +LOGIC0_X1 output(Z) Z=__const0__() ; +LOGIC1_X1 output(Z) Z=__const1__() ; + +BUF_X{1,2,4,8,16,32} input(A) output(Z) Z=BUF1(A) ; +CLKBUF_X{1,2,3} input(A) output(Z) Z=BUF1(A) ; +INV_X{1,2,4,8,16,32} input(A) output(ZN) ZN=INV1(A) ; + +AND2_X{1,2,4} input(A1,A2) output(ZN) ZN=AND2(A1,A2) ; +AND3_X{1,2,4} input(A1,A2,A3) output(ZN) ZN=AND3(A1,A2,A3) ; +AND4_X{1,2,4} input(A1,A2,A3,A4) output(ZN) ZN=AND4(A1,A2,A3,A4) ; +NAND2_X{1,2,4} input(A1,A2) output(ZN) ZN=NAND2(A1,A2) ; +NAND3_X{1,2,4} input(A1,A2,A3) output(ZN) ZN=NAND3(A1,A2,A3) ; +NAND4_X{1,2,4} input(A1,A2,A3,A4) output(ZN) ZN=NAND4(A1,A2,A3,A4) ; +OR2_X{1,2,4} input(A1,A2) output(ZN) ZN=OR2(A1,A2) ; +OR3_X{1,2,4} input(A1,A2,A3) output(ZN) ZN=OR3(A1,A2,A3) ; +OR4_X{1,2,4} input(A1,A2,A3,A4) output(ZN) ZN=OR4(A1,A2,A3,A4) ; +NOR2_X{1,2,4} input(A1,A2) output(ZN) ZN=NOR2(A1,A2) ; +NOR3_X{1,2,4} input(A1,A2,A3) output(ZN) ZN=NOR3(A1,A2,A3) ; +NOR4_X{1,2,4} input(A1,A2,A3,A4) output(ZN) ZN=NOR4(A1,A2,A3,A4) ; +XOR2_X{1,2} input(A,B) output(Z) Z=XOR2(A,B) ; +XNOR2_X{1,2} input(A,B) output(ZN) ZN=XNOR2(A,B) ; + +AOI21_X{1,2,4} input(A,B1,B2) output(ZN) ZN=AOI21(B1,B2,A) ; +OAI21_X{1,2,4} input(A,B1,B2) output(ZN) ZN=OAI21(B1,B2,A) ; +AOI22_X{1,2,4} input(A1,A2,B1,B2) output(ZN) ZN=AOI22(A1,A2,B1,B2) ; +OAI22_X{1,2,4} input(A1,A2,B1,B2) output(ZN) ZN=OAI22(A1,A2,B1,B2) ; + +OAI211_X{1,2,4} input(A,B,C1,C2) output(ZN) ZN=OAI211(C1,C2,A,B) ; +AOI211_X{1,2,4} input(A,B,C1,C2) output(ZN) ZN=AOI211(C1,C2,A,B) ; + +MUX2_X{1,2} input(A,B,S) output(Z) Z=MUX21(A,B,S) ; + +AOI221_X{1,2,4} input(A,B1,B2,C1,C2) output(ZN) BC=AO22(B1,B2,C1,C2) ZN=NOR2(BC,A) ; +OAI221_X{1,2,4} input(A,B1,B2,C1,C2) output(ZN) BC=OA22(B1,B2,C1,C2) ZN=NAND2(BC,A) ; + +AOI222_X{1,2,4} input(A1,A2,B1,B2,C1,C2) output(ZN) BC=AO22(B1,B2,C1,C2) ZN=AOI21(A1,A2,BC) ; +OAI222_X{1,2,4} input(A1,A2,B1,B2,C1,C2) output(ZN) BC=OA22(B1,B2,C1,C2) ZN=OAI21(A1,A2,BC) ; + +OAI33_X1 input(A1,A2,A3,B1,B2,B3) output(ZN) AA=OR2(A1,A2) BB=OR2(B1,B2) ZN=OAI22(AA,A3,BB,B3) ; + +HA_X1 input(A,B) output(CO,S) CO=XOR2(A,B) S=AND2(A,B) ; + +FA_X1 input(A,B,CI) output(CO,S) AB=XOR2(A,B) CO=XOR2(AB,CI) S=AO22(CI,A,B) ; + +CLKGATE_X{1,2,4,8} input(CK,E) output(GCK) GCK=AND2(CK,E) ; + +CLKGATETST_X{1,2,4,8} input(CK,E,SE) output(GCK) GCK=OA21(CK,E,SE) ; + +DFF_X{1,2} input(D,CK) output(Q,QN) Q=DFF(D,CK) QN=INV1(Q) ; +DFFR_X{1,2} input(D,RN,CK) output(Q,QN) DR=AND2(D,RN) Q=DFF(DR,CK) QN=INV1(Q) ; +DFFS_X{1,2} input(D,SN,CK) output(Q,QN) S=INV1(SN) DS=OR2(D,S) Q=DFF(DS,CK) QN=INV1(Q) ; +DFFRS_X{1,2} input(D,RN,SN,CK) output(Q,QN) S=INV1(SN) DS=OR2(D,S) DRS=AND2(DS,RN) Q=DFF(DRS,CK) QN=INV1(Q) ; + +SDFF_X{1,2} input(D,SE,SI,CK) output(Q,QN) DI=MUX21(D,SI,SE) Q=DFF(DI,CK) QN=INV1(Q) ; +SDFFR_X{1,2} input(D,RN,SE,SI,CK) output(Q,QN) DR=AND2(D,RN) DI=MUX21(DR,SI,SE) Q=DFF(DI,CK) QN=INV1(Q) ; +SDFFS_X{1,2} input(D,SE,SI,SN,CK) output(Q,QN) S=INV1(SN) DS=OR2(D,S) DI=MUX21(DS,SI,SE) Q=DFF(DI,CK) QN=INV1(Q) ; +SDFFRS_X{1,2} input(D,RN,SE,SI,SN,CK) output(Q,QN) S=INV1(SN) DS=OR2(D,S) DRS=AND2(DS,RN) DI=MUX21(DRS,SI,SE) Q=DFF(DI,CK) QN=INV1(Q) ; + +TBUF_X{1,2,4,8,16} input(A,EN) output(Z) Z=BUF1(A) ; +TINV_X1 input(I,EN) output(ZN) ZN=INV1(I) ; +TLAT_X1 input(D,G,OE) output(Q) Q=LATCH(D,G) ; + +DLH_X{1,2} input(D,G) output(Q) Q=LATCH(D,G) ; +DLL_X{1,2} input(D,GN) output(Q) G=INV1(GN) Q=LATCH(D,G) ; +""") + + +# SAED90nm library. unsupported: negative-edge flip-flops, tri-state, latches, clock gating, level shifters + +saed90 = TechLibNew(r""" +NBUFFX{2,4,8,16,32}$ input(INP) output(Z) Z=BUF1(INP) ; +AOBUFX{1,2,4}$ input(INP) output(Z) Z=BUF1(INP) ; +DELLN{1,2,3}X2$ input(INP) output(Z)Z=BUF1(INP) ; + +INVX{0,1,2,4,8,16,32}$ input(INP) output(ZN) ZN=INV1(INP) ; +AOINVX{1,2,4}$ input(INP) output(ZN) ZN=INV1(INP) ; +IBUFFX{2,4,8,16,32}$ input(INP) output(ZN) ZN=INV1(INP) ; + +TIEH$ output(Z) Z=__const1__() ; +TIEL$ output(ZN) ZN=__const0__() ; + +HEAD2X{2,4,8,16,32}$ input(SLEEP) output(SLEEPOUT) SLEEPOUT=BUF1(SLEEP) ; +HEADX{2,4,8,16,32}$ input(SLEEP) ; + +ANTENNA$ input(INP) ; +CLOAD1$ input(INP) ; +DCAP$ ; +DHFILL{HLH,LHL}2 ; +DHFILLHLHLS11$ ; +SHFILL{1,2,3,64,128}$ ; + +AND2X{1,2,4}$ input(IN1,IN2) output(Q) Q=AND2(IN1,IN2) ; +AND3X{1,2,4}$ input(IN1,IN2,IN3) output(Q) Q=AND3(IN1,IN2,IN3) ; +AND4X{1,2,4}$ input(IN1,IN2,IN3,IN4) output(Q) Q=AND4(IN1,IN2,IN3,IN4) ; +OR2X{1,2,4}$ input(IN1,IN2) output(Q) Q=OR2(IN1,IN2) ; +OR3X{1,2,4}$ input(IN1,IN2,IN3) output(Q) Q=OR3(IN1,IN2,IN3) ; +OR4X{1,2,4}$ input(IN1,IN2,IN3,IN4) output(Q) Q=OR4(IN1,IN2,IN3,IN4) ; +XOR2X{1,2}$ input(IN1,IN2) output(Q) Q=XOR2(IN1,IN2) ; +XOR3X{1,2}$ input(IN1,IN2,IN3) output(Q) Q=XOR3(IN1,IN2,IN3) ; +NAND2X{0,1,2,4}$ input(IN1,IN2) output(QN) QN=NAND2(IN1,IN2) ; +NAND3X{0,1,2,4}$ input(IN1,IN2,IN3) output(QN) QN=NAND3(IN1,IN2,IN3) ; +NAND4X{0,1}$ input(IN1,IN2,IN3,IN4) output(QN) QN=NAND4(IN1,IN2,IN3,IN4) ; +NOR2X{0,1,2,4}$ input(IN1,IN2) output(QN) QN=NOR2(IN1,IN2) ; +NOR3X{0,1,2,4}$ input(IN1,IN2,IN3) output(QN) QN=NOR3(IN1,IN2,IN3) ; +NOR4X{0,1}$ input(IN1,IN2,IN3,IN4) output(QN) QN=NOR4(IN1,IN2,IN3,IN4) ; +XNOR2X{1,2}$ input(IN1,IN2) output(Q) Q=XNOR2(IN1,IN2) ; +XNOR3X{1,2}$ input(IN1,IN2,IN3) output(Q) Q=XNOR3(IN1,IN2,IN3) ; + +ISOLAND{,AO}X{1,2,4,8}$ input(ISO,D) output(Q) ISOB=NOT1(ISO) Q=AND2(ISOB,D) ; +ISOLOR{,AO}X{1,2,4,8}$ input(ISO,D) output(Q) Q=OR2(ISO,D) ; + +AO21X{1,2}$ input(IN1,IN2,IN3) output(Q) Q=AO21(IN1,IN2,IN3) ; +OA21X{1,2}$ input(IN1,IN2,IN3) output(Q) Q=OA21(IN1,IN2,IN3) ; +AOI21X{1,2}$ input(IN1,IN2,IN3) output(QN) QN=AOI21(IN1,IN2,IN3) ; +OAI21X{1,2}$ input(IN1,IN2,IN3) output(QN) QN=OAI21(IN1,IN2,IN3) ; + +AO22X{1,2}$ input(IN1,IN2,IN3,IN4) output(Q) Q=AO22(IN1,IN2,IN3,IN4) ; +OA22X{1,2}$ input(IN1,IN2,IN3,IN4) output(Q) Q=OA22(IN1,IN2,IN3,IN4) ; +AOI22X{1,2}$ input(IN1,IN2,IN3,IN4) output(QN) QN=AOI22(IN1,IN2,IN3,IN4) ; +OAI22X{1,2}$ input(IN1,IN2,IN3,IN4) output(QN) QN=OAI22(IN1,IN2,IN3,IN4) ; + +MUX21X{1,2}$ input(IN1,IN2,S) output(Q) Q=MUX21(IN1,IN2,S) ; + +AO221X{1,2}$ input(IN1,IN2,IN3,IN4,IN5) output(Q) A=AO22(IN1,IN2,IN3,IN4) Q=OR2(IN5,A) ; +OA221X{1,2}$ input(IN1,IN2,IN3,IN4,IN5) output(Q) A=OA22(IN1,IN2,IN3,IN4) Q=AND2(IN5,A) ; +AOI221X{1,2}$ input(IN1,IN2,IN3,IN4,IN5) output(QN) A=AO22(IN1,IN2,IN3,IN4) QN=NOR2(IN5,A) ; +OAI221X{1,2}$ input(IN1,IN2,IN3,IN4,IN5) output(QN) A=OA22(IN1,IN2,IN3,IN4) QN=NAND2(IN5,A) ; + +AO222X{1,2}$ input(IN1,IN2,IN3,IN4,IN5,IN6) output(Q) A=AO22(IN1,IN2,IN3,IN4) Q=AO21(IN5,IN6,A) ; +OA222X{1,2}$ input(IN1,IN2,IN3,IN4,IN5,IN6) output(Q) A=OA22(IN1,IN2,IN3,IN4) Q=OA21(IN5,IN6,A) ; +AOI222X{1,2}$ input(IN1,IN2,IN3,IN4,IN5,IN6) output(QN) A=AO22(IN1,IN2,IN3,IN4) QN=AOI21(IN5,IN6,A) ; +OAI222X{1,2}$ input(IN1,IN2,IN3,IN4,IN5,IN6) output(QN) A=OA22(IN1,IN2,IN3,IN4) QN=OAI21(IN5,IN6,A) ; + +MUX41X{1,2}$ input(IN1,IN2,IN3,IN4,S0,S1) output(Q) A=MUX21(IN1,IN2,S0) B=MUX21(IN3,IN4,S0) Q=MUX21(A,B,S1) ; + +DEC24X{1,2}$ input(IN1,IN2) output(Q0,Q1,Q2,Q3) IN1B=INV1(IN1) IN2B=INV1(IN2) Q0=NOR2(IN1,IN2) Q1=AND(IN1,IN2B) Q2=AND(IN1B,IN2) Q3=AND(IN1,IN2) ; +FADDX{1,2}$ input(A,B,CI) output(S,CO) AB=XOR2(A,B) CO=XOR(AB,CI) S=AO22(AB,CI,A,B) ; +HADDX{1,2}$ input(A0,B0) output(SO,C1) C1=XOR2(A0,B0) SO=AND2(A0,B0) ; + +{,AO}DFFARX{1,2}$ input(D,CLK,RSTB) output(Q,QN) DR=AND2(D,RSTB) Q=DFF(DR,CLK) QN=INV1(Q) ; +DFFASRX{1,2}$ input(D,CLK,RSTB,SETB) output(Q,QN) DR=AND2(D,RSTB) SET=INV1(SETB) DRS=OR2(DR,SET) Q=DFF(DRS,CLK) QN=INV1(Q) ; +DFFASX{1,2}$ input(D,CLK,SETB) output(Q,QN) SET=INV1(SETB) DS=OR2(D,SET) Q=DFF(DS,CLK) QN=INV1(Q) ; +DFFSSRX{1,2}$ input(CLK,D,RSTB,SETB) output(Q,QN) DR=AND2(D,RSTB) SET=INV1(SETB) DRS=OR2(DR,SET) Q=DFF(DRS,CLK) QN=INV1(Q) ; +DFFX{1,2}$ input(D,CLK) output(Q,QN) Q=DFF(D,CLK) QN=INV1(Q) ; + +SDFFARX{1,2}$ input(D,CLK,RSTB,SE,SI) output(Q,QN) DR=AND2(D,RSTB) DI=MUX21(DR,SI,SE) Q=DFF(DI,CLK) QN=INV1(Q) ; +SDFFASRSX{1,2}$ input(D,CLK,RSTB,SETB,SE,SI) output(Q,QN,S0) DR=AND2(D,RSTB) SET=INV1(SETB) DRS=OR2(DR,SET) DI=MUX21(DRS,SI,SE) Q=DFF(DI,CLK) QN=INV1(Q) S0=BUF1(Q) ; +SDFFASRX{1,2}$ input(D,CLK,RSTB,SETB,SE,SI) output(Q,QN) DR=AND2(D,RSTB) SET=INV1(SETB) DRS=OR2(DR,SET) DI=MUX21(DRS,SI,SE) Q=DFF(DI,CLK) QN=INV1(Q) ; +SDFFASX{1,2}$ input(D,CLK,SETB,SE,SI) output(Q,QN) SET=INV1(SETB) DS=OR2(D,SET) DI=MUX21(DS,SI,SE) Q=DFF(DI,CLK) QN=INV1(Q) ; +SDFFSSRX{1,2}$ input(CLK,D,RSTB,SETB,SI,SE) output(Q,QN) DR=AND2(D,RSTB) SET=INV1(SETB) DRS=OR2(DR,SET) DI=MUX21(DRS,SI,SE) Q=DFF(DI,CLK) QN=INV1(Q) ; +SDFFX{1,2}$ input(D,CLK,SE,SI) output(Q,QN) DI=MUX21(D,SI,SE) Q=DFF(DI,CLK) QN=INV1(Q) ; +""".replace('$','{,_LVT,_HVT}')) \ No newline at end of file diff --git a/tests/test_logic_sim.py b/tests/test_logic_sim.py index 22b5866..5849310 100644 --- a/tests/test_logic_sim.py +++ b/tests/test_logic_sim.py @@ -1,9 +1,8 @@ import numpy as np from kyupy.logic_sim import LogicSim -from kyupy import bench +from kyupy import bench, logic, sim from kyupy.logic import mvarray, bparray, bp_to_mv, mv_to_bp -from kyupy import logic def assert_equal_shape_and_contents(actual, desired): desired = np.array(desired, dtype=np.uint8) @@ -11,17 +10,67 @@ def assert_equal_shape_and_contents(actual, desired): np.testing.assert_allclose(actual, desired) def test_2v(): - c = bench.parse('input(x, y) output(a, o, n) a=and(x,y) o=or(x,y) n=not(x)') - s = LogicSim(c, 8, m=8) # FIXME: do m=2 - assert s.s_len == 5 - bpa = bparray('00---', '01---', '10---', '11---') + c = bench.parse(f''' + input(i3, i2, i1, i0) + output({",".join([f"o{i:02d}" for i in range(33)])}) + o00=BUF1(i0) + o01=INV1(i0) + o02=AND2(i0,i1) + o03=AND3(i0,i1,i2) + o04=AND4(i0,i1,i2,i3) + o05=NAND2(i0,i1) + o06=NAND3(i0,i1,i2) + o07=NAND4(i0,i1,i2,i3) + o08=OR2(i0,i1) + o09=OR3(i0,i1,i2) + o10=OR4(i0,i1,i2,i3) + o11=NOR2(i0,i1) + o12=NOR3(i0,i1,i2) + o13=NOR4(i0,i1,i2,i3) + o14=XOR2(i0,i1) + o15=XOR3(i0,i1,i2) + o16=XOR4(i0,i1,i2,i3) + o17=XNOR2(i0,i1) + o18=XNOR3(i0,i1,i2) + o19=XNOR4(i0,i1,i2,i3) + o20=AO21(i0,i1,i2) + o21=OA21(i0,i1,i2) + o22=AO22(i0,i1,i2,i3) + o23=OA22(i0,i1,i2,i3) + o24=AOI21(i0,i1,i2) + o25=OAI21(i0,i1,i2) + o26=AOI22(i0,i1,i2,i3) + o27=OAI22(i0,i1,i2,i3) + o28=AO211(i0,i1,i2,i3) + o29=OA211(i0,i1,i2,i3) + o30=AOI211(i0,i1,i2,i3) + o31=OAI211(i0,i1,i2,i3) + o32=MUX21(i0,i1,i2) + ''') + s = LogicSim(c, 16, m=2) + bpa = logic.bparray([f'{i:04b}'+('-'*(s.s_len-4)) for i in range(16)]) s.s[0] = bpa s.s_to_c() s.c_prop() s.c_to_s() - mva = bp_to_mv(s.s[1]) - - assert_equal_shape_and_contents(mva[...,:4], mvarray('--001', '--011', '--010', '--110')) + mva = logic.bp_to_mv(s.s[1]) + for res, exp in zip(logic.packbits(mva[4:], dtype=np.uint32), [ + sim.BUF1, sim.INV1, + sim.AND2, sim.AND3, sim.AND4, + sim.NAND2, sim.NAND3, sim.NAND4, + sim.OR2, sim.OR3, sim.OR4, + sim.NOR2, sim.NOR3, sim.NOR4, + sim.XOR2, sim.XOR3, sim.XOR4, + sim.XNOR2, sim.XNOR3, sim.XNOR4, + sim.AO21, sim.OA21, + sim.AO22, sim.OA22, + sim.AOI21, sim.OAI21, + sim.AOI22, sim.OAI22, + sim.AO211, sim.OA211, + sim.AOI211, sim.OAI211, + sim.MUX21 + ]): + assert res == exp, f'Mismatch for SimPrim {sim.names[exp]} res={bin(res)} exp={bin(exp)}' def test_4v():