目录
3.1 default sequence无法使seq中的starting_phase赋值
一、AHB_SRAMC介绍
本项目为E课网所提供的基于AHB总线的SRAM控制器,sram大小为64K单端口存储。本项目中的AHB_SRAMC作用就是实现SRAM存储器与AHB总线的数据信息交换。其功能列表为:
- 支持低功耗
- 支持单周期读写
- 能够根据AHB总线的读写宽度进行相应的SRAM位宽选择
- 能够支持DFT/BIST测试
如上图所示为设计模块的具体框图,最外层的框图为sramc_top.v 模块,它包括了ahb_slave_if.v、sramc.v 、sram_core.v,其中sram_core.v 里面有sram_core 和BIST 模块。
- ahb_slave_if.v:给SRAM 控制器模块提供控制、数据信号、SRAM 片选地址的产生。
- sram_core.v:该模块包括两个部分,一个是sram 核,用来存放数据;另一个是BIST模块,将其与SRAM 核放在一个模块中,实现SRAM 功能的自测。
外部的访问请求,将会通过ahb总线传输到ahb_slave_if.v中进行转换处理,转换处理过的控制信号如图所示的sram_wen以及sram_ren以及数据信号将会传输到sram模块进行满足sram时序的实际的数据存取操作。
1.1 结构框图以及信号介绍
1.1.1 AHB slave interface 模块
AHB slave interface 模块:如图所示为SRAM 控制器的AHB slave interface,其产生读写控制信号(sram_r_en、sram_w_en)和SRAM 控制器片选所需的输入信号(bank0_csn、bank1_csn)。包括:AHB 输入控制信号和地址信号寄存模块、SRAM读写和片选产生模块、SRAM 输出数据接收模块。
1.1.2 SRAM 控制器顶层模块
该模块包括两个部分,一个是sram 核,用来存放数据;另一个是BIST模块,将其与SRAM 核放在一个模块中,实现SRAM 功能的自测。
ahb_slave_if.v 用来生成SRAM 的读写控制信号和片选所需的信号。该模块输出将haddr、hsize 寄存了一拍输出成haddr_reg、hsize_reg。同时还需要对hwrite信号进行特别处理(为了满足单周期读写,可以见下面的SRAM 读写时序),一方面,当写有效时,寄存一拍输出,信号为sram_wen,另一方面,当读有效时,模块内部要进行处理下,hwrite 进行逻辑组合输出,信号为sram_ren。本模块的读写数据无需进行寄存,其中haddr[15]用来生成SRAM 的bank 选择和byte/halfword/word的数据读写操作选择。通过AHB 接口过来的片选信号和地址总线的逻辑运算产生SRAM_CSn 的片选值。SRAM_CSn 片选SRAM 块示意框图如图 所示:
对SRAM 的byte/halfword/word 读写操作,如下表2所示:通过AHB 总线的传输方式
HSIZE 和地址总线的低2 位的逻辑运算产生AHB-SRAM 数据位宽选择值
在选定某个bank 后,当确定数据是以byte/halfword/word 中一种读写方式操作时,通过sram_csn 片选使能选定比如高16 位进行读写,或者低8 位、或者一个word(整行)的读写操作的SRAM 块。
其中具体片选代码逻辑如下:
/*当片选信号为1时,选中bank0;当片选信号为0时,选中bank1*/
assign sram_data_out = (bank_sel) ? {sram_q3, sram_q2, sram_q1, sram_q0} :
{sram_q7, sram_q6, sram_q5, sram_q4} ;
/*这一部分片选操作时,低32K空间选择bank0,在高32K空间选择bank1*/
assign bank_sel = (sram_csn_en && (sram_addr[15] == 1'b0)) ? 1'b1 : 1'b0;
assign bank0_csn= (sram_csn_en && (sram_addr[15] == 1'b0)) ? sram_csn : 4'b1111;
assign bank1_csn= (sram_csn_en && (sram_addr[15] == 1'b1)) ? sram_csn : 4'b1111;
/*数据从AHB总线写入SRAM */
assign sram_wdata = hwdata;
/*每个bank有4片SRAM,每一片SRAM有一个片选信号 */
always@(hsize_sel or haddr_sel)
begin
if(hsize_sel == 2'b10)
sram_csn = 4'b0;
/*一次片选两片SRAM */
else if(hsize_sel == 2'b01)
begin
if(haddr_sel[1] == 1'b0)
sram_csn = 4'b1100;
else
sram_csn = 4'b0011;
end
/*选择一片SRAM,具体到4片中的某一片*/
else if(hsize_sel == 2'b00)
begin
case(haddr_sel)
2'b00 : sram_csn = 4'b1110;
2'b01 : sram_csn = 4'b1101;
2'b10 : sram_csn = 4'b1011;
2'b11 : sram_csn = 4'b0111;
default : sram_csn = 4'b1111;
endcase
end
else
sram_csn = 4'b1111;
end
代码懒得手打,参考:AHB—SRAMC项目(结构图,核心代码、Testbench架构)-CSDN博客包括ahb_sramc结构在这篇文章也讲的很好。
1.1.3 读写时序
读写时序是构建验证环境的关键,其中ahb_sramc的读写时序如下图:
其中ahb时序不做详细介绍,sram写数据时序与ahb有所不同
ahb读时序:
- 第一拍给出读写控制以及地址信号;
- 当没有HREADY反压的时候,第二拍得到读数据信号;
- 当有HREADY反压的时候,第2拍以后的某一拍HREADY为高的时候,说明此时HRDATA有效,得到读数据信号;
ahb写时序:
- 第一拍给出读写控制以及地址信号;
- 第二拍给出写数据信号;
sram读时序:
- SRAMCS是片选信号,chip select,只有为高的时候SRAM才会真正的工作;
- 第一拍给出读写控制,地址信号;
- 第二拍给出读数据信号;(不考虑反压和错误的情况下,和AHB一模一样)
二、基于uvm的AHB_SRAMC验证环境框图
验证环境框图如图所示:
具体验证思想为将发送的激励数据包分为读写类型,先写后读,写的transaction经过参考模型后根据hsize以及haddr设定的数据宽度截取hwdata固定位数,形成期望的hrdata值,通过与monitor检测到的实际hrdata值进行对比,判断是否正确写入sram数据以及读取sram数据。
2.1 搭建基本验证环境
验证环境拓扑结构图如下所示:
2.1.1 sramc_tb_top
top中主要做了:
- 例化DUT以及接口
- 创建clk以及reset信号激励
- config_db set将interface传到下面组件
关键代码如下:
2.1.2 sramc_interface
最基本的验证环境需要实现clk reset,创建接口信号,关键代码如下:
2.1.3 transaction
transaction为激励包类型,规定了工厂注册的用于对比的数据
2.1.4 sequence
sequence规定了发包类型以及次数等,共写了4个seq分别对应byte halfword word 以及wordbank选择的各种情形进行验证:
其中以haifword举例其核心代码:
2.1.5 sequencer
sqr中未进行特殊操作,省略不写
2.1.6 sramc_driver
sramc_driver中主要功能为:
- 满足时序给dut激励
- 对dut内部信号进行复位
- 将收到的包传给reference model得到期望值
具体核心代码如下:
2.1.7 sramc_monitor
sramc_monitor功能为:
- 监测dut输出,得出读出的实际值,传送给scoreboard与期望值进行比较
核心代码如下:
红色框部分为对采集到的hrdata进行处理得到实际从sram读出的值(sramc可以定义数据宽度为8 16 32)
2.1.8 sramc_agent
agent依据传入is_active参数不同分别例化了drv mon以及sqr,并将mon以及drv中的port连接到agt_port上
关键代码如图:
2.1.9 sramc_model
reference model负责生成期望值,收到write的数据包时将该地址对应的mem值更新为应该存入sram的期望值,用于比较
核心代码如下:
2.1.10 sramc_scoreboard
scoreboard将收到的期望值与实际值进行比较,输出比较结果
核心代码:
2.1.11 sramc_env
env中主要例化各种组件,将各种port进行连接
核心代码:
2.1.12 makefile
2.2 仿真结果分析
至此验证环境基本搭建完成,还是以wr_halfword_test为例,仿真示意图以及scb对比结果如图所示
可以看出在读写时序均满足ahb协议,在0地址写入数据6387ba84,由于选择是halfword模式,且地址haddr[15] 为0因此选择bank0,且haddr[1]为0选择sramq0与sramq1进行存储16位数字ba84,因此存入sram的是hwdata后16位,当读取时hrdata为69f9ba84,此时低16位有效,读出有效数据为ba84,sram数据存取正常。
部分scb对比结果如图所示。
覆盖点设置以及覆盖率收集如下图:
写完vplan之后进行查看,代码覆盖率太低了,功能覆盖率100%
三、问题总结
3.1 default sequence无法使seq中的starting_phase赋值
在设置seq启动方式时使用了default_sequence的启动方式,仿真时发现无法正常raise_objection
原因为:在uvm1.1中采用default_sequence中会自动给starting_phase进行赋值,但是uvm1.2不建议使用default_sequence,不会给starting_phase进行赋值。所以在uvm1.2中,即使使用了default_sequence,sequence中starting_phase仍然为null
解决办法:将uvm1.2改为1.1
3.2 clk设置频率过快导致时序出错
发现此时地址周期后,两个clk才能读到hrdata值,与时序不符,出现问题
原因为:clk频率过快,在dut中设置了延迟#2 hrdata = sram_data_out,当clk小于2时,延迟将会大于一个时钟周期,导致时序出现问题。
3.3 最后一个seq没有执行完成便结束
发现此时最后一个读命令还没有执行完毕就finish了仿真,导致提前结束
原因为: 发送最后一个读命令包时虽然包已经发送,但是dut需要一定时间响应才能读出数据,因此应该在最后一笔延时一段时间
3.4 读数据出现不明原因的x态
原因为:hrdata为延时#2的sram_data_out,而sram_data_out依据bank_sel进行选择,而bank_sel在hclk时钟时钟上升沿进行跳变,因此sram_data_out在上升沿进行变化,而sram_q0-7在sram_clk的上升沿变化,即hclk的下降沿变化,因此在sram_data_out在上升沿采样数据时无法及时采到变化后的sram_q0-7的值
修改办法为,将sram_data_out的采样时间延迟到hclk的下降沿,这样采样就保持同步了
3.5 scb对比出现错误
期望值更新为0,显然是有问题的。
原因为:mem大小设置不够大,因为地址haddr为32位,当bank选择为bank1时,此时haddr过大超过mem边界没有更新上期望值所以为0
解决办法为:联想到此时虽然范围巨大,但实际存储数据较少,符合关联数组应用场景,使用关联数组进行期望值存储