PYNQ: PYTHON PRODUCTIVITY

Unable to read back floating-point values when using MMIO read

Hi. I am using PYNQ-Z2 ver 2.6.0. I am trying a variant of the procedures described in Lab: Pynq Memory Mapped IO (s_axilite) — pp4fpgas 0.0.1 documentation by writing and reading floating-point numbers instead of integers. I can read and write integers without problem. When I attempt to read back from any of the defined register, I keep getting integer value. Below are the details:

HLS code:
image

Overlay:

Extracted relevant address info:
//------------------------Address Info-------------------
// 0x00 : Control signals
// bit 0 - ap_start (Read/Write/COH)
// bit 1 - ap_done (Read/COR)
// bit 2 - ap_idle (Read)
// bit 3 - ap_ready (Read)
// bit 7 - auto_restart (Read/Write)
// others - reserved
// 0x10 : Data signal of grid
// bit 31~0 - grid[31:0] (Read)
// 0x14 : Control signal of grid
// bit 0 - grid_ap_vld (Read/COR)
// others - reserved
// 0x20 : Data signal of c1
// bit 31~0 - c1[31:0] (Read/Write)
// 0x28 : Data signal of c2
// bit 31~0 - c2[31:0] (Read/Write)
// 0x30 : Data signal of f_T
// bit 31~0 - f_T[31:0] (Read/Write)
// 0x38 : Data signal of i_DS
// bit 31~0 - i_DS[31:0] (Read/Write)

Python code snippets:

I looked into the read method in mmio.py and it appears the data read out is being type-casted to int. From comments, it is supposed to return a list of data.
image

Can someone advise whether floating-point read back is supported by MMIO or is it I have done something wrong in my environment?

There are a couple of ways of reading/writing floats. One is convert to/from an integer in your code:

f = struct.unpack('f', struct.pack('I', device.read(0x20)))[0]

Alternatively you can cast the entire address space to an array of float and access the registers through that: equivalently

ar = device.mmio.array.view('f')
f = ar[0x8]

Note that in this second way you need use indexes in the array rather than addresses.

You should also do something similar for writing floating point values - .write will also expect an int so floating point values may be converted to integers rather than written out bit-correctly.

Peter

Hi Peter. Thank you for responding to my issue. I tried the first method you suggested and I am able to get the floating-point value as expected. For clarity, below is the code change:
temp = struct.unpack(‘f’, struct.pack(‘I’, calc_grid_ip.read(grid_var_addr)))[0]

I will like to try out your second suggestion as well but I have some questions:

  1. The value “0x8” in the example you gave refers to the array size?
  2. How do I map the array to the address of the registers?
  3. Can I confirm the array method can be used to read/write register?
  4. Can I perform multiple read/write using array assignment?

Regarding my write statements, packing of my float value returns a bytearray which couldn’t get executed. There is explicit check for “int” and “bytes” data type and I ended up in the “else statement” i.e. data type error… I had to cast it to bytes to circumvent the limitation.

  1. The value of 0x8 was the array index corresponding to address 0x20. It was being used as an example to match the previous line of code
  2. The entire register spaces is mapped in mmio.array - the .view just changes what the bits should be interpreted as. The array will be the size of the address space listed in the HWH file.
  3. You can both read and write registers
  4. Yes up to a point. On ZU+ devices in particular you can run into issues if the data you’re writing isn’t aligned properly as that may result in random segfaults. Unless performance is critical I would go for the safer option of writing element by element.

For writing, casting to bytes is a perfectly reasonable solution - or using struct to repack the bytes as an int. I’ll put adding bytearray to the list of things to consider for the next release.

Peter

For 1, may I know how do you come to index ‘0x8’ for address offset ‘0x20’?
For 2, are you referring to the 2 lines below in my HWH file?
image

  1. Divide by 4 as each register word (and hence array element) is four bytes long
  2. Not that exact line but the same information - there’s a MEMORYMAP section elsewhere in the file that aggregates the ranges for all of the IP.

Peter

I tried the second method and it works. I have no further questions and thank you for all the information and clarifications.