从内存中的特定地址开始初始化数组 - C编程
Initialize array starting from specific address in memory - C programming
你知道如何从内存中的特定地址(不是虚拟的物理 DDR 内存)开始初始化结构数组吗?我正在 SoC 上实现 TxRx( ARM-FPGA)。基本上,ARM (PS) 和 FPGA (PL) 通过使用共享 RAM 内存相互通信。目前我在发射器端工作,所以我需要不断地将我从 MAC 层获得的数据包加载到内存中,然后我的 Tx 读取数据并在空中发送。为了实现这一点,我想在(ARM)端实现循环 FIFO 缓冲区,这样我就可以将最多 6 个数据包存储到缓冲区中并一个一个地发送它们,同时在已发送包的位置加载其他数据包。因为我需要使用特定的内存地址,所以我感兴趣的是是否可以初始化将存储在内存中特定地址的结构数组。 例如,我希望我的数组从地址 0x400000 开始到地址 0x400000 + MaximumNumberOfPackets x SizeOfPackets 我知道如何为结构的一个实例执行此操作,例如:
buffer_t *tmp = (结构 buffer_t *)234881024;
但是如何为结构数组做呢?
指向单个结构(或 int、float 或其他任何结构)的指针本质上是指向它们的数组的指针。指针类型为数组条目提供 sizeof() 值,因此允许指针算法工作。
因此,给定一个 struct buffer
你可以简单地做
static struct buffer * const myFIFO = (struct buffer *) 0x40000
然后简单地访问 myFIFO
作为数组
for (size_t i = 0; i < maxPackets; ++i)
{
buffer[i].someField = initialValue1;
buffer[i].someOtherField = 42;
}
这完全符合您的预期。
您不能做的(使用纯标准 C)是在特定地址声明一个数组,如下所示:
struct buffer myFIFO[23] @ 0x400000;
但是,您的编译器可能具有允许它的扩展。许多嵌入式编译器都这样做(毕竟,这通常是它们声明内存映射设备寄存器的方式),但对于每个编译器供应商来说都是不同的,并且可能对于每个芯片来说都是不同的,因为它是供应商扩展。
GCC 通过属性允许 AVR 处理器,例如
volatile int porta __attribute__((address (0x600)));
但是好像不支持ARM。
通常 @kdopen 是正确的,但对于 arm,您应该在 MEMORY 部分链接描述文件中创建一个条目,向链接器显示您的内存在哪里:
MEMORY
{
...
ExternalDDR (w) : ORIGIN = 0x400000, LENGTH = 4M
}
而且,当您声明变量时,只需使用
__attribute__((section("ExternalDDR")))
我找到了方法。我可以这样做吗?我将其设置为链接描述文件:
MEMORY {
ps7_ddr_0_S_AXI_BASEADDR : ORIGIN = 0x00100000, LENGTH = 0x1FF00000
ps7_ram_0_S_AXI_BASEADDR : ORIGIN = 0x00000000, LENGTH = 0x00030000
ps7_ram_1_S_AXI_BASEADDR : ORIGIN = 0xFFFF0000, LENGTH = 0x0000FE00
DAC_DMA (w) : ORIGIN = 0xE000000, LENGTH = 64K
}
.dacdma : {
__dacdma_start = .;
*(.data)
__dacdma_end = .;
} > DAC_DMA
然后我将其设置为代码
static buffer_t __attribute__((section("DAC_DMA"))) buf_pool[6];
你知道如何从内存中的特定地址(不是虚拟的物理 DDR 内存)开始初始化结构数组吗?我正在 SoC 上实现 TxRx( ARM-FPGA)。基本上,ARM (PS) 和 FPGA (PL) 通过使用共享 RAM 内存相互通信。目前我在发射器端工作,所以我需要不断地将我从 MAC 层获得的数据包加载到内存中,然后我的 Tx 读取数据并在空中发送。为了实现这一点,我想在(ARM)端实现循环 FIFO 缓冲区,这样我就可以将最多 6 个数据包存储到缓冲区中并一个一个地发送它们,同时在已发送包的位置加载其他数据包。因为我需要使用特定的内存地址,所以我感兴趣的是是否可以初始化将存储在内存中特定地址的结构数组。 例如,我希望我的数组从地址 0x400000 开始到地址 0x400000 + MaximumNumberOfPackets x SizeOfPackets 我知道如何为结构的一个实例执行此操作,例如: buffer_t *tmp = (结构 buffer_t *)234881024;
但是如何为结构数组做呢?
指向单个结构(或 int、float 或其他任何结构)的指针本质上是指向它们的数组的指针。指针类型为数组条目提供 sizeof() 值,因此允许指针算法工作。
因此,给定一个 struct buffer
你可以简单地做
static struct buffer * const myFIFO = (struct buffer *) 0x40000
然后简单地访问 myFIFO
作为数组
for (size_t i = 0; i < maxPackets; ++i)
{
buffer[i].someField = initialValue1;
buffer[i].someOtherField = 42;
}
这完全符合您的预期。
您不能做的(使用纯标准 C)是在特定地址声明一个数组,如下所示:
struct buffer myFIFO[23] @ 0x400000;
但是,您的编译器可能具有允许它的扩展。许多嵌入式编译器都这样做(毕竟,这通常是它们声明内存映射设备寄存器的方式),但对于每个编译器供应商来说都是不同的,并且可能对于每个芯片来说都是不同的,因为它是供应商扩展。
GCC 通过属性允许 AVR 处理器,例如
volatile int porta __attribute__((address (0x600)));
但是好像不支持ARM。
通常 @kdopen 是正确的,但对于 arm,您应该在 MEMORY 部分链接描述文件中创建一个条目,向链接器显示您的内存在哪里:
MEMORY
{
...
ExternalDDR (w) : ORIGIN = 0x400000, LENGTH = 4M
}
而且,当您声明变量时,只需使用
__attribute__((section("ExternalDDR")))
我找到了方法。我可以这样做吗?我将其设置为链接描述文件:
MEMORY {
ps7_ddr_0_S_AXI_BASEADDR : ORIGIN = 0x00100000, LENGTH = 0x1FF00000
ps7_ram_0_S_AXI_BASEADDR : ORIGIN = 0x00000000, LENGTH = 0x00030000
ps7_ram_1_S_AXI_BASEADDR : ORIGIN = 0xFFFF0000, LENGTH = 0x0000FE00
DAC_DMA (w) : ORIGIN = 0xE000000, LENGTH = 64K
}
.dacdma : {
__dacdma_start = .;
*(.data)
__dacdma_end = .;
} > DAC_DMA
然后我将其设置为代码
static buffer_t __attribute__((section("DAC_DMA"))) buf_pool[6];