• 电力电子转战数字IC20220824day68——uvm实战3


     寄存器模型的自动化生成

     编写excel文件,后缀为csv;编写python脚本

    才cmd中输入这两个文件的路径和命名就可以自动生成寄存器模型rgm

     

     

     寄存器模型的更新

    最开始的寄存器模型是这样的

     

     

     在reg_pkg中,这些接口信号作为uvm_sequence_item定义为reg_trans类。约束,注册,域的自动化,new函数,一个不要落。

    1. class reg_trans extends uvm_sequence_item;
    2. rand bit[7:0] addr;
    3. rand bit[1:0] cmd;
    4. rand bit[31:0] data;
    5. bit rsp;
    6. constraint cstr {
    7. soft cmd inside {`WRITE, `READ, `IDLE};
    8. soft addr inside {`SLV0_RW_ADDR, `SLV1_RW_ADDR, `SLV2_RW_ADDR, `SLV0_R_ADDR, `SLV1_R_ADDR, `SLV2_R_ADDR};
    9. addr[7:4]==0 && cmd==`WRITE -> soft data[31:6]==0;
    10. soft addr[7:5]==0;
    11. addr[4]==1 -> soft cmd == `READ;
    12. };
    13. `uvm_object_utils_begin(reg_trans)
    14. `uvm_field_int(addr, UVM_ALL_ON)
    15. `uvm_field_int(cmd, UVM_ALL_ON)
    16. `uvm_field_int(data, UVM_ALL_ON)
    17. `uvm_field_int(rsp, UVM_ALL_ON)
    18. `uvm_object_utils_end
    19. function new (string name = "reg_trans");
    20. super.new(name);
    21. endfunction
    22. endclass

     

     item由driver驱动

    1. class reg_driver extends uvm_driver #(reg_trans);
    2. local virtual reg_intf intf;
    3. `uvm_component_utils(reg_driver)
    4. function new (string name = "reg_driver", uvm_component parent);
    5. super.new(name, parent);
    6. endfunction
    7. function void set_interface(virtual reg_intf intf);
    8. if(intf == null)
    9. $error("interface handle is NULL, please check if target interface has been intantiated");
    10. else
    11. this.intf = intf;
    12. endfunction
    13. task run_phase(uvm_phase phase);
    14. fork
    15. this.do_drive();
    16. this.do_reset();
    17. join
    18. endtask
    19. task do_reset();
    20. forever begin
    21. @(negedge intf.rstn);
    22. intf.cmd_addr <= 0;
    23. intf.cmd <= `IDLE;
    24. intf.cmd_data_m2s <= 0;
    25. end
    26. endtask
    27. task do_drive();
    28. reg_trans req, rsp;
    29. @(posedge intf.rstn);
    30. forever begin
    31. seq_item_port.get_next_item(req);
    32. this.reg_write(req);
    33. void'($cast(rsp, req.clone()));
    34. rsp.rsp = 1;
    35. rsp.set_sequence_id(req.get_sequence_id());
    36. seq_item_port.item_done(rsp);
    37. end
    38. endtask
    39. task reg_write(reg_trans t);
    40. @(posedge intf.clk iff intf.rstn);
    41. case(t.cmd)
    42. `WRITE: begin
    43. intf.drv_ck.cmd_addr <= t.addr;
    44. intf.drv_ck.cmd <= t.cmd;
    45. intf.drv_ck.cmd_data_m2s <= t.data;
    46. end
    47. `READ: begin
    48. intf.drv_ck.cmd_addr <= t.addr;
    49. intf.drv_ck.cmd <= t.cmd;
    50. repeat(2) @(negedge intf.clk);
    51. t.data = intf.cmd_data_s2m;
    52. end
    53. `IDLE: begin
    54. this.reg_idle();
    55. end
    56. default: $error("command %b is illegal", t.cmd);
    57. endcase
    58. `uvm_info(get_type_name(), $sformatf("sent addr %2x, cmd %2b, data %8x", t.addr, t.cmd, t.data), UVM_HIGH)
    59. endtask
    60. task reg_idle();
    61. @(posedge intf.clk);
    62. intf.drv_ck.cmd_addr <= 0;
    63. intf.drv_ck.cmd <= `IDLE;
    64. intf.drv_ck.cmd_data_m2s <= 0;
    65. endtask
    66. endclass

     

     

     一共6个寄存器对应的csv文档如下

     更新后的结构图如下,寄存器被换成了APB总线?

    寄存器接口如下

     

     根据v1.csv和寄存器图,以及寄存器接口中的信号,更新寄存器为v2

     这是自己的傻逼更新,需要更改的地方是:预留区域reserved为RO只读,id的重置值不是全部为0;域不是信号名;free slot的重置值时'd32

     用相同的操作获得rgm.pkg。寄存器模型每个reg为一个类,最后多一个类mcdf_reg

     每个寄存器类的结构都是相似的:注册,声明域,域的覆盖组;new函数中有条件例化覆盖组;build_phase完成域的例化和配置;与覆盖组相对应的采样函数。

    在最后的mcdf_rgm中,所有寄存器class被作为随机变量,声明寄存器map,build_phase中对每个寄存器进行例化、配置、调用build、例化map+每个寄存器偏移地址,预留了后门访问的添加路径。最后是lock_model,这部分要再复习一下uvm的寄存器模型。

    1. class mcdf_rgm extends uvm_reg_block;
    2. `uvm_object_utils(mcdf_rgm)
    3. rand slv_en_reg slv_en;
    4. rand parity_err_clr_reg parity_err_clr;
    5. rand slv_id_reg slv_id;
    6. rand slv_len_reg slv_len;
    7. rand slv0_free_slot_reg slv0_free_slot;
    8. rand slv1_free_slot_reg slv1_free_slot;
    9. rand slv2_free_slot_reg slv2_free_slot;
    10. rand slv3_free_slot_reg slv3_free_slot;
    11. rand slv0_parity_err_reg slv0_parity_err;
    12. rand slv1_parity_err_reg slv1_parity_err;
    13. rand slv2_parity_err_reg slv2_parity_err;
    14. rand slv3_parity_err_reg slv3_parity_err;
    15. uvm_reg_map map;
    16. function new(string name = "mcdf_rgm");
    17. super.new(name, UVM_NO_COVERAGE);
    18. endfunction
    19. virtual function void build();
    20. slv_en = slv_en_reg::type_id::create("slv_en");
    21. slv_en.configure(this);
    22. slv_en.build();
    23. parity_err_clr = parity_err_clr_reg::type_id::create("parity_err_clr");
    24. parity_err_clr.configure(this);
    25. parity_err_clr.build();
    26. slv_id = slv_id_reg::type_id::create("slv_id");
    27. slv_id.configure(this);
    28. slv_id.build();
    29. slv_len = slv_len_reg::type_id::create("slv_len");
    30. slv_len.configure(this);
    31. slv_len.build();
    32. slv0_free_slot = slv0_free_slot_reg::type_id::create("slv0_free_slot");
    33. slv0_free_slot.configure(this);
    34. slv0_free_slot.build();
    35. slv1_free_slot = slv1_free_slot_reg::type_id::create("slv1_free_slot");
    36. slv1_free_slot.configure(this);
    37. slv1_free_slot.build();
    38. slv2_free_slot = slv2_free_slot_reg::type_id::create("slv2_free_slot");
    39. slv2_free_slot.configure(this);
    40. slv2_free_slot.build();
    41. slv3_free_slot = slv3_free_slot_reg::type_id::create("slv3_free_slot");
    42. slv3_free_slot.configure(this);
    43. slv3_free_slot.build();
    44. slv0_parity_err = slv0_parity_err_reg::type_id::create("slv0_parity_err");
    45. slv0_parity_err.configure(this);
    46. slv0_parity_err.build();
    47. slv1_parity_err = slv1_parity_err_reg::type_id::create("slv1_parity_err");
    48. slv1_parity_err.configure(this);
    49. slv1_parity_err.build();
    50. slv2_parity_err = slv2_parity_err_reg::type_id::create("slv2_parity_err");
    51. slv2_parity_err.configure(this);
    52. slv2_parity_err.build();
    53. slv3_parity_err = slv3_parity_err_reg::type_id::create("slv3_parity_err");
    54. slv3_parity_err.configure(this);
    55. slv3_parity_err.build();
    56. map = create_map("map", 'h0, 4, UVM_LITTLE_ENDIAN);
    57. map.add_reg(slv_en, 32'h00, "RW");
    58. map.add_reg(parity_err_clr, 32'h04, "RW");
    59. map.add_reg(slv_id, 32'h08, "RW");
    60. map.add_reg(slv_len, 32'h0C, "RW");
    61. map.add_reg(slv0_free_slot, 32'h80, "RO");
    62. map.add_reg(slv1_free_slot, 32'h84, "RO");
    63. map.add_reg(slv2_free_slot, 32'h88, "RO");
    64. map.add_reg(slv3_free_slot, 32'h8C, "RO");
    65. map.add_reg(slv0_parity_err, 32'h90, "RO");
    66. map.add_reg(slv1_parity_err, 32'h94, "RO");
    67. map.add_reg(slv2_parity_err, 32'h98, "RO");
    68. map.add_reg(slv3_parity_err, 32'h9C, "RO");
    69. //slv_en.add_hdl_path_slice("???", 0, 32);
    70. //parity_err_clr.add_hdl_path_slice("???", 0, 32);
    71. //slv_id.add_hdl_path_slice("???", 0, 32);
    72. //slv_len.add_hdl_path_slice("???", 0, 32);
    73. //slv0_free_slot.add_hdl_path_slice("???", 0, 32);
    74. //slv1_free_slot.add_hdl_path_slice("???", 0, 32);
    75. //slv2_free_slot.add_hdl_path_slice("???", 0, 32);
    76. //slv3_free_slot.add_hdl_path_slice("???", 0, 32);
    77. //slv0_parity_err.add_hdl_path_slice("???", 0, 32);
    78. //slv1_parity_err.add_hdl_path_slice("???", 0, 32);
    79. //slv2_parity_err.add_hdl_path_slice("???", 0, 32);
    80. //slv3_parity_err.add_hdl_path_slice("???", 0, 32);
    81. //add_hdl_path("???");
    82. lock_model();
    83. endfunction
    84. endclass

  • 相关阅读:
    ClickHouse进阶(十三):Clickhouse数据字典-3-文件数据源及Mysql数据源
    技术阅读周刊第十四期:常用的 Git 配置
    计算机竞赛 题目: 基于深度学习的疲劳驾驶检测 深度学习
    docker部署redis集群 删除节点(缩容)
    uniapp 防抖节流封装和使用
    Vue(模板语法1)
    leetCode 21.合并两个有序链表
    XUbuntu22.04之查找进程号pidof、pgrep总结(一百九十)
    【ESP8266点焊机】基于 ESP8266 for Arduino
    学了PS了还用学习AI吗,有什么区别
  • 原文地址:https://blog.csdn.net/weixin_39668316/article/details/126509034