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: 
Highlighted
Adventurer
Adventurer
490 Views
Registered: ‎06-03-2008

HLS testbench with AXIS interfaces

Jump to solution

Hello all,

 

I want to do a simple testbench of my IP that has an input and an output stream:

struct axiWord {
ap_uint<32> data;
ap_uint<4> strb;
ap_uint<1> last;
};

void my_ip_hls(stream<axiWord> &slaveIn,stream<axiWord> &masterOut);

The return "my_ip_hls" interface is set to ap_ctrl_none inside the function implementation.

This is my testbench:

int main() {

	uint32 i = 0;

	stream<axiWord> slaveIn("slaveIn");
	stream<axiWord> masterOut("masterOut");

	for (i=0;i<STREAM_TEST_ITERATIONS;i++) {
		axiWord dataIn = {0,0,0};
		dataIn.data = i+1;
		dataIn.strb = 0b1111;
		if (i == STREAM_TEST_ITERATIONS-1)
			dataIn.last = 1;
		else
			dataIn.last = 0;
		slaveIn.write(dataIn);
	}

	my_ip_hls(slaveIn, masterOut);

	while (!masterOut.empty()) {
		axiWord dataOut = {0,0,0};
		masterOut.read(dataOut);
		printf("read data: %u\n",(int)dataOut.data);
	}


	return 0;
}

I guess the idea is:

  1. First fill the slaveIn stream with data
  2. Call the function
  3. Read all results to "masterOut" as long as the output stream is not empty

However, the function is called once, then the testbench does not wait until it is done, hence it terminates, without even entering the "while (!masterOut.empty())" loop, stating also that the slaveIn stream contains leftover data:

 

INFO: [SIM 2] *************** CSIM start ***************
INFO: [SIM 4] CSIM will launch GCC as the compiler.
   Compiling ../../../my_ip_hls_tb.cpp in debug mode
   Generating csim.exe
WARNING: Hls::stream 'slaveIn' contains leftover data, which may result in RTL simulation hanging.
INFO: [SIM 1] CSim done with 0 errors.
INFO: [SIM 3] *************** CSIM finish ***************

Am I doing something wrong here?

 

Thanks,

dtheodor

 

 

 

0 Kudos
1 Solution

Accepted Solutions
Scholar u4223374
Scholar
385 Views
Registered: ‎04-26-2015

Re: HLS testbench with AXIS interfaces

Jump to solution

@dtheodor 

 

What I would normally do in this case is wrap the switch statement in an infinite loop (eg. "while (1) ..."), and then add something inside the switch statement to break the loop when an end condition (normally TLAST = 1 on the input stream) is detected.

 

Often in hardware the end condition will never occur at all (it'll be a true infinite loop) - but you can't simulate an infinite loop in C.

 

Related to this, you can (and probably should) remove the empty check on the input stream. Standard stream reads are blocking; HLS will automatically wait until data is available and then continue (works in hardware too).

7 Replies
Xilinx Employee
Xilinx Employee
456 Views
Registered: ‎09-05-2018

Re: HLS testbench with AXIS interfaces

Jump to solution

@dtheodor,

The C simulation runs sequentially, so it's unlikely that the issue is that the testbench is not waiting for the IP to run. 

You haven't shared the code, but based on your description, it sounds like my_ip_hls() is being called but not actually getting to the part that reads and writes the streams. Try adding some print statements to see if this is the case. Then, you may also want to use print statements to verify that there are an equal number of reads and writes on each stream.

On a separate but very important note, the testbench should not contain the statement, "return 0". The testbench needs to return a nonzero value if it detects a failure.

Nicholas Moellers

Xilinx Worldwide Technical Support
Scholar u4223374
Scholar
453 Views
Registered: ‎04-26-2015

Re: HLS testbench with AXIS interfaces

Jump to solution

As @nmoeller has said, the C simulation just compiles and runs your code as a single-threaded C program, ignoring all the pragmas (they only get used during synthesis), interface types, etc. It doesn't really have any way to bypass code.

Would it be possible to post the code for the IP itself? Everything you've already posted looks (a) correct, and (b) very nicely written.

 

For debugging, I often find it useful to add a printf statement immediately after the input stream is read - that way, if the printf statement doesn't print, then it's pretty clear that the stream isn't being read. For a fairly small stream size (eg. 10 elements for testing) you can also count the printf outputs and verify that the correct number of elements were read.

 

 

Edit: an idea! I've seen this problem before when the stream was being passed by value rather than by reference. You haven't made this mistake in your top-level function. However, are you passing that stream to a lower-level function? If so, check that it's being passed correctly.

Adventurer
Adventurer
419 Views
Registered: ‎06-03-2008

Re: HLS testbench with AXIS interfaces

Jump to solution

@u4223374, @nmoeller thank you both very much for your replies, they gave nice hints.

 

"my_ip_hls" comprises few internal functions, used exactly as mentioned in the XAPP1209 for designing protocol processing modules. Each module is based in a switch-case approach. After putting printf's I realized that calling a single time my IP, would allow only "running" a single switch case. For example, this is an excerpt of my code:

switch(curState) { 
	case (IN_STATE_IDLE): { 
		if (!inputFifo.empty()) { 
			inputFifo.read(newInWord); 
			if (newInWord.data == rule0) { 
				rule0Counter++; 				
			} 
			else { //data is clean, forward it to output 
				curState = IN_STATE_WRITE_DATA; 
			}
			break; 
		}
	}		
	
	case (IN_STATE_WRITE_DATA): {
		outputFifo.write(newInWord); 
		curState = IN_STATE_IDLE;  
		break; 
	}
	
};

According to the printf's, the testbench was reaching the "IN_STATE_IDLE", but was not executing the "IN_STATE_WRITE_DATA" state. Fortunately, in this case, both states can be merged into a signle one (writing the data to the output fifo in the same state):

switch(curState) {
	case (IN_STATE_IDLE): {
		if (!ps2ipIntFifo.empty()) {
			ps2ipIntFifo.read(newInWord);

			if (newInWord.data == rule0) {
				rule0Counter++;				
			}			
			else {  //data is clean, forward it to output
				ip2psIntFifo.write(newInWord);
			}
		}
		curState = IN_STATE_IDLE;
		break;
	}
};

By merging the two states into a single one, and calling within each for-loop iteration the "my_ip_hls" function, the testbench completes successfully:

 

int main() {

	uint32 i = 0;

	stream<axiWord> slaveIn("slaveIn");
	stream<axiWord> masterOut("masterOut");

	for (i=0;i<STREAM_TEST_ITERATIONS;i++) {
		axiWord dataIn = {0,0,0};
		dataIn.data = i+1;
		dataIn.strb = 0b1111;
		if (i == STREAM_TEST_ITERATIONS-1)
			dataIn.last = 1;
		else
			dataIn.last = 0;
		slaveIn.write(dataIn);
		my_ip_hls(slaveIn, masterOut);
		if (!masterOut.empty()) {
			axiWord dataOut = {0,0,0};
			masterOut.read(dataOut);
			printf("%d: forwarded data: %u\n",(int)i, (int)dataOut.data);
		}
		else {
			printf("%d: rejected data!\n",(int)i);
		}
	}
        //compare data against golden vector
        //....
}

So, now what is happening is:

  1. Fill the slaveIn stream with a sigle word
  2. Call my_ip_hls (that has only one switch case)
  3. Read (if it exists) the output
  4. Go to step 1 until all iterations are done

What I would like to do is:

  1. Fill the slaveIn stream with data
  2. Call ONCE my_ip_hls (that has multiple cases within a switch statement)
  3. Read all outputs

Thank you!

dtheodor

 

0 Kudos
Scholar u4223374
Scholar
386 Views
Registered: ‎04-26-2015

Re: HLS testbench with AXIS interfaces

Jump to solution

@dtheodor 

 

What I would normally do in this case is wrap the switch statement in an infinite loop (eg. "while (1) ..."), and then add something inside the switch statement to break the loop when an end condition (normally TLAST = 1 on the input stream) is detected.

 

Often in hardware the end condition will never occur at all (it'll be a true infinite loop) - but you can't simulate an infinite loop in C.

 

Related to this, you can (and probably should) remove the empty check on the input stream. Standard stream reads are blocking; HLS will automatically wait until data is available and then continue (works in hardware too).

Adventurer
Adventurer
370 Views
Registered: ‎06-03-2008

Re: HLS testbench with AXIS interfaces

Jump to solution

@u4223374Yes, this is a solution that works. I added:

 

while (newInWord.last == 0) {

switch {
...
}
}

And this way it works as discussed.I guess that these while loops are only valid for the testbench purposes; when I export the IP for integration to Vivado, I will remove them, because they are not needed.

Thanks @u4223374 !

0 Kudos
Scholar u4223374
Scholar
343 Views
Registered: ‎04-26-2015

Re: HLS testbench with AXIS interfaces

Jump to solution

@dtheodor If you just make it clear to Vivado that your end condition can never occur (eg. tie TLAST = 0, or if you're using TLAST elsewhere then use TUSER for your end condition instead and tie TUSER = 0 in Vivado) then it'll happily optimize all of that logic away.

Adventurer
Adventurer
336 Views
Registered: ‎06-03-2008

Re: HLS testbench with AXIS interfaces

Jump to solution

@u4223374That's a nice tip, thanks! I will have that in mind ;)

 

0 Kudos