I am trying to write a Signed Double number to memory and read back the same, reading back is redundant as it is just to verify if the correct data is in the memory before I trigger the PL (programmable logic) FPGA Fabric to access this data and perform a task.
I read a file into a double (part of a union) and then write to memory through the unsigned long (part of a union). But the data before writing into memory and after I read out is wrong, it is just the last byte. (see the code and comments for details)
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;
}
What mistake am I doing in writing to memory or reading from the memory, I want this complete 64 bit written to the memory. Or should I manually write each byte to a byte of memory, arent the memory word (32 Bit) addressable? or if not can I make it a word addressable?
Also, this is being done on Zynq with Petalinux
Please help :)
Your problem is here:
*((unsigned char *) (weights+0x00)) = conv.lw; // Writing into the mempory
SysMem= *((unsigned char *) (weights+0x00)); // Reading it out from the memory
You're casting your (void *) weights
as a (unsigned char *)
, then storing the value of conv.lw
at that pointer location.
But by doing that type-cast, you've explicitly told your compiler that you only want to write a single unsigned char
, so it quite happily does that with the least-significant byte of conv.lw
.
Similarly, when you read it back, you again cast weights
as an (unsigned char *)
and so you're only reading a singe byte form that location.
If you instead did something like:
*((unsigned long *) (weights+0x00)) = conv.lw; // Writing into the mempory
SysMem= *((unsigned long *) (weights+0x00)); // Reading it out from the memory
you'd be writing and reading all the bytes of conv.lw
.
There are also a few reasons which make what you're trying to do non-portable, including: unsigned long
is only typically only 4 bytes on a 32-bit architecture, and dereferencing pointers cast from other types is (at least sometimes) undefined behavior.