UPGRADE YOUR BROWSER

We have detected your current browser version is not the latest one. Xilinx.com uses the latest web technologies to bring you the best online experience possible. Please upgrade to a Xilinx.com supported browser:Chrome, Firefox, Internet Explorer 11, Safari. Thank you!

Reply
Accepted Solution

Ap_memory tutorial & ILA tutorial

Voyager
Posts: 320
Registered: ‎01-28-2014

Re: Ap_memory tutorial

The auto-generated HDL is tricky to read at best and I can't post my example (it's an actual design and thus proprietary). Provide me the raw HLS code if there's any more and I'll generate an example of yours from my version though.

 

 

 

 

Explorer
Posts: 208
Registered: ‎02-05-2015

Re: Ap_memory tutorial

I tried this and I works :D :D :D

 

That honestly sounds like a bug to me (but I'm not 100% sure, there might be some interactions that I'm not aware of atm) so I guess we'll have you try this:

 

#define BRAM_START_ADDRESS 0x10000000

The result is now 21.000 !!!

 

I'm happy as hell mate!Thank you very much. However, you need to please explain me what was wrong because I did not understood what I need to do in future designs with BRAM controllers.

 

Again, ty very very much

Voyager
Posts: 320
Registered: ‎01-28-2014

Re: Ap_memory tutorial

I'm really glad it worked :) I am however confused as to why the bitshift operator didn't work but oh well, I'm going to attribute that to a 2014.2 bug unless proven otherwise. Now you're asking for what you did wrong, can you be more specific? If you're asking about why your original design didn't work, I couldn't say since I haven't used the Xilinx DMA engine myself though I'm sure it could be made to work.

Explorer
Posts: 208
Registered: ‎02-05-2015

Re: Ap_memory tutorial

[ Edited ]

No mate. I'm just asking what I did wrong in my initial BRAM model.

 

I.e. from here

 

void bram_func(float    *mem, float *result_out){
#pragma HLS INTERFACE m_axi port=mem
#pragma HLS INTERFACE s_axilite port=result_out bundle=BUS_A

    float parameters[4];

    memcpy(&parameters,mem, sizeof(parameters));

    *result_out=parameters[2]+parameters[3];

} 

to here:

 

#define BRAM_START_ADDRESS 0x10000000

/*Example said by jprice in xilinx forum: ap_memory tutorial*/
float bram_func(float    *mem){
#pragma HLS INTERFACE m_axi port=mem

    float parameters[4];

    memcpy(&parameters,&mem[BRAM_START_ADDRESS], sizeof(parameters));

    return parameters[2]+parameters[3];

} 

I mean, I can see both the differences which are:

-Do the mem(BRAM_START_ADDRESS)

-Define the BRAM_START_ADDRESS to divide the bits by 4 with a bitshift.

 

But do I need to do this always when I use a BRAM controller? And also, I have not understood the bitshift very well, even though I read your comment many times now. Can you explain a little better please?

Voyager
Posts: 320
Registered: ‎01-28-2014

Re: Ap_memory tutorial

So the reason a physical address is necessary is due to the way the memory space is setup. The AXI interconnect maps devices that want to access memories to memories. Each memory is assigned an address space (sometimes multiple address spaces) to distinguish them. You setup a block RAM and IPI automatically assigned it its own address space. The Interconnect will map requests to the BRAM by looking at the address bits of the request. If those are not right, it cannot know where to map the request. Thus your HLS code needs to be aware of that to access the BRAM. Do you understand why HLS needs to be aware of the address now?

 

Now, the reason you we divided by 4. When you index an array, there is a base address and an offset. The offset is the size of the type of the array * the index. The base address + the offset is the final address. What we have is an float pointer and we need access it in such a way that the right addresses were requested. To that end you could view it as a gigantic array. The data we wanted occured at physical address 0x40000000 which is index 0x10000000. Does this make sense?

 

There are multiple ways to code this. Code that may be more intuitive to you and is a bit more standard:

 

float *BRAMPointer = 0x40000000;
memcpy(&parameters, BRAMPointer, sizeof(parameters));

 

Explorer
Posts: 208
Registered: ‎02-05-2015

Re: Ap_memory tutorial

[ Edited ]
Thus your HLS code needs to be aware of that to access the BRAM. Do you understand why HLS needs to be aware of the address now?

Yes but it doesn't make sense in my head that when I design a model in HLS I need to know the addresses every time even when I don't know which address Vivado is going to assign it. It's strange in my head but ok..

 

Now about the 2nd explanation. Sorry but I'm lost.

 

When you index an array, there is a base address and an offset.The offset is the size of the type of the array * the index. The base address + the offset is the final address

Yes! That I completely understood and I've done a lot of that in SDK already.

 

The data we wanted occured at physical address 0x40000000 which is index 0x10000000

This is where you lost me. If the value 10.0 which occupies 4 bytes is written at 0x40000000 and the next value 5.0 is written at 0x40000004, why is it that when I want to read those values I read starting from 0x10000000 and not 0x40000000?

Voyager
Posts: 320
Registered: ‎01-28-2014

Re: Ap_memory tutorial

A more sophisticated scheme would involve your driver communicating the physical address to your design. For example you could make physical address one of your parameters which you driver could write directly to your design. Then you could create a pointer pointing to it and access it like in my previous example. This is pretty typical in DMA schemes but we had to start simple here. That said when you design something in HLS, you still need to be aware of what memories it interfaces too and be aware of the physical interfaces. In this case all the memories that needed to be accessed were on a common memory bus . The M_AXI_GP0, your BRAM funnction were both connected to a common BRAM memory via the AXI Interconnect. So you had one AXI interface and you needed an address for it. You don't neccasirly need to know the exact address ahead of time, but if you don't then SW will have to communicate to you.

 

For your second question, when you access the array you are giving it an index, not a physical address. 0x10000000 is the index such that the address (where the base address is 0, the offset is 4*the index) that is calculated is 0x40000000. Like I said above, in a more sophisticated scheme the address is communicated to you. This is just a "dumb" way to get you up and running. 

 

 

Explorer
Posts: 208
Registered: ‎02-05-2015

Re: Ap_memory tutorial

[ Edited ]

I think I'm understading better but I still have some doubts about 2nd question:

 

So basically if I had an array of floats thisguy[4]={10.0, 5.0, 10.0, 20.0} in addresses (0x4000 0000, 0x4000 0004, 0x4000 0008, 0x4000 000C) respectively if I access the index thisguy[0] the value is 10.0 and if I do &thisguy[0] the result would be 0x4000 0000. That is easy to understand. My problem is when the index is an hexadecimal instead of a integer because I don't understand why we express the index as hexadecimal.

To clarify then: a PHYSICAL_ADDRESS = BASE_ADDR + (sizeof(x) * INDEX) correct?

 

Why is BASE_ADDR 0? My question is this because I would think that BASE_ADDR would be 0x4000 0000 is our case and INDEX would be 0, not the other way around...

 

Also, this means that instead of 

memcpy(&parameters,&mem[0x1000 0000], sizeof(parameters))

I could have

memcpy(&parameters,0x40000000, sizeof(parameters))

right?

 

So to access a float in 0x4000 0008 would I need &mem[0x1000 0002]?

 

I'm just extremely confused because in the hundreds official Vivado HLS tutorials never was said that one needs to specify addresses so I thought it would be automatic. Now that I see the reality I think it was better if I learned VHDL instead of how to work with Vivado HLS -_-

Highlighted
Voyager
Posts: 320
Registered: ‎01-28-2014

Re: Ap_memory tutorial

[ Edited ]

There's no reason you have to express indicies or addresses in hex its often easier to look at if they are expressed that way. For this sort of thing I prefer hex so I use it. There is no signifance to either quantity being represented in decimal vs. hex. 

 

 

So, keep in mind that in your HLS top level function parameters are representing physical interfaces which is very much not like normal C. You use the interface directive to indicate what kind of interface they are, keep that in mind as you develop your designs. So a pointer which we have set to be a master AXI port represents a physical AXI interface. You may want to study some of the AXI signal descriptions at some point since it may communicate more clearly how some of this works. Accesing that pointer translates to accesses on the AXI bus. However accessing that pointer has no implict base address and how could it. It's possible for there to be a variety of memory mapped devices that it could communicate with. There has to be a way to distinguish one from the other which is done by address space mapping. That said I believe it is possible to explicitly set a base address on an instantiation by instantiation basis. The VHDL created supports a "Target Address" generic which is added to all the transaction addresses. It may be possible to configure this in IPI as well. This would work for this application but when you have multiple memories you would have to rethink the scheme. Finally there is an offset for the m_axi directive which may do the same thing, but then you're back to your code needing to know the address. It also means the Zynq Software and your HLS design have slightly different memory maps which I would find undesirable but really is very application specific.  

 

 

I think your point of confusion may be due to the way the simple example I created works. It relies on a shared memry space between the Zynq PS and your HLS design. The memory is accessed by both using the same AXI interface on the AXI interconnect. Going through this thread again I might pick a slightly different example to communicate my point more clearly. For example you could have two different AXI BRAM Controllers connected to the same BRAM. The Zynq PS would talk to one through the interconnect and the HLS design would talk to another one directly. In this case the HLS design would only be accessing the BRAM's memory space and nothing more. As a result it would behave in a way closer to your thought process. Note the reason I'm using Master AXI and not say an ap_memory port is that memcpy requires a master AXI interface to work. 

 

Now your last point, you can't just specify an address because that's not specifying an interface. In normal SW that would work since the CPU only has access to one memory space. However in this case no such limitation exists. You have to explicitly use the pointer. Naturally my previous example code was a lie since it also doesn't specify an interface. It was to try to explain to you what's going on but it wouldn't work since it doesn't specify an interface.

 

 

Note: Learning VHDL is defintely helpful. I don't believe you can do everything in HLS without understanding some of the FPGA side as well. I've found HLS pretty simple to pick up but I have a lot of experience with the hardware side. From a HDL designer pointer of view HLS makes a lot of really annoying tasks substantially easier (far less work to develop/implement). I'm not sure the same is true if one is approaching from a software perspective. That said if you understand a handful of basic concepts you can probably go pretty far.

Explorer
Posts: 208
Registered: ‎02-05-2015

Re: Ap_memory tutorial

[ Edited ]

Ok, I think I understood everything now. Ty very much for the thorough answer and for all the help!

 

Yes, I'll eventually need to learn VHDL but for now I can't do that. It has a big learning curve and all I have to do at first it to implement an algorithm in the Zedboard to prove that it implements faster on the Zedboard than on a personal computer. Then on an advanced phase, I'll need to construct that algorithm from sratch in VDHL.Do you think my idea is feasable to a person with the knowledge you've seen that I have (i.e. little)?


Would it be too much if I asked help for another simple design that is not working (and my guess is that it is memory mapping related also) ? It's a simple AXI DMA MM2S and the trouble we would have is just to analyze an axi-stream interface via the ILA probes.