之前面试的时候把项目里大致的结构和scoreboard里的代码整理了出来,这样每次面试前不用再返回去看源码,花一点时间看下这个简略版就OK了,agent中有关driver和monitor的写法的话主要还是根据spec来,只要通信协议记得,即使代码忘了大概的思路也能说出来。
AHB to APB bridge
- 模块作用:AHB to APB bridge同步桥用来实现AHB端和APB端的数据的转换。
- 环境组成:
env:包含了两个vip以及scb,在connect_phase中将两个agent的monitor中的port连接到scb的tlm_fifo的export中。
fuv_cov:对ahb侧的haddr、hwrite、hburst、hsize进行采样,在对地址进行采样的时候将边界地址单独列出来。
scb:定义了两个tlm_analysis_fifo以及port,再将其相连,将ahb及apb的trans分别填充到两个port中。数据的比对:AHB-PKT的地址与APB-PKT的地址、AHB-PKT的wrdata与APB-PKT的data、hwrite与APB-PKT读写信号的对比、AHB-PKT的hprot与APB-PKT的prot信号的对比、AHB-PKT的hrsp与APB-PKT的slverr的对比、AHB-PKT的hwrite信号拉高分别进行byte、Hword、word的写操作时,更新了apb侧的哪个字节通道(pstrb信号)。
-
apb_sequence:slv_rdy(约束中slverr=0,nready_num=0)
slv_nrdy(约束中slverr=0,nready_num inside{[1:5]})
slv_slverr(约束中slverr=1,nready_num inside{[1:5]}) -
ahb_sequence:burst(hsel == 1’b1)
single_write32(hsel == 1’b1;htrans == ahbl_mst_pkg::NSEQ; hsize == ahbl_mst_pkg::WORD; hburst == ahbl_mst_pkg::SINGLE;hwrite == 1’b1)
single_read32(hsel == 1’b1; htrans == ahbl_mst_pkg::NSEQ; hsize == ahbl_mst_pkg::WORD; hburst == ahbl_mst_pkg::SINGLE; hwrite == 1’b0) -
testcase:
base_test:在test层中例化env。
single_read32:组合ahb_single_read32与apb_slv_rdy两个seq。
single_write32_slv_nrdy:组合ahb_single_write32与apb_slv_nrdy两个seq。
burst:先启动ahb_burst,然后再启动apb_slv_nrdy,再通过num_apb_seq计算启动的apb的seq的个数,当num_apb_seq大于ahb的
get_bst_beats()获得的bst_beats个数时再退出。
关于bst_beats:
burst_slverr:类似上个case,只不过加入了apb的slverr。
tight_transfer:两个ahb_mst和一个apb_slv进行burst操作。
- 两个vip:
APB-agent:
trans:对addr、data、prot、strb、slverr、nready_num等信号进行注册。
monitor:把在interface上监测到的信号转换到pkt中,再写进analysis_port中。
driver:apb作为slv时,wdata与waddr是input,rdata与raddr是output。
写操作时,将wdata与waddr从interface上读出写进apb的mem中,读操作时,将rdata与raddr从mem中取出驱动到interface上。
AHB-agent:ahb作为mst,hwdata和hwaddr是output,hrdata和hraddr是input。
trans:对相应的信号做相对应的约束。
monitor:分别在data_phase和address_phase中将interface上监测到的信号转换到pkt中,再写进analysis_port中。
driver:分别在data_phase和address_phase中将pkt里的数据通过interface驱动到DUT上。
APB - UART
- 模块作用:APB-UART模块可以实现串行数据和并行数据的转换,发送和接收逻辑分别用FIFO来存储数据,CPU可以通过APB总线访问该模块,进而间接的实现对UART串行数据的访问。
在进行数据发送操作时,需要发送的数据通过APB总线被写入到该模块后,会暂时存储在Transmit FIFO中,发送逻辑模块会在特定的时刻从Transmit FIFO中取走数据,并添上起始位、奇偶校验位以及停止位,形成一个完整的数据帧。最后发送逻辑会将该数据帧放入到发送端口另一端的移位寄存器中,按照特定的波特率将数据串行移位,实现数据发送的功能。
在进行数据接收操作时,串行数据通过接收端口后会进入到接收逻辑模块,该模块对数据进行格式检测后,会将其中的起始位、校验位以及停止位移除,并把剩下的数据暂时存储在Receive FIFO中,等待CPU访问。 - 环境组成:
env:在其中例化apb_agent和uart_agent,以及virtual sequencer和scb。
将agent中monitor的port连接到scb的export。
set两个agent的sequencer的句柄。
virtual sequencer:get两个agent的sequencer的句柄。
scb:在scb的中,创建了三个不同的函数来对数据进行比较。
Compare_config():此函数在configuration register上有读取操作时调用,将来自apb_monitor的值与配置了configuration后的scoreboard进行比较,这里的配置主要指uart_config中的波特率、帧长、奇偶校验以及停止位这几个参数。
(apb_pkt.PRDATA与baud_rate_reg、frame_len_reg、parity_config_reg、stop_bits_config_reg的比对)
Compare_transmission():此函数在DUT上有传输操作时调用,将apb_driver写入到DUT上的PWDATA与uart_monitor在DUT的TX_pin上监测到的数据进行比较。
(apb_pkt.PWDATA与uart_pkt.transmitter_reg的比对)
Compare_receive():在有接受操作时,此函数被调用,将uart_driver提供给RX_pin的数据与apb_monitor从DUT接收到的PRDATA进行比较。此外该函数还比较了错误信号,因为我们有向DUT提供错误数据的机制。
(apb_pkt.PRDATA与uart_pkt.payload的比对)
run_phase():
1.if(apb_pkt_mon.PWRITE==1&&(apb_pkt_mon.PADDR == cfg.baud_config_addr || apb_pkt_mon.PADDR == cfg.frame_config_addr || apb_pkt_mon.PADDR == cfg.parity_config_addr||apb_pkt_mon.PADDR == cfg.stop_bits_config_addr))
则对scoreboard进行配置。(4个reg为在scb中配置的寄存器)
2.elseif(apb_pkt_mon.PWRITE== 0&&(apb_pkt_mon.PADDR== cfg.baud_config_addr||apb_pkt_mon.PADDR== cfg.frame_config_addr||apb_pkt_mon.PADDR == cfg.parity_config_addr||apb_pkt_mon.PADDR == cfg.stop_bits_config_addr))
则调用compare_config函数。
3. else if(apb_pkt_mon.PADDR==cfg.trans_data_addr)
则
4.else if(apb_pkt_mon.PADDR==cfg.receive_data_addr)
则
-
assertion(property):
1.在setup_state中,PSELx应该是HIGH,PENABLE应该是LOW,set_up可以通过检测PSELx的上升沿来确定。
2.access_state发生在setup_state后的一个循环之后,所以PENABLE应该在PSELx拉高的下一个周期拉高。
3.在setup_state中,PWRITE和PADDR不应该是未知的。
4.在setup_state中,写操作期间PWDATA的值不应该是未知的。
5.在access_state中,PWRITE和PADDR的值不应该更改。
6.PWDATA在整个写周期中应该保持不变。
7.在读操作中,PRDATA的值在断言PREADY时不应该是未知的。
8.对于多个读/写操作,PSELx不一定要去断言,但在所有事务完成之前,其仍然保持HIGH。所以我们必须检查每次PENABLE拉高时,PSELx应该在一个cycle之前断言。 -
tb:DUT和assertion的接口端口。
Set agent的interface句柄。 -
测试计划:
1.通过在配置寄存器中存储特定的值来设置config。配置元素如下:波特率,帧大小,奇偶校验,停止位,可以通过使用APB接口提供的PADDR变量来访问它们的特定配置地址。
2.首先通过运行config sequence将配置设置写入DUT,然后将一些数据写入PWDATA端口,并通过TX-pin串行(逐位)读取数据。输出应该是相同的。加载在PWDATA上的数据应该在TX-pin上串行接收。
3.在RX引脚上逐位加载数据,然后在preready时从PRDATA端口读取数据。同样,我们可以先运行随机配置设置,然后根据相应的配置设置运行此测试。
4.发送一个帧,其中包含损坏的停止位。DUT应响应输出PSLVERR位拉高。设置DUT为random config,然后运行此测试。
5.发送包含损坏的奇偶校验位的帧。DUT应响应PSLVERR为高。设置DUT为random config,然后运行此测试。
6.设置random config,随机奇偶校验错误和帧错误。使DUT处于receive模式,包括在RX引脚上逐位发送数据,然后在PREADY时从PRDATA端口读取数据。
7.测试过程与上述随机序列相同。唯一会发生的变化是使用时钟和复位驱动器序列,时钟会有不同的周期,并会在每次transaction后进行重置。 -
APB-agent(driver、sequencer、monitor、config)
apb_config:slave_Addr、psel_Index的注册,定义AddrCalcFunc()函数。
apb_monitor:将从interface上监测到的信号驱动到trans_collected中(即apb_transaction),再在PREADY信号拉低后,将trans_collected中的数据write到item_collected_port_mon中。
apb_driver:get两个cfg的句柄。
将apb_transaction驱动到DUT上。
- UART-agent(driver、sequencer、monitor、config)
uart_config:定义baudRateFunc()函数,将bRate转换为baud_rate。
from APB agent:frame_len、n_sb、parity、bRate
to UART monitor:baud_rate
对frame_len、n_sb、parity、bRate进行相应的约束。
uart_transaction:
uart_monitor:根据波特率只对interface上监测到的data value(payload)进行采样,忽略奇偶位和停止位,不进行采样。首先,每帧的有效载荷被临时存储在本地寄存器中,在接收到所有帧后,寄存器的值被传递给transaction,然后通过analysis_port发送到scb。
uart_driver:transaction level to signal level
将seq_item级的value驱动到interface上。其包含了所有的信号
APB - I2C
- 模块作用:接收来自APB总线的数据,通过两组FIFO和移位寄存器,将从APB到I2C的数据进行串并转换。(类似APB-UART)进行写操作时,数据会先写到DW_APB_I2C的TX FIFO中。并且通过APB写入到DW_APB_I2C的IC_TAR寄存器的地址值,先把这个发到I2C线上,寻找对应的I2C设备。有设备回应后,再把寄存在DW_APB_I2C 内部TX FIFO的数据,通过TX shift一拍一拍的打到I2C线上,这样I2C上的SLAVE就可以收到写入的数据。
进行读操作时,APB上先给DW_APB_I2C发过来一个地址,并且对应一个数据,但是这个数据可能不是要发送到I2C上的数据,而是要写入DW_APB_I2C内部对应的控制寄存器的值。配置完成之后,DW_APB_I2C开始把地址发送到I2C线上,寻找对应的I2C设备。设备确认传输方向后,把数据一拍一拍打到I2C线上,然后DW_APB_I2C把这个数据经过RX SHIFT和RX FIFO,以并行数据的形式打到APB线上,然后apb master就可以拿到这个数据。 - 环境组成:
rkv_i2c_pkg:lvc_apb_pkg 、lvc_i2c_pkg 、 ral_rkv_i2c、 rkv_i2c_configs
rkv_i2c_master_scoreboard 、rkv_i2c_cgm 、rkv_i2c_virtual_sequencer
rkv_i2c_env、 rkv_element_sequences 、rkv_i2c_virtual_sequences
rkv_i2c_tests、 rkv_user_element_sequences、 rkv_i2c_user_virtual_sequences
rkv_i2c_user_tests
rkv_i2c_env:在env中例化rkv_i2c_config、rkv_i2c_if、apb_mst、i2c_mst、i2c_slv、
scb、virtual sqr、cgm、rgm、adapter、predictor、
在build_phase中get 到rkv_i2c_config、rkv_i2c_if、rgm的句柄,并set rgm、lvc_apb_config、scb、sqr、cgm的句柄。
在connect_phase中,将apb_mst和i2c_slv的monitor中的port连接到scb中的imp和cgm的imp上,将vip中的sequencer连接到virtual sequencer上。并对寄存器模型进行集成。
Virtual sequencer:传递三个sequencer、rkv_i2c_config、rgm的句柄。
Config:在defines中定义中断的ID,在config中定义两个使能信号:
master_scoreboard_enable,coverage_model_enable。在do_i2c_cfg()函数中对master_cfg与slave_cfg进行配置。
Scb:定义analysis import,run_phase()有四个函数:i2c_refmod(),i2c_write_comparer(),i2c_read_comparer(),i2c_mon_interrupt()。
write_apb_master:将lvc_apb_transfer中的transaction压进apb_trans_observed。
write_i2c_slave:将lvc_i2c_slave_transaction中的transaction压进write_data_observed或read_data_observed。
i2c_refmod():当apb_trans_observed的size()大于0时,将transaction从中pop出来,并将其push进write_data_expected()或read_data_expected()中。
(write_count_expected++ read_count_expected++)
i2c_write_comparer():比对write_data
i2c_read_comparer():比对read_data
compare_transaction():比对exp与obs,如果不匹配,则mismatch_detected=1,且mismatch_count++。
i2c_mon_interrupt(): monitored aborted/exceptional interrupt asserted, and disable scoreboard.
I2C的sequence和testcase没写,太多了,建议记几个比较典型的就可以了,比如说常见的寄存器是怎么验的。以及element sequence,virtual sequence,test case之间是怎么样的一个关系,比如在element sequence中定义具体要测试的signal和transfer,在virtual sequence中调用和管理element sequence,在test case中对virtual sequence进行挂载以及对objection进行控制。。