Improved graphs in pdf format, but multiple graphs per document not working yet ... master
authorNick Downing <nick@ndcode.org>
Tue, 22 Jul 2025 08:28:49 +0000 (18:28 +1000)
committerNick Downing <nick@ndcode.org>
Tue, 22 Jul 2025 08:28:49 +0000 (18:28 +1000)
.gitignore
8085/Makefile
scripts/blocks.py

index 04a4cf6..c638ba7 100644 (file)
 /8080/channels.txt
 /8080/nets.txt
 /8080/sizes.txt
+/8085/*.dot
 /8085/buried.png
-/8085/circuits.ps
+/8085/circuits.pdf
 /8085/circuits.txt
 /8085/diff.png
-/8085/dot
+/8085/fets.pdf
 /8085/fets.txt
+/8085/gates.pdf
 /8085/gates.txt
 /8085/layers.png
 /8085/layers_rev.png
 /8085/metal.png
-/8085/node_gnd.png
-/8085/node_phi0.png
-/8085/node_phi1.png
+/8085/net_gnd.png
+/8085/net_phi0.png
+/8085/net_phi1.png
 /8085/node_sizes.txt
-/8085/node_vcc.png
+/8085/net_vcc.png
 /8085/nodes.txt
 /8085/pads.png
 /8085/poly.png
index 1d8b362..6df0645 100644 (file)
 COLOURS=0,5,5,1,2,4,6,3,7
 
 all: \
-circuits.ps \
+circuits.pdf \
+gates.pdf \
+fets.pdf \
 node_sizes.txt \
-node_gnd.png \
-node_vcc.png \
-node_phi0.png \
-node_phi1.png \
+net_gnd.png \
+net_vcc.png \
+net_phi0.png \
+net_phi1.png \
 layers.png \
 layers_rev.png
 #buried2.png \
@@ -25,38 +27,46 @@ layers_rev.png
 #poly2.png \
 #vias2.png
 
-# requires psutils package
-circuits.ps: circuits.txt
-       rm -rf dot
-       ../scripts/blocks.py $< dot
-       for i in dot/*.dot; \
-do \
-  dot -Tps2 -o dot/`basename $$i .dot`.ps $$i; \
-done
-       psmerge -o$@ dot/*.ps
+circuits.pdf: circuits.dot
+       dot -Tpdf -o $@ $<
+
+circuits.dot: circuits.txt
+       ../scripts/blocks.py $< $@
 
 circuits.txt: gates.txt
        ../scripts/circuits.py $< $@ GND,VCC
 
+gates.pdf: gates.dot
+       dot -Tpdf -o $@ $<
+
+gates.dot: gates.txt
+       ../scripts/blocks.py $< $@
+
 gates.txt: fets.txt
        ../scripts/gates.py $< $@ GND,VCC
 
+fets.pdf: fets.dot
+       dot -Tpdf -o $@ $<
+
+fets.dot: fets.txt
+       ../scripts/blocks.py $< $@
+
 fets.txt: nodes.txt
        ../scripts/fets.py $< $@ 1,4,5,6,7
 
 node_sizes.txt: nodes.txt
        ../scripts/node_sizes.py $< >$@
 
-node_gnd.png: nodes.txt
+net_gnd.png: nodes.txt
        ../scripts/node_image.py --adjacency $< GND $@ ${COLOURS}
 
-node_vcc.png: nodes.txt
+net_vcc.png: nodes.txt
        ../scripts/node_image.py --adjacency $< VCC $@ ${COLOURS}
 
-node_phi0.png: nodes.txt
+net_phi0.png: nodes.txt
        ../scripts/node_image.py --adjacency $< phi0 $@ ${COLOURS}
 
-node_phi1.png: nodes.txt
+net_phi1.png: nodes.txt
        ../scripts/node_image.py --adjacency $< phi1 $@ ${COLOURS}
 
 nodes.txt: \
@@ -149,20 +159,21 @@ vias2.png: vias1.png
 
 clean:
        rm -rf \
-dot \
 buried.png \
 diff.png \
 layers.png \
 layers_rev.png \
 metal.png \
-node_gnd.png \
-node_phi0.png \
-node_phi1.png \
-node_vcc.png \
+net_gnd.png \
+net_phi0.png \
+net_phi1.png \
+net_vcc.png \
 pads.png \
 poly.png \
 split_diff.png \
 vias.png \
+circuits.pdf \
+circuits.dot \
 circuits.txt \
 fets.txt \
 gates.txt \
index 6b24837..4c3ebbe 100755 (executable)
@@ -1,6 +1,5 @@
 #!/usr/bin/env python3
 
-import os
 import sys
 
 SYMBOL_TYPE_FET = 0
@@ -27,11 +26,12 @@ if len(sys.argv) >= 2 and sys.argv[1] == '--dump_nets':
   dump_nets = True
   del sys.argv[1]
 if len(sys.argv) < 3:
-  print(f'usage: {sys.argv[0]:s} [--dump_nets] symbols.txt dot_dir')
+  print(f'usage: {sys.argv[0]:s} [--dump_nets] symbols.txt symbols.dot')
   sys.exit(1)
 symbols_txt = sys.argv[1]
-dot_dir = sys.argv[2]
+symbols_dot = sys.argv[2]
 
+print('input')
 nets = {}
 blocks = {}
 symbols = []
@@ -123,33 +123,52 @@ if dump_nets:
     for block in sorted(net_blocks):
       print(net, block)
 
-try:
-  os.mkdir(dot_dir)
-except FileExistsError:
-  pass
-for block, block_symbols in sorted(blocks.items()):
-  with open(f'{dot_dir:s}/{block:s}.dot', 'w') as fout:
-    fout.write(f'digraph "{block:s}" {{\n')
-    fout.write(f'  title="{block:s}"\n')
-
-    net_nodes = set()
-    disambiguator = 0
+print('output')
+with open(symbols_dot, 'w') as fout:
+  for block, block_symbols in sorted(blocks.items()):
+    fout.write(
+      f'''digraph "{block:s}" {{
+  title="{block:s}"
+  rankdir=LR
+'''
+    )
+
+    next_node = 0
+    def make_node(label, shape = None):
+      global next_node
+      node = next_node
+      next_node += 1
+      attrs = [f'label="{label:s}"']
+      if shape is not None:
+        attrs.append(f'shape={shape:s}')
+      fout.write('  {0:d} [{1:s}]\n'.format(node, ', '.join(attrs)))
+      return node
+
+    local_nets = {}
     def make_net_node(net):
-      global disambiguator
-
-      if len(nets[net]) > 1:
-        # global net, make a new copy each time
-        net_node = f'net:{net:s}:{disambiguator:d}'
-        disambiguator += 1
-        shape = 'box'
-      else:
+      if net in local_nets:
+        return local_nets[net]
+      if len(nets[net]) <= 1:
         # local net, make a shared copy
-        net_node = f'net:{net:s}'
+        local_nets[net] = next_node
         shape = 'plaintext'
-      if net_node not in net_nodes:
-        net_nodes.add(net_node)
-        fout.write(f'  "{net_node:s}" [shape={shape:s}, label="{net:s}"]\n')
-      return net_node
+      else:
+        shape = 'box'
+      return make_node(net, shape)
+
+    def make_edge(node0, node1, label = None, arrowhead = None):
+      attrs = []
+      if label is not None:
+        attrs.append(f'label="{label:s}"')
+      if arrowhead is not None:
+        attrs.append(f'arrowhead={arrowhead:s}')
+      fout.write(
+        '  {0:d} -> {1:d}{2:s}\n'.format(
+          node0,
+          node1,
+          '' if len(attrs) == 0 else ' [{0:s}]'.format(', '.join(attrs))
+        )
+      )
 
     for i in block_symbols:
       symbol_type = symbols[i][0]
@@ -166,24 +185,19 @@ for block, block_symbols in sorted(blocks.items()):
           r_matrix
         ) = symbols[i]
 
-        node = f'{symbol_type:d}:{channel:s}'
         label = channel
         if len(r_matrix) == 2:
-          label += f'\nR={r_matrix[1][0]:.3f}'
+          label += f'\\nR={r_matrix[1][0]:.3f}'
         else:
-          label += f'\nC={mass / 2e4:.3f}'
-        fout.write(f'  "{node:s}" [label="{label:s}"]\n')
-
-        net_node = make_net_node(poly_net)
-        fout.write(f'  "{net_node:s}" -> "{node:s}"\n')
+          label += f'\\nC={mass / 2e4:.3f}'
+        node = make_node(label)
 
+        make_edge(make_net_node(poly_net), node)
         for diff_net in diff_nets:
-          net_node = make_net_node(diff_net)
-          fout.write(f'  "{node:s}" -> "{net_node:s}" [arrowhead=none]\n')
+          make_edge(node, make_net_node(diff_net), arrowhead = 'none')
       elif symbol_type == SYMBOL_TYPE_GATE:
         _, _, (y_net, expr) = symbols[i]
 
-        node = f'{symbol_type:d}:{y_net:s}'
         if len(expr) == 1:
           label = (
             'FALSE'
@@ -192,82 +206,54 @@ for block, block_symbols in sorted(blocks.items()):
           if len(expr[0]) == 1 else
             'NAND'
           )
-          fout.write(
-            f'  "{node:s}" [shape="invhouse", label="{label:s}"]\n'
-          )
+          node = make_node(label, shape = 'cds')
 
           for a_net in expr[0]:
-            net_node = make_net_node(a_net)
-            fout.write(f'  "{net_node:s}" -> "{node:s}"\n')
+            make_edge(make_net_node(a_net), node)
         else:
           label = 'TRUE' if len(expr) == 0 else 'NOR'
-          fout.write(
-            f'  "{node:s}" [shape="invhouse", label="{label:s}"]\n'
-          )
+          node = make_node(label, shape = 'cds')
 
           for j in range(len(expr)):
-            inner_node = f'{node:s}:{j:d}'
             if len(expr[j]) == 1:
-              net_node = make_net_node(expr[j][0])
-              fout.write(f'  "{net_node:s}" -> "{node:s}"\n')
+              inner_node = make_net_node(expr[j][0])
             else:
               label = 'TRUE' if len(expr[j]) == 0 else 'AND'
-              fout.write(
-                f'  "{inner_node:s}" [shape="invhouse", label="{label:s}"]\n'
-              )
+              inner_node = make_node(label, shape = 'cds')
 
               for a_net in expr[j]:
-                net_node = make_net_node(a_net)
-                fout.write(f'  "{net_node:s}" -> "{inner_node:s}"\n')
-              fout.write(f'  "{inner_node:s}" -> "{node:s}"\n')
-        net_node = make_net_node(y_net)
-        fout.write(f'  "{node:s}" -> "{net_node:s}"\n')
+                make_edge(make_net_node(a_net), inner_node)
+            make_edge(inner_node, node)
+        make_edge(node, make_net_node(y_net))
       elif symbol_type == SYMBOL_TYPE_XOR:
         _, _, (a_net, b_net, y_net) = symbols[i]
 
-        node = f'{symbol_type:d}:{y_net:s}'
-        fout.write(f'  "{node:s}" [shape="invhouse", label="XOR"]\n')
+        node = make_node('XOR', shape = 'cds')
 
-        net_node = make_net_node(a_net)
-        fout.write(f'  "{net_node:s}" -> "{node:s}"\n')
-        net_node = make_net_node(b_net)
-        fout.write(f'  "{net_node:s}" -> "{node:s}"\n')
-        net_node = make_net_node(y_net)
-        fout.write(f'  "{node:s}" -> "{net_node:s}"\n')
+        make_edge(make_net_node(a_net), node)
+        make_edge(make_net_node(b_net), node)
+        make_edge(node, make_net_node(y_net))
       elif symbol_type == SYMBOL_TYPE_TG_LATCH:
         _, _, (d_net, le_net, len_net, q_net, qn_net) = symbols[i]
 
-        node = f'{symbol_type:d}:{q_net:s}'
-        fout.write(f'  "{node:s}" [shape="invhouse", label="TG_LATCH"]\n')
-
-        net_node = make_net_node(d_net)
-        fout.write(f'  "{net_node:s}" -> "{node:s}" [label="D"]\n')
-        net_node = make_net_node(le_net)
-        fout.write(f'  "{net_node:s}" -> "{node:s}" [label="LE"]\n')
-        net_node = make_net_node(len_net)
-        fout.write(f'  "{net_node:s}" -> "{node:s}" [label="/LE"]\n')
-        net_node = make_net_node(q_net)
-        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')
+        node = make_node('TG_LATCH', shape = 'cds')
+
+        make_edge(make_net_node(d_net), node, label = 'D')
+        make_edge(make_net_node(le_net), node, label = 'LE')
+        make_edge(make_net_node(len_net), node, label = '/LE')
+        make_edge(node, make_net_node(q_net), label = 'Q')
+        make_edge(node, make_net_node(qn_net), label = '/Q')
       elif symbol_type == SYMBOL_TYPE_TG_LATCH_FB:
         _, _, (d_net, le_net, len_net, q_net, qn_net, fb_net) = symbols[i]
 
-        node = f'{symbol_type:d}:{q_net:s}'
-        fout.write(f'  "{node:s}" [shape="invhouse", label="TG_LATCH_FB"]\n')
-
-        net_node = make_net_node(d_net)
-        fout.write(f'  "{net_node:s}" -> "{node:s}" [label="D"]\n')
-        net_node = make_net_node(le_net)
-        fout.write(f'  "{net_node:s}" -> "{node:s}" [label="LE"]\n')
-        net_node = make_net_node(len_net)
-        fout.write(f'  "{net_node:s}" -> "{node:s}" [label="/LE"]\n')
-        net_node = make_net_node(q_net)
-        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')
-        net_node = make_net_node(fb_net)
-        fout.write(f'  "{node:s}" -> "{net_node:s}" [label="FB"]\n')
+        node = make_node('TG_LATCH_FB', shape = 'cds')
+
+        make_edge(make_net_node(d_net), node, label = 'D')
+        make_edge(make_net_node(le_net), node, label = 'LE')
+        make_edge(make_net_node(len_net), node, label = '/LE')
+        make_edge(node, make_net_node(q_net), label = 'Q')
+        make_edge(node, make_net_node(qn_net), label = '/Q')
+        make_edge(node, make_net_node(fb_net), label = 'FB')
       elif (
         symbol_type == SYMBOL_TYPE_TG_LATCH_CLR or
         symbol_type == SYMBOL_TYPE_TG_LATCH_SET
@@ -278,139 +264,96 @@ for block, block_symbols in sorted(blocks.items()):
           (d_net, le_net, len_net, clr_set_net, q_net, qn_net)
         ) = symbols[i]
 
-        node = f'{symbol_type:d}:{q_net:s}'
         clr_set = (
           'CLR'
         if symbol_type == SYMBOL_TYPE_TG_LATCH_CLR else
           'SET'
         )
         label = f'TG_LATCH_{clr_set:s}'
-        fout.write(
-          f'  "{node:s}" [shape="invhouse", label="{label:s}"]\n'
-        )
-
-        net_node = make_net_node(d_net)
-        fout.write(f'  "{net_node:s}" -> "{node:s}" [label="D"]\n')
-        net_node = make_net_node(le_net)
-        fout.write(f'  "{net_node:s}" -> "{node:s}" [label="LE"]\n')
-        net_node = make_net_node(len_net)
-        fout.write(f'  "{net_node:s}" -> "{node:s}" [label="/LE"]\n')
-        net_node = make_net_node(clr_set_net)
-        fout.write(f'  "{net_node:s}" -> "{node:s}" [label="{clr_set:s}"]\n')
-        net_node = make_net_node(q_net)
-        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')
+        node = make_node(label, shape = 'cds')
+
+        make_edge(make_net_node(d_net), node, label = 'D')
+        make_edge(make_net_node(le_net), node, label = 'LE')
+        make_edge(make_net_node(len_net), node, label = '/LE')
+        make_edge(make_net_node(clr_set_net), node, label = clr_set)
+        make_edge(node, make_net_node(q_net), label = 'Q')
+        make_edge(node, make_net_node(qn_net), label = '/Q')
       elif (
         symbol_type == SYMBOL_TYPE_TG_LATCH_CLR_FB or
         symbol_type == SYMBOL_TYPE_TG_LATCH_SET_FB
       ):
-        (
-          _,
-          _,
-          (d_net, le_net, len_net, clr_set_net, q_net, qn_net, fb_net)
-        ) = symbols[i]
-
-        node = f'{symbol_type:d}:{q_net:s}'
         clr_set = (
           'CLR'
-        if symbol_type == SYMBOL_TYPE_TG_LATCH_CLR_FB else
+        if symbol_type == SYMBOL_TYPE_TG_LATCH_CLR else
           'SET'
         )
         label = f'TG_LATCH_{clr_set:s}_FB'
-        fout.write(
-          f'  "{node:s}" [shape="invhouse", label="{label:s}"]\n'
-        )
-
-        net_node = make_net_node(d_net)
-        fout.write(f'  "{net_node:s}" -> "{node:s}" [label="D"]\n')
-        net_node = make_net_node(le_net)
-        fout.write(f'  "{net_node:s}" -> "{node:s}" [label="LE"]\n')
-        net_node = make_net_node(len_net)
-        fout.write(f'  "{net_node:s}" -> "{node:s}" [label="/LE"]\n')
-        net_node = make_net_node(clr_set_net)
-        fout.write(f'  "{net_node:s}" -> "{node:s}" [label="{clr_set:s}"]\n')
-        net_node = make_net_node(q_net)
-        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')
-        net_node = make_net_node(fb_net)
-        fout.write(f'  "{node:s}" -> "{net_node:s}" [label="FB"]\n')
+        node = make_node(label, shape = 'cds')
+
+        make_edge(make_net_node(d_net), node, label = 'D')
+        make_edge(make_net_node(le_net), node, label = 'LE')
+        make_edge(make_net_node(len_net), node, label = '/LE')
+        make_edge(make_net_node(clr_set_net), node, label = clr_set)
+        make_edge(node, make_net_node(q_net), label = 'Q')
+        make_edge(node, make_net_node(qn_net), label = '/Q')
+        make_edge(node, make_net_node(fb_net), label = 'FB')
       elif (
         symbol_type == SYMBOL_TYPE_SUPER or
         symbol_type == SYMBOL_TYPE_NOT_SUPER
       ):
         _, _, (a_net, y_net) = symbols[i]
 
-        node = f'{symbol_type:d}:{y_net:s}'
         label = 'SUPER' if symbol_type == SYMBOL_TYPE_SUPER else 'NOT_SUPER'
-        fout.write(f'  "{node:s}" [shape="invhouse", label="{label:s}"]\n')
+        node = make_node(label, shape = 'cds')
 
-        net_node = make_net_node(a_net)
-        fout.write(f'  "{net_node:s}" -> "{node:s}" [label="A"]\n')
-        net_node = make_net_node(y_net)
-        fout.write(f'  "{node:s}" -> "{net_node:s}" [label="Y"]\n')
+        make_edge(make_net_node(a_net), node)
+        make_edge(node, make_net_node(y_net))
       elif (
         symbol_type == SYMBOL_TYPE_SUPER_OE or
         symbol_type == SYMBOL_TYPE_NOT_SUPER_OE
       ):
         _, _, (a_net, oen_net, y_net) = symbols[i]
 
-        # note: need a better way to disambiguate when y net can be hi-Z
-        node = f'{symbol_type:d}:{oen_net:s}:{y_net:s}'
-        label = 'SUPER_OE' if symbol_type == SYMBOL_TYPE_SUPER else 'NOT_SUPER_OE'
-        fout.write(f'  "{node:s}" [shape="invhouse", label="{label:s}"]\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')
+        label = (
+          'SUPER_OE'
+        if symbol_type == SYMBOL_TYPE_SUPER else
+          'NOT_SUPER_OE'
+        )
+        node = make_node(label, shape = 'cds')
+
+        make_edge(make_net_node(a_net), node, 'A')
+        make_edge(make_net_node(oen_net), node, '/OE')
+        make_edge(node, make_net_node(y_net), 'Y')
       elif symbol_type == SYMBOL_TYPE_NOR_SUPER:
         _, _, (a_net, b_net, y_net) = symbols[i]
 
-        node = f'{symbol_type:d}:{y_net:s}'
-        fout.write(f'  "{node:s}" [shape="invhouse", label="NOR_SUPER"]\n')
+        node = make_node('NOR_SUPER', shape = 'cds')
 
-        net_node = make_net_node(a_net)
-        fout.write(f'  "{net_node:s}" -> "{node:s}" [label="A"]\n')
-        net_node = make_net_node(b_net)
-        fout.write(f'  "{net_node:s}" -> "{node:s}" [label="B"]\n')
-        net_node = make_net_node(y_net)
-        fout.write(f'  "{node:s}" -> "{net_node:s}" [label="Y"]\n')
+        make_edge(make_net_node(a_net), node, 'A')
+        make_edge(make_net_node(b_net), node, 'B')
+        make_edge(node, make_net_node(y_net), 'Y')
       elif symbol_type == SYMBOL_TYPE_NOR_SUPER_HD:
         _, _, (a_net, b_net, y_net, hd_net) = symbols[i]
 
-        node = f'{symbol_type:d}:{y_net:s}'
-        fout.write(f'  "{node:s}" [shape="invhouse", label="NOR_SUPER_HD"]\n')
-
-        net_node = make_net_node(a_net)
-        fout.write(f'  "{net_node:s}" -> "{node:s}" [label="A"]\n')
-        net_node = make_net_node(b_net)
-        fout.write(f'  "{net_node:s}" -> "{node:s}" [label="B"]\n')
-        net_node = make_net_node(y_net)
-        fout.write(f'  "{node:s}" -> "{net_node:s}" [label="Y"]\n')
-        net_node = make_net_node(hd_net)
-        fout.write(f'  "{node:s}" -> "{net_node:s}" [label="HD"]\n')
+        node = make_node('NOR_SUPER_HD', shape = 'cds')
+
+        make_edge(make_net_node(a_net), node, 'A')
+        make_edge(make_net_node(b_net), node, 'B')
+        make_edge(node, make_net_node(y_net), 'Y')
+        make_edge(node, make_net_node(hd_net), 'HD')
       elif (
         symbol_type == SYMBOL_TYPE_MUX2 or
         symbol_type == SYMBOL_TYPE_MUX2_NOT
       ):
         _, _, (a_net, b_net, s_net, y_net) = symbols[i]
 
-        node = f'{symbol_type:d}:{y_net:s}'
         label = 'MUX2' if symbol_type == SYMBOL_TYPE_MUX2 else 'MUX2_NOT'
-        fout.write(f'  "{node:s}" [shape="invhouse", label="{label:s}"]\n')
-
-        net_node = make_net_node(a_net)
-        fout.write(f'  "{net_node:s}" -> "{node:s}" [label="A"]\n')
-        net_node = make_net_node(b_net)
-        fout.write(f'  "{net_node:s}" -> "{node:s}" [label="B"]\n')
-        net_node = make_net_node(s_net)
-        fout.write(f'  "{net_node:s}" -> "{node:s}" [label="S"]\n')
-        net_node = make_net_node(y_net)
-        fout.write(f'  "{node:s}" -> "{net_node:s}" [label="Y"]\n')
+        node = make_node(label, shape = 'cds')
+
+        make_edge(make_net_node(a_net), node, 'A')
+        make_edge(make_net_node(b_net), node, 'B')
+        make_edge(make_net_node(s_net), node, 'S')
+        make_edge(node, make_net_node(y_net), 'Y')
       else:
         assert False
     fout.write('}\n')