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!

cancel
Showing results for 
Search instead for 
Did you mean: 
Scholar jprice
Scholar
3,213 Views
Registered: ‎01-28-2014

Re: Ap_memory tutorial

Jump to solution

That is correct behavior :). When you write 1 to the base address that starts your logic. Your logic then reads from BRAM and and does its operation. It's done and won't read from BRAM again unless we tell it to run again. The result is then available to be read from the AXI Lite Slave Interface.

 

 

result = mm2s_bufferPtr[XBRAM_FUNC_AXILITES_ADDR_AP_RETURN]

This causes the result to be read from the AXI Slave Interface. If you were to trigger on your axi-lite slave's ARVALID you should see that along with RDATA/RVALID a little later.

 

 

0 Kudos
Explorer
Explorer
3,208 Views
Registered: ‎02-05-2015

Re: Ap_memory tutorial

Jump to solution

Yes, you are correct as always :)

 

So now the big question. Why is the block working well here but not when I do the other code in SDK?

0 Kudos
Scholar jprice
Scholar
3,204 Views
Registered: ‎01-28-2014

Re: Ap_memory tutorial

Jump to solution

Well, we haven't actually used your block to do anything yet. You should call your init_params now and let the values writes down to BRAM, then execute your design, sleep a bit, then read/print the value out. If that works then we can say its working. Then we can go from there.

 

Edit: Also paste the code you end up using.

0 Kudos
Explorer
Explorer
3,198 Views
Registered: ‎02-05-2015

Re: Ap_memory tutorial

Jump to solution

Here's the code I ended up using:

int main()
{
	int Status;
	u32 *mm2s_bufferPtr=NULL,result;


        init_platform();


	/* ***** Initialize drivers ******/
	Status = init_drivers();
	if (Status != XST_SUCCESS)
	{
		xil_printf("Driver initialization failed!\n\r");
		return XST_FAILURE;
	}
	/*Initialize IP block*/
	Status = bramfunc_init(&BRAM_func);
	if(Status != XST_SUCCESS){
		xil_printf("BRAM func block setup failed\n\r");
	  return XST_FAILURE;
	}

	initialize_parameters(XPAR_AXI_BRAM_CTRL_0_S_AXI_BASEADDR);

	mm2s_bufferPtr=(u32 *)(0x43C00000);
	mm2s_bufferPtr[0]=1;
	sleep(2);

	result= mm2s_bufferPtr[XBRAM_FUNC_AXILITES_ADDR_AP_RETURN];
        cleanup_platform();
        return 0;

When I trigger bram_func_0/m_axi_mem_ARVALID it triggers bu the RDATA is 0. Here's an attachement:

Screenshot from 2015-05-15 16:40:49.png
0 Kudos
Scholar jprice
Scholar
3,194 Views
Registered: ‎01-28-2014

Re: Ap_memory tutorial

Jump to solution

If you notice the read address bus from your block, its 0. That address range isn't really mapped to anything in your design, I actually have no clue where its getting any data back from, it should get stuck waiting (might be a feature of the interconnect to respond to unmapped address spaces?). Is your HLS code still reading from the physical address of the block RAM?

0 Kudos
Explorer
Explorer
3,189 Views
Registered: ‎02-05-2015

Re: Ap_memory tutorial

Jump to solution

Yes, the HLS code is still doing:

 

#define BRAM_START_ADDRESS 0x40000000

memcpy(&parameters, &mem[BRAM_START_ADDRESS], sizeof(parameters));
0 Kudos
Scholar jprice
Scholar
3,174 Views
Registered: ‎01-28-2014

Re: Ap_memory tutorial

Jump to solution

Now we're in tricky territory since I don't use IPI. When I build something in HLS I use the HDL. The HDL allows me to size certain parameters of teh AXI bus. In this case you want to make sure the address width is 32. See if you can play around in IPI and figure out what address size its using.

0 Kudos
Explorer
Explorer
3,168 Views
Registered: ‎02-05-2015

Re: Ap_memory tutorial

Jump to solution

When I synthesize in Vivado HLs it tells me that our S_AXI_AXILITEs_AWADDR and S_AXI_AXILITEs_ARADDR is of 5 bits. Are these the parameters that I need to change to 32?

 

See here:

------------------------+-----+-----+------------+--------------+--------------+
|        RTL Ports       | Dir | Bits|  Protocol  | Source Object|    C Type    |
+------------------------+-----+-----+------------+--------------+--------------+
|s_axi_AXILiteS_AWVALID  |  in |    1|    s_axi   |   AXILiteS   | return value |
|s_axi_AXILiteS_AWREADY  | out |    1|    s_axi   |   AXILiteS   | return value |
|s_axi_AXILiteS_AWADDR   |  in |    5|    s_axi   |   AXILiteS   | return value |
|s_axi_AXILiteS_WVALID   |  in |    1|    s_axi   |   AXILiteS   | return value |
|s_axi_AXILiteS_WREADY   | out |    1|    s_axi   |   AXILiteS   | return value |
|s_axi_AXILiteS_WDATA    |  in |   32|    s_axi   |   AXILiteS   | return value |
|s_axi_AXILiteS_WSTRB    |  in |    4|    s_axi   |   AXILiteS   | return value |
|s_axi_AXILiteS_ARVALID  |  in |    1|    s_axi   |   AXILiteS   | return value |
|s_axi_AXILiteS_ARREADY  | out |    1|    s_axi   |   AXILiteS   | return value |
|s_axi_AXILiteS_ARADDR   |  in |    5|    s_axi   |   AXILiteS   | return value |
|s_axi_AXILiteS_RVALID   | out |    1|    s_axi   |   AXILiteS   | return value |
|s_axi_AXILiteS_RREADY   |  in |    1|    s_axi   |   AXILiteS   | return value |
|s_axi_AXILiteS_RDATA    | out |   32|    s_axi   |   AXILiteS   | return value |
|s_axi_AXILiteS_RRESP    | out |    2|    s_axi   |   AXILiteS   | return value |
|s_axi_AXILiteS_BVALID   | out |    1|    s_axi   |   AXILiteS   | return value |
|s_axi_AXILiteS_BREADY   |  in |    1|    s_axi   |   AXILiteS   | return value |
|s_axi_AXILiteS_BRESP    | out |    2|    s_axi   |   AXILiteS   | return value |
|ap_clk                  |  in |    1| ap_ctrl_hs |   bram_func  | return value |
|ap_rst_n                |  in |    1| ap_ctrl_hs |   bram_func  | return value |
|interrupt               | out |    1| ap_ctrl_hs |   bram_func  | return value |
|m_axi_mem_AWVALID       | out |    1|    m_axi   |      mem     |    pointer   |
|m_axi_mem_AWREADY       |  in |    1|    m_axi   |      mem     |    pointer   |
|m_axi_mem_AWADDR        | out |   32|    m_axi   |      mem     |    pointer   |
|m_axi_mem_AWID          | out |    1|    m_axi   |      mem     |    pointer   |
|m_axi_mem_AWLEN         | out |    8|    m_axi   |      mem     |    pointer   |
|m_axi_mem_AWSIZE        | out |    3|    m_axi   |      mem     |    pointer   |
|m_axi_mem_AWBURST       | out |    2|    m_axi   |      mem     |    pointer   |
|m_axi_mem_AWLOCK        | out |    2|    m_axi   |      mem     |    pointer   |
|m_axi_mem_AWCACHE       | out |    4|    m_axi   |      mem     |    pointer   |
|m_axi_mem_AWPROT        | out |    3|    m_axi   |      mem     |    pointer   |
|m_axi_mem_AWQOS         | out |    4|    m_axi   |      mem     |    pointer   |
|m_axi_mem_AWREGION      | out |    4|    m_axi   |      mem     |    pointer   |
|m_axi_mem_AWUSER        | out |    1|    m_axi   |      mem     |    pointer   |
|m_axi_mem_WVALID        | out |    1|    m_axi   |      mem     |    pointer   |
|m_axi_mem_WREADY        |  in |    1|    m_axi   |      mem     |    pointer   |
|m_axi_mem_WDATA         | out |   32|    m_axi   |      mem     |    pointer   |
|m_axi_mem_WSTRB         | out |    4|    m_axi   |      mem     |    pointer   |
|m_axi_mem_WLAST         | out |    1|    m_axi   |      mem     |    pointer   |
|m_axi_mem_WID           | out |    1|    m_axi   |      mem     |    pointer   |
|m_axi_mem_WUSER         | out |    1|    m_axi   |      mem     |    pointer   |
|m_axi_mem_ARVALID       | out |    1|    m_axi   |      mem     |    pointer   |
|m_axi_mem_ARREADY       |  in |    1|    m_axi   |      mem     |    pointer   |
|m_axi_mem_ARADDR        | out |   32|    m_axi   |      mem     |    pointer   |
|m_axi_mem_ARID          | out |    1|    m_axi   |      mem     |    pointer   |
|m_axi_mem_ARLEN         | out |    8|    m_axi   |      mem     |    pointer   |
|m_axi_mem_ARSIZE        | out |    3|    m_axi   |      mem     |    pointer   |
|m_axi_mem_ARBURST       | out |    2|    m_axi   |      mem     |    pointer   |
|m_axi_mem_ARLOCK        | out |    2|    m_axi   |      mem     |    pointer   |
|m_axi_mem_ARCACHE       | out |    4|    m_axi   |      mem     |    pointer   |
|m_axi_mem_ARPROT        | out |    3|    m_axi   |      mem     |    pointer   |
|m_axi_mem_ARQOS         | out |    4|    m_axi   |      mem     |    pointer   |
|m_axi_mem_ARREGION      | out |    4|    m_axi   |      mem     |    pointer   |
|m_axi_mem_ARUSER        | out |    1|    m_axi   |      mem     |    pointer   |
|m_axi_mem_RVALID        |  in |    1|    m_axi   |      mem     |    pointer   |
|m_axi_mem_RREADY        | out |    1|    m_axi   |      mem     |    pointer   |
|m_axi_mem_RDATA         |  in |   32|    m_axi   |      mem     |    pointer   |
|m_axi_mem_RLAST         |  in |    1|    m_axi   |      mem     |    pointer   |
|m_axi_mem_RID           |  in |    1|    m_axi   |      mem     |    pointer   |
|m_axi_mem_RUSER         |  in |    1|    m_axi   |      mem     |    pointer   |
|m_axi_mem_RRESP         |  in |    2|    m_axi   |      mem     |    pointer   |
|m_axi_mem_BVALID        |  in |    1|    m_axi   |      mem     |    pointer   |
|m_axi_mem_BREADY        | out |    1|    m_axi   |      mem     |    pointer   |
|m_axi_mem_BRESP         |  in |    2|    m_axi   |      mem     |    pointer   |
|m_axi_mem_BID           |  in |    1|    m_axi   |      mem     |    pointer   |
|m_axi_mem_BUSER         |  in |    1|    m_axi   |      mem     |    pointer   |
+------------------------+-----+-----+------------+--------------+--------------+

 

Edit: About the reason for the 5-bit address, I was searching and it's like this: "From the UG871, it seems that the size of the array is from 0 to 16 samples, hence you need 32 addresses to access all values (see Figure 69). I guess that the number N is somewhere limited to be less than 32 (or be exactly 16). This means that Vivado knows this limitation, and generates only as many address bits as are needed. Most synthesis tools check the constraints on size and optimize unnecessary code away." from here.

0 Kudos
Scholar jprice
Scholar
3,160 Views
Registered: ‎01-28-2014

Re: Ap_memory tutorial

Jump to solution

Not the AXI Lite Interface, the master AXI interface which is 32 bits according to that table so thats not the problem. I'm not sure why, but its not reading from the correct address (0x0000_0000 instead of 0x4000_0000) and yet something is still responding to it. Typing this out made me realize the problem. Try this:

 

 

#define BRAM_START_ADDRESS 0x40000000

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

 

0 Kudos
Explorer
Explorer
3,103 Views
Registered: ‎02-05-2015

Re: Ap_memory tutorial

Jump to solution

Sorry for the delay in the answer. I'm going to try that now.

 

Can you tell me what that means though?

0 Kudos
Scholar jprice
Scholar
3,015 Views
Registered: ‎01-28-2014

Re: Ap_memory tutorial

Jump to solution

The >> operator is just a bitshift operator. A uint32 is 4 bytes, so when you access an array that is automatically converted to a byte aligned address. Since its 4 bytes per word, the address is effectively the base address of the array + 4*the index. The bitshift to the right by 2 is the same as a divide by 4.

Explorer
Explorer
3,007 Views
Registered: ‎02-05-2015

Re: Ap_memory tutorial

Jump to solution

I think this does not solve it.

 

Whit this code:

 

int main()
{
	int Status;
	u32 *mm2s_bufferPtr=NULL,result;
	union float32 thisone;


        init_platform();

	/* ***** Initialize drivers ******/
	Status = init_drivers();
	if (Status != XST_SUCCESS)
	{
		xil_printf("Driver initialization failed!\n\r");
		return XST_FAILURE;
	}
	/*Initialize IP block*/
	Status = bramfunc_init(&BRAM_func);
	if(Status != XST_SUCCESS){
		xil_printf("BRAM func block setup failed\n\r");
	  return XST_FAILURE;
	}

	initialize_parameters(XPAR_AXI_BRAM_CTRL_0_S_AXI_BASEADDR);


	mm2s_bufferPtr=(u32 *)(0x43C00000);
	mm2s_bufferPtr[0]=1;
	sleep(2);

	result = mm2s_bufferPtr[XBRAM_FUNC_AXILITES_ADDR_AP_RETURN];

it never triggers bram_func_0/m_axi_mem_ARREADY as well as axi_bram_ctrl_0/s_axi_arvalid...

What do you think is the problem mate? It looks like we tried everything

0 Kudos
Scholar jprice
Scholar
3,000 Views
Registered: ‎01-28-2014

Re: Ap_memory tutorial

Jump to solution

Are you triggering on the master AXI ARREADY or ARVALID? ARREADY should defintely be high, something would not be right with your setup if that wasn't. Before your made the suggested change to the HLS code the Master ARVALID as well as the AXI Lite ARVALID were both being triggered. Go back to the old HLS code (before the bitshift I added) and try again. If it's not triggering then something has gone wrong with your setup again. If it does work, then you add the bitshift back in and it doesn't work that would be peculiar. I would say you should still see ARVALID on the master port (I'm pretty confident in that). You might not see the AXI Lite Slave's ARVALId depending on the state of the AXI bus.

0 Kudos
Explorer
Explorer
2,998 Views
Registered: ‎02-05-2015

Re: Ap_memory tutorial

Jump to solution
Are you triggering on the master AXI ARREADY or ARVALID?

They are both never high. Keep in mind that it's the master from my bram_function.

 

I'm reverting it to the old HLS code (without the bitshift) and I'll tell you the results here

 

 

0 Kudos
Scholar jprice
Scholar
2,987 Views
Registered: ‎01-28-2014

Re: Ap_memory tutorial

Jump to solution

Ok, if ARVALID isn't going high you wouldn't see an ARREADY judging from the behavior of the interconnect so that may make sense. What you may want to do is confirm the AWVALID on the AXI Lite interface along with WVALID/WDATA are correct (this occurs when you write a 1 into your block telling it to start). 

0 Kudos
Explorer
Explorer
2,982 Views
Registered: ‎02-05-2015

Re: Ap_memory tutorial

Jump to solution

It's confirmed. With the old version of the HLS code (without the bitshifter) it "works".

 

ARVALID and from my master AXI (of my Bram_func) is going high (but not ARVALID from BRAM_CTRL).

 

Also,l with this old block and triggering AWVAId, everything seems ok (see attachment).

 

What do you want me to test next mate?

 

 Note: changing between HLs versions is a lot of trouble since I need to rebuild and re-export the Vivado HLs and then re-build and re-synthesize and re-generate bitstream on Vivado. This whole process takes like 40 minutes -_-

Screenshot from 2015-05-18 18:27:39.png
0 Kudos
Scholar jprice
Scholar
2,974 Views
Registered: ‎01-28-2014

Re: Ap_memory tutorial

Jump to solution

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

 This just makes the address shift implicit in the defintion instead, but the original way should have worked. I'm actually doing this exact thing in my design with no problems, so I'm a little confused. I would understand if ARREADY were not going high, but ARVALID should absolutely have gone high.

 

You also indicated your build times were taking a while. If you're doing every stpe manually and will be doing this for a while you may want to automate the process (pretty much everything is a Tcl command under the hood and there are journal files that show what commands were called). To avoid re-building we can make some of these constants programmable. That is to say you could have say the BRAM Start Address be an input into your function. You would have to get the AXI Lite commands to write that value into your design to work (The API functions Xilinx provides should make that siple). However it would then let you tweak just your SW to change the addresses around which could help.

 

0 Kudos
Explorer
Explorer
2,955 Views
Registered: ‎02-05-2015

Re: Ap_memory tutorial

Jump to solution
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

I don't have the zedboard with me today, I'm going to try it tomorrow.

 

Aboiut those tcl commands you recommended..I would like to learn that but I just don't have the time now.

 

I'm thinking about something: maybe these errors that we are seeing are related to the incompatibility of versions? The thing is, my Vivado HLS license expired in my desktop (running linux 64-bit) and so I had to install an older version on my laptop (Windows 7 64-bit). And the versions of the programs are not the same. The desktop one is 2014.4 and on the laptop the version of vivado/vivado HLS is the 2014.2 (this last is a cracked version that only works in Windows I believe).

Do you think this has something to do with the problems? I started thinking this because you made the same design in vivado hls and used the same block design in Vivado right?

0 Kudos
Scholar jprice
Scholar
2,951 Views
Registered: ‎01-28-2014

Re: Ap_memory tutorial

Jump to solution

That's certainly possible, it's also possible that the older version of HLS just has some bugs in it (I'm running into a handful even in 2014.4/2015.1). If you can I would defintely try to get 2014.4 or 2015.1 up and running. I am doing similiar things with an AXI interface but I'm also doing everything in HDL instead of IPI, so there's room for bugs and errors there as well. It's difficult to say. I just find the behavior of your HLS design changing behavior in the way it did from that bitshift very peculiar.

0 Kudos
Explorer
Explorer
2,946 Views
Registered: ‎02-05-2015

Re: Ap_memory tutorial

Jump to solution

Unfortunately I can't buy the license for the 2014.4 and 2015.1 so I'll need to stay with 2014.2. Tomorrow I'm going to post the generated VHDL (automatically by Vivado HLS) code here and if you can post yours. I'll compare and check where's the problem with my simple block

0 Kudos
Scholar jprice
Scholar
3,225 Views
Registered: ‎01-28-2014

Re: Ap_memory tutorial

Jump to solution

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.

 

 

 

 

0 Kudos
Explorer
Explorer
3,215 Views
Registered: ‎02-05-2015

Re: Ap_memory tutorial

Jump to solution

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

0 Kudos
Scholar jprice
Scholar
3,204 Views
Registered: ‎01-28-2014

Re: Ap_memory tutorial

Jump to solution

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.

0 Kudos
Explorer
Explorer
3,197 Views
Registered: ‎02-05-2015

Re: Ap_memory tutorial

Jump to solution

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?

0 Kudos
Scholar jprice
Scholar
3,186 Views
Registered: ‎01-28-2014

Re: Ap_memory tutorial

Jump to solution

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
Explorer
3,182 Views
Registered: ‎02-05-2015

Re: Ap_memory tutorial

Jump to solution
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?

0 Kudos
Scholar jprice
Scholar
3,178 Views
Registered: ‎01-28-2014

Re: Ap_memory tutorial

Jump to solution

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
Explorer
3,171 Views
Registered: ‎02-05-2015

Re: Ap_memory tutorial

Jump to solution

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 -_-

0 Kudos
Highlighted
Scholar jprice
Scholar
10,632 Views
Registered: ‎01-28-2014

Re: Ap_memory tutorial

Jump to solution

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
Explorer
3,152 Views
Registered: ‎02-05-2015

Re: Ap_memory tutorial

Jump to solution

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.

0 Kudos