读取写入内存 space
Read Write to Memory space
我正在尝试将一个 Signed Double 数写入内存并读回相同的数字,回读是多余的,因为它只是为了在触发 PL(可编程逻辑)FPGA 之前验证内存中的数据是否正确Fabric 以访问此数据并执行任务。
我将一个文件读入 double(联合的一部分),然后通过 unsigned long(联合的一部分)写入内存。但是写入内存前和读出后的数据是错误的,只是最后一个字节。 (详见代码和注释)
union floatpun {
double dw;
unsigned long lw;
};
void *lookup_slave_by_phy_addr(const int fd, const off_t target, const size_t mapsize)
{
void *map_base, *virt_addr;
/* Map one page */
map_base = mmap(0, mapsize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, target & ~(mapsize-1));
if (map_base == (void *) -1) { FATAL; }
printf("Memory mapped at address %p.\n", map_base);
fflush(stdout);
virt_addr = map_base + (target & (mapsize-1));
return virt_addr;
}
int main(int argc, char *argv[])
{
union floatpun conv;
FILE *fp;
fp = fopen("/media/card/numbers.txt", "r");
fscanf(fp,"%lf",&conv.dw); // 0.009101592004299160 Reads this number from the file, which is correct as expected.
printf("The value Read from the File is %lx \n",conv.lw); // Prints 3f 82 a3 da ff ff ff fe, which is also correct.
fclose(fp);
int fd;
if ((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1) { FATAL; }
printf("/dev/mem opened.\n");
fflush(stdout);
void *weights;
// Map systemMemory master phy address range 0000 0008 7000 0000 -> 0000 0008 7FFF FFFF
weights = lookup_slave_by_phy_addr(fd,strtoul("0x0000000870000000",0,0),MAP_SIZE_256M);
*((unsigned char *) (weights+0x00)) = conv.lw; // Writing into the mempory
SysMem= *((unsigned char *) (weights+0x00)); // Reading it out from the memory
printf("Read %lx\n", SysMem); // When this is printed I get only FE, the last byte of the data read from the file, I have read the following 0x01, 02 03 also, which are all junk data like 0x69 0x95 0x9A
close(fd);
return 0;
}
我写内存或读内存哪里出错了,我要把这个完整的64位写入内存。或者我应该手动将每个字节写入一个内存字节,内存字(32 位)是否可寻址?或者如果不能,我可以把它变成一个可寻址的词吗?
此外,这是在带有 Petalinux 的 Zynq 上完成的
请帮忙:)
你的问题在这里:
*((unsigned char *) (weights+0x00)) = conv.lw; // Writing into the mempory
SysMem= *((unsigned char *) (weights+0x00)); // Reading it out from the memory
您将 (void *) weights
转换为 (unsigned char *)
,然后将 conv.lw
的值存储在该指针位置。
但是通过这样做 type-cast,你已经明确地告诉你的编译器你只想写一个 unsigned char
,所以它很乐意用 conv.lw
的 least-significant 字节来做到这一点].
同样,当您读回它时,您再次将 weights
转换为 (unsigned char *)
,因此您只从该位置读取一个字节。
如果您改为执行以下操作:
*((unsigned long *) (weights+0x00)) = conv.lw; // Writing into the mempory
SysMem= *((unsigned long *) (weights+0x00)); // Reading it out from the memory
您将写入和读取 conv.lw
的所有字节。
还有一些原因会导致您尝试执行此操作 non-portable,包括:unsigned long
在 32 位架构上通常只有 4 个字节,并且解引用指针强制转换来自其他类型的是(至少有时)未定义的行为。
赋值 *((unsigned char *) (weights+0x00)) = conv.lw;
只写一个 unsigned char
,而 SysMem= *((unsigned char *) (weights+0x00));
只读一个 unsigned char
.
要写入和读取 double
,请使用:
* (double *) weights = conv.dw;
double x = * (double *) weights;
printf("%a\n", x); // Or use %g or %f.
或:
memcpy(weights, conv.dw, sizeof conv.dw);
double x;
memcpy(x, weights, sizeof x);
printf("%a\n", x); // Or use %g or %f.
第一种方法要求 weights
与您的平台适当对齐(看起来它会在您的示例代码中)。此代码不应直接存在别名问题,因为 conv.dw
是作为其正确类型 (double
) 访问的,并且 weights
实际上是一个动态分配的对象(提供获取其值的代码是正确的,并且大概你的编译器支持这个),因此通过向那里写入 double
可以在 weights
处有效地创建 double
。
如果 weights
中的地址在您的进程中可以正确访问,那么无论对齐如何,第二种方法都应该有效。
无论哪种情况,都不需要联合。 double
可以直接使用,无需使用 unsigned long
.
作为别名
我正在尝试将一个 Signed Double 数写入内存并读回相同的数字,回读是多余的,因为它只是为了在触发 PL(可编程逻辑)FPGA 之前验证内存中的数据是否正确Fabric 以访问此数据并执行任务。
我将一个文件读入 double(联合的一部分),然后通过 unsigned long(联合的一部分)写入内存。但是写入内存前和读出后的数据是错误的,只是最后一个字节。 (详见代码和注释)
union floatpun {
double dw;
unsigned long lw;
};
void *lookup_slave_by_phy_addr(const int fd, const off_t target, const size_t mapsize)
{
void *map_base, *virt_addr;
/* Map one page */
map_base = mmap(0, mapsize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, target & ~(mapsize-1));
if (map_base == (void *) -1) { FATAL; }
printf("Memory mapped at address %p.\n", map_base);
fflush(stdout);
virt_addr = map_base + (target & (mapsize-1));
return virt_addr;
}
int main(int argc, char *argv[])
{
union floatpun conv;
FILE *fp;
fp = fopen("/media/card/numbers.txt", "r");
fscanf(fp,"%lf",&conv.dw); // 0.009101592004299160 Reads this number from the file, which is correct as expected.
printf("The value Read from the File is %lx \n",conv.lw); // Prints 3f 82 a3 da ff ff ff fe, which is also correct.
fclose(fp);
int fd;
if ((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1) { FATAL; }
printf("/dev/mem opened.\n");
fflush(stdout);
void *weights;
// Map systemMemory master phy address range 0000 0008 7000 0000 -> 0000 0008 7FFF FFFF
weights = lookup_slave_by_phy_addr(fd,strtoul("0x0000000870000000",0,0),MAP_SIZE_256M);
*((unsigned char *) (weights+0x00)) = conv.lw; // Writing into the mempory
SysMem= *((unsigned char *) (weights+0x00)); // Reading it out from the memory
printf("Read %lx\n", SysMem); // When this is printed I get only FE, the last byte of the data read from the file, I have read the following 0x01, 02 03 also, which are all junk data like 0x69 0x95 0x9A
close(fd);
return 0;
}
我写内存或读内存哪里出错了,我要把这个完整的64位写入内存。或者我应该手动将每个字节写入一个内存字节,内存字(32 位)是否可寻址?或者如果不能,我可以把它变成一个可寻址的词吗?
此外,这是在带有 Petalinux 的 Zynq 上完成的
请帮忙:)
你的问题在这里:
*((unsigned char *) (weights+0x00)) = conv.lw; // Writing into the mempory
SysMem= *((unsigned char *) (weights+0x00)); // Reading it out from the memory
您将 (void *) weights
转换为 (unsigned char *)
,然后将 conv.lw
的值存储在该指针位置。
但是通过这样做 type-cast,你已经明确地告诉你的编译器你只想写一个 unsigned char
,所以它很乐意用 conv.lw
的 least-significant 字节来做到这一点].
同样,当您读回它时,您再次将 weights
转换为 (unsigned char *)
,因此您只从该位置读取一个字节。
如果您改为执行以下操作:
*((unsigned long *) (weights+0x00)) = conv.lw; // Writing into the mempory
SysMem= *((unsigned long *) (weights+0x00)); // Reading it out from the memory
您将写入和读取 conv.lw
的所有字节。
还有一些原因会导致您尝试执行此操作 non-portable,包括:unsigned long
在 32 位架构上通常只有 4 个字节,并且解引用指针强制转换来自其他类型的是(至少有时)未定义的行为。
赋值 *((unsigned char *) (weights+0x00)) = conv.lw;
只写一个 unsigned char
,而 SysMem= *((unsigned char *) (weights+0x00));
只读一个 unsigned char
.
要写入和读取 double
,请使用:
* (double *) weights = conv.dw;
double x = * (double *) weights;
printf("%a\n", x); // Or use %g or %f.
或:
memcpy(weights, conv.dw, sizeof conv.dw);
double x;
memcpy(x, weights, sizeof x);
printf("%a\n", x); // Or use %g or %f.
第一种方法要求 weights
与您的平台适当对齐(看起来它会在您的示例代码中)。此代码不应直接存在别名问题,因为 conv.dw
是作为其正确类型 (double
) 访问的,并且 weights
实际上是一个动态分配的对象(提供获取其值的代码是正确的,并且大概你的编译器支持这个),因此通过向那里写入 double
可以在 weights
处有效地创建 double
。
如果 weights
中的地址在您的进程中可以正确访问,那么无论对齐如何,第二种方法都应该有效。
无论哪种情况,都不需要联合。 double
可以直接使用,无需使用 unsigned long
.