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:
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)
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.
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.
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:
The value “0x8” in the example you gave refers to the array size?
How do I map the array to the address of the registers?
Can I confirm the array method can be used to read/write register?
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.
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
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.
You can both read and write registers
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.