cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
Observer
Observer
8,111 Views
Registered: ‎09-22-2014

Force BRAM to use dual ports in the same cycle

Hi, this is a loop i want to pipeline:

 

	#pragma HLS ARRAY_PARTITION variable=shift complete dim=0
	#pragma HLS ARRAY_PARTITION variable=buffer complete dim=0
	int bram[40];
	#pragma HLS RESOURCE variable=bram core=RAM_2P_BRAM

        for(i=0; i<10; i++){
	#pragma HLS PIPELINE II=1
		//fourth step
		if(third_step)
			bram[shift[2].address] = shift[2].data;

		//third - second steps
		if(shift[1].address != shift[0].address){
			shift[2].address=shift[1].address;
			shift[2].data=shift[1].data + buffer[1];
			third_step = true;
			shift[1]=shift[0];
		}else{
			shift[1].data+=shift[0].data;
			third_step = false;
		}
		buffer[1] = buffer[0];

		//first step
		buffer[0] = bram[is[i].address];
		shift[0]=is[i];
	}

 The problem is that i can't obtain II=1 even using a BRAM dual ports, the Analysis view suggest that the BRAM is never using the two ports simultaneously, can someone explain me why and how to force it to do so?

0 Kudos
Reply
7 Replies
Advisor
Advisor
8,021 Views
Registered: ‎04-26-2015

Is HLS actually complaining about a lack of ports? This looks more like a possible data dependency issue.

 

From a first glance, HLS is writing to a location (which it doesn't know until the previous iteration finishes) and then reading from a location (which it also doesn't know in advance). It has no way to be sure that it won't be reading from the same location that it's writing to, and if that is the case then it'll need* to delay one cycle while the write value is stored in RAM before reading from that location. Two ports won't help; the problem is that the RAM has to alternate read and write operations in order to be sure that correct ordering is maintained.

 

If you can guarantee a suitable access pattern, you can try using the DEPENDENCE pragma (which I've always found extremely confusing) to help HLS come up with the right solution. Otherwise, options are very limited; I've never had very much luck here.

 

 

 

(*) Yes, there are ways around this. In my experience, HLS does not use them.

0 Kudos
Reply
Observer
Observer
8,015 Views
Registered: ‎09-22-2014

The whole function is written to address the problem of writing and reading at the same location and at the same time the BRAM, yesterday i tried to use:

#pragma HLS DEPENDENCE variable=bram inter false

with no luck, any suggestion?

0 Kudos
Reply
Observer
Observer
8,011 Views
Registered: ‎09-22-2014

ARNING: [SCHED 204-68] Unable to enforce a carried dependency constraint (II = 1, distance = 1)
   between 'store' operation (hls_descriptor/solution1/source/bram_updater.cpp:49) of variable 'bram_load_1', hls_descriptor/solution1/source/bram_updater.cpp:49 on global variable 'buffer_0' and 'load' operation ('buffer_0_load', hls_descriptor/solution1/source/bram_updater.cpp:46) on global variable 'buffer_0'.

the problem is between these two instructions:

buffer[1] = buffer[0];

buffer[0] = bram[is[i].address];

 

0 Kudos
Reply
Advisor
Advisor
7,996 Views
Registered: ‎04-26-2015

Ah, right. I recognise this problem now.

 

If "buffer" is static, you may need to make it non-static and copy it from/to a static equivalent at the start/end of the function. HLS sometimes has trouble pipelining static variables.

 

If "buffer" is not static, forcing HLS to partition it completely may fix the problem. Even for very small arrays, HLS has trouble accepting that you can perform a read and a write on the same cycle; if you turn the array into registers then it works fine.

0 Kudos
Reply
Observer
Observer
7,984 Views
Registered: ‎09-22-2014

you were right but now the problem is moved to other instructions:

WARNING: [SCHED 204-68] Unable to enforce a carried dependency constraint (II = 1, distance = 1)
   between 'store' operation (hls_descriptor/solution1/source/bram_updater.cpp:38) of variable 'buffer[1]', hls_descriptor/solution1/source/bram_updater.cpp:38 on local variable 'buffer[1]' and 'load' operation ('buffer_1_3_load', hls_descriptor/solution1/source/bram_updater.cpp:40) on local variable 'buffer[1]'.

the line 38 to 40:

38 	if(shift[1].address != shift[0].address){
39		shift[2].address=shift[1].address;
40		shift[2].data=shift[1].data + buffer[1];

this is weird beacuse no buffer[1] are used on line 38.

0 Kudos
Reply
Observer
Observer
7,978 Views
Registered: ‎09-22-2014

This is my entire code:

 

#include "bram_updater.h"
#include <iostream>


void bram_updater(data_address_t* is, int *os){
	#pragma HLS INTERFACE ap_ctrl_none port=return
	#pragma HLS DATA_PACK variable=is
	#pragma HLS INTERFACE ap_fifo port=is
	#pragma HLS INTERFACE ap_fifo port=os

	data_address_t shift_0;
	data_address_t shift_1;
	data_address_t shift_2;
	int buffer_0;
	int buffer_1;
	int i=0;
	int bram[40];
	#pragma HLS RESOURCE variable=bram core=RAM_2P_BRAM
	#pragma HLS DEPENDENCE variable=bram inter false

	for(i=0; i<40; i++)
		bram[i] = 0;

	bool second_step = false;
	bool third_step = false;
	int foo;

	PIPE_LOOP: for(i=0; i<10; i++){
	#pragma HLS PIPELINE II=1
		//bramma[i+1] = foo;
		//foo = bramma[i];

		//third step
		if(third_step)
			bram[shift_2.address] = shift_2.data;

		//second steps
		if(second_step){
			if(shift_1.address != shift_0.address){
				shift_2.address=shift_1.address;
				shift_2.data=shift_1.data + buffer_1;
				third_step = true;
				shift_1=shift_0;
			}else{
				shift_1.data+=shift_0.data;
				third_step = false;
			}
		}
		buffer_1 = buffer_0;

		//first step
		shift_0=is[i];
		buffer_0 = bram[is[i].address];
		second_step = true;
	}

	for(i=0; i<40; i++){
		os[i] = bram[i];
		std::cout << i << " " << bram[i] << std::endl;
	}

}

The PIPE_LOOP is pipelined with II=2, this is the problem:

 

WARNING: [SCHED 204-68] Unable to enforce a carried dependency constraint (II = 1, distance = 1)
   between 'store' operation of variable 'buffer_1_load' on local variable 'buffer_1' and 'load' operation ('buffer_1_1_load', hls_descriptor/solution1/source/bram_updater.cpp:41) on local variable 'buffer_1'.

on this line:

shift_2.data=shift_1.data + buffer_1;

i don't get what the Warning is about.

0 Kudos
Reply
Explorer
Explorer
5,423 Views
Registered: ‎10-19-2012

Hope this helps:

 

I have solved the problem where I want to read and write to a simple dual port RAM in the same cycle, knowing that the write address and the read address are different. The data written to the RAM is also the data read on the last cycle.

 

 

 

    Some_loop:{
        
        static ram_type S2p_ram [RAM_SIZE] = { 0 };                     //Should initialize to all zeroes
        #pragma HLS RESOURCE variable=S2p_ram latency=1 core=RAM_S2P_BRAM      //Implement as Simple dual port Block RAM
    
        //Leading code
    
        RAM_Access:{
            #pragma HLS LATENCY max=1
            #pragma HLS DEPENDENCE variable=S2p_ram inter false
            #pragma HLS DEPENDENCE variable=S2p_ram intra false
            #pragma HLS DEPENDENCE variable=q_out inter false
            #pragma HLS DEPENDENCE variable=q_out intra false
            
            if (addr_write != addr_read)
            {
                S2p_ram[addr_write] = some_var+q_out;
            }
            
            q_out    = S2p_ram[addr_read];
        }
        
        addr_write = addr_read;
        
        //Trailing CODE
    }

 

Clearly this scheme only works if the write is on the next cycle of the read, otherwise correct operation is not guaranteed, that is where the LATENCY constraint of max=1 comes into play. Also, when declaring the dual port RAM resource set latency=1, otherwise HLS might try to put extra latency to meet period constraints.

 

Be sure to double-check with co-simulation (VERY important).

 

0 Kudos
Reply