如何使用Python實現(xiàn)FPGA編程“自動化”
之前讀到過一個公眾號文章,寫了關(guān)于《使用Python實現(xiàn)Vivado和Modelsim仿真的自動化》,連接https://mp.weixin.qq.com/s/2YR_LjpQNtJr9beqnCz7CA。根據(jù)該文章,基于自己的編程習慣和工作需要,我做了一些修改和便于自己編程的一些python代碼,這里和大家介紹一下。文章來源:http://www.zghlxwxcb.cn/news/detail-412960.html
一、自動生成tb文件
1、對于被生成的模塊的端口格式,必須按照以下格式,才能自動生成。
## entity top is
## Port (
## clk_in : in std_logic;
## rst : in std_logic;
## data_in : in std_logic;
## data_out: out std_logic_vector(7 downto 0);
## data_v : out std_logic_vector(7 downto 0);
## );
## end top;
2、預(yù)定義字符串列表,用于生成tb文件的基本框架,如下:
str1 = ['----------------------------------------------------------------------------------'
'-- Company: \n',
'-- Engineer: \n',
'-- \n',
'-- Create Date: \n',
'-- Design Name: \n',
'-- Module Name: - Behavioral\n',
'-- Project Name: \n',
'-- Target Devices: \n',
'-- Tool Versions: \n',
'-- Description: \n',
'-- \n',
'-- Dependencies: \n',
'-- \n',
'-- Revision:\n',
'-- Revision 0.01 - File Created\n',
'-- Additional Comments:\n',
'-- \n',
'----------------------------------------------------------------------------------\n',
'\n',
'\n',
'library IEEE;\n',
'use IEEE.STD_LOGIC_1164.ALL;\n',
'\n',
'-- Uncomment the following library declaration if using\n',
'-- arithmetic functions with Signed or Unsigned values\n',
'--use IEEE.NUMERIC_STD.ALL;\n',
'\n',
'-- Uncomment the following library declaration if instantiating\n',
'-- any Xilinx leaf cells in this code.\n',
'--library UNISIM;\n',
'--use UNISIM.VComponents.all;\n',
'\n',
'entity top is\n',
'-- port ();\n',
'end top;\n',
'\n',
'architecture Behavioral of top is\n',
'\n',
' constant period : TIME := 20 NS; --時鐘周期設(shè)置\n',
' constant CNT_MAX : INTEGER := 100 ; --cnt計數(shù)器最大值\n',
' signal cnt : INTEGER RANGE 0 TO CNT_MAX := 0 ; --復(fù)位設(shè)置\n',
'begin\n',
'-----------------------復(fù)位和時鐘生成----------------------------------------\n',
' clk_gen1 : PROCESS \n',
' BEGIN\n',
' clk_in <= \'1\';\n',
' WAIT FOR period/2;\n',
' clk_in <= \'0\';\n',
' WAIT FOR period/2;\n',
' END PROCESS;\n',
' \n',
' cnt : process(clk)\n',
' begin\n',
' if ( clk_in\'event and clk_in = \'1\') then\n',
' if (cnt = CNT_MAX) then\n',
' cnt <= 0;\n',
' else\n',
' cnt <= cnt + 1;\n',
' end if;\n',
' end if;\n',
' end process; \n',
'\n',
' reset : process(clk)\n',
' begin\n',
' if ( clk_in\'event and clk_in = \'1\') then\n',
' if cnt > CNT_MAX then\n',
' reset <= \'0\'; \n',
' else\n',
' reset <= \'1\'; --復(fù)位\n',
' end if;\n',
' end if;\n',
' end process;\n',
'\n',
'----------------------------UUT instantiate--------------------------\n',
' Port map(\n',
' );\n',
'\n',
'end Behavioral;']
3、讀取需要仿真的模塊頂層文件,讀取到環(huán)境列表中
vhdfile = open('\xxx.vhd','r') #讀取文件
vhdfilelines = vhdfile.readlines() #將文件列表寫入vhdfilelines中
vhdfile.close()
4、從vhdfilelines中循環(huán)查找端口、模塊名稱
entitystr = 'entity' #實體-識別字符串
endstr = 'end ' #實體結(jié)束部分-識別字符串
numend = 0 #端口開始的行號
numstart = 0 #端口結(jié)束的行號
for listline in vhdfilelines: #循環(huán)讀取文件列表
if entitystr in listline:
strline = listline
numstart = vhdfilelines.index(strline) #根據(jù)‘實體-識別字符串’查找對應(yīng)的行號
strline = strline.split(' ') #按照空格來分割
entityname = strline[1] #模塊名稱賦值
endstr = endstr + entityname #重新定義:實體結(jié)束部分-識別字符串
continue #跳出本次循環(huán)
if endstr in listline: #查找結(jié)束位置行號
strline = listline
numend = vhdfilelines.index(strline)
break #結(jié)束循環(huán)
5、提取要仿真的模塊端口信息
portlist = vhdfilelines[numstart+2:numend-1] #提取模塊實體部分
row_n = len(portlist) #確定長度
column_n = 2 #列表的列數(shù)
portmap = [['' for columns in range(2)] for rows in range(row_n)] #定義一個n行2列的空列表
for i in range(0,row_n): #for循環(huán)查找對應(yīng)信息
strline = portlist[i].split(':')
strline1 = strline[0].split(' ')
for j in range(0,len(strline1)):
if strline1[j] != '':
portmap[i][0] = strline1[j] #端口名稱賦值
break
portmap[i][1] = strline[1]
6、修改實體、結(jié)構(gòu)體部分的模塊名稱,如下:
ModuleName = "tb_" + entityname
str1[5] = "-- Module Name: " + ModuleName + " - Behavioral\n"
str1[32] = "entity " + ModuleName + " is\n"
str1[34] = "end " + ModuleName + ";\n"
str1[36] = "architecture Behavioral of " + ModuleName + " is\n"
7、生成tb文件中調(diào)試模塊的信號定義
for i in range(row_n-1,-1,-1): #逆序循環(huán)插入
strline = portmap[i][0] #信號名稱
strline = " "*tabnum + "signal " + strline #生成:" signal clk_in"
if portnamenum > len(strline): #判斷是否超出最大數(shù)
kongnum = portnamenum - len(strline)
else:
kongnum = 1
strline = strline + " "*kongnum + ":" #補入空格,對其到":"
if "in " in portmap[i][1]: #去掉第二段字符串的in、out方向關(guān)鍵字
strline1 = portmap[i][1].replace("in ","")
elif "out" in portmap[i][1]:
strline1 = portmap[i][1].replace("out","")
strline = strline + strline1 #拼接
str1.insert(38,strline) #插入
8、生成測試實體說明部分
str1.insert(38," "*tabnum + "end component;\n")
str1.insert(38," );\n")
for i in range(row_n-1,-1,-1): #倒序插入
strline = portmap[i][0] #
strline = " "*tabnum*2 + strline #
if portnamenum > len(strline): #判斷是否超出最大數(shù)
kongnum = portnamenum - len(strline)
else:
kongnum = 1
strline = strline + " "*kongnum + ":" #
strline = strline + portmap[i][1] #
str1.insert(38,strline) #
str1.insert(38," port(\n") #
str1.insert(38," "*tabnum + "component "+ entityname +"\n") #
9、生成測試實體的例化部分信號連接
numinst = str1.index(' Port map(\n') #由于上述插入多行,這里需要重新定為行號
str1.insert(numinst," UUT : "+ entityname +"\n") #
for i in range(row_n-1,-1,-1): #倒序插入
strline = portmap[i][0] #
strline = " "*tabnum*2 + strline #
if portnamenum > len(strline): #判斷是否超出最大數(shù)
kongnum = portnamenum - len(strline)
else:
kongnum = 1
strline = strline + " "*kongnum + "=> " #
strline = strline + portmap[i][0] + " "*(20-len(portmap[i][0]))#
if i != row_n-1:
strline = strline + ',\n'
else:
strline = strline + '\n'
str1.insert(numinst+2,strline) #
10、將修改好的激勵文件寫入到對應(yīng)的tb文件中
fileName= source_path + '\\' + ModuleName + '.vhd'
with open(fileName,'w',encoding='utf-8')as file:
file.writelines(str1)
二、對于vivado使用modelsim仿真時修改代碼不退出重新加載的方法
1、修改修改xxxxxxxx_Compile.do腳本,刪除quit -force,防止重新啟動仿真時關(guān)閉軟件
CompileDoFile = open('.\xxx_Compile.do', 'r')
CompileDoFileAllLines = CompileDoFile.readlines()
CompileDoFile.close()
CompileDoFile = open('.\xxx_Compile.do', 'w')
for EachLine in CompileDoFileAllLines:
if EachLine.find('quit -force') == -1:
CompileDoFile.writelines(EachLine)
CompileDoFile.close()
2、修改xxxxxxxx_simulate.do腳本,刪除run 1000ns和quit -force,添加log -r ./*,并且添加do {xxxx_compile.do}
SimulateDoFile = open('.\xxx_ simulate.do', 'r')
SimulateDoFileAllLines = SimulateDoFile.readlines()
SimulateDoFile.close()
dowrite = SimulateDoFileAllLines[8]
if "vsim" in dowrite:
SimulateDoFileAllLines.insert(8,"do {xxxx_compile.do}\n")
SimulateDoFile = open('.\xxx_ simulate.do', 'w')
for EachLine in SimulateDoFileAllLines:
#EachLine.find('run 1000ns')表示列表的某一元素中存在該find字符串,如果不存在,則返回-1
if EachLine.find('run 1000ns') == -1 and EachLine.find('quit -force') == -1:
SimulateDoFile.writelines(EachLine)
if ('log -r ./*\n' not in SimulateDoFileAllLines) == True:
SimulateDoFile.writelines('\nlog -r ./*\n')
SimulateDoFile.close()
總結(jié)
對于生成的tb文件使用了基本的python語言,對文件讀寫操作的語法,我以前也沒有怎么學(xué)過Python,但是經(jīng)過2天的學(xué)習,就掌握了基本語法,可以看懂程序。并進行編寫上述代碼。第一個程序解決了我們每次編寫仿真激勵時的麻煩,在自動生成的tb文件中,會自動生成時鐘和復(fù)位的代碼,也會將測試的模塊例化到tb文件中,開發(fā)人員只需完成模塊的其它輸入信號的仿真編寫。在自動重啟時加載修改后的代碼,并不會關(guān)閉modelsim界面,這樣也節(jié)省了我們開發(fā)人員的仿真時間??梢愿痈咝У霓k公。文章來源地址http://www.zghlxwxcb.cn/news/detail-412960.html
到了這里,關(guān)于如何使用Python實現(xiàn)FPGA編程“自動化”的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!