1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > AHB-SRAM

AHB-SRAM

时间:2021-08-12 04:36:01

相关推荐

AHB-SRAM

0.代码理解

DUT

AHB总线传输数据位宽有8/16/32(HSIZE[3:0]:000-8bits,001-16bits,010-32bits),而ram不一定支持(这里每个ram支持数据位宽为8位),所以用了4块ram,每块ram对应一个byte。当AHB传来8bit数据时,可以选择四个ram中的任何一个进行存放;传来16bit数据时,可以选择BRAM0/1或者BRAM2/3这两种组合进行存放;传来32bit时,BRAM0~3依次存放第1-4byte。增加一个输入信号HSELBRAM——该信号控制使能ram块。存储器写入控制信号reg_wr_en[3:0]由下一次写入使能信号nxt_wr_en[3:0]赋值得到,决定要将数据写进哪个ram中。

VIP_lib

配置类

lvc_ahb_agent_configuration.sv和lvc_ahb_configuration.sv

agent配置类中有一个1bit变量is_active,其控制着master_agent中,drv的port与sqr的export的连接,以及向它俩传递vif。

变量定义类

lvc_ahb_defines.svh

定义AHB传输data的最大宽度64bit,addr最大宽度32位。

ahb类型类

lvc_ahb_types.sv

规定AHB信号所对应的二进制码。 Slave发给Master的4个传输状态: OKEY:传输正常。ERROR:传输错误。RETRY:传输未完成,请求Master重新开始下一个传输,arbiter会继续使用通常的优先级。SPLIT:传输未完成,请求Master分离一次传输,arbiter会调整优先级方案,以便其他请求总线的主设备可以访问总线。 当前4种传输类型: IDLE:主设备占用总线,但没进行传输。BUSY:主设备占用总线,但是Master在burst传输过程中还没有准备好进行下一次传输,先暂停一下。NSEQ:表示一次单个数据的传输或者一次burst传输的第一个数据。SEQ :burst传输接下来的数据。 每一个transfer传输的数据大小: BURST_SIZE(8~1024)但实际只能用到8/16/32 Burst传输类型: 单个传输数据传输、任意长度的数据传输、打包4/8/16拍传输,四个地址是一个回环范围、4/8/16拍传输,地址是增加的。 传输操作类型:读、写、空闲。传输状态类型: INITIAL:表示该标志的默认状态。一旦节拍级传输开始,它就会被更新。PARTIAL_ACCEPT:一旦每个节拍的地址被从机接受,状态就会从INITIAL变为PARTIAL_ACCEPT。ACCEPT:一旦节拍级数据被从机接受,状态就会变为ACCEPT。ABORTED:如果交易因Slave的ERROR/SPLIT或RETRY响应而被中止,或者在EBT的情况下,状态变为ABORT。 规定一个限制每一次transfer数据大小的函数extract_valid_data,因为Slave(RAM)只能处理8/16/32bit的数据(变量定义类中:定义AHB传输data的最大宽度64bit)。 ✅ ​case语句对参数bsize(单个数据大小)判断: 8bit:data右移0/8/16/24位,然后和8’hFF按位与。——分别对应存放进4个不同的ram块中。16bit:data右移0/16位,然后和16’hFF按位与。——分别对应存放低两个ram块或高两个ram块。32bit:和32’hFFFF按位与。其它位就报错。

ahb接口类

lvc_ahb_if.sv

定义三个clocking_block:cb_mst、cb_slv、cb_mon

激励和组件类

先定义顶层的trans、drv、mon、sqr类。然后apb_master的trans、drv、mon、sqr类再继承与它们,apb_master的trans、mon、sqr类都没内容,主要是apb_master_drv。

lvc_ahb_transaction.sv

定义了各个信号的默认值:burst_size为8bit,即每一拍中的一个数据为8bit;burst_type为单个传输…并将这些变量添加到域的自动化。定义一个increase_data函数,每次调用,data会新建一个比以上一个data长度多1的新动态数组,并把上一个data的值传进来,动态数组all_beat_response也是。也就是data动态数组中会包含一次burst中的所有数据,且all_beat_response动态数组也包含了在该次burst中slave返回给master的传输状态。

lvc_ahb_base_sequence.sv没内容

lvc_ahb_master_single_trans继承于lvc_ahb_base_sequence

约束了传输操作类型只有读和写,没有idle。body函数中,为req规定默认约束,然后调用get_response任务来检索响应,是阻塞的。✅如果是读操作,那么将rsp中data的[0]赋给data(这里是因为drv中将hrdata放进的data的[0]),然后打印req中的成员变量。

lvc_ahb_sequencer.sv没内容

lvc_ahb_driver.sv

声明agent配置类对象和ahb虚接口。run_phase中fork_join_none两个任务:get_and_drive、reset_listener get_and_drive任务:port端口get seq产生的req,然后打印“我拿到item”,再调用drive_transfer任务(由其子类中定义)将req发送出去(通过接口给dut),然后req调用系统克隆函数,并转化子类句柄并赋给rsp,分别获取req的seq_id、trans_id并交给rsp(发送的单个数据id、数据包的id),然后将rsq消化掉。reset_listener任务:由子类定义内容(就是复位所有信号)。

lvc_ahb_monitor.sv

声明agent配置类对象和ahb虚接口和广播端口ap(与rkv_ahbram_subscriber相连)。run_phase中fork_join_none一个任务:monitor_transactions monitor_transactions任务中先声明了ahb_transaction类型对象t,又无限循环collect_transfer任务和将t写进广播端口(收集来自dut-aph的trans并广播发送出去): collect_transfer任务:创建对象t实例,等待接口上ck_mon时钟块信号htrans(传输类型:nonseq/seq/idle/busy)为NSEQ,即burst传输的第一个数据或单个传输,便对该时钟块将dut-aph的信号(是burst传输的信息变量)采样。再无限循环monitor_valid_data任务(),遇到idle便打破该循环。 monitor_valid_data(检测有效数据)任务:等待接口上ck_mon时钟块信号hready信号为1,便对该时钟块将dut-aph的信号采样,t调用lvc_ahb_transaction中的increase_data函数(将每次burst的data和slave返回的状态保存到动态数组);并用int类型变量current_data_beat_num来存储当前data的个数;条件语句判断是读指令还是写指令,分别将hwdata/hrdata采集进动态数组data的对应位置,将采集到的hresp放进动态数组all_beat_response的对应位置。

lvc_ahb_master_driver.sv

drive_transfer任务不支持burst传输,仅支持单个数据传输。 单个数据传输——分为初始读或写、受保护的读或写四种读写方式。(这里读写都是相对于ahb来说的,drv都是将信号驱动给ahb)初始的读或写——要先等待bus的grant,即要等接口上cb_mst时钟块的hgrant信号=1,dut的master准备好了,才能开始对它的读和写。 写操作——就将t中各个变量驱动到接口,然后下一时钟块发送一个idle,然后将data驱动到dut。然后在clk下降沿检查hready是否=1,=1就继续走,不等1就一直在循环中,数据也不会写给slave。然后发送一个data后,将传输类型更新为NESQ,current_data_beat_num更新为0,hresp更新进all_beat_response数组中。读操作——前边和写操作一样,不同之处是要将t.data依次放在除[0]位的高位上,然后这次的hrdata放进t.data[0]。

lvc_ahb_master_agent.sv

将mst_drv/mon/sqr和agent_cfg封装。

seq_lib

rkv_ahbram_base_element_sequence.sv

内有一个简单的compare_data函数,进行读写数据的对比,并且每次会计数+1。

rkv_ahbram_single_read_seq.svrkv_ahbram_single_read_seq.sv

继承于rkv_ahbram_base_element_sequence类。将lvc_ahb_master_single_trans类型seq的对象实例挂载到p_sequencer.ahb_mst_sqr,并约束xact为读或写。

rkv_ahbram_base_virtual_sequence.sv

例化了single读和写seq。定义了四个task:等待复位信号的上升沿task、等待复位信号的下升沿task,等待n个时钟cycle的task(n为输入参数)、wait_ready_for_stim任务中调用:等待复位信号的下升沿task和n=10的等待n个时钟cycle的task。其他seq都继承于rkv_ahbram_base_virtual_sequence。

rkv_ahbram_smoke_virt_seq.sv

冒烟测试:当测试平台搭建好后,首先进行一个很基础、很简单的测试,确保测试平台可以正常运转。产生10个数据,addr[1:0]约束为0,因为lvc_ahb_transaction中规定默认data为8bits,所以这里约束8bit的数据要存放在SRAM0,即靠低位按字对齐存放。然后将读出的数据和写入的数据通过compare_data函数作比较。

rkv_ahbram_diff_haddr_virt_seq.sv

不同HADDR的对齐读写测试:发送数据个数由rkv_ahbram_config.sv中的32bit变量addr_end控制。且地址addr的随机范围也在[addr_start: addr_end]之间。

rkv_ahbram_diff_hsize_virt_seq.sv

不同HSIZE的对齐读写测试:相较于前两个测试都是传输8bits的数据,该测试增加对bsize的随机(8/16/32)然后产生100个数据。与前两个测试seq区别:在进行数据比较时,根据不同位(8/16)的数据,分别和32’hFF/32’hFFFF按位&之后再比较。是要保证读写数据是按低按字对齐的。

rkv_ahbram_haddr_word_unaligned_virt_seq.sv

不同HSIZE的非对齐读写测试:相较于之前对其测试(用约束addr[1:0]为0,来限制数据对齐读写),该测试没有约束addr[1:0]为0。所以当数据为8bits时,可存放在SRAM0/1/2/3中任意一块。且约束当bsize为16时,addr[0] == 0,即16位的数据可存放在SRAM0/1或SRAM2/3中。

rkv_ahbram_reset_w2r_virt_seq.sv

复位前后的读写功能测试:复位前,进行十次正常的读写操作,并将十个数据的地址写到一个队列addr_q[$]里,后边复位后再拿出来用,正常这些相应地址应该没有数据了,读出来的是32’hx。然后通过rkv_ahbram_if接口中定义的复位任务去复位AHB,停止向ram中读写。之后do_while循环(先开始循环,等while后条件不满足后退出循环,即存放地址的队列中addr拿完后退出),对之前的写入地址还是再次进行读操作,然后和32’hx进行对比。

cfg

env

rkv_ahbram_subscriber.sv

rkv_ahbram_scoreboard和rkv_ahbram_cov继承于rkv_ahbram_subscriber。定义uvm_analysis_imp与lvc_ahb_monitor相连,接收来自mon的数据,imp通过port调用write函数来接收数据(t)预留了两个任务:do_events_trigger()、do_listen_events()。

rkv_ahbram_scoreboard.sv

继承于订阅者,其内置的write函数覆盖了父类中write函数,并通过is_addr_valid函数判断tr.addr是否有效(地址范围要在rkv_ahbram_cfg中规定的两个变量addr_start、addr_end之间),addr有效的话再判断tr.xact_type是读还是写操作。写操作——调用store_data_with_hburst函数: 先判断tr.burst_type,是SINGLE的话就执行store_data_with_hsize函数,其他传输类型就报错(暂不支持)。 store_data_with_hsize函数中,根据数据size,再通过extract_current_beat_mem_data函数,将数据拿出来,再赋给scoreboard中定义的mem的相应地址位(按低位、按字节对齐存放)。 extract_current_beat_mem_data函数中,将data[0]的数据拿出来,赋值给mdata的对应字节位。 读操作——调用check_data_with_hburst函数: 先判断tr.burst_type,是SINGLE的话就执行check_data_with_hsize函数,其他传输类型就报错(暂不支持)。 check_data_with_hsize函数,将写进去的mdata和读出来的tdata进行对比。

rkv_ahbram_cov.sv

继承于订阅者,定义了两个覆盖组T1和T2,前者采集地址覆盖率,后者采集传输类型(SINGLE、INCR、WRAP4、INCR4)和SIZE覆盖率。t1的ADDR覆盖点,对addr整个进行采样,定义了19个bin,各个bin取值范围分别是起始、终止、超出范围、和合法范围。BYTEACC覆盖点,对addr[1:0]进行采样。t2的BURST_TYPE覆盖点和BURST_SIZE覆盖点,分别定义4个bin对传输类型和size进行采样。

rkv_ahbram_env.sv

build_phase中,通过config_db将rkv_ahbram_config和lvc_ahb_agent_configuration的实例对象,分别set进virt_sqr、cov、scb和anb_mst。connect_phase中,及那个ahb_mst_sqr赋给virt_sqr中的ahb_mst_sqr;寄存器模型的map和adapter连接并挂到ahb_mst.sequencer上,并把rgm.map和adapter赋给predictor;ahb_mst.mon的广播端口item_observed_port与predictor、cov、scb相连(当ahb_mst.monitor一旦捕捉到有效trans,就会发送给predictor,然后predictor将trans交给adapter进行转换,转换后的寄存器模型有关信息更新到map中)。

test

rkv_ahbram_base_test.sv

将起始和终止地址数值配置成:

cfg.addr_start = 32'h0;cfg.addr_end = 32'h0000_FFFF;

tb

rkv_ahbram_if.sv

该接口中定义一个控制复位的任务,形式参数nclks:控制等待nclks个时钟上升沿后拉低复位信号。然后再等5个时钟上升沿后将其拉高。

rkv_ahbram_tb.sv

这里定义了两个接口,lvc_ahb_if和rkv_ahbram_if。前者是TB与DUT之间正常通信的接口,后者是专门为了测试复位后写和读功能的一个接口。后者是TB与DUT的顶层的接口,前者是TB与AHB的接口。

1.AHB VIP及TB框架的实现

VCS有自带的模板生成工具:UVM Template Generator (UVM)User Guideterminal中输入指令,使用模板生成工具:uvmgenlvc——列正verification component,就是列正自动化平台的组件(模板自动生成的组件)。条件编译选项:“idndef defin ifdef enif” ifndef 的含义:即 “if not defined”,也就是说,当文件编译到这一行,如果这个文件还没有被编译过,也就是首次编译,就会执行后续的 `define xxx这句话,把后续的代码定义一次。反之,则不会再重复编译。ifdef 的含义:即"if defined",与 ifndef 的作用相反,如果已经编译过,那么则继续执行后面的代码。enif 的含义:出现 ifndef 或者 ifdef 作为开头,程序块的末尾就需要有 endif 作为结束的标识。 lvc_ahb_master_sequencer和lvc_ahb_slave_sequencer中间会有公共相同的部分,那么把公共的部分抽取到一个lvc_ahb_sequencer,作为父类。文件夹列表: cfg cov env seq_lib sim tb test vip_lb

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。
相关阅读