【SystemVerilog项目实践】5.AHB-SRAMC(编写Systemverilog Testbench-1)

本文详细介绍了验证平台的三层架构,包括top、testcase和env部分,并重点讲解了代码目录结构、AHB从机接口信号定义、数据包transaction建模、数据生成模块generator的编写以及agent模块的作用。此外,还展示了如何使用VCS编译相关文件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 验证平台的架构图

 整个验证平台的框架如图所示,由外往内可以分为三大部分:最顶层的top部分,包含验证平台、接口和DUT;testcase部分,包含了验证环境;env部分,包含了transaction、generator、agent、driver、monitor、scoreboard、coverage部分。图中agent部分没画出来,实际上他是一个可有可无的部分,但是较为复杂的环境中都会存在agent。

验证平台的代码目录

给出的验证平台代码存放目录,ahb_sramc_sv_tb是对顶层的文件,包含doc、rtl、verif。doc部分存放设计文件,rtl存放设计代码,verif中存放agent、env、sim、tb、tests部分。agent文件夹中包含agent.sv文件,env中包含transaction、generator、driver、monitor、scoreboard、environment文件,sim文件中包含Makefile、rtl.f文件,tb中包含接口文件和top顶层文件,tests中包含测试代码文件。

第一步:根据AHB_slave接口信号编写ahb_slave_interface

ahb_slave_interface部分代码中主要定义了AHB从机的接口信号,monitor和driver的时钟块,主要作用是用于显示的额同步时钟域。modport可以防止我们把信号接反。

`ifndef AHB_SLAVE_IF_SV
`define AHB_SLAVE_IF_SV

interfece ahb_slv_if(input hclk);   时钟信号一般声明在接口名后
    logic                 hsel;
    logic       [31:0]    haddr;
    logic                 hwrite;
    logic       [1:0]     htrans;
    logic       [2:0]     hsize;
    logic       [2:0]     hburst;   
    logic       [31:0]    hwdata;
    logic                 hresetn;
    logic                 hclk;
    logic                 hready ;
    logic       [1:0]     hresp;
    logic       [31:0]    hrdata;

 clocking drv_cb(posedge hclk);
    output          hsel;
    output          hwrite;
    output          htrans;
    output          hsize;
    output          haddr;
    output          hwdata;

    output          hready;
    input           hrdata;
endclocking

 clocking mon_cb(posedge hclk);

    input           hsel;
    input           hwrite;
    input           htrans;
    input           hsize;
    input           haddr;
    input           hwdata;

    input           hready;
    input           hrdata;
endclocking

modport driver(clocking drv_cb)

modport minitor(clocking mon_cb)

endinterface

`endif

Q:对于时钟块的输入输出方向是怎么判断的?

A:对于driver而言,它自身是一个master,通过接口interface按照AHB协议与DUT相连,所以,其信号的输入输出应以DUT为依据;对于monitor而言,它通过DUT、接口和driver相连接,他会采集所有接口上的信息,然后通过邮箱mailbox将数据送到Scoreboard进行比对,所以都是input。

第二部,根据AHB_slave输入和输出接口,进行数据建模:数据包transaction

对数据激励进行建模,产生随机化的数据包,主要对地址信号、控制信号、选择信号和读取数据进行随机化,对地址、大小、数据类型进行约束,其中进行了条件约束的操作。并不是所有的信号都放在transaction中,因为有些信号是固定死的,所以没必要去采集去看他的覆盖率或者发送的时候进行随机化。

`ifndef TRANSACTION_SV
`define TRANSACTION_SV

class transaction;
    rand bit     [31:0] haddr;
    rand bit     [1:0]  hsize;
    rand bit     [1:0]  htrans;
    rand bit            hsel;
    rand bit            hwrite;
    rand bit     [1:0]  hburst;
    rand bit     [31:0] hwdata;
    rand bit     [31:0] hrdata;

    constraint c1{
                   haddr inside {[32'h0:32'h0000_FFFF]};
}

    constraint c2{
                   hsize inside {2'b00,2'b01,2'b10};
}
    constraint c3{
                   htrans inside {2'b00,2'b11};
}
    constraint c4{
                   (hsize==2'10) -> (haddr[1:0]==2'b00);
    
                   (hsize==2'01) -> (haddr[1:0]==2'b00) ||  (haddr[1:0]==2'b10);
}

endclass

`endif

第三步,编写数据生成模块

利用系统函数随机生成数据。所有的测试用例,都会用到generator,但是产生的激励可能有所不用,就需要用参数化的方式把不同的命令传进来,甘肃generator组件,我需要干什么,

`ifndef GENERATOR_SV
`define GENERATOR_SV

class generator;
    int         tr_num;
    transaction tr;
    event        gen_data;
    mailbox      mbx=new();

    extern function new(mailbox mbx,int tr_num);
    extern function build();
    extern task write_data32(logic [31:0] wdata,logic [31:0] addr);
    extern task write_data16(logic [31:0] wdata,logic [31:0] addr);
    extern task write_data8(logic [31:0] wdata,logic [31:0] addr);
    extern task write_data32_random(logic [31:0] addr);    
    extern task write_data16_random(logic [31:0] addr);
    extern task write_data8_random(logic [31:0] addr);
    extern task read_data32(logic [31:0] addr);
    extern task read_data16(logic [31:0] addr);
    extern task read_data8(logic [31:0] addr);
    extern task read_addr_random();
    extern task read_write_random();
    extern task all_random();   
    extern task no_op();
    extern task run();
endtask

    function new(mailbox mbx;tr_num);
    this.mbx = mbx;
    this.tr_num = tr_num;
    endfunction

    function new(mailbox mbx;tr_num);
    tr = new;
    if(!tr.randomsize()) begin
        $display("@/0t ERROR::generator::build randonmize faild",$time);
    end
    endfunction

task generator::write_data32(logic [31:0] wdata,logic [31:0] addr);
    tr = new;
    tr.haddr = addr;
    tr.hwdata = wdata;
    tr.hsize = 2'b10;
    tr.htrans= 2'b10;    
    tr.hburst= 2'b00;
    tr.hwrite= 1'b1;
    tr.hsel = 1'b1;
        ->gen_data;
endtask


task generator::write_data16(logic [31:0] wdata,logic [31:0] addr);
    tr = new;
    tr.haddr = addr;
    tr.hwdata = wdata;
    tr.hsize = 2'b01;
    tr.htrans= 2'b10;    
    tr.hburst= 2'b00;
    tr.hwrite= 1'b1;
    tr.hsel = 1'b1;
        ->gen_data;
endtask


task generator::write_data8(logic [31:0] wdata,logic [31:0] addr);
    tr = new;
    tr.haddr = addr;
    tr.hwdata = wdata;
    tr.hsize = 2'b00;
    tr.htrans= 2'b10;    
    tr.hburst= 2'b00;
    tr.hwrite= 1'b1;
    tr.hsel = 1'b1;
        ->gen_data;
endtask

task generator::write_data32_random(logic [31:0] addr); 
    tr = new;
    tr.haddr = addr;
    tr.hsize = 2'b10;
    tr.htrans= 2'b10;    
    tr.hburst= 2'b00;
    tr.hwrite= 1'b1;
    tr.hsel = 1'b1;
        ->gen_data;
endtask

task generator::write_data16_random(logic [31:0] addr); 
    tr = new;
    tr.haddr = addr;
    tr.hsize = 2'b01;
    tr.htrans= 2'b10;    
    tr.hburst= 2'b00;
    tr.hwrite= 1'b1;
    tr.hsel = 1'b1;
        ->gen_data;
endtask


task generator::write_data8_random(logic [31:0] addr); 
    tr = new;
    tr.haddr = addr;
    tr.hsize = 2'b00;
    tr.htrans= 2'b10;    
    tr.hburst= 2'b00;
    tr.hwrite= 1'b1;
    tr.hsel = 1'b1;
        ->gen_data;
endtask

task generator::read_data32(logic [31:0] addr);
    tr = new;
    tr.haddr = addr;
    tr.hsize = 2'b10;
    tr.htrans= 2'b10;    
    tr.hwrite= 1'b0;
    tr.hsel = 1'b1;
        ->gen_data;
endtask


task generator::read_data16(logic [31:0] addr);
    tr = new;
    tr.haddr = addr;
    tr.hsize = 2'b01;
    tr.htrans= 2'b10;    
    tr.hwrite= 1'b0;
    tr.hsel = 1'b1;
        ->gen_data;
endtask


task generator::read_data8(logic [31:0] addr);
    tr = new;
    tr.haddr = addr;
    tr.hsize = 2'b00;
    tr.htrans= 2'b10;    
    tr.hwrite= 1'b0;
    tr.hsel = 1'b1;
        ->gen_data;
endtask

task generator:: read_addr_random();
    tr = new;
    if(!tr.randomsize()) begin
        $display("@/0t ERROR::generator::read_addr_random randonmize faild",$time);
    end
    tr.hsize = 2'b10;
    tr.htrans= 2'b10;    
    tr.hwrite= 1'b0;
    tr.hsel = 1'b1;
        ->gen_data;
endtask


task generator::  read_write_random();
    tr = new;
    if(!tr.randomsize()) begin
        $display("@/0t ERROR::generator::read_write_random randonmize faild",$time);
    end
    tr.hsize = 2'b10;
    tr.htrans= 2'b10;    
    tr.hsel = 1'b1;
        ->gen_data;
endtask

task generator:: all_random();  
    tr = new;
    if(!tr.randomsize()) begin
        $display("@/0t ERROR::generator::read_write_random randonmize faild",$time);
    end
        ->gen_data;
endtask

task generator:: no_op();
    tr = new;
    if(!tr.randomsize()) begin
        $display("@/0t ERROR::generator::read_write_random randonmize faild",$time);
    end
    tr.htrans= 2'b0;    
    tr.hsel = 1'b0;
        ->gen_data;
endtask


task generator:: run();
    repeat(tr_num) begin
    @(gen_data);
    mbx.put(tr)
end    
endtask


`endif

第四步、生成agent模块

agent组件的作用是相当于是数据中转站,把数据包送往不同的地方,代码中的三个邮箱代表着三组不同方向的数据,从generator中获取,然后分别送往driver和scoreboard

`ifndef AGENT_SV
`define AGENT_SV

class agent;

    int          tr_num;
    transaction  tr;
    mailbox       gen2agt_max=new();
    mailbox       agt2drv_max=new();
    mailbox       agt2scb_max=new();


    extern function new(mailbox gen2agt_max,agt2drv_max,agt2scb_max, int tr_num);
    extern taskbuild();
    extern task run();


endclass


function agent::new(mailbox gen2agt,agt2drv,agt2scb,tr_num);
    this.gen2agt_max = gen2agt_max;
    this.agt2drv_max = agt2drv_max;
    this.agt2scb_max = agt2scb_max;
    this.tr_num = tr_num;
endfunction

task agent::build();
endtask


task run();
    repeat(tr_num)begin
    tr = new();
    gen2agt_max.get(tr);
    agt2drv_max.put(tr);
    agt2scb_max.put(tr);
    end
ebdtask


`endif

vcs编译文件命令

vcs +v2k -sverilog ./transaction.sv ./generator.sv ./agent/agent.sv  (根据文件目录修改编译文件路径)

根据文件的需要,如果不需要其他文件,就只编译自身,例如:transaction.sv;如果需要其他文件,需要一同编译,例如:agent.sv

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值