》BusMonitor结构
在仿真架构里,除了要向DUT注入激励外,还要监控DUT的输出。针对DUT的输出监控,cocotb里的主要组件是BusMonitor。整个BusMonitor的实现架构如下图所示:
从整个图中可以看出,Monitor是基类,先来看整个Monitor里面都做了哪些。
》Monitor:init
先来看下Monitor的初始化函数:
在初始化函数里,除了变量的声明外 其核心是拉起了_monitor_recv()的协程,句柄交由_thread来执行 。_monitor_recv()在Monitor中的实现为:
可见,当我们要继承使用Monitor时,我们 在实现中需要自己实现_monitor_recv()函数,而且需要调用_recv函数 。那么继续看_recv函数都做了哪些动作:
_recv函数主要用于处理接收监控到的transaction,其所做的动作为:
-
每接收到一个任务,stats.received_transactions便加1。从而我们 能够通过stats变量方便得到Monitor接收了多少任务 。
-
_callbacks中保存了收到任务时需要调用的回调函数。 当收到transactions时,以transaction为参数,依次调用所有的回调函数。
-
_recvQ用于保存接收到的transaction ,但指定注意的是, 只有当没有指定回调函数时,任务才会保存到_recvQ中 。
-
当_event,_wait_event不为空时,以transaction为参数依次触发 。
了解了_recv()函数的动作,不难看出,我们在自己的设计里实现_monitor_recv()函数需要做的主要内容是:
** 采样总线上的有效任务,并将采集到的数据封装成transaction后调用_recv()函数。**
》Monitor:其他函数
了解了Monitor的主业,再来看下Monitor实现的一些其他方法:
** wait_for_recv()函数用于等待有效transaction** 。其可以传入一个timeout参数,该参数默认值为仿真中timestep中的设定值。_wait_event由_recv()中触发。
kill函数用于退出_recv_monitor()进程,使用应该相对较少。
除了在__init__函数中传入callback参数外,还可以通过调用add_callback函数来传入callback参数。
如前所述,当我们在没有传入callback时,收到的transaction均会传入到_recvQ中,而_recvQ为一个内部变量,这两个方法提供了外部访问_recvQ中元素数量及指定index内容的方式(可自行了解python中这两个方法的意义)。
看完了Monitor的实现,那么就看其子类BusMonitor又做了什么扩展了,Monitor一般还是很少直接使用的。
》BusMonitor:init
BusMonitor将Monitor与Bus进行了进一步的结合,其初始化函数为:
初始化函数很简单,也很容易理解,需要做的就是指定好_signals及_optional_signals即可。
除了初始化函数外,BusMonitor中的另一个主要函数便是in_reset了:
** 该函数主要是用于检测Bus是否处于复位状态。** 毕竟在复位时一般是不需要监控的。
值得注意的是BusMonitor并未实现_monitor_recv(),那么我们还需要自己实现该函数。
按例,后面给出一个example。
》DUT
DUT还是采用和上次一样的:
》TB
这里我们传入了一个showResult作为callback。
原作者:玉骐