优化数字前端工作流的小脚本
使用python编写了两个优化工作流的小脚本。在前端设计工作时,我的工作流是:初步规划端口(markdown)-> 初步rtl代码设计(verilog)-> 完整rtl代码设计(verilog)-> 输出最终端口(markdown)
所以这里涉及两个可以自动化的步骤,一个是把我用markdown下画的表格使用脚本转化成verilog文件。另一个是把编写好的verilog文件转化回markdown表格。所以我又靠AI(还是new bing)写了这两个脚本:
将表格转换成verilog:
def generate_verilog(file_path):
with open(file_path, 'r') as f:
table = f.read()
lines = table.split('\n')
ports = []
for line in lines[3:]:
if line.strip() == '':
continue
port, width, direction, function = [x.strip() for x in line.split("|")[1:-1]]
port = port.strip()
width = width.strip()
direction = direction.strip()
function = function.strip()
ports.append((port, width, direction,function))
verilog = 'module my_module (\n'
for port, width, direction, function in ports:
if direction == 'input':
if int(width) == 1:
verilog += f' input {port}, // {function} \n'
else:
verilog += f' input [{int(width)-1}:0] {port}, // {function} \n'
elif direction == 'output':
if int(width) == 1:
verilog += f' output {port}, // {function} \n'
else:
verilog += f' output [{int(width)-1}:0] {port}, // {function} \n'
verilog = verilog + '\n);\n'
for port, width, direction,function in ports:
if int(width) == 1:
if direction == 'output':
verilog += f'reg {port};\n'
else:
if direction == 'output':
verilog += f'reg [{int(width)-1}:0] {port};\n'
verilog += '\nendmodule'
return verilog
file_path = input('Enter the file path: ')
verilog_code = generate_verilog(file_path)
output_file_path = input('Enter the output file path: ')
with open(output_file_path, 'w') as f:
f.write(verilog_code)
例如输入一个表格:
Port | Width | Direction | Function |
---|---|---|---|
clk | 1 | input | 时钟 |
rst_n | 1 | input | 复位 |
inst_dout | 32 | input | 指令数据 |
inst_addr | 5 | output | 指令地址 |
运行脚本后就会自动输出verilog代码:
module my_module (
input clk, // 时钟
input rst_n, // 复位
input [31:0] inst_dout, // 指令数据
output [4:0] inst_addr, // 指令地址
);
reg [4:0] inst_addr;
endmodule
注意一下最后一个信号把逗号删除就行。
反过来如果要把verilog转换回表格,使用下面这个脚本:
import re
def verilog_to_markdown(input_file, output_file):
with open(input_file, 'r') as f:
verilog_str = f.read()
# Extract the module declaration
module_declaration = re.search(r'module\s+\w+\s*\(([^)]*)\);', verilog_str, re.DOTALL)
if not module_declaration:
return 'Error: No valid module declaration found'
port_declarations = module_declaration.group(1).strip().split('\n')
# Create the markdown table
markdown_table = '| Port | Width | Direction | Function |\n'
markdown_table += '| :-----------------------: | :---: | :-------: | :----------------------------------: |\n'
for port_declaration in port_declarations:
port_declaration = port_declaration.strip()
if not port_declaration:
continue
direction, port_name = port_declaration.split(' ',1)[:2]
port_name = port_name.rstrip(',')
width = 1
if '[' in port_name:
width_str = re.search(r'\[(\d+):(\d+)\]', port_name).group()
msb, lsb = map(int, width_str[1:-1].split(':'))
width = msb - lsb + 1
port_name = re.sub(r'\[\d+:\d+\]', '', port_name)
port_name = port_name.split('//')[0]
port_name = port_name.replace(',', '')
# Extract the comment after '//'
comment = ''
comment_match = re.search(r'//(.*)', port_declaration)
if comment_match:
comment = comment_match.group(1).strip()
markdown_table += f'| {port_name:<23} | {width:^5} | {direction:^9} | {comment:<35} |\n'
with open(output_file, 'w') as f:
f.write(markdown_table)
input_file = input('Enter the input file name: ')
output_file = input('Enter the output file name: ')
verilog_to_markdown(input_file, output_file)
例如输入一个verilog的端口声明代码:
module my_module (
input clk, // 时钟
input rst_n, // 复位
input [31:0] inst_dout, // 指令数据
output [4:0] inst_addr // 指令地址
);
就能获得一个markdown描述的表格:
Port | Width | Direction | Function |
---|---|---|---|
clk | 1 | input | 时钟 |
rst_n | 1 | input | 复位 |
inst_dout | 32 | input | 指令数据 |
inst_addr | 5 | output | 指令地址 |
当然这两个脚本也不是很完善,后面可以再增加一些新的功能。
最后把数据交给后端时,可以通过把markdown里面的信号拆解到excel表格里面,通过下面这个脚本:
import pandas as pd
from openpyxl import Workbook
import re
import sys
def parse_markdown_table(file_path):
with open(file_path, 'r') as f:
lines = f.readlines()
table_data = []
for line in lines:
if '|' in line:
row = [item.strip() for item in line.split('|')[1:-1]]
table_data.append(row)
headers = table_data[0]
data = {header: [] for header in headers}
for row in table_data[2:]:
for i, item in enumerate(row):
header = headers[i]
data[header].append(item)
return data
# 读取命令行参数中的Markdown文件路径
file_path = sys.argv[1]
# 读取Markdown文件中的表格数据
data = parse_markdown_table(file_path)
# 创建一个Excel工作簿
wb = Workbook()
ws = wb.active
# 遍历每个端口
for i in range(len(data['Port'])):
port = data['Port'][i]
width = int(data['Width'][i]) # 确保宽度是整数
# 对于每个端口,生成对应位宽的行
for j in range(width):
if width == 1:
ws.append([f'{port}'])
else:
ws.append([f'{port}<{j}>'])
# 保存Excel文件
wb.save('ports.xlsx')
你可以通过命令行运行这个脚本,并将Markdown文件的路径作为第一个参数传递给它,例如:python script.py your_markdown_file.md。这个脚本会读取Markdown文件中的表格数据,然后根据端口名和位宽生成一个名为ports.xlsx的Excel文件。