Port as register variable?

Technical questions regarding the XTC tools and programming with XMOS.
IanH
Junior Member
Posts: 7
Joined: Wed Jun 02, 2010 1:47 pm

Port as register variable?

Post by IanH »

I would like to use a couple of pins to produce a pair of pulses, up to 1 second long with 2.5ns resolution (400 MHz o/p register clock). The first 'fill' is immediatley followed by the second 'clear'.
Looking at the dissassembly I see:

FillPin <: AllOnes;
becomes;
ldwdp (lru6) r2, dp
out (r2r) res[r2], r11

Is there a way of getting FillPin and ClearPin to be register variables, so that instructions such as "r2, dp" will not be created?. This would considerably speed things up.

Code: Select all

[size=85][color=#0000FF]      {
on stdcore [0] : out buffered port:32 ClearPin = PortClearPin ;
on stdcore [0] : out buffered port:32 FillPin = PortFillPin;
<-------snip-------->

	  register unsigned long NFB,NCB,FillBits,ClearBits1,ClearBits2;
	  register unsigned long AllOnes,AllZeroes;     
<----- snip ------->   
    	  FillPin <: AllOnes;
	      ClearPin <: AllZeroes;
	      NFB = NFB - 1;  
	      start_clock(clk);
    
	      while (NFB != 0)
	        {
		      FillPin <: AllOnes;
		      ClearPin <: AllZeroes;
		      NFB = NFB - 1;
	        }   
	     FillPin <: FillBits;
	     ClearPin <: ClearBits1;

	     while (NCB != 0)
		  {
			  FillPin <: AllZeroes;
			  ClearPin <: AllOnes;
			  NCB = NCB -1;
		  }	  
		  ClearPin <: ClearBits2;
		  FillPin <: AllZeroes;

		  sync(ClearPin);	     
      }
[/color][/size]


[code] FillPin <: AllOnes;
0x00010174 <FillClearPulse+200>: ldwdp (lru6) r2, dp
0x00010178 <FillClearPulse+204>: out (r2r) res[r2], r11
ClearPin <: AllZeroes;
0x0001017a <FillClearPulse+206>: ldwdp (lru6) r2, dp
0x0001017e <FillClearPulse+210>: out (r2r) res[r2], r3
NFB = NFB - 1;
0x00010180 <FillClearPulse+212>: sub (2rus) r1, r1, i 0x1
start_clock(clk);
0x00010182 <FillClearPulse+214>: ldwdp (lru6) r2, dp
0x00010186 <FillClearPulse+218>: setc (ru6) res[r2], i 0xf

while (NFB != 0)
0x00010188 <FillClearPulse+220>: brft (ru6) r1, i 0x2
0x0001018a <FillClearPulse+222>: brfu (u6) i 0x10
{
FillPin <: AllOnes;
0x0001018c <FillClearPulse+224>: ldwdp (lru6) r2, dp
0x00010190 <FillClearPulse+228>: out (r2r) res[r2], r11
ClearPin <: AllZeroes;
0x00010192 <FillClearPulse+230>: ldwdp (lru6) r2, dp
0x00010196 <FillClearPulse+234>: out (r2r) res[r2], r3
NFB = NFB - 1;
0x00010198 <FillClearPulse+236>: sub (2rus) r1, r1, i 0x1
0x0001019a <FillClearPulse+238>: brbu (u6) i 0x14
}
FillPin <: FillBits;
0x0001019c <FillClearPulse+240>: ldwdp (lru6) r1, dp
0x000101a0 <FillClearPulse+244>: out (r2r) res[r1], r6
ClearPin <: ClearBits1;
0x000101a2 <FillClearPulse+246>: ldwdp (lru6) r1, dp
0x000101a6 <FillClearPulse+250>: out (r2r) res[r1], r5

while (NCB != 0)
0x000101a8 <FillClearPulse+252>: brft (ru6) r0, i 0x2
0x000101aa <FillClearPulse+254>: brfu (u6) i 0x10
{
FillPin <: AllZeroes;
0x000101ac <FillClearPulse+256>: ldwdp (lru6) r1, dp
0x000101b0 <FillClearPulse+260>: out (r2r) res[r1], r3
[/code]


richard
Respected Member
Posts: 318
Joined: Tue Dec 15, 2009 12:46 am

Post by richard »

What optimisation level are you using? The compiler should try to eliminate multiple loads of the same global value at -O2 and above.
IanH
Junior Member
Posts: 7
Joined: Wed Jun 02, 2010 1:47 pm

Post by IanH »

Hi, could you point me to the instructions for using the xc code optimiser please?, I am not using it. :oops:
Thanks
Ian
richard
Respected Member
Posts: 318
Joined: Tue Dec 15, 2009 12:46 am

Post by richard »

IanH wrote:Hi, could you point me to the instructions for using the xc code optimiser please?, I am not using it. :oops:
Thanks
Ian
If you are using the XDE there by default there should be a Release configuration which by default enables -O2. To change to this click on the down arrow next to the hammer icon on the toolbar and choose Release. If you want more fine grained control over build options you can change them in the project properties, see the section 4.2 Building a Project in the 10.4 tools user guide

If you are using the command line tools just add the -O2 flag to the command line when compiling.
IanH
Junior Member
Posts: 7
Joined: Wed Jun 02, 2010 1:47 pm

Post by IanH »

OK, I found the project->properties->build->settings optimisation level, it wass at -O3. Have changed it to -O2, the code still generates the extra register load operation before each out statement.

I dont want to use assembler, (there doesnt seem to be an idiots guide anywhere) but I am guessing I will need to inline an asm 'out RegFill,AllOnes' statement to replace the FillPin<: AllOnes etc, having somehow loaded a couple of registers with the FillPin (RegFill) and ClearPin addresses?.
richard
Respected Member
Posts: 318
Joined: Tue Dec 15, 2009 12:46 am

Post by richard »

If you are already using -O2 or above then the optimisation isn't being applied for some reason. My guess would be there is too much register pressure. I notice you have qualified some of your variables with 'register'. It may be that by declaring too many variables with 'register' the register allocator has no choice but to spill everything else. I would recommend initially declaring variables without using register qualifer, only adding the register qualifer if necessary after looking at the generated code.
but I am guessing I will need to inline an asm 'out RegFill,AllOnes' statement to replace the FillPin<: AllOnes
This shouldn't be necessary. You can change your code to pass the port in as parameter instead of accessing it each time as a global. For example instead of:

Code: Select all

port global_port;

int main() {
  f();
}

void f() {
  global_port <: 0;
  global_port <: 1;
  ...
}
use:

Code: Select all

port global_port;

int main() {
  f(global_port);
}

void f(port p) {
  p <: 0;
  p <: 1;
  ...
}
If you do this then the port can be stored in a register even without the compiler optimisation that eliminates multiple loads of the same global value. You can qualify the parameter with register if you want.
IanH
Junior Member
Posts: 7
Joined: Wed Jun 02, 2010 1:47 pm

Post by IanH »

Thanks, when I try passing the ports as arguments to the function the compiler complains at the altered function call in main:

Multiple markers at this line
-passing arg 2 of `FillClearPulse' changes synchronicity of reference target type


any clues?
Cheers
Ian


EDIT:
fixed, have to specify port properly in called function,
ie out buffered port:32 FillPin
not just port FillPin
oops.

However ... the code generated is unchanged
FillPin <: AllOnes;
ldwdp (lru6) r2, dp
out (r2r) res[r2], r11
richard
Respected Member
Posts: 318
Joined: Tue Dec 15, 2009 12:46 am

Post by richard »

Hmm, that's unexpected. Are you able to attach enough of your source code for me to try and recreate this? If you don't want to post it publicly then you can create a support ticket on the XMOS website.
IanH
Junior Member
Posts: 7
Joined: Wed Jun 02, 2010 1:47 pm

Post by IanH »

Done!
Ta.
Ian
IanH
Junior Member
Posts: 7
Joined: Wed Jun 02, 2010 1:47 pm

Post by IanH »

My problem was resolved XMOS Richard's help, I had no optimisation on the debug version, and no debug info with the release version. Fixing this solved the problem and the OUT statements no longer are preceded with a port address load to register; my timing requirements appear to be met, though I am still finding my way around the toolset.