Читать запись в память - PullRequest
1 голос
/ 23 мая 2019

Я пытаюсь записать число с двойной подписью в память и прочитать то же самое, чтение излишне, поскольку оно просто проверяет, есть ли в памяти правильные данные, прежде чем я запускаю матрицу PL (программируемая логика) FPGA дляполучить доступ к этим данным и выполнить задачу.

Я читаю файл в 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 бита)?или, если нет, могу ли я сделать это слово адресуемым?

Кроме того, это делается на Zynq с Petalinux

Пожалуйста, помогите:)

Ответы [ 2 ]

1 голос
/ 23 мая 2019

Ваша проблема здесь:

    *((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 в этом месте указателя.
Но, делаяПри приведении типа вы явно сказали своему компилятору, что вы хотите написать только один unsigned char, так что он довольно счастливо делает это с младшим байтом conv.lw.
Аналогично, когда вы читаете егоназад, вы снова разыгрываете 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.

Есть также несколько причин, по которым вы пытаетесь сделать непереносимыми, в том числе: unsigned long - это всего лишь 4 байта в 32-битной архитектуре и разыменование указателей, приведенных из других типов.является (по крайней мере, иногда) неопределенным поведением.

0 голосов
/ 23 мая 2019

Назначение *((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.

...