Implement the SB_NOT (useful) and SB_AND_OR (not so useful) circuits
authorNick Downing <nick@ndcode.org>
Mon, 21 Jul 2025 03:23:36 +0000 (13:23 +1000)
committerNick Downing <nick@ndcode.org>
Mon, 21 Jul 2025 03:44:11 +0000 (13:44 +1000)
scripts/blocks.py
scripts/circuits.py

index 168a50f..6206b39 100755 (executable)
@@ -8,7 +8,9 @@ SYMBOL_TYPE_FET = 0
 SYMBOL_TYPE_GATE = 1
 SYMBOL_TYPE_XOR = 2
 SYMBOL_TYPE_TG_LATCH = 3
-N_SYMBOL_TYPES = 4
+SYMBOL_TYPE_SB_NOT = 4
+SYMBOL_TYPE_SB_AND_OR = 5
+N_SYMBOL_TYPES = 5
 
 dump_nets = False
 if len(sys.argv) >= 2 and sys.argv[1] == '--dump_nets':
@@ -118,6 +120,38 @@ with open(symbols_txt) as fin:
           (d_net, le_net, len_net, q_net, qn_net)
         )
       )
+    elif symbol_type == SYMBOL_TYPE_SB_NOT:
+      assert len(fields) == 5
+      a_net, oen_net, y_net = fields[2:]
+
+      for net in [a_net, oen_net, y_net]:
+        if net not in nets:
+          nets[net] = set() # blocks (of symbols) that the net visits
+        nets[net].add(block)
+
+      symbols.append(
+        (
+          symbol_type,
+          block,
+          (a_net, oen_net, y_net)
+        )
+      )
+    elif symbol_type == SYMBOL_TYPE_SB_AND_OR:
+      assert len(fields) == 8
+      a0_net, a1_net, b0_net, b1_net, oen_net, y_net = fields[2:]
+
+      for net in [a0_net, a1_net, b0_net, b1_net, oen_net, y_net]:
+        if net not in nets:
+          nets[net] = set() # blocks (of symbols) that the net visits
+        nets[net].add(block)
+
+      symbols.append(
+        (
+          symbol_type,
+          block,
+          (a0_net, a1_net, b0_net, b1_net, oen_net, y_net)
+        )
+      )
     else:
       assert False
 
@@ -253,6 +287,36 @@ for block, block_symbols in sorted(blocks.items()):
         fout.write(f'  "{node:s}" -> "{net_node:s}" [label="Q"]\n')
         net_node = make_net_node(qn_net)
         fout.write(f'  "{node:s}" -> "{net_node:s}" [label="/Q"]\n')
+      elif symbol_type == SYMBOL_TYPE_SB_NOT:
+        _, _, (a_net, oen_net, y_net) = symbols[i]
+
+        node = f'sb_not:{q_net:s}'
+        fout.write(f'  "{node:s}" [shape="invhouse", label="SB_NOT"]\n')
+
+        net_node = make_net_node(a_net)
+        fout.write(f'  "{net_node:s}" -> "{node:s}" [label="A"]\n')
+        net_node = make_net_node(oen_net)
+        fout.write(f'  "{net_node:s}" -> "{node:s}" [label="/OE"]\n')
+        net_node = make_net_node(y_net)
+        fout.write(f'  "{node:s}" -> "{net_node:s}" [label="Y"]\n')
+      elif symbol_type == SYMBOL_TYPE_SB_AND_OR:
+        _, _, (a0_net, a1_net, b0_net, b1_net, oen_net, y_net) = symbols[i]
+
+        node = f'sb_and_or:{q_net:s}'
+        fout.write(f'  "{node:s}" [shape="invhouse", label="SB_AND_OR"]\n')
+
+        net_node = make_net_node(a0_net)
+        fout.write(f'  "{net_node:s}" -> "{node:s}" [label="A0"]\n')
+        net_node = make_net_node(a1_net)
+        fout.write(f'  "{net_node:s}" -> "{node:s}" [label="A1"]\n')
+        net_node = make_net_node(b0_net)
+        fout.write(f'  "{net_node:s}" -> "{node:s}" [label="B0"]\n')
+        net_node = make_net_node(b1_net)
+        fout.write(f'  "{net_node:s}" -> "{node:s}" [label="B1"]\n')
+        net_node = make_net_node(oen_net)
+        fout.write(f'  "{net_node:s}" -> "{node:s}" [label="/OE"]\n')
+        net_node = make_net_node(y_net)
+        fout.write(f'  "{node:s}" -> "{net_node:s}" [label="Y"]\n')
       else:
         assert False
     fout.write('}\n')
index aaf31c3..d1cb4ea 100755 (executable)
@@ -8,13 +8,19 @@ SYMBOL_TYPE_FET = 0
 SYMBOL_TYPE_GATE = 1
 SYMBOL_TYPE_XOR = 2
 SYMBOL_TYPE_TG_LATCH = 3
-N_SYMBOL_TYPES = 4
+SYMBOL_TYPE_SB_NOT = 4
+SYMBOL_TYPE_SB_AND_OR = 5
+N_SYMBOL_TYPES = 6
 
 CIRCUITS = [
   # XOR gate as follows:
-  # int = a NOR b
-  # q = (a AND b) NOR int
-  # virtual nets are 0 = a, 1 = b, 2 = int, 3 = out
+  #   int = a NOR b
+  #   q = (a AND b) NOR int
+  # virtual nets are:
+  #   0 = a
+  #   1 = b
+  #   2 = int
+  #   3 = out
   (
     [
       (SYMBOL_TYPE_GATE, (3, [[0, 1], [2]])),
@@ -26,8 +32,16 @@ CIRCUITS = [
     [False, False, True, False],
   ),
   # transmission-gate latch with d, le, /le, q, /q as follows:
-  # fb = le ? d : q, /q = NOT fb, q = NOT /q
-  # virtual nets are 0 = d, 1 = le, 2 = /le, 3 = fb, 4 = /q, 5 = q
+  #   fb = le ? d : /le ? q : Z
+  #   /q = NOT fb
+  #   q = NOT /q
+  # virtual nets are:
+  #   0 = d
+  #   1 = le
+  #   2 = /le
+  #   3 = fb
+  #   4 = /q
+  #   5 = q
   (
     [
       (SYMBOL_TYPE_FET, (1, [0, 3])),
@@ -40,13 +54,64 @@ CIRCUITS = [
     ],
     [False, False, False, True, False, False]
   ),
+  # inverting superbuffer with a, /oe, y as follows:
+  #   h = /oe NOR a
+  #   l = /oe NOR h
+  #   y = h ? VCC : l ? GND : Z
+  # virtual nets are:
+  #   -2 = VCC
+  #   -1 = GND
+  #   0 = a
+  #   1 = /oe
+  #   2 = h
+  #   3 = l
+  #   4 = y
+  (
+    [
+      (SYMBOL_TYPE_GATE, (2, [[1], [0]])),
+      (SYMBOL_TYPE_GATE, (3, [[1], [2]])),
+      (SYMBOL_TYPE_FET, (2, [-2, 4])),
+      (SYMBOL_TYPE_FET, (3, [-1, 4])),
+    ],
+    [
+      (SYMBOL_TYPE_SB_NOT, (0, 1, 4)),
+    ],
+    [False, False, True, True, False],
+  ),
+  # non-inverting superbuffer with a0, a1, b0, b1, /oe, y as follows:
+  #   l = /oe NOR (a0 AND a1) NOR (b0 AND b1)
+  #   h = /oe NOR l
+  #   y = l ? GND : h ? VCC : Z
+  # virtual nets are:
+  #   -4 = VCC
+  #   -1 = GND
+  #   0 = a0
+  #   1 = a1
+  #   2 = b0
+  #   3 = b1
+  #   4 = /oe
+  #   5 = l
+  #   6 = h
+  #   7 = y
+  (
+    [
+      (SYMBOL_TYPE_GATE, (5, [[4], [0, 1], [2, 3]])),
+      (SYMBOL_TYPE_GATE, (6, [[4], [5]])),
+      (SYMBOL_TYPE_FET, (5, [-1, 7])),
+      (SYMBOL_TYPE_FET, (6, [-2, 7])),
+    ],
+    [
+      (SYMBOL_TYPE_SB_AND_OR, (0, 1, 2, 3, 4, 7)),
+    ],
+    [False, False, False, False, False, True, True, False],
+  ),
 ]
 
 if len(sys.argv) < 3:
   print(f'usage: {sys.argv[0]:s} symbols.txt net_gnd,net_vcc')
   sys.exit(1)
 symbols_txt = sys.argv[1]
-[net_gnd, net_vcc] = sys.argv[2].split(',')
+global_nets = sys.argv[2].split(',')
 
 nets = {}
 symbols = []
@@ -132,7 +197,7 @@ class Match(Exception):
 for circuit_find, circuit_replace, circuit_internal in CIRCUITS:
   assert len(circuit_find)
   circuit_symbols = [-1] * len(circuit_find)
-  circuit_nets = [None] * len(circuit_internal)
+  circuit_nets = global_nets[::-1] + [None] * len(circuit_internal)
 
   # recurse into symbol template looking for nets that already know (as we
   # have unified against them already) and use them to narrow candidate set
@@ -144,9 +209,9 @@ for circuit_find, circuit_replace, circuit_internal in CIRCUITS:
       if isinstance(t, tuple) or isinstance(t, list):
         candidates1 = candidate_symbols(t)
       else: # FIX THIS
-        #print('circuit_nets[t]', circuit_nets[t])
-        if circuit_nets[t] is not None:
-          candidates1 = nets[circuit_nets[t]]
+        gt = len(global_nets) + t
+        if circuit_nets[gt] is not None:
+          candidates1 = nets[circuit_nets[gt]]
         else:
           continue
       #print('candidates1', candidates1)
@@ -170,11 +235,12 @@ for circuit_find, circuit_replace, circuit_internal in CIRCUITS:
           # all nets flagged as internal are not connected to another symbol
           symbols_internal = set(circuit_symbols)
           for j in range(len(circuit_internal)):
+            gj = len(global_nets) + j
             if (
               circuit_internal[j] and
-              len(nets[circuit_nets[j]] - symbols_internal)
+              len(nets[circuit_nets[gj]] - symbols_internal)
             ):
-              #print('rejecting net', circuit_net[j])
+              #print('rejecting net', circuit_nets[gj])
               return
           #print('match')
           raise Match()
@@ -228,19 +294,20 @@ for circuit_find, circuit_replace, circuit_internal in CIRCUITS:
           return
         elif isinstance(t, int):
           assert isinstance(a, str)
-          if circuit_nets[t] != a:
-            if circuit_nets[t] is None:
+          gt = len(global_nets) + t
+          if circuit_nets[gt] != a:
+            if circuit_nets[gt] is None:
               #print('trying net', t, a)
               stack = (i, template, actual, stack)
-              circuit_nets[t] = a
+              circuit_nets[gt] = a
               match(level, stack)
               #print('failed net', t, a)
-              circuit_nets[t] = None
+              circuit_nets[gt] = None
             #else:
-            #  print('rejecting circuit_nets[t]', circuit_nets[t])
+            #  print('rejecting circuit_nets[gt]', circuit_nets[gt])
             return
           #else:
-          #  print('matched circuit_nets[t]', circuit_nets[t])
+          #  print('matched circuit_nets[gt]', circuit_nets[gt])
         else:
           assert False
       level -= 1
@@ -252,7 +319,7 @@ for circuit_find, circuit_replace, circuit_internal in CIRCUITS:
     if isinstance(template, list):
       return [substitute(t) for t in template]
     if isinstance(template, int):
-      return circuit_nets[template]
+      return circuit_nets[len(global_nets) + template]
     assert False
 
   # outer search is special, as it keeps track of symbol we are up to,
@@ -286,7 +353,7 @@ for circuit_find, circuit_replace, circuit_internal in CIRCUITS:
 
         # continue search
         circuit_symbols = [-1] * len(circuit_find)
-        circuit_nets = [None] * len(circuit_internal)
+        circuit_nets = global_nets[::-1] + [None] * len(circuit_internal)
 
 for i in range(len(symbols)):
   symbol_type = symbols[i][0]
@@ -315,3 +382,9 @@ for i in range(len(symbols)):
   elif symbol_type == SYMBOL_TYPE_TG_LATCH:
     [_, block, (d_net, le_net, len_net, q_net, qn_net)] = symbols[i]
     print(symbol_type, block, d_net, le_net, len_net, q_net, qn_net)
+  elif symbol_type == SYMBOL_TYPE_SB_NOT:
+    [_, block, (a_net, oen_net, y_net)] = symbols[i]
+    print(symbol_type, block, a_net, oen_net, y_net)
+  elif symbol_type == SYMBOL_TYPE_SB_AND_OR:
+    [_, block, (a0_net, a1_net, b0_net, b1_net, oen_net, y_net)] = symbols[i]
+    print(symbol_type, block, a0_net, a1_net, b0_net, b1_net, oen_net, y_net)