用bind来解耦

转自: 用bind来解耦

应用了boost::bind, boost::function, boost::test
代码稍有修改。

#define BOOST_AUTO_TEST_MAIN
#include <boost/test/auto_unit_test.hpp>
#include <boost/test/included/unit_test_framework.hpp>
#include <boost/thread/thread.hpp>
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <string>

using namespace std;

//声明一个函数指针的类型
typedef void (* ON_SEGMENT) (char *);

//用function<> 和指针回调指针来解除耦合
//注意解耦效果: CReader 和 CSaver 没有任何关系

class CReader
{
public:
    CReader()
    {
        m_pFunc=NULL;
        m_functor=NULL;
    };

    void UseFreeFunc(ON_SEGMENT pFunc)
    {
        m_pFunc=pFunc;
    };

    void UseFunctor(boost::function<void(char *)>  functor)
    {
        m_functor= functor;
    };

    void Read(char * pchar)
    {
        if(m_pFunc)
        {
            m_pFunc(pchar);
        };
        if(m_functor)
        {
            m_functor(pchar);
        };
    }

private:
    ON_SEGMENT m_pFunc;//函数指针
    boost::function<void(char *)>  m_functor; //函数对象
};

class CSaver
{
public:
    //接受输入的字符,保存在内部变量m_str
    void Input(char * pchar)
    {
        m_str.append(pchar);
    };

    string m_str;
};

BOOST_AUTO_TEST_CASE(test_bind)
{
    //两个类并不知道对方的任何细节
    CSaver  saver;
    CReader reader;

    //预先 把函数 CSaver::Input 和要操作的数据 &saver 注册到 reader
    //只要函数形式符合(返回值是void,传入参数是char *),都可以注册
    //解除CSaver 和 CReader的耦合
    //bind产生的函数对象,重载操作符()
    //函数对象的本质是 函数指针加this指针,即 操作和数据
    //函数对象 比 函数指针优越的地方是可以带有内部状态

    reader.UseFunctor( boost::bind(&CSaver::Input, &saver, _1) );

    //延时调用,解除CSaver 和 CReader的耦合
    //把字符从reader 放入 saver里面
    reader.Read("Hello");
    reader.Read("Mafeitao");

    BOOST_CHECK(saver.m_str=="HelloMafeitao");
}

//asio 里面的 async_accept 的简化版本
//可以接受 函数指针; 比如 async_accept(FreeFunc,Para)
//可以接受 函数对象; 比如
// CSaverFunctor func;
//async_accept(func,Para)
//可以接受 bind
template <typename AcceptHandler,typename Para>
void async_accept(AcceptHandler handler, Para p)
{
    handler(p);
};

// 自由函数,没有内部状态
void FreeFunc(char * pChar)
{
    printf("In FreeFunc %s/n", pChar);
}

BOOST_AUTO_TEST_CASE(bind_asio)
{
    //类 CSaver 和 模板函数 async_accept,没有任何关系
    CSaver saver;
    char *pchar="Hello";

    //bind生成一个临时的functor类 CSaverTemp
    //类似于
    /*
    class CSaverTemp
    {
    public:

        void operator ()(char * pchar)
        {
            m_str.append(pchar);
        };
        string m_str
    }

    CSaverTemp saver;
    async_accept(saver,pchar);
    }
    */
    //全局函数 async_accept,接受一个bind产生的函数对象( 函数指针和this指针)
    async_accept( boost::bind(&CSaver::Input, &saver,_1) , pchar);

    BOOST_CHECK(saver.m_str=="Hello");
    pchar="Mafeitao";
    async_accept( boost::bind(&CSaver::Input, &saver,_1) , pchar);
    BOOST_CHECK(saver.m_str=="HelloMafeitao");

    //接受 全局函数指针,和下面的效果一样
    async_accept( boost::bind(FreeFunc,_1), pchar);
    //接受 全局函数指针,和上面的效果一样
    async_accept( FreeFunc, pchar);
}

//带有模板函数的类
class TReader
{
public:
    //模板函数
    template <typename OnReadHandler,typename Para>
    void Read(OnReadHandler & handler, Para p)
    {
        //可以接受 函数指针,参数
        //可以接受 函数对象,参数
        //可以接受 bind
        handler(p);
    };
};

BOOST_AUTO_TEST_CASE(bind_template)
{
    TReader reader;
    CSaver saver;
    char *pchar="Hello";
    boost::function<void (char*)> handler
        = boost::bind(&CSaver::Input, &saver,_1);
    reader.Read(handler, pchar);
    BOOST_CHECK(saver.m_str=="Hello");

    pchar="Mafeitao";
    reader.Read(handler, pchar);
    BOOST_CHECK(saver.m_str=="HelloMafeitao");
}

//函数对象,重载操作符()
//函数对象的本质是 函数指针加this指针,即 操作和数据
//函数对象 比 函数指针优越的地方是可以带有内部状态
class CSaverFunctor
{
public:
    void operator ()(char * pchar)
    {
        m_str.append(pchar);
    };
    string m_str;
};

BOOST_AUTO_TEST_CASE(test_functor)
{
    //带有模板函数的类
    TReader reader;

    //函数对象
    CSaverFunctor saver;

    //把字符从reader 放入 saver里面
    char *pchar="Hello";
    reader.Read( saver , pchar);

    pchar="Mafeitao";
    reader.Read( saver , pchar);
    BOOST_CHECK(saver.m_str=="HelloMafeitao");
}


<think>好的,我现在需要帮助用户理解UVM中的bind含义及使用方法。首先,我需要回顾一下UVM的基础知识,特别是bind的相关内容。根据用户提供的引用,尤其是引用[1]提到uvm_test扩展了uvm_component,说明组件在UVM中的重要性。而bind通常与组件之间的连接有关,可能涉及端口和接口的绑定。 接下来,我应该明确bind在UVM中的具体作用。通常,在UVM中,bind用于将验证组件(如driver或monitor)与设计(DUT)的接口连接起来。这样,测试平台可以通过接口与设计进行通信。例如,在SystemVerilog中,使用`uvm_config_db`来传递虚拟接口,但bind可能是在模块实例化时将接口直接绑定到DUT的端口上。 然后,用户可能需要知道如何使用bind。根据引用[3]和[4],TLM通信在UVM中很重要,而bind可能与TLM端口的连接有关。不过,更常见的是,bind在硬件环境中用于连接DUT和验证组件的接口。例如,在顶层模块中,将DUT的信号与interface实例绑定,然后在验证环境中通过uvm_config_db获取该interface的引用。 需要区分SystemVerilog中的bind语法和UVM中的使用方式。SystemVerilog的bind允许将模块或接口实例绑定到另一个模块的实例或模块定义上,这在UVM中常用于将监视器或驱动器连接到DUT的特定实例上,而无需修改DUT的代码。 接下来,考虑用户可能需要示例来说明bind的使用。例如,定义一个interface,然后在顶层模块中使用bind将interface连接到DUT的端口。之后,在测试环境中通过uvm_config_db获取该interface,并将其分配给driver和monitor的虚拟接口。 同时,要确保回答结构清晰,分点解释含义、使用方法和示例。需要引用提供的资料,例如引用[1]关于组件基类的使用,可能提到使用bind来明确组件之间的连接意图,使代码更清晰。 还要检查是否有相关的引用可能遗漏的信息,比如引用[2]提到的phase跳转,这可能与bind的使用场景关系不大,但引用[3]和[4]提到的TLM通信可能与bind在高层连接有关联,需要适当提及。 最后,生成相关问题,帮助用户进一步学习,比如bind与uvm_config_db的区别,常见错误等。</think>### UVM中bind的含义及使用方法 #### 1. **bind的含义** 在UVM中,`bind`是一种将验证组件(如driver、monitor)与设计(DUT)接口关联的机制。它通过**SystemVerilog的`bind`语法**实现,允许在不修改设计代码的前提下,将接口或模块插入到DUT的指定位置。这种机制常用于以下场景: - 将**接口实例**连接到DUT的信号端口。 - 将**验证组件(如监视器)**直接绑定到DUT层级中,实现信号采集或功能覆盖[^3][^4]。 #### 2. **使用方法** **步骤1:定义接口** ```systemverilog interface my_interface(input logic clk, input logic rst); logic [7:0] data; logic valid; endinterface ``` **步骤2:在DUT模块中声明端口** ```systemverilog module dut(input clk, input rst, output [7:0] data_out); // DUT内部逻辑... endmodule ``` **步骤3:使用`bind`将接口与DUT连接** ```systemverilog module top; logic clk, rst; logic [7:0] data_out; // 实例化DUT dut u_dut(.clk(clk), .rst(rst), .data_out(data_out)); // 绑定接口到DUT实例 bind dut my_interface u_my_if(.clk(clk), .rst(rst), .data(data_out)); endmodule ``` **步骤4:在验证环境中通过`uvm_config_db`传递接口** ```systemverilog class my_env extends uvm_env; virtual my_interface vif; ... function void build_phase(uvm_phase phase); if (!uvm_config_db#(virtual my_interface)::get(this, "", "vif", vif)) `uvm_fatal("NO_VIF", "Interface not found") endfunction endclass ``` #### 3. **关键作用** - **解耦设计代码与验证代码**:无需修改DUT即可插入验证组件[^1]。 - **简化信号连接**:通过接口统一管理信号交互,避免分散的线网连接。 - **支持模块化验证**:可将多个验证组件(如多个monitor)绑定到不同层级的设计模块。 #### 4. **示例:绑定监视器到DUT** ```systemverilog // 定义监视器模块 module my_monitor(my_interface if_m); always @(posedge if_m.clk) begin if (if_m.valid) $display("Data captured: %0h", if_m.data); end endmodule // 在顶层绑定监视器 bind dut my_monitor u_monitor(.if_m(u_my_if)); ``` #### 5. **注意事项** - **命名空间一致性**:绑定的接口实例名需与验证环境中引用的名称一致。 - **跨模块绑定**:可通过`bind design_module::hierarchy_path`绑定到特定层级。 - **与TLM的协同**:若需高层次通信(如事务级),可结合TLM端口与`bind`的物理接口[^4]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值