如何用Python写Verilog?

嵌入式技术

1368人已加入

描述

事情是这样的,SoC工程师的一项典型工作就是集成。俗称连连看。

当然除了连连看还有一些集成级的代码需要设计,比如CRG,regfile,ahb/apb/local bus decoder,axi bus matrix/network等等。这些代码很多是有vendor提供工具生成,或者用脚本生成。集成工作我们前面介绍的GVim插件已经实现了自动化。总之就是能不手写代码就不手写代码。

因为只要是人手写就有可能出错,review不可能每一行都能review到,输入给代码生成脚本的文件一定是简洁明了,方便review的。而且一旦经过一次项目洗礼,后面就闭着眼睛用,一劳永逸。

那么今天给大家分享一个编写Python脚本生成一个ahb decoder的脚本。首先分析一下ahb decoder的原理。主要就两大部分。

第一部分就是slave的sel信号decoder。根据地址空间划分,选择选择不同的地址段。

脚本

第二部分是rdata和response信号的返回mux。

脚本

地址decoder部分是共用的。decoder和mux可以归纳出一些编码模版,即slave的数据量再增加,同一段代码模版可以复用,只是代码量增加。这种有固定套路的代码完全可以借助脚本生成。

规定一下脚本的输入文件形式,比如表格输入。

脚本

ahb decoder桥是1路ahb slave接口入,多路ahb master接口输出,表格中填写master接口输出名,起始地址段,结束地址段。这样review时候只需要review这个表格即可。

接下来是python脚本开发

安装pandas。用于表格处理。

 

sudo apt install python3-pip
sudo pip install pandas

 

缺啥库,再用pip安装即可。

接下来就开始生成代码,这类代码生成套路就是根据表格提供信息,打印代码模版替换其中的关键词。我把要生成的代码一行一行追加到一个列表中,然后再一行一行打印到一个新的.v文件中。

首先用pandas读取表格,根据输入的表格路径,sheet name,读取当前sheet的数据。

 

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会处理成二维列表。

脚本

然后打开一个.v文件,文件名也是用户自己输入 。创建一个空列表,往里面塞代码。

 

fp = open(para_list[1]+".v", "w") 
print_line = []

 

给代码生成头文件,显得专业些。年份,日期,filename等自动匹配生成。

 

    print_line.append("// +FHDR----------------------------------------------------------------------------")
    print_line.append("// Copyright (c) "+year+" SiliconPeasant.")
    print_line.append("// ALL RIGHTS RESERVED Worldwide")
    print_line.append("//         ")
    print_line.append("// Author        : "+user)
    print_line.append("// Email         : ninghechuan@foxmail.com")
    print_line.append("// Created On    : "+date1+" "+time)
    print_line.append("// Last Modified : "+date1+" "+time)
    print_line.append("// File Name     : "+filename)
    print_line.append("// Description   :")
    print_line.append("// ")
    print_line.append("// ---------------------------------------------------------------------------------")
    print_line.append("// Modification History:")
    print_line.append("// Date         By              Version                 Change Description")
    print_line.append("// ---------------------------------------------------------------------------------")
    print_line.append("// "+date1+"   "+user+"     1.0                     Original")
    print_line.append("// -FHDR----------------------------------------------------------------------------")

 

脚本

然后往列表里塞Verilog代码,固定的代码模版,直接输入,比如我们要生成的ahb decoder只有一组ahb slave接口,名字暂时固定,未开放给用户。

 

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,")

 

接下来追加decoder输出的master的代码,根据表格第一列填写的数据,给输出的ahb master接口加上用户自定义关键词。

 

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部分代码。根据地址高位产生一个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")

 

脚本

生成每个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")

 

脚本

将列表中的文件,循环打印出到.v中,最后一行加上endmodule。

 

for line in print_line:
      #print(line)
      fp.write(line)
      fp.write('
')
  
  fp.write('
')
  fp.write('endmodule')
  
  fp.close()

 

最后再加一个help函数

 

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

 

脚本

使用说明,咱们就是说,就是一个专业配套齐全。

使用命令

 

python3 xxb_decoder.py ./ahb_dec.xlsx ahb_dec dec_gen

 

本篇只是提供一个思路,生成代码机制并不完善,地址译码逻辑暂时还有限制,不过照这个思路我们就可以生成很多代码了,只要它有规律就能生成。真正做到成为一个不写Verilog的芯片工程师。这个脚本的源代码和Excel文件放GitHub上了。感兴趣的朋友可以留言多多交流。

https://github.com/NingHeChuan/Silicon_Peasant/tree/master/script

最后

写Python的时候,有些奇妙的感觉,和Verilog的思维方式完全不同,一种久违的感觉,那种代码是一行一行的执行,出错debug,加很多print然后分析。最后调试出来后,是另外一种快乐。

  审核编辑:汤梓红
 
打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分