Skip to content

Commit

Permalink
Merge pull request #294 from ALIGN-analoglayout/feature/logging
Browse files Browse the repository at this point in the history
Set log-level from command line
  • Loading branch information
parijatm authored Jan 6, 2020
2 parents 5b58048 + 814ebc3 commit b9654c9
Show file tree
Hide file tree
Showing 12 changed files with 265 additions and 243 deletions.
13 changes: 12 additions & 1 deletion align/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,15 @@
__version__ = '0.9.8'

import pathlib
import os
import logging

logdir = pathlib.Path.cwd() / "LOG"
if not os.path.exists(logdir):
os.mkdir(logdir)
elif os.path.exists(logdir / "compiler.log"):
os.rename(logdir / "compiler.log", logdir / "compiler.log1")
logging.basicConfig(filename=logdir / "compiler.log", level=logging.ERROR)

from .main import schematic2layout
from .cmdline import CmdlineParser
from .cmdline import CmdlineParser
10 changes: 10 additions & 0 deletions align/cmdline.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import argparse
from .main import schematic2layout
from . import __version__

class CmdlineParser():

Expand Down Expand Up @@ -67,6 +68,15 @@ def __init__(self, *args, **kwargs):
"--extract",
action='store_true',
help='Set to true to extract post-layout netlist')
parser.add_argument( "-l", "--log",
dest="log_level",
choices=['DEBUG','INFO','WARNING','ERROR','CRITICAL'],
default='WARNING',
help="Set the logging level (default: %(default)s)")
parser.add_argument('--version',
action='version',
version='%(prog)s ' + __version__)

self.parser = parser

def parse_args(self, *args, **kwargs):
Expand Down
36 changes: 18 additions & 18 deletions align/compiler/basic_element.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
@author: kunal
"""
#%% creating basic element
from .util import logging

import logging
logger = logging.getLogger(__name__)

class BasicElement:
"""
Expand Down Expand Up @@ -61,7 +62,7 @@ def get_elements(self, num_pins=2):
self.pins[n]='vss'


logging.info("real inst type from netlist: %s",self.real_inst_type)
logger.info("real inst type from netlist: %s",self.real_inst_type)
start = 1
multiple = 2
self.pin_weight = [start*multiple**i for i in range(self.num_pins)]
Expand Down Expand Up @@ -192,7 +193,7 @@ def parse_value(all_param, vtype=None):
param = all_param[idx - 1]
if not value:
value = all_param[idx + 1]
logging.info('Found device values: %s, value:%s', param, value)
logger.info('Found device values: %s, value:%s', param, value)
device_param_list[param] = value
if not device_param_list and len(all_param)>0:
device_param_list[vtype] =all_param[0]
Expand All @@ -201,11 +202,10 @@ def parse_value(all_param, vtype=None):

def _parse_inst(line):
""" PARSE instance lines"""
logging.basicConfig(filename='./LOG/instances.log', level=logging.DEBUG)

#line = line.replace("(", "").replace(")", "")
element = BasicElement(line)
#logging.info('READ line:'+line)
#logger.info('READ line:'+line)
device = None
if not line.strip():
return device
Expand All @@ -218,28 +218,28 @@ def _parse_inst(line):
or line.strip().startswith('xp') \
or (line.strip().startswith('I') and 'mos' in line) \
or line.strip().lower().startswith('t'):
logging.debug('FOUND transistor : %s', line.strip())
logger.debug('FOUND transistor : %s', line.strip())
device = element.transistor()
elif line.strip().lower().startswith('v'):
logging.debug('FOUND v_source: %s', line.strip())
logger.debug('FOUND v_source: %s', line.strip())
device = element.v_source()
elif line.strip().lower().startswith('e'):
logging.debug('FOUND vcvs_source: %s', line.strip())
logger.debug('FOUND vcvs_source: %s', line.strip())
device = element.vcvs_source()
elif line.strip().startswith('i'):
logging.debug('FOUND i_source: %s', line.strip())
logger.debug('FOUND i_source: %s', line.strip())
device = element.i_source()
elif line.strip().lower().startswith('c') \
or ( line.strip().lower().startswith('xc') \
and 'cap' in line.strip().split()[3].lower()):
#DESIGN=Sanitized_TX_8l12b has XC for caps
logging.debug('FOUND cap: %s', line.strip())
logger.debug('FOUND cap: %s', line.strip())
device = element.capacitor()
elif line.strip().lower().startswith('r') or line.strip().lower().startswith('xr'):
logging.debug('FOUND resistor: %s', line.strip())
logger.debug('FOUND resistor: %s', line.strip())
device = element.resistor()
elif line.strip().lower().startswith('l'):
logging.debug("inductance: %s", line.strip())
logger.debug("inductance: %s", line.strip())
device = element.inductor()
elif line.strip().lower().startswith('x') \
or line.strip().startswith('I'):
Expand All @@ -263,7 +263,7 @@ def _parse_inst(line):
if not value:
value = all_nodes[idx + 1]
pass
logging.info('Found subckt parameter values: %s, value:%s',
logger.info('Found subckt parameter values: %s, value:%s',
param, value)
device_param_list[param] = value

Expand All @@ -278,18 +278,18 @@ def _parse_inst(line):
"edge_weight": list(range(len(hier_nodes[1:-1]))),
"values": device_param_list
}
logging.debug('FOUND subckt instance: %s, type %s ', device["inst"],
logger.debug('FOUND subckt instance: %s, type %s ', device["inst"],
device["inst_type"])

if device:
if '=' in device["inst"] or '=' in device[
"inst_type"] or '=' in ' '.join(device["ports"]):
device = None
logging.error("RECHECK unidentified Device: %s", line)
logger.error("RECHECK unidentified Device: %s", line)
elif device["inst_type"]=="dummy":
#device = None
logging.error("Removing dummy transistor: %s", line)
logger.error("Removing dummy transistor: %s", line)
else:
logging.error("Extraction error: %s (unidentified line)", line)
logger.error("Extraction error: %s (unidentified line)", line)

return device
51 changes: 27 additions & 24 deletions align/compiler/compiler.py
Original file line number Diff line number Diff line change
@@ -1,33 +1,36 @@
import pathlib

from .util import _write_circuit_graph, logging,max_connectivity
from .util import _write_circuit_graph, max_connectivity
from .read_netlist import SpiceParser
from .match_graph import read_inputs, read_setup,_mapped_graph_list,preprocess_stack,reduce_graph,define_SD,check_nodes,add_parallel_caps,add_series_res
from .write_verilog_lef import WriteVerilog, WriteSpice, print_globals,print_header,print_cell_gen_header,generate_lef
from .write_verilog_lef import WriteConst,FindArray,WriteCap,check_common_centroid
from .read_lef import read_lef

import logging
logger = logging.getLogger(__name__)

def generate_hierarchy(netlist, subckt, output_dir, flatten_heirarchy, unit_size_mos , unit_size_cap):
updated_ckt,library = compiler(netlist, subckt, flatten_heirarchy)
return compiler_output(netlist, library, updated_ckt, subckt, output_dir, unit_size_mos , unit_size_cap)

def compiler(input_ckt:pathlib.Path, design_name:str, flat=0,Debug=False):
input_dir=input_ckt.parents[0]
logging.info("Reading subckt %s", input_ckt)
logger.info("Reading subckt %s", input_ckt)
sp = SpiceParser(input_ckt, design_name, flat)
circuit = sp.sp_parser()[0]

design_setup=read_setup(input_dir / (input_ckt.stem + '.setup'))
logging.info("template parent path: %s",pathlib.Path(__file__).parent)
logger.info("template parent path: %s",pathlib.Path(__file__).parent)
lib_path=pathlib.Path(__file__).resolve().parent.parent / 'config' / 'basic_template.sp'
logging.info("template library path: %s",lib_path)
logger.info("template library path: %s",lib_path)
basic_lib = SpiceParser(lib_path)
library = basic_lib.sp_parser()
lib_path=pathlib.Path(__file__).resolve().parent.parent / 'config' / 'user_template.sp'
user_lib = SpiceParser(lib_path)
library += user_lib.sp_parser()
library=sorted(library, key=lambda k: max_connectivity(k["graph"]), reverse=True)
logging.warning("dont use cells: %s",design_setup['DONT_USE_CELLS'])
logger.warning("dont use cells: %s",design_setup['DONT_USE_CELLS'])
if len(design_setup['DONT_USE_CELLS'])>0:
library=[lib_ele for lib_ele in library if lib_ele['name'] not in design_setup['DONT_USE_CELLS']]

Expand All @@ -41,20 +44,20 @@ def compiler(input_ckt:pathlib.Path, design_name:str, flat=0,Debug=False):

UPDATED_CIRCUIT_LIST = []
for circuit_name, circuit in hier_graph_dict.items():
logging.info("START MATCHING in circuit: %s", circuit_name)
logger.info("START MATCHING in circuit: %s", circuit_name)
G1 = circuit["graph"]
if circuit_name in design_setup['DIGITAL']:
mapped_graph_list = _mapped_graph_list(G1, library, design_setup['CLOCK'], True )
else:
define_SD(G1,design_setup['POWER'],design_setup['GND'], design_setup['CLOCK'])
logging.info("no of nodes: %i", len(G1))
logger.info("no of nodes: %i", len(G1))
add_parallel_caps(G1)
add_series_res(G1)
preprocess_stack(G1)
initial_size=len(G1)
delta =1
while delta > 0:
logging.info("CHECKING stacked transistors")
logger.info("CHECKING stacked transistors")
preprocess_stack(G1)
delta = initial_size - len(G1)
initial_size = len(G1)
Expand All @@ -75,13 +78,13 @@ def compiler(input_ckt:pathlib.Path, design_name:str, flat=0,Debug=False):
def compiler_output(input_ckt, library, updated_ckt, design_name, result_dir, unit_size_mos=12, unit_size_cap=12):
if not result_dir.exists():
result_dir.mkdir()
logging.info("Writing results in dir: %s",result_dir)
logger.info("Writing results in dir: %s",result_dir)
input_dir=input_ckt.parents[0]
VERILOG_FP = open(result_dir / (design_name + '.v'), 'w')
## File pointer for running cell generator
LEF_FP = open(result_dir / (design_name + '_lef.sh'), 'w')

logging.info("writing spice file for cell generator")
logger.info("writing spice file for cell generator")

## File pointer for spice generator
SP_FP = open(result_dir / (design_name + '_blocks.sp'), 'w')
Expand All @@ -92,12 +95,12 @@ def compiler_output(input_ckt, library, updated_ckt, design_name, result_dir, un
POWER_PINS = [design_setup['POWER'][0],design_setup['GND'][0]]
except (IndexError, ValueError):
POWER_PINS=[]
logging.error("no power and gnd defination, correct setup file")
logger.error("no power and gnd defination, correct setup file")

#read lef to not write those modules as macros
lef_path = pathlib.Path(__file__).resolve().parent.parent / 'config'
ALL_LEF = read_lef(lef_path)
logging.info("Available library cells: %s", ", ".join(ALL_LEF))
logger.info("Available library cells: %s", ", ".join(ALL_LEF))
# local hack for deisgn vco_dtype,
#there requirement is different size for nmos and pmos
if 'vco_dtype_12' in design_name:
Expand All @@ -112,23 +115,23 @@ def compiler_output(input_ckt, library, updated_ckt, design_name, result_dir, un
continue
else:
duplicate_modules.append(name)
logging.info("Found module: %s", name )
logger.info("Found module: %s", name )
inoutpin = []
logging.info("found ports match: %s",members["ports_match"])
logger.info("found ports match: %s",members["ports_match"])
floating_ports=[]
if members["ports_match"]:
for key in members["ports_match"].keys():
if key not in POWER_PINS:
inoutpin.append(key)
if members["ports"]:
logging.info("Found module ports kk:%s",members["ports"] )
logger.info("Found module ports kk:%s",members["ports"] )
floating_ports = list(set(inoutpin) - set(members["ports"]))
logging.warning("floating port found: %s",floating_ports)
logger.warning("floating port found: %s",floating_ports)
else:
inoutpin = members["ports"]

graph = members["graph"].copy()
logging.info("Reading nodes from graph: %s", str(graph))
logger.info("Reading nodes from graph: %s", str(graph))
for node, attr in graph.nodes(data=True):
#lef_name = '_'.join(attr['inst_type'].split('_')[0:-1])
if 'net' in attr['inst_type']: continue
Expand All @@ -140,35 +143,35 @@ def compiler_output(input_ckt, library, updated_ckt, design_name, result_dir, un
LEF_FP, lef_name, attr["values"],
primitives, unit_size_mos, unit_size_cap)
block_name_ext = block_name.replace(lef_name,'')
logging.info("Created new lef for: %s", block_name)
logger.info("Created new lef for: %s", block_name)
if block_name in primitives:
assert block_args == primitives[block_name]
else:
primitives[block_name] = block_args
graph.nodes[node]['inst_type'] = block_name
else:
logging.warning("No physical information found for: %s", name)
logger.warning("No physical information found for: %s", name)

if name in ALL_LEF:
logging.info("writing spice for block: %s", name)
logger.info("writing spice for block: %s", name)
ws = WriteSpice(graph, name+block_name_ext, inoutpin, updated_ckt)
ws.print_subckt(SP_FP)
continue

print("generated data", name, generated_module, primitives)
if name not in ALL_LEF:
logging.info("call verilog writer for block: %s", name)
logger.info("call verilog writer for block: %s", name)
wv = WriteVerilog(graph, name, inoutpin, updated_ckt, POWER_PINS)
const_file = (result_dir / (name + '.const'))
logging.info("call array finder for block: %s", name)
logger.info("call array finder for block: %s", name)
all_array=FindArray(graph, input_dir, name )
logging.info("cap constraint gen for block: %s", name)
logger.info("cap constraint gen for block: %s", name)
WriteCap(graph, result_dir, name, unit_size_cap,all_array)
check_common_centroid(graph,const_file,inoutpin)
##Removinf constraints to fix cascoded cmc
lib_names=[lib_ele['name'] for lib_ele in library]
if name not in design_setup['DIGITAL'] and name not in lib_names:
logging.info("call constraint generator writer for block: %s", name)
logger.info("call constraint generator writer for block: %s", name)
WriteConst(graph, input_dir, name, inoutpin, result_dir)
wv.print_module(VERILOG_FP)
generated_module.append(name)
Expand Down
Loading

0 comments on commit b9654c9

Please sign in to comment.