Added support for Paul Schulz's alphanumeric font character library
for magic, including a modification of the text2mag.py script for
use with the open_pdks installation.
diff --git a/sky130/custom/scripts/text2mag.py b/sky130/custom/scripts/text2mag.py
new file mode 100755
index 0000000..8d62db3
--- /dev/null
+++ b/sky130/custom/scripts/text2mag.py
@@ -0,0 +1,143 @@
+#!/bin/env python3
+
+# text2mag.py
+#
+# Read a text file from standard input and write out the text as an
+# array of magic cells using the sky130_ml_xx_hd library.
+#
+# Adapted from the script by Paul Schulz <paul@mawsonlakes.org> in
+# the sky130_ml_xx_hd repository.  Modified for open_pdks standard
+# paths, and to take the text string as an argument in addition to
+# stdin.
+
+import getopt
+import sys
+import os
+import subprocess
+
+
+# Options
+options, remainder = getopt.getopt(sys.argv[1:],
+                                   'c:p:m:kh',
+                                   ['cellname',
+				    'pdk',
+				    'message',
+				    'keep',
+                                    'help',
+                                   ])
+
+def usage(ofile):
+    print('text2mag.py <options>', file=ofile)
+    print('', file=ofile)
+    print('  Options:', file=ofile)
+    print('    [-c|--cellname]   - Required. Cell name to use.', file=ofile)
+    print('    [-m|--message]    - Text to convert (default: use stdin).', file=ofile)
+    print('    [-k|--keep]       - Keep generator script', file=ofile)     
+    print('    [-h|--help]       - Display these details', file=ofile)
+
+keep = False
+message = None
+cellname = None
+for opt, arg in options:
+    if opt in ('-c', '--cellname'):
+        cellname = arg
+    elif opt in ('-m', '--message'):
+        message = arg
+    elif opt in ('-k', '--keep'):
+        keep = True
+    elif opt in ('-h', '--help'):
+        usage(sys.stdout)
+        sys.exit(0)
+    else:
+        usage(sys.stderr)
+        sys.exit(1)
+
+if not cellname:
+    usage(sys.stderr)
+    print('', file=sys.stderr)
+    print('*** cellname required', file=sys.stderr)
+    sys.exit(1)
+
+# Convert character ID to cellname
+# Accepts character UTF-8 encodings
+
+def get_cellname (ch):
+    """Return name of cell used to store character data"""
+
+    prefix = 'font_'
+
+    if (ord(ch) < 0x100):
+        cellname = '{:02X}'.format(ord(ch))
+    elif (ord(ch) < 0x10000):
+        cellname = '{:04X}'.format(ord(ch))
+    elif (ord(ch) < 0x1000000):
+        cellname = '{:06X}'.format(ord(ch))
+    else:
+        cellname = '{:X}'.format(ord(ch))
+
+    return prefix + cellname
+
+def write_text_generator(message, ofile):
+    x = 0
+    y = 0
+    baselineskip = 400
+
+    print('drc off', file=ofile)
+    print('snap int', file=ofile)
+    print('select top cell', file=ofile)
+    print('box position 0 0', file=ofile)
+    print('', file=ofile)
+
+    # NOTE:  When a character is not found, substitute "?"
+
+    for char in message:
+        if char != '\n':
+            filename = get_cellname(char)
+            print('if {[catch {getcell ' + filename + ' child 0 0}]} {', file=ofile)
+            print('   getcell font_3F child 0 0', file=ofile)
+            print('}', file=ofile)
+            print('pushstack', file=ofile)
+            print('set bbox [property FIXED_BBOX]', file=ofile)
+            print('set width [expr {[lindex $bbox 2] - [lindex $bbox 0]}]', file=ofile)
+            print('popstack', file=ofile)
+            print('box move e $width', file=ofile)
+        else:
+            x = 0
+            y = y - baselineskip
+            print('box position {} {}'.format(x,y), file=ofile)
+
+    print('save ' + cellname, file=ofile)
+    print('quit -noprompt', file=ofile)
+
+##############################################################################
+# Take message from stdin if not specified on the command line.
+
+if not message:
+    for line in sys.stdin:
+        message = message + line
+
+with open('gen_message.tcl', 'w') as ofile:
+    write_text_generator(message, ofile)
+
+    # Run magic with the text generator script as input.
+    # NOTE:  Assumes that a .magicrc file exists at the target and that
+    # it already includes the library in the search path.
+
+    mproc = subprocess.run(['magic', '-dnull', '-noconsole', 'gen_message.tcl'],
+		stdin = subprocess.DEVNULL, stdout = subprocess.PIPE,
+		stderr = subprocess.PIPE, universal_newlines = True)
+    if mproc.stdout:
+        for line in mproc.stdout.splitlines():
+            print(line)
+    if mproc.stderr:
+        print('Error message output from magic:')
+        for line in mproc.stderr.splitlines():
+            print(line)
+    if mproc.returncode != 0:
+        print('ERROR:  Magic exited with status ' + str(mproc.returncode))
+
+# Delete the text generator script
+if not keep:
+    os.remove('gen_message.tcl')
+
+sys.exit(mproc.returncode)