最近看到AXI slave vip memory,记录下如何backdoor读写memory.
define `MEM_MAX_DATA_WIDTH (64)
define `MEM_MAX_ADDR_WIDTH (20)
ps: define 记得加上括号。
========================================================================
//处理从memory读出来的数据,返回读出来的数据
//比如,读addr=7,byte_num=2,则需要读取两个memory entry(0和8),然后把addr=7对应的data(8'h12)和addr=8对应的data
//(8'h34)merge在一起后返回(16'h3412)
function bit [`MEM_MAX_DATA_WIDTH:0] backdoor_read_mem(
bit [`MEM_MAX_ADDR_WIDTH-1 : 0] addr =0,
bit [`MEM_MAX_DATA_WIDTH-1 : 0] byte_num = `MEM_MAX_DATA_WIDTH/8);
bit [`MEM_MAX_DATA_WIDTH-1 : 0] data = 0;
bit [`MEM_MAX_DATA_WIDTH-1 : 0] data_tmp = 0;
bit [`MEM_MAX_ADDR_WIDTH-1 : 0] end_addr = addr + byte_num -1;
int dwidth_power =0;
bit [`MEM_MAX_ADDR_WIDTH-1 : 0] addr_lsb =0;
dwidth_power = cal_data_width_power(`MEM_MAX_ADDR_WIDTH);
addr_lsb = addr & {dwidth_power{1'b1}};//用于计算unalign addr
if((addr >> dwidth_power) == (end_addr >> dwidth_power)begin//同一个memory entry
data_tmp = slave_mem.read(addr);
data = data_tmp >>(addr_lsb*8);
end
else begin
data_tmp = slave_mem.read(addr);
data = data_tmp >>(addr_lsb*8);//移到最低位
data_tmp = slave_mem.read(addr);
data |= data_tmp <<((`MEM_MAX_DATA_WIDTH/8-addr_lsb)*8);//两次数据进行merge
end
if(byte_num < `MEM_MAX_DATA_WIDTH/8)//把没有用的bit置为0
data &= ({byte_num*8{1'b1}});
return data;
endfunction
===================================================================
function bit backdoor_write_mem(
bit [`MEM_MAX_ADDR_WIDTH-1 : 0] addr =0,
bit [`MEM_MAX_DATA_WIDTH-1 : 0] data = 0,
bit [`MEM_MAX_DATA_WIDTH-1 : 0] byte_num = `MEM_MAX_DATA_WIDTH/8);
bit [`MEM_MAX_DATA_WIDTH-1 : 0] data_tmp = 0;
bit [`MEM_MAX_ADDR_WIDTH-1 : 0] end_addr = addr + byte_num -1;
bit [`MEM_MAX_DATA_WIDTH/8-1 : 0] byteen = ~0;//所有bit 为1
int dwidth_power =0;
bit [`MEM_MAX_ADDR_WIDTH-1 : 0] addr_lsb =0;
bit [`MEM_MAX_ADDR_WIDTH-1 : 0] end_addr_lsb =0;
dwidth_power = cal_data_width_power(`MEM_MAX_ADDR_WIDTH);
addr_lsb = addr & {dwidth_power{1'b1}};//用于计算unalign addr
end_addr_lsb = end_addr & {dwidth_power{1'b1}};
if((addr >> dwidth_power) == (end_addr >> dwidth_power)begin//同一个memory entry
byteen=0;
for(int i=addr_lsb;i<=end_addr_lsb;i++)
byteen[i] = 1'b1;
data_tmp = data <<(data_lsb*8);
if(slave_mem.write(addr,data_tmp,byteen) == 0)begin
`uvm_fatal(....)
return 0;
end
end
else begin
byteen = ~0;
for(int i=0;i<addr_lsb;I++)
byteen[i] = 1'b0;
data_tmp = data <<(addr_lsb*8);
slave_mem.write(addr,data_tmp,byteen);
byteen= 'b0;
for(int i=0;i<end_addr_lsb;i++)
byteen[i] = 1'b1;
data_tmp = data >>((`MEM_MAX_DATA_WIDTH/8-addr_lsb)*8);
addr = ((addr>>dwidth_power)+1)<<dwidth_power;
slave_mem.write(addr,data_tmp,byteen);
end
rerurn 1;
endfunction
===================================================================
//用于计算数据位宽是2的几次幂;
//对于memory而言,每行entry的起始addr(即aligned addr)的低data_width_power位是全为0;
//比如 数据宽度为64bit, 则power=3,每行entry对应的起始addr为'h0,'h8,'h10,'h18....,其低3bit全为0;
function int cal_data_width_power(data_width);
int i = 0;
int tmp_value = data_width/8;
while(tmp_value>0)begin
tmp_value = tmp_value >> 1;
if(tmp_value == 0) break;
i++;
end
return i;
endfunction
========================================================================
class mem extends uvm_sequence_item;
typedef bit [`MEM_MAX_DATA_WIDTH-1:0] data_t;
typedef bit [`MEM_MAX_ADDR_WIDTH-1:0] addr_t;
bit [`MEM_MAX_ADDR_REGION_WIDTH-1:0] addr_region = 0;//暂时没用到
bit [`MEM_MAX_ADDR_WIDTH-1:0] min_addr = 0;
bit [`MEM_MAX_ADDR_WIDTH-1:0] max_addr = 0;
int data_wdth = 0;
bit [`MEM_MAX_DATA_WIDTH-1:0] meminit_value;
mem_word mem_array[*];//memory hash
mem_word mem_item; //每个memory entry
static int dwidth_power;
function new(string name = "mem_inst",
int data_wdth = 32,
int addr_region = 0,
bit [`MEM_MAX_ADDR_WIDTH-1:0] min_addr = 0,
bit [`MEM_MAX_ADDR_WIDTH-1:0] max_addr = ((1<<`MEM_MAX_ADDR_WIDTH)-1)
);
this.addr_region = addr_region;
this.data_wdth = data_wdth;
this.min_addr = min_addr;
this.max_addr = max_addr;
endfunction
function logic[`MEM_MAX_DATA_WIDTH-1:0] read(bit [`MEM_MAX_ADDR_WIDTH-1:0] addr, int set_lock = -1);
bit [`MEM_MAX_DATA_WIDTH-1:0] mem_idx = (addr >>dwidth_power);
if(mem_array.exists(mem_idx))
return mem_array[mem_idx].read();
else begin
set_meminit_value();//设置初始值
mem_item = new(addr_region,mem_idx,);//例化一个memory entry
mem_item.write(this.meminit_value); //把初始值写入entry
mem_array[mem_idx] = mem_item; //把entry 存入memory
return this.meminit_value;
end
endfunction
function bit write (bit [`MEM_MAX_ADDR_WIDTH-1:0] addr, bit [`MEM_MAX_DATA_WIDTH-1:0] data = 0,
bit [`MEM_MAX_DATA_WIDTH/8-1:0] byteen=~0,int set_lock = -1);
bit [`MEM_MAX_DATA_WIDTH-1:0] mem_idx = (addr >>dwidth_power);
if(set_lock == 1)
return 0;
else begin
if(! mem_array.exists(mem_idx))begin
mem_item = new(addr_region,mem_idx,);//例化一个memory entry
set_meminit_value();//设置初始值,随机选择全0,全1,随机值
mem_item.write(this.meminit_value); //把初始值写入entry
mem_array[mem_idx] = mem_item; //把entry 存入memory
end
void' (mem_array[mem_idx].write(data,byteen,));
return 1;
end
endfunction
function void clear();
mem_array.delete;
endfunction
endclass
=================================================================================
class mem_word;
bit [`MEM_MAX_ADDR_REGION_WIDTH-1:0] addrspace;
bit [`MEM_MAX_ADDR_WIDTH-1:0] addr;
bit [`MEM_MAX_DATA_WIDTH-1:0] data;
static int dwidth_power = 7;
function new (bit [`MEM_MAX_ADDR_REGION_WIDTH-1:0] addrspace,
bit [`MEM_MAX_ADDR_WIDTH-1:0] addr;
bit [`MEM_MAX_DATA_WIDTH-1:0] init_data = 'bx;
);
this.addrspace = addrspace;
this.addr = addr;
this.data = init_data;
endfunction
function logic[`MEM_MAX_DATA_WIDTH-1:0] read();
return this.data;
endfunction
function bit write (bit [`MEM_MAX_DATA_WIDTH-1:0] data ,
bit [`MEM_MAX_DATA_WIDTH/8-1:0] byteen=~0,
int set_lock = -1);
logic [`MEM_MAX_DATA_WIDTH-1:0] org_word_tmp;
logic [`MEM_MAX_DATA_WIDTH-1:0] in_word_tmp;
logic [`MEM_MAX_DATA_WIDTH-1:0] word_tmp;
logic [7:0] byte_tmp;
logic [7:0] in_byte_tmp;
int i;
if(set_lock == 1)
return 0;
else begin
for(i=(`MEM_MAX_DATA_WIDTH/8-1);i>=0;i--)begin
org_word_tmp = (this.data>>(i*8));//之前已经存入memory中的data
byte_tmp = org_word_tmp[7:0];//从最高byte(MSB)开始循环,每次把当前byte右移到最低byte处
in_word_tmp = (data>>(i*8));//当前要存入memory中的data
in_byte_tmp = in_word_tmp[7:0];
if(byteen[i]==1)//当前byte 数据有更新
byte_tmp = in_byte_tmp;
word_tmp = (word_tmp<<8) | byte_tmp;
end
this.data = word_tmp;
return 1;
end
endclass