Pynq to m_axi HLS IP

** PYNQ Version **
Release 2021_11_18 14a7328
Board 2021_11_18 14a7328 GitHub - Xilinx/PYNQ: Python Productivity for ZYNQ

  • Standard Image
  • Board: Pynq-Z1

What I’m trying to do:

  • Ultimately, I’m trying to make a matrix multiplier HLS IP that can interface with the Pynq platform via jupyter notebooks.
  • Currently, I’m trying to build off of the “AXI_manual_bursts” example HLS program to just read in a portion of memory from DRAM and write it back out. (code is below)

Why I’m trying to do this:

  • I’m trying to do this because I’m trying to work with images that are of size 256x256x3 color spaces and storing all of this data at once… outside of DRAM just wont be possible. So I’m trying to use manual bursts to read portions of DRAM and then write the modified data back to “out” in DRAM. When the IP is done with the data, the Pynq platform should be able to read the final data from “out”.

Problem:

  • Apparently all of the ports are “write-only”

  • My guess is that the HLS platform can’t determine that “out” is actually an HLS IP output for reading purposes? I don’t know.

  • Also, semi off-topic, how do I read the address space for the HLS IP in jupyter notebooks? Not the register_map.

Thanks,
Nick

Also, I’ve since changed my HLS to look like the following:

And I’ve changed my python to look like the following:
image

  • All data is written into HLS “in” input via register 0x10
  • All data is written out of HLS “out” output via register 0x1C

** This leaves me with questions: **

  1. Why do I do a write the same way to input the data to HLS and output the data from HLS? The semantics of the register_map write() are strange to me. I also couldn’t understand how to get read() to work.

  2. Is there a better way to do this? Am I doing this in a recommended way? Is there anything I should do differently?

Thank you,
Nick

Hi @NNUT,

Did you review this tutorial?

What you see in the register map is the control register of your IP. in and out are write-only arguments in your accelerator from the point of view of the PS. So, you need to pass a reference to memory where you want to read/write. Once you start your IP, it will issue transactions to read/write from memory independently from the PS.

From the tutorial above: To be really clear, a (in your case in and out) will be an AXI Master interface, but we can write the memory offset to a register on the AXI Slave interface…

These arguments are write-only and you should not read from them.

  • All data is written into HLS “in” input via register 0x10
  • All data is written out of HLS “out” output via register 0x1C

This is not correct, you are only writing the reference (physical address) where that data is allocated.

  • Also, semi off-topic, how do I read the address space for the HLS IP in jupyter notebooks? Not the register_map.

I suppose you mean the result (out) of your IP. The data will be available in the output buffer you allocate in the Python code.

  1. Why do I do a write the same way to input the data to HLS and output the data from HLS? The semantics of the register_map write() are strange to me. I also couldn’t understand how to get read() to work.

Refer to the tutorial and answer above (4th paragraph).

  1. Is there a better way to do this? Am I doing this in a recommended way? Is there anything I should do differently?

This is the correct way, but I think your understanding of how this works is not correct.

Mario

1 Like

Hi @marioruiz,

Thank you so much for your detailed response and for your help!

I think you’re right, I have a lack of understanding of the m_axi interface. I’ve read the following page: Documentation Portal but… I don’t think it was enough to fully understand what is going on (or I missed something).

I referenced the tutorial from here: PYNQ_tutorials/hls_m_axi_example.ipynb at master · cathalmccabe/PYNQ_tutorials · GitHub

I did read that tutorial but I missed some things:

  • the meaning of “offset=slave” as explained in the tutorial
  • the meaning of not including the offset for m_axi ports

Blockquote
What you see in the register map is the control register of your IP. in and out are write-only arguments in your accelerator from the point of view of the PS. So, you need to pass a reference to memory where you want to read/write. Once you start your IP, it will issue transactions to read/write from memory independently from the PS.

Why would “in” and “out” be write-only from the point of view of the ps if m_axi has separate read and write lines? Is this because “in” and “out” are connected via “s_axilite” interfaces as well? Just curious, which part of the tutorial is passing a memory references where you want to read/write? Is it this: “my_ip.register_map.a_1 = py_buffer.physical_address”? Also does this mean that “py_buffer” in the tutorial is a buffer used for writing to and reading from memory? I just don’t want to assume things.

Blockquote
From the tutorial above: To be really clear, a (in your case in and out) will be an AXI Master interface, but we can write the memory offset to a register on the AXI Slave interface…

I’m sorry to ask such a trivial question but how do you do this? When you allocate a buffer, is this automatically invoked on the AXI slave interface?

Thank you so much for your help! It means a lot!
Nick

Hi,

  • the meaning of “offset=slave” as explained in the tutorial
  • the meaning of not including the offset for m_axi ports

I suggest you read the pragma documentation.

Why would “in” and “out” be write-only from the point of view of the ps if m_axi has separate read and write lines?

These arguments are being mapped to AXI4-Lite

Just curious, which part of the tutorial is passing a memory references where you want to read/write? Is it this: “my_ip.register_map.a_1 = py_buffer.physical_address”?

Yes.

Also does this mean that “py_buffer” in the tutorial is a buffer used for writing to and reading from memory?

Yes, if you check the code you can see this.

When you allocate a buffer, is this automatically invoked on the AXI slave interface?

No, you need to pass the memory reference to the IP.

Mario