Dskpimc? · 3月20日 · 黑龙江

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

1. 责任链模式

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

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

image.png

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

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

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

image.png

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

看到责任链模式的使用方法,大家没有觉得很熟悉吗?在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)在芯片验证中的应用。

作者:谷公子
文章来源:CSDN

推荐阅读

更多IC设计干货请关注IC设计专栏。
迎添加极术小姐姐微信(id:aijishu20)加入技术交流群,请备注研究方向。
推荐阅读
关注数
19610
内容数
1303
主要交流IC以及SoC设计流程相关的技术和知识
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息