【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可以通过实现一部分地址空间的组件进行扩展。

MemoryRegionRegion的扩展,使用mmap实例来处理内存操作。 MemoryRegion还提供了十六进制转储方法以及索引和切片。

SparseMemoryRegion类似于MemoryRegion,但由SparseMemory而不是mmap支持,因此可以模拟非常大的地址空间区域。

PeripheralRegionRegion的扩展,可以包装另一个实现read()write()的对象,作为扩展Region的替代方案。

AddressSpace是处理地址空间的核心对象。 Region对象可以用指定的基址、大小和偏移量注册到AddressSpace。 然后,AddressSpace对象将read()write()操作定向到适当的Regions,在必要时适当地拆分请求并转换地址。 用offset而不是None登记的区域被转换,使得对基地址+ N的访问映射到N +偏移。 注册为offsetNone的区域不会被翻译。 与同一Region注册的AddressSpace对象不能重叠,但同一Region可以注册多次。 AddressSpace还提供了创建Pool对象的方法。

PoolAddressSpace的扩展,支持MemoryRegions的动态分配。 它使用标准的内存管理算法来提供所请求大小的自然对齐的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:交易ID
    • bresp:写响应
    • 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:附加边带数据

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/621869.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

企业异地访问办公系统:对比运营商MPLS专线,内网穿透有何优势?

为了实现连锁门店、企业内部各地分支机构ERP、OA、远程监控、自建邮件服务器、智能网络设备等数据传输、互访,使用运营商专线或是采用内网穿透方案,彼此之间究竟有何区别呢? 简单来说,MPLS专线和普通宽带类似是运营商提供的网络租…

ruoyi后台管理系统部署-2-安装mysql

centos7 mysql 安装 1. 手动安装 安装 首先查看系统是否安装了: rpm -qa|grep mariadb rpm -qa | grep mysql systemctl status mysqld find / -name mysql.cnf卸载自带的 mariadb: rpm -e mariadb-libs-5.5.68-1.el7.x86_64 --nodeps去官网下载 mysql 安装包&…

【数据结构与算法】之数组系列-20240113

这里写目录标题 一、66. 加一二、121. 买卖股票的最佳时机三、136. 只出现一次的数字四、268. 丢失的数字五、350. 两个数组的交集 II 一、66. 加一 简单 给定一个由 整数 组成的 非空 数组所表示的非负整数,在该数的基础上加一。 最高位数字存放在数组的首位&…

NVMe系统内存结构 - PRP与PRP List

NVMe系统内存结构 - PRP与PRP List 1 为什么需要PRP2 PRP3 PRP List4 PRP寻址算法4.1 仅PRP1指向数据4.2 PRP1指向数据,PRP2指向数据4.3 PRP1指向数据,PRP2指向PRP List 本文属于《 NVMe协议基础系列教程》之一,欢迎查看其它文章。 1 为什么…

【C++】“Hello World!“

&#x1f984;个人主页:修修修也 &#x1f38f;所属专栏:C ⚙️操作环境:Visual Studio 2022 ​ 2024.1.14 纪念一下自己编写的第一个C程序 #include<iostream>int main() {/*我的第一个C程序*/std::cout << "Hello world!:>" <<std::endl;ret…

【开发板资料】Arduino NANO 资料分享(引脚分布图、原理图、亮灯程序等)

给出部分参考资料以及来源 引脚分布 PINOUT 来源&#xff1a;Nano | Arduino Documentation https://docs.arduino.cc/hardware/nano PINOUT PINOUT 来源&#xff1a;https://www.tumblr.com/pighixxx/42591353009/arduino-nano-pinout https://www.tumblr.com/pighixxx/…

在关系模式中,如何求所有候选码?

求所有候选码(键)&#xff1a; 根据函数依赖集F&#xff0c;找出L(只在左部传递)、R(只在右部传递)、LR(既出现在左边也出现在右边)找出候选码&#xff0c;候选码一般出现在L处&#xff0c;不可能出现在R处判断在L中找出的候选码是否是唯一候选码&#xff1a; 若L中找出的候选码…

Leetcode 3007. Maximum Number That Sum of the Prices Is Less Than or Equal to K

Leetcode 3007. Maximum Number That Sum of the Prices Is Less Than or Equal to K 1. 解题思路2. 代码实现 题目链接&#xff1a;3007. Maximum Number That Sum of the Prices Is Less Than or Equal to K 1. 解题思路 这一题我的思路上就是一个二分的思路&#xff0c;先…

C++深入学习之STL:1、容器部分

标准模板库STL的组成 主要由六大基本组件组成&#xff1a;容器、迭代器、算法、适配器、函数对象(仿函数)以及空间配置器。 容器&#xff1a;就是用来存数据的&#xff0c;也称为数据结构。 本文要详述的是容器主要如下&#xff1a; 序列式容器&#xff1a;vector、list 关联…

如何使用手机公网远程访问本地群辉Video Station中视频文件【内网穿透】

最近&#xff0c;我发现了一个超级强大的人工智能学习网站。它以通俗易懂的方式呈现复杂的概念&#xff0c;而且内容风趣幽默。我觉得它对大家可能会有所帮助&#xff0c;所以我在此分享。点击这里跳转到网站。 文章目录 1.使用环境要求&#xff1a;2.下载群晖videostation&am…

React 原理

函数式编程 纯函数 reducer 必须是一个纯函数&#xff0c;即没有副作用的函数&#xff0c;不修改输入值&#xff0c;相同的输入一定会有相同的输出不可变值 state 必须是不可变值&#xff0c;否则在 shouldComponentUpdate 中无法拿到更新前的值&#xff0c;无法做性能优化操作…

在 SpringBoot中的WebSocket使用介绍

在 Spring Boot 中&#xff0c;WebSocket 是一种非常有用的通信协议。WebSocket 可以使客户端和服务器之间实现双向通信&#xff0c;而不是传统的单向 HTTP 请求和响应。本文将介绍在 Spring Boot 中如何使用 WebSocket。 添加依赖 在 pom.xml 文件中添加以下依赖&#xff1a;…

【GitHub项目推荐--国外大神复刻暗黑2】【转载】

《暗黑破坏神2》&#xff0c;由顶尖游戏公司暴雪研发&#xff0c;2000 年上市&#xff0c;其资料片 2001 年上市&#xff0c;2D 画面。相信这款游戏已经成为很多人的回忆了&#xff0c;不知道当时是不是也和我一样沉迷于收集套装呢&#xff1f; 这款游戏的剧情设计、画面感都令…

vue3+threejs可视化项目——搭建vue3+ts+antd路由布局(第一步)

文章目录 ⭐前言&#x1f496;vue3系列相关文章 ⭐搭建vue3项目过程&#x1f496; 初始化项目&#x1f496; 添加antd和router依赖&#x1f496; vite配置项映射目录和代理&#x1f496; antd国际化&#x1f496; layout布局封装&#x1f496; vite读取modules目录文件作为路由…

迁移npm包到nexus

背景&#xff1a;外包项目完工后&#xff0c;需要搭建客户开发环境&#xff0c;因此需要将对应的npm开发包迁移到客户nexus 步骤: 1.先从前端工程中的yarn.lock文件中获取组件列表 2.使用python脚本下载组件到本地 3.使用pythons脚本上传npm包到nexus仓库 第2不脚本如下&#…

网络爬虫丨基于scrapy+mysql爬取博客信息并保存到数据库中

文章目录 写在前面实验描述实验框架实验需求 实验内容1.安装依赖库2.创建Scrapy项目3.配置系统设置4.配置管道文件5.连接数据库6.分析要爬取的内容7.编写爬虫文件 运行结果写在后面 写在前面 本期内容&#xff1a;基于scrapymysql爬取博客信息并保存到数据库中 实验需求 ana…

第二十八周:文献阅读笔记(弱监督学习)+ pytorch学习

第二十八周&#xff1a;文献阅读笔记&#xff08;弱监督学习&#xff09; 摘要Abstract1. 弱监督学习1.1. 文献摘要1.2. 引言1.3. 不完全监督1.3.1. 主动学习与半监督学习1.3.2. 通过人工干预1.3.3. 无需人工干预 1.4. 不确切的监督1.5. 不准确的监督1.6. 弱监督学习的创新点 2…

【读书笔记】《重构_改善既有代码的设计》重构的方法论

重构的方法论 标题&#xff1a;【读书笔记】【读书笔记】《重构_改善既有代码的设计》重构的方法论 时间&#xff1a;2024.01.14 作者&#xff1a;耿鬼不会笑 重构是什么? 什么是重构&#xff1a; “重构”这个词既可以用作名词也可以用作动词。 重构&#xff08;名词&…

HandlerInterceptor拦截器 postHandle执行addHeader无效,postHandle执行setStatus无效的解决方案

问题描述 想在postHandle方法里执行addHeader方法来补充一些Header信息&#xff08;如分页信息&#xff09;&#xff0c;但是最后执行却未如期显示 拦截器源码 import com.zhangziwa.practisesvr.utils.response.ResponseContext; import jakarta.servlet.http.HttpServletR…

动态内存管理4大函数的进阶

&#x1d649;&#x1d65e;&#x1d658;&#x1d65a;!!&#x1f44f;&#x1f3fb;‧✧̣̥̇‧✦&#x1f44f;&#x1f3fb;‧✧̣̥̇‧✦ &#x1f44f;&#x1f3fb;‧✧̣̥̇:Solitary-walk ⸝⋆ ━━━┓ - 个性标签 - &#xff1a;来于“云”的“羽球人”。…