Compare commits
2 Commits
2a9154e953
...
2a10ad95f9
Author | SHA1 | Date |
---|---|---|
![]() |
2a10ad95f9 | |
![]() |
32c09ff0f1 |
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,138 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import sys
|
||||
import os
|
||||
import xlrd
|
||||
import xlwt
|
||||
import shutil
|
||||
|
||||
def parse_args():
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: python3 xxx.py xxx.xls [-name sheetName]")
|
||||
sys.exit(1)
|
||||
file_path = sys.argv[1]
|
||||
sheet_name = None
|
||||
if '-name' in sys.argv:
|
||||
idx = sys.argv.index('-name')
|
||||
if idx + 1 < len(sys.argv):
|
||||
sheet_name = sys.argv[idx + 1]
|
||||
else:
|
||||
print("Error: -name 参数后需跟 sheet 名称")
|
||||
sys.exit(1)
|
||||
if not os.path.exists(file_path):
|
||||
print(f"文件 {file_path} 不存在")
|
||||
sys.exit(1)
|
||||
return file_path, sheet_name
|
||||
|
||||
def find_header_indices(sheet):
|
||||
header = [str(sheet.cell_value(0, col)).strip() for col in range(sheet.ncols)]
|
||||
try:
|
||||
bits_col = header.index('Bits')
|
||||
offset_col = header.index('OffsetAddress')
|
||||
regname_col = header.index('RegName')
|
||||
offsetwidth_col = header.index('OffsetWidth')
|
||||
except ValueError as e:
|
||||
print(f"表头缺失: {e}")
|
||||
sys.exit(1)
|
||||
return bits_col, offset_col, regname_col, offsetwidth_col
|
||||
|
||||
def process_sheet(sheet, wb, sheet_name):
|
||||
bits_col, offset_col, regname_col, offsetwidth_col = find_header_indices(sheet)
|
||||
ws = wb.add_sheet(sheet_name)
|
||||
# 复制表头
|
||||
for col in range(sheet.ncols):
|
||||
ws.write(0, col, sheet.cell_value(0, col))
|
||||
|
||||
offset = 0
|
||||
reg_idx = 0
|
||||
row = 1
|
||||
while row < sheet.nrows:
|
||||
bits_start_cell = str(sheet.cell_value(row, bits_col)).strip()
|
||||
# 匹配 '31' 或 '[31:' 开头
|
||||
if bits_start_cell == '31.0' or bits_start_cell.startswith('[31:'):
|
||||
print(f"Processing row {row+1}: Bits = {bits_start_cell}")
|
||||
# replace OffsetAddress
|
||||
offset_str = f"0x{offset:02X}"
|
||||
ws.write(row, offset_col, offset_str)
|
||||
# replace RegName
|
||||
reg_str = f"reg_{reg_idx:02X}"
|
||||
ws.write(row, regname_col, reg_str)
|
||||
# 校验
|
||||
if offset // 4 != reg_idx:
|
||||
print(f"[Check] OffsetAddress {offset_str} 与 RegName {reg_str} 不匹配")
|
||||
# Bits列刷新
|
||||
offset += 4
|
||||
reg_idx += 1
|
||||
|
||||
bits_sum = 0
|
||||
left = 31
|
||||
start_row = row
|
||||
# one Bits row starts and ends
|
||||
while row < sheet.nrows:
|
||||
# 复制其他列
|
||||
for col in range(sheet.ncols):
|
||||
if col in (bits_col, offset_col, regname_col):
|
||||
continue
|
||||
ws.write(row, col, sheet.cell_value(row, col))
|
||||
|
||||
width = (sheet.cell_value(row, offsetwidth_col))
|
||||
if width is None or width == '':
|
||||
ws.write(row, bits_col, sheet.cell_value(row, bits_col))
|
||||
bits_cell = str(sheet.cell_value(row, bits_col)).strip()
|
||||
row += 1
|
||||
if bits_cell.endswith('0]'):
|
||||
print(f"Bits cell ends with 0, breaking at row {row}")
|
||||
break
|
||||
else:
|
||||
continue
|
||||
|
||||
if int(width) < 0 or int(width) > 32:
|
||||
raise ValueError(f"OffsetWidth {width} 不在 0-32 范围内")
|
||||
|
||||
width = int(width)
|
||||
right = left - width + 1
|
||||
if left == right:
|
||||
bits_str = f"[{left}]"
|
||||
else:
|
||||
bits_str = f"[{left}:{right}]"
|
||||
|
||||
ws.write(row, bits_col, bits_str)
|
||||
|
||||
bits_sum += width
|
||||
|
||||
left = right - 1
|
||||
# next row
|
||||
bits_end_cell = str(sheet.cell_value(row, bits_col)).strip()
|
||||
if bits_end_cell == '0' or bits_start_cell.endswith('0]') or right == 0:
|
||||
row += 1
|
||||
print(f"The 0 is bits_end_cell")
|
||||
break
|
||||
row += 1
|
||||
|
||||
if bits_sum != 32:
|
||||
print(f"[Warning] {sheet_name} 第{start_row+1}行起 OffsetWidth 累加为{bits_sum},应为32")
|
||||
else:
|
||||
# 其他行保持原样
|
||||
ws.write(row, offset_col, sheet.cell_value(row, offset_col))
|
||||
ws.write(row, regname_col, sheet.cell_value(row, regname_col))
|
||||
ws.write(row, bits_col, sheet.cell_value(row, bits_col))
|
||||
row += 1
|
||||
|
||||
def main():
|
||||
file_path, sheet_name = parse_args()
|
||||
# 先备份原文件
|
||||
shutil.copyfile(file_path, file_path + ".bak")
|
||||
book = xlrd.open_workbook(file_path)
|
||||
wb = xlwt.Workbook()
|
||||
sheets = [sheet_name] if sheet_name else book.sheet_names()
|
||||
print(sheets)
|
||||
for name in sheets:
|
||||
sheet = book.sheet_by_name(name)
|
||||
process_sheet(sheet, wb, name)
|
||||
# 覆盖原文件
|
||||
wb.save(file_path)
|
||||
print(f"已刷新并覆盖原文件: {file_path},原文件已备份为: {file_path}.bak")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
|
@ -2,10 +2,12 @@
|
|||
# coding: utf-8
|
||||
|
||||
import xlrd
|
||||
import xlwt
|
||||
import re
|
||||
import os
|
||||
import sys
|
||||
import math
|
||||
import do_apb_file
|
||||
|
||||
# ==========================================================
|
||||
# func process excel start#{{{
|
||||
|
@ -630,29 +632,53 @@ def gen_reg_ralf(p_sheet,ModuleName):
|
|||
|
||||
#max_rows=sheet0.nrows#行数
|
||||
#max_cols=sheet0.ncols#列数
|
||||
if(len(sys.argv) < 2):
|
||||
print("[Error]:Not have input file")
|
||||
print("Usage : %s <filename>.xlsx"%(sys.argv[0]))
|
||||
sys.exit(1)
|
||||
#def parse_args():
|
||||
# """解析命令行参数"""
|
||||
# parser = argparse.ArgumentParser(description='Generate APB register files')
|
||||
# parser.add_argument('xls_file', help='Excel configuration file path')
|
||||
# parser.add_argument('-proc', action='store_true',
|
||||
# help='Enable Excel preprocessing before generation')
|
||||
# return parser.parse_args()
|
||||
|
||||
if __name__ == "__main__":
|
||||
if(len(sys.argv) < 2):
|
||||
print("[Error]:Not have input file")
|
||||
print("Usage : %s <filename>.xlsx"%(sys.argv[0]))
|
||||
sys.exit(1)
|
||||
|
||||
if(sys.argv[1]=='-help'):
|
||||
print("Usage : %s <filename>.xlsx"%(sys.argv[0]))
|
||||
sys.exit(0)
|
||||
|
||||
if(os.path.exists(sys.argv[1])==False):
|
||||
print(f"[Error]: 文件 {sys.argv[1]} 不存在")
|
||||
print("[Error]:Not such file")
|
||||
sys.exit(1)
|
||||
|
||||
file_path = sys.argv[1]
|
||||
|
||||
with_proc = False
|
||||
if len(sys.argv) > 2 and '-proc' in sys.argv:
|
||||
with_proc = True
|
||||
|
||||
#book = xlrd.open_workbook(file_path)
|
||||
|
||||
book = xlrd.open_workbook(file_path)
|
||||
sheets = [sheet_name] if sheet_name else book.sheet_names()
|
||||
|
||||
wb = xlwt.Workbook()
|
||||
for name in sheets:
|
||||
if with_proc:
|
||||
process_sheet(sheets,wb,name)
|
||||
wb.save(file_path)
|
||||
|
||||
for name in sheets:
|
||||
gen_reg_hdl(sheet0,ModuleName)
|
||||
gen_reg_cheader(sheet0,ModuleName)
|
||||
gen_reg_ralf(sheet0,ModuleName)
|
||||
|
||||
if(sys.argv[1]=='-help'):
|
||||
print("Usage : %s <filename>.xlsx"%(sys.argv[0]))
|
||||
sys.exit(0)
|
||||
|
||||
if(os.path.exists(sys.argv[1])==False):
|
||||
print(f"[Error]: 文件 {sys.argv[1]} 不存在")
|
||||
print("[Error]:Not such file")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
book = xlrd.open_workbook(sys.argv[1])
|
||||
sheets_num = len(book.sheet_names())
|
||||
for index in range (sheets_num):
|
||||
sheet0 = book.sheet_by_index(index)
|
||||
ModuleName = sheet0.name
|
||||
#ModuleName = re.search('^[a-z]+',sys.argv[1]).group()#从开头位置开始匹配返回第一个,而findall返回一个list
|
||||
gen_reg_hdl(sheet0,ModuleName)
|
||||
gen_reg_cheader(sheet0,ModuleName)
|
||||
gen_reg_ralf(sheet0,ModuleName)
|
||||
sys.exit(0)
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
======== ts1n12ffcllulvta1024x133_ssgnp0p72v125c.ds ==========
|
||||
[Area Info]
|
||||
1. Area
|
||||
Pre-shrink (dimensions in GDS database)
|
||||
Width(um) Height(um) Area(um²)
|
||||
66.6950 284.9760 19006.4743
|
||||
|
||||
2.1 Timing Protocol (Refer to the waveforms in the databook)
|
||||
|
||||
xxxxxxxxxxxxxxxxxx
|
||||
|
||||
[Timing Info]
|
||||
The following values are based on 1st point of LUT (Look Up Table) in NLDM liberty file
|
||||
|
||||
I Normal
|
||||
Symbol Param. Value (ns) Parameter
|
||||
tcyc 0.9469 Minimum CLK cycle time
|
||||
tckh 0.0952 Minimum CLK Pulse High
|
||||
tckl 0.1565 Minimum CLK Pulse Low
|
||||
tcd 0.5055 CLK to valid Q (data output)
|
||||
thold 0.3776 CLK to invalid Q (data output)
|
||||
tcs 0.1204 CEB setup before CLK rising
|
||||
tch 0.0736 CEB hold after CLK rising
|
||||
tas 0.0927 A setup before CLK rising
|
||||
tah 0.0939 A hold after CLK rising
|
||||
tws 0.1108 WEB setup before CLK rising
|
||||
tbwh 0.0860 WEB hold after CLK rising
|
||||
Error: tcycÖµ³¬±ê (0.9469ns > 0.8ns)
|
||||
|
||||
================================================================================
|
||||
|
|
@ -90,6 +90,7 @@ def gen_sram_sh(rb,sheet_name, output_dir):
|
|||
with open(sh_path, 'w') as f:
|
||||
f.write("#!/bin/bash\n")
|
||||
f.write("\n".join(sorted(commands)))
|
||||
os.chmod(sh_path, 0o755) # 设置可执行权限
|
||||
|
||||
except Exception as e:
|
||||
print(f"Generate shell script failed: {str(e)}")
|
||||
|
@ -99,11 +100,23 @@ def gen_config_txt(sram_name, compiler, compile_depth, compile_width, mux, outpu
|
|||
config_dir = os.path.join(output_dir, "config")
|
||||
os.makedirs(config_dir, exist_ok=True)
|
||||
|
||||
config_content = f"{compile_depth}x{compile_width}m{mux}scp ulvt"
|
||||
if(compiler == 'tsn12ffcllspsram_130b'):
|
||||
config_content = f"{compile_depth}x{compile_width}m{mux}scp ulvt "
|
||||
elif(compiler == 'tsn12ffcll2prf_130a'):
|
||||
config_content = f"{compile_depth}x{compile_width}m{mux}scp ulvt "
|
||||
elif(compiler == 'tsn12ffclluhd2prf_130b'):
|
||||
config_content = f"{compile_depth}x{compile_width}m{mux} ulvt "
|
||||
elif(compiler == 'tsn12ffcllshcspsbsram_130c'):
|
||||
config_content = f"{compile_depth}x{compile_width}m{mux}s ulvt "
|
||||
elif(compiler == 'tsn12ffcll1prf_130a'):
|
||||
config_content = f"{compile_depth}x{compile_width}m{mux}scp ulvt "
|
||||
else:
|
||||
config_content = f"{compile_depth}x{compile_width}m{mux}scp ulvt "
|
||||
|
||||
config_path = os.path.join(config_dir, f"{sram_name}_{compiler}_config.txt")
|
||||
with open(config_path, 'w') as f:
|
||||
f.write(config_content)
|
||||
f.write("\n")
|
||||
|
||||
|
||||
def generate_files(xls_path, sheet_name=None):
|
||||
|
@ -164,7 +177,7 @@ def generate_files(xls_path, sheet_name=None):
|
|||
sram_port = 'SRAM_SP'
|
||||
template_file = "template_sram_sp_wrap.v"
|
||||
elif row[col_map['port']] == 'TP':
|
||||
sram_port = 'SRAM_SYNC_TP' if (row[col_map['ASYNC']] == 'No') else 'SRAM_ASYNC_TP'
|
||||
sram_port = 'SRAM_SYNC_TP' if (row[col_map['ASYNC']] == 'No' or row[col_map['ASYNC']] == 'NO') else 'SRAM_ASYNC_TP'
|
||||
template_file = "template_sram_tp_wrap.v" if (row[col_map['ASYNC']] == 'No') \
|
||||
else "template_sram_tp_async_wrap.v"
|
||||
else: # Assembly
|
||||
|
@ -172,7 +185,7 @@ def generate_files(xls_path, sheet_name=None):
|
|||
sram_port = 'SRAM_SP'
|
||||
template_file = "template_sram_sp_wrap_asmbly.v"
|
||||
elif row[col_map['port']] == 'TP':
|
||||
sram_port = 'SRAM_SYNC_TP_ASMBLY' if (row[col_map['ASYNC']] == 'No') else 'SRAM_ASYNC_TP_ASMBLY'
|
||||
sram_port = 'SRAM_SYNC_TP_ASMBLY' if (row[col_map['ASYNC']] == 'No' or row[col_map['ASYNC']] == 'NO') else 'SRAM_ASYNC_TP_ASMBLY'
|
||||
template_file = "template_sram_tp_wrap_asmbly.v" if (row[col_map['ASYNC']] == 'No') \
|
||||
else "template_sram_tp_async_wrap_asmbly.v"
|
||||
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
import os
|
||||
import glob
|
||||
|
||||
def extract_info(file_path):
|
||||
"""提取关键信息"""
|
||||
area_info = []
|
||||
sram_timing = []
|
||||
error_msgs = []
|
||||
|
||||
with open(file_path, 'r') as f:
|
||||
lines = f.readlines()
|
||||
in_area = False
|
||||
|
||||
for i, line in enumerate(lines):
|
||||
# 提取Area信息块
|
||||
if line.strip().startswith("1. Area"):
|
||||
area_info = lines[i:i+8]
|
||||
break # 每个文件只提取第一个Area块
|
||||
|
||||
# 提取时序信息(直接搜索tcyc到tbwh)
|
||||
tcyc_line = next((i for i, line in enumerate(lines) if line.strip().startswith("2.2 SRAM timing")), None)
|
||||
tbwh_line = next((i for i, line in enumerate(lines) if line.strip().startswith("tbwh")), None)
|
||||
if tbwh_line is None:
|
||||
tbwh_line = tcyc_line + 10
|
||||
|
||||
if tcyc_line is not None and tbwh_line is not None:
|
||||
sram_timing = lines[tcyc_line+2:tbwh_line+1]
|
||||
else:
|
||||
print(f"Warning: Timing info not found in {file_path}")
|
||||
|
||||
# 新增数值提取逻辑
|
||||
tcyc_value = None
|
||||
tcd_value = None
|
||||
|
||||
# 提取时序值
|
||||
for line in lines:
|
||||
line_clean = line.strip()
|
||||
# 提取tcyc值
|
||||
if line_clean.startswith('tcyc'):
|
||||
parts = line_clean.split()
|
||||
if len(parts) >= 2:
|
||||
val_str = parts[1]
|
||||
print(f"Processing tcyc value: {val_str}")
|
||||
try:
|
||||
tcyc_value = float(val_str)
|
||||
if tcyc_value > 0.8:
|
||||
error_msgs.append(f"Error: tcyc OVER ({tcyc_value}ns > 0.8ns)")
|
||||
except ValueError:
|
||||
pass
|
||||
# 提取tcd值
|
||||
elif line_clean.startswith('tcd'):
|
||||
parts = line_clean.split()
|
||||
if len(parts) >= 2:
|
||||
val_str = parts[1]
|
||||
print(f"Processing tcyc value: {val_str}")
|
||||
try:
|
||||
tcd_value = float(val_str)
|
||||
if tcd_value > 0.6:
|
||||
error_msgs.append(f"Error: tcd OVER ({tcd_value}ns > 0.6ns)")
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
return area_info, sram_timing, error_msgs
|
||||
|
||||
def write_info():
|
||||
output = []
|
||||
|
||||
# 递归所有子目录
|
||||
for root, _, files in os.walk('.'):
|
||||
# 匹配目标文件模式
|
||||
for ds_file in glob.glob(os.path.join(root, '*_ssgnp0p72v125c.ds')):
|
||||
print(f"Processing: {ds_file}")
|
||||
area, timing, error_msgs = extract_info(ds_file)
|
||||
|
||||
output.append(f"======== {os.path.basename(ds_file)} ==========\n")
|
||||
output.append("[Area Info]\n")
|
||||
output.extend(area)
|
||||
output.append("\n[Timing Info]\n")
|
||||
output.extend(timing)
|
||||
if error_msgs:
|
||||
print (f"Errors found in {ds_file}: {error_msgs}")
|
||||
output.extend([msg + "\n" for msg in error_msgs])
|
||||
output.append("\n" + "="*80 + "\n")
|
||||
output.append("\n")
|
||||
|
||||
# 写入结果文件
|
||||
with open('area_and_timing.txt', 'w') as f:
|
||||
f.writelines(output)
|
||||
|
||||
if __name__ == "__main__":
|
||||
write_info()
|
|
@ -0,0 +1,57 @@
|
|||
1. Area
|
||||
Pre-shrink (dimensions in GDS database)
|
||||
Width(um) Height(um) Area(um²)
|
||||
66.6950 284.9760 19006.4743
|
||||
|
||||
2.1 Timing Protocol (Refer to the waveforms in the databook)
|
||||
|
||||
xxxxxxxxxxxxxxxxxx
|
||||
ddddddddddddddd
|
||||
xxxxxxxxxxxxxxxxxx
|
||||
ddddddddddddddd
|
||||
xxxxxxxxxxxxxxxxxx
|
||||
ddddddddddddddd
|
||||
|
||||
2.2 SRAM timing
|
||||
2.2.1 Normal Mode and Power Management Mode
|
||||
The following values are based on 1st point of LUT (Look Up Table) in NLDM liberty file
|
||||
|
||||
I Normal
|
||||
Symbol Param. Value (ns) Parameter
|
||||
tcyc 0.9469 Minimum CLK cycle time
|
||||
tckh 0.0952 Minimum CLK Pulse High
|
||||
tckl 0.1565 Minimum CLK Pulse Low
|
||||
tcd 0.5055 CLK to valid Q (data output)
|
||||
thold 0.3776 CLK to invalid Q (data output)
|
||||
tcs 0.1204 CEB setup before CLK rising
|
||||
tch 0.0736 CEB hold after CLK rising
|
||||
tas 0.0927 A setup before CLK rising
|
||||
tah 0.0939 A hold after CLK rising
|
||||
tws 0.1108 WEB setup before CLK rising
|
||||
tbwh 0.0860 WEB hold after CLK rising
|
||||
xxxxxxxxxxxxxxxxxx
|
||||
ddddddddddddddd
|
||||
xxxxxxxxxxxxxxxxxx
|
||||
ddddddddddddddd
|
||||
xxxxxxxxxxxxxxxxxx
|
||||
ddddddddddddddd
|
||||
xxxxxxxxxxxxxxxxxx
|
||||
ddddddddddddddd
|
||||
xxxxxxxxxxxxxxxxxx
|
||||
ddddddddddddddd
|
||||
xxxxxxxxxxxxxxxxxx
|
||||
ddddddddddddddd
|
||||
xxxxxxxxxxxxxxxxxx
|
||||
ddddddddddddddd
|
||||
xxxxxxxxxxxxxxxxxx
|
||||
ddddddddddddddd
|
||||
xxxxxxxxxxxxxxxxxx
|
||||
ddddddddddddddd
|
||||
xxxxxxxxxxxxxxxxxx
|
||||
ddddddddddddddd
|
||||
xxxxxxxxxxxxxxxxxx
|
||||
ddddddddddddddd
|
||||
xxxxxxxxxxxxxxxxxx
|
||||
ddddddddddddddd
|
||||
xxxxxxxxxxxxxxxxxx
|
||||
ddddddddddddddd
|
Binary file not shown.
BIN
Scripts/test.xls
BIN
Scripts/test.xls
Binary file not shown.
Loading…
Reference in New Issue