完善interface以及transaction
在上一节以及搭建好了整个uvm的验证环境,添加了base的test以及base的virtual sequence。
- 完善lvc_ahb_if:定义的信号与dut的接口信号一致。下方的时钟块是为了与组件匹配,确定信号的传输方向。master与slave的驱动方向相反。是为了驱动和采集interface的信号。对于monitor而言,需要采集所有的信号。
`ifndef LVC_AHB_IF_SV
`define LVC_AHB_IF_SV
interface lvc_ahb_if;
`include "lvc_ahb_defines.svh"
import lvc_ahb_pkg::*;
logic hclk;
logic hresetn;
logic hgrant;
logic [(`LVC_AHB_MAX_DATA_WIDTH-1):0] hrdata;
logic hready;
logic [1:0] hresp;
logic [(`LVC_AHB_MAX_ADDR_WIDTH-1):0] haddr;
logic [2:0] hburst;
logic hbusreq;
logic hlock;
logic [3:0] hprot;
logic [2:0] hsize;
logic [1:0] htrans;
logic [(`LVC_AHB_MAX_DATA_WIDTH-1):0] hwdata;
logic hwrite;
// debug
response_type_enum debug_hresp;
trans_type_enum debug_htrans;
burst_size_enum debug_size;
burst_type_enum debug_hburst;
xact_type_enum debug_xact;
status_enum debug_status;
// debug signals assignment
assign debug_hresp = response_type_enum'(hresp);
assign debug_htrans = trans_type_enum'(htrans);
assign debug_hsize = burst_size_enum'(hsize);
assign debug_hburst = burst_type_enum'(hburst);
// the below signals to be assigned by monitor
// debug_xact ..
// debug_status ..
// clk block
clocking cb_mst @(posedge hclk);
// USER: Add clocking block detail
default input #1ps output #1ps;
output haddr, hburst, hbusreq, hlock, hprot, hsize, htrans, hwdata, hwrite;
input hready, hgrant, hrdata, hresp;
endclocking : cb_mst
clocking cb_slv @(posedge hclk);
// USER: Add clocking block detail
default input #1ps output #1ps;
input haddr, hburst, hbusreq, hlock, hprot, hsize, htrans, hwdata, hwrite;
output hready, hgrant, hrdata, hresp;
endclocking : cb_slv
clocking cb_mon @(posedge hclk);
// USER: Add clocking block detail
default input #1ps output #1ps;
input haddr, hburst, hbusreq, hlock, hprot, hsize, htrans, hwdata, hwrite;
input hready, hgrant, hrdata, hresp;
endclocking : cb_mon
endinterface
`endif
- 完善了lvc的interface文件后需要完善在tb中与dut的连接:
- 可以看出lvc的interface中的rstn信号是来自与rkv_ahbram的interface的。
module rkv_ahbram_tb;
import uvm_pkg::*;
`include "uvm_macros.svh"
import rkv_ahbram_pkg::*;
logic clk;
logic rstn;
// 时钟的产生
initial begin : clk_gen
clk = 0;
forever #2ns clk = !clk;
end
ahb_blockram_32 #(.ADDRESSWIDTH(16)) dut(
.HCLK(ahb_if.hclk)
,.HRESETn(ahb_if.hresetn)
,.HSELBRAM(1'b1)
,.HREADY(ahb_if.hready)
,.HTRANS(ahb_if.htrans)
,.HSIZE(ahb_if.hsize)
,.HWRITE(ahb_if.hwrite)
,.HADDR(ahb_if.haddr)
,.HWDATA(ahb_if.hwdata)
,.HREADYOUT(ahb_if.hready)
,.HRESP(ahb_if.hresp)
,.HRDATA(ahb_if.hrdata)
);
// clk from tb rstn from ahbram_if
lvc_ahb_if ahb_if();
assign ahb_if.hclk = clk;
assign ahb_if.hresetn = rstn;
assign ahb_if.hgrant = 1'b1; // select
rkv_ahbram_if ahbram_if();
assign ahbram_if.clk = clk;
assign rstn = ahbram_if.rstn;
initial begin
run_test();
end
endmodule
- rstn的信号在rkv_ahbram_if中完善:
`ifndef RKV_AHBRAM_IF_SV
`define RKV_AHBRAM_IF_SV
interface rkv_ahbram_if;
logic clk;
logic rstn;
initial begin : rstn_gen
assert_reset(10);
end
task automatic assert_reset ( int nclks = 1, int delay = 0);
#(delay * 1ns);
repeat(nclks) @(posedge clk);
rstn <= 0;
repeat(5) @(posedge clk);
rstn <= 1;
endtask
endinterface
`endif
interface连接好之后,需要制作dut的sequence,首先制作好transaction,因为他就是seq在发的,驱动到dut上的内容。AHB总线协议有很多规定的内容,例如trans_type代表其状态,00代表空闲、01代表在忙、10 NSEQ代表在传数据的第一个数据,SEQ代表在传数据的其余拍等等。所以需要对其的值提前按照协议定义好,在第一节中已经提到过lvc的架构需要lvc_ahb_types,存放的就是与AHB协议相关的定义:
`ifndef LVC_AHB_TYPES_SV
`define LVC_AHB_TYPES_SV
typedef enum bit[1:0] {
OKAY = 2'b00, /**< OKAY response */
ERROR = 2'b01, /**< ERROR response */
RETRY = 2'b10, /**< RETRY response */
SPLIT = 2'b11 /**< SPLIT response */
} response_type_enum;
typedef enum bit[1:0] {
IDLE = 2'b00, /**< IDLE transaction */
BUSY = 2'b01, /**< BUSY transaction */
NSEQ = 2'b10, /**< NONSEQUENTIAL transaction */
SEQ = 2'b11 /**< SEQUENTIAL transaction */
} trans_type_enum;
typedef enum bit[2:0] {
BURST_SIZE_8BIT = 3'b000, /**< 8-bits transfer size */
BURST_SIZE_16BIT = 3'b001, /**< 16-bits transfer size */
BURST_SIZE_32BIT = 3'b010, /**< 32-bits transfer size */
BURST_SIZE_64BIT = 3'b011, /**< 64-bits transfer size */
BURST_SIZE_128BIT = 3'b100, /**< 128-bits transfer size */
BURST_SIZE_256BIT = 3'b101, /**< 256-bits transfer size */
BURST_SIZE_512BIT = 3'b110, /**< 512-bits transfer size */
BURST_SIZE_1024BIT = 3'b111 /**< 1024-bits transfer size */
} burst_size_enum;
typedef enum bit[2:0] {
SINGLE = 3'b000, /**< SINGLE Burst type */
INCR = 3'b001, /**< INCR Burst type */
WRAP4 = 3'b010, /**< 4-beat WRAP Burst type */
INCR4 = 3'b011, /**< 4-beat INCR Burst type */
WRAP8 = 3'b100, /**< 8-beat WRAP Burst type */
INCR8 = 3'b101, /**< 8-beat INCR Burst type */
WRAP16 = 3'b110, /**< 16-beat WRAP Burst type */
INCR16 = 3'b111 /**< 16-beat INCR Burst type */
} burst_type_enum;
typedef enum bit[1:0] {
READ = 2'b00, /**< Read transaction. */
WRITE = 2'b01, /**< Write transaction. */
IDLE_XACT = 2'b10 /**< Idle transaction. In case of active Master:
all the control signals except hlock(always zero) can be controlled
through respective transaction attributes
(similar to READ or WRITE transaction types);
the value of hwrite signal can be controlled through
lvc_ahb_transaction::idle_xact_hwrite. */
} xact_type_enum;
typedef enum bit[1:0] {
INITIAL ='b00, // Indicates the default state of the flag. It gets
// updated once the beat level transfer begins
PARTIAL_ACCEPT ='b01, // The status changes from INITIAL to PARTIAL_ACCEPT
// once the address of each beat is accepted by slave
ACCEPT ='b10, // The status changes to ACCEPT once the beat level
// data is accepted by the slave
ABORTED ='b11 // The status changes to ABORT in case the transaction
// is ABORTED due to ERROR/SPLIT or RETRY response from
// the slave or in case of EBT
} status_enum;
`endif
- 定义好AHB相关的协议之后,完善transaction
`ifndef LVC_AHB_TRANSACTION_SV
`define LVC_AHB_TRANSACTION_SV
class lvc_ahb_transaction extends uvm_sequence_item;
// wdata or rdata from bus 32bit
rand bit [`LVC_AHB_MAX_DATA_WIDTH-1:0] data[];
rand bit [`LVC_AHB_MAX_ADDR_WIDTH-1:0] addr = 0;
rand xact_type_enum xact_type = IDLE_XACT;
// represents the burst size of a transaction
rand burst_size_enum burst_size = BURST_SIZE_8BIT; // one data width
// transaction type
rand burst_type_enum burst_type = SINGLE; // ccm
// response from slave
rand response_type_enum response_type = OKAY;
//************************************************
// NOTE:: members possibly to be applied later可能后期使用
//************************************************
// Indicates the type of the current transfer, which can be
trans_type_enum trans_type;
// This array variable stores the responses for all the completed beats of transaction. Following are the possible response types
response_type_enum all_beat_response[];
// Indicates the beat number of the current transfer当前传输节拍数
int current_data_beat_num;
// Represents the current status of the transaction表示当前的事务状态
status_enum status = INITIAL;
// aborted_xact_status_enum aborted_xact_status = NOT_ABORTED;
// Represents the hwrite signal value when
rand bit idle_xact_hwrite = 1;//附一个默认值
`uvm_object_utils_begin(lvc_ahb_transaction)
`uvm_field_array_int(data, UVM_ALL_ON)
`uvm_field_int(addr, UVM_ALL_ON)
`uvm_field_enum(burst_size_enum, burst_size, UVM_ALL_ON)
`uvm_field_enum(burst_type_enum, burst_type, UVM_ALL_ON)
`uvm_field_enum(xact_type_enum, xact_type, UVM_ALL_ON)
`uvm_field_enum(response_type_enum, response_type, UVM_ALL_ON)
`uvm_field_enum(trans_type_enum, trans_type, UVM_ALL_ON)
`uvm_field_array_enum(response_type_enum, all_beat_response, UVM_ALL_ON)
`uvm_field_int(current_data_beat_num, UVM_ALL_ON)
`uvm_field_enum(status_enum, status, UVM_ALL_ON)
`uvm_object_utils_end
function new(string name = "lvc_ahb_transaction");
super.new(name);
endfunction
endclass
`endif