1. 功能
在IC测试中,需要将测试机从chroma升级到高端测试机爱德万,但大量的测试pattern无法转平台,爱德万也不提供技术支持,因此,本人写了一个脚本,用于批量且快速的转换。
2. 代码
首先需要具备两个目录CHROMA_PAT
和ADV_PAT
与此脚本同级目录,然后放置一个或多个chroma pat到CHROMA_PAT
目录,运行此脚本即可。
2.1 chroma pat 例子:
SET_DEC_FILE "xxxxx_pin.dec"
HEADER
NRST,PA_7,PA_8,PA_9,PA_10,PA_11,PA_12,PA_13,PA_14,PA_15,PB_0,PB_1,PB_10,PB_11,PB_12,PB_13,PC_0,PA_4,PA_5;
SPM_PATTERN (ompress_occ_all1) {
*10000000000XXXX0000* TS8; //start
*1KK00000000XXXX0000* ; //start
*10000000000XXXX0000* STOP; //start
}
2.2 转换完成的adv pat 例子:
将转换完成的pat进行解包如下:
Comments.cmt:
1 start
2 start
3 start
Program.sprg:
<?xml version="1.0" encoding="UTF-8"?>
<Program xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Program.xsd">
<!-- patfile: ompress_occ_all1.pat, use decfile: ss517a_pin.dec -->
<Instrument id="NRST,PA_7,PA_8,PA_9,PA_10,PA_11,PA_12,PA_13,PA_14,PA_15,PB_0,PB_1,PB_10,PB_11,PB_12,PB_13,PC_0,PA_4,PA_5">
<Instruction id="genVec" value="3"/>
</Instrument>
</Program>
Vectors.vec:
10000000000XXXX0000
1KK00000000XXXX0000
10000000000XXXX0000
2.3 chroma2adv_pat脚本:
"""
@auther:刘泽文
@data:2023.05.23
@function:chroma.pat->adv.pat
"""
import os
import sys
import time
import re
import shutil
# 将log写入文件
# sys.stdout = open("conversion_log.log", "w", encoding="utf-8")
# 切换到本文件目录
os.chdir(os.path.dirname(__file__))
sys.path.append("./dos2unix/bin")
CHROMA_PAT_PATH = "./CHROMA_PAT"
ADV_PAT_PATH = "./ADV_PAT"
CRLF = "\r\n"
LF = "\n"
line_end = LF
LOG = list()
# 找出CHROMA_PAT_PATH目录下所有.pat结尾文件
def list_all_file(dir_path, file_ext):
file_list = list()
for root, dirs, files in os.walk(dir_path):
for f in files:
if f.lower().endswith(file_ext):
file_list.append(f)
return file_list
# 找字符串substr在str中第time次出现的位置
def findSubStrIndex(str, substr, time):
times = str.count(substr)
if (times == 0) or (times < time):
pass
else:
i = 0
index = -1
while i < time:
index = str.find(substr, index+1)
i += 1
return index
# 获取一个文件中 第二对"{}"之间的字符串
def get_str_between_two_char(s, left="", right="", time_l=1, time_r=1):
# 判断是否存在左右括号
if left not in s or right not in s:
return ""
# 找到左括号的位置
left_pos = findSubStrIndex(s, left, time_l)
# 找到右括号的位置
right_pos = findSubStrIndex(s, right, time_r)
# 返回左右括号之间的字符串
return s[left_pos:right_pos]
# 添加头部
def add_program_header(program_lines):
program_lines.append(f"<?xml version=\"1.0\" encoding=\"UTF-8\"?>{line_end}")
program_lines.append(f"<Program xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"Program.xsd\">{line_end}")
return program_lines
def add_program_header_end(program_lines):
program_lines.append(f"</Program>{line_end}")
return program_lines
def set_program_xmode(program_lines, xmode_value):
program_lines.append(f"<Assignment id=\"xmode\" value=\"{int(xmode_value)}\"/>{line_end}")
return program_lines
# 添加PINLIST
def add_program_pin(program_lines, pinlist):
pinlist_str = ",".join(pinlist)
program_lines.append(f" <Instrument id=\"{pinlist_str}\">{line_end}")
return program_lines
def add_program_pin_end(program_lines):
program_lines.append(f" </Instrument>{line_end}")
return program_lines
def add_program_genvec(program_lines, line_number):
program_lines.append(f" <Instruction id=\"genVec\" value=\"{int(line_number)}\"/>{line_end}")
return program_lines
# 增加repeat
def add_program_repeat(program_lines, d_line_number, repeat_number):
program_lines.append(f" <Instruction id=\"genVec\" value=\"{int(d_line_number)}\">{line_end}")
program_lines.append(f" <Assignment id=\"repeat\" value=\"{int(repeat_number)}\"/>{line_end}")
program_lines.append(f" </Instruction>{line_end}")
return program_lines
# 增加loop
def add_program_loop(program_lines, loop_number):
program_lines.append(f" <Instruction id=\"loop\" value=\"{int(loop_number)}\" />{line_end}")
return program_lines
def add_program_loopend(program_lines):
program_lines.append(f" <Instruction id=\"loopEnd\" />{line_end}")
return program_lines
def add_program_comment(program_lines, comment):
program_lines.append(f" <!-- {comment} -->{line_end}")
return program_lines
CHROMA_PAT_FILE_LIST = list_all_file(CHROMA_PAT_PATH, ".pat")
# 批量处理所有pat
for CHROMA_PAT_FILE in CHROMA_PAT_FILE_LIST:
print(f"\n*********************************************** 开始处理文件{CHROMA_PAT_FILE} ***********************************************\n")
PIN_LIST = list()
comments_lines = list()
vectors_count = 0
vectors_lines = list()
# 距离上一次有标记的line过去多少行了
differ_line_count = 0
differ_line_count_all = 0
program_lines = list()
# 打开所有pat
with open(os.path.join(CHROMA_PAT_PATH, CHROMA_PAT_FILE), "r", encoding="utf-8", errors='ignore') as chroma_pat:
chroma_pat_lines = chroma_pat.readlines()
PIN_LIST = list()
pin_def_in = False
for line in chroma_pat_lines:
if "HEADER" in line:
pin_def_in = True
if "SPM_PATTERN" in line:
pin_def_in = False
if pin_def_in:
if re.search(r'//.*', line, re.I):
line = line.split("//")[0]
if re.search(r'[A-Za-z0-9_]+\s*[,;]+', line, re.I):
pin_list = re.findall(r'([A-Za-z0-9_]+)\s*[,;]+', line, re.I)
if len(pin_list) > 0:
for i in range(0, len(pin_list)):
PIN_LIST.append(pin_list[i])
PIN_LIST = [i.strip() for i in PIN_LIST if i != ""]
chroma_pat_str = "".join(chroma_pat_lines)
DEC_FILENAME = ""
if re.search(r'"[A-Za-z0-9_]+\.dec"', chroma_pat_str, re.I):
DEC_FILENAME = re.findall(r'"([A-Za-z0-9_]+\.dec)"', chroma_pat_str, re.I)[0].strip()
program_lines = add_program_header(program_lines)
program_lines = add_program_comment(program_lines, f"patfile: {CHROMA_PAT_FILE}, use decfile: {DEC_FILENAME}")
program_lines = add_program_pin(program_lines, PIN_LIST)
# print(PIN_LIST)
for line in chroma_pat_lines:
# 查找pat行
if re.search(r'\*.+\*.*;', line, re.I):
vectors_count = vectors_count + 1
differ_line_count = differ_line_count + 1
vectors_line = re.findall(r'\*(.+)\*.*;', line, re.I)[0].replace(" ", "").strip() + line_end
# 去除vectors_line里面的所有空格
vectors_lines.append(vectors_line)
# 取log
if re.search(r'\*.+\*.*;\s*//.+', line, re.I):
comments_line = f"{vectors_count} " + re.findall(r'\*.+\*.*;\s*//(.+)', line, re.I)[0].strip() + line_end
# print(comments_line, end="")
comments_lines.append(comments_line)
if re.search(r'\*.+\*\s*RPT\s*\d+\s*;', line, re.I):
rpt_number = int(re.findall(r'\*.+\*\s*RPT\s*(\d+)\s*;', line, re.I)[0].strip())
# print(f"RPT {rpt_number}")
if differ_line_count > 1:
program_lines = add_program_genvec(program_lines, differ_line_count-1)
program_lines = add_program_repeat(program_lines, 1, rpt_number)
else:
program_lines = add_program_repeat(program_lines, differ_line_count, rpt_number)
differ_line_count_all = differ_line_count_all + differ_line_count
# 清空计数
differ_line_count = 0
if re.search(r'\*.+\*\s*SETX\d*\s*\d+\s*;', line, re.I):
loop_number = int(re.findall(r'\*.+\*\s*SETX\d*\s*(\d+)\s*;', line, re.I)[0].strip())
# print(f"LOOP {loop_number}")
# 从该行前面开始循环,所以differ_line_count-1
if differ_line_count > 1:
program_lines = add_program_genvec(program_lines, differ_line_count - 1)
program_lines = add_program_loop(program_lines, loop_number)
differ_line_count_all = differ_line_count_all + differ_line_count - 1
# 清空计数
differ_line_count = 1
elif re.search(r'\*.+\*\s*JNZ.+\s*;', line, re.I):
# 从该行后面结束循环,所以differ_line_count不用-1
if differ_line_count > 0:
program_lines = add_program_genvec(program_lines, differ_line_count)
program_lines = add_program_loopend(program_lines)
differ_line_count_all = differ_line_count_all + differ_line_count
# 清空计数
differ_line_count = 0
program_lines = add_program_genvec(program_lines, differ_line_count)
program_lines = add_program_pin_end(program_lines)
program_lines = add_program_header_end(program_lines)
differ_line_count_all = differ_line_count_all + differ_line_count
# print("总行数为:%d"%(differ_line_count_all))
# 校验中间文件总数是否等于pat总行数
if vectors_count != differ_line_count_all:
print(f"{CHROMA_PAT_FILE}文件 行数{vectors_count} 与 {differ_line_count_all} 不一致!")
LOG.append(f"{CHROMA_PAT_FILE}文件 行数{vectors_count} 与 {differ_line_count_all} 不一致!\n")
# 文件夹名
ADV_PAT_FILE_DIR = os.path.join(ADV_PAT_PATH, CHROMA_PAT_FILE.split(".")[0])
# 创建以该pat名为名的文件夹
if not os.path.exists(ADV_PAT_FILE_DIR):
os.mkdir(ADV_PAT_FILE_DIR)
# 将所有参数写入三个文件
ADV_PAT_FILE_COMMENT_FILE = os.path.join(ADV_PAT_FILE_DIR, "Comments.cmt")
with open(ADV_PAT_FILE_COMMENT_FILE, "w", encoding="utf-8") as comments_file:
comments_file.writelines(comments_lines)
ADV_PAT_FILE_PROGRAM_FILE = os.path.join(ADV_PAT_FILE_DIR, "Program.sprg")
with open(ADV_PAT_FILE_PROGRAM_FILE, "w", encoding="utf-8") as program_file:
program_file.writelines(program_lines)
ADV_PAT_FILE_VECTORS_FILE = os.path.join(ADV_PAT_FILE_DIR, "Vectors.vec")
with open(ADV_PAT_FILE_VECTORS_FILE, "w", encoding="utf-8") as vectors_file:
vectors_file.writelines(vectors_lines)
# dos系统文件转unix格式,行尾序列转换
os.system(f"dos2unix {ADV_PAT_FILE_COMMENT_FILE}")
os.system(f"dos2unix {ADV_PAT_FILE_PROGRAM_FILE}")
os.system(f"dos2unix {ADV_PAT_FILE_VECTORS_FILE}")
# 压缩打包为zip
os.system("7z a -tzip %s.zip %s/*.* -r -mx=9 -mm=Deflate"%(ADV_PAT_FILE_DIR, ADV_PAT_FILE_DIR))
# 删除已存在的.pat
if os.path.exists(os.path.join(ADV_PAT_PATH, CHROMA_PAT_FILE)):
os.remove(os.path.join(ADV_PAT_PATH, CHROMA_PAT_FILE))
# 将.zip重命名为.pat
os.rename(f"{ADV_PAT_FILE_DIR}.zip", os.path.join(ADV_PAT_PATH, CHROMA_PAT_FILE))
# shutil.rmtree(ADV_PAT_FILE_DIR)
LOG.append(f"{CHROMA_PAT_FILE}文件 转换OK!\n")
with open("conversion_log.log", "w", encoding="utf-8") as conversion_log:
conversion_log.writelines(LOG)