#!
# -*- 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()