实验一代码结构
tb4.sv
chnl initiator 发送激励任务, chnl_write()封装在了 module里面,tb4出了例化DUT、产生时钟、复位以外,还做了3个 chnl_initiator chn10_init , chnl_initiator chn11_init , chnl_initiator chn12_init (用硬件模块做了例化),然后通过一些线网类型来给 dut 的 ch0,1,2 做驱动, mcdt的最终输出、arbit输出,在实验1 环节暂时没用到 。
相比较实验0来讲,发送激励的部分,由之前简单的任务发送,改成把任务封装在chnl_initiator 模块里面了。实验1里,模块也可以定义一些函数、定义一些任务。到了下一个实验,要把模块逐渐做一个迁移,迁移到类(硬件盒子迁移到软件盒子)
时钟复位信号送给 chnl0_init, chnl1_init, chnl2_init(硬件模块实现)。 MCDT也需要时钟信号
上角标M表示硬件模块,chnl0/1/2_init 硬件模块在 tb 平台上做了一个例化, 通过线网做了一个连线,调用 chnl_write, chnl_idle 发送一些数据。数据从哪来? chnl_initiator 自己不产生数据,只会将拿到的数据通过线网驱动到 dut 的端口上面。 数据产生于动态数组,数据就可以交给硬件模块,硬件模块可以拿到每一个数据去消化,最终送到 mcdt
想让动态数组预先产生一些数据
实验1 的结构,相比于实验0来讲,把发送数据的任务(chnl_write, chnl_idle )都封装在一个硬件模块里面(chnl initiator)。更符合验证环境组件的结构,验证环境各个组件发挥各自的作用。
tb2.sv中 ,initial过程块语句被2个task, clk_gen() 和 rstn_gen()取代了 。 时钟周期是固定的,通过clk_gen() 生成一个任意周期的时钟,想通过时钟周期做一个参数
timescale 1ns(时间单位)/1ps(时间精度)
tb3.sv
在initial里面对3个动态数组初始化 ,没个数组产生100个数据
在这里面将100个数据拿出来
对每个数据调用chnl_write() 分别对channel 0/1/2 做写操作
tb4.sv
相比tb3 , tb4 有了新变化
前提做完tb1, tb2, tb3, tb4
chnl_initiator 例化了3次实例, tb4 之前发送激励都是用 chnl_write ,现在是封装在了 chnl_initiator ,之前的chnl_write 有2个参数,一个是id ,一个是数据 ,现在只用发数据 不用id 了
内部调用 chnl_idle() , chnl_idle() 实现一个空闲的时钟周期,等一个时钟的上升沿,上升沿时把 ch_valid 拉低, ch_data 也拉低
chnl_write():怎样使用ch_ready信号 ? 在chnl_write() 时不仅要等到时钟的上升沿、 把ch_valid 信号拉高、 把ch_data送出去 ,还要看当前这一拍信号有没有为高, 如果 ch_ready 为高, 这一次 chnl_write 就执行完毕, 如果 ch_ready 为低 要一直等待直到 ch_ready 为高
数据并行发送, tb3 顺序发送数据, tb4 并行发送数据(每一个initiator模块 都是独立的 ), chnl_write 里面,每发送一个数据 就会调用 chnl_idle 等待一个空闲时钟周期 , 能否紧凑发送数据 , 没有 chnl_idle ?
channel_slave 的 chx_ready 信号拉低 ,各自 channel_slave 里的 FIFO 写满之后 chx_ready 才会拉低
实验1相比实验0 ,在实验0 的基础上 把 产生数据的部分通过动态数组 预先生成数据 变得容易。 发送激励的部分不单是通过一个 task 了, 而是通过一个模块 chnl_initiator