| # Copyright 2020 Efabless Corporation |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| import json |
| import argparse |
| import copy |
| import re |
| import os |
| from pyverilog.vparser.parser import parse |
| |
| # import StringIO |
| try: |
| from StringIO import StringIO |
| except ImportError: |
| from io import StringIO |
| parser = argparse.ArgumentParser( |
| description="top module generation for a given (core design, pads library) pair" |
| ) |
| |
| |
| parser.add_argument( |
| "--design", |
| "-d", |
| action="store", |
| required=True, |
| help="The json description of the design", |
| ) |
| |
| parser.add_argument( |
| "--padsLibs", |
| "-p", |
| action="store", |
| required=True, |
| help="The pad libraries json description", |
| ) |
| |
| parser.add_argument( |
| "--verilog", |
| "-v", |
| action="store", |
| required=True, |
| help="The input verilog file containing the core module header definition", |
| ) |
| |
| parser.add_argument( |
| "--output", |
| "-o", |
| action="store", |
| required=True, |
| help="The verilog file to output to", |
| ) |
| |
| |
| args = parser.parse_args() |
| design = args.design |
| padsLibs = args.padsLibs |
| output = args.output |
| verilog_file = args.verilog |
| |
| # description of the design parsed into a dict |
| if not os.path.exists(design): |
| raise IOError("file not found: " + design) |
| designJSONOpener = open(design, "r") |
| design_json_complete = json.load(designJSONOpener) |
| designJSONOpener.close() |
| |
| |
| # description of the libraries parsed into a dict |
| if not os.path.exists(padsLibs): |
| raise IOError("file not found: " + padsLibs) |
| padsLibsJSONOpener = open(padsLibs, "r") |
| padsLibs_json = json.load(padsLibsJSONOpener) |
| padsLibsJSONOpener.close() |
| |
| # Finding the used pads library |
| padsLib_json = dict() |
| for padsLib in padsLibs_json: |
| if padsLib["library_name"] == design_json_complete["pads_library"]: |
| padsLib_json = padsLib |
| break |
| |
| if len(padsLib_json) == 0: |
| raise Exception("Used Pad Lib is not found in the given Pad Libraries JSON") |
| |
| # extracting the core module needed pads |
| design_json = design_json_complete["module"] |
| |
| # Necessary intermediate containers |
| written_macros = list() |
| wiresToDeclare = dict() |
| headerSignalsToDeclare = dict() |
| |
| # Segments of the final written verilog code |
| topModuleHeader = "module " + design_json_complete["design_name"] + "(\n" |
| topModuleDeclarations = "" |
| topModuleDefines = ( |
| "`timescale 1 ns / 1 ps\n\n`define USE_PG_PIN\n`define functional\n\n" |
| ) |
| topModuleIncludes = "" |
| topModuleBody = "" |
| topModuleMacros = "" |
| designDeclaration = "" |
| topModuleExtra = "" |
| padFrameModule = "" |
| padFrameHeader = "chip_io padframe(\n" |
| padFrameHeaderDefinition = "module chip_io(\n" |
| padFrameWires = "" |
| # parsePads is responsible for parsing the pads except for power/corner pads |
| def parsePads(): |
| global topModuleHeader |
| for user_pad in design_json["pads"]: |
| # find pad direction |
| padType = user_pad["type"] |
| |
| padUsed = dict() |
| |
| # extract pad |
| for library_pad in padsLib["pads"]: |
| if library_pad["type"] == padType: |
| padUsed = library_pad |
| break |
| if len(padUsed) == 0: |
| raise Exception("Used Pad is not of a defined type") |
| writePad(padUsed, user_pad) |
| topModuleHeader = topModuleHeader[:-2] + ");\n" |
| |
| |
| # writePad is responsible for adding a non-power/non-corner pad to the output verilog |
| def writePad(padUsed, user_info): |
| global topModuleHeader |
| global padFrameModule |
| global padFrameHeaderDefinition |
| global padFrameHeader |
| |
| v = user_info["size"] > 1 |
| macro_name = "" |
| if v: |
| macro_name += padUsed["type"] + "_V" |
| else: |
| macro_name += padUsed["type"] |
| writePadMacro(padUsed, v, macro_name) |
| instType = resolveInterfaceType(user_info["type"]) |
| instSize = resolveSize(user_info["size"]) |
| topModuleHeader += instType + " " |
| topModuleHeader += instSize + " " |
| topModuleHeader += user_info["name"] + ",\n" |
| |
| if instType == "input": |
| instType = "inout" |
| padFrameHeaderDefinition += instType + " " |
| padFrameHeaderDefinition += instSize + " " |
| padFrameHeaderDefinition += user_info["name"] + ",\n" |
| |
| padFrameHeader += "." + user_info["name"] + "(" + user_info["name"] + "),\n" |
| |
| inst_body = "`" + macro_name + " (" |
| if v: |
| inst_body += str(user_info["size"]) + "," |
| |
| for key in padUsed["mapping"].keys(): |
| res = None |
| |
| if key == "name": |
| res = [user_info] |
| elif key in user_info.keys(): |
| res = user_info[key] |
| else: |
| for port in padUsed["ports"]: |
| if "condition" in port.keys(): |
| continue |
| if port["name"] == padUsed["mapping"][key]: |
| res = port["connection"] |
| break |
| if res is not None: |
| if isinstance(res, dict) and "name" not in res.keys(): |
| wire_name = padUsed["type"] + "_" + user_info["name"] + "_" + key |
| createDictWireForPads(wire_name, res, user_info["size"]) |
| inst_body += wire_name + "," |
| elif len(res) > 1 and key != "name": |
| wire_name = padUsed["type"] + "_" + user_info["name"] + "_" + key |
| createWireForPads(wire_name, res) |
| inst_body += wire_name + "," |
| else: |
| if isinstance(res[0], dict): |
| inst_body += res[0]["name"] + " " |
| if "size" in res[0].keys() and key != "name": |
| inst_body += resolveSize(res[0]["size"]) |
| else: |
| inst_body += res[0] + " " |
| inst_body += "," |
| else: |
| inst_body += " , " |
| inst_body = inst_body[:-1] + ");\n" |
| |
| padFrameModule += inst_body |
| |
| |
| # createDictWireForPads creates the wire for a pad macro parameter if it has a complex object description. The description is parsed into an assign to that wire. i.e. "mode":{"bit_0":{}, "bit_1":{}, "bit_2":{}} |
| def createDictWireForPads(wire_name, wire_info, size): |
| global padFrameWires |
| wire_body = ( |
| "wire [" |
| + str(size * len(wire_info.keys()) - 1) |
| + ":0] " |
| + wire_name |
| + " = {\n\t\t" |
| ) |
| for i in reversed(range(size)): |
| for key in wire_info.keys(): |
| wire_body += wire_info[key] + "[" + str(i) + "]," |
| wire_body += "\n\t\t" |
| wire_body = wire_body[:-4] + "};\n" |
| padFrameWires += wire_body |
| |
| |
| # createWireForPads creates the wire for a pad macro parameter if it has a list description. |
| def createWireForPads(wire_name, wire_info): |
| global padFrameWires |
| wire_body = ( |
| "wire [" + str(getConcatSize(wire_info) - 1) + ":0] " + wire_name + " = {" |
| ) |
| for con in wire_info: |
| if isinstance(con, dict): |
| wire_body += con["name"] + " " |
| if "size" in con.keys(): |
| wire_body += resolveSize(con["size"]) |
| else: |
| wire_body += con + " " |
| wire_body += ", " |
| wire_body = wire_body[:-2] + "};\n" |
| padFrameWires += wire_body |
| |
| |
| # getConcatSize gets the total size of a concatenation |
| def getConcatSize(concatentation): |
| tot_size = 0 |
| |
| for signal in concatentation: |
| if isinstance(signal, dict): |
| if "size" in signal.keys(): |
| if isinstance(signal["size"], int): |
| tot_size += signal["size"] |
| else: |
| tot_size += signal["size"]["offset"] |
| else: |
| tot_size += 1 |
| else: |
| tot_size += 1 |
| return tot_size |
| |
| |
| # writePadMacro is responsible for writing the macro definition of the pads except for power/corner pads |
| def writePadMacro(pad_macro, v, macro_name): |
| if macro_name in written_macros: |
| return |
| pad_macro_copy = copy.deepcopy(pad_macro) |
| written_macros.append(macro_name) |
| global topModuleMacros |
| macro_body = "" |
| if v: |
| macro_body += "`define " + macro_name + "(V," |
| else: |
| macro_body += "`define " + macro_name + "(" |
| |
| for key in pad_macro_copy["mapping"].keys(): |
| macro_body += key.upper() + "," |
| |
| pad_macro_copy["ports"] = resolvePortMapping( |
| pad_macro_copy["mapping"], pad_macro_copy["ports"] |
| ) |
| macro_body = macro_body[:-1] + ") \\\n" |
| |
| for wire in pad_macro_copy["wire_declaration_info"]: |
| macro_body += "wire " |
| if v: |
| macro_body += "[V-1:0] " |
| macro_body += resolveConnectionName(wire["name"]) + "; \\\n" |
| |
| macro_body += pad_macro_copy["pad_name"] + " NAME``_pad " |
| if v: |
| macro_body += "[V-1:0] ( \\\n" |
| else: |
| macro_body += "( \\\n" |
| |
| if "defines" in pad_macro_copy.keys(): |
| macro_body += addPadDefines(pad_macro_copy["defines"], True) |
| |
| for port in pad_macro_copy["ports"]: |
| if "condition" in port.keys(): |
| hasElse = False |
| if "def" in port["condition"].keys(): |
| portd = port["condition"]["def"] |
| macro_body += "`ifdef " + port["condition"]["name"] + " \\\n" |
| macro_body += "\t." + portd["name"] + "( " |
| if portd["connection"] is not None: |
| if len(portd["connection"]) > 1: |
| macro_body += "{" |
| for connection in portd["connection"]: |
| macro_body += resolveConnectionName(connection) + "," |
| macro_body = macro_body[:-1] + "}," |
| else: |
| macro_body += ( |
| resolveConnectionName(portd["connection"][0]) + "," |
| ) |
| macro_body = macro_body[:-1] + "), \\\n" |
| hasElse = True |
| if "ndef" in port["condition"].keys(): |
| portd = port["condition"]["ndef"] |
| if hasElse: |
| macro_body += "`else \\\n" |
| else: |
| macro_body += "`ifndef " + port["condition"]["name"] + " \\\n" |
| macro_body += "\t." + portd["name"] + "( " |
| if portd["connection"] is not None: |
| if len(portd["connection"]) > 1: |
| macro_body += "{" |
| for connection in portd["connection"]: |
| macro_body += resolveConnectionName(connection) + "," |
| macro_body = macro_body[:-1] + "}," |
| else: |
| macro_body += ( |
| resolveConnectionName(portd["connection"][0]) + "," |
| ) |
| macro_body = macro_body[:-1] + "), \\\n" |
| macro_body += "`endif \\\n" |
| |
| else: |
| macro_body += "." + port["name"] + "( " |
| if port["connection"] is not None: |
| if len(port["connection"]) > 1: |
| macro_body += "{" |
| for connection in port["connection"]: |
| macro_body += resolveConnectionName(connection) + "," |
| macro_body = macro_body[:-1] + "}," |
| else: |
| macro_body += resolveConnectionName(port["connection"][0]) + "," |
| macro_body = macro_body[:-1] + "), \\\n" |
| |
| macro_body = macro_body[:-4] + ")\n\n" |
| |
| topModuleMacros += macro_body |
| |
| |
| # resolveConnectionName to replace any references to $name with the proper ``NAME or NAME`` |
| def resolveConnectionName(connection): |
| if connection.find("$name") == 0: |
| return connection.replace("$name", "NAME``") |
| else: |
| return connection.replace("$name", "``NAME") |
| |
| |
| # resolvePortMapping to resolve the value of defined port with the user defined value or retrieve it from the the default values defined in the PADs library |
| def resolvePortMapping(mapping, ports): |
| for key in mapping.keys(): |
| for portIdx in range(len(ports)): |
| port = ports[portIdx] |
| if "condition" in port.keys(): |
| if "def" in port["condition"].keys(): |
| if port["condition"]["def"]["name"] == mapping[key]: |
| port["condition"]["def"]["connection"] = [key.upper()] |
| |
| if "ndef" in port["condition"].keys(): |
| if port["condition"]["ndef"]["name"] == mapping[key]: |
| port["condition"]["ndef"]["connection"] = [key.upper()] |
| elif port["name"] == mapping[key]: |
| port["connection"] = [key.upper()] |
| ports[portIdx] = port |
| return ports |
| |
| |
| # resolveSize to resolve the size whether its defined as 1, [size-1:0], or [offset-start+1:start] |
| def resolveSize(size): |
| if isinstance(size, int): |
| if int(size) > 1: |
| return "[" + str(size - 1) + ":0] " |
| else: |
| return "" |
| else: |
| return ( |
| "[" |
| + str(size["offset"] + size["start"] - 1) |
| + ":" |
| + str(size["start"]) |
| + "] " |
| ) |
| |
| |
| # resolveInterfaceType to resolve type of interface to input, output, or inout |
| def resolveInterfaceType(padType): |
| if padType in ["DIGITAL_INPUT", "ANALOG_INPUT", "DIGITAL_INPUT_TV2", "XRES"]: |
| return "input" |
| if padType in ["DIGITAL_OUTPUT", "ANALOG_OUTPUT", "DIGITAL_OUTPUT_TV2"]: |
| return "output" |
| if padType in ["DIGITAL_INOUT", "ANALOG_INOUT"]: |
| return "inout" |
| |
| raise Exception("Used Pad is not of a defined type") |
| |
| |
| # parsePowerCornerPads is responsible for parsing the power/corner pads |
| def parsePowerCornerPads(): |
| # Handle Case of user give power/corner pads |
| for pad in padsLib["pads"]: |
| if "count" in pad.keys(): |
| global padFrameModule |
| if "powerCornerPads" in design_json_complete.keys(): |
| for new_pad in design_json_complete["powerCornerPads"]: |
| if pad["type"] == new_pad["type"]: |
| if "count" in new_pad.keys(): |
| pad["count"] = new_pad["count"] |
| |
| if "ports" in new_pad.keys(): |
| for p_new in new_pad["ports"]: |
| for p_default_idx in range(len(pad["ports"])): |
| if ( |
| p_new["name"] |
| == pad["ports"][p_default_idx]["name"] |
| ): |
| pad["ports"][p_default_idx] = p_new |
| break |
| break |
| if "condition" in pad.keys(): |
| if pad["condition"]["def"]: |
| padFrameModule += "`ifdef " + pad["condition"]["name"] + "\n" |
| else: |
| padFrameModule += "`ifndef " + pad["condition"]["name"] + "\n" |
| padFrameModule += writePowerCornerPad(pad) |
| padFrameModule += "`endif\n" |
| else: |
| padFrameModule += writePowerCornerPad(pad) + "\n" |
| |
| |
| # writePowerCornerPad is responsible for adding a power/corner pad to the output verilog |
| def writePowerCornerPad(padUsed): |
| padBody = str(padUsed["pad_name"]) + " " + str(padUsed["type"]) |
| if int(padUsed["count"]) > 1: |
| padBody += " [" + str(int(padUsed["count"]) - 1) + ":0] (\n" |
| else: |
| padBody += " (\n" |
| |
| if "defines" in padUsed.keys(): |
| padBody += addPadDefines(padUsed["defines"], False) |
| |
| ports = padUsed["ports"] |
| |
| # add wires to the declaration plan |
| if "wire_declaration_info" in padUsed.keys(): |
| if padUsed["wire_declaration_info"] is not None: |
| for wire in padUsed["wire_declaration_info"]: |
| wiresToDeclare[wire["name"]] = wire |
| |
| # add header signals to the declaration plan |
| if "interface_declaration_info" in padUsed.keys(): |
| if padUsed["interface_declaration_info"] is not None: |
| for signal in padUsed["interface_declaration_info"]: |
| headerSignalsToDeclare[signal["name"]] = signal |
| |
| for port in ports: |
| if "condition" in port.keys(): |
| hasElse = False |
| if "def" in port["condition"].keys(): |
| portd = port["condition"]["def"] |
| padBody += "`ifdef " + port["condition"]["name"] + " \n" |
| padBody += "\t." + portd["name"] + "( " |
| if portd["connection"] is not None: |
| if len(portd["connection"]) > 1: |
| padBody += "{" |
| for con in portd["connection"]: |
| padBody += con + ", " |
| padBody = padBody[:-2] + "}," |
| else: |
| padBody += portd["connection"][0] + "," |
| |
| padBody = padBody[:-1] + "),\n" |
| hasElse = True |
| if "ndef" in port["condition"].keys(): |
| portd = port["condition"]["ndef"] |
| if hasElse: |
| padBody += "`else \n" |
| else: |
| padBody += "`ifndef " + port["condition"]["name"] + " \n" |
| padBody += "\t." + portd["name"] + "( " |
| if portd["connection"] is not None: |
| padBody += "{" |
| if len(portd["connection"]) > 1: |
| for con in portd["connection"]: |
| padBody += con + ", " |
| padBody = padBody[:-2] + "}," |
| else: |
| padBody += portd["connection"][0] + "," |
| padBody = padBody[:-1] + "),\n" |
| padBody += "`endif \n" |
| else: |
| padBody += "." + port["name"] + "( " |
| if port["connection"] is not None: |
| if len(port["connection"]) > 1: |
| padBody += "{" |
| for con in port["connection"]: |
| padBody += con + ", " |
| padBody = padBody[:-2] + "}," |
| else: |
| padBody += port["connection"][0] + "," |
| padBody = padBody[:-1] + "),\n" |
| |
| padBody = padBody[:-2] + ");\n" |
| return padBody |
| |
| |
| # addPadDefines adds the defines inside the pads i.e. `ABUTMENT_PINS |
| def addPadDefines(defines, isMacro): |
| ret = "" |
| for define in defines: |
| if "condition" in define.keys(): |
| hasElse = False |
| if "def" in define["condition"]: |
| hasElse = True |
| ret += "`ifdef " + define["condition"]["name"] |
| if isMacro: |
| ret += " \\\n" |
| else: |
| ret += " \n" |
| for single_define in define["condition"]["def"]: |
| ret += "`" + single_define["name"] |
| if isMacro: |
| ret += " \\\n" |
| else: |
| ret += " \n" |
| |
| if "ndef" in define["condition"]: |
| if hasElse: |
| ret += "`else" |
| if isMacro: |
| ret += " \\\n" |
| else: |
| ret += " \n" |
| else: |
| ret += "`ifndef " + define["condition"]["name"] |
| if isMacro: |
| ret += " \\\n" |
| else: |
| ret += " \n" |
| for single_define in define["condition"]["ndef"]: |
| ret += "`" + single_define["name"] |
| if isMacro: |
| ret += " \\\n" |
| else: |
| ret += " \n" |
| ret += "`endif" |
| if isMacro: |
| ret += " \\\n" |
| else: |
| ret += " \n" |
| else: |
| ret += "`" + define["name"] |
| if isMacro: |
| ret += " \\\n" |
| else: |
| ret += " \n" |
| return ret |
| |
| |
| # parseMacros parses user defines or pad library defines |
| def parseMacros(defines): |
| global topModuleDefines |
| for define in defines: |
| # add wires to the declaration plan |
| if "wire_declaration_info" in define.keys(): |
| if define["wire_declaration_info"] is not None: |
| for wire in define["wire_declaration_info"]: |
| wiresToDeclare[wire["name"]] = wire |
| |
| # add header signals to the declaration plan |
| if "interface_declaration_info" in define.keys(): |
| if define["interface_declaration_info"] is not None: |
| for signal in define["interface_declaration_info"]: |
| headerSignalsToDeclare[signal["name"]] = signal |
| |
| topModuleDefines += writeMacro(define)[:-2] + "\n\n" |
| |
| |
| # writeMacro writes the macro to the final verilog output |
| def writeMacro(define): |
| macro_body = "" |
| if "condition" in define.keys(): |
| hasElse = False |
| if "def" in define["condition"]: |
| hasElse = True |
| macro_body += "`ifdef " + define["condition"]["name"] + " \n" |
| macro_body += writeMacro(define["condition"]["def"]) |
| |
| if "ndef" in define["condition"]: |
| if hasElse: |
| macro_body = macro_body[:-2] + "\n`else \n" |
| else: |
| macro_body += "`ifndef " + define["condition"]["name"] + " \n" |
| macro_body += writeMacro(define["condition"]["ndef"]) |
| macro_body = macro_body[:-2] + "\n`endif \n" |
| else: |
| macro_body += "`define " + define["name"] + " \\\n" |
| if "ports" in define.keys(): |
| for port in define["ports"]: |
| if "condition" in port.keys(): |
| hasElse = False |
| if "def" in port["condition"]: |
| hasElse = True |
| portd = port["condition"]["def"] |
| macro_body += "`ifdef " + port["condition"]["name"] + " \\\n" |
| macro_body += "\t." + portd["name"] + "( " |
| if portd["connection"] is not None: |
| if len(portd["connection"]) > 1: |
| macro_body += "{" |
| for con in portd["connection"]: |
| macro_body += con + ", " |
| macro_body = macro_body[:-2] + "}," |
| else: |
| macro_body += portd["connection"][0] + "," |
| macro_body = macro_body[:-1] + "), \\\n" |
| if "ndef" in define["condition"]: |
| portd = port["condition"]["ndef"] |
| if hasElse: |
| macro_body += "`else \\\n" |
| else: |
| macro_body += ( |
| "`ifndef " + define["condition"]["name"] + " \\\n" |
| ) |
| macro_body += "\t." + portd["name"] + "( " |
| if portd["connection"] is not None: |
| if len(portd["connection"]) > 1: |
| macro_body += "{" |
| for con in portd["connection"]: |
| macro_body += con + ", " |
| macro_body = macro_body[:-2] + "}," |
| else: |
| macro_body += portd["connection"][0] + "," |
| macro_body = macro_body[:-1] + "), \\\n" |
| macro_body += "`endif \\\n" |
| else: |
| macro_body += "\t." + port["name"] + "( " |
| if port["connection"] is not None: |
| if len(port["connection"]) > 1: |
| macro_body += "{" |
| for con in port["connection"]: |
| macro_body += con + ", " |
| macro_body = macro_body[:-2] + "}," |
| else: |
| macro_body += port["connection"][0] + "," |
| macro_body = macro_body[:-1] + "), \\\n" |
| return macro_body |
| |
| |
| # addTopModuleWires writes the wires required by the pads/user in the top module |
| def addPadFrameWires(): |
| global padFrameWires |
| for wire in wiresToDeclare: |
| if wire in headerSignalsToDeclare: |
| continue |
| else: |
| decl = "\nwire " |
| if "size" in wiresToDeclare[wire]: |
| decl += resolveSize(wiresToDeclare[wire]["size"]) |
| decl += wire + ";" |
| padFrameWires += decl |
| |
| |
| # Add the module interface required by the pads: i.e. vss, vdd1v8, vdd |
| def addTopModulePadsInterface(): |
| global topModuleHeader |
| global padFrameHeaderDefinition |
| global padFrameHeader |
| |
| if len(headerSignalsToDeclare): |
| topModuleHeader = topModuleHeader[:-3] + ",\n" |
| for signal in headerSignalsToDeclare: |
| decl = resolveInterfaceType(headerSignalsToDeclare[signal]["type"]) + " " |
| if "size" in headerSignalsToDeclare[signal]: |
| decl += resolveSize(headerSignalsToDeclare[signal]["size"]) + " " |
| decl += signal + ",\n" |
| topModuleHeader += decl |
| padFrameHeaderDefinition += decl |
| padFrameHeader += "." + signal + "(" + signal + "),\n" |
| topModuleHeader = topModuleHeader[:-2] + ");\n" |
| padFrameHeaderDefinition = padFrameHeaderDefinition[:-2] + ");\n" |
| padFrameHeader = padFrameHeader[:-2] + ");\n" |
| |
| |
| # parseDesignHeader parses the verilog module header of the core module and creates its wires and connections |
| def parseDesignHeader(verilog_file): |
| global padFrameHeaderDefinition |
| global padFrameHeader |
| global topModuleDeclarations |
| global topModuleBody |
| module_header = design_json["name"] + " core_inst(\n" |
| wiresDeclarations = "" |
| ast, x = parse([verilog_file]) |
| # output = StringIO() |
| out = StringIO() |
| ast.show(buf=out) |
| rlst = out.getvalue() |
| # print(rlst) |
| startString = "ModuleDef: " + design_json["name"] |
| startPoint = rlst.find(startString) |
| startPoint = rlst.find("Portlist:", startPoint) |
| declIdx = rlst.find("Decl:", startPoint) |
| instanceListIdx = rlst.find("InstanceList:", startPoint) |
| moduleDefIdx = rlst.find("ModuleDef:", startPoint) |
| if declIdx == -1: |
| declIdx = 0x0FFFFFFF |
| if instanceListIdx == -1: |
| instanceListIdx = 0x0FFFFFFF |
| if moduleDefIdx == -1: |
| moduleDefIdx = 0x0FFFFFFF |
| endIdx = min(declIdx, instanceListIdx, moduleDefIdx) |
| if endIdx != 0x0FFFFFFF: |
| rlst = rlst[:endIdx] |
| portList = rlst[startPoint:].split("Ioport:") |
| # print(portList) |
| # print(portList) |
| for port in portList[1:]: |
| port_split = port.split("\n") |
| for idx in range(len(port_split)): |
| line = port_split[idx] |
| if line.find("Input") != -1: |
| signalName = getSignalName(line) |
| signalSize = extractSizeFromVerilog(port_split, idx) |
| module_header += "." + signalName + "(" + signalName + "),\n" |
| wiresDeclarations += "wire " + signalSize + " " + signalName + ";\n" |
| padFrameHeader += "." + signalName + "(" + signalName + "),\n" |
| padFrameHeaderDefinition += ( |
| "output " + signalSize + " " + signalName + ",\n" |
| ) |
| break |
| elif line.find("Output") != -1: |
| signalName = getSignalName(line) |
| signalSize = extractSizeFromVerilog(port_split, idx) |
| module_header += "." + signalName + "(" + signalName + "),\n" |
| wiresDeclarations += "wire " + signalSize + " " + signalName + ";\n" |
| padFrameHeader += "." + signalName + "(" + signalName + "),\n" |
| padFrameHeaderDefinition += ( |
| "input " + signalSize + " " + signalName + ",\n" |
| ) |
| break |
| elif line.find("Inout") != -1: |
| signalName = getSignalName(line).strip() |
| signalSize = extractSizeFromVerilog(port_split, idx) |
| module_header += "." + signalName + "(" + signalName + "),\n" |
| wiresDeclarations += "wire " + signalSize + " " + signalName + ";\n" |
| padFrameHeader += "." + signalName + "(" + signalName + "),\n" |
| padFrameHeaderDefinition += ( |
| "inout " + signalSize + " " + signalName + ",\n" |
| ) |
| break |
| module_header = module_header[:-2] + ");\n" |
| topModuleDeclarations += wiresDeclarations |
| topModuleBody += module_header |
| |
| |
| def getSignalName(line): |
| pattern = re.compile(r"\s*?[\S+]+\,") |
| for signal in re.findall(pattern, line): |
| return signal[1:-1] |
| |
| |
| def extractSizeFromVerilog(port_split, start_idx): |
| size = "" |
| end_idx = min(start_idx + 3, len(port_split)) |
| for idx in range(start_idx, end_idx): |
| line = port_split[idx] |
| if line.find("Width") != -1: |
| pattern = re.compile(r"\s*?\d+\s") |
| size += "[" |
| for s in re.findall(pattern, port_split[idx + 1]): |
| size += s + ":" |
| break |
| for s in re.findall(pattern, port_split[idx + 2]): |
| size += s + "]" |
| break |
| return size |
| |
| |
| # parseIncludes parses the includes of a given json |
| def parseIncludes(includes): |
| global topModuleIncludes |
| for include in includes: |
| topModuleIncludes += writeInclude(include) + "\n\n" |
| |
| |
| # writeInclude writes the includes into the final verilog output |
| def writeInclude(include): |
| include_body = "" |
| if isinstance(include, dict) and "condition" in include.keys(): |
| hasElse = False |
| if "def" in include["condition"]: |
| hasElse = True |
| include_body += "`ifdef " + include["condition"]["name"] + " \n" |
| if isinstance(include["condition"]["def"], list): |
| for i in include["condition"]["def"]: |
| include_body += writeInclude(i) |
| else: |
| include_body += writeInclude(include["condition"]["def"]) |
| |
| if "ndef" in include["condition"]: |
| if hasElse: |
| include_body = include_body + "`else \n" |
| else: |
| include_body += "`ifndef " + include["condition"]["name"] + " \n" |
| include_body += writeInclude(include["condition"]["ndef"]) |
| if isinstance(include["condition"]["ndef"], list): |
| for i in include["condition"]["ndef"]: |
| include_body += writeInclude(i) |
| else: |
| include_body += writeInclude(include["condition"]["ndef"]) |
| include_body = include_body + "`endif \n" |
| else: |
| include_body += '\t`include "' + include["name"] + '"\n' |
| return include_body |
| |
| |
| # If defines/macros section exists in the descriptions, write those defines |
| if "defines" in padsLib.keys() and len(padsLib["defines"]): |
| topModuleDefines += "\n//PADs Library defines/macros\n" |
| parseMacros(padsLib["defines"]) |
| if "defines" in design_json_complete.keys() and len(design_json_complete["defines"]): |
| topModuleDefines += "\n//User defines/macros\n" |
| parseMacros(design_json_complete["defines"]) |
| |
| # If the includes section exists in the description, write those includes |
| if "includes" in padsLib_json.keys() and len(padsLib_json["includes"]): |
| topModuleIncludes += "\n//PADs Library includes\n" |
| parseIncludes(padsLib_json["includes"]) |
| if "includes" in design_json_complete.keys() and len(design_json_complete["includes"]): |
| topModuleIncludes += "\n//User includes\n" |
| parseIncludes(design_json_complete["includes"]) |
| |
| # Parse the pads |
| padFrameModule += "\n//Input/Output PADs\n" |
| parsePads() |
| padFrameModule += "\n//Power/Corner PADs\n" |
| parsePowerCornerPads() |
| |
| |
| # if section extra_verilog exists, write append the extra_verilog to the module |
| if "extra_verilog" in design_json_complete.keys(): |
| if isinstance(design_json_complete["extra_verilog"], list): |
| for ex in design_json_complete["extra_verilog"]: |
| topModuleExtra += ex + "\n" |
| else: |
| topModuleExtra = design_json_complete["extra_verilog"] |
| |
| # Read the user verilog file and parse the top module header |
| if not os.path.exists(verilog_file): |
| raise IOError("file not found: " + verilog_file) |
| """verilogFileOpener = open(verilog_file, 'r') |
| verilogFileData = verilogFileOpener.read() |
| verilogFileOpener.close()""" |
| topModuleBody += "\n\n//Core Module Instantiation\n" |
| parseDesignHeader(verilog_file) |
| |
| |
| # add the module interface |
| addTopModulePadsInterface() |
| |
| # add the used wires |
| addPadFrameWires() |
| |
| |
| # write endmodule |
| topModuleBody += "\n\n//PadFrame Instantiation\n" + padFrameHeader |
| topModuleBody += "\n\nendmodule" |
| |
| # join padframe module sections |
| padFrameModule = ( |
| padFrameHeaderDefinition |
| + "\n\n" |
| + padFrameWires |
| + "\n\n" |
| + padFrameModule |
| + "\n\nendmodule" |
| ) |
| |
| # join the code segments |
| topModule = ( |
| topModuleDefines |
| + "\n\n\n" |
| + topModuleIncludes |
| + "\n\n\n" |
| + topModuleMacros |
| + "\n\n\n" |
| + topModuleHeader |
| + "\n\n\n" |
| + topModuleDeclarations |
| + "\n\n\n" |
| + topModuleExtra |
| + topModuleBody |
| + "\n\n" |
| + padFrameModule |
| + "\n\n" |
| ) |
| |
| # write the code |
| outputFileOpener = open(output, "w+") |
| outputFileOpener.write(topModule) |
| outputFileOpener.close() |