• 电力电子转战数字IC20220725day56——寄存器模型


     

    目录

    uvm_reg

    寄存器模型集成

    总线UVC的实现

    寄存器访问方式

    前门访问

    后门访问


    • 寄存器:硬件模块之间交谈的窗口,读出reg状态获取硬件当前的状态,配置reg使其工作在一定模式下
    • 通过硬件的reg模型和总线UVC建立一个验证环境
      • reg有关的设计流程
      • reg model相关类
      • 将reg model集成到现有环境,与总线UVC桥接,与dut模型绑定
      • reg model常用方法和预定义的seq
      • reg测试和功能覆盖率
    • reg的域:WO,RO,RW,RC读后擦除clean_on_read,W1S只写一次write_one_to_set

    • reg按照地址索引的关系是按字对齐
    • 寄存器列表(块):将寄存器按照地址排列

    • 寄存器的中心化管理:保证通过软件建立reg模型与硬件reg的内容属性保持一致

    uvm_reg

     

    1. class ctrl_reg extends uvm_reg;
    2. `uvm_object_utils(ctrl_reg)
    3. uvm_reg_field reserved;
    4. rand uvm_reg_field pkt_len;//声明域,且可以随机化
    5. rand uvm_reg_field prio_level;
    6. rand uvm_reg_field chnl_en;
    7. function new(string name ="ctrl_reg");
    8. super.new(name, 32, UVM_NO_COVERAGE);
    9. endfunction
    10. virtual function build();
    11. reserved = uvm_reg_field::type_id::create("");
    12. pkt_len = uvm_reg_field::type_id::create("");
    13. prio_level = uvm_reg_field::type_id::create("");
    14. chnl_en = uvm_reg_field::type_id::create("");//例化
    15. reserved.configure(this, 26, 6, "RO", 0, 26'h0, 1, 0 , 0);//配置
    16. pkt_len.configure(this,3,3,"RW",0,3'h0,1,1,0);
    17. prio_level.configure(this,2,1,"RW",0,2'h3,1,1,0);
    18. chnl_en.configure(this,1,0,"RW",0,1'h0,1,1,0);
    19. endfunction
    20. endclass
    21. class stat_reg extends uvm_reg;
    22. `uvm_object_utils()
    23. uvm_reg_field reserved;//保留位的域
    24. rand uvm_reg_field fifo_avail;
    25. function new(string name="stat_reg");
    26. super.new(name, 32, UVM_NO_COVERAGE);
    27. endfunction
    28. virtual function build();
    29. reserved = uvm_reg_field::type_id::create("");
    30. fifo_avail= uvm_reg_field::type_id::create("");
    31. reserved.configure(this,24,8,"RO",0,24'h0,1,0,0);
    32. fifo_avail.configure(this,8,0,"RO",0,8'h0,1,1,0);
    33. endfunction
    34. endclass
    35. class mcdf_rgm extends uvm_reg_block;
    36. `uvm_object_utils(mcdf_rgm)
    37. rand ctrl_reg chnl0_ctrl_reg;
    38. rand ctrl_reg chnl1_ctrl_reg;
    39. rand ctrl_reg chnl2_ctrl_reg;
    40. rand stat_reg chnl0_stat_reg;
    41. rand stat_reg chnl1_stat_reg;
    42. rand stat_reg chnl2_stat_reg;
    43. uvm_reg_map map;
    44. function new(string name ="")
    45. super.new(name, UVM_NO_COVERAGE);
    46. endfunction
    47. virtual function build();
    48. chnl0_ctrl_reg=ctrl_reg::type_id::create("");
    49. chnl0_ctrl_reg.configure(this);//创建,配置,
    50. chnl0_ctrl_reg.build();
    51. chnl1_ctrl_reg=ctrl_reg::type_id::create("");
    52. chnl1_ctrl_reg.configure(this);
    53. chnl1_ctrl_reg.build();
    54. chnl2_ctrl_reg=ctrl_reg::type_id::create("");
    55. chnl2_ctrl_reg.configure(this);
    56. chnl2_ctrl_reg.build();
    57. chnl0_stat_reg=stat_reg::type_id::create("");
    58. chnl0_stat_reg.configure(this);
    59. chnl0_stat_reg.build();
    60. chnl1_stat_reg=stat_reg::type_id::create("");
    61. chnl1_stat_reg.configure(this);
    62. chnl1_stat_reg.build();
    63. chnl2_stat_reg=stat_reg::type_id::create("");
    64. chnl2_stat_reg.configure(this);
    65. chnl2_stat_reg.build();
    66. map=create_map("map", 'h0, 4, UVM_LITTLE_ENDIAN);//map名字,基地址,位宽,endianess
    67. map.add_reg(chnl0_ctrl_reg, 32'h00000000, "RW");//偏移地址offset addr
    68. map.add_reg(chnl1_ctrl_reg, 32'h00000004, "RW");//完整reg地址addr=base addr+offset addr
    69. map.add_reg(chnl2_ctrl_reg, 32'h00000008, "RW");
    70. map.add_reg(chnl0_stat_reg, 32'h00000010, "RO");//添加每个reg的偏移地址和访问属性(模式)
    71. map.add_reg(chnl1_stat_reg, 32'h00000014, "RO");
    72. map.add_reg(chnl2_stat_reg, 32'h00000018, "RO");
    73. lock_model();//reg构建后锁住这个模型,不允许外部访问寄存器内部,只可以用预测组件来改变
    74. endfunction
    75. endclass

    • 寄存器模型可以用来写一些激励

    寄存器模型集成

    总线UVC的实现

    • 控制reg接口在每一个clk解析cmd:写,读
    • 以下是8位地址线和32位数据线的总线UVC
    1. class mcdf_bus_trans extends uvm_sequence_item;
    2. rand bit[1:0] cmd;
    3. rand bit[7:0] addr;
    4. rand bit[31:0] data;
    5. bit[31:0] rdata;//从总线读回来的,不可随机化
    6. `uvm_object_utils_begin()...//注册以及域的自动化
    7. ...endclass
    8. class mcdf_bus_sequencer extends uvm_sequencer;
    9. virtual mcdf_if vif;
    10. `uvm_component_utils()
    11. ...//注册,例化
    12. function void build_phase(u p);
    13. if(!uvm_config_db#(virtual mcdf_if)::get(this, "", "vif", vif))begin
    14. `uvm_error("", "") end
    15. endfunction
    16. endclass
    17. class mcdf_bus_monitor extends uvm_monitor;//等下连接到uvm_reg_predictor
    18. virtual mcdf_if vif;
    19. uvm_analysis_port #(mcdf_bus_trans) ap;//monitor要广播
    20. `uvm_component_utils()
    21. ...
    22. function void build_phase(u p);
    23. if(!uvm_config_db#(virtual mcdf_if)::get(this, "", "vif", vif))begin
    24. `uvm_error("", "") end
    25. ap =new("", this);//不能用create,因为port不是object
    26. endfunction
    27. task run_phase(u p);
    28. forever begin
    29. mon_trnas() end
    30. endtask
    31. task mon_trans();
    32. mcdf_bus_trans t;
    33. @(posedge vif.clk);
    34. if(vif.cmd==`WRITE) begin
    35. t=new();
    36. t.cmd=`WRITE;
    37. t.addr=vif.addr;
    38. t.wdata=vif.wdata;
    39. ap.write(t);
    40. end
    41. else if(vif.cmd==`READ) begin
    42. t=new();
    43. t.cmd=`READ;
    44. t.addr=vif.addr;
    45. fork begin//等下一个周期
    46. @(posedge vif.clk);
    47. #10ps;
    48. t.rdata=vif.rdata;
    49. ap.write(t); end
    50. join_none//的同时不错过下一拍
    51. end
    52. endtask
    53. endclass
    54. class mcdf_bus_driver extends uvm_driver;
    55. virtual mcdf_if vif;
    56. ...//注册+例化
    57. function void build_phase(u p);
    58. if(!uvm_config_db#(virtual mcdf_if)::get(this, "", "vif", vif))begin
    59. `uvm_error("", "") end
    60. endfunction
    61. task run_phase(u p);
    62. REQ tmp;
    63. mcdf_bus_trans req, rsp;
    64. reset_listener();
    65. forever begin
    66. seq_item_port.get_next_item(tmp);
    67. void'($cast(req,tmp));
    68. `uvm_info("got")
    69. void'($cast(rsp, req.clone()));
    70. rsp.set_sequence_id(req.get_sequence_id());
    71. rsp.set_transaction_id(req.get_transaction_id());
    72. driver_bus(rsp);
    73. set_item_port.item_done(rsp);
    74. `uvm_info("sent")
    75. end
    76. endtask
    77. task reset_listener();
    78. fork
    79. forever begin
    80. @(negdege vif.rstn) drive_idle();
    81. end
    82. join_none
    83. endtask
    84. task drive_bus(mcdf_bus_trans t);
    85. case (t.cmd)
    86. `WRITE:drive_write(t);
    87. `READ :drive_read(t);
    88. `IDLE :drive_idle();
    89. default: `uvm_error()
    90. endcase
    91. endtask
    92. task drive_write(mcdf_bus_trans t);
    93. @(posedge vif.clk);
    94. vif.cmd<=t.cmd;
    95. vif.addr<=t.addr;
    96. vif.data<=t.wdata;
    97. endtask
    98. task drive_read(mcdf_bus_trans t);
    99. @(posedge vif.clk);
    100. vif.cmd<=t.cmd;
    101. vif.addr<=t.addr;
    102. @(posedge vif.clk);
    103. #10ps;
    104. t.rdata=vif.rdata;
    105. endtask
    106. task drive_idle(bit is_sync=0);
    107. if(is_sync) @(posedge vif.clk);
    108. vif.cmd<='h0;
    109. vif.addr<='h0;
    110. vif.data<='h0;
    111. endtask
    112. endclass
    113. class mcdf_bus_agent extends uvm_agent;
    114. mcdf_bus_driver driver;
    115. mcdf_bus_sequencer sequencer;
    116. mcdf_bus_monitor monitor;
    117. ...
    118. function void build_phase(u p);
    119. driver =mcdf_bus_driver::type_id::create("", this);
    120. sequencer=mcdf_bus_sequencer::type_id::create("", this);
    121. monitor =mcdf_bus_monitor::type_id::create("", this);
    122. endfunction
    123. function void connect_phase(u p);
    124. driver.seq_item_port.connect(sequencer.seq_item_export);
    125. endfunction
    126. endclass

    硬件reg

    module ctrl_regs();
    

    还差个adapter和predictor

    1. class ref2mcdf_adapter extends uvm_reg_adapter;
    2. `uvm_object_utils()
    3. function new(string name ="");
    4. super.new(name);
    5. provides_responses=1;//enable了provides_responses,总线可以返回rsp的数据
    6. endfunction
    7. //预定义的,也是必须实现的,名字一个字都不能差
    8. function uvm_sequence_item reg2bus (const ref uvm_reg_bus_op rw);
    9. mcdf_bus_trans t=mcdf_bus_trnas::type_id::create("t");//创建子类对象
    10. t.cmd=(rw.kind == UVM_WRITE)? `WRITE : `READ;
    11. t.addr=rw.addr;
    12. t.wdata=rw.data;
    13. return t;//做了隐式转换
    14. endfunction//完成了寄存器级别操作rw到bus上的桥接,下面的func反之
    15. function void bus2reg(uvm_sequence_item bus_item, ref uvm_reg_bus_op rw);
    16. //从driver将数据写会sequencer,adapter从sqr拿到rsp(t)后自动调用
    17. mcdf_bus_trans t;
    18. if(!$cast(t, bus_item)) begin//父类句柄,转换成子类mcdf_bus_trans句柄
    19. `uvm_fatal("", "")
    20. return; end
    21. rw.kind=(t.cmd==`WRITE)? UVM_WRITE : UVM_READ;//转换后才可以访问子类对象
    22. rw.addr=t.addr;
    23. rw.data=(t.cmd==`WRITE)? t.wdata : t.rdata;
    24. rw.status=UVM_IS_OK;
    25. endfunction
    26. endclass

     uvm_reg_bus_op包含这些成员变量,要转换成mcdf_bus_trans

    • 如何将adapter集成到环境中?

      • 从test层传入寄存器模型rgm句柄,在顶层例化后通过uvm_config_db进行配置
      • rgm在创建后要调用build()函数,因为uvm_reg_block是object类型,其预定义的build()不会自动执行
      • 这里由于还没集成predictor,所以调用set_auto_predict(),采用auto prediction方式
      • 顶层连接时,需要将rgm的map组件和bus sequencer和adapter连接(reg信息-总线侧激励驱动-reg级别和硬件总线级别的桥接),adapter的桥接功能才可以工作
      1. class mcdf_bus_env extends uvm_env;
      2. mcdf_bus_agent agent;
      3. mcdf_rgm rgm;
      4. reg2mcdf_adapter reg2mcdf;
      5. ...//注册+例化
      6. function void build_phase(u p);
      7. agent=mcdf_bus_agent::type_id::create("", this);
      8. if(!uvm_config_db#(mcdf_rgm)::get(this, "", "rgm", rgm)) begin
      9. `uvm_info()
      10. rgm=mcdf_rgm::type_id::create("", this);
      11. end
      12. rgm.build();//创建,配置reg,调用各个reg的build,以及它们的field
      13. rgm.map.set_auto_predict();
      14. reg2mcdf=reg2mcdf_adapter::type_id::create("");
      15. endfunction
      16. function void connect_phase(u p);
      17. rgm.map.set_sequencer(agent.sequencer, reg2mcdf);//!连接
      18. endfunction
      19. endclass
      20. class test1 extends uvm_test;
      21. mcdf_rgm rgm;
      22. mcdf_bus_env env;
      23. ...//注册+例化
      24. function void build_phase(u p);
      25. rgm=mcdf_rgm::type_id::create("", this);
      26. uvm_config_db#(mcdf_rgm)::set(this, "env*", "rgm", rgm)
      27. env=mcdf_bus_env::type_id::create("", this);
      28. endfunction
      29. task run_phase(u p); ...
      30. endclass

    寄存器访问方式

    前门访问

    • 在rgm上做读写操作,最终会通过总线UVC来实现总线上的物理时序访问
    1. class mcdf_example_seq extends uvm_reg_sequence;
    2. mcdf_rgm rgm;
    3. `uvm_object_utils()
    4. `uvm_declare_p_sequencer(mcdf_bus_sequencer)
    5. ...
    6. task body();
    7. uvm_status_e status;
    8. uvm_reg_data_t data;
    9. if(!uvm_config_db#(mcdf_rgm)::get(null, get_full_name(), "rgm", rgm)) begin
    10. `uvm_error("", "") end
    11. //方式1:uvm_reg::read()/write()
    12. rgm.chnl0_ctrl_reg.read (status, data, UVM_FRONTDOOR, .parent(this));
    13. rgm.chnl0_ctrl_reg.write(status, 'h11, UVM_FRONTDOOR, .parent(this));
    14. rgm.chnl0_ctrl_reg.read (status, data, UVM_FRONTDOOR, .parent(this));
    15. //方式2:uvm_reg_sequence::read_reg()/write_reg()
    16. read_reg (rgm.chnl1_ctrl_reg.read, status, data, UVM_FRONTDOOR);
    17. write_reg (rgm.chnl1_ctrl_reg.read, status, 'h22, UVM_FRONTDOOR);
    18. read_reg (rgm.chnl1_ctrl_reg.read, status, data, UVM_FRONTDOOR);
    19. endtask
    20. endclass

    后门访问

    • 利用UVM DPI (uvm_hdl_read()和uvm_hdl_deposit()),将reg的操作直接作用到DUT内的寄存器变量,不通过物理总线访问,不是真实的硬件行为,速度快不消耗时间
    • 首先需要确保rgm在建立时是否将各个reg映射到DUT一侧的HDL路径,如下
    1. class mcdf_rgm extends uvm_reg_block;
    2. ...//reg成员,map声明
    3. virtual function build();
    4. ...//创建
    5. add_hdl_path("reg_backdoor_access,dut");
    6. chnl0_ctrl_reg.add_hdl_path_slice($sformat("regs[%0d]", `SLV0_RW_REG), 0,32);
    7. chnl1_ctrl_reg.add_hdl_path_slice($sformat("regs[%0d]", `SLV1_RW_REG), 0,32);
    8. chnl2_ctrl_reg.add_hdl_path_slice($sformat("regs[%0d]", `SLV2_RW_REG), 0,32);
    9. chnl0_stat_reg.add_hdl_path_slice($sformat("regs[%0d]", `SLV0_R_REG), 0,32);
    10. chnl1_stat_reg.add_hdl_path_slice($sformat("regs[%0d]", `SLV1_R_REG), 0,32);
    11. chnl2_stat_reg.add_hdl_path_slice($sformat("regs[%0d]", `SLV2_R_REG), 0,32);
    12. lock_model();//结束地址映射关系,保证model不会被其他用户修改
    13. endfunction
    14. endclass

    1. class mcdf_example_seq extends uvm_reg_sequence;
    2. mcdf_rgm rgm;
    3. `uvm_object_utils()
    4. `uvm_declare_p_sequencer(mcdf_bus_sequencer)
    5. ...
    6. task body();
    7. uvm_status_e status;
    8. uvm_reg_data_t data;
    9. if(!uvm_config_db#(mcdf_rgm)::get(null, get_full_name(), "rgm", rgm)) begin
    10. `uvm_error("", "") end
    11. //read()/write()
    12. rgm.chnl0_ctrl_reg.read (status, data, UVM_BACKDOOR, .parent(this));
    13. rgm.chnl0_ctrl_reg.write(status, 'h11, UVM_BACKDOOR, .parent(this));
    14. rgm.chnl0_ctrl_reg.read (status, data, UVM_BACKDOOR, .parent(this));
    15. rgm.chnl1_ctrl_reg.peek (status, data, .parent(this));
    16. rgm.chnl1_ctrl_reg.poke (status, 'h22, .parent(this));
    17. rgm.chnl1_ctrl_reg.peek (status, data, .parent(this));
    18. //peek()/poke()
    19. read_reg (rgm.chnl2_ctrl_reg.read, status, data, UVM_BACKDOOR);
    20. write_reg (rgm.chnl2_ctrl_reg.read, status, 'h22, UVM_BACKDOOR);
    21. read_reg (rgm.chnl2_ctrl_reg.read, status, data, UVM_BACKDOOR);
    22. peek_reg (rgm.chnl2_ctrl_reg, status, data);//peek读取reg
    23. poke_reg (rgm.chnl2_ctrl_reg, status, 'h33);//poke修改reg
    24. peek_reg (rgm.chnl2_ctrl_reg, status, data);
    25. endtask
    26. endclass

    二者比较如下

  • 相关阅读:
    【.NET 6】使用EF Core 访问Oracle+Mysql+PostgreSQL并进行简单增改操作与性能比较
    【Oracle】Oracle系列之十一--PL/SQL
    上周热点回顾(10.3-10.9)
    红杉资本:生成式AI 一个创造性的新世界
    边缘智能模型训练、推理的关键技术
    Vue:搭建前端项目-----我给你打个样
    C# 实时监控双门双向门禁控制板源码
    HALCON 22.11来了
    Spring Security中文文档
    格式转换 ▏Python 实现Word转HTML
  • 原文地址:https://blog.csdn.net/weixin_39668316/article/details/126007682