GP2X Optimizing Or Converting To Asm?


zico

Member
Joined
Jun 3, 2006
Messages
273
Hey people.

Still I'm working on my Descent ports and I have 2 CPU "eater" functions here I would like to optimize.

I think the best I would get with ASM but I really have no clue about it. But probably rewriting could help as well.

Here is the code:
Code:
int32_t fixdivquadlong(u_int32_t nl,u_int32_t nh,u_int32_t d)
{
	int i;
	u_int32_t tmp0;
	ubyte tmp1;
	u_int32_t r;
	ubyte T,Q,M;

	r = 0;

	Q = ((nh&0x80000000)!=0);
	M = ((d&0x80000000)!=0);
	T = (M!=Q);

	if (M == 0)
	{
		for (i=0; i<32; i++ )   {
	
			r <<= 1;
			r |= T;
			T = ((nl&0x80000000L)!=0);
			nl <<= 1;
	
			switch( Q ) {
		
			case 0:
				Q = (unsigned char)((0x80000000L & nh) != 0 );
				nh = (nh << 1) | (u_int32_t)T;

				tmp0 = nh;
				nh -= d;
				tmp1 = (nh>tmp0);
				if (Q == 0)
					Q = tmp1;
				else
					Q = (unsigned char)(tmp1 == 0);
				break;
			case 1:
				Q = (unsigned char)((0x80000000L & nh) != 0 );
				nh = (nh << 1) | (u_int32_t)T;

				tmp0 = nh;
				nh += d;
				tmp1 = (nh<tmp0);
				if (Q == 0)
					Q = tmp1;
				else
					Q = (unsigned char)(tmp1 == 0);
				break;
			}
			T = (Q==M);
		}
	}
	else
	{
		for (i=0; i<32; i++ )   {
	
			r <<= 1;
			r |= T;
			T = ((nl&0x80000000L)!=0);
			nl <<= 1;
	
			switch( Q ) {
		
			case 0:
				Q = (unsigned char)((0x80000000L & nh) != 0 );
				nh = (nh << 1) | (u_int32_t)T;

				tmp0 = nh;
				nh += d;
				tmp1 = (nh<tmp0);
				if (Q == 1)
					Q = tmp1;
				else
					Q = (unsigned char)(tmp1 == 0);
				break;
			case 1: 
				Q = (unsigned char)((0x80000000L & nh) != 0 );
				nh = (nh << 1) | (u_int32_t)T;

				tmp0 = nh;
				nh = nh - d;
				tmp1 = (nh>tmp0);
				if (Q == 1)
					Q = tmp1;
				else
					Q = (unsigned char)(tmp1 == 0);
				break;
			}
			T = (Q==M);
		}
	}

	r = (r << 1) | T;

	return r;
}

AND

Code:
void fixmulaccum(quad *q,fix a,fix b)
{
	u_int32_t aa,bb;
	u_int32_t ah,al,bh,bl;
	u_int32_t t,c=0,old;
	int neg;

	neg = ((a^b) < 0);

	aa = labs(a); bb = labs(b);

	ah = aa>>16;  al = aa&0xffff;
	bh = bb>>16;  bl = bb&0xffff;

	t = ah*bl + bh*al;

	if (neg)
		fixquadnegate(q);

	old = q->low;
	q->low += al*bl;
	if (q->low < old) q->high++;
	
	old = q->low;
	q->low += (t<<16);
	if (q->low < old) q->high++;
	
	q->high += ah*bh + (t>>16) + c;
	
	if (neg)
		fixquadnegate(q);

}

Any idead about this?

Probably I could do some things with inline asm but as said.. no clue how :(
 
The way I would suggest starting is by looking at the assembly code gcc produces for those, and then splitting them out into a separate assembly file that you can optimize and compile to object files that get linked with the rest of the code.
 
I really think that you would beter just "chage" the functios... they seem like fixed point division/multiplications, may be you could just use math_ssl.h for optimized 64bit fixed point(32.32) implementation...

Once you make that work you could optimize even more ussing only 32bit fixedpoint arithmetichs later... in my experience 16.16 or 20.10 fixed point uses to be enough for software rasterization even with prepective correction.

Hey people.

Still I'm working on my Descent ports and I have 2 CPU "eater" functions here I would like to optimize.

I think the best I would get with ASM but I really have no clue about it. But probably rewriting could help as well.

Here is the code:
Code:
int32_t fixdivquadlong(u_int32_t nl,u_int32_t nh,u_int32_t d)
{
}

AND

Code:
void fixmulaccum(quad *q,fix a,fix b)
{
}

Any idead about this?

Probably I could do some things with inline asm but as said.. no clue how :(
 
Last edited by a moderator:
To be honest that is very cryptic for me :(

The function that eats definately the most CPU time (70%) is the texture mapper:

Code:
void c_tmap_scanline_quad()
{
	ubyte *dest;
	uint c;
	int x;
	fix u,v,l,dudx, dvdx, dldx;

	// Quadratic setup stuff:
	fix a0, a1, a2, b0, b1, b2, dudx1, dvdx1;
	fix u0 = fx_u;
	fix u2 = fx_u + fx_du_dx*(fx_xright-fx_xleft+1);	// This just needs to be uright from outer loop
	fix v0 = fx_v;
	fix v2 = fx_v + fx_dv_dx*(fx_xright-fx_xleft+1);	// This just needs to be vright from outer loop
	fix w0 = fx_z;
	fix w2 = fx_z + fx_dz_dx*(fx_xright-fx_xleft+1);	// This just needs to be zright from outer loop
	fix u1 = fixdiv((u0+u2),(w0+w2));						
	fix v1 = fixdiv((v0+v2),(w0+w2));
	int dx = fx_xright-fx_xleft+1;		
	u0 = fixdiv( u0, w0 );	// Divide Z out.  This should be in outer loop
	v0 = fixdiv( v0, w0 );	// Divide Z out.  This should be in outer loop
	u2 = fixdiv( u2, w2 );	// Divide Z out.  This should be in outer loop
	v2 = fixdiv( v2, w2 );	// Divide Z out.  This should be in outer loop
	a0 = u0;									
	b0 = v0;
	a1 = (-3*u0+4*u1-u2)/dx;			
	b1 = (-3*v0+4*v1-v2)/dx;
	a2 = (2*(u0-2*u1+u2))/(dx*dx);	
	b2 = (2*(v0-2*v1+v2))/(dx*dx);
	dudx = a1 + a2;
	dvdx = b1 + b2;
	dudx1 = 2*a2;
	dvdx1 = 2*b2;
	u = u0;
	v = v0;

	// Normal lighting setup
	l = fx_l>>8;
	dldx = fx_dl_dx>>8;
	
	// Normal destination pointer setup
	dest = (ubyte *)(write_buffer + fx_xleft + (bytes_per_row * fx_y)  );

	if (!Transparency_on)	{
		for (x= fx_xright-fx_xleft+1; x > 0; --x ) {
			*dest++ = gr_fade_table[ (l&(0xff00)) + (uint)pixptr[  (f2i(v)&63)*64 + (f2i(u)&63) ] ];
			l += dldx;
			u += dudx;
			v += dvdx;
			dudx += dudx1;		// Extra add for quadratic!
			dvdx += dvdx1;		// Extra add for quadratic!
		}
	} else {
		for (x= fx_xright-fx_xleft+1; x > 0; --x ) {
			c = (uint)pixptr[  (f2i(v)&63)*64 + (f2i(u)&63) ];
			if ( c!=255)
				*dest = gr_fade_table[ (l&(0xff00)) + c ];
			dest++;
			l += dldx;
			u += dudx;
			v += dvdx;
			dudx += dudx1;		// Extra add for quadratic!
			dvdx += dvdx1;		// Extra add for quadratic!
		}
	}
}

And I'm honest I even don't understand the comments writtn here even if I undestand they could be related to the usage...

But I'm very interested how to turn this code into assembler as described by BradN. Probably I could do something with that.
 
Code:
int32_t fixdivquadlong(u_int32_t nl,u_int32_t nh,u_int32_t d)

There are plenty of ARM optimized division function available on the net.
What you are looking for is a division that takes a 64 bits dividand and a 32 bits divizor, then returns a 32 bits quotient.

You can also replace it by :

int32_t fixdivquadlong(u_int32_t nl,u_int32_t nh,u_int32_t d) {
return ((int64_t)nh<<32) | nl)/d;
}

and let GCC use the one he knows :)
 
Last edited by a moderator:
Back
Top