PYNQ: PYTHON PRODUCTIVITY

Why is the input parameter has 2 addresses?

Hello

I have created an IP with Vitis HLS 2020.2 with the following interface (with the convenient pragmas for better understanding):

void pobj_accel(hls::stream<axis_t> &in_A, hls::stream<axis_t> &in_X, hls::stream<axis_t> &in_Y, hls::stream<axis_t> &out_Z, double lmbda, double pobj)
{
#pragma HLS INTERFACE s_axilite port = return bundle = control
#pragma HLS INTERFACE s_axilite port = lmbda bundle = pobj_port
#pragma HLS INTERFACE s_axilite port = pobj bundle = pobj_port

#pragma HLS INTERFACE axis port = in_A
#pragma HLS INTERFACE axis port = in_X
#pragma HLS INTERFACE axis port = in_Y
#pragma HLS INTERFACE axis port = out_Z

.............
}

I have synthesized the IP successfully and created a block design then generated the bitstream without any problem.
To start the IP and assign the input parameters lmbda and pobj (as output). I had to look for the Adress Info. So I got the following:
control port

//------------------------Address Info-------------------
// 0x0 : 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
// 0x4 : Global Interrupt Enable Register
//       bit 0  - Global Interrupt Enable (Read/Write)
//       others - reserved
// 0x8 : IP Interrupt Enable Register (Read/Write)
//       bit 0  - enable ap_done interrupt (Read/Write)
//       bit 1  - enable ap_ready interrupt (Read/Write)
//       others - reserved
// 0xc : IP Interrupt Status Register (Read/TOW)
//       bit 0  - ap_done (COR/TOW)
//       bit 1  - ap_ready (COR/TOW)
//       others - reserved
// (SC = Self Clear, COR = Clear on Read, TOW = Toggle on Write, COH = Clear on Handshake)

pobj_port

//------------------------Address Info-------------------
// 0x00 : reserved
// 0x04 : reserved
// 0x08 : reserved
// 0x0c : reserved
// 0x10 : Data signal of lmbda
//        bit 31~0 - lmbda[31:0] (Read/Write)
// 0x14 : Data signal of lmbda
//        bit 31~0 - lmbda[63:32] (Read/Write)
// 0x18 : reserved
// 0x1c : Data signal of pobj
//        bit 31~0 - pobj[31:0] (Read/Write)
// 0x20 : Data signal of pobj
//        bit 31~0 - pobj[63:32] (Read/Write)
// 0x24 : reserved
// (SC = Self Clear, COR = Clear on Read, TOW = Toggle on Write, COH = Clear on Handshake)

From this, I understood the following: since my input parameters are of type ‘Double’ it has been divided into 2 registers of 32-bit (Hgh and low). Is this correct?
In that case, how can I assign the input value correctly while having 2 addresses?
This is how I am trying to run the kernel:

from pynq import (allocate, Overlay)
import numpy as np

ol = Overlay('pobj.bit')
pobj_ip = ol.pobj_accel_0
dma_A = ol.axi_dma_A
dma_X = ol.axi_dma_X
dma_Y = ol.axi_dma_Y
dma_Z = ol.axi_dma_Z

M = 64
N = 512

A_buff = allocate(shape=(M, N), dtype=np.float64, cacheable=False)
x_buff = allocate(shape=(N, 1), dtype=np.float64, cacheable=False)
y_buff = allocate(shape=(1, M), dtype=np.float64, cacheable=False)
z_buff = allocate(shape=(1, M), dtype=np.float64, cacheable=False)

CTRL_REG = 0x00
AP_START = (1<<0) # bit 0
AUTO_RESTART = (1<<7) # bit 7

def run_kernel():
    dma_A.sendchannel.transfer(A_buff)
    dma_X.sendchannel.transfer(x_buff)
    dma_Y.sendchannel.transfer(y_buff)
    dma_Z.recvchannel.transfer(z_buff)
    mmult_ip.write(CTRL_REG, (AP_START | AUTO_RESTART))  # initialize the module
    dma_A.sendchannel.wait()
    dma_X.sendchannel.wait()
    dma_Y.sendchannel.wait()
    dma_Z.recvchannel.wait()

How can I assign lmbda and pobj parameters correctly?

You need to bundle all the AXI4-Lite registers to the same bus.

#pragma HLS INTERFACE s_axilite port = return bundle = control
#pragma HLS INTERFACE s_axilite port = lmbda bundle = control
#pragma HLS INTERFACE s_axilite port = pobj bundle = control

Mario

Hello @marioruiz,

I followed your advice and I bundled all the AXI4-Lite registers to the same bus. But, my original issue is not yet solved. Please check the following:

//------------------------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
// 0x04 : Global Interrupt Enable Register
//        bit 0  - Global Interrupt Enable (Read/Write)
//        others - reserved
// 0x08 : IP Interrupt Enable Register (Read/Write)
//        bit 0  - enable ap_done interrupt (Read/Write)
//        bit 1  - enable ap_ready interrupt (Read/Write)
//        others - reserved
// 0x0c : IP Interrupt Status Register (Read/TOW)
//        bit 0  - ap_done (COR/TOW)
//        bit 1  - ap_ready (COR/TOW)
//        others - reserved
// 0x10 : Data signal of lmbda
//        bit 31~0 - lmbda[31:0] (Read/Write)
// 0x14 : Data signal of lmbda
//        bit 31~0 - lmbda[63:32] (Read/Write)
// 0x18 : reserved
// 0x1c : Data signal of pobj
//        bit 31~0 - pobj[31:0] (Read/Write)
// 0x20 : Data signal of pobj
//        bit 31~0 - pobj[63:32] (Read/Write)
// 0x24 : reserved
// (SC = Self Clear, COR = Clear on Read, TOW = Toggle on Write, COH = Clear on Handshake)

the AXI4-Lite signals are mapped on 2 registers (check lmbda for example). So, How can I handle that in python? How can I write the input value into lmbda ?

The AXI4-Lite interface by default uses 32-bit width data path.
You will have to write the LSB and MSB parts of the lmbda and pobj register from python to the corresponding register.

Note that PYNQ does not support floating values in the register map, you will have to make sure to write the correct double precision representation value.

Mario