目录
fmt_pkg.sv 代码分析
fmt_pkg.sv 中的 fmt_driver
driver 分为 inititator 和 responder, 之前的 chnl_driver 和 reg_driver 都是 initiator 发送数据或者指令, 而 formatter 的 driver 是一个 接收数据的 从端 slave, 所以我们的 driver 类似要模仿一个 fifo 缓冲数据,而且 fifo 的位宽可大可小。
我们 fifo 接收来自 formatter 的数据,并把它按照我们 fifo 的位宽发送出去,实现缓冲,我们的 fifo 在接收数据时 , 只要按照 formatter的时序, 控制 fmt_grant 和接收数据即可。
对于收到 来自 formatter 的 req 请求, 我们给出 grant=1 同意发送数据,而 formatter 的 位宽,深度和 我们的 fifo 不一致 ,当上大下小, 我们的 grant 发送的就慢一些,可能要经过好几拍, 当上小下大, 我们的 grant 就发送的快一些,只有当上小下大时,才可以在 req 拉高之后的 下一拍 把 grant 拉高 。这样可以在下一步继续实现对formatter 的功能验证。
其中, driver 中的 do_receive() 和 do_consume() 如下图所示:
do_consume() 的代码解析
do_consume() 也就是按照 我们给 fifo 的带宽 不断地往下流出数据
do_receive() 的代码解析
do_receive() 也就是按照formatter 的时序,不断(forever)的接收数据,当grant=1,代表我们同意接收来自formatter的数据,按照数据包的长度往fifo里放数据。
给 formatter 发送 grant = 1 的 条件是 fifo 内部的余量 大于 来自formatter的 数据 (我理解的也就是 fifo 的深度余量 和 来自formatter数据包的长度)
也就是 ( this.fifo_bound - this.fifo.num() ) >= intf.fmt_length
提醒一下自己: fifo 是个 mailbox, 回顾mailbox的 相关函数, fifo.new() 创建一个信箱实例,fifo.put() 往信箱里放数据, fifo.get()/fifo.peek() 从信箱里拿数据,get()/peek() 是阻塞的拿, 拿不到会一直等着, fifo.try_put() fifo.try_get()/fifo.try_peek()都是非阻塞, 放不进去或者拿不到都返回0,
fifo.num() 返回信箱里的数据的数量。
do_config() 的代码解析
do_config 里面对 fifo 进行了 new() , 为什么还要在 driver 的 构造函数里 再进行一次 new?有必要吗?
答: 引用这个博主写的很详细路科验证MCDF_svlab4笔记_Hardworking_IC_boy的博客-CSDN博客_路科验证
- 这个问题有个假设,就是do_config需要存在,也就是你需要一开始就进行配置。但是这个假设并不是一直成立的。有时候是没有do_config的,比如有一些组件是作为slave,他不可能每次接收master的数据都事先配置。
- 这种情况下,你就没有办法通过req_mb得到req,也就不知道req.fifo,没法得到fifo_bound,因此也就无法根据fifo_bound的大小来对fifo进行new,那么fmt_pkg也就不工作了,没法模拟下行。
- 事先例化fifo,其实就相当于一个初始值,让fmt_pkg在没有配置的时候也能工作。
- 此处fifo_bound设置为4096,以及data_consum_peroid设置为1,只是为了让FIFO的空间比较大,消化数据比较快,那么当fmt发送req时,fmt_pkg模拟的下行能够更快地让grant拉高。
- 也就是说,这里将fifo_bound设置成4096并不是一个硬性的要求,也可以是其他的数值,比如64、256等等,目的都是为了更快地让grant拉高。
- 不探究fifo_bound和data_consum_peroid的影响时,就选一个最好的值就行了。等需要探究了,再特地改变他们的值。(比如下行从端低带宽测试就是探究低带宽带来的影响)