makeBMM のソースコード

#!
# -*- coding: utf-8 -*-
# Copyright (C) 2015 TOPS SYSTEMS
### @file makeBMM.py
### @brief makeBMM
###
### Vivado siteロケーションファイルをBMMファイルに変換する
### Vivado siteロケーションファイルをMMIファイルに変換する
###
### Contact: izumida@topscom.co.jp
###
### @author: M.Izumida
### @date: July 6, 2015
###
# DM サポート版
# v02r01 2016/05/30 MMI サポート トライアル版
# v02r02 2016/07/07 Ultra Scale IM 8bit 対応
#
# Written for Python 2.7 (NOT FOR 3.x)

#=======================================================================
# インポート宣言
from __future__ import division
import sys
import re
import argparse
import os
from lxml import etree
#from PIL import Image
from datetime import datetime
#=======================================================================
# バージョン文字列
versionSTR = "makeBMM.py v02r02 Tops Systems (pgm by mpi)"
__author__ = "mpi"
__date__ = "July 7, 2016"
#=======================================================================
# 共通サブルーチン
#-------------------------------------------------------------------
def errPrint(mes):
    """errPrint.

    エラー出力へのメッセージ表示
    後の始末はその後で別に書くこと
    """
    sys.stderr.write(mes)
    sys.stderr.write('\n')

#-------------------------------------------------------------------
def stdExceptionHandler(mes):
    """standard Exception Handler.

    エラーメッセージを送出し、デバッグのための情報を出力する
    """
    errPrint("Exception Captured: " + str(mes))
    errPrint("Type:" + str(sys.exc_info()[0]))
    errPrint("Value:" + str(sys.exc_info()[1]))

#-------------------------------------------------------------------
def tryIntParse(st, dval, rdx=10):
    """try Parse string to Integer

    文字列stをパースして整数化できれば値を返す、できなければデフォルト値dvalを返す
    :param str st: 変換対象文字列
    :param str dval: 変換不能時のデフォルト値
    :param int rdx: 基数、指定しないと10進
    :return: 整数に変換した値
    :rtype: int
    """
    try:
        work = int(st, rdx)
    except:
        return dval
    return work

#-------------------------------------------------------------------
def findCount(pat, sss):
    """find counter.
    
    パターンのマッチ回数を列挙するクラス
    :param str pat: 検索するパターン
    :param str sss: 検索対象文字列
    :return: マッチ回数
    :rtype: int
    """
    cnt = 0
    pos = 0
    while pos >= 0:
        pos = sss.find(pat, pos)
        if pos >= 0:
            cnt += 1
            pos += 1
        if pos < 0:
            break
    return cnt

#-------------------------------------------------------------------
def getInstIM(core, Loc, num, site):
    """get IM site string.
    
    """
    header="inst_SMYLEvideo_Gen2_8core/inst_IM1/IM"
    mid1="/inst_im_dp/inst_im_mem/IM_"
    mid2A="/U_im_bram_32x4096_"
    mid2B="/U0/inst_blk_mem_gen/gnativebmg.native_blk_mem_gen/valid.cstr/ramloop["
    mid3="].ram.r/prim_init.ram/DEVICE_7SERIES.NO_BMM_INFO.SP.SIMPLE_PRIM36.ram "
    if   (Loc=="LL") and (num=="0"):
        bitPos = "[8:0]"
    elif (Loc=="LL") and (num=="1"):
        bitPos = "[17:9]"
    elif (Loc=="LL") and (num=="2"):
        bitPos = "[26:18]"
    elif (Loc=="LL") and (num=="3"):
        bitPos = "[35:27]"
    elif (Loc=="LH") and (num=="0"):
        bitPos = "[44:36]"
    elif (Loc=="LH") and (num=="1"):
        bitPos = "[53:45]"
    elif (Loc=="LH") and (num=="2"):
        bitPos = "[62:54]"
    elif (Loc=="LH") and (num=="3"):
        bitPos = "[71:63]"
    elif (Loc=="HL") and (num=="0"):
        bitPos = "[80:72]"
    elif (Loc=="HL") and (num=="1"):
        bitPos = "[89:81]"
    elif (Loc=="HL") and (num=="2"):
        bitPos = "[98:90]"
    elif (Loc=="HL") and (num=="3"):
        bitPos = "[107:99]"
    elif (Loc=="HH") and (num=="0"):
        bitPos = "[116:108]"
    elif (Loc=="HH") and (num=="1"):
        bitPos = "[125:117]"
    elif (Loc=="HH") and (num=="2"):
        bitPos = "[134:126]"
    elif (Loc=="HH") and (num=="3"):
        bitPos = "[143:135]"
    else:
        bitPos = "[N/A:N/A]"
    mid4=" PLACED="
    trailer=";"
    return header+core+mid1+Loc+mid2A+Loc+mid2B+num+mid3+bitPos+ mid4+site+trailer

#-------------------------------------------------------------------
def getInstIM_U(core, Loc, num, site):
    """get IM site string, Ultra Scale.
    
    """
    header="inst_SMYLEvideo_Gen2_8core/inst_IM1/IM"
    mid1="/inst_im_dp/inst_im_mem/IM_"
    mid2A="/U_im_bram_32x4096_"
    mid2B="/U0/inst_blk_mem_gen/gnativebmg.native_blk_mem_gen/valid.cstr/ramloop["
    mid3="].ram.r/prim_init.ram/DEVICE_7SERIES.NO_BMM_INFO.SP.SIMPLE_PRIM36.ram "
    if   (Loc=="LL") and (num=="0"):
        bitPos = "[7:0]"
    elif (Loc=="LL") and (num=="1"):
        bitPos = "[15:8]"
    elif (Loc=="LL") and (num=="2"):
        bitPos = "[23:16]"
    elif (Loc=="LL") and (num=="3"):
        bitPos = "[31:24]"
    elif (Loc=="LH") and (num=="0"):
        bitPos = "[39:32]"
    elif (Loc=="LH") and (num=="1"):
        bitPos = "[47:40]"
    elif (Loc=="LH") and (num=="2"):
        bitPos = "[55:48]"
    elif (Loc=="LH") and (num=="3"):
        bitPos = "[63:56]"
    elif (Loc=="HL") and (num=="0"):
        bitPos = "[71:64]"
    elif (Loc=="HL") and (num=="1"):
        bitPos = "[79:72]"
    elif (Loc=="HL") and (num=="2"):
        bitPos = "[87:80]"
    elif (Loc=="HL") and (num=="3"):
        bitPos = "[95:88]"
    elif (Loc=="HH") and (num=="0"):
        bitPos = "[103:96]"
    elif (Loc=="HH") and (num=="1"):
        bitPos = "[111:104]"
    elif (Loc=="HH") and (num=="2"):
        bitPos = "[119:112]"
    elif (Loc=="HH") and (num=="3"):
        bitPos = "[127:120]"
    else:
        bitPos = "[N/A:N/A]"
    mid4=" PLACED="
    trailer=";"
    return header+core+mid1+Loc+mid2A+Loc+mid2B+num+mid3+bitPos+ mid4+site+trailer

#-------------------------------------------------------------------
def getInstDM(Loc, num, site):
    """get DM site string.
    
    nL : 0..7
    nN : 0..31 <= 8で割った商でビットレーンが決まる
    nN : 0..31 <= 8で割った余りでアドレスブロックが決まる
    """
    header="inst_SMYLEvideo_Gen2_8core/DM["
    mid1="].ram.r/BPOS["
    mid2="]/prim_init.ram/DEVICE_7SERIES.NO_BMM_INFO.SP.SIMPLE_PRIM32.ram "
    trailer=";"
    nL = tryIntParse(Loc, 0)
    nN = tryIntParse(num, 0)
    bytePos = (nL * 4) + (nN // 8)
    BL = nN % 8
    bitPos = "[" + str(bytePos*8+7) + ":" + str(bytePos*8) + "]"
    mid4=" PLACED="
    result = (BL*32+bytePos, header + str(BL) + mid1 + str(bytePos) + mid2 + bitPos + mid4 + site + trailer)
#    print result
    return result

#-------------------------------------------------------------------
def getBitPosDM(Loc, num, site):
    """get DM Bit Position.
    
    nL : 0..7
    nN : 0..31 <= 8で割った商でビットレーンが決まる
    nN : 0..31 <= 8で割った余りでアドレスブロックが決まる
    :return: [site, beginBit, endBit]
    :rtype: list
    """
    nL = tryIntParse(Loc, 0)
    nN = tryIntParse(num, 0)
    bytePos = (nL * 4) + (nN // 8)
    #BL = nN % 8
    bitPos = [ site, str(bytePos*8+7), str(bytePos*8)]
    return bitPos

#-------------------------------------------------------------------
def getBitPosIM(Loc, num, site):
    """get IM Bit Position.
    
    :return: [site, beginBit, endBit]
    :rtype: list
    """
    if   (Loc=="LL") and (num=="0"):
        return [site, 0, 8]
    elif (Loc=="LL") and (num=="1"):
        return [site, 9, 17]
    elif (Loc=="LL") and (num=="2"):
        return [site, 18, 26]
    elif (Loc=="LL") and (num=="3"):
        return [site, 27, 35]
    elif (Loc=="LH") and (num=="0"):
        return [site, 36, 44]
    elif (Loc=="LH") and (num=="1"):
        return [site, 45, 53]
    elif (Loc=="LH") and (num=="2"):
        return [site, 54, 62]
    elif (Loc=="LH") and (num=="3"):
        return [site, 63, 71]
    elif (Loc=="HL") and (num=="0"):
        return [site, 72, 80]
    elif (Loc=="HL") and (num=="1"):
        return [site, 81, 89]
    elif (Loc=="HL") and (num=="2"):
        return [site, 90, 98]
    elif (Loc=="HL") and (num=="3"):
        return [site, 99, 107]
    elif (Loc=="HH") and (num=="0"):
        return [site, 108, 116]
    elif (Loc=="HH") and (num=="1"):
        return [site, 117, 125]
    elif (Loc=="HH") and (num=="2"):
        return [site, 126, 134]
    elif (Loc=="HH") and (num=="3"):
        return [site, 135, 143]
    else:
        return [site, 0, 0]

#-------------------------------------------------------------------
def getBitPosIM_U(Loc, num, site):
    """get IM Bit Position, Ultra Scale.
    
    :return: [site, beginBit, endBit]
    :rtype: list
    """
    if   (Loc=="LL") and (num=="0"):
        return [site, 0, 7]
    elif (Loc=="LL") and (num=="1"):
        return [site, 8, 15]
    elif (Loc=="LL") and (num=="2"):
        return [site, 16, 23]
    elif (Loc=="LL") and (num=="3"):
        return [site, 24, 31]
    elif (Loc=="LH") and (num=="0"):
        return [site, 32, 39]
    elif (Loc=="LH") and (num=="1"):
        return [site, 40, 47]
    elif (Loc=="LH") and (num=="2"):
        return [site, 48, 55]
    elif (Loc=="LH") and (num=="3"):
        return [site, 56, 63]
    elif (Loc=="HL") and (num=="0"):
        return [site, 64, 71]
    elif (Loc=="HL") and (num=="1"):
        return [site, 72, 79]
    elif (Loc=="HL") and (num=="2"):
        return [site, 80, 87]
    elif (Loc=="HL") and (num=="3"):
        return [site, 88, 95]
    elif (Loc=="HH") and (num=="0"):
        return [site, 96, 103]
    elif (Loc=="HH") and (num=="1"):
        return [site, 104, 111]
    elif (Loc=="HH") and (num=="2"):
        return [site, 112, 119]
    elif (Loc=="HH") and (num=="3"):
        return [site, 120, 127]
    else:
        return [site, 0, 0]

#=======================================================================
# 解析オプション クラス
class Options:
    """Options Class.

    グローバルオプションを保持するクラス
    """
    pass

#=======================================================================
# Siteファイルリーダクラス
[ドキュメント]class siteReader: """Site File Reader Class. Siteファイルを読み取ってBMMを生成するためのクラス """ #-------------------------------------------------------------------- def __init__(self, fnam, bname): """site File Reader Constructor コンストラクタ """ self.siteFname = fnam self.bmmName = bname # self.errorMessage = "" self.errorFlag = False # self.searchSite = True self.lNumber = 1 self.work = [] self.core = "" self.loc = "" self.num = "" self.site = "" # self.p0search = re.compile('IM0/IM([0-7])\*IM_(LL|LH|HL|HH)\*ramloop\[([0-7])\]') self.p1match = re.compile('RAMB36_(X[0-9]+Y[0-9]+)') #デバッグ self.debug = False self.verbose = False #MMI option self.mmi = False self.mmiDic = dict() self.mmiWork = [] self.ultra = False #--------------------------------------------------------------------
[ドキュメント] def read(self): """read method ファイルから行をリードして処理するメソッド """ try: with open(self.siteFname, 'r') as f: for line in f: if self.rLine(line): break self.lNumber += 1 except: stdExceptionHandler("ERROR: in file reading = " + self.siteFname) return False return True
#--------------------------------------------------------------------
[ドキュメント] def rLine(self, lin): """Read Line method 読み取った1行を処理するメソッド エラーならTrueを返す そうでない場合はFalseを返す """ if self.searchSite: p0 = self.p0search.search(lin) if p0: self.core = p0.group(1) self.loc = p0.group(2) self.num = p0.group(3) if (self.loc=="LL") and (self.num=="0"): self.work=[] self.mmiWork=[] self.searchSite = False else: p1 = self.p1match.match(lin) if p1: self.site = p1.group(1) if self.ultra: self.work.append(getInstIM_U(self.core, self.loc, self.num, self.site)) self.mmiWork.append(getBitPosIM_U(self.loc, self.num, self.site)) else: self.work.append(getInstIM(self.core, self.loc, self.num, self.site)) self.mmiWork.append(getBitPosIM(self.loc, self.num, self.site)) self.searchSite = True if (self.loc=="HH") and (self.num=="3"): if self.mmi: self.writeMMI() else: self.writeBMM()
#--------------------------------------------------------------------
[ドキュメント] def writeBMM(self): """Write BMM file. BMMファイルを出力する """ fnam = self.bmmName + self.core + ".BMM" try: with open(fnam, 'w') as f: f.write("ADDRESS_SPACE c00im RAMB36 WORD_ADDRESSING [0x0000:0xFFFF]\n") f.write("\n") f.write("BUS_BLOCK\n") f.write("\n") for item in self.work: f.write(item) f.write("\n") f.write("\n") f.write("END_BUS_BLOCK;\n"); f.write("\n") f.write("END_ADDRESS_SPACE;\n"); except: stdExceptionHandler("ERROR: in file writing = " + fnam) return False return True
#--------------------------------------------------------------------
[ドキュメント] def writeMMI(self): """Write MMI file. MMIファイルを出力する """ fnam = self.bmmName + self.core + ".mmi" mmi = mmiWriter(fnam, 1) iPath = "IM" + str(self.core) aSpace = "inst_SMYLEvideo_Gen2_8core_IM_" + str(self.core) mmi.setPathAndSpace(iPath, aSpace) # mmiWorkを舐める for item in self.mmiWork: mmi.setBitLane(item[0], str(item[2]), str(item[1])) return mmi.writeMMI()
#======================================================================= # DM Siteファイルリーダクラス
[ドキュメント]class dmSiteReader(siteReader): """DM Site File Reader Class. DM Siteファイルを読み取ってBMMを生成するためのクラス """ #-------------------------------------------------------------------- def __init__(self, fnam, bname, blkNum): """DM site File Reader Constructor コンストラクタ """ siteReader.__init__(self, fnam, bname) # self.dmDic = dict() self.blkNum = blkNum # ADDRESS RANGE 0:00000-1FFFF, ... , 7:E0000-FFFFF # self.p0search = re.compile('\*DM\*DM([0-7])\*ramloop\[([0-9]+)\]') self.p1match = re.compile('RAMB36_(X[0-9]+Y[0-9]+)') #--------------------------------------------------------------------
[ドキュメント] def rLine(self, lin): """Read Line method 読み取った1行を処理するメソッド エラーならTrueを返す そうでない場合はFalseを返す """ if self.searchSite: p0 = self.p0search.search(lin) if p0: self.loc = p0.group(1) self.num = p0.group(2) self.searchSite = False else: p1 = self.p1match.match(lin) if p1: self.site = p1.group(1) temp = getInstDM(self.loc, self.num, self.site) self.dmDic[temp[0]] = temp[1] self.mmiDic[temp[0]] = getBitPosDM(self.loc, self.num, self.site) self.searchSite = True if (self.loc=="7") and (self.num=="31"): if self.mmi: self.writeMMI() else: self.writeBMM()
#--------------------------------------------------------------------
[ドキュメント] def writeBMM(self): """Write BMM file. BMMファイルを出力する """ fnam = self.bmmName + str(self.blkNum) + ".BMM" try: with open(fnam, 'w') as f: f.write("ADDRESS_SPACE c00dm RAMB32 WORD_ADDRESSING [0x00000:0x1FFFF]\n") f.write("\n") f.write("BUS_BLOCK\n") f.write("\n") startBLK = self.blkNum * 32 for item in range(startBLK, startBLK+32): f.write(self.dmDic[item]) f.write("\n") f.write("\n") f.write("END_BUS_BLOCK;\n"); f.write("\n") f.write("END_ADDRESS_SPACE;\n"); except: stdExceptionHandler("ERROR: in file writing = " + fnam) return False return True
#--------------------------------------------------------------------
[ドキュメント] def writeMMI(self): """Write MMI file. MMIファイルを出力する """ fnam = self.bmmName + str(self.blkNum) + ".mmi" mmi = mmiWriter(fnam) iPath = "DM" + str(self.blkNum) aSpace = "inst_SMYLEvideo_Gen2_8core_DM_" + str(self.blkNum) mmi.setPathAndSpace(iPath, aSpace) # mmiDicを舐める startBLK = self.blkNum * 32 for idx in range(startBLK, startBLK+32): item = self.mmiDic[idx] mmi.setBitLane(item[0], item[1], item[2]) return mmi.writeMMI()
#======================================================================= # MMI ファイルライタクラス class mmiWriter: """MMI File Writer Class. MMIファイルの生成を行うためのクラス """ #-------------------------------------------------------------------- def __init__(self, fnam, opt=0): """MMI File Writer Constructor コンストラクタ。 opt=0でデータメモリ、opt=1でコードメモリ """ self.xmlFileName = fnam # xml tree self.xmlRoot = etree.Element("MemInfo", Version="1", Minor="0") self.bitLaneDic = dict() self.widthDic = dict() self.adrDic = dict() self.parDic = dict() self.ready = False self.BeginAddress = "0" if opt == 0: self.EndAddress = "131071" self.bramType = "RAMB32" else: self.EndAddress = "65535" self.bramType = "RAMB32" #self.bramType = "RAMB36" # self.verbose = False self.debug = False #-------------------------------------------------------------------- def setPathAndSpace(self, iPath, aSpace): """set InstPath and AddressSpace InstPathとAddressSpaceをセットするメソッド """ self.xmlProcessor = etree.SubElement(self.xmlRoot, "Processor", Endianness="Little", InstPath=iPath) self.xmlAddrSpace = etree.SubElement(self.xmlProcessor, "AddressSpace", Name=aSpace, Begin=self.BeginAddress, End=self.EndAddress) self.xmlBusBlock = etree.SubElement(self.xmlAddrSpace, "BusBlock") self.xmlConfig = etree.SubElement(self.xmlRoot, "Config") self.xmlOption = etree.SubElement(self.xmlConfig, "Option", Name="Part", Val="xcvu095-ffva2104-2-e-es2") self.ready = True #-------------------------------------------------------------------- def setBitLane(self, place, msb, lsb): """set Bit Lane Bit Laneをセットするメソッド """ if self.ready: self.bitLaneDic[place] = etree.SubElement(self.xmlBusBlock, "BitLane", MemType=self.bramType, Placement=place) self.widthDic[place] = etree.SubElement(self.bitLaneDic[place], "DataWidth", MSB=msb, LSB=lsb) self.adrDic[place] = etree.SubElement(self.bitLaneDic[place], "AddressRange", Begin=self.BeginAddress, End=self.EndAddress) self.parDic[place] = etree.SubElement(self.bitLaneDic[place], "Parity", ON="false", NumBits="0") #-------------------------------------------------------------------- def writeMMI(self): """write MMI File MMI ファイルを書き込むメソッド 書き込み成功すれば真、失敗すれば偽 """ try: with open(self.xmlFileName, 'w') as f: f.write(etree.tostring(self.xmlRoot, xml_declaration=True, encoding="UTF-8", pretty_print=True)) return True except: stdExceptionHandler("ERROR: Writing XML : " + self.xmlFileName) return False #======================================================================= # メインプログラム def main(): """main. メインプログラム """ #----------------------------------------------------------------------- # コマンドラインオプション処理 # parser = argparse.ArgumentParser(description='make BMM file.') parser.add_argument('--SITE', nargs=1, help='Specify SITE file name.') parser.add_argument('--DMSITE', nargs=1, help='Specify DM SITE file name.') parser.add_argument('--DMB', nargs=1, help='Specify DM BLOCK number 0-7:128K block.') parser.add_argument('--BMM', nargs=1, help='Specify BMM file base name.') parser.add_argument('-x', dest='mmi', help='Output MMI mode. Force Ultra Scale option.', action='store_true', default=False) parser.add_argument('-u', dest='ultra', help='Ultra Scale option.', action='store_true', default=False) parser.add_argument('-v', dest='verbose', help='Verbose mode.', action='store_true', default=False) parser.add_argument('-d', dest='debug', help='Debug mode.', action='store_true', default=False) parser.add_argument('-V', dest='VERSION', help='Show Version, then exit', action='store_true', default=False) args = parser.parse_args() #----------------------------------------------------------------------- # Version 表示 # print versionSTR if args.VERSION: sys.exit(0) #----------------------------------------------------------------------- # ファイル名処理 # if args.BMM is not None: bmmFname = args.BMM[0] else: bmmFname = "CORE_" if args.SITE is not None: siteFname = args.SITE[0] if not os.path.isfile(siteFname): errPrint('ERROR: SITE FILE, NOT EXIST. ' + siteFname) sys.exit(1) if args.DMSITE is not None: dmSiteFname = args.DMSITE[0] if not os.path.isfile(dmSiteFname): errPrint('ERROR: DM SITE FILE, NOT EXIST. ' + dmSiteFname) sys.exit(1) if (args.SITE is None) and (args.DMSITE is None): errPrint('ERROR: NO SITE FILE.') sys.exit(1) #----------------------------------------------------------------------- # パラメータ処理 if args.DMB is not None: dmBlockN = tryIntParse(args.DMB[0], 0) else: dmBlockN = 5 #----------------------------------------------------------------------- # 実処理 # print "-"*50 # IM の処理 if args.SITE is not None: site = siteReader(siteFname, bmmFname) site.debug = args.debug site.verbose = args.verbose site.mmi = args.mmi if args.mmi: site.ultra = True else: site.ultra = args.ultra site.read() # DM の処理 if args.DMSITE is not None: dmsite = dmSiteReader(dmSiteFname, "DM_" + bmmFname, dmBlockN) dmsite.debug = args.debug dmsite.verbose = args.verbose dmsite.mmi = args.mmi if args.mmi: dmsite.ultra = True else: dmsite.ultra = args.ultra dmsite.read() #終了表示 today = datetime.today() print today.strftime("FINISH: %Y/%m/%d %H:%M:%S") #----------------------------------------------------------------------- # 正常終了 # sys.exit(0) #======================================================================= # メインプログラムの起動 if __name__ == "__main__": main()