设计模式在芯片验证中的应用——责任链

本文介绍了责任链模式在软件设计中的应用,特别是在复位事件处理中,通过构建软复位、硬复位和无复位的处理链。文章提供了UML类图和UVM代码示例,展示了如何通过责任链模式实现请求的逐级处理。
摘要由CSDN通过智能技术生成

1. 责任链模式

责任链(Chain of Responsibility)是一种软件行为设计模式,它允许一个操作或命令由多个接收者处理。发送方不是将请求与所有接收方耦合,而是将请求发送给链中的第一个元素。请求依次从一个接收方传播到另一个接收方,使更多的接收方有机会处理请求。根据应用场景的不同,即使请求由一个接收者处理,它也可能被传递给下一个接收者。

举个项目示例场景,如下图,设计逻辑复位树包含两个复位:软复位、硬复位。硬复位表示上电复位,由电压控制器控制。当输入电压降至规定值以下时,触发上电复位,把设计全部复位。软复位是根据对设计的某块生成的软件复位,复位功能块中的某一部分。 每个复位会影响设计中的不同模块,其中硬复位包含了软复位的功能。还有一种场景就是没有复位。结合以上条件,我们可以使用责任链设计模式来对设计建模。

责任链模式定义的组件包括:

  • 抽象处理者(Abstract handler):声明了所有具体处理者的通用接口。 该接口通常仅包含单个方法用于请求处理, 但有时其还会包含一个设置链上下个处理者的方法。
  • 具体处理者 (Concrete Handlers):通常情况下, 该类中定义了一个保存对于下个处理者引用的成员变量。 客户端可通过将处理者传递给上个处理者的构造函数或设定方法来创建链。 该类还可以实现默认的处理行为: 确定下个处理者存在后再将请求传递给它。另外它包含处理请求的实际代码。 每个处理者接收到请求后, 都必须决定是否进行处理, 以及是否沿着链传递请求。
  • 客户端 (Client) 可根据程序逻辑一次性或者动态地生成链。 值得注意的是, 请求可发送给链上的任意一个处理者, 而非必须是第一个处理者。在UVM方法中,专用的UVM monitor组件观察低功耗接口和复位事件,因此常作为客户端。

下图为使用责任链模式画出reset_handler的UML类图。

在使用责任链模式构建模型时,第一步是配置请求处理者的顺序。需要注意的是,顺序配置可以动态更改,处理者可以动态添加到链中或从链中删除。责任链可以正向处理请求,也可以反向处理请求。

看到责任链模式的使用方法,大家没有觉得很熟悉吗?在UVM代码里使用了很多改方法,比如uvm_phase的自顶向下和自下向上的执行顺序,就是参考责任链模式的设计的。理解了设计模式,不光自己写代码有好处,也可以更容易的看懂别人的代码。

2. 参考代码

复位处理的责任链模式参考代码如下:

typedef enum bit [1:0] {SOFT = 2'b00, HARD = 2'b01, NONO = 2'b10} reset_type_t;

interface class reset_handler;

    pure virtual function void set_next(reset_handler _handler);
    pure virtual function void handle(reset_type_t _type);

endclass : reset_handler


class soft_reset implements reset_handler;

    reset_handler next_handler;

    virtual function void set_next(reset_handler _handler);
        next_handler = _handler;
    endfunction : set_next

    virtual function void handle(reset_type_t _type);
        if ( _type inside {SOFT, HARD} ) begin
            `uvm_info("COR", $psprintf("The %s reset is processed by soft_reset class", _type.name()), UVM_LOW)
        end
        if ( _type != SOFT ) begin
            if ( next_handler == null ) `uvm_fatal("COR", $psprintf("%s cannot be processed by soft_reset class", _type.name()))
            next_handler.handle(_type);
        end
    endfunction : handle

endclass : soft_reset


class hard_reset implements reset_handler;

    reset_handler next_handler;

    virtual function void set_next(reset_handler _handler);
        next_handler = _handler;
    endfunction : set_next

    virtual function void handle(reset_type_t _type);
        if ( _type == HARD ) begin
            `uvm_info("COR", $psprintf("The %s reset is processed by hard_reset class", _type.name()), UVM_LOW)
        end else begin
            if ( next_handler == null ) `uvm_fatal("COR", $psprintf("%s cannot be processed by hard_reset class", _type.name()))
            next_handler.handle(_type);
        end
    endfunction : handle

endclass : hard_reset



class nono_reset implements reset_handler;

    reset_handler next_handler;

    virtual function void set_next(reset_handler _handler);
        next_handler = _handler;
    endfunction : set_next

    virtual function void handle(reset_type_t _type);
        if ( _type == NONO ) begin
            `uvm_info("COR", $psprintf("The %s reset is processed by nono_reset class", _type.name()), UVM_LOW)
        end else begin
            if ( next_handler == null ) `uvm_fatal("COR", $psprintf("%s cannot be processed by nono_reset class", _type.name()))
            next_handler.handle(_type);
        end
    endfunction : handle

endclass : nono_reset

模拟测试代码如下:

class client extends uvm_object;

    `uvm_object_utils (client)

    soft_reset soft_rst = new();
    hard_reset hard_rst = new();
    nono_reset nono_rst = new();

    function new (string name = "client");
        super.new(name);
    endfunction : new

    // soft -> hard -> nono
    function void execute();
        soft_rst.set_next(hard_rst);
        hard_rst.set_next(nono_rst);
        nono_rst.set_next(null);
        soft_rst.handle(NONO);
        hard_rst.handle(NONO);
        soft_rst.handle(HARD);
        hard_rst.handle(HARD);
        soft_rst.handle(SOFT);
        hard_rst.handle(SOFT);
    endfunction : execute

endclass : client

输出仿真日志如下:

[COR] The NONO reset is processed by nono_reset class
[COR] The NONO reset is processed by nono_reset class
[COR] The HARD reset is processed by soft_reset class
[COR] The HARD reset is processed by hard_reset class
[COR] The HARD reset is processed by hard_reset class
[COR] The SOFT reset is processed by soft_reset class
[COR] SOFT cannot be processed by nono_reset class

复位事件的监测(client)可以由uvm_monitor完成,在上述责任链代码的client类中的execute()函数里,确定了soft_reset,hard_reset和nono_reset这3个类的执行顺序,后面从各个不同的链节点输入测试复位事件。比如说soft_rst.handle(NONO)这行代码,NONO复位事件传递给soft_rst,soft_rst的handle()函数无法处理它,就继续传递给下一个链节点hard_rst,hard_reset的handle()函数发现自己也无法处理它,就继续传递给下一个链节点nono_rst,nono_rst的handler()函数能处理它,就输出” The NONO reset is processed by nono_reset class”的仿真日志。其它仿真结果以此类推,大家可以自行分析下。

好了,今天就写到这里了。下次给大家分享下设计模式中装饰模式(Decorator)在芯片验证中的应用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

谷公子的藏经阁

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值