前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >UVM方法学与设计模式_5:命令模式 & UVM Sequence

UVM方法学与设计模式_5:命令模式 & UVM Sequence

作者头像
AsicWonder
发布2020-06-12 16:26:47
5300
发布2020-06-12 16:26:47
举报

Part 1. 命令模式代码示例

假设有如上一段第一代版本的代码,run函数用于执行对receiver模块的一系列操作/命令。

随着项目的进展,V1需要做一些改变,新增了命令得到V2的代码版本,如下所示:

随着操作和命令的继续增多,我们需要不断对代码进行修改:

更加糟糕的是,如果我们希望对命令进行更精细的控制,比如我们希望有相关的使能信号可以开关相关的命令,则代码将会演化成如下的糟糕状态:

代码语言:javascript
复制
class Invoker
{
public:
    void run(Receiver *receiver,
             bool IsCrcEnable,
             bool IsYuvEnable,
             bool IsNewCmd0Enable,
             ...,
             bool IsNewCmdNEnable)
    {
        receiver->TurnOn;
        if (IsCrcEnable)
        {
            receiver->CrcOn;
        }
        if (IsYuvEnable)
        {
            receiver->YuvOn;
        }
        if (IsNewCmd0Enable)
        {
            receiver->NewCmd0On;
        }
        if (IsNewCmd1Enable)
        {
            receiver->NewCmd1On;
        }
        if (IsNewCmd2Enable)
        {
            receiver->NewCmd2On;
        }
                .
                .
                .
        if (IsNewCmdNEnable)
        {
            receiver->NewCmdNOn;
        }

        ...

        if (IsNewCmdNEnable)
        {
            receiver->NewCmdNOff;
        }
                .
                .
                .

        if (IsNewCmd2Enable)
        {
            receiver->NewCmd2Off;
        }
        if (IsNewCmd1Enable)
        {
            receiver->NewCmd1Off;
        }
        if (IsNewCmd0Enable)
        {
            receiver->NewCmd0Off;
        }
        if (IsYuvEnable)
        {
            receiver->YuvOff;
        }
        if (IsCrcEnable)
        {
            receiver->CrcOff;
        }
        receiver->TurnOff;
    }
}
代码语言:javascript
复制

更不要说,当我们需要对这些操作/命令进行排队,制定优先级取消操作了。可想而知我们的代码将会变得十分冗长,并且难以阅读和维护(阅读和维护代码往往占用了我们80%的编程时间)。

命令模式可以非常好的解决这个问题。让我们来试着发现这个模式。

上述代码最大的问题是什么呢?run函数知道的太多了(正如我们在之前几篇文章中所说的一样:))!

事实上run函数只需要进行执行操作,并不需要将具体执行的具体操作hard coding进我们的函数体内。

到这里,仔细的同学估计已经想到了,套用之前几篇文章的套路,还是使用多态来进行代码改造(所以说多态才是OOP的根本,只不过C++和SV的多态都借用了继承的方式而已)。

我们将每一个命令都封装一个个具体的对象,那么就非常容易对这些命令进行使能操作。具体可见如下代码(不要在意具体的细节,这里只是示意代码):

代码语言:javascript
复制
class Command
{
public:
    Command(Receiver *pReceiver): m_pReceiver(pReceiver) {}
    virtual void excute() = 0;
protected:
    Receiver *m_pReceiver;
};

class CrcOnCmd: public Command
{
public:
    CrcOnCmd(Receiver *pReceiver): Command(pReceiver) {}
    virtual void excute()
{
        m_pReceiver->CrcOn();
    }
};

class CrcOffCmd: public Command
{
public:
    CrcOffCmd(Receiver *pReceiver): Command(pReceiver) {}
    virtual void excute()
{
        m_pReceiver->CrcOff();
    }
};

class TurnOnCmd: public Command
{
public:
    TurnOnCmd(Receiver *pReceiver): Command(pReceiver) {}
    virtual void excute()
{
        m_pReceiver->TurnOn();
    }
}

class TurnOffCmd: public Command
{
public:
    TurnOffCmd(Receiver *pReceiver): Command(pReceiver) {}
    virtual void excute()
{
        m_pReceiver->TurnOff();
    }
}

class YuvOnCmd: public Command
{
public:
    YuvOnCmd(Receiver *pReceiver): Command(pReceiver) {}
    virtual void excute()
{
        m_pReceiver->YuvOn();
    }
}

class YuvOffCmd: public Command
{
public:
    YuvOffCmd(Receiver *pReceiver): Command(pReceiver) {}
    virtual void excute()
{
        m_pReceiver->YuvOff();
    }
}

class Receiver
{
public:
    virtual void TurnOn() {}
    virtual void TurnOff() {}
    virtual void CrcOn() {}
    virtual void CrcOff() {}
    virtual void YuvOn() {}
    virtual void YuvOff() {}
}

class Invoker
{
public:
    void AddCmd(Command *cmd)
{
        vector.push_back(cmd);
    }
    void RemoveCmd(Command *cmd)
{
        auto it = find(m_CommandVector.begin(), m_CommandVector.end(), cmd);
    if (it != m_CommandVector.end())
      m_CommandVector.erase(it);
    }
    void Run()
{
        for (auto &it : m_CommandVector)
            it->excute();
    }
private:
    std::vector<Command*> m_CommandVector;
}

int main()
{
    Invoker *invoker = new invoker();
    Receiver *receiver = new Receiver();
    CrcOnCmd *crconcmd = new CrcOnCmd(receiver);
    CrcOffCmd *crcoffcmd = new CrcOffCmd(receiver);
    TurnOnCmd *turnoncmd = new TurnOnCmd(receiver);
    TurnOffCmd *turnoffcmd = new TurnOffCmd(receiver);
    YuvOnCmd *yuvoncmd = new YuvOnCmd(receiver);
    YuvOffCmd *yuvoncmd = new YuvOffCmd(receiver);

    invoker->AddCmd(crconcmd);
    invoker->AddCmd(yuvoncmd);
    invoker->AddCmd(turnoncmd);

    invoker->Run();

    return 0;
}
代码语言:javascript
复制

通过使用AddCmd和RemoveCmd方法我们就可以非常轻松的对命令进行增加和删除操作(示例代码中是逐一调用AddCmd方法,有没有更好的方法呢?)。

并且我们可以在此基础上非常方便的加入优先级功能,确保某些命令优先执行,只要对不同的命令赋予不同的优先级值即可,Run方法可以根据不同的优先级值对命令进行排序执行操作,对应的代码也不难实现。

Part 2. UVM Sequence

本质上发给DUT的激励就可以看成是一个个具体的命令,在UVM中,这些激励被称为transaction

transaction往往包装在sequence中进行后续的发射操作,UVM中可以对sequence及其中的transaction进行管理,其中包括设置优先级(uvm_do_pri)、同步操作等。

试想,如果不是采用对象的方式对transaction和sequence进行管理,想要实现类似的功能框架代码和具体的业务代码其耦合性得多强。

Part3. 总结

命令模式定义:将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能。

授权转载于 知乎专栏《UVM方法学与设计模式》

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-04-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 数字芯片实验室 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档