事情是這樣的,SoC工程師的一項(xiàng)典型工作就是集成。俗稱連連看。
當(dāng)然除了連連看還有一些集成級(jí)的代碼需要設(shè)計(jì),比如CRG,regfile,ahb/apb/local bus decoder,axi bus matrix/network等等。這些代碼很多是有vendor提供工具生成,或者用腳本生成。集成工作我們前面介紹的GVim插件已經(jīng)實(shí)現(xiàn)了自動(dòng)化。總之就是能不手寫(xiě)代碼就不手寫(xiě)代碼。
因?yàn)橹灰侨耸謱?xiě)就有可能出錯(cuò),review不可能每一行都能review到,輸入給代碼生成腳本的文件一定是簡(jiǎn)潔明了,方便review的。而且一旦經(jīng)過(guò)一次項(xiàng)目洗禮,后面就閉著眼睛用,一勞永逸。
那么今天給大家分享一個(gè)編寫(xiě)Python腳本生成一個(gè)ahb decoder的腳本。首先分析一下ahb decoder的原理。主要就兩大部分。
第一部分就是slave的sel信號(hào)decoder。根據(jù)地址空間劃分,選擇選擇不同的地址段。
第二部分是rdata和response信號(hào)的返回mux。
地址decoder部分是共用的。decoder和mux可以歸納出一些編碼模版,即slave的數(shù)據(jù)量再增加,同一段代碼模版可以復(fù)用,只是代碼量增加。這種有固定套路的代碼完全可以借助腳本生成。
規(guī)定一下腳本的輸入文件形式,比如表格輸入。
ahb decoder橋是1路ahb slave接口入,多路ahb master接口輸出,表格中填寫(xiě)master接口輸出名,起始地址段,結(jié)束地址段。這樣review時(shí)候只需要review這個(gè)表格即可。
接下來(lái)是python腳本開(kāi)發(fā)
安裝pandas。用于表格處理。
?
sudo apt install python3-pip sudo pip install pandas
?
缺啥庫(kù),再用pip安裝即可。
接下來(lái)就開(kāi)始生成代碼,這類代碼生成套路就是根據(jù)表格提供信息,打印代碼模版替換其中的關(guān)鍵詞。我把要生成的代碼一行一行追加到一個(gè)列表中,然后再一行一行打印到一個(gè)新的.v文件中。
首先用pandas讀取表格,根據(jù)輸入的表格路徑,sheet name,讀取當(dāng)前sheet的數(shù)據(jù)。
?
if para_list[2] == "dec_gen": df = pd.read_excel(para_list[0], sheet_name = para_list[1]) dec_corpus = df.values.tolist() print(" all data:") print (df) dec_ser = pd.Series(dec_corpus) #print(dec_ser) dec_gen(para_list, dec_corpus, dec_ser)
?
pandas會(huì)處理成二維列表。
然后打開(kāi)一個(gè).v文件,文件名也是用戶自己輸入 。創(chuàng)建一個(gè)空列表,往里面塞代碼。
?
fp = open(para_list[1]+".v", "w") print_line = []
?
給代碼生成頭文件,顯得專業(yè)些。年份,日期,filename等自動(dòng)匹配生成。
?
print_line.append("http:// +FHDR----------------------------------------------------------------------------") print_line.append("http:// Copyright (c) "+year+" SiliconPeasant.") print_line.append("http:// ALL RIGHTS RESERVED Worldwide") print_line.append("http:// ") print_line.append("http:// Author : "+user) print_line.append("http:// Email : ninghechuan@foxmail.com") print_line.append("http:// Created On : "+date1+" "+time) print_line.append("http:// Last Modified : "+date1+" "+time) print_line.append("http:// File Name : "+filename) print_line.append("http:// Description :") print_line.append("http:// ") print_line.append("http:// ---------------------------------------------------------------------------------") print_line.append("http:// Modification History:") print_line.append("http:// Date By Version Change Description") print_line.append("http:// ---------------------------------------------------------------------------------") print_line.append("http:// "+date1+" "+user+" 1.0 Original") print_line.append("http:// -FHDR----------------------------------------------------------------------------")
?
然后往列表里塞Verilog代碼,固定的代碼模版,直接輸入,比如我們要生成的ahb decoder只有一組ahb slave接口,名字暫時(shí)固定,未開(kāi)放給用戶。
?
print_line.append("module "+para_list[1]+"(") print_line.append(" input hclk,") print_line.append(" input hresetn,") print_line.append(" //slave") print_line.append(" input ahb_s_hsel,") print_line.append(" input [31:0] ahb_s_haddr,") print_line.append(" input [1:0] ahb_s_htrans,") print_line.append(" input ahb_s_hwrite,") print_line.append(" input [2:0] ahb_s_hsize,") print_line.append(" input [2:0] ahb_s_hburst,") print_line.append(" input [3:0] ahb_s_hprot,") print_line.append(" input [31:0] ahb_s_hwdata,") print_line.append(" input ahb_s_hready_in,") print_line.append(" output reg [31:0] ahb_s_hrdata,") print_line.append(" output reg ahb_s_hready,") print_line.append(" output reg [1:0] ahb_s_hresp,")
?
接下來(lái)追加decoder輸出的master的代碼,根據(jù)表格第一列填寫(xiě)的數(shù)據(jù),給輸出的ahb master接口加上用戶自定義關(guān)鍵詞。
?
count = 0 for dec_info in dec_corpus: count += 1 print_line.append(" //"+dec_info[0]) print_line.append(" output reg ahb_"+dec_info[0].lower()+"_hsel,") print_line.append(" output reg [31:0] ahb_"+dec_info[0].lower()+"_haddr,") print_line.append(" output reg [1:0] ahb_"+dec_info[0].lower()+"_htrans,") print_line.append(" output reg ahb_"+dec_info[0].lower()+"_hwrite,") print_line.append(" output reg [2:0] ahb_"+dec_info[0].lower()+"_hsize,") print_line.append(" output reg [2:0] ahb_"+dec_info[0].lower()+"_hburst,") print_line.append(" output reg [3:0] ahb_"+dec_info[0].lower()+"_hprot,") print_line.append(" output reg [31:0] ahb_"+dec_info[0].lower()+"_hwdata,") print_line.append(" output reg ahb_"+dec_info[0].lower()+"_hready_in,") print_line.append(" input [31:0] ahb_"+dec_info[0].lower()+"_hrdata,") print_line.append(" input ahb_"+dec_info[0].lower()+"_hready,") print_line.append(" input [1:0] ahb_"+dec_info[0].lower()+"_hresp,")
?
追加decoder部分代碼。根據(jù)地址高位產(chǎn)生一個(gè)index為選擇slave。
?
print_line.append(" always @(*)begin") count = 0 for dec_info in dec_corpus: start_addr_list = list(dec_info[1]) end_addr_list = list(dec_info[2]) #print(start_addr_list) #print(end_addr_list) start_dec_num = start_addr_list[2] end_dec_num = end_addr_list[2] if count == 0: print_line.append(" if(ahb_s_haddr[15:12] >= 4'h"+start_dec_num+" && ahb_s_haddr[15:12] <= 4'h"+end_dec_num+")") else: print_line.append(" else if(ahb_s_haddr[15:12] >= 4'h"+start_dec_num+" && ahb_s_haddr[15:12] <= 4'h"+end_dec_num+")") print_line.append(" addroutport[3:0] = 4'h"+str(count)+";") count += 1 print_line.append(" else ") print_line.append(" addroutport[3:0] = 4'hf;") print_line.append(" end")
?
生成每個(gè)slave的sel decoder代碼
?
count = 0 for dec_info in dec_corpus: print_line.append(" 4'h"+str(count)+":begin") print_line.append(" ahb_"+dec_info[0].lower()+"_hsel = 1'b1;") print_line.append(" ahb_"+dec_info[0].lower()+"_haddr[31:0] = ahb_s_haddr;") print_line.append(" ahb_"+dec_info[0].lower()+"_htrans[1:0] = ahb_s_htrans;") print_line.append(" ahb_"+dec_info[0].lower()+"_hwrite = ahb_s_hwrite;") print_line.append(" ahb_"+dec_info[0].lower()+"_hsize[2:0] = ahb_s_hsize;") print_line.append(" ahb_"+dec_info[0].lower()+"_hburst[2:0] = ahb_s_hburst;") print_line.append(" ahb_"+dec_info[0].lower()+"_hprot[3:0] = ahb_s_hprot;") print_line.append(" ahb_"+dec_info[0].lower()+"_hwdata[31:0] = ahb_s_hwdata;") print_line.append(" ahb_"+dec_info[0].lower()+"_hready_in = ahb_s_hready_in;") print_line.append(" end") count += 1
?
生成rdata和response mux代碼
?
print_line.append(" ") print_line.append(" always @(*)begin") print_line.append(" if(ahb_s_hsel)begin") print_line.append(" case(addroutport_d[3:0])") count = 0 for dec_info in dec_corpus: print_line.append(" 4'd0:begin") print_line.append(" ahb_s_hrdata[31:0] = ahb_"+dec_info[0].lower()+"_hrdata;") print_line.append(" ahb_s_hready = ahb_"+dec_info[0].lower()+"_hready;") print_line.append(" ahb_s_hresp[1:0] = ahb_"+dec_info[0].lower()+"_hresp;") print_line.append(" end") print_line.append(" default:begin") print_line.append(" ahb_s_hrdata[31:0] = 32'h0;") print_line.append(" ahb_s_hready = 1'h1;") print_line.append(" ahb_s_hresp[1:0] = 2'h0;") print_line.append(" end") print_line.append(" endcase") print_line.append(" end") print_line.append(" end")
?
將列表中的文件,循環(huán)打印出到.v中,最后一行加上endmodule。
?
for line in print_line: #print(line) fp.write(line) fp.write(' ') fp.write(' ') fp.write('endmodule') fp.close()
?
最后再加一個(gè)help函數(shù)
?
def help(): print("############## help ####################") print("########################################") print("generate dec_gen module") print("xxb_decoder.py excel_path sheet_name dec_gen") print("########################################")
?
輸入命令
?
python3 xxb_decoder.py -h
?
使用說(shuō)明,咱們就是說(shuō),就是一個(gè)專業(yè)配套齊全。
使用命令
?
python3 xxb_decoder.py ./ahb_dec.xlsx ahb_dec dec_gen
?
本篇只是提供一個(gè)思路,生成代碼機(jī)制并不完善,地址譯碼邏輯暫時(shí)還有限制,不過(guò)照這個(gè)思路我們就可以生成很多代碼了,只要它有規(guī)律就能生成。真正做到成為一個(gè)不寫(xiě)Verilog的芯片工程師。這個(gè)腳本的源代碼和Excel文件放GitHub上了。感興趣的朋友可以留言多多交流。
https://github.com/NingHeChuan/Silicon_Peasant/tree/master/script
最后
寫(xiě)Python的時(shí)候,有些奇妙的感覺(jué),和Verilog的思維方式完全不同,一種久違的感覺(jué),那種代碼是一行一行的執(zhí)行,出錯(cuò)debug,加很多print然后分析。最后調(diào)試出來(lái)后,是另外一種快樂(lè)。
評(píng)論