| #!/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) |