• 电力电子转战数字IC20220718-19day51-52——TLM通信


    目录

    10. 通信

    TLM通信

    端口声明

    对应关系

    常规步骤

    实例

    单向通信

    实例

    双向通信

    实例

    多向通信

    通信管道

    uvm_tlm_fifo

    analysis port

    analysis TLM FIFO

    req&rsp通信管道


     

    10. 通信

    TLM通信

    系统原型,芯片验证

    • 作用:更快实现硬件原型之间/验证组件之间的数据通信
    • 将模块内的计算和模块之间的通信从时间跨度方面剥离开
    • 条件:需要两个通信的对象
      • initiator:发起通信请求
      • target:发起通信的响应方
      • 按照transaction的流向可以分为producer和consumer
    • 用户需要将tlm在target一端中实现,便于initiator以后调用target的通信方法
    • 最后,在更高层次中连接两个对象,在两个对象中创建TLM端口
    • 步骤:
      • 分辨initiator和target,分辨producer和consumer
      • 在target中实现TLM通信方法
      • 在两个对象中创建TLM端口
      • 在更高层次将两个对象的端口进行连接
    • 数据流向分为单向和双向。单向只有initiator发出req,双向还有target发出rsp返回给initiator
    • 端口分为:
      • port:initiator的发起端
      • export:中间层次的端口
      • imp:target接受req的末端,imp的连接无法再次延伸
    • 单双向*端口类型
      • uvm_void
        • uvm_port_base
          • uvm_UNDIR_port #(trans_t)
          • uvm_UNDIR_export #(trans_t)
          • uvm_UNDIR_imp #(trans_t, imp_parent_t)
          • uvm_BIDIR_port #(req_trans_t, rsp_trans_t)
          • uvm_BIDIR_export #(req_trans_t, rsp_trans_t)
          • uvm_BIDIR_imp #(req_trans_t, rsp_trans_t, imp_parent_t)

    端口声明

    • 单向端口声明(前3个)
      • 声明port和export作为req的发起方,指定trans类型
      • 声明imp作为req的接收方,指定trans类型+parent指定所在的组件类型
    • 双向端口声明(后3个):trans拆成req和rsp

    对应关系

    • initiator例化port,中间层次例化export,target例化imp
    • 多个port可以连到同一个export或imp,反之就不行,一个port或export不能连到多个imp(traget)
    • req的起点是port,终点是imp,中间可以穿越多个层次,但是建议在穿越的层次中声明export
    • port可任意连接;export不能连接port;imp只能作为终点,无法扩展连接

    常规步骤

    • 定义TLM传输的数据类型
    • 在各个层次的component声明并创建端口对象
    • connect()完成端口连接
    • imp中需要提供给initiator的可调用方法,必须!否则端口连接了也无法进行数据传输

    实例

     

    1. class request extends uvm_transaction;
    2. byte cmd;
    3. int addr;
    4. int req;
    5. endclass
    6. class response extends uvm_transaction;
    7. byte cmd;
    8. int addr;
    9. int rsp;
    10. int status;
    11. endclass
    12. class comp1 extends uvm_agent;
    13. uvm_blocking_get_port #(request) bg_port;//port被数据流指向为get
    14. `uvm_component_utils(comp1)
    15. ...
    16. endclass
    17. class comp2 extends uvm_agent;
    18. uvm_blocking_get_port #(request) bg_port;
    19. uvm_nonblocking_put_imp #(request, comp2) nbp_imp;//imp被数据流指向为put
    20. `uvm_component_utils(comp2)
    21. ...
    22. function bit try_put (request req);
    23. function bit can_put();
    24. endclass
    25. class comp3 extends uvm_agent;
    26. uvm_blocking_transport_port #(request, response) bt_port;//双向端口transport
    27. `uvm_component_utils(comp3)
    28. ...
    29. endclass
    30. class comp4 extends uvm_agent;
    31. uvm_blocking_get_imp #(request, comp4) bg_imp;//发送数据流的imp是get
    32. uvm_nonblocking_put_port #(request) nbp_port;//发送数据流的port是put
    33. `uvm_component_utils(comp3)
    34. ...
    35. task get(output request req);
    36. endclass
    37. class comp5 extends uvm_agent;
    38. uvm_blocking_transport_imp #(request, response, comp5) bt_imp;//双向imp
    39. `uvm_component_utils(comp5)
    40. ...
    41. task transport(request req, output response rsp);
    42. endclass
    43. class agent1 extends uvm_agent;
    44. uvm_blocking_get_port #(request) bg_port;//从上往下依次对应3个端口
    45. uvm_nonblocking_put_export #(request) nbp_exp;
    46. uvm_blocking_transport_port #(request, response) bt_port;
    47. comp1 c1;
    48. comp2 c2;
    49. comp3 c3;
    50. `uvm_compontne_utils(agent1)
    51. ...
    52. function void build_phase(uvm_phase phase);
    53. super.build_phase(phase);
    54. c1=comp1::type_id::create("c1", this);
    55. c2=comp2::type_id::create("c2", this);
    56. c3=comp3::type_id::create("c3", this);
    57. endfunction
    58. function void connect_phase(uvm_phase phase);
    59. super.connect_phase(phase);
    60. c1.bg_port.connect(this.bg_port);//comp1的bg_port连到this agent上的bg_port
    61. c2.bg_port.connect(this.bg_port);//port连到export
    62. this.nbp_exp.connect(c2.nbp.imp);//export连到imp

    单向通信

    • 单一数据流向的TLM端口类型

      • uvm_blocking_put_PORT;
      • uvm_nonblocking_put_PORT;
      • uvm_put_PORT;
      • uvm_blocking_get_PORT;
      • uvm_nonblocking_get_PORT;
      • uvm_get_PORT;
      • uvm_blocking_peek_PORT;
      • uvm_nonblocking_peek_PORT;
      • uvm_peek_PORT;
      • uvm_blocking_get_peek_PORT;
      • uvm_nonblocking_get_peek_PORT;
      • uvm_get_peek_PORT;

      总结成表格如下:

      uvm_

      putgetpeekget_peek
      blocking(task)
      nonblocking(function)

      _PORT=port/export/imp

    对应的方法声明如下:

     

    • 通信两个要素
      • 哪种方法
      • 是否阻塞
    • blocking的
      • put():initiator生成数据T t传送到target
      • get():initiator从target获得数据T t
      • peek():同get,但是target中的数据T t保留着
    • nonblocking的
      • try_put():
      • can_put():
      • try_get():
      • can_get():
      • try_peek():
      • can_peek():

    实例

     

    1. class itrans extends uvm_transaction;
    2. int id;
    3. int data;
    4. endclass
    5. class otrans extends uvm_transaction;
    6. int id;
    7. int data;
    8. endclass
    9. class comp1 extends uvm_component;
    10. uvm_nonblocking_get_port #(otrans) nbg_port;//接收
    11. uvm_blocking_put_port #(itrans) bp_port;//发送数据
    12. `uvm_component_utils(comp1)
    13. ...
    14. endclass
    15. class comp2 extends uvm_component;
    16. uvm_blocking_put_imp #(itrans, comp2) bp_imp;
    17. uvm_nonblocking_get_imp #(otrans, comp2) nbg_imp;
    18. itrans itr_q[$];
    19. `uvm_component_utils(comp2)
    20. ...
    21. task put(itrans t);
    22. itr_q.push_back(t);
    23. endtask
    24. function bit try_get (output otrans t);
    25. itrans i;
    26. if(itr_q.size() != 0) begin
    27. i=itr_q.pop_front();
    28. t=new("t", this);
    29. t.id=i.id;
    30. t.data=i.data<<8;
    31. return 1; end
    32. else return 0;
    33. endfunction
    34. function bit can_get();
    35. if(itr_q.size()!=0) return 1;
    36. else return 0;
    37. endfunction
    38. endclass
    39. class env1 extends uvm_env;
    40. comp1 c1;
    41. comp2 c2;
    42. `uvm_component_utols(env1)
    43. ...
    44. function void build_phase(uvm_phase phase);
    45. super.build_phase(phase);
    46. c1=comp1::type_id::create("c1", this);
    47. c2=comp2::type_id::create("c2", this);
    48. endfunction
    49. function void connect_phase(uvm_phase phase);
    50. super.connect_phase(phase);
    51. c1.bp_port.connect(c2.bp_imp);
    52. c2.nbg_port.connect(c2.nbg_imp);
    53. endfunction
    54. endclass
    55. //................................................
    56. task run_phase(uvm_phase phase);
    57. itrans itr;
    58. otrans otr;
    59. int trans_num=2;
    60. fork
    61. begin
    62. for(int i=0; i
    63. itr=new("itr", this);
    64. itr.id=i;
    65. itr.data='h10+i;
    66. this.bp_port.put(itr);//连接的imp中定义的put()
    67. `uvm_info("PUT", $sformatf("'h%0x, 'h%0x", itr.id, itr.data), UVM_LOW) end
    68. end
    69. begin
    70. for(int j=0; j
    71. forever begin
    72. if(this.nbg.port.try_get(otr)==1) break;
    73. else #1ns; end
    74. `uvm_info("TRYGET", $sformatf("'h%0x, 'h%0x", otr.id, otr.data), UVM_LOW)
    75. end
    76. join

    双向通信

    • 双向端口
      • uvm_blocking_transport_PORT
      • uvm_nonblocking_transport_PORT
      • uvm_transport_PORT
      • uvm_blocking_master_PORT
      • uvm_nonblocking_master_PORT
      • uvm_master_PORT
      • uvm_blocking_slave_PORT
      • uvm_nonblocking_slave_PORT
      • uvm_slave_PORT
    transportmasterslave
    blocking(task)
    nonblocking(function)

    对应的方法

     

    • 两种通信方式
      • transport:通过方法transport()完成req和rsp的发出和返回,1个方法完成1次握手
      • master+slave:必须分别调用put、get、peek完成,调用两个方法完成1次握手通信
    • initiator作为master时,发起req到target并获取rsp回来
    • initiator作为slave时,从target获取req再发送rsp

    实例

     

    1. class comp1 extends uvm_component;
    2. uvm_blocking_transport_port #(itrans, otrans) bt_port;
    3. `uvm_component_utils(comp1)
    4. ...
    5. task run_phase(uvm_phase phase);
    6. itrans itr;
    7. otrans otr;
    8. int trans_num=2;
    9. for (int i=0; i
    10. itr=new("itr", this);
    11. itr.id=i;
    12. itr.data='h10+i;
    13. this.bt_port.transport(itr, otr);
    14. `uvm_info("TRANSPORT", $sformatf("'h%0x, 'h%0x, 'h%0x, 'h%0x", itr.id, itr.data, otr.id, otr.data), UVM_LOW)
    15. end
    16. endtask
    17. endclass
    18. class comp2 extends uvm_component;
    19. uvm_blocking_transport_imp #(itrans, otrans, comp2) bt_imp;
    20. `uvm_component_utils(comp2)
    21. ...
    22. task transport(itrans req, output otrans rsp);
    23. rsp=new("rsp", this);
    24. rsp.id=req.id;
    25. rsp.data=req.data<<8;
    26. endtask
    27. endclass
    28. class env1 extends uvm_env;
    29. comp1 c1;
    30. comp2 c2;
    31. `uvm_component_utils(comp2)
    32. ...
    33. function void build_phase(uvm_phase phase);
    34. super.build_phase(phase);
    35. c1=comp1::type_id::create("c1", this);
    36. c2=comp2::type_id::create("c2", this);
    37. endfunction
    38. function void connect_phase(uvm_phase phase);
    39. super.connect_phase(phase);
    40. c1.bt_port.connect(c2.bt_imp);
    41. endfunction
    42. endclass

    多向通信

    • 两个组件之间的通信:initiator和target之间的相同TLM端口数量超过1个
    • 问题:相同的端口,端口名字可以不一样,方法会出现同名的问题
    • 方法:UVM端口宏声明(`上述端口类型_decl(SFX)),sfx表示后缀名称

     

    1. `uvm_blocking_put_imp_decl(_p1)
    2. `uvm_blocking_put_imp_decl(_p2)
    3. class comp1 extends uvm_component;
    4. uvm_blocking_put_port #(itrans) bt_port1;//不需要做区分
    5. uvm_blocking_put_port #(itrans) bt_port2;
    6. `uvm_component_utils(comp1)
    7. ...
    8. task run_phase(uvm_phase phase);
    9. itrans itr1, itr2;
    10. int trans_num=2;
    11. fork
    12. for (int i=0; i
    13. itr1=new("itr1", this);
    14. itr1.id=i;
    15. itr1.data='h10+i;
    16. this.bp_port1.put(itr1);//不是put_p1
    17. end
    18. for (int i=0; i
    19. itr2=new("itr2", this);
    20. itr2.id=i;
    21. itr2.data='h10+i;
    22. this.bp_port2.put(itr2);//不是put_p2
    23. end
    24. join
    25. endtask
    26. endclass
    27. class comp2 extends uvm_component;
    28. uvm_blocking_put_imp_p1 #(itrans, comp2) bt_imp_p1;
    29. uvm_blocking_put_imp_p2 #(itrans, comp2) bt_imp_p2;
    30. itrans itr_q[$];
    31. semaphore key;//共享资源,互斥资源的保护
    32. `uvm_component_utils(comp2)
    33. ...
    34. task put_p1(itrans t);
    35. key.get();
    36. itr_q.push_back(t);
    37. `uvm_info("PUTP1", $sformatf("'h%0x, 'h%0x", t.id, t.data), UVM_LOW)
    38. key.put();
    39. endtask
    40. task put_p2(itrans t);
    41. key.get();
    42. itr_q.push_back(t);
    43. `uvm_info("PUTP2", $sformatf("'h%0x, 'h%0x", t.id, t.data), UVM_LOW)
    44. key.put();
    45. endtask
    46. endclass
    47. class env1 extends uvm_env;
    48. comp1 c1;
    49. comp2 c2;
    50. `uvm_component_utils(env1)
    51. ...
    52. function void build_phase(uvm_phase phase);
    53. super.build_phase(phase);
    54. c1=comp1::type_id::create("c1", this);
    55. c2=comp2::type_id::create("c2", this);
    56. endfunction
    57. function void connect_phase(uvm_phase phase);
    58. super.connect_phase(phase);
    59. c1.bp_port1.conect(c2.bt_imp_p1);
    60. c1.bp_port2.conect(c2.bt_imp_p2);
    61. endfunction
    62. endclass

    通信管道

    uvm_tlm_fifo

    • uvm_tlm_fifo类继承于uvm_component,内置了多个端口、实现了多个对应方法
    • 作用:在consumer分析事务之前,将对象存储到本地fifo以供稍后使用

    analysis port

    • 一个端口到多个端口,多个组件对同一个数据进行处理
    • 类比:广播,发出来后依次调用多个target中的write函数实现数据传输,不做任何反馈,也就是说,这个端口只管发出,不管别人接收到与否,类似于广播
    • 类型:对应三种类型的端口
    • 连接:在顶层将initiator端的aport和多个target端的uvm_analysis_imp进行连接

     

    1. initiator.ap.connect(target1.aimp);
    2. initiator.ap.connect(target2.aimp);
    3. initiator.ap.connect(target3.aimp);

    analysis TLM FIFO

    • uvm_tlm_analysis_fifo提供可以搭配uvm_analysis_port和uvm_analysis_imp端口和write函数
    • uvm_tlm_analysis_fifo继承于uvm_tlm_fifo
    1. uvm_analysis_imp #(T, uvm_tlm_analysis_fifo #(T)) analysis_export;
    2. //端口类型是imp,只是名字是export
    • 实现一端对多端的数据传输,插入多个uvm_tlm_analysis_fifo
    • 连接方式:initiator的uvm_analysis port——tlm_analysis_fifo的get_export——target的uvm_get_port。从target调用get方法就可以得到tlm_analysis_fifo中的数据
    1. initiator.ap.conncet(tlm_analysis_fifo1.analysis_export);
    2. target1.get_port.connect(tlm_analysis_fifo1.get_export);
    3. //2和3以此类推

     

     

    req&rsp通信管道

    • 类比双向通信端口transport:在target端口实现transport()方法可以一次传输完成发送req+接收rsp
    • 作用:数据缓存区域,既有TLM端口从外侧接收req和rsp,也有TLM端口供外侧获取req和rsp
    • uvm_tlm_req_rsp_channel
      • 例化的端口如下
      • 内部例化了两个mailbox分别存储req和rsp
        • protected uvm_tlm_fifo #(REQ) m_request_fifo;
        • protected uvm_tlm_fifo #(RSP) m_response_fifo;

     

    1. uvm_put_export #(REQ) put_request_export;
    2. uvm_put_export #(RSP) put_response_export;
    3. uvm_get_peek_export #(REQ) get_peek_request_export;
    4. uvm_get_peek_export #(RSP) get_peek_response_export;
    5. uvm_analysis_port #(REQ) request_ap;
    6. uvm_analysis_port #(RSP) response_ap;
    7. uvm_master_imp #(REQ, RSP, this_type, uvm_tlm_fifo #(REQ), uvm_tlm_fifo #(RSP)) master_export;
    8. uvm_slave_imp #(REQ, RSP, this_type, uvm_tlm_fifo #(REQ), uvm_tlm_fifo #(RSP)) slave_export;
    1. initiator.put_port.connect(req_rsp_channel.put_request_export);
    2. target.get_peek_port.connect(req_rsp_channel.get_peek_request_export);
    3. target.put_port.connect(req_rsp_channel.put_response_export);
    4. initiator.get_peek_port.connect(req_rsp_channel.get_peek_response_export);

    • 也可以用这种方式

     

    1. initiator.master_port.connect(req_rsp_channel.master_export);
    2. target.slave_port.connect(req_rsp_channel.slave_export);
    • 但是,这两种方法都需要调用两次方法才可以完成req和rsp的传输

    • uvm_tlm_transport_channel继承于uvm_tlm_req_rsp_channel类

      • 新例化了transport端口:uvm_transport_imp #(REQ, RSP, this_type) transport_export;
      • 作用:针对一些无法流水化处理的req和rsp传输,initiator发送完req后等到rsp收到了才可以发送下一个req
      • 上图的连接修改为:initiator.transport_port.connect(transport_channel.transport_export)。transport_channel到target之间的连接不做修改:target.slave_port.connect(req_rsp_channel.slave_export);
  • 相关阅读:
    用HTML+CSS仿网易云音乐网站(6个页面)
    有手就行10——Jenkins+SonarQube代码审查
    数据结构--单链表
    网络爬虫之HTTP原理
    什么是space-around
    IP地址与代理ip在网络安全中的关键作用
    【pen200-lab】10.11.1.231
    Jenkins+Allure+Pytest的持续集成
    CCF ChinaSoft 2023 论坛巡礼 | NASAC青年软件创新奖论坛
    关于el-date-picker点击清空参数变为null的问题
  • 原文地址:https://blog.csdn.net/weixin_39668316/article/details/125880955