• 【python脚本】ICer的脚本入门训练——gen_tc


    前言

    【python脚本】ICer的脚本入门训练——svn_back

    上一篇博客的目的,是通过处理固定流程的事物来体现脚本的必要性。而后这篇博客的目的,是熟悉脚本里的一些基本的处理思路。

    gen_tc是一个芯片前端验证很常见的脚本,作用是:

    1.根据已有的tc生成新的tc文件;

    2.修改内部关键字;

    3.输出文件;

    在这个过程中,我们需要涉及到的处理包括:吃命令行,遍历输入文件,正则匹配与替换,文件输出等过程,作为我第一个学习的脚本,几十行的内容简直最合适作为入门训练。

    要求

    假定目前我们有一个case,文件名为:sanity_case.sv,内容就是个普普通通的case如下:

    1. `ifndef SANITY_CASE_SV
    2. `define SANITY_CASE_SV
    3. class sanity_case_seq extends my_sequence;
    4. extern function new(string name = "sanity_case_seq");
    5. extern virtual task body();
    6. `uvm_object_utils(sanity_case_seq)
    7. endclass: sanity_case_seq
    8. function sanity_case_seq::new(string name = "sanity_case_seq");
    9. super.new(name);
    10. endfunction: new
    11. task sanity_case_seq::body();
    12. repeat(10000) begin
    13. `uvm_do_with(my_tr, {my_tr.par_err == 0;})
    14. end
    15. #100;
    16. endtask: body
    17. class sanity_case extends base_test;
    18. extern function new(string name = "base_test", uvm_component parent=null);
    19. extern virtual function void build_phase(uvm_phase phase);
    20. `uvm_component_utils(sanity_case)
    21. endclass: sanity_case
    22. function sanity_case::new(string name = "base_test", uvm_component parent=null);
    23. super.new(name, parent);
    24. endfunction: new
    25. function void sanity_case::build_phase(uvm_phase phase);
    26. super.build_phase(phase);
    27. uvm_config_db #(uvm_object_wrapper)::set(
    28. this,
    29. "env.i_agt0.sqr.main_phase",
    30. "default_sequence",
    31. sanity_case_seq::type_id::get()
    32. );
    33. uvm_config_db #(uvm_object_wrapper)::set(
    34. this,
    35. "env.i_agt1.sqr.main_phase",
    36. "default_sequence",
    37. sanity_case_seq::type_id::get()
    38. );
    39. endfunction: build_phase
    40. `endif

    那么我们要做的就是,编写一个脚本 gen_tc,在当前目录执行gen_tc sanity_case.v new_case.v之后,在当前目录生成新的文件new_case.v。

    实操

    1.新建文件gen_tc

    键入以下内容作为初始:

    之后修改文件属性为可执行属性chmod a+x gen_tc,然后你就会发现你的脚本绿了:

    敲一下,确认可执行,然后继续下一步:

    2.读取命令参数

    gen_tc脚本要吃两个参数,一般处理参数有两种常用的方式:sys.argv数组和argparse库。使用argparse的典型方式,如下面的代码,具体功能我们不做探究:

    1. import argparse
    2. def input_args_proc():
    3. parser = argparse.ArgumentParser(description="argparse info")
    4. parser.add_argument('-o', action='store_true', default=False, help='open this script')
    5. result = parser.parse_args()
    6. if result.o == True:
    7. os.system("gvim %s" % __file__)
    8. sys.exit(0)

    gen_tc的输入参数情况比较简单,两个参数必须输入,因此不需要使用argparse,直接使用sys.argv数组即可。比如目前的输入获取方式:

    1. def input_sys():
    2. if len(sys.argv) > 2:
    3. from_tc = sys.argv[1]
    4. to_tc = sys.argv[2]
    5. else:
    6. print("Input error")
    7. sys.exit(0)
    8. return from_tc, to_tc

    sys.argv[0]不要使用,那是脚本自身名称。在main函数中接受该函数的返回值,读取输入参数的操作就完成了。

    from_tc, to_tc = input_sys()

    3.读取并修改参考tc

    可以通过以下的形式形式来读取文件:

    1. def modify_tc(file):
    2. with open(file, "r") as handle:
    3. hd = handle.readlines()
    4. for line in hd:
    5. line = line.strip("\n")
    6. print(line)

    读取文件后,在没一行内匹配“sanity_case”或“SANITY_CASE”关键字,并将其替换为“new_case”和“NEW_CASE”,而后将字符串暂存于数组中,作为函数返回值:

    1. def modify_tc(frm, to):
    2. frm_key = re.sub("\.sv","",frm) #得到sanity_case.sv里的sanity_case
    3. frm_uc = frm_key.upper() #纯小写
    4. frm_lc = frm_key.lower() #纯大写,执行的时候把这块注释删了
    5. to_key = re.sub("\.sv","",to)
    6. to_uc = to_key.upper()
    7. to_lc = to_key.lower()
    8. out_file = []
    9. with open(frm, "r") as handle:
    10. hd = handle.readlines()
    11. for line in hd:
    12. line = line.strip("\n")
    13. line = re.sub(frm_uc, to_uc, line)
    14. line = re.sub(frm_lc, to_lc, line)
    15. out_file.append(line)
    16. return out_file

    main函数中接收返回值:

    out_file = modify_tc(from_tc, to_tc)

    4.输出文件

    输出文件的函数比较固定:

    1. def write_list(lst, out):
    2. with open(out, "w") as handle:
    3. for line in lst:
    4. handle.write(line+"\n")

    在main中把out_file和to_tc作为参数传给该函数即可:

    write_list(out_file, to_tc)

    5.执行脚本

    代码编写完成后,执行脚本,打开文件new_case.sv:

    1. `ifndef NEW_CASE_SV
    2. `define NEW_CASE_SV
    3. class new_case_seq extends my_sequence;
    4. extern function new(string name = "new_case_seq");
    5. extern virtual task body();
    6. `uvm_object_utils(new_case_seq)
    7. endclass: new_case_seq
    8. function new_case_seq::new(string name = "new_case_seq");
    9. super.new(name);
    10. endfunction: new
    11. task new_case_seq::body();
    12. repeat(10000) begin
    13. `uvm_do_with(my_tr, {my_tr.par_err == 0;})
    14. end
    15. #100;
    16. endtask: body
    17. class new_case extends base_test;
    18. extern function new(string name = "base_test", uvm_component parent=null);
    19. extern virtual function void build_phase(uvm_phase phase);
    20. `uvm_component_utils(new_case)
    21. endclass: new_case
    22. function new_case::new(string name = "base_test", uvm_component parent=null);
    23. super.new(name, parent);
    24. endfunction: new
    25. function void new_case::build_phase(uvm_phase phase);
    26. super.build_phase(phase);
    27. uvm_config_db #(uvm_object_wrapper)::set(
    28. this,
    29. "env.i_agt0.sqr.main_phase",
    30. "default_sequence",
    31. new_case_seq::type_id::get()
    32. );
    33. uvm_config_db #(uvm_object_wrapper)::set(
    34. this,
    35. "env.i_agt1.sqr.main_phase",
    36. "default_sequence",
    37. new_case_seq::type_id::get()
    38. );
    39. endfunction: build_phase
    40. `endif

  • 相关阅读:
    Fiddler下载与安装
    12.optimizer优化器和evaluate评估
    全面指南:如何使用Python编写代码,利用热像仪自动测量人员体温进行发热症状的早期筛查
    RK3588平台开发系列讲解(项目篇)视频监控之RTMP推流
    idea leetcode配置
    安卓12手机不能安装问题记录
    node内置模块——crypoty模块
    Spring(bean的生命周期)
    idea异常关闭后,端口被占用终极解决方案!
    C++ Primer学习笔记-----第十三章:拷贝控制
  • 原文地址:https://blog.csdn.net/moon9999/article/details/126210533