ADS PDK Automation Part.1 Py Test Plan

5 篇文章 0 订阅
3 篇文章 0 订阅
'''
# 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)

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值