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/VERSION b/VERSION
index 5ca0603..9d25b39 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.0.88
+1.0.89
diff --git a/sky130/Makefile.in b/sky130/Makefile.in
index 194b5e6..aab678b 100644
--- a/sky130/Makefile.in
+++ b/sky130/Makefile.in
@@ -46,6 +46,10 @@
 #		cloned from https://github.com/google/skywater-pdk.  This
 #		option is mandatory and has no default.
 #
+#
+# NOTE:  The comments below are for features that have not yet been
+# implemented.
+#
 # Enable/disable for specific libraries to be installed (and downloaded if
 # needed).  Libraries that are part of the open_pdks repository are enabled
 # by default and must be disabled by passing an option to configure.  Libraries
@@ -85,11 +89,9 @@
 #		repository and installed.
 #
 #	--enable-alpha-lib[=<path>]
-#		If enabled, install the alphanumeric library.  If <path> is
-#		specified, then the alphanumeric library is expected to be
-#		found rooted at the given path.  If not specified, then the
-#		alphanumeric library will be cloned from the git repository
-#		and installed.
+#		If enabled, install the sky130_ml_xx_hd font library from
+#		Paul Schulz on github.  If not specified, then the font
+#		library will be cloned from the git repository and installed.
 #
 #	--enable-xschem[=<path>]
 #		If enabled, install the Sky130 setup for the xschem schematic
@@ -169,6 +171,9 @@
 # Path to OSU standard cell library sources (to be added to configuration options).
 OSU_PATH = ~/gits/osu_130_pdk
 
+# Path to independent library sources (to be added to configuration options).
+REPO_PATH = ~/gits
+
 # NOTE:  Install destination is the git repository of the technology platform.
 # Once updated in git, the git project can be distributed to all hosts.
 #
@@ -506,6 +511,14 @@
 	${RM} ${STAGING_PATH}/${SKY130A}/libs.ref/sky130_fd_sc_ms/verilog/*.*.v
 	${RM} ${STAGING_PATH}/${SKY130A}/libs.ref/sky130_fd_sc_ls/verilog/*.*.v
 	${RM} ${STAGING_PATH}/${SKY130A}/libs.ref/sky130_fd_sc_lp/verilog/*.*.v
+	# Install alphanumeric library.
+	${STAGE} -source ${REPO_PATH} -target ${STAGING_PATH}/${SKY130A} \
+		-mag %l/mag/*.mag \
+		-library general sky130_ml_xx_hd |& tee -a ${SKY130A}_install.log
+	# Install text2mag.py script for alphanumeric library
+	mkdir -p ${STAGING_PATH}/${SKY130A}/libs.ref/sky130_ml_xx_hd/scripts
+	cp custom/scripts/text2mag.py \
+		${STAGING_PATH}/${SKY130A}/libs.ref/sky130_ml_xx_hd/scripts
 	# Install OSU digital standard cells.
 	${STAGE} -source ${SKYWATER_PATH} -target ${STAGING_PATH}/${SKY130A} \
 		-techlef %l/latest/lef/sky130_osu_sc.tlef rename=sky130_osu_sc_t18.tlef \
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)
diff --git a/sky130/magic/sky130.magicrc b/sky130/magic/sky130.magicrc
index 601e378..c0828aa 100644
--- a/sky130/magic/sky130.magicrc
+++ b/sky130/magic/sky130.magicrc
@@ -61,6 +61,7 @@
     addpath ${PDKPATH}/libs.ref/${MAGTYPE}/sky130_fd_sc_ms
     addpath ${PDKPATH}/libs.ref/${MAGTYPE}/sky130_osu_sc
     addpath ${PDKPATH}/libs.ref/${MAGTYPE}/sky130_osu_sc_t18
+    addpath ${PDKPATH}/libs.ref/${MAGTYPE}/sky130_ml_xx_hd
 } else {
     addpath ${PDKPATH}/libs.ref/sky130_fd_pr/${MAGTYPE}
     addpath ${PDKPATH}/libs.ref/sky130_fd_io/${MAGTYPE}
@@ -73,6 +74,7 @@
     addpath ${PDKPATH}/libs.ref/sky130_fd_sc_ms/${MAGTYPE}
     addpath ${PDKPATH}/libs.ref/sky130_osu_sc/${MAGTYPE}
     addpath ${PDKPATH}/libs.ref/sky130_osu_sc_t18/${MAGTYPE}
+    addpath ${PDKPATH}/libs.ref/sky130_ml_xx_hd/${MAGTYPE}
 }
 
 # add path to GDS cells
@@ -89,6 +91,7 @@
     path cell +${PDKPATH}/libs.ref/gds/sky130_fd_sc_ms
     path cell +${PDKPATH}/libs.ref/gds/sky130_osu130
     path cell +${PDKPATH}/libs.ref/gds/sky130_osu130_t18
+    path cell +${PDKPATH}/libs.ref/gds/sky130_ml_xx_hd
 } else {
     path cell ${PDKPATH}/libs.ref/sky130_fd_pr/gds
     path cell +${PDKPATH}/libs.ref/sky130_fd_io/gds
@@ -101,6 +104,7 @@
     path cell +${PDKPATH}/libs.ref/sky130_fd_sc_ms/gds
     path cell +${PDKPATH}/libs.ref/sky130_osu130/gds
     path cell +${PDKPATH}/libs.ref/sky130_osu130_t18/gds
+    path cell +${PDKPATH}/libs.ref/sky130_ml_xx_hd/gds
 }
 #endif (FULLTECH)