HLS IP with AXI4 Master hangs on second run

Hi there,
I’m having some trouble with an HLS IP core that uses an AXI4 master port to access DRAM. It works properly - it modifies memory as expected when run for the first time. However, if I run it a second time, ap_start just stays high and the IP execution never completes. The only way I can unlock it is by reconfiguring the FPGA again.

The HLS code was extracted from GitHub - Xilinx/Vitis-HLS-Introductory-Examples and is as follows:

#include <stdio.h>
#include <string.h>

void example100(volatile int *a){
  
#pragma HLS INTERFACE m_axi port=a depth=50
  
  int i;
  int buff[50];
  
  //memcpy creates a burst access to memory
  //multiple calls of memcpy cannot be pipelined and will be scheduled sequentially
  //memcpy requires a local buffer to store the results of the memory transaction
  memcpy(buff,(const int*)a,50*sizeof(int));
  
  for(i=0; i < 50; i++){
    buff[i] = buff[i] + 100;
  }
  
  memcpy((int *)a,buff,50*sizeof(int));
}

The design is straighforward:

Please ignore the ILA core. The behaviour is exactly the same without this core. I’ve just been inspecting AXI transactions to see if I could find something odd but I didn’t.

Thank you.

Edit:
There is another anomaly in the behaviour of the HLS block: ap_done stays high just after the first run completes. It should stay high just for a clock cycle. I guess that’s the problem. Any clue why this is happening?

1 Like

Hi,

Can you share the python code you are using to run the accelerator?

Mario

Sure, here’s the code:

from pynq import Overlay

ov = Overlay("Config_add.bit")
ov.download()

from pynq import allocate
input_buffer = allocate(shape=(50,), dtype='int')
input_buffer[:] = list(range(50))

ov.example100_0.register_map.a_1 = input_buffer.physical_address
ov.example100_0.register_map.CTRL.AP_START = 1

After running the core like this the register map looks like:

RegisterMap {
  CTRL = Register(AP_START=0, AP_DONE=1, AP_IDLE=1, AP_READY=0, AP_CONTINUE=0, RESERVED_1=0, AUTO_RESTART=0, RESERVED_2=0),
  GIER = Register(Enable=0, RESERVED=0),
  IP_IER = Register(CHAN0_INT_EN=0, CHAN1_INT_EN=0, RESERVED=0),
  IP_ISR = Register(CHAN0_INT_ST=0, CHAN1_INT_ST=0, RESERVED=0),
  a_1 = Register(a=377790464),
  a_2 = Register(a=0)
}

After running the core again by setting AP_START once again the register map looks like:

RegisterMap {
  CTRL = Register(AP_START=1, AP_DONE=1, AP_IDLE=0, AP_READY=0, AP_CONTINUE=0, RESERVED_1=0, AUTO_RESTART=0, RESERVED_2=0),
  GIER = Register(Enable=0, RESERVED=0),
  IP_IER = Register(CHAN0_INT_EN=0, CHAN1_INT_EN=0, RESERVED=0),
  IP_ISR = Register(CHAN0_INT_ST=0, CHAN1_INT_ST=0, RESERVED=0),
  a_1 = Register(a=377790464),
  a_2 = Register(a=0)
}

Thank you,
Gabriel

Hi,

Please provide the following information about your setup

  • board
  • PYNQ SD card image
  • Vitis HLS/Vivado version

This does not seems to be a PYNQ problem, at least in the verified environment. The IP is working for me in a PYNQ-Z2, with PYNQ 2.7 and Vivado 2020.2. I only had to add a few directives to the code

void example100(volatile int *a){
#pragma HLS INTERFACE s_axilite port=a
#pragma HLS INTERFACE s_axilite port=return
  
#pragma HLS INTERFACE m_axi depth=50 port=a

Mario

Hi,
As requested:

  • PYNQ-Z2.
  • PYNQ version 2.6.2 (2.6.0 upgraded to 2.6.2 from the PYNQ Composable Video tutorialhttps://discuss.pynq.io/t/the-composable-video-pipeline/2758),
  • Vitis HLS/Vivado 2020.2

I have tried adding those directives and it still doesn’t work. I will check whether upgrading to 2.7 helps. Anyway, did it work for you as provided? Why did you have to add those directives to get a return port?

Gabriel

Edit: I’ve just tested it and the same thing happens with PYNQ 2.7.