| #!/usr/bin/env python3 | |
| #-------------------------------------------------------- | |
| # make_icon_from_soft.py -- | |
| # | |
| # Create an electric icon (manually) from information taken from | |
| # a verilog module. | |
| #----------------------------------------------------------------- | |
| import os | |
| import re | |
| import sys | |
| import json | |
| import datetime | |
| import subprocess | |
| def create_symbol(projectpath, verilogfile, project, destfile=None, debug=False, dolist=False): | |
| if not os.path.exists(projectpath): | |
| print('No path to project ' + projectpath) | |
| return 1 | |
| if not os.path.isfile(verilogfile): | |
| print('No path to verilog file ' + verilogfile) | |
| return 1 | |
| if not os.path.exists(projectpath + '/elec'): | |
| print('No electric subdirectory /elec/ in project.') | |
| return 1 | |
| if not destfile: | |
| delibdir = projectpath + '/elec/' + project + '.delib' | |
| if not os.path.isdir(delibdir): | |
| print('No electric library ' + project + '.delib in project.') | |
| return 1 | |
| if os.path.isfile(delibdir + '/' + project + '.ic'): | |
| print('Symbol file ' + project + '.ic exists already.') | |
| print('Please remove it if you want to overwrite it.') | |
| return 1 | |
| # By default, put the icon file in the project's electric library | |
| destfile = projectpath + '/elec/' + project + '.delib/' + project + '.ic' | |
| desthdr = projectpath + '/elec/' + project + '.delib/header' | |
| else: | |
| if os.path.isfile(destfile): | |
| print('Symbol file ' + project + '.ic exists already.') | |
| print('Please remove it if you want to overwrite it.') | |
| return 1 | |
| destdir = os.path.split(destfile)[0] | |
| desthdr = destdir + '/header' | |
| if not os.path.isdir(destdir): | |
| os.makedirs(destdir) | |
| # Original verilog source can be very complicated to parse. Run through | |
| # qflow's vlog2Verilog tool to get a much simplified header, which also | |
| # preprocesses the verilog, handles parameters, etc. | |
| vdir = os.path.split(verilogfile)[0] | |
| vtempfile = vdir + '/vtemp.out' | |
| p = subprocess.run(['/usr/local/share/qflow/bin/vlog2Verilog', | |
| '-p', '-o', vtempfile, verilogfile], stdout = subprocess.PIPE) | |
| if not os.path.exists(vtempfile): | |
| print('Error: Failed to create preprocessed verilog from ' + verilogfile) | |
| return 1 | |
| # Okay, ready to go. Now read the verilog source file and get the list | |
| # of pins. | |
| commstr1 = '/\*.*\*/' | |
| commstr2 = '//[^\n]*\n' | |
| c1rex = re.compile(commstr1) | |
| c2rex = re.compile(commstr2) | |
| # Find and isolate the module and its pin list. | |
| modstr = 'module[ \t]+' + project + '[ \t]*\(([^\)]+)\)[ \t\n]*;' | |
| modrex = re.compile(modstr) | |
| # End parsing on any of these tokens | |
| endrex = re.compile('[ \t]*(initial|function|task|always)') | |
| inpins = [] | |
| outpins = [] | |
| iopins = [] | |
| invecs = [] | |
| outvecs = [] | |
| iovecs = [] | |
| with open(vtempfile, 'r') as ifile: | |
| vlines = ifile.read() | |
| # Remove comments | |
| vlines2 = c2rex.sub('\n', c1rex.sub('', vlines)) | |
| # Find and isolate the module pin list | |
| modpinslines = modrex.findall(vlines2) | |
| modpinsstart = modrex.search(vlines2) | |
| if modpinsstart: | |
| startc = modpinsstart.span()[0] | |
| else: | |
| startc = 0 | |
| modpinsend = endrex.search(vlines2[startc:]) | |
| if modpinsend: | |
| endc = modpinsend.span()[0] | |
| else: | |
| endc = len(vlines2) | |
| vlines2 = vlines2[startc:endc] | |
| # Find the module (there should be only one) and get pins if in the | |
| # format with input / output declarations in the module heading. | |
| pinlist = [] | |
| if len(modpinslines) > 0: | |
| modpins = modpinslines[0] | |
| pinlist = re.sub('[\t\n]', '', modpins).split(',') | |
| # If each pinlist entry is only one word, then look for following | |
| # lines "input", "output", etc., and compile them into a similar | |
| # list. Then parse each list entry. | |
| knownreal = {} | |
| knownpower = {} | |
| knownground = {} | |
| if len(pinlist) > 0 and len(pinlist[0].split()) == 1: | |
| invecrex = re.compile('\n[ \t]*input[ \t]*\[[ \t]*([0-9]+)[ \t]*:[ \t]*([0-9]+)[ \t]*\][ \t]*([^;]+);') | |
| insigrex = re.compile('\n[ \t]*input[ \t]+([^\[;]+);') | |
| outvecrex = re.compile('\n[ \t]*output[ \t]*\[[ \t]*([0-9]+)[ \t]*:[ \t]*([0-9]+)[ \t]*\][ \t]*([^;]+);') | |
| outsigrex = re.compile('\n[ \t]*output[ \t]+([^;\[]+);') | |
| iovecrex = re.compile('\n[ \t]*inout[ \t]*\[[ \t]*([0-9]+)[ \t]*:[ \t]*([0-9]+)[ \t]*\][ \t]*([^;]+);') | |
| iosigrex = re.compile('\n[ \t]*inout [ \t]+([^;\[]+);') | |
| # Find input, output, and inout lines | |
| for test in insigrex.findall(vlines2): | |
| pinname = list(item.strip() for item in test.split(',')) | |
| inpins.extend(pinname) | |
| for test in outsigrex.findall(vlines2): | |
| pinname = list(item.strip() for item in test.split(',')) | |
| outpins.extend(pinname) | |
| for test in iosigrex.findall(vlines2): | |
| pinname = list(item.strip() for item in test.split(',')) | |
| iopins.extend(pinname) | |
| for test in invecrex.finditer(vlines2): | |
| tpin = test.group(3).split(',') | |
| for pin in tpin: | |
| pinname = pin.strip() + '[' + test.group(1) + ':' + test.group(2) + ']' | |
| invecs.append(pinname) | |
| for test in outvecrex.finditer(vlines2): | |
| tpin = test.group(3).split(',') | |
| for pin in tpin: | |
| pinname = pin.strip() + '[' + test.group(1) + ':' + test.group(2) + ']' | |
| outvecs.append(pinname) | |
| for test in iovecrex.finditer(vlines2): | |
| tpin = test.group(3).split(',') | |
| for pin in tpin: | |
| pinname = pin.strip() + '[' + test.group(1) + ':' + test.group(2) + ']' | |
| iovecs.append(pinname) | |
| # Apply syntax checks (to do: check for "real" above) | |
| powerrec = re.compile('VDD|VCC', re.IGNORECASE) | |
| groundrec = re.compile('VSS|GND|GROUND', re.IGNORECASE) | |
| for pinname in inpins + outpins + iopins + invecs + outvecs + iovecs: | |
| pmatch = powerrec.match(pinname) | |
| gmatch = groundrec.match(pinname) | |
| if pmatch: | |
| knownpower[pinname] = True | |
| if gmatch: | |
| knownground[pinname] = True | |
| else: | |
| # Get pin lists from module pin list. These are simpler to | |
| # parse, since they have to be enumerated one by one. | |
| invecrex = re.compile('[ \t]*input[ \t]*\[[ \t]*([0-9]+)[ \t]*:[ \t]*([0-9]+)[ \t]*\][ \t]*(.+)') | |
| insigrex = re.compile('[ \t]*input[ \t]+([a-zA-Z_][^ \t]+)') | |
| outvecrex = re.compile('[ \t]*output[ \t]*\[[ \t]*([0-9]+)[ \t]*:[ \t]*([0-9]+)[ \t]*\][ \t]*(.+)') | |
| outsigrex = re.compile('[ \t]*output[ \t]+([a-zA-Z_][^ \t]+)') | |
| iovecrex = re.compile('[ \t]*inout[ \t]*\[[ \t]*([0-9]+)[ \t]*:[ \t]*([0-9]+)[ \t]*\][ \t]*(.+)') | |
| iosigrex = re.compile('[ \t]*inout[ \t]+([a-zA-Z_][^ \t]+)') | |
| realrec = re.compile('[ \t]+real[ \t]+') | |
| logicrec = re.compile('[ \t]+logic[ \t]+') | |
| wirerec = re.compile('[ \t]+wire[ \t]+') | |
| powerrec = re.compile('VDD|VCC', re.IGNORECASE) | |
| groundrec = re.compile('VSS|GND|GROUND', re.IGNORECASE) | |
| for pin in pinlist: | |
| # Pull out any reference to "real", "logic", or "wire" to get pin name | |
| ppin = realrec.sub(' ', logicrec.sub(' ', wirerec.sub(' ', pin.strip()))) | |
| pinname = None | |
| # Make syntax checks | |
| rmatch = realrec.match(pin) | |
| pmatch = powerrec.match(pin) | |
| gmatch = groundrec.match(pin) | |
| imatch = insigrex.match(ppin) | |
| if imatch: | |
| pinname = imatch.group(1) | |
| inpins.append(pinname) | |
| omatch = outsigrex.match(ppin) | |
| if omatch: | |
| pinname = omatch.group(1) | |
| outpins.append(pinname) | |
| bmatch = iosigrex.match(ppin) | |
| if bmatch: | |
| pinname = bmatch.group(1) | |
| iopins.append(pinname) | |
| ivmatch = invecrex.match(ppin) | |
| if ivmatch: | |
| pinname = ivmatch.group(3) + '[' + ivmatch.group(1) + ':' + ivmatch.group(2) + ']' | |
| invecs.append(pinname) | |
| ovmatch = outvecrex.match(ppin) | |
| if ovmatch: | |
| pinname = ovmatch.group(3) + '[' + ovmatch.group(1) + ':' + ovmatch.group(2) + ']' | |
| outvecs.append(pinname) | |
| bvmatch = iovecrex.match(ppin) | |
| if bvmatch: | |
| pinname = bvmatch.group(3) + '[' + bvmatch.group(1) + ':' + bvmatch.group(2) + ']' | |
| iovecs.append(pinname) | |
| # Apply syntax checks | |
| if pinname: | |
| if rmatch: | |
| knownreal[pinname] = True | |
| if pmatch and rmatch: | |
| knownpower[pinname] = True | |
| if gmatch and rmatch: | |
| knownground[pinname] = True | |
| if (os.path.exists(vtempfile)): | |
| os.remove(vtempfile) | |
| if len(inpins) + len(outpins) + len(iopins) + len(invecs) + len(outvecs) + len(iovecs) == 0: | |
| print('Failure to parse pin list for module ' + project + ' out of verilog source.') | |
| return 1 | |
| if debug: | |
| print("Input pins of module " + project + ":") | |
| for pin in inpins: | |
| print(pin) | |
| print("Output pins of module " + project + ":") | |
| for pin in outpins: | |
| print(pin) | |
| print("Bidirectional pins of module " + project + ":") | |
| for pin in iopins: | |
| print(pin) | |
| # If "dolist" is True, then create a list of pin records in the style used by | |
| # project.json, and return the list. | |
| if dolist == True: | |
| pinlist = [] | |
| for pin in inpins: | |
| pinrec = {} | |
| pinrec["name"] = pin | |
| pinrec["description"] = "(add description here)" | |
| if pin in knownreal: | |
| pinrec["type"] = 'signal' | |
| else: | |
| pinrec["type"] = 'digital' | |
| pinrec["Vmin"] = "-0.5" | |
| pinrec["Vmax"] = "VDD + 0.3" | |
| pinrec["dir"] = "input" | |
| pinlist.append(pinrec) | |
| for pin in outpins: | |
| pinrec = {} | |
| pinrec["name"] = pin | |
| pinrec["description"] = "(add description here)" | |
| if pin in knownreal: | |
| pinrec["type"] = 'signal' | |
| else: | |
| pinrec["type"] = 'digital' | |
| pinrec["Vmin"] = "-0.5" | |
| pinrec["Vmax"] = "VDD + 0.3" | |
| pinrec["dir"] = "output" | |
| pinlist.append(pinrec) | |
| for pin in iopins: | |
| pinrec = {} | |
| pinrec["name"] = pin | |
| pinrec["description"] = "(add description here)" | |
| if pin in knownpower: | |
| pinrec["type"] = 'power' | |
| pinrec["Vmin"] = "3.6" | |
| pinrec["Vmax"] = "3.0" | |
| elif pin in knownground: | |
| pinrec["type"] = 'ground' | |
| pinrec["Vmin"] = "0" | |
| pinrec["Vmax"] = "0" | |
| elif pin in knownreal: | |
| pinrec["type"] = 'signal' | |
| pinrec["Vmin"] = "-0.5" | |
| pinrec["Vmax"] = "VDD + 0.3" | |
| else: | |
| pinrec["type"] = 'digital' | |
| pinrec["Vmin"] = "-0.5" | |
| pinrec["Vmax"] = "VDD + 0.3" | |
| pinrec["dir"] = "inout" | |
| pinlist.append(pinrec) | |
| for pin in invecs: | |
| pinrec = {} | |
| pinrec["name"] = pin | |
| pinrec["description"] = "(add description here)" | |
| if pin in knownreal: | |
| pinrec["type"] = 'signal' | |
| else: | |
| pinrec["type"] = 'digital' | |
| pinrec["dir"] = "input" | |
| pinrec["Vmin"] = "-0.5" | |
| pinrec["Vmax"] = "VDD + 0.3" | |
| pinlist.append(pinrec) | |
| for pin in outvecs: | |
| pinrec = {} | |
| pinrec["name"] = pin | |
| pinrec["description"] = "(add description here)" | |
| if pin in knownreal: | |
| pinrec["type"] = 'signal' | |
| else: | |
| pinrec["type"] = 'digital' | |
| pinrec["dir"] = "output" | |
| pinrec["Vmin"] = "-0.5" | |
| pinrec["Vmax"] = "VDD + 0.3" | |
| pinlist.append(pinrec) | |
| for pin in iovecs: | |
| pinrec = {} | |
| pinrec["name"] = pin | |
| pinrec["description"] = "(add description here)" | |
| if pin in knownpower: | |
| pinrec["type"] = 'power' | |
| pinrec["Vmin"] = "3.6" | |
| pinrec["Vmax"] = "3.0" | |
| elif pin in knownground: | |
| pinrec["type"] = 'ground' | |
| pinrec["Vmin"] = "0" | |
| pinrec["Vmax"] = "0" | |
| elif pin in knownreal: | |
| pinrec["type"] = 'signal' | |
| pinrec["Vmin"] = "-0.5" | |
| pinrec["Vmax"] = "VDD + 0.3" | |
| else: | |
| pinrec["type"] = 'digital' | |
| pinrec["Vmin"] = "-0.5" | |
| pinrec["Vmax"] = "VDD + 0.3" | |
| pinrec["dir"] = "inout" | |
| pinlist.append(pinrec) | |
| return pinlist | |
| # Okay, we've got all the pins, now build the symbol. | |
| leftpins = len(inpins) + len(invecs) | |
| rightpins = len(outpins) + len(outvecs) | |
| # Arbitrarily, bidirectional pins are put on bottom and vectors on top. | |
| toppins = len(iovecs) | |
| botpins = len(iopins) | |
| height = 2 + max(leftpins, rightpins) * 10 | |
| width = 82 + max(toppins, botpins) * 10 | |
| # Enforce minimum height (minimum width enforced above) | |
| if height < 40: | |
| height = 40 | |
| # Run electric -v to get version string | |
| p = subprocess.run(['electric', '-v'], stdout = subprocess.PIPE) | |
| vstring = p.stdout.decode('utf-8').rstrip() | |
| # Get timestamp | |
| timestamp = str(int(datetime.datetime.now().strftime("%s")) * 1000) | |
| with open(destfile, 'w') as ofile: | |
| print('H' + project + '|' + vstring, file=ofile) | |
| print('', file=ofile) | |
| print('# Cell ' + project + ';1{ic}', file=ofile) | |
| print('C' + project + ';1{ic}||artwork|' + timestamp + '|' + timestamp + '|E', file=ofile) | |
| print('Ngeneric:Facet-Center|art@0||0|0||||AV', file=ofile) | |
| print('NBox|art@1||0|0|' + str(width) + '|' + str(height) + '||', file=ofile) | |
| pnum = 0 | |
| # Title | |
| print('Ngeneric:Invisible-Pin|pin@' + str(pnum) + '||0|5|||||ART_message(BD5G5;)S' + project, file=ofile) | |
| pnum += 1 | |
| # Fill in left side pins | |
| px = -(width / 2) | |
| py = -(height / 2) + 5 | |
| for pin in inpins: | |
| print('Nschematic:Wire_Pin|pin@' + str(pnum) + '||' + str(px - 10) + '|' + str(py) + '|1|1||', file=ofile) | |
| pnum += 1 | |
| print('NPin|pin@' + str(pnum) + '||' + str(px - 10) + '|' + str(py) + '|1|1||', file=ofile) | |
| pnum += 1 | |
| print('NPin|pin@' + str(pnum) + '||' + str(px) + '|' + str(py) + '|1|1||', file=ofile) | |
| pnum += 1 | |
| py += 10 | |
| for pin in invecs: | |
| print('Nschematic:Bus_Pin|pin@' + str(pnum) + '||' + str(px - 10) + '|' + str(py) + '|1|1||', file=ofile) | |
| pnum += 1 | |
| print('NPin|pin@' + str(pnum) + '||' + str(px - 10) + '|' + str(py) + '|1|1||', file=ofile) | |
| pnum += 1 | |
| print('NPin|pin@' + str(pnum) + '||' + str(px) + '|' + str(py) + '|1|1||', file=ofile) | |
| pnum += 1 | |
| py += 10 | |
| # Fill in right side pins | |
| px = (width / 2) | |
| py = -(height / 2) + 5 | |
| for pin in outpins: | |
| print('Nschematic:Wire_Pin|pin@' + str(pnum) + '||' + str(px + 10) + '|' + str(py) + '|1|1||', file=ofile) | |
| pnum += 1 | |
| print('NPin|pin@' + str(pnum) + '||' + str(px + 10) + '|' + str(py) + '|1|1||', file=ofile) | |
| pnum += 1 | |
| print('NPin|pin@' + str(pnum) + '||' + str(px) + '|' + str(py) + '|1|1||', file=ofile) | |
| pnum += 1 | |
| py += 10 | |
| for pin in outvecs: | |
| print('Nschematic:Bus_Pin|pin@' + str(pnum) + '||' + str(px + 10) + '|' + str(py) + '|1|1||', file=ofile) | |
| pnum += 1 | |
| print('NPin|pin@' + str(pnum) + '||' + str(px + 10) + '|' + str(py) + '|1|1||', file=ofile) | |
| pnum += 1 | |
| print('NPin|pin@' + str(pnum) + '||' + str(px) + '|' + str(py) + '|1|1||', file=ofile) | |
| pnum += 1 | |
| py += 10 | |
| # Fill in bottom side pins | |
| py = -(height / 2) | |
| px = -(width / 2) + 45 | |
| for pin in iopins: | |
| print('Nschematic:Wire_Pin|pin@' + str(pnum) + '||' + str(px) + '|' + str(py - 10) + '|1|1||', file=ofile) | |
| pnum += 1 | |
| print('NPin|pin@' + str(pnum) + '||' + str(px) + '|' + str(py) + '|1|1||', file=ofile) | |
| pnum += 1 | |
| print('NPin|pin@' + str(pnum) + '||' + str(px) + '|' + str(py - 10) + '|1|1||', file=ofile) | |
| pnum += 1 | |
| px += 10 | |
| # Fill in top side pins | |
| py = (height / 2) | |
| px = -(width / 2) + 45 | |
| for pin in iovecs: | |
| print('Nschematic:Bus_Pin|pin@' + str(pnum) + '||' + str(px) + '|' + str(py + 10) + '|1|1||', file=ofile) | |
| pnum += 1 | |
| print('NPin|pin@' + str(pnum) + '||' + str(px) + '|' + str(py) + '|1|1||', file=ofile) | |
| pnum += 1 | |
| print('NPin|pin@' + str(pnum) + '||' + str(px) + '|' + str(py + 10) + '|1|1||', file=ofile) | |
| pnum += 1 | |
| px += 10 | |
| # Start back at pin 1 and retain the same order when drawing wires | |
| pnum = 1 | |
| nnum = 0 | |
| px = -(width / 2) | |
| py = -(height / 2) + 5 | |
| for pin in inpins: | |
| pnum += 1 | |
| print('ASolid|net@' + str(nnum) + '|||FS0|pin@' + str(pnum) + '||' + str(px - 10) + '|' + str(py) + '|pin@' + str(pnum + 1) + '||' + str(px) + '|' + str(py), file=ofile) | |
| pnum += 2 | |
| nnum += 1 | |
| py += 10 | |
| for pin in invecs: | |
| pnum += 1 | |
| print('ASolid|net@' + str(nnum) + '|||FS0|pin@' + str(pnum) + '||' + str(px - 10) + '|' + str(py) + '|pin@' + str(pnum + 1) + '||' + str(px) + '|' + str(py), file=ofile) | |
| pnum += 2 | |
| nnum += 1 | |
| py += 10 | |
| px = (width / 2) | |
| py = -(height / 2) + 5 | |
| for pin in outpins: | |
| pnum += 1 | |
| print('ASolid|net@' + str(nnum) + '|||FS0|pin@' + str(pnum) + '||' + str(px + 10) + '|' + str(py) + '|pin@' + str(pnum + 1) + '||' + str(px) + '|' + str(py), file=ofile) | |
| pnum += 2 | |
| nnum += 1 | |
| py += 10 | |
| for pin in outvecs: | |
| pnum += 1 | |
| print('ASolid|net@' + str(nnum) + '|||FS0|pin@' + str(pnum) + '||' + str(px + 10) + '|' + str(py) + '|pin@' + str(pnum + 1) + '||' + str(px) + '|' + str(py), file=ofile) | |
| pnum += 2 | |
| nnum += 1 | |
| py += 10 | |
| py = -(height / 2) | |
| px = -(width / 2) + 45 | |
| for pin in iopins: | |
| pnum += 1 | |
| print('ASolid|net@' + str(nnum) + '|||FS0|pin@' + str(pnum) + '||' + str(px) + '|' + str(py) + '|pin@' + str(pnum + 1) + '||' + str(px) + '|' + str(py - 10), file=ofile) | |
| pnum += 2 | |
| nnum += 1 | |
| px += 10 | |
| py = (height / 2) | |
| px = -(width / 2) + 45 | |
| for pin in iovecs: | |
| pnum += 1 | |
| print('ASolid|net@' + str(nnum) + '|||FS0|pin@' + str(pnum) + '||' + str(px) + '|' + str(py) + '|pin@' + str(pnum + 1) + '||' + str(px) + '|' + str(py + 10), file=ofile) | |
| pnum += 2 | |
| nnum += 1 | |
| px += 10 | |
| # Add the exports (which are the only nontrivial elements) | |
| pnum = 1 | |
| for pin in inpins: | |
| print('E' + pin + '||D6G4;X12.0;Y0.0;|pin@' + str(pnum) + '||I', file=ofile) | |
| pnum += 3 | |
| for pin in invecs: | |
| print('E' + pin + '||D6G4;X12.0;Y0.0;|pin@' + str(pnum) + '||I', file=ofile) | |
| pnum += 3 | |
| for pin in outpins: | |
| print('E' + pin + '||D4G4;X-12.0;Y0.0;|pin@' + str(pnum) + '||O', file=ofile) | |
| pnum += 3 | |
| for pin in outvecs: | |
| print('E' + pin + '||D4G4;X-12.0;Y0.0;|pin@' + str(pnum) + '||O', file=ofile) | |
| pnum += 3 | |
| for pin in iopins: | |
| print('E' + pin + '||D6G4;RX0.0;Y12.0;|pin@' + str(pnum) + '||B', file=ofile) | |
| pnum += 3 | |
| for pin in iovecs: | |
| print('E' + pin + '||D6G4;RRRX0.0;Y-12.0;|pin@' + str(pnum) + '||B', file=ofile) | |
| pnum += 3 | |
| # X marks the spot, or at least the end. | |
| print('X', file=ofile) | |
| if not os.path.isfile(desthdr): | |
| with open(desthdr, 'w') as ofile: | |
| print('# header information:', file=ofile) | |
| print('H' + project + '|' + vstring, file=ofile) | |
| print('', file=ofile) | |
| print('# Views:', file=ofile) | |
| print('Vicon|ic', file=ofile) | |
| print('', file=ofile) | |
| print('# Tools:', file=ofile) | |
| print('Ouser|DefaultTechnology()Sschematic', file=ofile) | |
| print('Osimulation|VerilogUseAssign()BT', file=ofile) | |
| print('C____SEARCH_FOR_CELL_FILES____', file=ofile) | |
| return 0 | |
| def usage(): | |
| print("make_icon_from_soft.py <project_path> [<verilog_source>] [<output_file>]") | |
| print("") | |
| print(" where <project_path> is the path to a standard efabless project, and") | |
| print(" <verilog_source> is the path to a verilog source file.") | |
| print("") | |
| print(" The module name must be the same as the project's ip-name.") | |
| print("") | |
| print(" <verilog_source> is assumed to be in verilog/source/<ip-name>.v by") | |
| print(" default if not otherwise specified.") | |
| print("") | |
| print(" If <output_file> is not specified, output goes in the project's") | |
| print(" electric library.") | |
| print("") | |
| if __name__ == '__main__': | |
| arguments = [] | |
| options = [] | |
| for item in sys.argv[1:]: | |
| if item[0] == '-': | |
| options.append(item.strip('-')) | |
| else: | |
| arguments.append(item) | |
| debug = True if 'debug' in options else False | |
| numarg = len(arguments) | |
| if numarg > 3 or numarg == 0: | |
| usage() | |
| sys.exit(0) | |
| projectpath = arguments[0] | |
| projdirname = os.path.split(projectpath)[1] | |
| jsonfile = projectpath + '/project.json' | |
| if not os.path.isfile(jsonfile): | |
| # Legacy behavior is to have the JSON file name the same as the directory name. | |
| jsonfile = projectpath + '/' + projdirname + '.json' | |
| if not os.path.isfile(jsonfile): | |
| print('Error: No project JSON file found for project ' + projdirname) | |
| sys.exit(1) | |
| project = None | |
| with open(jsonfile, 'r') as ifile: | |
| datatop = json.load(ifile) | |
| dsheet = datatop['data-sheet'] | |
| project = dsheet['ip-name'] | |
| if not project: | |
| print('Error: No project IP name in project JSON file.') | |
| sys.exit(1) | |
| if numarg > 1: | |
| verilogfile = arguments[1] | |
| else: | |
| verilogfile = projectpath + '/verilog/source/' + project + '.v' | |
| if not os.path.exists(verilogfile): | |
| print('Error: No verilog file ' + verilogfile + ' found.') | |
| print('Please specify full path as 2nd argument.') | |
| sys.exit(1) | |
| if numarg > 2: | |
| destfile = arguments[2] | |
| else: | |
| destfile = projectpath + '/elec/' + project + '.delib/' + project + '.ic' | |
| if os.path.exists(destfile): | |
| print('Error: Icon file ' + destfile + ' already exists.') | |
| print('Please delete any unwanted original before running this script.') | |
| sys.exit(1) | |
| result = create_symbol(projectpath, verilogfile, project, destfile, debug) | |
| sys.exit(result) |