# Double array

**URL:** <https://discuss.pynq.io/t/double-array/4456>\
**Category:** Support\
**Created:** [July 13, 2022, 6:45pm UTC](https://discuss.pynq.io/t/double-array/4456 "2022-07-13T18:45:27Z")\
**Posts on this page:** 16\
**Page:** 1

<div class="post-metadata">

**Author:** ![alienflip](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.pynq.io/alienflip/32/3408_2.png) [@alienflip](https://discuss.pynq.io/u/alienflip)\
**Post date:** [July 13, 2022, 6:45pm UTC](https://discuss.pynq.io/t/double-array/4456/1 "2022-07-13T18:45:27Z")

</div>

Hey 🙂

So I am using vivado/vitis 2022.2, and have been messing around with a project which I thought would extend [this example](https://pp4fpgas.readthedocs.io/en/latest/axidma.html) a little, since the original works very nicely (for me):

The idea is it will just add two vectors together pairwise.

```auto
#include "ap_axi_sdata.h"
#include "hls_stream.h"

typedef ap_axiu<32, 0, 0, 0> trans_pkt;

void ssmul(hls::stream< trans_pkt > &INPUT0, hls::stream< trans_pkt > &INPUT1, hls::stream< trans_pkt > &OUTPUT)
{
        #pragma HLS INTERFACE axis port=INPUT0
        #pragma HLS INTERFACE axis port=INPUT1
        #pragma HLS INTERFACE axis port=OUTPUT
        trans_pkt data_p;
        trans_pkt data_q;
        trans_pkt data_r;
        
        INPUT0.read(data_p);
        INPUT1.read(data_q);

        data_r.data = data_p.data + data_q.data;
        OUTPUT.write(data_r);
}

```

And for the design, my plan was to run automation on the following config:

 ![design_1](https://us1.discourse-cdn.com/flex019/uploads/pynq1/original/2X/e/e547db4663c6e5e93b3abe68a903cb01821c9e4f.jpeg)

It compiles nicely all the way through, but stalls in jupyter ☹

This is the notebook:

```auto
import time, random, numpy
from pynq import Overlay, allocate, MMIO
import pynq.lib.dma

ol = Overlay('./design_1.bit')
ol.download()

dma0 = ol.axi_dma_0
dma1 = ol.axi_dma_1

length = 10

in_buffer0 = allocate(shape=(length,), dtype=numpy.int32) 
in_buffer1 = allocate(shape=(length,), dtype=numpy.int32)
out_buffer = allocate(shape=(length,), dtype=numpy.int32) 

samples = random.sample(range(0, length), length)
numpy.copyto(in_buffer0, samples)
numpy.copyto(in_buffer1, samples)
numpy.copyto(out_buffer, samples)

t_start = time.time()
dma0.sendchannel.transfer(in_buffer0)
dma1.sendchannel.transfer(in_buffer1)
dma0.recvchannel.transfer(out_buffer)
dma0.sendchannel.wait()
dma1.sendchannel.wait()
dma0.recvchannel.wait()
t_stop = time.time()

in_buffer0.close()
in_buffer1.close()
out_buffer.close()

print(t_start - t_stop)

```

Any one got any ideas?

---

<div class="post-metadata">

**Author:** ![cathalmccabe](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.pynq.io/cathalmccabe/32/3348_2.png) [@cathalmccabe](https://discuss.pynq.io/u/cathalmccabe)\
**Post date:** [July 13, 2022, 9:16pm UTC](https://discuss.pynq.io/t/double-array/4456/2 "2022-07-13T21:16:04Z")

</div>

It would be helpful if you could post the block design after you completed the design to make sure the problem isn’t there/that there isn’t another problem there.

In this case it looks like a problem with your HLS code. You are not setting “LAST” which means the DMA transactions don’t complete.

Cathal

---

<div class="post-metadata">

**Author:** ![alienflip](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.pynq.io/alienflip/32/3408_2.png) [@alienflip](https://discuss.pynq.io/u/alienflip)\
**Post date:** [July 13, 2022, 9:28pm UTC](https://discuss.pynq.io/t/double-array/4456/3 "2022-07-13T21:28:47Z")

</div>

Ace 🙂

About setting `LAST`, in this example … does this look right?

```auto
#include "ap_axi_sdata.h"
#include "hls_stream.h"

typedef ap_axiu<32, 0, 0, 0> trans_pkt;

void ssmul(hls::stream< trans_pkt > &INPUT0, hls::stream< trans_pkt > &INPUT1, hls::stream< trans_pkt > &OUTPUT)
{
        #pragma HLS INTERFACE axis port=INPUT0
        #pragma HLS INTERFACE axis port=INPUT1
        #pragma HLS INTERFACE axis port=OUTPUT
        trans_pkt data_p;
        trans_pkt data_q;
        trans_pkt data_r;
        
        INPUT0.read(data_p);
        INPUT1.read(data_q);

        data_r.data = data_p.data + data_q.data;
        OUTPUT.write(data_r);

        if(data_r.last){
        	return;
        }
}

```

?

Also, here is the final block design 🙂

 ![design_1](https://us1.discourse-cdn.com/flex019/uploads/pynq1/original/2X/4/4c11707330be790c665865564c66ae6d17441df9.jpeg)

K

---

<div class="post-metadata">

**Author:** ![briansune](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.pynq.io/briansune/32/3087_2.png) [@briansune](https://discuss.pynq.io/u/briansune)\
**Post date:** [July 13, 2022, 10:59pm UTC](https://discuss.pynq.io/t/double-array/4456/4 "2022-07-13T22:59:46Z")

</div>

@alienflip

Can u expand the signal of the HLS IP block to show us the signals that are generate is correct.  
Apart from your HLS design, at minimum case the interface signals need to be correct.

Thank you

---

<div class="post-metadata">

**Author:** ![alienflip](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.pynq.io/alienflip/32/3408_2.png) [@alienflip](https://discuss.pynq.io/u/alienflip)\
**Post date:** [July 13, 2022, 11:10pm UTC](https://discuss.pynq.io/t/double-array/4456/5 "2022-07-13T23:10:21Z")

</div>

Here it is as a hierarchy in .pdf, with expansions:

[design\_1.pdf](https://discuss.pynq.io/uploads/short-url/oj1Ekxwo67hzajn8u2wr2ahsu39.pdf) (63.0 KB)

On a side note; after some testing, I am sure that it is the line of code

```auto
dma0.recvchannel.wait()

```

which is causing the stall … not sure what to do with that information, though 😅

---

<div class="post-metadata">

**Author:** ![briansune](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.pynq.io/briansune/32/3087_2.png) [@briansune](https://discuss.pynq.io/u/briansune)\
**Post date:** [July 13, 2022, 11:24pm UTC](https://discuss.pynq.io/t/double-array/4456/6 "2022-07-13T23:24:18Z")

</div>

@alienflip  
In short there are tlast signal invoked during HLS.

 ![image](https://us1.discourse-cdn.com/flex019/uploads/pynq1/original/2X/3/38efda3921501266436157955b67e8c5db16877e.png)

However this is all related to the HLS design now.  
Debug using System-ILA via AXI-stream.

As previous post and this post already mentioned.  
DMA will only complete via tlast or data return # is met.

Try learning from this example:

> [@MNIST + AXI Stream on PYNQ 2.7 (Attention to Details)](https://discuss.pynq.io/t/mnist-axi-stream-on-pynq-2-7-attention-to-details/4267):
>
> Hello PYNQ community: I wish you all doing great =] Previous support posts are having trouble on AXI stream HLS about CNN design and DMA: So I am going to share the details on 2020.2 HLS tool and PYNQ 2.7 design. The Github Repository Link for this tutorial: HLS AXI Stream People keep asking about tlast is missing, which this is common that after version (not sure when) the structure C no longer interpret as we expected: Old struct AXI\_DMA\_IO{ ap\_int\<16\> data; ap\_int\<1\>last; }; New #in…

---

<div class="post-metadata">

**Author:** ![alienflip](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.pynq.io/alienflip/32/3408_2.png) [@alienflip](https://discuss.pynq.io/u/alienflip)\
**Post date:** [July 13, 2022, 11:32pm UTC](https://discuss.pynq.io/t/double-array/4456/7 "2022-07-13T23:32:58Z")

</div>

Cool thanks!

Not sure I understand what you mean though, this all seems very like advanced NN stuff which my smooth brain can’t fathom!

Could you point out where exactly to execute the fix in my example? I know once I see how `tlast` works one time in a simple example like this, it will stick 🙂

---

<div class="post-metadata">

**Author:** ![briansune](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.pynq.io/briansune/32/3087_2.png) [@briansune](https://discuss.pynq.io/u/briansune)\
**Post date:** [July 14, 2022, 2:09am UTC](https://discuss.pynq.io/t/double-array/4456/8 "2022-07-14T02:09:52Z")

</div>

At the beginning of that tutorial it had mention how AXI-stream define, while the tutorial of cathalmccabe also provide a good tutorial however different case had different signal interface so you can learn two different case on those two tutorial. Even it is a NN example it is still following the same AXI-Stream protocol as this is a very basic and standard protocol.

As I had mentioned interface-wise is good, so you got to debug why data are not flowing out to trigger the tlast.

---

<div class="post-metadata">

**Author:** ![alienflip](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.pynq.io/alienflip/32/3408_2.png) [@alienflip](https://discuss.pynq.io/u/alienflip)\
**Post date:** [July 14, 2022, 2:20am UTC](https://discuss.pynq.io/t/double-array/4456/9 "2022-07-14T02:20:44Z")

</div>

I read through @cathalmccabe tutorial, and it suggests to do something like:

```auto
#include "ap_axi_sdata.h"
#include "hls_stream.h"

typedef ap_axiu<32, 2, 5, 6> pkt;

void ssmul(hls::stream< pkt > &INPUT0, hls::stream< pkt > &INPUT1, hls::stream< pkt > &OUTPUT)
{
#pragma hls interface s_axilite port=return
#pragma HLS INTERFACE axis port=INPUT0
#pragma HLS INTERFACE axis port=INPUT1
#pragma HLS INTERFACE axis port=OUTPUT

	pkt data_p;
	pkt data_q;
	pkt data_r;

	while(1){
		INPUT0.read(data_p);
		INPUT1.read(data_q);

		data_r.data = data_p.data.to_int() + data_q.data.to_int();
		OUTPUT.write(data_r);

		if(data_r.last){
			break;
		}
	}
}

```

Which I have now tried aswell … it results in an identical stall ☹

This is the block design:

[design\_1.pdf](https://discuss.pynq.io/uploads/short-url/oj1Ekxwo67hzajn8u2wr2ahsu39.pdf) (63.0 KB)

Gonna sleep for a bit! But thanks for the help so far 🙂

---

<div class="post-metadata">

**Author:** ![mizan](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.pynq.io/mizan/32/2119_2.png) [@mizan](https://discuss.pynq.io/u/mizan)\
**Post date:** [July 14, 2022, 5:19am UTC](https://discuss.pynq.io/t/double-array/4456/10 "2022-07-14T05:19:12Z")

</div>

First of all, there is no assignment to data\_r.last, so how it ever be true I don’t get it. You have to assign data\_r.tlast to 1 at a certain time and write the data to the output afterward.  
Another thing, you should debug your Vivado project using ILA to see where it went wrong.

---

<div class="post-metadata">

**Author:** ![pynqzen](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.pynq.io/pynqzen/32/97_2.png) [@pynqzen](https://discuss.pynq.io/u/pynqzen)\
**Post date:** [July 14, 2022, 6:32am UTC](https://discuss.pynq.io/t/double-array/4456/11 "2022-07-14T06:32:02Z")

</div>

Hi,

Just to expand a little here on what @mizan kindly stated. For your output HLS stream data\_r you need to set data\_r.last to a bool false until it is the last one. For just the last data chunk you need to set data\_r.last to bool true. You’re using C++ so bool is a valid data type here, if you like, 1 or 0 also works. When the .last member is set appropriately and the DMA wired properly it should work.

In your latest source example, if the input data streams data\_p or data\_q have a proper .last set in them, you could assign data\_r.last = data\_p.last and that would also work.

Kind regards

---

<div class="post-metadata">

**Author:** ![marioruiz](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.pynq.io/marioruiz/32/2177_2.png) [@marioruiz](https://discuss.pynq.io/u/marioruiz)\
**Post date:** [July 14, 2022, 7:52am UTC](https://discuss.pynq.io/t/double-array/4456/12 "2022-07-14T07:52:14Z")

</div>

Hi,

Don’t forget to set keep as well, otherwise the design may not work.

Mario

---

<div class="post-metadata">

**Author:** ![cathalmccabe](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.pynq.io/cathalmccabe/32/3348_2.png) [@cathalmccabe](https://discuss.pynq.io/u/cathalmccabe)\
**Post date:** [July 14, 2022, 7:55am UTC](https://discuss.pynq.io/t/double-array/4456/13 "2022-07-14T07:55:34Z")

</div>

I didn’t realise my first post wasn’t clear enough.  
@pynqzen and @mizan have given the answer above. (Thanks to you both 🙂 )  
To be really clear, and in case it helps someone else, you can set last like this (or similar):

```auto
void ssmul(hls::stream< trans_pkt > &INPUT0, hls::stream< trans_pkt > &INPUT1, hls::stream< trans_pkt > &OUTPUT)
{
        #pragma HLS INTERFACE axis port=INPUT0
        #pragma HLS INTERFACE axis port=INPUT1
        #pragma HLS INTERFACE axis port=OUTPUT
        trans_pkt data_p;
        trans_pkt data_q;
        trans_pkt data_r;
        
        INPUT0.read(data_p);
        INPUT1.read(data_q);

        data_r.data = data_p.data + data_q.data;
        data_r.last = data_p.last; // Set LAST
        OUTPUT.write(data_r);
}

```

If you have the same number of inputs as outputs you can just assign the value of last for one of the inputs to the last of the output. If you have a different number of inputs to outputs you would add some extra code to calculate when to set last.

In this example, your two input vectors should be the same length so you could set last equal to the value of last for either inputs. You could also do an AND or an OR of the two LAST values if you wanted to but an AND may cause your design to stall if you send the wrong inputs. An OR would cause the transaction to complete early if one of the inputs was too short.

One other point, you should really be simulating designs like this to test them. Either C simulation or RTL simulation. This should help resolve problems like this.

Cathal

---

<div class="post-metadata">

**Author:** ![alienflip](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.pynq.io/alienflip/32/3408_2.png) [@alienflip](https://discuss.pynq.io/u/alienflip)\
**Post date:** [July 14, 2022, 10:37am UTC](https://discuss.pynq.io/t/double-array/4456/14 "2022-07-14T10:37:19Z")

</div>

Wow, thanks for the suggestions all! Learning a lot here 🙂

So taking a combination of advice from above, I put this together:

```auto
#include "ap_axi_sdata.h"
#include "hls_stream.h"

typedef ap_axiu<32, 1, 1, 1> pkt;

void ssmul(hls::stream< pkt > &INPUT0, hls::stream< pkt > &INPUT1, hls::stream< pkt > &OUTPUT, ap_int<32> constant0, ap_int<32> constant1)
{
#pragma HLS interface s_axilite port=constant0
#pragma HLS interface s_axilite port=constant1
#pragma HLS INTERFACE axis port=INPUT0
#pragma HLS INTERFACE axis port=INPUT1
#pragma HLS INTERFACE axis port=OUTPUT

	pkt data_p;
	pkt data_q;
	pkt data_r;

	while(1){
		INPUT0.read(data_p);
		INPUT1.read(data_q);

		data_r.data = data_p.data + data_q.data;
        data_r.dest = data_p.dest;
        data_r.id = data_p.id;
        data_r.keep = data_p.keep;
        data_r.last = data_p.last;
        data_r.strb = data_p.strb;
        data_r.user = data_p.user;

		OUTPUT.write(data_r);

		if(data_r.last){
			break;
		}
	}
}

```

The vitis output produced:  
 ![output](https://us1.discourse-cdn.com/flex019/uploads/pynq1/original/2X/e/ec670eac444cb2613a371b63ed97cf17fa71960d.png)  
and

```auto
// ==============================================================
// Vitis HLS - High-Level Synthesis from C, C++ and OpenCL v2022.1 (64-bit)
// Tool Version Limit: 2022.04
// Copyright 1986-2022 Xilinx, Inc. All Rights Reserved.
// ==============================================================
// control
// 0x00 : reserved
// 0x04 : reserved
// 0x08 : reserved
// 0x0c : reserved
// 0x10 : Data signal of constant0
// bit 31~0 - constant0[31:0] (Read/Write)
// 0x14 : reserved
// 0x18 : Data signal of constant1
// bit 31~0 - constant1[31:0] (Read/Write)
// 0x1c : reserved
// (SC = Self Clear, COR = Clear on Read, TOW = Toggle on Write, COH = Clear on Handshake)

#define XSSMUL_CONTROL_ADDR_CONSTANT0_DATA 0x10
#define XSSMUL_CONTROL_BITS_CONSTANT0_DATA 32
#define XSSMUL_CONTROL_ADDR_CONSTANT1_DATA 0x18
#define XSSMUL_CONTROL_BITS_CONSTANT1_DATA 32

```

The vivado block design finished as followed:  
[design\_1.pdf](https://discuss.pynq.io/uploads/short-url/pImzAmvmnDfKqmNS7AKzM9u1G8X.pdf) (109.1 KB)

In my notebook, I tried:

```auto
from pynq import Overlay, allocate
import pynq.lib.dma
import time, random, numpy

ol = Overlay('./design_1.bit')
ol.download()

CONST0_ADDRESS = 0x10
CONST1_ADDRESS = 0x18
ip = ol.ssmul_0
dma0 = ol.axi_dma_0
dma1 = ol.axi_dma_1

length = 100

in_buffer0 = allocate(shape=(length,), dtype=numpy.int32) 
in_buffer1 = allocate(shape=(length,), dtype=numpy.int32)
out_buffer_silicon = allocate(shape=(length,), dtype=numpy.int32) 

samples0 = random.sample(range(0, length), length)
samples1 = random.sample(range(0, length), length)
zeros = numpy.zeros((length,), dtype=int)

numpy.copyto(in_buffer0, samples0)
numpy.copyto(in_buffer1, samples1)
numpy.copyto(out_buffer_silicon, zeros)
ip.write(CONST0_ADDRESS, 1)
ip.write(CONST1_ADDRESS, 1)

t_start = time.time()
dma0.sendchannel.transfer(in_buffer0)
dma1.sendchannel.transfer(in_buffer1)
dma0.recvchannel.transfer(out_buffer_silicon)
dma0.sendchannel.wait()
dma1.sendchannel.wait()
dma0.recvchannel.wait()
t_stop = time.time()

in_buffer0.close()
in_buffer1.close()
out_buffer_silicon.close()

print("Hardware execution speed: ", t_stop - t_start)
print("Array out: ", out_buffer_silicon)

```

And it works! Thanks everyone 🙂

---

<div class="post-metadata">

**Author:** ![cathalmccabe](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.pynq.io/cathalmccabe/32/3348_2.png) [@cathalmccabe](https://discuss.pynq.io/u/cathalmccabe)\
**Post date:** [July 14, 2022, 12:21pm UTC](https://discuss.pynq.io/t/double-array/4456/15 "2022-07-14T12:21:29Z")

</div>

Great, and thanks for posting back your solution and letting us know it works for you.

Cathal

---

<div class="post-metadata">

**Author:** ![marioruiz](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.pynq.io/marioruiz/32/2177_2.png) [@marioruiz](https://discuss.pynq.io/u/marioruiz)\
**Post date:** [July 14, 2022, 1:44pm UTC](https://discuss.pynq.io/t/double-array/4456/16 "2022-07-14T13:44:28Z")

</div>


