极简UVM RAL示例(PART1--前门运行成功)

13 篇文章 1 订阅
9 篇文章 2 订阅

结构说明

极简RAL结构
此环境用于快速实验ral的各种基本功能,简化到接近最低的组件要求。
UVM环境只需要 env, sqr, driver, test,再加上RAL所需的uvm_reg, uvm_reg_model, adapter。sqr更是只有一句话。

代码部分

宏定义

addr_defines.svh

`ifndef ADDR_DEFINES
    `define ADDR_DEFINES
    `define REG1_ADDR 'h0
    `define REG2_ADDR 'h4
    `define REG3_ADDR 'h8
    `define REG4_ADDR 'hC

    parameter AW = 8;
    parameter DW = 16;

`endif

仿真代码

simplest_ral.sv

`include "addr_defines.svh"
import uvm_pkg::*;

//dut
module reg_rw(
input [AW-1:0] addr,
input [DW-1:0] din,
input clk,
input rstn,
input wr,
input rd,
output logic [DW-1:0] dout
);

    logic [DW-1:0] reg1,reg2,reg3,reg4;
    logic          is_reg1_addr;
    logic          is_reg2_addr;
    logic          is_reg3_addr;
    logic          is_reg4_addr;
    logic [DW-1:0] dout_tmp;

    //RO
always@(posedge clk or negedge rstn)
    if(!rstn)
        reg1 <= 0;
    else if(rd && is_reg1_addr)   //
        reg1 <= reg2 + 1;

    //RW
always@(posedge clk or negedge rstn)
    if(!rstn)
        reg2 <= 0;
    else if(wr && is_reg2_addr)
        reg2 <= din;
    else if(rd && is_reg2_addr)   //
        reg2 <= reg2 + 2;

    //RC
always@(posedge clk or negedge rstn)
    if(!rstn)
        reg3 <= 0;
    else if(rd && is_reg3_addr)   //
        reg3 <= 0;
    else if(rd && is_reg2_addr && reg3==0)
        reg3 <= 1;   //record reg2 is read

    //RS
always@(posedge clk or negedge rstn)
    if(!rstn)
        reg4 <= 0;
    else if(rd && is_reg4_addr)   //record reg3
        reg4 <= '1;
    else if(rd && is_reg1_addr && reg3==0)
        reg4 <= 0;   //record reg1 is read, negtive

assign is_reg1_addr = addr == `REG1_ADDR;
assign is_reg2_addr = addr == `REG2_ADDR;
assign is_reg3_addr = addr == `REG3_ADDR;
assign is_reg4_addr = addr == `REG4_ADDR;

    always_comb begin
        case(addr)
        `REG1_ADDR:    dout_tmp = reg1;
        `REG2_ADDR:    dout_tmp = reg2;
        `REG3_ADDR:    dout_tmp = reg3;
        `REG4_ADDR:    dout_tmp = reg4;
        endcase
    end

always@(posedge clk or negedge rstn)
    if(!rstn)
        dout <= 0;
    else if(rd) 
        dout <= dout_tmp;
    
endmodule

interface reg_if(input bit clk);
    logic rstn;
    logic wr;
    logic rd;
    logic [AW-1:0] addr;
    logic [DW-1:0] din;
    logic [DW-1:0] dout;

    clocking cb @(posedge clk);
        output addr, din, wr, rd;
        input dout;
    endclocking

    modport test(clocking cb,output rstn);
endinterface

//uvm begins
class reg_tr extends uvm_sequence_item;
    rand logic [AW-1:0] addr;
    rand logic          wr;
    rand logic          rd;
    rand logic [DW-1:0] din;
    rand logic [DW-1:0] dout;

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

    constraint at_reg2_addr {
        addr <= 'h20;
    };
    `uvm_object_utils_begin(reg_tr)
    `uvm_field_int(addr,UVM_ALL_ON)
    `uvm_field_int(wr,UVM_ALL_ON)
    `uvm_field_int(rd,UVM_ALL_ON)
    `uvm_field_int(din,UVM_ALL_ON)
    `uvm_field_int(dout,UVM_ALL_ON)
    `uvm_object_utils_end
endclass

class driver extends uvm_driver #(reg_tr);
    virtual reg_if drv_if;
    `uvm_component_utils(driver)
    function new(string name="",uvm_component parent=null);
    super.new(name,parent);
    endfunction

    extern virtual function void build_phase(uvm_phase phase);
    extern task main_phase(uvm_phase phase);
endclass

function void driver::build_phase(uvm_phase phase);
super.build_phase(phase);
uvm_config_db#(virtual reg_if)::get(this,"","drv_if",drv_if);

endfunction

task driver::main_phase(uvm_phase phase);
    drv_if.wr   <= 1'b0;
    drv_if.rd   <= 1'b0;
    drv_if.din  <= 0;
    drv_if.addr <= 0;
    @(posedge drv_if.rstn);
while(1) begin
    seq_item_port.get_next_item(req);
    //drive access
    @(drv_if.cb);
    drv_if.addr <= req.addr;
    if(req.wr) begin
       drv_if.wr <= 1'b1;
       drv_if.din <= req.din;
       @(drv_if.cb);
       drv_if.wr <= 1'b0;
    end
    if(req.rd) begin
       drv_if.rd <= 1'b1;
       @(drv_if.cb);
       req.dout <= drv_if.dout;
       drv_if.rd <= 1'b0;
    end
    @(drv_if.cb);
    seq_item_port.item_done();
end
endtask

typedef uvm_sequencer #(reg_tr) sequencer;

class environment extends uvm_env;
    driver drv;
    sequencer sqr;
    `uvm_component_utils(environment)

    function new(string name="environment", uvm_component parent=null);
    super.new(name,parent);
    endfunction

    virtual function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    drv = driver::type_id::create("drv",this);
    sqr = sequencer::type_id::create("sqr",this);

    endfunction

    virtual function void connect_phase(uvm_phase phase);
    drv.seq_item_port.connect(sqr.seq_item_export);
    endfunction
endclass

class adapter extends uvm_reg_adapter;
    string tID = get_type_name();
    `uvm_object_utils(adapter)
    function new(string name="adapter");
    super.new(name);
    endfunction

    function uvm_sequence_item reg2bus(const ref uvm_reg_bus_op rw);
    reg_tr tr;
    tr =new("tr");
    tr.addr = rw.addr;
    if(rw.kind == UVM_READ) begin
        tr.wr = 1'b0;
        tr.rd = 1'b1;
    end
    else begin
        tr.wr = 1'b1;
        tr.rd = 1'b0;
        tr.din = rw.data;
    end
    return tr;
    endfunction : reg2bus

    function void bus2reg(uvm_sequence_item bus_item, ref uvm_reg_bus_op rw);
    reg_tr tr;
    //`uvm_info($sformatf("%s",bus_item.get_type_name()),$sformatf("%s",bus_item.sprint()),UVM_MEDIUM);
    if(!($cast(tr,bus_item))) begin
        `uvm_fatal(tID,"wrong bus_item for bus2reg");
        return;
    end
    rw.kind = tr.rd ? UVM_READ : UVM_WRITE;
    rw.addr = tr.addr;
    rw.data = tr.rd ? tr.dout : tr.din ;
    rw.status = UVM_IS_OK;
    endfunction

endclass

//ralf file
class reg1 extends uvm_reg;
    `uvm_object_utils(reg1)
    rand uvm_reg_field reg1_ro;

    function new(string name="reg1");
    super.new(name,16,UVM_NO_COVERAGE);
    endfunction

    extern virtual function void build();
endclass

function void reg1::build();
reg1_ro = uvm_reg_field::type_id::create("reg1_ro");
               //parent, size,lsb,acc, vola, reset, has_reset, is_rand,indivi
reg1_ro.configure(this, 16,  0, "RO", 0,   'b0,     1,         1,      0);
endfunction

class reg2 extends uvm_reg;
    `uvm_object_utils(reg2)
    rand uvm_reg_field reg2_rw;

    function new(string name="reg2");
    super.new(name,16,UVM_NO_COVERAGE);
    endfunction

    extern virtual function void build();
endclass

function void reg2::build();
reg2_rw = uvm_reg_field::type_id::create("reg2_rw");
               //parent, size,lsb,acc, vola, reset, has_reset, is_rand,indivi
reg2_rw.configure(this, 16,  0, "RW", 0,   'b0,     1,         1,      0);
endfunction

class reg3 extends uvm_reg;
    `uvm_object_utils(reg3)
    rand uvm_reg_field reg3_rc;

    function new(string name="reg3");
    super.new(name,16,UVM_NO_COVERAGE);
    endfunction

    extern virtual function void build();
endclass

function void reg3::build();
reg3_rc = uvm_reg_field::type_id::create("reg3_rc");
               //parent, size,lsb,acc, vola, reset, has_reset, is_rand,indivi
reg3_rc.configure(this, 16,  0, "WRC", 0,   'b0,     1,         1,      0);
endfunction

class reg4 extends uvm_reg;
    `uvm_object_utils(reg4)
    rand uvm_reg_field reg4_rs;

    function new(string name="reg4");
    super.new(name,16,UVM_NO_COVERAGE);
    endfunction

    extern virtual function void build();
endclass

function void reg4::build();
reg4_rs = uvm_reg_field::type_id::create("reg4_rs");
               //parent, size,lsb,acc, vola, reset, has_reset, is_rand,indivi
reg4_rs.configure(this, 16,  0, "RS", 0,   'b0,     1,         1,      0);
endfunction

class regmodel extends uvm_reg_block;
    `uvm_object_utils(regmodel)
    rand reg1 reg1_reg;
    rand reg2 reg2_reg;
    rand reg3 reg3_reg;
    rand reg4 reg4_reg;

    function new(string name = "regmodel");
    super.new(name,UVM_NO_COVERAGE);
    endfunction

    extern virtual function void build();

endclass

function void regmodel::build() ;
//                  name, base, bytes,endian, byte_addressing
default_map = create_map("",0,  2,    UVM_LITTLE_ENDIAN,0);
reg1_reg = reg1::type_id::create("reg1_reg");
//             parent, file handle, name
reg1_reg.configure(this,null,"reg1");
reg1_reg.build();

reg2_reg = reg2::type_id::create("reg2_reg");
//             parent, file handle, name
reg2_reg.configure(this,null,"reg2");
reg2_reg.build();

reg3_reg = reg3::type_id::create("reg3_reg");
//             parent, file handle, name
reg3_reg.configure(this,null,"reg3");
reg3_reg.build();

reg4_reg = reg4::type_id::create("reg4_reg");
//             parent, file handle, name
reg4_reg.configure(this,null,"reg4");
reg4_reg.build();

default_map.add_reg(reg1_reg,`REG1_ADDR,"RO");
default_map.add_reg(reg2_reg,`REG2_ADDR,"RW");
default_map.add_reg(reg3_reg,`REG3_ADDR,"RO");
default_map.add_reg(reg4_reg,`REG4_ADDR,"RO");

endfunction
//end of ralf

class tests extends uvm_test;
    environment env;
    regmodel rgm;
    adapter  adp;
    `uvm_component_utils(tests)

    function new(string name="tests",uvm_component parent=null);
    super.new(name,parent);
    endfunction
    
    virtual function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    env = environment::type_id::create("env",this);
    rgm = regmodel::type_id::create("rgm",this);
    rgm.build();
    rgm.lock_model();
    rgm.reset();

    adp = new("adp");
    endfunction

    virtual function void connect_phase(uvm_phase phase);
    super.connect_phase(phase);
    rgm.default_map.set_sequencer(env.sqr,this.adp);
    rgm.default_map.set_auto_predict(1);
    endfunction

    virtual function void start_of_simulation_phase(uvm_phase phase);
    uvm_top.print_topology();
    check_config_usage();
    endfunction

    virtual task main_phase(uvm_phase phase);
    uvm_status_e status;
    uvm_reg_data_t value;

    phase.phase_done.set_drain_time(this,1000);
    phase.raise_objection(this);

    //first write and read reg2
    rgm.reg2_reg.write(status,0,UVM_FRONTDOOR);
    rgm.reg2_reg.read(status,value,UVM_FRONTDOOR);
    `uvm_info(get_full_name(),$sformatf("%s:%0h",rgm.reg2_reg.get_full_name(),value),UVM_MEDIUM);
    rgm.reg2_reg.write(status,1,UVM_FRONTDOOR);
    rgm.reg2_reg.read(status,value,UVM_FRONTDOOR);
    `uvm_info(get_full_name(),$sformatf("%s:%0h",rgm.reg2_reg.get_full_name(),value),UVM_MEDIUM);
    
    rgm.reg2_reg.read(status,value,UVM_FRONTDOOR);
    `uvm_info(get_full_name(),$sformatf("%s:%0h",rgm.reg2_reg.get_full_name(),value),UVM_MEDIUM);

    rgm.reg2_reg.read(status,value,UVM_FRONTDOOR);
    `uvm_info(get_full_name(),$sformatf("%s:%0h",rgm.reg2_reg.get_full_name(),value),UVM_MEDIUM);

    //reg2 should be 7
    //reg1 = reg2  +1;  reg3 records if reg2 is read; reg4 records (low active) if reg1 is read; 
    //then write and read reg1, reg3
    
    rgm.reg4_reg.read(status,value,UVM_FRONTDOOR);
    `uvm_info(get_full_name(),$sformatf("%s:%0h",rgm.reg4_reg.get_full_name(),value),UVM_MEDIUM);
    rgm.reg1_reg.read(status,value,UVM_FRONTDOOR);
    `uvm_info(get_full_name(),$sformatf("%s:%0h",rgm.reg1_reg.get_full_name(),value),UVM_MEDIUM);
    rgm.reg1_reg.read(status,value,UVM_FRONTDOOR);
    `uvm_info(get_full_name(),$sformatf("%s:%0h",rgm.reg1_reg.get_full_name(),value),UVM_MEDIUM);
    rgm.reg3_reg.read(status,value,UVM_FRONTDOOR);
    `uvm_info(get_full_name(),$sformatf("%s:%0h",rgm.reg3_reg.get_full_name(),value),UVM_MEDIUM);
    rgm.reg3_reg.read(status,value,UVM_FRONTDOOR);
    `uvm_info(get_full_name(),$sformatf("%s:%0h",rgm.reg3_reg.get_full_name(),value),UVM_MEDIUM);
    rgm.reg4_reg.read(status,value,UVM_FRONTDOOR);
    `uvm_info(get_full_name(),$sformatf("%s:%0h",rgm.reg4_reg.get_full_name(),value),UVM_MEDIUM);

    #100;
    phase.drop_objection(this);
    endtask

endclass
//end of uvm

//test top
module tb_top;

    bit clk, rstn;
    initial begin
        clk = 1'b0;
        rstn = 1'b0;
        #100;
        rstn = 1'b1;
        #10ms;
        $finish;
    end

    initial begin
        forever begin
           #10 clk = ~clk;
        end
    end
    initial begin
        $fsdbDumpvars;
        $fsdbDumpon;
    end

    reg_if reg2_if(clk);
    assign reg2_if.rstn = rstn;

    reg_rw u_dut(.clk(clk),
      .rstn(reg2_if.rstn),
      .wr(reg2_if.wr),
      .rd(reg2_if.rd),
      .addr(reg2_if.addr),
      .din(reg2_if.din),
      .dout(reg2_if.dout)
    );

    initial begin

    uvm_config_db#(virtual reg_if)::set(
        null,"uvm_test_top.env.drv","drv_if",reg2_if);
    run_test();
    end

endmodule

VCS仿真环境

demo1 — src
| – sim

sim/makefile

TIMESCALE := +timescale=1ns/1ps
INC_DIR := +incdir+../src
DEMO1_FILES := ../src/simplest_ral.sv
CASENAME := tests
SV := -full64 -sverilog -debug_access+all -kdb -lca ${INC_DIR} -timescale=1ns/10ps
UVM := -ntb_opts uvm +UVM_TESTNAME=${CASENAME} 

compile_demo1: 
	vcs ${SV} ${UVM} +memcbk -top tb_top ${DEMO1_FILES} 

run_demo1: 
	./simv +UVM_TESTNAME=${CASENAME} +UVM_VERDI_TRACE="UVM_AWARE|RAL|TLM|TLM2|IMP|HIER" +UVM_LOG_RECORD +UVM_TR_RECORD 

verdi:
	verdi -ssf novas.fsdb -nologo & 

verdi debug ral

在这里插入图片描述

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值