正则表达式扩充gtkwave gtkw信号列表

背景

在调试一些chisel项目的波形时,经常遇到某些信号有多路,添加这些信号经常需要一个个找、一个个调整顺序,麻烦。
如有多路提交通道,io_commits_commitValid_0 ~ io_commits_commitValid_7io_commits_robIdx_0_value[7:0] ~ io_commits_robIdx_7_value[7:0]、……

虽然可以通过正则表达式进行信号搜索、过滤,但我还是想将每一路的多个信号放在一起。

因此想搞一个工具,可以快速添加信号。

想法

添加波形的时候通过正则表达式只添加1路,然后用工具生成其他路。

注意到EDA软件保存添加的信号列表的文件通常是文本文件,很容易编辑,如verdi的rc文件和gtkwave的gtkw文件。
而这些信号中经常只有一个数字改变,因此可以采用正则表达式进行匹配和替换。

实现

直接让gpt生成一个python程序,然后再手动调整下
读入gtkw文件,输入匹配信号的正则表达式和路数,可以实时预览结果,按钮写回文件

import tkinter as tk
from tkinter import filedialog
import re

def replace_first_group(s, p, v):
    def replacement(match):
        full_match = match.group(0)
        first_group = match.group(1)
        return full_match.replace(first_group, v, 1)
    result = re.sub(p, replacement, s)
    return result

class GTKWaveEditor:
    def __init__(self, root):
        self.root = root
        self.root.title("GTKWave Signal Editor")
        self.file_path = tk.StringVar()
        self.regex_pattern = tk.StringVar()
        self.duplicate_count = tk.IntVar(value=1)
        self.matched_signals = tk.StringVar()
        self.preview_signals = tk.StringVar()

        self.create_widgets()
        
    def create_widgets(self):
        tk.Label(self.root, text="GTKW File:").grid(row=0, column=0, sticky='e')
        tk.Entry(self.root, textvariable=self.file_path, width=50).grid(row=0, column=1)
        tk.Button(self.root, text="Browse", command=self.load_file).grid(row=0, column=2)
        tk.Label(self.root, text="Regex Pattern:").grid(row=1, column=0, sticky='e')
        regex_entry = tk.Entry(self.root, textvariable=self.regex_pattern, width=50)
        regex_entry.grid(row=1, column=1)
        regex_entry.bind('<KeyRelease>', self.update_matched_signals)
        tk.Label(self.root, text="Duplicate Count:").grid(row=2, column=0, sticky='e')
        duplicate_entry = tk.Entry(self.root, textvariable=self.duplicate_count, width=10)
        duplicate_entry.grid(row=2, column=1, sticky='w')
        duplicate_entry.bind('<KeyRelease>', self.update_preview)
        tk.Label(self.root, text="Matched Signals:").grid(row=3, column=0, sticky='ne')
        self.matched_signals_text = tk.Text(self.root, height=10, width=70, wrap='word', state='disabled')
        self.matched_signals_text.grid(row=3, column=1, columnspan=2, sticky='w')
        tk.Label(self.root, text="Preview Duplicated Signals:").grid(row=4, column=0, sticky='ne')
        self.preview_signals_text = tk.Text(self.root, height=10, width=70, wrap='word', state='disabled')
        self.preview_signals_text.grid(row=4, column=1, columnspan=2, sticky='w')
        tk.Button(self.root, text="Process and Save", command=self.process_file).grid(row=5, column=1, pady=10)

    def load_file(self):
        file_path = filedialog.askopenfilename(filetypes=[("GTKWave Files", "*.gtkw")])
        if file_path:
            self.file_path.set(file_path)
            self.file_lines = open(file_path, 'r').readlines()
            self.update_matched_signals()

    def update_matched_signals(self, event=None):
        file_path = self.file_path.get()
        pattern = self.regex_pattern.get()
        if not file_path or not pattern:
            return
        try:
            lines = self.file_lines
            matched_signals = []
            begin = len(lines)
            end = 0
            for i, line in enumerate(lines):
                if len(line) >= 1 and line[0] in ["[", "@", "-"]:
                    continue
                match = re.match(pattern, line)
                if match:
                    signal = {}
                    signal['pre'] = lines[i-1].strip() if i > 0 and lines[i-1].startswith('@') else ''
                    signal['sig'] = line.strip()
                    signal['index'] = int(match.group(1))
                    matched_signals.append(signal)

                    begin = i if i < begin else begin
                    end = i if i > end else end

            self.matched_signals_text.config(state='normal')
            self.matched_signals_text.delete(1.0, tk.END)
            self.matched_signals_text.insert(tk.END, "\n".join(map(lambda x: x['sig'], matched_signals)))
            self.matched_signals_text.config(state='disabled')

            duplicate_count = self.duplicate_count.get()
            preview_text = ''

            for i in range(duplicate_count):
                preview_text += f'-{i}\n'
                for signal in matched_signals:
                    modified_signal = replace_first_group(signal['sig'], pattern, str(signal['index'] + i))
                    preview_text += signal['pre'] + '\n'
                    preview_text += modified_signal + '\n'
                preview_text += f'-{i}\n'
            self.preview_duplicated_signals(preview_text)
            self.content = '\n'.join(lines[:begin]) + preview_text + '\n'.join(lines[end+1:]) 

        except Exception as e:
            print(e)


    def update_preview(self, event=None):
        self.update_matched_signals()

    def preview_duplicated_signals(self, preview_text):
        self.preview_signals_text.config(state='normal')
        self.preview_signals_text.delete(1.0, tk.END)
        self.preview_signals_text.insert(tk.END, preview_text)
        self.preview_signals_text.config(state='disabled')

    def process_file(self):
        with open(self.file_path.get(), 'w') as f:
            f.write(self.content)

if __name__ == "__main__":
    root = tk.Tk()
    app = GTKWaveEditor(root)
    root.mainloop()
posted @ 2024-10-12 21:31  一鸣惊人_001  阅读(79)  评论(0)    收藏  举报