前言
【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. 4. class sanity_case_seq extends my_sequence; 5. 6. extern function new(string name = "sanity_case_seq"); 7. extern virtual task body(); 8. 9. `uvm_object_utils(sanity_case_seq) 10. endclass: sanity_case_seq 11. 12. function sanity_case_seq::new(string name = "sanity_case_seq"); 13. super.new(name); 14. endfunction: new 15. 16. task sanity_case_seq::body(); 17. repeat(10000) begin 18. `uvm_do_with(my_tr, {my_tr.par_err == 0;}) 19. end 20. #100; 21. endtask: body 22. 23. class sanity_case extends base_test; 24. 25. extern function new(string name = "base_test", uvm_component parent=null); 26. extern virtual function void build_phase(uvm_phase phase); 27. 28. `uvm_component_utils(sanity_case) 29. endclass: sanity_case 30. 31. function sanity_case::new(string name = "base_test", uvm_component parent=null); 32. super.new(name, parent); 33. endfunction: new 34. 35. function void sanity_case::build_phase(uvm_phase phase); 36. super.build_phase(phase); 37. uvm_config_db #(uvm_object_wrapper)::set( 38. this, 39. "env.i_agt0.sqr.main_phase", 40. "default_sequence", 41. sanity_case_seq::type_id::get() 42. ); 43. uvm_config_db #(uvm_object_wrapper)::set( 44. this, 45. "env.i_agt1.sqr.main_phase", 46. "default_sequence", 47. sanity_case_seq::type_id::get() 48. ); 49. 50. endfunction: build_phase 51. 52. `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. 6. to_key = re.sub("\.sv","",to) 7. to_uc = to_key.upper() 8. to_lc = to_key.lower() 9. 10. out_file = [] 11. with open(frm, "r") as handle: 12. hd = handle.readlines() 13. for line in hd: 14. line = line.strip("\n") 15. line = re.sub(frm_uc, to_uc, line) 16. line = re.sub(frm_lc, to_lc, line) 17. out_file.append(line) 18. 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. 4. class new_case_seq extends my_sequence; 5. 6. extern function new(string name = "new_case_seq"); 7. extern virtual task body(); 8. 9. `uvm_object_utils(new_case_seq) 10. endclass: new_case_seq 11. 12. function new_case_seq::new(string name = "new_case_seq"); 13. super.new(name); 14. endfunction: new 15. 16. task new_case_seq::body(); 17. repeat(10000) begin 18. `uvm_do_with(my_tr, {my_tr.par_err == 0;}) 19. end 20. #100; 21. endtask: body 22. 23. class new_case extends base_test; 24. 25. extern function new(string name = "base_test", uvm_component parent=null); 26. extern virtual function void build_phase(uvm_phase phase); 27. 28. `uvm_component_utils(new_case) 29. endclass: new_case 30. 31. function new_case::new(string name = "base_test", uvm_component parent=null); 32. super.new(name, parent); 33. endfunction: new 34. 35. function void new_case::build_phase(uvm_phase phase); 36. super.build_phase(phase); 37. uvm_config_db #(uvm_object_wrapper)::set( 38. this, 39. "env.i_agt0.sqr.main_phase", 40. "default_sequence", 41. new_case_seq::type_id::get() 42. ); 43. uvm_config_db #(uvm_object_wrapper)::set( 44. this, 45. "env.i_agt1.sqr.main_phase", 46. "default_sequence", 47. new_case_seq::type_id::get() 48. ); 49. 50. endfunction: build_phase 51. 52. `endif