棋子 · 1 天前

cocotb 仿真加速——合并

✎ 编 者 按
在 cocotb 里,通过将信号在 python 中进行合并的方式来对仿真进行提速。

从 cocotbext-axi 说起

对于一个 RTL 设计而言,无论什么功能,其接口均可以抽象为 valid-only(Flow)接口或者 valid-ready(stream)接口。那么在 cocotbext-axi 里,其已经提供了一套非常不错的处理机制。在之前的文章《cocotb——一文看懂 stream lib》中对于如何使用,已经有了相对详细的分析。对于 cocotb 而言,其仿真效率一直是一言难尽的。那么当我们的接口都抽象为 Flow 接口或者 Stream 接口时,对于其中的 payload 信号,是分开赋值驱动还是一并驱动,哪个效率相对而言更高一些呢?

这里做了两个 RTL demo:

case classAddDemo() extendsComponent{
  val data_in=slave(Stream(Vec(UInt(8 bits),256)))
  val data_out=master(Stream(Vec(UInt(8 bits),256)))
  data_out<-<data_in.translateWith(Vec(data_in.payload.map(255-_)))
}

case classAddDemo1() extendsComponent{
  val data_in=slave(Stream(Bits(8*256 bits)))
  val data_out=master(Stream(Bits(8*256 bits)))
  data_out<-<data_in.translateWith(data_in.payload.asBits.subdivideIn(8 bits).map(255-_.asUInt).asBits())
}

两个 demo 的输入、输出都是 Stream 接口,差别在于 AddDemo 中的 data_in、data_out 的 payload 为 256 个 8bit UInt、而对于 AddDemo1 中,其 data_in、data_out 的 payload 为一个完成的 2K 位宽的 UInt。

对于 AddDemo,在采用 cocotb 进行仿真时,其 driver、monitor 定义如下:

image.png

SimEnv 定义如下:

Image

在 send_data 中,通过借用 python 的 setattr 方法对于每个 payload 进行赋值。

而对于 AddDemo1,其 paylaod 只有一个。

对于两个 Demo,进行相同的仿真 Case,分别输入 50000 组数据的输入与校验。最终仿真结果:

image.png

相较于采用数据分离的形式,采用数据合并的方式还是有不少的效率提升。

那么对于我们的仿真而言,完全可以采用将抽象后的借口的除 valid/ready 信号外均打包成一个信号。在 python 与仿真器之间进行交互时降低信号驱动/采样的交互次数。

lib 改造

在确定了上述的策略,那么我们可以对 cocotbext-axi 提供的 define_stream 函数进行改造。

首先,我们需要自己定义 StreamTransaction:

Image

这里定义 PortTransaction 继承 StreamTransaction。_signals 用于定义总线限号 payload。此外,也定义了待封装解封装的信号。定义 pack 方法用于将 data 打包成要驱动的 payload 信号值,而 unpack 则用于将采样到的 payload 信号解析赋值到 data 中。

既然我们自己定义了 StreamTransaction,那么就需要对 define_stream 进行改造:

defdefine_stream1(name, signals,transaction, optional_signals=None, valid_signal=None, ready_signal=None, signal_widths=None):
    all_signals = signals.copy()

    if optional_signals isNone:
        optional_signals = []
    else:
        all_signals += optional_signals

    if valid_signal isNone:
        for s in all_signals:
            if s.lower().endswith('valid'):
                valid_signal = s
    if valid_signal notin all_signals:
        signals += valid_signal

    if ready_signal isNone:
        for s in all_signals:
            if s.lower().endswith('ready'):
                ready_signal = s
    else:
        if ready_signal notin all_signals:
            signals += ready_signal

    if signal_widths isNone:
        signal_widths = {}

    if valid_signal notin signal_widths:
        signal_widths[valid_signal] = 1

    if ready_signal notin signal_widths:
        signal_widths[ready_signal] = 1

    filtered_signals = []

    for s in all_signals:
        if s notin (ready_signal, valid_signal):
            filtered_signals.append(s)

    attrib = {}
    attrib['_signals'] = signals
    attrib['_optional_signals'] = optional_signals
    bus = type(name+"Bus", (StreamBus,), attrib)

    attrib = {s: 0for s in filtered_signals}
    attrib['_signals'] = filtered_signals

    #transaction = type(name+"Transaction", (StreamTransaction,), attrib)

    attrib = {}
    attrib['_signals'] = signals
    attrib['_optional_signals'] = optional_signals
    attrib['_signal_widths'] = signal_widths
    attrib['_ready_signal'] = ready_signal
    attrib['_valid_signal'] = valid_signal
    attrib['_transaction_obj'] = transaction
    attrib['_bus_obj'] = bus

    source = type(name+"Source", (StreamSource,), attrib)
    sink = type(name+"Sink", (StreamSink,), attrib)
    monitor = type(name+"Monitor", (StreamMonitor,), attrib)

    return bus, source, sink, monitor

在定义 driver、monitor 时,则采用如下方式:

Image

最终,在搭建 SimEnv 时,则可以做如下改造:

Image

这里在 send_data 函数中,通过在 275 行调用 pack 将数据打包合并到待驱动的信号上。而在 scb 中,对于采样到的信号,则在 283 行通过 unpack 将信号解析出来。

如此,则能够达成我们的目的。

写在最后

相较于 SpinalHDL 而言,cocotb 的效率仍旧是差很多的。之前在仿真效对比和加速也有过两篇文章《给仿真加点速》《既生瑜何生亮——SpinalHDL VS Cocotb》。由于在本地电脑上都是采用的 Verilator 进行仿真,在 SpinalHDL 上也做了一个简单类似的测试,但测试结果却是分开驱动仿真反倒比合并驱动采样的时间消耗要高一些。据说对于 Verilator 仿真器两者的使用方式略有差别,对于商业仿真器有待验证。

END

作者:玉骐
文章来源:Spinal FPGA

推荐阅读

更多 IC 设计干货请关注IC设计专栏。欢迎添加极术小姐姐微信(id:aijishu20)加入技术交流群,请备注研究方向。

推荐阅读
关注数
21803
内容数
1340
主要交流IC以及SoC设计流程相关的技术和知识
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息