diff --git a/Scripts/gen_apb_file/apb_file_test.xls b/Scripts/gen_apb_file/apb_file_test.xls new file mode 100644 index 0000000..54871ab Binary files /dev/null and b/Scripts/gen_apb_file/apb_file_test.xls differ diff --git a/Scripts/gen_apb_file/apb_file_test.xls.bak b/Scripts/gen_apb_file/apb_file_test.xls.bak new file mode 100644 index 0000000..2e4667e Binary files /dev/null and b/Scripts/gen_apb_file/apb_file_test.xls.bak differ diff --git a/Scripts/gen_apb_file/do_apb_file.py b/Scripts/gen_apb_file/do_apb_file.py new file mode 100644 index 0000000..9ad18ee --- /dev/null +++ b/Scripts/gen_apb_file/do_apb_file.py @@ -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() \ No newline at end of file diff --git a/Scripts/gen_apb_file.py b/Scripts/gen_apb_file/gen_apb_file.py similarity index 95% rename from Scripts/gen_apb_file.py rename to Scripts/gen_apb_file/gen_apb_file.py index f590a5d..24eb2b3 100644 --- a/Scripts/gen_apb_file.py +++ b/Scripts/gen_apb_file/gen_apb_file.py @@ -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 .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 .xlsx"%(sys.argv[0])) + sys.exit(1) + + if(sys.argv[1]=='-help'): + print("Usage : %s .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 .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) diff --git a/Scripts/do_apb_file.py b/Scripts/gen_apb_file/old_apb.py similarity index 100% rename from Scripts/do_apb_file.py rename to Scripts/gen_apb_file/old_apb.py diff --git a/Scripts/gen_sram_wrap/area_and_timing.txt b/Scripts/gen_sram_wrap/area_and_timing.txt new file mode 100644 index 0000000..59464df --- /dev/null +++ b/Scripts/gen_sram_wrap/area_and_timing.txt @@ -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) + +================================================================================ + diff --git a/Scripts/gen_sram_wrap/datasheet.txt b/Scripts/gen_sram_wrap/datasheet.txt new file mode 100644 index 0000000..e69de29 diff --git a/Scripts/gen_sram_wrap/gen_sram_wrap.py b/Scripts/gen_sram_wrap/gen_sram_wrap.py index 75d047f..afa7f24 100644 --- a/Scripts/gen_sram_wrap/gen_sram_wrap.py +++ b/Scripts/gen_sram_wrap/gen_sram_wrap.py @@ -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" diff --git a/Scripts/gen_sram_wrap/get_ds_info.py b/Scripts/gen_sram_wrap/get_ds_info.py new file mode 100644 index 0000000..fad3713 --- /dev/null +++ b/Scripts/gen_sram_wrap/get_ds_info.py @@ -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() diff --git a/Scripts/gen_sram_wrap/ts1n12ffcllulvta1024x133/DATASHEET/ts1n12ffcllulvta1024x133_ssgnp0p72v125c.ds b/Scripts/gen_sram_wrap/ts1n12ffcllulvta1024x133/DATASHEET/ts1n12ffcllulvta1024x133_ssgnp0p72v125c.ds new file mode 100644 index 0000000..65360be --- /dev/null +++ b/Scripts/gen_sram_wrap/ts1n12ffcllulvta1024x133/DATASHEET/ts1n12ffcllulvta1024x133_ssgnp0p72v125c.ds @@ -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 \ No newline at end of file diff --git a/Scripts/template.xls b/Scripts/template.xls index f16ee41..6b179a1 100644 Binary files a/Scripts/template.xls and b/Scripts/template.xls differ diff --git a/Scripts/test.xls b/Scripts/test.xls deleted file mode 100644 index 3b3ef24..0000000 Binary files a/Scripts/test.xls and /dev/null differ