Layering Sequence介绍

如果在构建更加复杂的协议总线传输,例如PCie、USB3.0等,那么通过一个单一的传输层次会对以后的激励复用、上层控制不那么友好。对于这钟更深层次化的数据传输,在实际中无论是VIP还是自开发的环境,都倾向于通过若干抽象层次的sequence群落来模拟协议层次。通过层次化的sequence可以分别构建transaction layer、transport layer和physical layer等从高抽象级到低抽象级的transaction转化。这种层次化的sequence构建方式,称之为layering sequence。例如在进行寄存器级别的访问操作,其需要通过transport layer转化,最终映射为具体的总线传输。
在这里插入图片描述

typedef enum {CLKON, CLKOFF, RESET, WRREG, RDREG} phy_cmd_t; // 定义物理层命令枚举类型
typedef enum {FREQ_LOW_TRANS, FREQ_MED_TRANS, FREQ_HIGH_TRANS} layer_cmd_t; // 定义数据层命令枚举类型

class bus_trans extends uvm_sequence_item; // 定义物理层事务类
    rand phy_cmd_t cmd; // 随机物理层命令
    rand int addr; // 随机地址
    rand int data; // 随机数据
    constraint cstr { // 定义约束
        soft addr == 'h0; // 限制地址为 0
        soft data == 'h0; // 限制数据为 0
    }
    ...
    
endclass

class packet_seq extends uvm_sequence; // 定义数据层序列类
    rand int len; // 随机包长度
    rand int addr; // 随机地址
    rand int data[]; // 随机数据数组
    rand phy_cmd_t cmd; // 随机物理层命令
    constraint cstr { // 定义约束
        soft len inside {[30:50]}; // 包长度范围为 30 到 50
        soft addr[31:16] == 'hFF00; // 地址的高 16 位固定为 'hFF00
        data.size() == len; // 数据数组大小等于包长度
    }
    ...
    task body(); // 序列执行逻辑
        bus_trans req;
        foreach(data[i]) // 遍历数据数组
            `uvm_do_with(req, {cmd == local::cmd; // 设置物理层命令
                               addr == local::addr; // 设置地址
                               data == local::data[i];}) // 设置数据
        endtask
endclass

class layer_trans extends uvm_sequence_item; // 定义数据层事务类
    rand layer_cmd_t layer_cmd; // 随机数据层命令
    rand int pkt_len; // 随机包数量
    rand int pkt_idle; // 随机包之间间隔时间
    constraint cstr { // 定义约束
        soft pkt_len inside {[10:20]}; // 包数量范围为 10 到 20
        layer_cmd == FREQ_LOW_TRANS -> pkt_idle inside {[300:400]}; // 低速率时,间隔时间范围为 300 到 400
        layer_cmd == FREQ_MED_TRANS -> pkt_idle inside {[100:200]}; // 中速率时,间隔时间范围为 100 到 200
        layer_cmd == FREQ_HIGH_TRANS -> pkt_idle inside {[20:40]}; // 高速率时,间隔时间范围为 20 到 40
            
    }
    ...
    
endclass

class adapter_seq extends uvm_sequence; // 定义数据层到物理层适配器序列类
    `uvm_object_utils(adapter_seq) // 使用 `uvm_object_utils` 宏定义字段
    `uvm_declare_p_sequencer(phy_master_sequencer) // 声明父 sequencer 类型
    ...
    
    task body(); // 序列执行逻辑
        layer_trans trans; // 声明数据层事务
        packet_seq pkt; // 声明数据层包序列
        forever begin
            p_sequencer.up_sqr.get_next_item(req);  // 获得高抽象层的 transaction
            void'h(trans, req); // 将高抽象层事务转换为数据层事务
            repeat(trans.pkt_len) begin // 循环发送指定数量的包
                `uvm_do(pkt) // 发送一个数据层包
                delay(trans.pkt_idle); // 延迟指定时间
            end
            p_sequencer.up_sqr.item_done(); // 通知高抽象层事务完成
        end
    endtask
    virtual task delay(int delay); // 延迟任务
        ...
    endtask
endclass

class top_seq extends uvm_sequence; // 定义顶层序列类
    ...
    task body(); // 序列执行逻辑
        layer_trans trans; // 声明数据层事务
        `uvm_do_with(trans, {layer_cmd == FREQ_LOW_TRANS;}) // 发送低速率事务
        `uvm_do_with(trans, {layer_cmd == FREQ_HIGH_TRANS;}) // 发送高速率事务
    endtask
endclass

class layering_sequencer extends uvm_sequencer; // 定义数据层 sequencer 类
    ...
endclass

class phy_master_sequencer extends uvm_sequencer; // 定义物理层 sequencer 类
    layering_sequencer up_sqr; // 声明上层 sequencer
    ...
endclass

class phy_master_driver extends uvm_driver; // 定义物理层 driver 类
    ...
    task run_phase(uvm_phase phase); // 驱动程序运行逻辑
        REQ tmp; // 声明临时变量
        bus_trans req; // 声明物理层事务
        forever begin
            seq_item_port.get_next_item(tmp); // 获取序列项
            void'($cast(req, tmp)); // 将序列项转换为物理层事务
            `uvm_info("DRV", $sformatf("got a item \n %s", req.sprint()), UVM_LOW) // 打印信息
            seq_item_port.item_done(); // 通知 sequencer 序列项完成
        end
    endtask
endclass

class phy_master_agent extends uvm_agent; // 定义物理层 agent 类
    phy_master_sequencer sqr; // 声明物理层 sequencer
    phy_master_driver drv; // 声明物理层 driver
    ...
    function void build_phase(uvm_phase phase); // 创建物理层 sequencer 和 driver
        sqr = phy_master_sequencer::type_id::create("sqr", this);
        drv = phy_master_driver::type_id::create("drv", this);
    endfunction
    
    function void connect_phase(uvm_phase phase); // 连接物理层 sequencer 和 driver
        drv.seq_item_port.connect(sqr.seq_item_export);
    endfunction
endclass

class test1 extends uvm_test; // 定义测试用例类
    layering_sequencer layer_sqr; // 声明数据层 sequencer
    phy_master_agent phy_agt; // 声明物理层 agent
    ...
    function void build_phase(uvm_phase phase); // 创建数据层 sequencer 和 物理层 agent
        layer_sqr = layering_sequencer::type_id::create("layer_sqr", this);
        phy_agt = phy_master_agent::type_id::create("phy_agt", this);
    endfunction
    function connect_phase(uvm_phase phase); // 连接数据层 sequencer 和 物理层 agent
        phy_agt.sqr.up_sqr = layer_sqr;
    endfunction
    task run_phase(uvm_phase phase); // 测试用例运行逻辑
        top_seq seq; // 声明顶层序列
        adapter_seq adapter; // 声明数据层到物理层适配器序列
        phase.raise_objection(phase); // 声明阻塞
        seq = new(); // 创建顶层序列
        adapter = new(); // 创建数据层到物理层适配器序列
        fork
            adapter.start(phy_agt.sqr); // 启动数据层到物理层适配器序列
        join_none
        seq.start(layer_sqr); // 启动顶层序列
        phase.drop_objection(phase); // 解除阻塞
    endtask
endclass

代码功能:

bus_trans 类定义了物理层的事务,包含命令、地址和数据。

packet_seq 类定义了一个数据层序列,它会发送一系列物理层事务,模拟一个数据包的传输。

layer_trans 类定义了数据层的事务,包含数据层命令、包数量和包之间间隔时间。

adapter_seq 类定义了一个数据层到物理层适配器序列,它会将数据层事务转换为物理层事务,并发送给物理层 driver。

top_seq 类定义了顶层序列,它会发送数据层事务给数据层 sequencer。

layering_sequencer 类定义了数据层 sequencer,它会将数据层事务发送给适配器序列。

phy_master_sequencer 类定义了物理层 sequencer,它会将物理层事务发送给物理层 driver。

phy_master_driver 类定义了物理层 driver,它会将物理层事务发送到 DUT。

phy_master_agent 类定义了物理层 agent,它管理物理层 sequencer 和 driver。

test1 类定义了测试用例,它会启动顶层序列,并连接数据层和物理层 agent。

测试流程:

测试用例 test1 创建数据层 sequencer 和 物理层 agent。

测试用例启动顶层序列 seq。

顶层序列发送数据层事务给数据层 sequencer。

数据层 sequencer 将数据层事务发送给适配器序列 adapter。

适配器序列将数据层事务转换为物理层事务,并发送给物理层 sequencer。

物理层 sequencer 将物理层事务发送给物理层 driver。

物理层 driver 将物理层事务发送到 DUT。

这个简单的测试环境展示了 UVM 如何使用 sequence、sequencer 和 driver 来验证分层协议模型。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值