rkv_ahbram_haddr_word_unaligned_virt_seq:
对addr和bsize都随机化操作
`ifndef RKV_AHBRAM_HADDR_WORD_UNALIGNED_VIRT_SEQ_SV
`define RKV_AHBRAM_HADDR_WORD_UNALIGNED_VIRT_SEQ_SV
class rkv_ahbram_haddr_word_unaligned_virt_seq extends rkv_ahbram_base_virtual_sequence;
`uvm_object_utils(rkv_ahbram_haddr_word_unaligned_virt_seq)
function new (string name = "rkv_ahbram_haddr_word_unaligned_virt_seq");
super.new(name);
endfunction
virtual task body();
bit [31:0] addr, data;
burst_size_enum bsize;
super.body();
`uvm_info("body", "Entered...", UVM_LOW)
for(int i=0; i<100; i++) begin
std::randomize(bsize) with {bsize inside {BURST_SIZE_8BIT, BURST_SIZE_16BIT, BURST_SIZE_32BIT};};
std::randomize(addr) with {addr inside {['h1000:'h1FFF]};
bsize == BURST_SIZE_16BIT -> addr[0] == 0;//为了地址对齐
bsize == BURST_SIZE_32BIT -> addr[1:0] == 0;
};
std::randomize(wr_val) with {wr_val == (i << 24) + (i << 16) + (i << 8) + i;};//使每一个byte位都有数据
data = wr_val;
`uvm_do_with(single_write, {addr == local::addr; data == local::data; bsize == local::bsize;})
`uvm_do_with(single_read, {addr == local::addr; bsize == local::bsize;})
end
`uvm_info("body", "Exiting...", UVM_LOW)
endtask
endclass
`endif
monitor获取过来原始数据给scb;但是scoreboard没有做地址对齐,需要修改
问题在于:按之前的情况如果存入`h10=`hFFAABBCC;
之后如果在`h11中存入`h11=`hEE;
则输出保存的结果为`h10`=`hFFAAEECC;会被覆盖掉
所以要做地址操作,保证传输过来的数据都被保存在scoreboard中:
`ifndef RKV_AHBRAM_SCOREBOARD_SV
`define RKV_AHBRAM_SCOREBOARD_SV
class rkv_ahbram_scoreboard extends rkv_ahbram_subscriber;
// events of scoreboard
bit [31:0] mem [int unsigned];
// typedef enum {CHECK_LOADCOUNTER} check_type_e;
`uvm_component_utils(rkv_ahbram_scoreboard)
function new (string name = "rkv_ahbram_scoreboard", uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
endfunction
task run_phase(uvm_phase phase);
super.run_phase(phase);
do_data_check();
endtask
virtual function void write(lvc_ahb_transaction tr);
if(is_addr_valid(tr.addr)) begin
case(tr.xact_type)
WRITE : store_data_with_hburst(tr);
READ : check_data_with_hburst(tr);
endcase
end
endfunction
task do_listen_events();
endtask
virtual task do_data_check();
endtask
function bit is_addr_valid(bit [31:0] addr);
if(addr >= cfg.addr_start && addr <= cfg.addr_end)
return 1;
endfunction
function void store_data_with_hburst(lvc_ahb_transaction tr);
// TODO implementation in child class
case(tr.burst_type)
SINGLE: begin
store_data_with_hsize(tr, 0);
end
INCR : begin `uvm_error("TYPEERR", "burst type not supported yet") end
WRAP4 : begin `uvm_error("TYPEERR", "burst type not supported yet") end
INCR4 : begin `uvm_error("TYPEERR", "burst type not supported yet") end
WRAP8 : begin `uvm_error("TYPEERR", "burst type not supported yet") end
INCR8 : begin `uvm_error("TYPEERR", "burst type not supported yet") end
WRAP16: begin `uvm_error("TYPEERR", "burst type not supported yet") end
INCR16: begin `uvm_error("TYPEERR", "burst type not supported yet") end
default: begin `uvm_error("TYPEERR", "burst type not defined") end
endcase
endfunction
function bit check_data_with_hburst(lvc_ahb_transaction tr);
// TODO implementation in child class
case(tr.burst_type)
SINGLE: begin
check_data_with_hburst = (check_data_with_hsize(tr, 0));
end
INCR : begin `uvm_error("TYPEERR", "burst type not supported yet") end
WRAP4 : begin `uvm_error("TYPEERR", "burst type not supported yet") end
INCR4 : begin `uvm_error("TYPEERR", "burst type not supported yet") end
WRAP8 : begin `uvm_error("TYPEERR", "burst type not supported yet") end
INCR8 : begin `uvm_error("TYPEERR", "burst type not supported yet") end
WRAP16: begin `uvm_error("TYPEERR", "burst type not supported yet") end
INCR16: begin `uvm_error("TYPEERR", "burst type not supported yet") end
default: begin `uvm_error("TYPEERR", "burst type not defined") end
endcase
if(check_data_with_hburst)
`uvm_info("DATACHK", $sformatf("ahbram[%0x] hburst[%s] is as expected", tr.addr, tr.burst_type), UVM_HIGH)
else
`uvm_error("DATACHK", $sformatf("ahbram[%0x] hburst[%s] is NOT as expected", tr.addr, tr.burst_type))
endfunction
function void store_data_with_hsize(lvc_ahb_transaction tr, int beat);
case(tr.burst_size)//1:0位不管补0,地址最少相差4字节往里写,不会有覆盖现象
BURST_SIZE_8BIT : mem[{tr.addr[31:2],2'b00}] = extract_current_beat_mem_data(tr, beat);//mem接收到偏移处理后的mdata
BURST_SIZE_16BIT : mem[{tr.addr[31:2],2'b00}] = extract_current_beat_mem_data(tr, beat);
BURST_SIZE_32BIT : mem[{tr.addr[31:2],2'b00}] = extract_current_beat_mem_data(tr, beat);
BURST_SIZE_64BIT : begin `uvm_error("TYPEERR", "burst size not supported") end
default : begin `uvm_error("TYPEERR", "burst size not supported") end
endcase
endfunction
function bit check_data_with_hsize(lvc_ahb_transaction tr, int beat);
bit[31:0] tdata = extract_valid_data(tr.data[beat], tr.addr, tr.burst_size);
bit[31:0] mdata = extract_valid_data(mem[{tr.addr[31:2],2'b00}], tr.addr, tr.burst_size);
check_data_with_hsize = tdata == mdata ? 1 : 0;
cfg.scb_check_count++;
if(check_data_with_hsize)
`uvm_info("DATACHK", $sformatf("ahbram[%0x] data expected 'h%0x = actual 'h%0x", tr.addr, mdata, tdata), UVM_HIGH)
else begin
cfg.scb_check_error++;
`uvm_error("DATACHK", $sformatf("ahbram[%0x] data expected 'h%0x != actual 'h%0x", tr.addr, mdata, tdata))
end
endfunction
function bit [31:0] extract_current_beat_mem_data(lvc_ahb_transaction tr, int beat);//数据进行偏移处理
bit [31:0] mdata = mem[{tr.addr[31:2],2'b00}];
bit [31:0] tdata = tr.data[beat];//存入data
case(tr.burst_size) //8BIT mdata如果addr为0存放在7:0位,addr为1存放在15:8位,addr为2存放在23:16位,addr为3存放在31:24位
BURST_SIZE_8BIT : mdata[(tr.addr[1:0]*8 + 7) -: 8] = tdata >> (8*tr.addr[1:0]);//不管tdata多少位只拾取低八位
//16BIT mdata如果addr[1]为0tdata存放在16:0位,addr[1]为1存放在31:17位
BURST_SIZE_16BIT : mdata[(tr.addr[1]*16 + 15) -: 16] = tdata >> (16*tr.addr[1]);
BURST_SIZE_32BIT : mdata = tdata;
BURST_SIZE_64BIT : begin `uvm_error("TYPEERR", "burst size not supported") end
default : begin `uvm_error("TYPEERR", "burst size not supported") end
endcase
return mdata;//输出mdata给mem
endfunction
endclass
`endif
代码分解:write操作存入mem
function void store_data_with_hsize(lvc_ahb_transaction tr, int beat);
case(tr.burst_size)//1:0位不管补0,如195d和195e都写在同一地址195c,但是不同偏移量
BURST_SIZE_8BIT : mem[{tr.addr[31:2],2'b00}] = extract_current_beat_mem_data(tr, beat);//mem接收到偏移处理后的mdata
BURST_SIZE_16BIT : mem[{tr.addr[31:2],2'b00}] = extract_current_beat_mem_data(tr, beat);
BURST_SIZE_32BIT : mem[{tr.addr[31:2],2'b00}] = extract_current_beat_mem_data(tr, beat);
BURST_SIZE_64BIT : begin `uvm_error("TYPEERR", "burst size not supported") end
default : begin `uvm_error("TYPEERR", "burst size not supported") end
endcase
endfunction
function bit [31:0] extract_current_beat_mem_data(lvc_ahb_transaction tr, int beat);//数据进行偏移处理
bit [31:0] mdata = mem[{tr.addr[31:2],2'b00}];
bit [31:0] tdata = tr.data[beat];//存入data
case(tr.burst_size) //8BIT mdata如果addr为0存放在7:0位,addr为1存放在15:8位,addr为2存放在23:16位,addr为3存放在31:24位
BURST_SIZE_8BIT : mdata[(tr.addr[1:0]*8 + 7) -: 8] = tdata >> (8*tr.addr[1:0]);//不管tdata多少位只拾取低八位
//16BIT mdata如果addr[1]为0tdata存放在16:0位,addr[1]为1存放在31:17位
BURST_SIZE_16BIT : mdata[(tr.addr[1]*16 + 15) -: 16] = tdata >> (16*tr.addr[1]);
BURST_SIZE_32BIT : mdata = tdata;
BURST_SIZE_64BIT : begin `uvm_error("TYPEERR", "burst size not supported") end
default : begin `uvm_error("TYPEERR", "burst size not supported") end
endcase
return mdata;//输出mdata给mem
endfunction
为了防止出现覆盖,mem中存放的地址为写入地址的后两位取0,如195d和195e都在同一地址195c,但是具有不同偏移量。(先地址统一再进行偏移存放)
在8BIT中,如果后两位地址为0,则数据存放在mem的7:0位;
如果后两位地址位1,则数据存放在mem的15:8位;
如果后两位地址为2,则数据存放在mem的23:16位;
如果后两位地址为3,则数据存放在mem的31:24位;
在16BIT中,如果addr[1]为0,则数据存放在mem的15:0位;
如果addr[1]为1,则数据存放在mem的31:16位;
例子:
195d 8BIT 数据02020202:
地址统一为195c开始存放,后两位地址为1,则存放在15:8位,为00000200;
195e 16BIT 数据03030303:
地址统一为195c开始存放,后两位地址为3,则存放在31:16位,为03030200;
113c 16BIT 数据04040404:
地址统一为113c开始存放,后两位地址为0,则存放在15:0位,为00000404;
17f3 8BIT 数据05050505:
地址统一为17f0开始存放,后两位地址为3,则存放在31:24位,为05000000;
read:check_data
function bit check_data_with_hsize(lvc_ahb_transaction tr, int beat);
bit[31:0] tdata = extract_valid_data(tr.data[beat], tr.addr, tr.burst_size);
bit[31:0] mdata = extract_valid_data(mem[{tr.addr[31:2],2'b00}], tr.addr, tr.burst_size);
check_data_with_hsize = tdata == mdata ? 1 : 0;
cfg.scb_check_count++;
if(check_data_with_hsize)
`uvm_info("DATACHK", $sformatf("ahbram[%0x] data expected 'h%0x = actual 'h%0x", tr.addr, mdata, tdata), UVM_HIGH)
else begin
cfg.scb_check_error++;
`uvm_error("DATACHK", $sformatf("ahbram[%0x] data expected 'h%0x != actual 'h%0x", tr.addr, mdata, tdata))
end
endfunction
function bit [31:0] extract_valid_data([`LVC_AHB_MAX_DATA_WIDTH - 1:0] data
,[`LVC_AHB_MAX_ADDR_WIDTH - 1 : 0] addr
,burst_size_enum bsize);
case(bsize)
BURST_SIZE_8BIT : return (data >> (8*addr[1:0])) & 8'hFF;
BURST_SIZE_16BIT : return (data >> (16*addr[1]) ) & 16'hFFFF;
BURST_SIZE_32BIT : return data & 32'hFFFF_FFFF;
BURST_SIZE_64BIT : begin `uvm_error("TYPEERR", "burst size not supported") end
default : begin `uvm_error("TYPEERR", "burst size not supported") end
endcase
endfunction
将监测的读数据与mem的数据都进行函数extract_valid_data处理:
如读回来195d中的数据应为00000200;右移8位并&FF得到00000002;
mem中195d地址统一为195c,其中数据为03030200(有195e的16bit0303);右移8位 并&FF得到00000002
最后两个数进行对比,结果相同;