AHB_SLAVE设计与验证

AHB_SLAVE设计与验证

提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加
根据AMBA3.0总线协议设计



前言

新手入门超详细AHB_slave的设计与验证详细过程


一、核心程序

示例:pandas 是基于NumPy 的一种工具,该工具是为了解决数据分析任务而创建的。

1.ahb_slave_if设计

这个是我们本次设计的核心代码如下(示例):

module ahb_slave_if(input hclk,
input hresetn,//为0时进行复位
input hsel,//片选,因为一个master往往接了很多的slave,如何确定是让本slave工作,除了hready信号以及hresetn信号外就还需要hsel来选择
input hwrite,//1为写吗,0为读
input hready_in,//hready信号表示前一次操作已经完成,可以进行当前操作,如果为0则继续保持前一次操作
input [2:0] hsize,//表示传输数据大小的选择
input [1:0] htrans,//表示传输数据的方式是连续传输还是终止还是暂停
input [31:0] hwdata,//master传到sram的数据通过这里进入
input [31:0] haddr,//master传到sram的地址通过这个传入
input [31:0] sram_data,//当为读的时候sram传回master的数据从这里传回
//out to sram
output hready_resp,//salve控制模块将来自sram的信号传给master,这个表示传输完成
output [31:0] hrdata,//读回的信号
output [12:0] sram_addr_out,//slave控制块给sram的地址
output [31:0] sram_wdata,//slave控制块给sram 的数据
output sram_cs,//表示使能,如果为高说明本次操作有效
output reg[3:0] sram_wen,//表示片选,代表具体工作的位数。写操作时用到,因为写操作有写8/16/32、64等写入操作即word halfword byte传输
output sram_read,//读有效
output reg[31:0] haddr_r,//-r表示延迟一拍的信号
output sram_cs_m);
reg hwrite_r;
reg [2:0] hsize_r;
reg sram_write_r;
wire [1:0] haddr_sel;
wire [1:0] hsize_sel;
wire sram_csn_en;
wire sram_write;
wire [15:0] sram_addr;
wire [31:0] sram_data_out;
reg hready_re;
reg hresp_before;
//hready_out
assign hready_resp=hready_re;
//sram_haddr
assign sram_write=(htrans[1]==1'b1)&&(hsel==1'b1)&&(hready_in==1'b1)&&(hwrite==1'b1);
assign sram_read=(htrans[1]==1'b1)&&(hsel==1'b1)&&(hready_in==1'b1)&&(hwrite==1'b0);
assign sram_addr==(htrans[1]==1'b1)&&(hsel==1'b1)&&(hready_in==1'b1)&&(hwrite==1'b0)? haddr[15:0]:haddr_r[15:0];
assign sram_addr_out=sram_addr[14:2];
//sram_cs
assign hresp=sram_cs? hresp_before:2'b0;
assign sram_cs=((sram_write_r&&hresp_before)||sram_read);
//monitor use
assign sram_cs_m=(sram_write_r)||sram_read
//hrdata
assign hrdata=sram_data;
//sram_wen
assign haddr_sel=sram_addr[1:0];
assign hsize_sel=hsize_r[1:0];
//sram_wdata
assign sram_wdata=hwdata;
//sram_w_en to monitor
always@(*) begin
if(sram_write_r==1)
sram_w_en=0;
else if(sram_read==1)
sram_w_en=1;
else sram_w_en=1'bx;
end
always@(posedage hclk or negedge hresetn)begin
if(!hresetn)begin
sram_write_r<=1'b0;
end
else begin
sram_write_r<=sram_write;
end
end
always@(posedage hclk or negedge hresetn)begin
if(!hresetn)begin
hsize_r=3'b0;
haddr_r<=32'b0;
end
else if(hsel&&hready_in&&htrans[1])begin
hsize_r<=hsize;
haddr_r<=haddr;
end
end
always@(posedage hclk or negedge hresetn)begin
hwrite_r<=hwrite;
end
//sram_wen and efficient addr 
always@(*)begin
if(sram_write_r==1'b1)begin
case(hsize_sel)
2'b0:begin
case(haddr_sel[1:0])
2'b0:begin sram_wen=4'b0001;hresp_before=2'b1;end
2'b1:begin sram_wen=4'b0010;hresp_before=2'b1;end
2'b2:begin sram_wen=4'b0100;hresp_before=2'b1;end
default:begin sram_wen=4'b1000;hresp_before=2'b1;end
endcase
end
2'b1:begin
case(haddr_sel[1:0])
2'b0:begin sram_wen=4'b0011;hresp_before=2'b1;end
2'b1:begin sram_wen=4'b0;hresp_before=2'b0;end
2'b2:begin sram_wen=4'b1100;hresp_before=2'b1;end
default:begin sram_wen=4'b0;hresp_before=2'b0;end
endcase
end
2'b2:begin
case(haddr_sel[1:0])
2'b0:begin sram_wen=4'b1111;hresp_before=2'b1;end
2'b1:begin sram_wen=4'b0;hresp_before=2'b0;end
2'b2:begin sram_wen=4'b0;hresp_before=2'b0;end
default:begin sram_wen=4'b0;hresp_before=2'b0;end
endcase
end
default:begin
sram_wen=4'b0;hresp_before=2'b0;
end
encase
end
else if(sram_read==1'b0)
sram_wen=4'b0;hresp_before=2'b1;
end
end
always@(*) begin
if(sram_write_r==1'b1&&hresp_before==1'b1)begin
if(hwrite==1'b0)begin
hready_re=1'b0;
end
else begin
hready_re=1'b1;
end
end
end
endmodule



2.sram_model设计

代码如下(示例):

module  SRAM_MODEL(
input clk,
input rstn,
input [9:0] sram_addr,
input [31:0]sram_wdata,
input sram_cs,
input [3:0] sram_wen,
output reg [31:0] sram_rdata);
reg [31:0] mem[0:1023];
reg sram_wr_en;
reg sram_rd_en;
always @(*)begin
if(sram_cs==1'b1)begin 
if(|sram_wen==1'b1)begin
sram_wr_en=1'b1;
sram_rd_en=1'b0;
end
else begin
sram_wr_en=1'b0;
sram_rd_en=1'b1;
end
end
else begin
sram_wr_en=1'b0;
sram_rd_en=1'b0;
end
end
//mem body
genvar i;
generate 
 for(i=0;i<1023;i=i+1)begin:MEM_BODY
 always @(posedge clk or negedge rstn)begin
 if(!rstn)begin
 mem[i]<=32'b0;
 end
 else begin
 if(sram_wr_en==1'b1)begin
 if(sram_wen[0]==1'b1)begin
 mem[sram_addr][7:0]<=sram_wdata[7:0];
 end
  if(sram_wen[1]==1'b1)begin
 mem[sram_addr][15:8]<=sram_wdata[15:8];
 end
 if(sram_wen[2]==1'b1)begin
 mem[sram_addr][23:16]<=sram_wdata[23:16];
 end
  if(sram_wen[3]==1'b1)begin
 mem[sram_addr][31:24]<=sram_wdata[31:24];
 end
 end
 end
 end
 end
 endgenerate
 always@(posedge clk or negedge rstn)begin
 if(!rstn)begin
 sram_rdata<=32'b0;
 end
 else begin
 if(sram_rd_en==1'b1)begin
 sram_rdata<=mem[sram_addr];
 end
 end
 end
 endmodule

3.top层设计

作用就是连接以上两个模块

module sramc_top(
input wire hclk,
input hresetn,
input hsel,
input hwrite,
input[1:0] htrans,
input[2:0] hsize,
input  hready_in,
input[2:0] hburst,
input [31:0] haddr,
input [31:0] hwdata,
output [31:0] hrdata,
output hready_resp,
output [31:0] sram_data,
output [31:0]sram_wdata,
output [12:0]sram_addr_out,
output  sram_cs,
output  sram_read,
output  [31:0] haddr_r,
output [3:0]sram_wen,
output sram_w_en,
output sram_cs_m
);
ahb_slave-if ahb_slave_if_u(
.hclk     (hclk),
.hresetn  (hresetn),
.hsel      (hsel),
.hwrite    (hwrite),
.hready_in (hready_in),
.hsize (hsize),
.htrans (htrans),
.hwdata  (hwdata),
.haddr   (haddr),
.sram_data  (sram_data),
.hready_resp (hready_resp),
.hrdata (hrdata),
.sram_addr_out (sram_addr_out),
.sram_wdata (sram_wdata),
.sram_cs   (sram_cs),
.haddr_r  (haddr_r),
.sram_cs_m (sram_cs_m));
SRAM_MODEL SRAM_MODEL_u(
.clk (hclk),
.rstn (hresetn),
.sram_addr (sram_addr_out[9:0]),
.sram_wdata (sram_wdata),
.sram_cs  (sram_cs),
.sram_wen  (srma_wen),
.sram_rdata (sram_data));
endmodule


二、验证环境

1.接口组件设计interface

interface ahb_sram_if(input hclk);
logic hresetn;
logic hsel;
logic hwrite;
logic[1:0] htrans;
logic[2:0] hsize;
logic  hready;
logic[2:0] hburst;
logic [31:0] haddr;
logic [31:0] hwdata;
logic [31:0] hrdata;
logic hready_resp;
logic [31:0] sram_data;
logic [31:0]sram_wdata;
logic [12:0]sram_addr_out;
logic  sram_cs;
logic  sram_read;
logic  [31:0] haddr_r;
logic [3:0]sram_wen;
logic sram_w_en;
logic sram_cs_m;
clocking drv_cb@(posedge hclk);
output hsel;
output hresetn;
output hready;
output haddr;
output htrans;
output hsize;
output hwrite;
output hwdata;
input hrdata;
input hready_resp;
endclocking
clocking mon_cb@(posedge hclk);
input hsel;
input hresetn;
input hready;
input haddr;
input htrans;
input hsize;
input hwrite;
input hwdata;
input hrdata;
input hready_resp;
input sram_data_out;
input sram_data;
input sram_wdata;
input sram_addr_out;
input sram_cs;
input sram_read;
input haddr_r;
input sram_wen;
input sram_w_en;
input sram_cs_m
endclocking
modport driver(clocking drv_cb);
modport monitor(clocking mon_cb);
endinterface

2.DUT与 验证test的连接


module ahb_sram_svtb_top();
bit hclk;
logic h;
logic [30:0] hreadyclk;
logic hreadycl;
assign hreadyclk=$urandom();
initial begin
for(int j=0;j<32;j++)begin
for(int c=0;c<32;c++)begin
for(int i=0;i<32;)begin
#60
@(posedge hclk)
#5
h=hreadyclk[i];
i=i+5;
end
end
end
end
ahb_slv_if ahb_sramc_if(hclk);//例化了一个接口
ahb_sram_test test(ahb_sramc_if);//将例化的接口与test连接
initial begin
#20 hreadycl=1;
#20 hreadycl=1;
#20 hreadycl=0;
#20 hreadycl=1;
end
assign ahb_sramc_if.hresetn=hreadycl;
assign ahb_sramc_if.hready=ahb_sramc_if.hready_resp&&h;
sramc_top  u_sramc_top(
.hclk   (hclk),
.hresetn (ahb_sramc_if.hresetn),
.hsel    (ahb_sramc_if.hsel),
.hwrite  (ahb_sramc_if.hwrite),
.htrans  (ahb_sramc_if.htrans),
.hsize  (ahb_sramc_if.hsize),
.hready_in  (ahb_sramc_if.hready_in),
.hburst  (3'b0),
.haddr  (ahb_sramc_if.haddr),
.hwdata  (ahb_sramc_if.hwdata),
.hrdata  (ahb_sramc_if.hrdata),
.hready_resp  (ahb_sramc_if.hready_resp),
.sram_data  (ahb_sramc_if.sram_data),
.sram_wdata  (ahb_sramc_if.sram_wdata),
.sram_addr_out  (ahb_sramc_if.sram_addr_out),
.sram_cs  (ahb_sramc_if.sram_cs),
.sram_read  (ahb_sramc_if.sram_read),
.haddr_r  (ahb_sramc_if.haddr_r),
.sram_wen  (ahb_sramc_if.sram_wen),
.sram_w_en  (ahb_sramc_if.sram_w_en),
.sram_cs_m  (ahb_sramc_if.sram_cs_m)
);
initial begin
forever #10 hclk=~hclk;
end   
initial begin
string dump;
if($value$plusargs(''Dump=%s'',dump))begin
 if(dump==''ON'')begin
 $fsdbDumpfile(''../sim/waves1.fsdb'');
  $fsdbDumpfile(0,ahb_sramc_svtb_top,''+mda'');//这三条缺一不可注意是tb的名称
  $display(''tb:dump_wave'',$time);
  end
  end
  end
  endmodule

3.test

program ahb_sram_test(ahb_slv_if slv_if);
int tr_num;//传输数据的个数
int rnd_seed;//随机种子
int tc_num;//case编号
class tc_base;
int tr_num;
environment ahb_env;
virtual ahb_slv_if slv_if;
extern function new(virtual ahb_slv_if slv_if,int tr_num);
extern function build();
extern virtual task run();
endclass
function tc_base::new(virtual ahb_slv_if slv_if,int tr_num);
this.slv_if=slv_if;
this.tr_num=tr_num;
endfunction
function tc_base::build();
ahb_env=new(this.slv_if,tr_num);
ahb_env.build();
endfunction
function tc_base::run();
ahb_env.run;
endfunction
class tc010 extends tc_base;
 extern function new(virtual ahb_slv slv_if,int tr_num);
 extern task run();
 enclass
 function tc010::new(virtual ahb_slv_if slv_if,int tr_num);
 super.new(slv_if,tr_num);
 endfunction
 task tc010::run();
 fork
 ahb_env.run;
 begin
 for(int i=0;i<(tr_num/3);i++)begin
 #0.01;
 ahb_env.gen.write_all_random(i+1);
 end
  for(int i=0;i<(tr_num/3);i++)begin
 #0.01;
 ahb_env.gen.read_all_random(i+1);
 end
  for(int i=0;i<(tr_num/3);i++)begin
 #0.01;
 ahb_env.gen.write_all_random(i+2);
 end
 end
 join
 endtask
 tc010 tc10;
 initial begin
 #3900;
 $finish;
 initial begin
 $vcdpluson();
 if(!value$plusargs("tc_num=%d",tc_num))begin
 tc_num=0;
 end
 else begin
 $display("tc_num is:%0d",$time,tc_num);
 end
tc10=new(slv_if.100);
if(tc_num==10)begin
tc10.build();
tc10.run();
end
endprogram

4.environment

class environment;
generator gen;  
agent agt;
driver drv;
scoreboard scb;
monitor mon;
int tr_num;
mailbox gen2agt_mbx=new();
mailbox agt2drv_mbx=new();
mailbox drv2scb_mbx=new();
mailbox mon2scb_mbx=new();
mailbox mon2drv_mbx=new();
virtual ahb_slv_if slv_if;
extern function new(virtual ahb_slv_if slv_if,int tr_num);
extern function build();
extern task run();
endclass
function environment::new(virtual ahb_slv_if,int tr_num);
this.slv_if=slv_if;
this.tr_num=tr_num;
enfunction
function environment::build();
gen=new(gen2agt_mbx,tr_num);
drv=new(agt2drv_mbx,drv2scb_mbx,slv_if,tr_num);
mon=new(mon2scb_mbx,slv,tr_num);
scb=new(drv2scb_mbx,mon2scb_mbx,tr_num);
endfunction
task environment::run();
fork
gen.run();
agt.run();
drv.run();
mon.run();
scd.run();
join
endtask

5.transaction

class transaction;
rand bit [31:0] haddr;
rand bit [31:0] haddr_r;
rand bit hsel_r;
rand bit [1:0] htrans_r;
rand bit [1:0] hwrite_r;
rand bit [1:0] hsize_r;
rand bit [31:0] hwdata_r;
rand bit hsel;
rand bit [1:0] htrans;
rand bit [1:0] hsize;
rand bit hwrite;
rand bit hburst;
rand bit hwdata;
rand bit hrdata;
rand bit sram_w_en;
rand bit hready;
rand bit hready_resp;
rand bit sram_cs;
rand bit [3:0] sram_wen;
rand bit [31:0] sram_wdata;
rand bit [12:0] sram_addr_out;
rand bit [31:0] sram_data;
rand bit hresetn;
rand bit sram_read;
constraint c1{hsize inside{[2'b00:2'b10]};
htrans inside{[2'b00:2'b11]};
haddr inside{[32'h0:32'h0000_FFFF]};}
endclass

6.generator

class generator;
int tr_num;
transaction tr;
mailbox mbx=new();
event gen_data;//设置一个事件来表示一个场景执行完了,mailbox可以传递
  // 在类中extern函数,在类外实现,这种方式工程上的用的非常多
  extern function new(mailbox mbx,int tr_num); 
  extern function build(); 
  extern task write_data32(logic [31:0] addr, logic [31:0] wdata);     
  extern task read_data16(logic [31:0] addr);  
  extern task read_all_random(logic [31:0] addr);					//读32/16/8位数据,testcase告知addr
  extern task write_all_random(logic [31:0] addr);
  extern task no_op();            //无操作,空命令
  extern task run();			  //产生数据之后放到mailbox中去

endclass
function generator::new(mailbox mbx,int tr_num);
  this.mbx = mbx;       
  this.tr_num = tr_num; 
endfunction
function generator::build();        
  tr = new;                          //对象tr实例化,分配空间
  if(!tr.randomize())begin           //随机化transaction中的数据
    $display("@%0t ERROR::generator::build randomize failed",$time);
  end
endfunction

task generator::write_data32(logic [31:0] addr, logic [31:0] wdata); 
  tr = new;                 //对象tr实例化分配空间
  tr.haddr  = addr;         //testcase传入地址,对数据进行地址分配地址
  tr.hsel   = 1'b1;         //选中该slave
  tr.hwrite = 1'b1;         //1'b1:表示写数据传输模式
  tr.htrans = 2'b10;       
  tr.hsize  = 2'b10;        //2'b10:表示有效数据传输位为32bit
  tr.hburst = 2'b00;        //single操作,非连续传输(可省略),burst传输第一个传输类型为NONSEQ,其后为SEQ
  tr.hwdata = wdata;        //写入数据
  -> gen_data;     //触发事件,在后边run();的时刻,等待事件在收到触发时,就会把tr放入邮箱
endtask
task generator::read_data32(logic [31:0] addr);
  tr = new;
  tr.haddr  = addr;       
  tr.hsel   = 1'b1;         //选中该slave
  tr.hwrite = 1'b0;         //1'b0:表示读数据传输模式
  tr.htrans = 2'b10;        //2'b10:表示指示传输命令有效:NONSEQ
  tr.hsize  = 2'b10;        //2'b10:表示有效数据传输位为32bit
  -> gen_data;
endtask
task generator::no_op();            //无操作命令
  tr = new;
  if(!tr.randomize())begin  //随机化transaction包中的数据
    $display("@%0t ERROR::generator::no_op randomize failed",$time);
  end
  tr.hsel   = 'h0;         //未选中slave
  tr.htrans = 'h0;        //无效命令指示,  无效操作
  -> gen_data;
endtask

//前面产生激励的task,如果产生数据的话就会产生一个gen.data 的一个event去告诉run我已经产生data了,run就会等待,等待的次数为你发的命令的个数那么多次,每次发一个就会等待一下,如果等待你发一个包过来那么就把他放到邮箱里面去。
//就是根据给到的发包的个数循环那么多次,然后在上面的这些线程产生完一次数据之后就会把数据放到我的邮箱里面,等待我的另外一个组件去取。这个邮箱就是FIFO
task generator::run();        //前面产生激励的task,如果产生数据的话,便会同时触发事件gen_data,告诉run();
  repeat(tr_num)begin         //tr数据包已产生了数据,然后run会把数据包放入邮箱mbx,等待下一个组件去取。
     //等待gen_data,它是靠前面的gen_data来驱动的,前面不调用的话是不起作用的
     @(gen_data);             //testcase每发一个包命令,run()就等待tr产生数据,然后放入邮箱
     mbx.put(tr);             //这里的邮箱就相当于一个FIFO
  end
endtask

`endif


7.agent

class agent;
int tr_num;
mailbox gen2agt_mbx=new();
mailbox agt2drv_mbx=new();
transaction tr;
extern function new(mailbox gen2agt_mbx,agt2drv_mbx,int tr_num);
extern function build();
extern task run();
endclass
function agent::new(mailbox gen2agt_mbx,agt2drv_mbx,int tr_num);
 this.gen2agt_mbx=gen2agt_mbx;
 this.agt2drv_mbx=agt2drv_mbx;
 this.tr_num=tr_num;
 endfunction
 function agent::build();
 endfunction
 task agent::run();
 repeat(tr_num)begin
tr=new();
gen2agt_mbx.get(tr);
agt2drv_mbx.put(tr);
endtask

8.driver

class driver;
mailbox agt2drv_mbx=new();
mailbox drv2scb_mbx=new();
transaction tr;
transaction tr2;
virtual ahb_slv_if slv_if;
int tr_num;
int i;
int l;
logic [31:0] hwdata_ld;
logic[31:0] A[][];
logic pre_put;
logic [31:0] B[20];
extern function new(mailbox agt2drv_mbx,drv2scb_mbx,virtual ahb_slv_if slv_if,int tr_num);
extern function build();
extern task run();
enclass
function driver::new(mailbox agt2drv_mbx,drv2scb_mbx,virtual ahb_slv_if slv_if,int tr_num);
this.agt2drv_mbx=agt2drv_mbx;
this.drv2scb_mbx=drv2scb_mbx;
this.slv_if=slv_if;
this.tr_num=tr_num;
A=new[3*tr_num];
foreach(A[j])
A[j]=new[30];
endfunction
function driver::build();
endfunction
task driver::run();
@slv.drv_cb;
@slv.drv_cb;
pre_put=1'b0;//用于做打拍处理
for(int i=2;i<tr_num+3;)begin
tr=new();
tr2=new();
@slv.drv_cb;
drv_2scb_mbx.num();//查看邮箱里的状态是不是空
//只有当前信号的hready为1且hready_resp为1即前一个信号的操作完成了,才进行get新信号的操作,并将新的信号传给邮箱
if(slv_if.drv_cb.hready_resp&&slv_if.hready)begin
agt2drv_mbbx.get(tr);
i=i+1;
A[i][0]=tr.hsel;
A[i][1]=tr.haddr;
A[i][2]=tr.htrans;
A[i][3]=tr.hwrite;
A[i][4]=tr.hsize;
A[i][5]=tr.hwdata;
A[i][6]=slv_if.hready;
A[i][7]=slv_if.hresetn;
slv_if.drv_cd.hsel<=A[i][0];
slv_if.drv_cd.haddr<=A[i][1];
slv_if.drv_cd.htrans<=A[i][2];
slv_if.drv_cd.hwrite<=A[i][3];
slv_if.drv_cd.hsize<=A[i][4];
slv_if.drv_cd.hwdata<=A[i-1][5];
slv_if.drv_cd.hresetn<=A[i][7];

if(pre_put==1'b1)begin
pre_put=1'b0;
tr2.hsel<=B[0];
tr2.haddr<=B[1];
tr2.htrans<=B[2];
tr2.hwrite<=B[3];
tr2.hwdata<=B[5];
tr2.hsize<=B[4];
tr2.hrdata<=slv_if.hrdata;
drv2scb_mbx.put(tr2);
end
if(tr.hsel==1'b1&&tr.htrans[1]==1'b1)begin
pre_put=1'b1;
B[0]=tr.hsel;
B[1]=tr.haddr;
B[2]=tr.htrans;
B[3]=tr.hwrite;
B[4]=tr.hsize;
B[5]=tr.hwdata;
end
end
end
repeat(10)begin
@slv_if.drv_cb;
end
endtask

8.monitor

class monitor;
mailbox mon2scb_mbx=new();
transaction tr;
virtual ahb_slv_if slv_if;
int tr_num;
logic [31:0] A[][];
logic [31:0] B[20];
int j;
logic hready_resp;
logic pre_put;
extern function new(mailbox mon2scb_mbx,virtual ahb_slv_if slv_if,int tr_num);
extern function build();
extern task run();
endclass
function monitor::new(mailbox mon2scb_mbx,virtual ahb_slv_if slv_if,int tr_num);
this.mon2scb_mbx=mon2scb_mbx;
this.slv_if=slv_if;
this.tr_num=tr_num;
A=new[3*tr_num];
foreach(A[i])
A[i]=new[30];
endfunction
function monitor::build();
endfunction
task monitor::run();
#180//提高抓取速度,直接从180 秒后开始转因为在这之前信号无效,可根据自己情况设置;
pre_put=1'b0;
for(int j=0;j<=tr_num+3;)begin
tr=new();
@posedge slv_if.hclk;
if(slv_if.mon_cb.sram_w_en=1)begin//读写判断,此为读时
if(slv_if.mon_cb.sram_cs_m)begin//写信号有效(不需判断地址有没有效)
j=j+1;
tr.sram_addr_out<=slv_if.mon_cb.sram_addr_out;
tr.sram_wen<=slv_if.mon_cb.sram_w_en;
tr.sram_cs<=slv_if.mon_cb.sram_cs;
tr.sram_wdata<=slv_if.mon_cb.sram_wdata;
tr.sram_data<=slv_if.mon_cb.sram_data;
tr.sram_w_en<=slv_if.mon_cb.sram_w_en;
mon2scb_mbx.put(tr);
end
end
if(pre_put==1'b1)begin
pre_put=1'b0;
tr.sram_addr_out<=B[0];
tr.sram_wen<=B[1];
tr.sram_cs<=B[2];
tr.sram_wdata<B[3];
tr.sram_data<=slv_if.mon_cb.sram_data;
tr.sram_w_en<=B[5];
mon2scb_mbx.put(tr);
end
if(slv_if.moncb.sram_w_en==0)begin
 if(slv_if.moncb.sram_cs)begin
 j=j+1;
 pre_put=1'b1;
 B[0]=slv_if.mon_cb.sram_addr_out;
  B[1]=slv_if.mon_cb.sram_wen;
   B[2]=slv_if.mon_cb.sram_cs;
    B[3]=slv_if.mon_cb.sram_wdata;
     B[5]=slv_if.mon_cb.sram_w_en;
     end
     end
     end
     repeat(10) begin
     @slv_if.mon_cb;
     end
     endtask

9.scoreboard

class scoreboard;
int tr_num;
logic[31:0] D[][];
logic [31:0] M[][];
int i;
logic [3:0] sram_wen;
logic sram_cs;
mailbox drv2scb_mbx=new();
mailbox mon2scb_mbx=new();
transaction tr=new();
transaction tr2=new();
parameter ADD_WIDTH=16;
parameter SRAM_ADDR_WIDTH=ADDR_WIDTH-2;
parameter SRAM_DEPTH=1<(SRAM_ADDR_WIDTH);
logic [31:0] sram_gld[2][SRAM_DEPTH];
int err_cnt=0;
extern function new(mailbox drv2scb_mbx,mon2scb_mbx,int tr_num);
extern function build();
extern task check();
extern task run();
endclass
function scorboard::new(mailbox drv2scb_mbx,mon2scb_mbx,int tr_num);
this.drv2scb_mbx=drv2scb_mbx;
this.mon2scb_mbx=mon2scb_mbx;
this.tr_num=tr_num;
D=new[30*tr_num];
foreach 
D[j]=new[30];
M=new[30*tr_num];
foreach
M[l]=new[30];
endfunction
function scoreboard::build();
endfunction
task scoreboard::check();
for(int i=2;i<=tr_num+95;)begin
i=i+1;
#20
if(drv2scb_mbx.num()&&mon2scb_mbx.num())//判断两个邮箱是不是空
begin
drv2scb_mbx.get(tr2);
mon2scb_mbx.get(tr);
if(tr.sram_cs==1)begin
if(tr.hwrite==1)begin
if(tr.sram_wdata==tr2.sram_wdata)begin
display("@0t 1.AHB to sram data correct");
end
else begin
display("@0t 1.AHB to sram data error");err_cnt++;
end
end
if(tr.hwrite==0)begin
if(tr2.hrdata==tr.sram_data)begin
display("@0t 2. sram to AHB data correct");
end
else begin
display("@0t 2. sram to AHB data error");err_cnt++;
end
if(tr.sram_addr_out==tr2.haddr[14:2])begin
display("@0t 3. AHB addr  to sram——addr correct");
end
else begin
display("@0t 3. AHB addr  to sram——addr error");err_cnt++;
end
if(tr2.hwrite==1'b1)begin
 case(tr2.hsize[1:0])
 2'd0:begin
   case(tr2.haddr[1:0])
    2'd0:begin
     sram_wen=4'b0001;
     end
    2'd1:begin
    sram_wen=4'b0010;
    2'd2:begin
    sram_wen=4'b0100;
    default:begin
    sram_wen=4'b1000;
    end
    endcase
    end
    
    2'd1:begin
   case(tr2.haddr[1:0])
    2'd0:begin
     sram_wen=4'b0011;
     end
    2'd1:begin
    sram_wen=4'b0010;
    2'd2:begin
    sram_wen=4'b1100;
    default:begin
    sram_wen=4'b0000;
    end
    endcase
    end
    
    2'd2:begin
   case(tr2.haddr[1:0])
    2'd0:begin
     sram_wen=4'b1111;
     end
    2'd1:begin
    sram_wen=4'b0000;
    2'd2:begin
    sram_wen=4'b1111;
    default:begin
    sram_wen=4'b0000;
    end
    endcase
    end
   default:begin
   sram_wen=4'b0;
   end
   endcase
   end
   else if(tr.hwrite==1'b0)begin
   sram_wen=4'b0;
   end
   else sram_wen=sram_wen;
   if(sram_wen==tr.sram_wen) 
   display("@0t 4. AHB sram_wen correct");
   else begin
   display("@0t 4. AHB sram_wen error");err_cnt++;
   end
   end
   end
   end
   endtask
   task scorboard::run();
   check();
   if(err_cnt==0)begin
 display("*********************************")
 display("*********************************")
 display("************TEST PASS************")
 display("*********************************")
 display("*********************************")
 end
 else begin
 display("*********************************")
 display("*********************************")
 display("***TEST FAILED WITH %0d errors***",err_cnt);
 display("*********************************")
 display("*********************************")
end
endtask

三、脚本

1.shell脚本seed1.sh

作用就是定义种子选择执行的case,运行编译与仿真以及verdi , dve

#!/bin/bash
declare -i i j seed tc_um
seed=10
tc_num=10
make compile
make simulate TESTNAME=$tc_num SEED=$seed
make urg
make dve

2.makefile脚本Makefile


export DESIGN_PATH=/home/fsun/design10
VERDI  =/tool/synopsys/Verdi/N-2017.12-1
VERDI_TAB =${VERDI}/share/PLI/VCS/linux64/verdi.tab
VERDI_LIB=${VERDI}/share/PLI/VCS/linux64/pli.a
C_COMPILER="-cc gcc -ld g++ -CC"
export LD_LIBRARY_PATH=${VERDI}/share/PLI/VCS/LINUX64
TESTNAME?=SPI
SEED?=SPI
SOFT_CASE_NUM?=TX
DUMP?=ON
COV_OPT :=line+cond+tgl+fsm
ROOT=$(shell pwd)
rnd_seed=$(SEED)
tc_num=$(TESTNAME)
all:compile simulate
compile:
	vcs\
	-o vcs_sim_exe\
	-l vcs.com_log\
	+vcs+lic+wait\
	-debug_access\
	-Mupdate\
	+lint=TFIPC-L\
	-deraceclockdata\
	+vcsd\
	+vpi\
	-timescale=1ns/1ns\
	+define+VCS= \
	+define+FSDB_DUMP=\
	+define+SIMULLATION\
	+define+RTL_ONLY\
	-f ahb_slave.list//表示文件目录注意此处是放RTL以及testbench文件所在的目录
	+systemverilogext+.sv\
	-sverilog\
	+define+DUMP\
	+define+DEBUSSY\
	+memcbk\
	+warn=all\
	-full64\
	-P ${VERDI_TAB} ${VERDI_LIB}\
	-cm line+cond+fsm+tgl\
	../interface/inerface.sv\//放置环境其他组件的目录
	../env/generator.sv\
	../env/agent.sv\
	../env/driver.sv\
	../env/monitor.sv\
	../env/scoreboard.sv\
	../env/environment.sv\
	../testcase/ahb_sram_test.sv\

simulate:
	./vcs_sim_exe\
	+fsdb+all\
	+TESTNAME=${TESTNAME}\
	+SOFT_CASE_NUM=${SOFT_CASE_NUM}\
	+vcs+lic+wait\
	-assert verbose+errmsg\
	-assert nopostproc\
	+DUMP=$(DUMP)\
	+DUMP=ON\
	+DEBUSSY=1\
	-assert\
	-cm line+cond+fsm+tgl\
	-cm_name 2_$(TESTNAME)_${SOFT_CASE_NUM}\
	.sim -l sim_$(tc_num).log +plusargs_save\
	+ntb_random_seed=$(rnd_seed)\
	+tc_num=$(tc_num)\
	-l vcs_run.log\
dve_wave:
	dve -vpd vcdplus.vpd&
dve:
	dve -full64 -cov -dir merge.vdb &
log:
	sed '/^[^*].*/d' sim_$(tc_num).log>rslt.log
urg:
	urg -full64 -dir vcs_sim_exe.vdb -dbname merge -report both
open:
	gvim rslt.log
verdi:
	verdi\
	-sv\
	-f ahb_slave.lst\
	-ssf ./waves1.fsdb &
clean:
	rm -rf work mti_lib transcript modelsim.ini *.log *.wlf test.ucdb merge.vdb
//.list
//rtl目录
$DESIGN_PATH/ahb_slave/rtl/ahb_slave.v
//TBtestbench目录
+incdir+$DESIGN_PATH/ahb_slave/tb
$DESIGN_PATH/ahb_slave/tb/ahb_sramc_svtb_top.sv

3.lint检查语法问题

每次写完RTL代码后都要进行RTL代码的语法检查,这里使用spyglass进行简单的语法检查
lint主要需要三个文件:
1.lint.csh:

#!/bin/csh
rm -rf UWB_MAC_TOP*
sg_shell -64bit -tcl lint.tcl |tee lint.log

2.lint.tcl:

new_project s_t_c//工程名
read_file -type sourcelist /home/desgin/rtl_list.f//放置需要测试rtl所在路径的文件一般可以命名为模块名称.f
current_goal Design_Read -alltop
set_option top s_to_c//放置rtl模块名注意是module名不是文件名
set_option enableSV yes
link_design -force
current_goal lint/lint_rtl -top s_to_c//这里最好也是模块名称
run_goal
exit -save

3.RTL所在路径的包含文件 .f文件
/home/fsun/design/rtl/signle_to_convert.v

总结

设计流程是这样:写核心程序—lint语法检查—写验证环境-----定向用例–写脚本----随机用例
全文流程是这样:运行脚本seed1.sh调用Makefile,Makefile脚本将赋值在seed中的种子,传输数据数量以及调用的testcase传达到dut与test链接的top中,进而调用testcase,testcase调用generator和transaction生成数据包并且传给agent,agent传给driver,driver判断有效后传给scorebored且加入时序信息后传给DUT,monitor从DUT中抓取出sram侧信号传给scorebored两者进行对比,通过Verdi看波形,通过输出看比对,比对通过后,通过urgent以及dve看覆盖率
提示:这里对文章进行总结:

例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

北极光sdu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值