本文主要是介绍【Cocotb】cocotbext-axi拓展库,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
用于Cocotb的AXI接口模块,GitHub仓库: https://github.com/alexforencich/cocotbext-axi
介绍
AXI、AXI lite和AXIStream仿真模型
安装
从pip安装(发布版本,稳定):
$ pip install cocotbext-axi
从git安装(最新开发版本,可能不稳定):
$ pip install https://github.com/alexforencich/cocotbext-axi/archive/master.zip
主动开发的安装:
$ git clone https://github.com/alexforencich/cocotbext-axi
$ pip install -e cocotbext-axi
文档和使用示例
请参阅tests
目录、verilog-axi和verilog-axis以获取使用这些模块的完整测试台。
AXI和AXI lite Master
AxiMaster和AxiLiteMaster类实现AXI主机功能,并能够对AXI从机进行读写操作。 请求操作将根据AXI规范进行拆分和对齐。 AxiMaster模块能够生成窄突发,处理多个进行中的操作,以及处理跨不同事务ID的响应中的重新排序和交织。 AxiMaster和AxiLiteMaster以及相关的对象都扩展了Region,因此它们可以附加到AddressSpace对象上以处理指定区域中的内存操作。
AxiMaster是围绕AxiMasterWrite和AxiMasterRead的包装器。 类似地AxiLiteMaster是围绕AxiLiteMasterWrite和AxiLiteMasterRead的包装器。 如果需要只读或只写接口而非全接口,可使用相应的只读或只写变体,用法和API完全相同。
要使用这些模块,请导入您需要的模块并将其连接到DUT:
from cocotbext.axi import AxiBus, AxiMasteraxi_master = AxiMaster(AxiBus.from_prefix(dut, "s_axi"), dut.clk, dut.rst)
构造函数的第一个参数接受AxiBus或AxiLiteBus对象,视情况而定。 这些对象是接口信号的容器,并包含自动连接的类方法。一旦模块被实例化就可以通过几种不同的方式启动读和写操作。
首先,可以使用异步阻塞的read()、write()及其相关的字访问包装器进行操作。从不同协程启动的多个并发操作会被正确处理,并按照操作完成的顺序返回结果。例如:
await axi_master.write(0x0000, b'test')
data = await axi_master.read(0x0000, 4)
可以指定其他参数来控制边带信号和突发设置。传输将根据AXI规范拆分为一个或多个突发。从对read()或write()的相同调用中生成的所有突发将使用相同的ID,如果未指定,该ID将自动生成。Read()和write()返回包含地址、数据或长度以及resp的namedtuple对象。这是首选样式,也是字节访问包装器支持的唯一样式。
或可以使用非阻塞的init_read()和init_write()初始化操作。这些函数返回操作完成时触发的Event对象,并且可以从Event.data中检索结果。例如:
write_op = axi_master.init_write(0x0000, b'test')
await write_op.wait()
resp = write_op.data
read_op = axi_master.init_read(0x0000, 4)
await read_op.wait()
resp = read_op.data
使用此方法,可以从同一个协程启动多个并发操作。还可以将事件与Combine、First和with_timeout一起使用。
AxiMaster 和 AxiLiteMaster 构造函数参数
- bus:包含AXI接口信号的AxiBus或AxiLiteBus对象
- clock:时钟信号
- reset:复位信号(可选)
- reset_active_level:重置活动级别(可选,默认True)
AxiMaster附加参数
- max_burst_len:以周期为单位的最大脉冲串长度,范围1-256,默认值256。
方法
- init_read(address, length, ...):从address开始读取length字节数据。 返回Event对象。
- init_write(address, data, ...):从address开始开始写入data(字节)。 返回Event对象。
- idle():当没有未完成的操作正在进行时,返回True
- wait():阻塞等待,直到所有未完成的操作完成
- wait_read():等待所有未完成的读取操作完成
- wait_write():等待所有未完成的写入操作完成
- read(address, length, ...):从address开始读取length字节
- read_words(address, count, byteorder='little', ws=2, ...):从address开始读取count个ws字节
- read_dwords(address, count, byteorder='little', ...):从address开始读取count个4字节
- read_qwords(address, count, byteorder='little', ...):从address开始读取count个8字节
- read_byte(address, ...):读取address处的单个字节
- read_word(address, byteorder='little', ws=2, ...):读取address处的单个ws字节字
- read_dword(address, byteorder='little', ...):读取address处单个4字节字
- read_qword(address, byteorder='little', ...):读取address处的单个8字节字
- write(address, data, ...):从address开始写入data(字节)
- write_words(address, data, byteorder='little', ws=2, ...):从address开始写入data(ws字节字)
- write_dwords(address, data, byteorder='little', ...):从address开始写入data(4字节双字)
- write_qwords(address, data, byteorder='little', ...):从address开始写入data(8字节qwords)
- write_byte(address, data, ...):在address处写入data单个字节data
- write_word(address, data, byteorder='little', ws=2, ...):在address处写入data单个ws字节字
- write_dword(address, data, byteorder='little', ...):在address处写入data单个4字节双字
- write_qword(address, data, byteorder='little', ...):在address处写入data单个8字节qword
AxiMaster的附加可选项
- arid,awid:突发的AXI ID,默认自动分配
- burst:AXI突发类型,default AxiBurstType.INCR
- size:AXI突发大小,接口支持的默认最大值
- lock:AXI锁类型,默认AxiLockType.NORMAL
- cache:AXI缓存字段,默认0b0011
- prot:AXI保护标志,默认AxiProt.NONSECURE
- qos:AXI QOS字段,默认0
- region:AXI region字段,默认0
- user:AXI用户信号(awuser/aruser),默认0
- wuser:AXI wuser信号,默认值0(仅限写相关方法)
- event:Event对象用于等待并获取特定操作的结果,默认为None。 当操作完成并通过Event.data返回结果时,将触发该事件。 (仅限init_read()和init_write())
AxiLiteMaster的附加可选项
- prot:AXI保护标志,默认AxiProt.NONSECURE
- event:Event对象用于等待并获取特定操作的结果,默认为None。 当操作完成并通过Event.data返回结果时,将触发该事件。 (仅限init_read()和init_write())
AxiBus和AxiLiteBus
AxiBus、AxiLiteBus和相关对象是接口信号的容器,包含了各个通道的总线对象实例,扩展自cocotb_bus.bus.Bus类。提供了from_entity和from_prefix类方法来方便信号名称匹配。对于AXI接口,请使用适当的AxiBus、AxiReadBus或AxiWriteBus。对于AXI lite接口,请使用适当的AxiLiteBus、AxiLiteReadBus或AxiLiteWriteBus。
AXI和AXI lite slave
AxiSlave和AxiLiteSlave类实现了AXI从机,能够完成来自上游AXI主机的读写操作。AxiSlave模块能够处理窄突发。这些模块既可以用于代表DUT在MemoryInterface上执行内存读取和写入,也可以扩展它们以实现自定义功能。
AxiSlave是AxiSlaveWrite和AxiSlaveRead的包装器。类似地,AxiLiteSlave是AxiLiteSlaveWrite和AxiLiteSlaveRead的包装。如果需要只读或只写接口而非全接口,请使用相应的只读或只写变体,其用法和API完全相同。
要使用这些模块,请导入您需要的模块并将其连接到DUT:
from cocotbext.axi import AxiBus, AxiSlave, MemoryRegionaxi_slave = AxiSlave(AxiBus.from_prefix(dut, "m_axi"), dut.clk, dut.rst)
region = MemoryRegion(2**axi_slave.read_if.address_width)
axi_slave.target = region
构造函数的第一个参数接受一个AxiBus或AxiLiteBus对象。这些对象是接口信号的容器,并包含自动化连接的类方法。
也可以扩展这些模块;可以通过重写内部的_read()和_write()方法来定制操作。参见AxiRam和AxiLiteRam的例子。
AxiSlave和AxiLiteSlave构造函数参数
bus:包含AXI接口信号的AxiBus或AxiLiteBus对象
clock:时钟信号
reset:复位信号(可选)
reset_active_level:重置活动级别(可选,默认True)
target:目的域(可选,默认None)
属性
target:目的域
AXI和AXI lite RAM
AxiRam和AxiLiteRam类实现了AXI RAM,并能够完成来自上游AXI主机的读写操作。AxiRam模块能够处理窄突发传输。这些模块是相应的AxiSlave和AxiLiteSlave模块的扩展。在内部使用SparseMemory来支持仿真非常大的存储器。
AxiRam是AxiRamWrite和AxiRamRead的包装器,类似地AxiLiteRam是AxiLiteRamWrite和AxiLiteRamRead的包装。如果需要只读或只写接口而非全接口,请使用相应的只读或只写变体,其用法和API完全相同。
要使用这些模块,请导入您需要的模块并将其连接到DUT:
from cocotbext.axi import AxiBus, AxiRamaxi_ram = AxiRam(AxiBus.from_prefix(dut, "m_axi"), dut.clk, dut.rst, size=2**32)
构造函数的第一个参数接受一个AxiBus或AxiLiteBus对象。这些对象是接口信号的容器,并包含自动化连接的类方法。
模块实例化后,可以通过几种不同的方式访问内存内容。首先,可以通过mem属性直接访问mmap对象。其次,可以使用read()、write()和各种字节访问包装器。还提供了十六进制转储帮助器方法用于调试。例如:
axi_ram.write(0x0000, b'test')
data = axi_ram.read(0x0000, 4)
axi_ram.hexdump(0x0000, 4, prefix="RAM")
多端口存储器可以通过将第一个实例的mem
对象传递给其他实例来构造, 例如以下是如何创建一个四端口RAM:
axi_ram_p1 = AxiRam(AxiBus.from_prefix(dut, "m00_axi"), dut.clk, dut.rst, size=2**32)
axi_ram_p2 = AxiRam(AxiBus.from_prefix(dut, "m01_axi"), dut.clk, dut.rst, mem=axi_ram_p1.mem)
axi_ram_p3 = AxiRam(AxiBus.from_prefix(dut, "m02_axi"), dut.clk, dut.rst, mem=axi_ram_p1.mem)
axi_ram_p4 = AxiRam(AxiBus.from_prefix(dut, "m03_axi"), dut.clk, dut.rst, mem=axi_ram_p1.mem)
AxiRam和AxiLiteRam构造函数参数
bus:包含AXI接口信号的AxiBus或AxiLiteBus对象
clock:时钟信号
reset:复位信号(可选)
reset_active_level:重置活动级别(可选,默认True)
size:内存大小(以字节为单位)(可选,默认值2**64)
mem:要使用的mmap或SparseMemory支持对象(可选,覆盖大小)
属性
mem:直接访问共享的mmap或SparseMemory备份对象
方法
- read(address,length):从address开始读取length字节
- read_byte(address):读取address上的单个字节
- read_dword(address,byteorder='little'):读取address上的单个4字节dword
- read_dwords(address,count, byteorder='little'):从address开始读取count个4字节
- read_qword(address,byteorder='little'):读取address处的单个8字节qword
- read_qwords(address,count, byteorder='little'):从address开始读取count个8字节
- read_word(address,byteorder='little', ws=2):在address处读取单个ws-byte字
- read_words(address,count, byteorder='little', ws=2):读取从address开始读取count个ws-byte字
- write(address,data):从address开始写数据(字节)
- write_byte(address,data):在address上写单个字节
- write_word(address,data, byteorder='little', ws=2):在address上写单个ws字节
- write_words(address,data,byteorder='little', ws=2):写入数据(ws-byte字),从address开始
- write_dword(address,data,byteorder='little'):在address上写入单个4字节的dword
- write_dwords(address,data,byteorder='little'):从address开始写数据(4字节的dwords)
- write_qword(address,data,byteorder='little'):在address上写一个8字节的qword
- write_qwords(address,data,byteorder='little'):从address开始写数据(8字节的qwords)
- hexdump(address,length,prefix= ' '):从address开始返回length字节的十六进制转储,前缀行可选前缀
- hexdump_line(address,length,prefix= ' '):从address开始返回length字节的十六进制转储(str列表),前缀行可选前缀
- hexdump_str(address,length,prefix= ' '):从address开始返回length字节的十六进制转储(str),前缀行可选
AXI stream
AxiStreamSource、AxiStreamSink和AxiStreamMonitor类可用于驱动、接收和监控AXI流接口上的流量。 AxiStreamSource驱动除tready以外的所有信号,可用于将AXI流流量驱动到设计中。 AxiStreamSink仅驱动tready线路,因此可以接收AXI流业务并施加背压。 AxiStreamMonitor不驱动任何信号,因此可以连接到设计中的任何地方的AXI流接口,以被动监控流量。
要使用这些模块,请导入您需要的模块并将其连接到DUT:
from cocotbext.axi import (AxiStreamBus, AxiStreamSource, AxiStreamSink, AxiStreamMonitor)axis_source = AxiStreamSource(AxiStreamBus.from_prefix(dut, "s_axis"), dut.clk, dut.rst)
axis_sink = AxiStreamSink(AxiStreamBus.from_prefix(dut, "m_axis"), dut.clk, dut.rst)
axis_mon= AxiStreamMonitor(AxiStreamBus.from_prefix(dut.inst, "int_axis"), dut.clk, dut.rst)
构造函数的第一个参数接受一个AxiStreamBus对象。 这个对象是接口信号的容器,包括自动连接的类方法。
使用AxiStreamSource将数据发送到设计中,调用send()/send_nowait()或write()/write_nowait()。可接受的数据类型是可迭代对象或AxiStreamFrame对象。可选地,调用wait()来等待传输操作完成。例子:
await axis_source.send(b'test data')
# wait for operation to complete (optional)
await axis_source.wait()
也可以通过在AxiStreamFrame
对象的tx_complete字段中传递事件,然后等待该事件来等待特定帧的传输完成。 设置了模拟时间字段的帧将在事件数据中返回。 例子:
frame = AxiStreamFrame(b'test data', tx_complete=Event())
await axis_source.send(frame)
await frame.tx_complete.wait()
print(frame.tx_complete.data.sim_time_start)
要使用AxiStreamSink或AxiStreamMonitor接收数据,请调用recv()/recv_nowait()或read()/read_nowait()。 可选地调用wait()以等待新的接收数据。 recv()用于面向帧的接口,默认情况下在返回之前压缩AxiStreamFrames。 read()用于非面向帧的流。 调用read()在内部调用队列中当前所有帧的recv(),然后压缩所有帧中的tdata并将其合并到一个单独的读取队列中,从该队列返回读取数据。 所有边带数据会被丢弃。
data = await axis_sink.recv()
信号
- tdata:数据,必填
- tvalid:限定所有其他信号;可选,默认为1
- tready:表示接收器已准备好接收数据;可选,默认为1
- tlast:标记帧的最后一个周期;可选,默认为1
- tkeep:限定数据字节,数据总线宽度必须能被tkeep信号宽度整除;可选,默认为1
- tid:ID信号,可用于路由;可选,默认为0
- tdest:目的地信号,可用于路由;可选,默认为0
- tuser:附加用户数据;可选,默认为0
构造函数参数
- bus:包含AXI流接口信号的AxiStreamBus对象
- clock:时钟信号
- reset:复位信号(可选)
- reset_active_level:重置活动级别(可选,默认True)
- byte_size:字节大小(可选)
- byte_lanes:字节通道计数(可选)
注意:byte_size、byte_lanes、len(tdata)和len(tkeep)都是相关的,因为byte_lanes是从tkeep(如果连接)和byte_size*byte_lanes == len(tdata)设置的。 因此,如果连接了tkeep,byte_size和byte_lanes都将在内部计算,并且不能被覆盖。 如果tkeep未连接,则可以指定byte_size或byte_lanes,另一个将被计算,使得byte_size*byte_lanes == len(tdata)。
属性
- pause:暂停接口(deassert tready或tvalid)(source/sink only)
- queue_occupancy_bytes:队列中的字节数(all)
- queue_occupancy_frames:队列中的帧数(all)
- queue_occupancy_limit_bytes:在应用反压之前允许的队列中的最大字节数(source/sink only)
- queue_occupancy_limit_frames:在应用反压之前允许的队列中的最大帧数(source/sink only)
方法
- send(frame):发送帧(阻塞)(source)
- send_nowait(frame):发送帧(非阻塞)(source)
- write(data):发送数据(等同于send)(阻塞)(source)
- write_nowait(data):发送数据(等同于send_nowait)(非阻塞)(源代码)
- recv(compact=True):接收帧作为GmiiFrame(阻塞)(sink)
- recv_nowait(compact=True):接收帧作为GmiiFrame(非阻塞)(sink)
- read(count):从缓冲区读取计数字节(阻塞)(sink/monitor)
- read_nowait(count):从缓冲区读取计数字节(非阻塞)(sink/monitor)
- count():返回队列中的项目数(all)
- empty():如果队列为空,则返回True(all)
- full():如果满足队列占用限制(source/sink),则返回True
- idle():如果没有传输正在进行(all)或队列不为空(source),则返回True
- clear():删除队列中的所有数据(all)
- wait():等待空闲(source)
- wait(timeout=0, timeout_unit='ns'):等待接收帧(sink)
- set_pause_generator(generator):为暂停信号设置发生器,发生器将在每个时钟周期(source/sink)提前
- clear_pause_generator():删除暂停信号发生器(source/sink)
AxiStreamBus对象
AxiStreamBus对象是接口信号的容器,目前是cocotb.bus.Bus的扩展。 提供类方法from_entity和from_prefix以促进信号名称匹配。
AxiStreamFrame
对象
AxiStreamFrame对象是要经由AXIStream
传输的帧的容器。 tdata字段包含字节列表形式的分组数据,如果字节大小是8位,则该字段是bytearray,否则是list中的int。 tkeep、tid、tdest和tuser可以是None中的int、list或int。
属性
- tdata:bytes、bytearray或list
- tkeep:tkeep字段,可选;列表,每个条目限定tdata中的相应条目。 可用于在源端插入间隙。
- tid:tid字段,可选; int或列表,每个tdata一个条目,发送时每个周期使用的最后一个值。
- tdest:tdest字段,可选; int或列表,每个tdata一个条目,发送时每个周期使用的最后一个值。
- tuser:tuser字段,可选; int或列表,每个tdata一个条目,发送时每个周期使用的最后一个值。
- sim_time_start:帧的第一个传输周期的模拟时间。
- sim_time_end:帧最后一个传输周期的模拟时间。
- tx_complete:帧传输时触发的事件或可调用。
方法
- normalize(): 将tkeep, tid, tdest和tuser打包到与tdata相同的长度,必要时复制最后一个元素,初始化tkeep为list为1,如果没有指定,则初始化tid, tdest和tuser为list为0。
- compact():删除基于tkeep的tdata, tid, tdest和tuser值,如果所有值都相同,则删除tkeep,将tid, tdest和tuser压缩为int。
地址空间抽象
地址空间抽象提供了一个框架,用于交叉连接多个内存映射接口,用于测试与复杂系统(包括具有DMA引擎的组件)接口的组件。
MemoryInterface是地址空间抽象中所有组件的基类。MemoryInterface提供了核心的read()和write()方法,实现了边界检查以及字节访问包装器,提供了创建Window和WindowPool对象的方法。函数get_absolute_address()将地址转换为系统地址空间。MemoryInterface可以通过覆盖_read()和_write()来扩展以实现自定义功能。
Window对象表示具有一定长度和偏移量的父地址空间上的视图。 Window上的read()write()操作被转换为父地址空间上的等效操作。 多个Window实例可以重叠并访问地址空间的同一部分。
WindowPool提供了一种从地址空间的一部分动态分配窗口的方法。 它使用标准的内存管理算法来提供所请求大小的自然对齐的Window对象。
Region是实现地址空间一部分的所有组件的基类。 Region对象可以与AddressSpace对象注册,以处理指定区域中的read()和write()操作。 Region可以通过实现一部分地址空间的组件进行扩展。
MemoryRegion
是Region
的扩展,使用mmap
实例来处理内存操作。 MemoryRegion
还提供了十六进制转储方法以及索引和切片。
SparseMemoryRegion
类似于MemoryRegion
,但由SparseMemory
而不是mmap
支持,因此可以模拟非常大的地址空间区域。
PeripheralRegion
是Region
的扩展,可以包装另一个实现read()
和write()
的对象,作为扩展Region
的替代方案。
AddressSpace
是处理地址空间的核心对象。 Region
对象可以用指定的基址、大小和偏移量注册到AddressSpace
。 然后,AddressSpace
对象将read()
和write()
操作定向到适当的Region
s,在必要时适当地拆分请求并转换地址。 用offset
而不是None
登记的区域被转换,使得对基地址+ N的访问映射到N +偏移。 注册为offset
或None
的区域不会被翻译。 与同一Region
注册的AddressSpace
对象不能重叠,但同一Region
可以注册多次。 AddressSpace
还提供了创建Pool
对象的方法。
Pool
是AddressSpace
的扩展,支持MemoryRegion
s的动态分配。 它使用标准的内存管理算法来提供所请求大小的自然对齐的MemoryRegion
对象。
例子
这是一个简单的示例,展示了如何使用地址空间抽象组件将DUT连接到模拟主机系统,包括模拟RAM、来自DUT的用于DMA的AXI接口以及到DUT的用于控制的AXI lite接口。
from cocotbext.axi import AddressSpace, SparseMemoryRegion
from cocotbext.axi import AxiBus, AxiLiteMaster, AxiSlave# 系统地址空间
address_space = AddressSpace(2**32)# RAM
ram = SparseMemoryRegion(2**24)
address_space.register_region(ram, 0x0000_0000)
ram_pool = address_space.create_window_pool(0x0000_0000, 2**20)# DUT控制寄存器接口
axil_master = AxiLiteMaster(AxiLiteBus.from_prefix(dut, "s_axil_ctrl"), dut.clk, dut.rst)
address_space.register_region(axil_master, 0x8000_0000)
ctrl_regs = address_space.create_window(0x8000_0000, axil_master.size)# DMA from DUT
axi_slave = AxiSlave(AxiBus.from_prefix(dut, "m_axi_dma"), dut.clk, dut.rst, target=address_space)# 测试DUT DMA功能
src_block = ram_pool.alloc_window(1024)
dst_block = ram_pool.alloc_window(1024)test_data = b'test data'
await src_block.write(0, test_data)await ctrl_regs.write_dword(DMA_SRC_ADDR, src_block.get_absolute_address(0))
await ctrl_regs.write_dword(DMA_DST_ADDR, dst_block.get_absolute_address(0))
await ctrl_regs.write_dword(DMA_LEN, len(test_data))
await ctrl_regs.write_dword(DMA_CONTROL, 1)while await ctrl_regs.read_dword(DMA_STATUS) == 0:passassert await dst_block.read(0, len(test_data)) == test_data
AXI信号
- 写地址通道
- awid:交易ID
- awaddr:地址
- awlen:突发长度(周期)
- awsize:突发大小(字节/周期)
- awburst:突发类型
- awlock:锁类型
- awcache:缓存控制
- awprot:保护位
- awqos:QoS字段
- awregion:区域字段
- buser:附加用户边带数据
- awvalid:有效信号,限定所有通道字段
- bready:就绪信号,来自后级模块的背压
- 写数据通道
- wdata:写入数据
- wstrb:写选通
- wlast:脉冲串结束标志
- buser:附加用户边带数据
- awvalid:有效信号,限定所有通道字段
- bready:就绪信号,来自后级模块的背压
- 写响应信道
awid
:交易IDbresp
:写响应buser
:附加用户边带数据awvalid
:有效信号,限定所有通道字段bready
:就绪信号,来自后级模块的背压
- 读地址通道
- awid:交易ID
- awaddr:地址
- awlen:突发长度(周期)
- awsize:突发大小(字节/周期)
- awburst:突发类型
- awlock:锁类型
- awcache:缓存控制
- awprot:保护位
- awqos:QoS字段
- awregion:区域字段
- buser:附加用户边带数据
- awvalid:有效信号,限定所有通道字段
- bready:就绪信号,来自后级模块的背压
- 读数据通道
- awid:交易ID
- rdata:读取数据
- rresp:读取响应
- wlast:脉冲串结束标志
- buser:附加用户边带数据
- awvalid:有效信号,限定所有通道字段
- bready:就绪信号,来自后级模块的背压
AXI lite信号
- 写地址通道
- awaddr:地址
- awprot:保护位
- awvalid:有效信号,限定所有通道字段
- bready:就绪信号,来自后级模块的背压
- 写数据通道
- wdata:写入数据
- wstrb:写选通
- awvalid:有效信号,限定所有通道字段
- bready:就绪信号,来自后级模块的背压
- 写响应信道
- bresp:写响应
- awvalid:有效信号,限定所有通道字段
- bready:就绪信号,来自后级模块的背压
- 读地址通道
- awaddr:地址
- awprot:保护位
- awvalid:有效信号,限定所有通道字段
- bready:就绪信号,来自后级模块的背压
- 读数据通道
- rdata:读取数据
- rresp:读取响应
- awvalid:有效信号,限定所有通道字段
- bready:就绪信号,来自后级模块的背压
-
AXI流信号
- tdata:数据
- tvalid:限定所有其他信号
- tready:表示接收器已准备好接收数据
- tlast:标记帧的最后一个周期
- tkeep:限定tdata中的数据字节
- tid:ID信号,可用于路由
- tdest:目的地信号,可用于路由
- tuser:附加边带数据
这篇关于【Cocotb】cocotbext-axi拓展库的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!