'''
# Version 0.0.2
# Coder: Huang Xiao
# Target: improve quality and effeciency
1.Pcell Code Coverage
2.two of LVS 3 level check:PDK level
3.Simulation QA
4.DRC Code coverage
5.PDK Consistency: ADS & Cadence
6.PDK Generation Framework
# Function: 1.drc code 2.auto lvs
Log:
2018.12.06 Hxj: Add Setting Dict to Control performance, Function also change
2018.12.07 Hxj: Modify Function ParseCircuitAelofPath(DocPath) extend return default value of PDK
2018.12.07 Hxj: Add WritePDKComponentInfo2Excel to read PDK Component Info and write to excel
2018.12.07 Hxj: Debug Function Sampling/ReadDeviceList handle type=4 parameter value expression
2018.12.08 Hxj: Debug Function AelScriptGeneration: add symbol in PcellPath to ajust schematic generation
2018.12.10 Hxj: Debug pop() key error
2018.12.14 Hxj: Debug Sampling() to adjust type4 like [TV_slot_20X40, TV_circle_40]
2018.12.14 Hxj: Debug InfoCat() to adjust error like wrong parameter name in Excel
Topic:
DeviceList.xlsx: if "the instance statement" is blank
PDK: ael document contain old component that is not used
process component do not has not symbol
Case: P15LN cannot read SCdio:n
'''
#================================================== Section 0. Package ============================================
import re
import xlrd
import xlwt
import os
import sys
Setting={'TableFormatHeader':['No','Device','Terminal','DeviceName','Instance Statement','Device Description (ADS explanation)','Equation'],
'DeviceListStatementPattern':['(\d+\.{0,1}\d*){1}\s*\[\s*(\d+\.{0,1}\d*)\s*,\s*(\d+\.{0,1}\d*)\s*\]' , '(\d+\.{0,1}\d*)\s*\(\s*\]' , '\s*(\d+\.{0,1}\d*)\s*,{0,1}\s*' , '(\d+\.{0,1}\d*)','(\d+\.{0,1}\d*){1}\s*\[\s*(\d+\.{0,1}\d*)\s*:\s*(\d+\.{0,1}\d*)\s*:\s*(\d+\.{0,1}\d*)\s*\]'],
'WorkPath':'C:/Users/10000130/Desktop/Work/QA.autoQ/AutoQA/QA/Sanan_P15LN/',
'ScriptPath':'QA/script/',
'DeviceListPath':'QA/PDKdevicelist.xls',
'SheetName':'netlist_v1',
'ComponentArtworkPath':'circuit/ael/',
}
#============================================ Section 1. Prcossing Function ============================================
def DeleteNullInList(StringList):
Length1=len(StringList)
Length2=0
while(Length2<Length1):
Length1=len(StringList)
for item in StringList:
if (item=='' or item==[]):
StringList.remove(item)
Length2=len(StringList)
def BacktraceSpaceIndex(ValueString,IndexStart):
StringLen=len(ValueString)
if(IndexStart>=0 & IndexStart<StringLen):
Index=IndexStart
while(Index>=0):
if(ValueString[Index]==' '):
return Index
Index-=1
return Index
else:
return 'Input IndexStart Range Error'
def Float2Str(ValueList):
ResultList=[]
try:
for item in ValueList:
ResultList.append('%.2f'%item)
return ResultList
except:
return ValueList
def Str2Float(StrList):
ResultList=[]
try:
for item in StrList:
ResultList.append(float(item))
return ResultList
except:
return StrList
''' Test Code
PatternList=['prm\s*\((.+?)\)\s*' , ',\s*\"\d*\.{0,1}\d+(.*?)\"']
IndexList=[0,0]
StatementString='LENGTH_UNIT, prm("StdForm", "") , // default value list(dm_create_cb(PARM_MODIFIED_CB,'
StatementString1='LENGTH_UNIT, prm("StdForm", "20 um ") , // default value list(dm_create_cb(PARM_MODIFIED_CB,'
StatementString2='LENGTH_UNIT, prm("StdForm", "20") , // default value list(dm_create_cb(PARM_MODIFIED_CB,'
StatementString3='LENGTH_UNIT, prm("StdForm", "20.5 um ") , // default value list(dm_create_cb(PARM_MODIFIED_CB,'
StatementString4='LENGTH_UNIT, prm("StdForm", "vtw") , // default value list(dm_create_cb(PARM_MODIFIED_CB,' #may cause error
#expect result '',' um', ' um'
'''
def MultipleExtract(StatementString,PatternList,IndexList):
if len(PatternList)<len(IndexList):
return 'Input List Length Format Error !'
ExtractedList=[]
for i in range(len(PatternList)):
PatternExpression=re.compile(PatternList[i])
ExtractedList=PatternExpression.findall(StatementString) # if not found return [] empty list
try:
StatementString=ExtractedList[IndexList[i]]
except:
StatementString=''
return StatementString
'''
StatementString='create_parm( "ne", "Number of fingers: Emitter ---> 1 to 8 ",'
'''
def RecursionFileInDoc(PATH):
# Fcuntion: get all files in PATH
# Setting:
# Requirement: input is path string, should be: 1.some fixed format pattern ; 2.paht should be exist
# Package Depend on: os
#LinuxPathStringFormat='(\/w*)(\1)+'
#WindowsPathStrtingFormat
if(PATH[-1]!='/'):
PWD=PATH+'/'
else:
PWD=PATH # if not / add
Files=[]
try:
CurrentDir=os.listdir(PATH)
for i in range (len(CurrentDir)):
if(os.path.isdir(PWD+CurrentDir[i])):
Files=Files+(recursionFile(PWD+CurrentDir[i]))
elif(os.path.isfile(PWD+CurrentDir[i])):
Files.append(PWD+CurrentDir[i])
return Files
except FileNotFoundError as e:
return e
def FilenameFilter(FileList,FilterKeyword):
# Fcuntion: Processing Files with 'xxx.yyy' format
# Setting:
# Requirement: input is path string list and format string yyy
# Package Depend on:
for filename in FileList:
#tempname=re.split('.',filename) # . will be regard as regular pattern here
tempname=filename.split('.')
if tempname[-1]!=FilterKeyword :
FileList.remove(filename)
#================================================== Section 2. Module ==================================================
def ReadDeviceList(ExcelPath,SheetName,Setting):
# Fcuntion: Read sheet in .xlsx , output device infomation without parsed
# Setting: TableFormatHeader
# Requirement: input .xlsx and SheetName should be fixed
# Package Depend on: xlrd
#define output data
DeviceDict={}
#Define Tabel format:
TableFormatHeader=Setting['TableFormatHeader']
ColumnOfTable=len(TableFormatHeader)
#read excel and parse
with xlrd.open_workbook(ExcelPath) as Excel:
#SheetName= Excel.sheet_names()[0]
#get sheet contain Device List info
Sheet=Excel.sheet_by_name(SheetName)
#遍历每一行,count数行数
Nrows=Sheet.nrows #获得sheet的总行数
Section=0
Count=0
while Count<Nrows:
RowList=Sheet.row_values(Count) #RowList是一个以每一行的各个列元素组合成的list
Count+=1
#read by lines, Section = 1 mean catch the table info of device list
#compare row with fixed TableForamtHearder setting to find out the head of table
Flag=True
for header in TableFormatHeader:
if (header not in RowList):
Flag=False
if (Flag): #RowList should be string or error occur
Section=1 # the first section Mask Name table, extract Layers
continue #if catch header, jump out of this segment
elif Section==1: #
try:
DeviceDict[RowList[TableFormatHeader.index('DeviceName')]]=RowList[TableFormatHeader.index('Instance Statement')]
except IndexError:
pass
elif Section==2: #Section 2 is Design Rule Info
pass
if Count==0:
pass
#read failure
#Excel.close() workbook do not have close() function
try:
DeviceDict.pop('') # the key not in the dict cause pop() key error
except:
pass
return DeviceDict #output format {DeviceName:'statement'} statement format like {'qebe':'qbebxxx (E,B,C) we =2[1.6,5] le =20[10,50] ne=1[2,8] nb=3[::] nc=2 selft =1 trise = 0 rthpkg =0 cthpag =0'}
'''Value Pattern varys:
1. 25[25,200] -> default,min,max '(\d+\.{0,1}\d*){1}\s*\[\s*(\d+\.{0,1}\d*)\s*,\s*(\d+\.{0,1}\d*)\s*\]'
2. 10(] -> default,min,max ;
3.[2,3,4,5,6] -> default,min,max,list
4. type=xx like TV ? may
5. 3[::] passively change ignore
6. 4[smin,5] -> defalut,smin=?
7.Layer=Double_Metal[Double_Metal,M1,M2]
'''
#3 test cases: nb = 1[:] nf=[,,,] we=20[10,30] w=10(]
def ParseStatement(Statement,Setting):
# Fcuntion: Pasrsed String in to Parameter-Restrict_Value Dict
# Setting: Pattern
# Requirement: should input String Statement
# Package Depend on: re, DeleteNullInList
#Setting:depend on Excel format
Pattern=Setting['DeviceListStatementPattern']
#define output
ParameterDict={}
ParameterExpressionTypeDict={}
ParameterExpressionType=0
#Pins=[]
#PinsDict={}
#
if isinstance(Statement,str): #check Statement is str type , the child str
RegularStatement=re.sub('=',' = ',Statement)
RegularStatement=re.sub(',',',',RegularStatement)
RegularStatement=re.sub(',',' , ',RegularStatement)
RegularStatement=re.sub(';',' ; ',RegularStatement)
#check if string
#find the index of '='
while(RegularStatement.find('=') != -1):
IndexEqual=RegularStatement.find('=')
ParameterNameInfo=RegularStatement[0:IndexEqual]
InfoList=ParameterNameInfo.split(' ')
DeleteNullInList(InfoList)
ParameterName=InfoList[-1]
ParameterValueInfo=RegularStatement[IndexEqual+1:]
RegularStatement=ParameterValueInfo
if(RegularStatement.find('=')!=-1):
IndexEqual=RegularStatement.find('=')
ValueInfo=RegularStatement[0:IndexEqual]
else:
ValueInfo=RegularStatement
#match break
# math statement in ParameterName=statements type lik 10(] 5[3,10] [2,3,4,5]
if(re.findall(Pattern[0],ValueInfo)!=[]):
#Expression Type 1: 4[3,10]
Default,Min,Max=re.findall(Pattern[0],ValueInfo)[0]
ParameterDict[ParameterName]=[Default,Min,Max]
ParameterExpressionType=1
elif(re.findall(Pattern[1],ValueInfo)!=[]):
#Expression Type 2: 4(]
Default=re.findall(Pattern[1],ValueInfo)[0]
ParameterDict[ParameterName]=[Default, Default,'-1']
ParameterExpressionType=2
elif(re.findall('\[([^:]+)\]',ValueInfo)!=[]): # exclude like 2[:] this format is passively changed that will be ignore
#Expression type 3: [1,3,5,7] or [TV_Circle_50,TV_slot_30x60]
#ParameterDict[ParameterName]=re.findall(Pattern[2],ValueInfo) this expression only extract numbers which make error on "TV_slot_30x60"
ParameterDict[ParameterName]=re.findall('\[([^:]+)\]',ValueInfo)[0].split(',')
ParameterExpressionType=3
elif(len(re.findall(Pattern[3],ValueInfo))==1):
#Expression type 4: Parm=Value nf=1
#ParameterDict[ParameterName]=re.findall(Pattern[2],ValueInfo) * 3
# only 1 value means default forever, ignore the parameter, like trise=0
# only accpet numbers
ParameterDict[ParameterName]=re.findall(Pattern[3],ValueInfo)
ParameterExpressionType=4
elif(len(re.findall(Pattern[4],ValueInfo))!=0):
# fix step like inductor: only accept 4.5[1.5:0.25:15.5]
Default,Min,Step,Max=re.findall(Pattern[4],ValueInfo)[0]
ParameterDict[ParameterName]=[Default,Min,Max,Step]
ParameterExpressionType=5
else:
#continue will ignore the code follows so ParameterExpressionTypeDict[ParameterName]=ParameterExpressionType will not be carry out
continue
ParameterExpressionTypeDict[ParameterName]=ParameterExpressionType
return ParameterDict,ParameterExpressionTypeDict
else:
return 'TypeError: Arguement is not string'
def ParseDeviceDict(DeviceDictRaw,Setting):
# Fcuntion: Parsed Statements, bundle handle
# Setting:
# Requirement: should input String Statement dict
# Package Depend on: ParseStatement
DeviceDict={}
DeviceSamplingDict={}
for key in DeviceDictRaw:
ParameterDict,ParameterExpressionTypeDict=ParseStatement(DeviceDictRaw[key],Setting)
#TempDict.update(Parameters)
#TempDict.update(Pins) #we don't need pins information
DeviceDict[key]=ParameterDict
DeviceSamplingDict[key]=ParameterExpressionTypeDict
return DeviceDict,DeviceSamplingDict #Output Like: 'qebe':{'we':[2,2,80],'le':['20','20','80'],'n':[2,3,4,5,6,7,8]} & {'qebe':{'we':2,'le':2,n:'3',trise=4}}
def ParseCircuitAel(FilePath):
# Fcuntion: Parse PDK ael file in /circuit/ael
# Setting:
# Requirement: Fixed ael code style
# Package Depend on:
# Notice: input/output string is related to code and decode
# Debug: PermissionError: [Errno 13] Permission denied: FILEPATH
#DeviceParameterList=[]
ExclePDKInfoLink={}
PDKParameterInfo={}
ResultInfo=True
try:
CircuitAelFile=open(FilePath,'rb')
#FilePath is CircuitAelFile
#ParseWords=[]
Count=0
TempStringList=[]
CodeString=''
CommentIndex=-1
# 0: not parsing >0 parsing; different segment different parsing
for row in CircuitAelFile:
CommentIndex=row.decode().find('//')
CodeString=row[0:CommentIndex].decode()
#when row catch 'create_item' start Parsing
if CodeString.find('create_item')!=-1:
TempStringList.append('')
Count=1
elif CodeString.find('create_parm')!=-1:
TempStringList.append(CodeString)
Count=Count+1
if Count>0:
TempStringList[Count-1]+=CodeString
#Count = the number of segements which contains parameters and device modelname
#TempStringList is code segements split by 'create_item' or 'create_parm'
#TempStringList[0] is code segment of device definition
DeviceInfoString=TempStringList[0]
#return DeviceInfoString
DeviceName=''
IndexStart=DeviceInfoString.find('"')
DeviceInfoString=DeviceInfoString[IndexStart+1:]
IndexEnd =DeviceInfoString.find('"')
DeviceName=DeviceInfoString[0:IndexEnd]
DeviceInfoString=DeviceInfoString[IndexEnd+1:]
#skip internal segment
for i in range(9):
IndexStart=DeviceInfoString.find(',')
DeviceInfoString=DeviceInfoString[IndexStart+1:]
#9rd section is prefix--model name
ModelName=''
IndexStart=DeviceInfoString.find('"')
DeviceInfoString=DeviceInfoString[IndexStart+1:]
IndexEnd =DeviceInfoString.find('"')
ModelName=DeviceInfoString[0:IndexEnd]
DeviceInfoString=DeviceInfoString[IndexEnd+1:]
ExclePDKInfoLink[ModelName]=DeviceName
#Parsed device parameter unit
ParameterDict={}
DefaultValueDict={}
for Segment in TempStringList[1:]:
PatternList=['prm\s*\((.+?)\)\s*' , ',\s*\"\d*\.{0,1}\d+(.*?)\"'] # ? means Non-greedy match
IndexList=[0,0]
Unit=MultipleExtract(Segment,PatternList,IndexList) # if IndexList is not found, will cause error that file not parased
PatternList=['prm\s*\((.+?)\)\s*' , ',\s*\"(\d*\.{0,1}\d+.*?)\"'] # ? means Non-greedy match
IndexList=[0,0]
DefaultValue=MultipleExtract(Segment,PatternList,IndexList) # if IndexList is not found, will cause error that file not parased
DeviceInfoString=Segment
IndexStart=DeviceInfoString.find('"')
DeviceInfoString=DeviceInfoString[IndexStart+1:]
IndexEnd =DeviceInfoString.find('"')
ParameterName=DeviceInfoString[0:IndexEnd]
ParameterDict.update({ParameterName:Unit})
DefaultValueDict.update({ParameterName:DefaultValue})
ParameterDict.update({'Default':DefaultValueDict})
PDKParameterInfo[ModelName]=ParameterDict
except IOError as e:
ResultInfo='Error:Parsing %s fail: %s. \n'%(FilePath,e)
finally:
CircuitAelFile.close()
return ExclePDKInfoLink,PDKParameterInfo,ResultInfo
#output ExcelPDKInfoLink FormatL lik {'c12':'BIHEMT_M1CC'}
def WritePDKComponentInfo2Excel(DocPath,OutputExcelPath,Setting):
# create a workbook and worksheet, only in memery, should be save latter
Workbook = xlwt.Workbook(encoding = 'ascii')
Worksheet = Workbook.add_sheet(Setting['SheetName'])
# extract info from PDK
DeviceModelSet,DeviceParameterUnitSet,ErrorFileList=ParseCircuitAelofPath(DocPath)
TableFormatHeader=Setting['TableFormatHeader']
i=0
for j in range(len(TableFormatHeader)):
Worksheet.write(i, j, label = TableFormatHeader[j])
for item in DeviceModelSet:
i+=1
ComponentName=DeviceModelSet[item]
DeviceModel=item
ParmDefaultDict=DeviceParameterUnitSet[item]['Default'] #2018.12.7 DeviceModelSet may contain key '',which will lead to error
Statement=''
for parm in ParmDefaultDict:
#if ParmDefaultDict[parm]!='':
Statement+=parm
Statement+=' = '
Statement+=ParmDefaultDict[parm]
Statement+=' , '
j=TableFormatHeader.index('No')
Worksheet.write(i, j, label = '%i'%i)
j=TableFormatHeader.index('Device')
Worksheet.write(i, j, label = ComponentName)
j=TableFormatHeader.index('DeviceName')
Worksheet.write(i, j, label = DeviceModel)
j=TableFormatHeader.index('Instance Statement')
Worksheet.write(i, j, label = Statement)
Workbook.save(OutputExcelPath)
def PDKInfo(WorkPath):
# Fcuntion: Extract PDK component library name
# Setting:
# Requirement: Fixed PDK structure
# Package Depend on:
# Notice: os
#find library name
if(WorkPath[-1]!='/'):
PWD=WorkPath+'/'
else:
PWD=WorkPath # if not / add
# if not / add
CurrentDir=os.listdir(WorkPath)
Result=''
for Document in CurrentDir:
#if(os.path.isdir(PWD+Document) & Document.find('_tech')==-1 & Document.find('Sanan')!=-1):
if(Document[-5:]=='_tech'):
Result=Document[0:-5]
return Result
#input info
#input data structure:
# DeviceSet={Pcell:ParameterNameList,ParameterValueList,LocationList} ParameterName/ValueList come from DeviceList.xlsx LocationList also and caculation
# PDKInfo={"H20_CC_M1":[LibName,LayoutName]} read from PDK code
# EnterInfo={'Libname':"Ex_lib",'CellName':"Ex_Cell"} comefrom input assignment
#principle for data structure of this segement: some sturcture is convenience for code writing
def AelScriptGeneration(AelPath,DeviceSet,PDKInfo,EnterInfo):
# Fcuntion: Generate ael code from infomation,
# Setting:
# Requirement: Fixed data structure
# Package Depend on:
# Notice:
AelScript="//========= ael Script for QA_autoplacement ==========\n"
for Pcell in DeviceSet.keys():
PcellOfPDKInfo=PDKInfo[Pcell]
PcellPath=[PcellOfPDKInfo[0]]+[Pcell]+[PcellOfPDKInfo[1]]+[PcellOfPDKInfo[2]] # like ['PINAB',Cap_M1AB,'layout','symbol']
ParameterNameList=DeviceSet[Pcell]['ParameterNameList']
ParameterValueList=DeviceSet[Pcell]['ParameterValueList']
LocationList=DeviceSet[Pcell]['LocationList']
AelScript+="\n//========= Start of %s placement =========\n\n"%Pcell
AelScript+="decl PcellPath=list(\"%s\",\"%s\",\"%s\",\"%s\");\n"%(PcellPath[0],PcellPath[1],PcellPath[2],PcellPath[3])
AelScript+="decl ParameterNameList=list(\"%s\");\n"%("\",\"".join(ParameterNameList))
ListOfValue=[]
for ValueList in ParameterValueList:
ListOfValue.append("list(\"%s\")"%("\",\"".join(ValueList)))
AelScript+="decl ParameterValueList=list(%s);\n"%(",".join(ListOfValue))
ListOfLocation=[]
for XList in LocationList:
ListOfLocation.append("list(%s,%s)"%(XList[0],XList[1]))
AelScript+="decl LocationList=list(%s);\n"%(",".join(ListOfLocation))
if(EnterInfo['Setting']==1):
AelScript+="decl LayoutPath=list(\"%s\",\"%s\",\"%s\");\n"%(EnterInfo['LibName'],EnterInfo['CellName'],PcellPath[1]+'_layout')
AelScript+="DeviceLayoutGeneration(PcellPath,LayoutPath,ParameterNameList,ParameterValueList,LocationList);\n"
AelScript+="decl SymbolPath=list(\"%s\",\"%s\",\"%s\");\n"%(EnterInfo['LibName'],EnterInfo['CellName'],PcellPath[1]+'_schematic')
AelScript+="DeviceSchematicGeneration(PcellPath,SymbolPath,ParameterNameList,ParameterValueList,LocationList);\n"
elif(EnterInfo['Setting']==2):
AelScript+="decl LayoutPath=list(\"%s\",\"%s\",\"%s\");\n"%(EnterInfo['LibName'],EnterInfo['CellName'],'QA_layout')
AelScript+="DeviceLayoutGeneration(PcellPath,LayoutPath,ParameterNameList,ParameterValueList,LocationList);\n"
AelScript+="decl SymbolPath=list(\"%s\",\"%s\",\"%s\");\n"%(EnterInfo['LibName'],EnterInfo['CellName'],'QA_schematic')
AelScript+="DeviceSchematicGeneration(PcellPath,SymbolPath,ParameterNameList,ParameterValueList,LocationList);\n"
AelScript+="\n//********* End of %s placement ********* \n\n"%Pcell
try:
AelFile=open(AelPath,'w')
AelFile.write(AelScript)
AelFile.close()
return 'Write Ael Success:'+AelScript
except:
AelFile.close()
return 'Export Ael Error'
#Simpling is still a difficult:
# 1.Input StrList is vary kinds of Str, lik TV [TV_circle50, TV_circle40]
# 2.Sampling
def Sampling(StrList,Num,ListType):
# Fcuntion: Num sampling
# Setting:
# Requirement: Fixed data structure
# Package Depend on: Str2Float, Float2Str
# Notice: can not handle string type parameters like TV
ResultList=[]
StrResultList=[]
#ListType is link to value expression in DeviceList.xlxs like type1:x[x,x] type2:x(] type3:[x,x,x]
'''
ListType=0
if (Min<=Default and Default<Max):
ListType=1
elif(Min<=Default and Default>Max):
ListType=2 #like 10(] -> 10,10,-1
elif(Min>Default and Max>Min):
ListType=3
elif(Default==Min and Min == Max):
ListType=4 # only one value for parameter
'''
if(ListType==1):
ValueList=Str2Float(StrList)
ValueListLen=len(ValueList)
#Type 1 like Default[Min,Max]
Default=ValueList[0]
Min=ValueList[1]
Max=ValueList[2]
Default,Min,Max=ValueList
ResultList=[Default,Min,Max]+[(Max-Min)*(n+1)/(Num+1)+Min for n in range(Num)]
elif(ListType==2):
ValueList=Str2Float(StrList)
ValueListLen=len(ValueList)
#Type 2 like 20(]
#print('Input STEP for Sampling:')
#STEP=input()
Default=ValueList[0]
Min=ValueList[1]
Max=ValueList[2]
STEP=Min/2
Max=STEP*(Num+1)+Min
ResultList=[Default,Min,Max]+[(Max-Min)*(n+1)/(Num+1)+Min for n in range(Num)]
elif(ListType==3):
#Type 3 like [1,2,3,4] [1x100,1x150]fixed
ValueList=StrList
ValueListLen=len(ValueList)
ResultList=ValueList*(round(Num/ValueListLen)+1)
ResultList=[ValueList[0],ValueList[-1],ValueList[-1]]+ResultList[0:Num]
elif(ListType==4):
ValueList=Str2Float(StrList)
ValueListLen=len(ValueList)
#Type 4 like Parm=Value
ResultList=ValueList*Num
elif(ListType==5):
ValueList=Str2Float(StrList)
ValueListLen=len(ValueList)
#Type 5 like inductor 4.5[1.5:0.25:15.5]
Default,Min,Max,Step=ValueList
ResultList=[Default,Min,Max]+[(n+1)*Step+Min for n in range(Num)]
else:
pass
StrResultList=Float2Str(ResultList)
return StrResultList #the length of ResultList is Num+3
#Cartesian(ListA,ListB)
# We would better check value type
def PlaceLocationAjustComponentSize(ArraySetting,Gap,SizeList):
# Fcuntion: for component placement
# Setting:
# Requirement: ArraySetting is int dict:{'row':3,'col':5} means 3 rows 5 colmuns, Gap is [dx,dy], SizeList is components size[x,x,x,x]
# Package Depend on:
# Notice: No used now, get component size in ael API
LocationList=[]
SampleCount=0
CurrentLocation=[0,0]
for i in range(ArraySetting['row']):
if SampleCount<len(SizeList):
Size=SizeList[SampleCount]
CurrentLocation[1]+=(Size+Gap[1])
CurrentLocation[0]=0
else:
break
LocationList.append([])
for j in range(ArraySetting['col']):
if SampleCount<len(SizeList):
Size=SizeList[SampleCount]
CurrentLocation[0]+=(Size+Gap[0])
LocationList[i].append(CurrentLocation)
else:
break
SampleCount+=1
return LocationList
#================================================== Section 3. Batch Run ==================================================
def ParseCircuitAelofPath(DocPath):
# Fcuntion: batch run ParseCircuitAel
# Setting:
# Requirement: Fixed ael code style
# Package Depend on: ParseCircuitAel,RecursionFileInDoc
# Notice:
#Output
ExclePDKInfoLink={}
PDKParameterInfo={}
DeviceModelSet={}
DeviceParameterUnitSet={}
ErrorFileList=[]
FileList=RecursionFileInDoc(DocPath)
FilterKeyword='ael'
FilenameFilter(FileList,FilterKeyword)
for file in FileList:
try:
ExclePDKInfoLink,PDKParameterInfo,ResultInfo=ParseCircuitAel(file)
DeviceModelSet.update(ExclePDKInfoLink)
DeviceParameterUnitSet.update(PDKParameterInfo)
if (ResultInfo!=True):
ErrorFileList.append(file)
except:
ErrorFileList.append(file)
# the format that doesn't match the pattern will be expect and get
#DeviceModelSet.pop('') #cause Process.ael will parse none info
#DeviceParameterUnitSet.pop('')
return DeviceModelSet,DeviceParameterUnitSet,ErrorFileList
#================================================== Section 4. Main ==================================================
def InfoCat(Num,InfoDict,Setting):
#Input Format: InfoDict is contain nessary info for layout/schematic generation
#Setting: cause other functino need it
#WorkPath='C:/Users/10000130/Desktop/Work/autoQ/AutoQA/QA/Sanan_HBT/'
#Define temp var
ValueList=[]
PDKInfoDict={} # !!!! seems not used
ErrorInfo=[]
#==============internal variables
DeltaX=InfoDict['DeltaLocation'][0]
DeltaY=InfoDict['DeltaLocation'][1]
#========================================= Got Setting ==============================================
WorkPath=Setting['WorkPath']
DocPath=WorkPath+Setting['ComponentArtworkPath']
ExcelPath=WorkPath+Setting['DeviceListPath']
SheetName=Setting['SheetName']
#============================================ Read PDK =================================================
#in ReadPDKCircuitAel.py
# PDKInfo={"H20_CC_M1":["Sanan_HBT","layout"],"H20_Stacked_mim":["Sanan_HBT","layout"]}
PcellLibName=PDKInfo(WorkPath)
#DocPath like 'C:/Users/10000130/Desktop/Work/autoQ/AutoQA/QA/Sanan_BIHEMT/circuit/ael/'
PDKInfoRaw,DeviceParameterUnitSet,ErrorFileList=ParseCircuitAelofPath(DocPath)
#Output like DeviceSet:{'qbeb':'H20_QBEB'}
for key in PDKInfoRaw:
tempDict={PDKInfoRaw[key]:[PcellLibName,'layout','symbol']}
PDKInfoDict.update(tempDict)
# PDKInfoDict like {"H20_CC_M1":["Sanan_HBT","layout"],"H20_Stacked_mim":["Sanan_HBT","layout"]}
#======================================== Read Device List==============================================
# ReadDeviceList.py
#20181204 ExcelPath=WorkPath+'QA/'+'PDKdevicelist.xlsx'
#20181204 SheetName='netlist_v1'
DeviceDictRaw=ReadDeviceList(ExcelPath,SheetName,Setting)
DeviceDict,DeviceSamplingDict=ParseDeviceDict(DeviceDictRaw,Setting)
#Output Like: 'qebe':{'we':[2,2,80],'le':['20','20','80'],'n':[2,3,4,5,6,7,8]}
#=====================================================================================================
#print('Input the number for parameters Simpling: ')
#Num=input()
#Num is the simpling number
DeviceSet={}
ErrorDeviceSet={}
CountDevice=0
for key in DeviceDict:
# !!! inital code should nest in
ParameterNameList=[]
ParameterUnitList=[]
ParameterValueList=[]
TempList=[]
TempArray=[]
#LocationList may be caculate in code
#LocationList=['200','200']
LocationList=[]
LocationList4Symbol=[]
try:
#InfoDict={PDKInfoRaw[key]:DeviceDict[key]} #create link by key
for parameter in DeviceDict[key]:
ValueList=DeviceDict[key][parameter]
ParameterNameList.append(parameter)
try:
ParameterUnitList.append(DeviceParameterUnitSet[key][parameter]) #If excel key in wrong parameter name, will cause key error
TempList=Sampling(ValueList,Num,DeviceSamplingDict[key][parameter]) #if ValueList is like [TV_circle50,TV] [MET1,MET2] how to
TempArray.append(TempList)
except KeyError as e:
ErrorInfo.append(e)
ParameterNum=len(TempArray)
SampleNum=len(TempArray[0])
#ParameterValueList=[[0]*ParameterNum]*SampleNum #!!!! nest list structure, the 1st-list is point of sublist,when * it will be shallow copy, means copy pointer not the value been pointed. so error caused
ParameterValueUnitList=ParameterValueList
for i in range(SampleNum):
ParameterValueList.append([])
for j in range(ParameterNum):
ParameterValueList[i].append(TempArray[j][i])
for i in range(SampleNum):
#LocationList.append([2*max(Str2Float(ParameterValueList[i]))]*2) # ParameterValueList for TV is not value will cause error
LocationList.append([DeltaX*(i+1),DeltaY*(CountDevice+1)])
for i in range(len(ParameterValueList)):
for j in range(len(ParameterUnitList)):
ParameterValueList[i][j]=ParameterValueList[i][j]+ParameterUnitList[j]
TempDict={PDKInfoRaw[key]:{'ParameterNameList':ParameterNameList,'ParameterValueList':ParameterValueList,'LocationList':LocationList,'ParameterUnitList':ParameterUnitList}} #create link by key
DeviceSet.update(TempDict)
CountDevice+=1
except IndexError as e:
ErrorDeviceSet.update({key:e})
#output like DeviceSet={Pcell:{ParameterNameList:ParameterValueList}}
#we want DeviceSet={Pcell:ParameterNameList,ParameterValueList,LocationList}
return DeviceSet,PDKInfoDict #,ErrorDeviceSet,DeviceDict #,EnterInfo,DeviceDict,PDKInfoRaw
#1.Some PDK contains other format of ael code file that is not nesscesary to used
#2.Some PDK contains old version of file that may lead to double definition
'''
def DataStructureTransform(DeviceParaListSet):
DeviceParaDictSet={}
ListLen=len(DeviceParaListSet)
i=0
while(i<ListLen):
try:
item=DeviceParaListSet[i]
DeviceName=item[0]
ParaList=item[1:]
DeviceParaDictSet.update({DeviceName:ParaList})
except IndexError:
pass
return 'IndexError: out of range'
i+=1
return DeviceParaDictSet
'''
#================== Test Case =============================
def Test(Setting):
WorkPath=Setting['WorkPath']
ScriptPath=Setting['ScriptPath']
Num=1
# Generate DeviceList from PDK
OutputExcelPath=Setting['WorkPath']+Setting['DeviceListPath']
DocPath=Setting['WorkPath']+Setting['ComponentArtworkPath']
WritePDKComponentInfo2Excel(DocPath,OutputExcelPath,Setting)
#Enter Info
#Print('Enter the QA library name that you have create in ADS workspace, if haven\'t, do it :')
QALibName='QA' # define outside
InfoDict={'DeltaLocation':[300,300]}
DeviceSet,PDKInfoDict=InfoCat(Num,InfoDict,Setting)
EnterInfo={'LibName':QALibName,'CellName':"QA_Cell",'Setting':1}
AelPath=WorkPath+ScriptPath+'QA_autoplacement1.ael'
AelScriptGeneration(AelPath,DeviceSet,PDKInfoDict,EnterInfo)
InfoDict={'DeltaLocation':[10,10]}
DeviceSet,PDKInfoDict=InfoCat(Num,InfoDict,Setting)
EnterInfo={'LibName':QALibName,'CellName':"QA_Cell",'Setting':2}
AelPath=WorkPath+ScriptPath+'QA_autoplacement2.ael'
AelScriptGeneration(AelPath,DeviceSet,PDKInfoDict,EnterInfo)
def Test1(Setting):
WorkPath=Setting['WorkPath']
ScriptPath=Setting['ScriptPath']
Num=60
# Generate DeviceList from PDK
OutputExcelPath=Setting['WorkPath']+Setting['DeviceListPath']
DocPath=Setting['WorkPath']+Setting['ComponentArtworkPath']
# WritePDKComponentInfo2Excel(DocPath,OutputExcelPath,Setting)
#Enter Info
#Print('Enter the QA library name that you have create in ADS workspace, if haven\'t, do it :')
QALibName='QA' # define outside
InfoDict={'DeltaLocation':[300,300]} #for Layout
DeviceSet,PDKInfoDict=InfoCat(Num,InfoDict,Setting)
EnterInfo={'LibName':QALibName,'CellName':"QA_Cell",'Setting':1}
AelPath=WorkPath+ScriptPath+'QA_autoplacement1.ael'
AelScriptGeneration(AelPath,DeviceSet,PDKInfoDict,EnterInfo)
InfoDict={'DeltaLocation':[10,10]} #for schematic
DeviceSet,PDKInfoDict=InfoCat(Num,InfoDict,Setting)
EnterInfo={'LibName':QALibName,'CellName':"QA_Cell",'Setting':2}
AelPath=WorkPath+ScriptPath+'QA_autoplacement2.ael'
AelScriptGeneration(AelPath,DeviceSet,PDKInfoDict,EnterInfo)
Test1(Setting)