// nicked from output of PGC Rel 1.4 -opt 2 .text .align 8 .text #define trace_regs(label)\ adds -16, sp, sp; \ st.l r1, 4(sp); \ adds -256, sp, sp; \ st.l r17, 64(sp); \ orh ha%label, r0, r17; \ or l%label, r17, r17; \ call _reg_dump; \ adds 256, sp, sp; \ ld.l 4(sp), r1; \ adds 16, sp, sp //{{{ Heavy description // // DIVISION pxpl5 support code // // over and above the normal transform / light / clip, pxpl5 // requires triangles to be prepared for display by converting them // into screen-space linear expressions. Both scan-conversion and shading // information need to be so converted // // constructing linear expressions for scan-conversion is EDGIZing // constructing linear expressions for shading is PLANARIZing // putting triangles into 64x128 pixel bins is BINITIZing // // these are some optimized routines for edgizing, planarizing and // binitizing // // it is clear that this software is just not fast enough when coded in C for // 2 reasons - inefficient register usage (crap compiler) and excessive memory // hits. Memory hits occur at function calls, where stack frames are moved // and registers saved away to adhere to C calling conventions - lets trash // the calling conventions (and make this undebuggable!) // // The functions below are very optimized to NEVER hit memory. The price // we pay is that they are not directly callable in C - the C-callable // code is in pxpl5tri.ss, and is a bunch of triangle functions, which // save away volatile registers, chain together calls to these functions, // then restore registers and return // // HOWEVER - note safe_binitize_fn, which every 256 triangles or so is forced // to call some C, and which may under worst-case circumstances call malloc. // dont be scared, it works // // depressing timings - the gayboy coding of planarize executes in 116 ticks, // the steroid-laden version 73 ticks - this is for 32 fpu ops. So, I // shall make this even worse, by introducing a zbuf_plus2_fn, which // both z-buffers, AND planarizes 2 other functions at the same time. This // can take advantage of the 3-ness of the i860 pipe by unrolling 3 // planarizations at once. It is also optimized for the PAZ primitive of // z-buffer, luminance, specularity - using z-buffer, planar, planar I get // 97k triangles/sec .. lets try to get 130k from zbuf_plus2_fn // // oh rats - the VERTEX and NORM_COL are now separated in memory - I need to // pass in offset from Z, otherOffset from Z into z_buf_plus2 // // define some useful registers, which are // pointers to 4 vertices rv1 .. rv4 // 4 x coordinates fx1 .. fx4 // 4 y coordinates fy1 .. fy4 // 3 value coordinates fv1 .. fv3 // minimaxes fminx, fminy, fmaxx, fmaxy // repeated expressions fx23, fx31, fx12, fC //}}} #include "u:\projects\dbi0150\dbi0151\ucode\igc_opco.h" #include "\pazpl5\pxpl5sup\pxplmacr.h" #include "\pazpl5\pxpl5sup\divpxmap.h" #include "\pazpl5\pxpl5sup\dmaengn.h" #include "\pazpl5\pxpl5sup\register.h" //{{{ some housekeeping code //{{{ tex_scalefac .globl _tex_scalefac .align 8 _tex_scalefac:: // // fparam1, 2, 3 hold 3 z values - find which is biggest, scale // it up to have no leading zeros, return scale factor (1.0, 2.0 etc) // sign bit guaranteed not set // z not yet munged by scale bits, so z in range 0.0 .. 1.0 // biggest test is easy - fxfr to integer registers, // do integer compare to determine biggest // extract exponent from biggest, all 3 zs // // use r31 to hold max, use int parameter registers as temporaries // // this would appear to take 16ish ticks // fxfr fparam1, iparam1 fxfr fparam2, iparam2 fxfr fparam3, iparam3 subs iparam1, iparam2, r0 bc i2_gt_i1 subs iparam1, iparam3, r0 bnc.t igotmax mov iparam1, r31 br igotmax mov iparam3, r31 i2_gt_i1:: subs iparam2, iparam3, r0 bnc.t igotmax mov iparam2, r31 br igotmax mov iparam3, r31 igotmax:: // // compute exponent difference between 0.999 and max // // dont worry, its just IEEE-754 - read the i860 databook // // warning - it may fall down in a heap if we ever give it // a denormal, so just set the far clipping plane somewhere // sensible - i will work out where // andh 0x7f80, r31, r31 // extract exponent of max orh 0x7e80, r0, iparam1 subu iparam1, r31, r31 // and we have magic bri r1 ixfr r31, fparam1 //}}} //{{{ _trunc_test ( int *truncy, float a, float b, float c ) .globl _trunc_test .align 8 _trunc_test:: adds -64, sp, sp fst.d f2, 0(sp) fst.d f4, 8(sp) fst.d f6, 16(sp) fst.d f8, 24(sp) st.l r4, 28(sp) st.l r5, 32(sp) st.l r6, 36(sp) pftrunc.sd f8, f0 pftrunc.sd f9, f0 pftrunc.sd f10, f0 pfadd.sd f0, f0, f2 pfadd.sd f0, f0, f4 pfadd.sd f0, f0, f6 fxfr f2, r4 fxfr f4, r5 fxfr f6, r6 st.l r4, 0(r16) st.l r5, 4(r16) st.l r6, 8(r16) fld.d 0(sp), f2 fld.d 8(sp), f4 fld.d 16(sp), f6 fld.d 24(sp), f8 ld.l 28(sp), r4 ld.l 32(sp), r5 ld.l 36(sp), r6 bri r1 adds 64, sp, sp //}}} //{{{ give_fp returns value of frame pointer .globl _give_fp .align 8 // binitize a primitive _give_fp:: bri r1 addu r0, r3, r16 //}}} //{{{ give_stepping .globl _give_stepping .align 8 _give_stepping:: ld.c epsr, r16 shr 8, r16, r16 bri r1 and 0x1f, r16, r16 //}}} //{{{ give_860type .globl _give_860type .align 8 _give_860type:: ld.c epsr, r16 bri r1 and 0xff, r16, r16 //}}} //}}} // // these are the function prototypes // // extern void preplanarize_fn ( float *coeffs, VERTEX *v1, VERTEX *v2, VERTEX *v3, VERTEX *v4 ); // extern void edgize_tri_fn ( void ); // extern void edgize_quad_fn ( void ); // extern void zbuffer_fn ( void ); // extern void zb_plus2_fn ( void ); // extern void planarize_fn ( int pp5_opcode, int index ); // extern void binitize_fn ( int macro_lo, int macro_hi, // int scrmaxx, int scrmaxy, int scrbinsx ) // extern void safe_binitize_fn ( int macro_lo, int macro_hi, int scrbinsx ) // #if 0 //{{{ edgize_tri_fn_p pipelined, dual-instruction GOOD ONE // per edge // // eqn[0]=p1[Y] - p2[Y]; // eqn[1]=p2[X] - p1[X]; // eqn[2]=(p2[Y]*p1[X]) - (p2[X]*p1[Y]); // // good general approach for anything 'triangly' - open out the loop in // 3s, dealing with a vertex at a time. The coding couldnt be simpler, // and yields a floating point result per tick // // // nb // we enter here with rcoeffptr pre-decremented by 4 bytes // .globl _edgize_tri_fn_p .align 8 _edgize_tri_fn_p:: d.pfsub.ss fy1, fy2, f0 st.l iparam1, 4(rcoeffptr) d.pfsub.ss fy2, fy3, f0 nop d.pfsub.ss fy3, fy1, f0 nop // d.pfsub.ss fx2, fx1, ftmp2 nop d.pfsub.ss fx3, fx2, ftmp1 fst.l ftmp2, 8(rcoeffptr) // edge[0] eqn[0] d.pfsub.ss fx1, fx3, ftmp2 fst.l ftmp1, 24(rcoeffptr) // edge[1] eqn [0] // // eqn[2]=(p2[Y]*p1[X]) - (p2[X]*p1[Y]); // d.m12tpm.ss fx1, fy2, ftmp1 fst.l ftmp2, 40(rcoeffptr) // edge[2] eqn [0] d.m12tpm.ss fx2, fy3, ftmp2 nop d.m12tpm.ss fx3, fy1, ftmp3 st.l iparam1, 20(rcoeffptr) d.pfmul.ss fy1, fx2, ftmp4 // fy2*fx1 nop d.pfmul.ss fy2, fx3, ftmp5 // fy3*fx2 fst.l ftmp1, 12(rcoeffptr) // edge[0] eqn[1] d.pfmul.ss fy3, fx1, ftmp6 // fy1*fx3 fst.l ftmp2, 28(rcoeffptr) // edge[1] eqn[1] d.i2s1.ss ftmp4, f0, f0 // push y2*x1 - x2*y1 fst.l ftmp3, 44(rcoeffptr) // edge[2] eqn[1] d.i2s1.ss ftmp5, f0, f0 nop d.i2s1.ss ftmp6, f0, f0 st.l iparam1, 36(rcoeffptr) d.pfadd.ss f0, f0, ftmp1 fst.l ftmp1, 16(rcoeffptr) // edge[0] eqn[2] d.pfadd.ss f0, f0, ftmp2 fst.l ftmp2, 32(rcoeffptr) // edge[1] eqn[2] pfadd.ss f0, f0, ftmp3 fst.l ftmp3, 48(rcoeffptr)++ // edge[2] eqn[2] fnop bri r1 //}}} #endif #if 0 //{{{ preplanaredge // // // .globl _preplanaredge .align 8 // // preplanarize_fn ( float *coeffs, unused, v1, v2, v3, v4 ); // // preplanarize sets up the shared expressions and edgeizes the // triangle - we need to cache the deltas dx0, dx1, dx2 into registers, // determine whether triangle subtends too small an area on-screen, and do // trivial rejection based on screen-space bounds // // VICIOUS - returns TRIV_REJECT in r31 // _preplanaredge:: // preplanaredge - calcDeltas in unc-speak, ROLLED IN WITH edgize_tri // // dx0 = x1 // dy0 = y1 // dx1 = x2 - x1 // dy1 = y2 - y1 // dx2 = x3 - x1 // dy2 = y3 - y1 // c = 1.0f / (dx1 * dy2) - (dy1 * dx2) // dx1*=c // dx2*=c // dy1*=c // dy2*=c // // nb we can define x0, x1, x2 etc as dx0, dx1, dx2 // #define max_screen_x fx4 #define max_screen_y fy4 orh ha%.C00037, r0, r31 // pre-load 2.0000e+00 fld.l l%.C00037(r31), ftmp3 orh ha%.C362436, r0, r31 // pre-load minimum area fld.l l%.C362436(r31), ftmp1 orh ha%.Cmax_x, r0, r31 fld.d l%.Cmax_x(r31), max_screen_x orh ha%_screenize_rec, r0, r31 or l%_screenize_rec, r31, r31 fld.d 0(r31), fminx fld.d 8(r31), fmaxx // now pipe up repeated expressions // dx1 = x1 - x0 // dy1 = y1 - y0 // dx2 = x2 - x0 // dy2 = y2 - y0 // c = 1.0f / (dx1 * dy2) - (dy1 * dx2) pfsub.ss fx2, fx1, f0 pfsub.ss fx3, fx1, f0 pfsub.ss fy2, fy1, f0 pfsub.ss fy3, fy1, dx1 pfsub.ss f0, f0, dx2 m12ttpa.ss dx1, dx2, dy1 // m-stage1 = x1*x2 m12ttpa.ss f0, f0, dy2 // 2 m12ttpa.ss dy1, dy2, f0 // m-stage1 = y1*y2, m-stage3 = x1*x2 i2ap1.ss f0, f0, f0 // x1*x2 into T i2st.ss f0, f0, f0 // x1*x2 - y1*y2 into a-stage 1 // // these are rolled into edgize below // // pfadd.ss f0, f0, f0 // stage 2 // pfadd.ss f0, f0, f0 // stage 3 // pfadd.ss f0, f0, fC // into C // // in-line edgize_tri !!! // per edge // // eqn[0]=p1[Y] - p2[Y]; // eqn[1]=p2[X] - p1[X]; // eqn[2]=(p2[Y]*p1[X]) - (p2[X]*p1[Y]); // // so edge1 A = y1-y2 // so edge1 B = x2-x1 // C = y2x1 - x2y1 // so edge2 A = y2-y3 // so edge2 B = x3-x2 // C = y3x2 - x3y2 // so edge3 A = y3-y1 // so edge3 B = x1-x3 // C = y1x3 - x1y3 // // nb we enter here with rcoeffptr pre-decremented by 4 bytes // // there are 15 flops above, of which we need to compute 13 // (y3-y1, x2-x1 are already in registers), so lets get // it down to 13 ticks? m12apm.ss x1, y2, f0 m12apm.ss x2, y1, f0 m12apm.ss x2, y3, fC // saved 3 ticks there ! m12ttpa.ss x3, y2, f0 // push x1y2 to T m12tsm.ss x3, y1, f0 // adder 1 = x1y2 - x2y1 pfmul.ss y3, x1, ftmp1 // ftmp1 = x2y3 mim1s2.ss y1, y2, ftmp2 // ftmp2 = x3y2, adder1 = y1-y2 mim1s2.ss ftmp1, ftmp2, ftmp1 // ftmp1 = x3y1, adder3=x1y2-x2y1 rat1s2.ss x1, x3, fA // fA = edge1 A, T = x3y1 r2st.ss f0, f0, ftmp2 // adder1=y1x3-x1y3, ftmp2=y1-y2 // multiplier is now flushed! pfsub.ss y2, y3, ftmp3 // tmp3 = x2y3-x3y2 pfsub.ss x1, x3, ftmp4 // tmp4 = x1 - x3 pfadd.ss f0, f0, ftmp5 // tmp5 = y1x3 - x1y3 pfadd.ss f0, f0, ftmp6 // tmp6 = y2 - y3 pfadd.ss f0, f0, ftmp7 // tmp7 = x1 - x3 // now invert C - try to roll this in above? // // d1 = recp (V) // b = d1 * V // c = 2 - b // d2 = d1 * c // e = d2 * V // f = 2 - e // inv = d2 * f frcp.ss fC, ftmp1 // start 1.0 / fC - 2^-8 fmul.ss fC, ftmp1, ftmp2 // guess * divisor fld.l iparam2(rv1), fv1 fsub.ss ftmp3, ftmp2, ftmp2 // 2 - (guess * divisor) fmul.ss ftmp1, ftmp2, ftmp1 // 2^-15 fld.l iparam2(rv2), fv2 fmul.ss fC, ftmp1, ftmp2 // guess * divisor fsub.ss ftmp3, ftmp2, ftmp2 // 2 - (guess * divisor) fld.l iparam2(rv3), fv3 fmul.ss ftmp1, ftmp2, fC // 2^-23 - run with it pfmul.ss fC, dx1, f0 pfmul.ss fC, dx2, f0 pfmul.ss fC, dy1, f0 pfmul.ss fC, dy2, f0 pfmul.ss fC, fC, dx1 pfmul.ss f0, f0, dx2 pfmul.ss f0, f0, dy1 pfmul.ss f0, f0, dy2 pfmul.ss f0, f0, fC // fC now == C^2 pfgt fC, ftmp1, f0 bnc .triv_reject // if area < MINAREA, triv_reject // ****************************************** // clamp minimax against screen max coordinates // now get real minimax xy for binning // // firstly check triv rejection, max < 0 etc. // pfgt.ss ftmp1, fmaxx, f0 bc .triv_reject pfgt.ss ftmp1, fmaxy, f0 bc .triv_reject pfgt.ss fminx, max_screen_x, f0 bc .triv_reject pfgt.ss fminy, max_screen_y, f0 bc .triv_reject // now check binning // get real minx pfgt.ss fminx, f0, f0 bc .no_clamp_fminx fmov.ss f0, fminx .no_clamp_fminx:: // get real miny pfgt.ss fminy, f0, f0 bc .no_clamp_fminy fmov.ss f0, fminy .no_clamp_fminy:: // get real maxx pfgt.ss max_screen_x, fmaxx, f0 bc .no_clamp_fmaxx fmov.ss max_screen_x, fmaxx .no_clamp_fmaxx:: // get real maxy pfgt.ss max_screen_y, fmaxy, f0 bc .no_clamp_fmaxy fmov.ss max_screen_y, fmaxy .no_clamp_fmaxy:: bri r1 or 0x0, r0, r31 .triv_reject:: bri r1 or 0x1, r0, r31 //}}} //{{{ preplanaredge - roll 1/C into pipelined sequence // // // .globl _preplanaredge .align 8 // // preplanarize_fn ( float *coeffs, unused, v1, v2, v3, v4 ); // // preplanarize sets up the shared expressions and edgeizes the // triangle - we need to cache the deltas dx0, dx1, dx2 into registers, // determine whether triangle subtends too small an area on-screen, and do // trivial rejection based on screen-space bounds // // VICIOUS - returns TRIV_REJECT in r31 // _preplanaredge:: // preplanaredge - calcDeltas in unc-speak, ROLLED IN WITH edgize_tri // // dx0 = x1 // dy0 = y1 // dx1 = x2 - x1 // dy1 = y2 - y1 // dx2 = x3 - x1 // dy2 = y3 - y1 // c = 1.0f / (dx1 * dy2) - (dy1 * dx2) // dx1*=c // dx2*=c // dy1*=c // dy2*=c // // nb we can define x0, x1, x2 etc as dx0, dx1, dx2 // #define max_screen_x fx4 #define max_screen_y fy4 orh ha%.C00037, r0, r31 // pre-load 2.0000e+00 fld.l l%.C00037(r31), ftmp3 orh ha%.C362436, r0, r31 // pre-load minimum area fld.l l%.C362436(r31), ftmp1 orh ha%.Cmax_x, r0, r31 fld.d l%.Cmax_x(r31), max_screen_x orh ha%_screenize_rec, r0, r31 or l%_screenize_rec, r31, r31 fld.d 0(r31), fminx fld.d 8(r31), fmaxx // now pipe up repeated expressions // dx1 = x1 - x0 // dy1 = y1 - y0 // dx2 = x2 - x0 // dy2 = y2 - y0 // c = 1.0f / (dx1 * dy2) - (dy1 * dx2) pfsub.ss fx2, fx1, f0 pfsub.ss fx3, fx1, f0 pfsub.ss fy2, fy1, f0 pfsub.ss fy3, fy1, dx1 pfsub.ss f0, f0, dx2 m12ttpa.ss dx1, dx2, dy1 // m-stage1 = x1*x2 m12ttpa.ss f0, f0, dy2 // 2 m12ttpa.ss dy1, dy2, f0 // m-stage1 = y1*y2, m-stage3 = x1*x2 i2ap1.ss f0, f0, f0 // x1*x2 into T r2st.ss f0, f0, f0 // x1*x2 - y1*y2 into a-stage 1 m12apm.ss x1, y2, f0 m12apm.ss x2, y1, f0 // m 1 2 3 a 1 2 3 m12apm.ss x2, y3, fC // x2y3 x2y1 x1y2 frcp.ss fC, frcp // in-line edgize_tri !!! // per edge // // eqn[0]=p1[Y] - p2[Y]; // eqn[1]=p2[X] - p1[X]; // eqn[2]=(p2[Y]*p1[X]) - (p2[X]*p1[Y]); // // so edge1 A = y1-y2 // so edge1 B = x2-x1 // C = y2x1 - x2y1 // so edge2 A = y2-y3 // so edge2 B = x3-x2 // C = y3x2 - x3y2 // so edge3 A = y3-y1 // so edge3 B = x1-x3 // C = y1x3 - x1y3 // // nb we enter here with rcoeffptr pre-decremented by 4 bytes // // there are 15 flops above, of which we need to compute 13 // (y3-y1, x2-x1 are already in registers), so lets get // it down // // d1 = recp (V) // b = d1 * V // c = 2 - b // d2 = d1 * c // e = d2 * V // f = 2 - e // inv = d2 * f m12ttpa.ss x3, y2, f0 // push x1y2 to T m12tsm.ss x3, y1, f0 // adder 1 = x1y2 - x2y1 pfmul.ss y3, x1, ftmp1 // ftmp1 = x2y3 mim1s2.ss y1, y2, ftmp2 // ftmp2 = x3y2, adder1 = y1-y2 mim1s2.ss ftmp1, ftmp2, ftmp1 // ftmp1 = x3y1, adder3=x1y2-x2y1 rat1s2.ss x1, x3, fA // fA = edge1 A, T = x3y1 m12tsm.ss frcp, fC, ftmp2 // adder1=y1x3-x1y3, ftmp2=y1-y2 ia1s2.ss y2, y3, ftmp3 // tmp3 = x2y3-x3y2 ia1s2.ss x1, x3, ftmp4 // tmp4 = x1 - x3 i2s1.ss two, f0, ftmp5 // tmp5 = y1x3 - x1y3 adder1=2-rcp*C r2pt.ss frcp, f0, ftmp6 // tmp6 = y2 - y3 push rcp into KR pfadd.ss f0, f0, ftmp7 // tmp7 = x1 - x3 rat1p2.ss f0, f0, f0 // mul-1 = rcp*(2-rcp*c) pfmul.ss f0, f0, f0 pfmul.ss f0, f0, f0 pfmul.ss f0, f0, frcp // now unpipeline ? fmul.ss fC, frcp, ftmp // guess*divisor fsub.ss two, ftmp, ftmp // 2-guess*divisor fmul.ss fC, ftmp, fC // result ! pfmul.ss dx1, fC, f0 pfmul.ss fC, dx2, f0 pfmul.ss fC, dy1, f0 pfmul.ss fC, dy2, f0 pfmul.ss fC, fC, dx1 pfmul.ss f0, f0, dx2 pfmul.ss f0, f0, dy1 pfmul.ss f0, f0, dy2 pfmul.ss f0, f0, fC // fC now == C^2 pfgt fC, ftmp1, f0 bnc .triv_reject // if area < MINAREA, triv_reject // ****************************************** // clamp minimax against screen max coordinates // now get real minimax xy for binning // // firstly check triv rejection, max < 0 etc. // pfgt.ss ftmp1, fmaxx, f0 bc .triv_reject pfgt.ss ftmp1, fmaxy, f0 bc .triv_reject pfgt.ss fminx, max_screen_x, f0 bc .triv_reject pfgt.ss fminy, max_screen_y, f0 bc .triv_reject // now check binning // get real minx pfgt.ss fminx, f0, f0 bc .no_clamp_fminx fmov.ss f0, fminx .no_clamp_fminx:: // get real miny pfgt.ss fminy, f0, f0 bc .no_clamp_fminy fmov.ss f0, fminy .no_clamp_fminy:: // get real maxx pfgt.ss max_screen_x, fmaxx, f0 bc .no_clamp_fmaxx fmov.ss max_screen_x, fmaxx .no_clamp_fmaxx:: // get real maxy pfgt.ss max_screen_y, fmaxy, f0 bc .no_clamp_fmaxy fmov.ss max_screen_y, fmaxy .no_clamp_fmaxy:: bri r1 or 0x0, r0, r31 .triv_reject:: bri r1 or 0x1, r0, r31 //}}} //{{{ edgize_tri pipelined, dual-instruction // we have in register fy12, fy31, fy23 and // fx13, fx21, fx32 // so this can shrink to 10 ticks from 20 // per edge // // eqn[0]=p1[Y] - p2[Y]; // eqn[1]=p2[X] - p1[X]; // eqn[2]=(p2[Y]*p1[X]) - (p2[X]*p1[Y]); // // so edge1 A = y1-y2 // so edge1 B = x2-x1 // C = y2x1 - x2y1 // so edge2 A = y2-y3 // so edge2 B = x3-x2 // C = y3x2 - x3y2 // so edge3 A = y3-y1 // so edge3 B = x1-x3 // C = y1x3 - x1y3 // // nb we enter here with rcoeffptr pre-decremented by 4 bytes // .globl _edgize_tri .align 8 _edgize_tri:: // there are 15 flops above, of which we need to compute 13 // (y3-y1, x2-x1 are already in registers), so lets get // it down to 13 ticks? pfmul.ss x1, y2, f0 pfmul.ss x2, y1, f0 pfmul.ss x2, y3, f0 m12ttpa.ss x3, y2, f0 // push x1y2 to T m12tsm.ss x3, y1, f0 // adder 1 = x1y2 - x2y1 pfmul.ss y3, x1, ftmp1 // ftmp1 = x2y3 mim1s2.ss y1, y2, ftmp2 // ftmp2 = x3y2, adder1 = y1-y2 mim1s2.ss ftmp1, ftmp2, ftmp1 // ftmp1 = x3y1, adder3=x1y2-x2y1 rat1s2.ss x1, x3, fA // fA = edge1 A, T = x3y1 r2st.ss f0, f0, ftmp2 // adder1=y1x3-x1y3, ftmp2=y1-y2 // multiplier is now flushed! pfsub.ss y2, y3, ftmp3 // tmp3 = x2y3-x3y2 pfsub.ss x1, x3, ftmp4 // tmp4 = x1 - x3 pfadd.ss f0, f0, ftmp5 // tmp5 = y1x3 - x1y3 pfadd.ss f0, f0, ftmp6 // tmp6 = y2 - y3 pfadd.ss f0, f0, ftmp7 // tmp7 = x1 - x3 //}}} //{{{ _old_planarize_fn_p pipelined DONT STORE OPCODE // // Hey Ho Lets Go! // // The definitive planarization algorithm // // invC=1.0f / (fx1 * (fy2 - fy3)) + // (fx2 * (fy3 - fy1)) + // (fx3 * (fy1 - fy2)); // // eqn[0]= invC*(fy1 * (fv3 - fv2)) + // (fy2 * (fv1 - fv3)) + // (fy3 * (fv2 - fv1)); // // a = fv3 - fv2 // b = fv1 - fv3 // c = fv2 - fv1 // d = fy1 * a // e = fy2 * b // f = fy3 * c // g = d + e // h = g + f // eqn[0] = fC * h // // eqn[1]= invC*(fv1 * (fx3 - fx2)) + // (fv2 * (fx1 - fx3)) + // (fv3 * (fx2 - fx1)); // // i = fv1 * fx32 // j = fv2 * fx13 // k = fv3 * fx21 // l = i + j // m = k + l // eqn[1] = fC * m // // eqn[2]= invC*(fx1*((fy2*fv3) - (fy3*fv2))) + // (fx2*((fy3*fv1) - (fy1*fv3))) + // (fx3*((fy1*fv2) - (fy2*fv1))); // // n = fy2 * fv3 // o = fy3 * fv2 // p = fy3 * fv1 // q = fy1 * fv3 // r = fy1 * fv2 // s = fy2 * fv1 // t = n - o // u = p - q // v = r - s // w = fx1 * t // x = fx2 * u // y = fx3 * v // z = w + x // aa= y + z // eqn[2] = invC * aa // #define ft1 ftmp1 #define ft2 ftmp2 #define ft3 ftmp3 .globl _old_planarize_fn_p .globl _planarize_fn_p .align 8 _old_planarize_fn_p:: _planarize_fn_p:: // m1 m2 m3 | T | a1 a2 a3 | KR | t1 t2 t3 // n = fy2 * fv3 // o = fy3 * fv2 pfmul.ss fy2, fv3, f0 // n ? ? | ? | ? ? ? | ? | ? ? ? pfmul.ss fy3, fv2, f0 // o n ? | ? | ? ? ? | ? | ? ? ? // p = fy3 * fv1 // q = fy1 * fv3 pfmul.ss fy3, fv1, f0 // p o n | ? | ? ? ? | ? | ? ? ? mm12ttpm.ss fy1, fv3, f0 // q p o | n | ? ? ? | ? | ? ? ? // r = fy1 * fv2 // t = n - o // s = fy2 * fv1 m12tsm.ss fy1, fv2, f0 // r q p | ? | t ? ? | ? | ? ? ? mm12ttpm.ss fy2, fv1, f0 // s r q | p | ? t ? | ? | ? ? ? // i = fv1 * fx32 // u = p - q // a = fv3 - fv2 m12tsm.ss fv1, fx32, f0 // i s r | ? | u ? t | ? | ? ? ? pfsub.ss fv3, fv2, ft1 // i s r | ? | a u ? | ? | t ? ? // j = fv2 * fx13 // k = fv3 * fx21 // v = r - s mm12ttpm.ss fv2, fx13, f0 // j i s | r | ? a u | ? | t ? ? m12tsm.ss fv3, fx21, ft2 // k j i | ? | v ? a | ? | t u ? // w = fx1 * t // x = fx2 * u pfmul.ss fx1, ft1, ft3 // w k j | ? | v ? a | ? | ? u i pfmul.ss fx2, ft2, ft1 // x w k | ? | v ? a | ? | j ? i // l = i + j // d = fy1 * a pfadd.ss ft1, ft3, ft2 // x w k | ? | l v ? | ? | ? a ? mm12mpm.ss fy1, ft2, ft3 // d x w | ? | ? l v | ? | ? ? k // b = fv1 - fv3 // c = fv2 - fv1 pfsub.ss fv1, fv3, ft1 // d x w | ? | b ? l | ? | v ? k pfsub.ss fv2, fv1, ft2 // d x w | ? | c b ? | ? | v l k // m = k + l // y = fx3 * v // z = w + x rat1p2.ss ft2, ft3, f0 // ? d x | w | m c b | ? | v ? ? m12tpm.ss fx3, ft1, ft2 // y ? d | ? | z m c | ? | ? b ? // e = fy2 * b // f = fy3 * c d.m12ttpa.ss fy2, ft2, ft1 // e y ? | d | ? z m | ? | c ? ? fld.l iparam2(rv3), fv3 d.m12apm.ss fy3, ft1, ft2 // f e y | d | ? ? z | ? | ? m ? fld.l iparam2(rv2), fv2 // last-stage mul+T ->g, fC -> KR, save adder result ! // eqn[1] = fC * m // g = d + e d.pfmul.ss fC, ft2, ft1 // e1 f e | d | ? ? z | ? | y ? ? nop d.r2pt.ss fC, f0, ft2 // ? e1 f | ? | g ? ? | ? | y z ? fld.l iparam2(rv1), fv1 // aa= y + z d.mrm1p2.ss ft1, ft2, ft3 // ? ? e1| ? | aa g ? | ? | ? ? f nop d.mm12mpm.ss f0, f0, ft2 // ? ? ? | ? | ? aa g | ? | ? e1 f adds 4, rcoeffptr, rcoeffptr // h = g + f // eqn[2] = invC * aa d.r2ap1.ss ft3, f0, f0 // ? ? ? | ? | h ? aa | ? | ? e1 ? nop d.ra1p2.ss f0, f0, f0 // e2 ? ? | ? | ? h ? | ? | ? e1 ? nop // eqn[0] = fC * h d.i2p1.ss f0, f0, f0 // ? e2 ? | ? | ? ? h | ? | ? e1 ? fst.l ft2, 12(rcoeffptr) d.rat1p2.ss f0, f0, f0 nop d.mi2p1.ss f0, f0, ft1 nop d.mi2p1.ss ft3, f0, f0 fst.l ft1, 16(rcoeffptr)++ mi2p1.ss f0, f0, ft3 bri r1 fnop fst.l ft3, -8(rcoeffptr) //}}} //{{{ edgize_tri_fn_p pipelined, dual-instruction, DONT STORE OPCODE // per edge // // eqn[0]=p1[Y] - p2[Y]; // eqn[1]=p2[X] - p1[X]; // eqn[2]=(p2[Y]*p1[X]) - (p2[X]*p1[Y]); // // good general approach for anything 'triangly' - open out the loop in // 3s, dealing with a vertex at a time. The coding couldnt be simpler, // and yields a floating point result per tick // // // nb // we enter here with rcoeffptr pre-decremented by 4 bytes // .globl _edgize_tri_fn_p .align 8 _edgize_tri_fn_p:: d.pfsub.ss fy1, fy2, f0 nop d.pfsub.ss fy2, fy3, f0 nop d.pfsub.ss fy3, fy1, f0 nop // d.pfsub.ss fx2, fx1, ftmp2 nop d.pfsub.ss fx3, fx2, ftmp1 fst.l ftmp2, 8(rcoeffptr) // edge[0] eqn[0] d.pfsub.ss fx1, fx3, ftmp2 fst.l ftmp1, 24(rcoeffptr) // edge[1] eqn [0] // // eqn[2]=(p2[Y]*p1[X]) - (p2[X]*p1[Y]); // d.m12tpm.ss fx1, fy2, ftmp1 fst.l ftmp2, 40(rcoeffptr) // edge[2] eqn [0] d.m12tpm.ss fx2, fy3, ftmp2 nop d.m12tpm.ss fx3, fy1, ftmp3 nop d.pfmul.ss fy1, fx2, ftmp4 // fy2*fx1 nop d.pfmul.ss fy2, fx3, ftmp5 // fy3*fx2 fst.l ftmp1, 12(rcoeffptr) // edge[0] eqn[1] d.pfmul.ss fy3, fx1, ftmp6 // fy1*fx3 fst.l ftmp2, 28(rcoeffptr) // edge[1] eqn[1] d.i2s1.ss ftmp4, f0, f0 // push y2*x1 - x2*y1 fst.l ftmp3, 44(rcoeffptr) // edge[2] eqn[1] d.i2s1.ss ftmp5, f0, f0 nop d.i2s1.ss ftmp6, f0, f0 nop d.pfadd.ss f0, f0, ftmp1 fst.l ftmp1, 16(rcoeffptr) // edge[0] eqn[2] d.pfadd.ss f0, f0, ftmp2 fst.l ftmp2, 32(rcoeffptr) // edge[1] eqn[2] d.pfadd.ss f0, f0, ftmp3 fst.l ftmp3, 48(rcoeffptr)++ // edge[2] eqn[2] fnop bri r1 fnop //}}} #endif #if 0 //{{{ _new_planarize_fn_p pipelined #define df1 ftmp1 #define df2 ftmp2 #define ft3 ftmp3 #define fA ftmp4 #define fB ftmp5 #define fC ftmp6 #define tmp1 ftmp7 #define tmp2 ftmp8 // // The new and totally definitive planarization algorithm // // df1 = fv1 - fv0 // df2 = fv2 - fv0 // A = (dy2*df1) - (dy1*df2) // B = (dx1*df2) - (dx2*df1) // C = fv0 - (A * dx0) - (B * dy0) // .globl _new_planarize .align 8 _new_planarize:: d.pfsub.ss fv1, fv0, f0 nop d.pfsub.ss fv2, fv0, f0 fld.l iparam2(rv2), fv2 // load up vertex 1 for next call d.i2pt.ss dx0, f0, f0 nop // st fC from last scalar op d.r2pt.ss dy0, f0, df1 // click pipe, drop dy0 into KR fld.l iparam2(rv3), fv3 // ditto v2 d.m12apm.ss dy2, df1, df2 // nop d.m12apm.ss dy1, df2, f0 // nop d.pfmul.ss dx1, df2, f0 // st.l 4(rcoeffptr), iparam1 d.pfmul.ss dx2, df1, fA // ... dy2*df1 adds 4, rcoeffptr, rcoeffptr d.i2s1.ss fA, f0, f0 // 1st stage adder = A nop d.i2ap1.ss f0, f0, f0 // T-reg = dx1*df2 nop d.i2st.ss dx0, f0, f0 // 1st-stage adder = B, 3rd stage = A nop d.iat1p2.ss f0, f0, fA // 1st stage mult = A*dx0 (KI) fst.l fA, 4(rcoeffptr)++ d.ia1p2.ss f0, f0, f0 // .. click pipes nop d.rat1s2.ss f0, f0, fB // 1st stage mult = B*dy0 (KR) fst.l fB, 4(rcoeffptr)++ d.i2s1.ss fv0, f0, f0 // 1st stage add = f0 - A*dx0 nop d.ra1p2.ss f0, f0, f0 // .. click pipes fld.l iparam2(rv1), fv1 d.mr2pt.ss f0, f0, tmp1 // nop ia1p2.ss f0, f0, tmp2 // bri r1 fsub.ss tmp2, tmp1, fC // 21 ticks in total nop #undef df1 #undef df2 #undef ft3 #undef fA #undef fB #undef fC #undef tmp1 #undef tmp2 //}}} #endif //{{{ fsr access // .globl _getFsr // .align 8 //_getFsr:: // bri r1 // ld.c fsr, r16 // // // .globl _setFsr // .align 8 //_setFsr:: // bri r1 // st.c r16, fsr //}}} //{{{ _reg_dump .globl _reg_dump .align 8 _reg_dump:: //{{{ proc entry - save r1 r2 r3 addu -256, sp, sp st.l r1,0(sp) adds 256,sp,r1 // save r2 **before** call into stack frame st.l r1,4(sp) st.l fp,8(sp) //}}} //{{{ save r4..r31, f2..f31 st.l r4, 12(sp) st.l r5, 16(sp) st.l r6, 20(sp) st.l r7, 24(sp) st.l r8, 28(sp) st.l r9, 32(sp) st.l r10, 36(sp) st.l r11, 40(sp) st.l r12, 44(sp) st.l r13, 48(sp) st.l r14, 52(sp) st.l r15, 56(sp) st.l r16, 60(sp) //st.l r17, 64(sp) st.l r18, 68(sp) st.l r19, 72(sp) st.l r20, 76(sp) st.l r21, 80(sp) st.l r22, 84(sp) st.l r23, 88(sp) st.l r24, 92(sp) st.l r25, 96(sp) st.l r26, 100(sp) st.l r27, 104(sp) st.l r28, 108(sp) st.l r29, 112(sp) st.l r30, 116(sp) st.l r31, 120(sp) adds 120, sp, sp fst.l f2, 4(sp)++ fst.l f3, 4(sp)++ fst.l f4, 4(sp)++ fst.l f5, 4(sp)++ fst.l f6, 4(sp)++ fst.l f7, 4(sp)++ fst.l f8, 4(sp)++ fst.l f9, 4(sp)++ fst.l f10, 4(sp)++ fst.l f11, 4(sp)++ fst.l f12, 4(sp)++ fst.l f13, 4(sp)++ fst.l f14, 4(sp)++ fst.l f15, 4(sp)++ fst.l f16, 4(sp)++ fst.l f17, 4(sp)++ fst.l f18, 4(sp)++ fst.l f19, 4(sp)++ fst.l f20, 4(sp)++ fst.l f21, 4(sp)++ fst.l f22, 4(sp)++ fst.l f23, 4(sp)++ fst.l f24, 4(sp)++ fst.l f25, 4(sp)++ fst.l f26, 4(sp)++ fst.l f27, 4(sp)++ fst.l f28, 4(sp)++ fst.l f29, 4(sp)++ fst.l f30, 4(sp)++ fst.l f31, 4(sp)++ adds -240, sp, sp //}}} call _trace_regs mov sp, r16 //{{{ restore all ld.l 12(sp) , r4 ld.l 16(sp) , r5 ld.l 20(sp) , r6 ld.l 24(sp) , r7 ld.l 28(sp) , r8 ld.l 32(sp) , r9 ld.l 36(sp) , r10 ld.l 40(sp) , r11 ld.l 44(sp) , r12 ld.l 48(sp) , r13 ld.l 52(sp) , r14 ld.l 56(sp) , r15 ld.l 60(sp) , r16 ld.l 64(sp) , r17 ld.l 68(sp) , r18 ld.l 72(sp) , r19 ld.l 76(sp) , r20 ld.l 80(sp) , r21 ld.l 84(sp) , r22 ld.l 88(sp) , r23 ld.l 92(sp) , r24 ld.l 96(sp) , r25 ld.l 100(sp) , r26 ld.l 104(sp) , r27 ld.l 108(sp) , r28 ld.l 112(sp) , r29 ld.l 116(sp) , r30 ld.l 120(sp) , r31 adds 120, sp, sp fld.l 4(sp)++, f2 fld.l 4(sp)++, f3 fld.l 4(sp)++, f4 fld.l 4(sp)++, f5 fld.l 4(sp)++, f6 fld.l 4(sp)++, f7 fld.l 4(sp)++, f8 fld.l 4(sp)++, f9 fld.l 4(sp)++, f10 fld.l 4(sp)++, f11 fld.l 4(sp)++, f12 fld.l 4(sp)++, f13 fld.l 4(sp)++, f14 fld.l 4(sp)++, f15 fld.l 4(sp)++, f16 fld.l 4(sp)++, f17 fld.l 4(sp)++, f18 fld.l 4(sp)++, f19 fld.l 4(sp)++, f20 fld.l 4(sp)++, f21 fld.l 4(sp)++, f22 fld.l 4(sp)++, f23 fld.l 4(sp)++, f24 fld.l 4(sp)++, f25 fld.l 4(sp)++, f26 fld.l 4(sp)++, f27 fld.l 4(sp)++, f28 fld.l 4(sp)++, f29 fld.l 4(sp)++, f30 fld.l 4(sp)++, f31 adds -240, sp, sp //}}} //{{{ proc exit ld.l 0(sp),r1 ld.l 8(sp),fp bri r1 addu 256, sp, sp //}}} //}}} // constant for 1/x code .data .align 8 .Cmax_x: // (0) .C640: .long 0x442fbf5c // 7.02989990E+02 .Cmax_y: // (0) .C480: .long 0x43ff7eb8 // 5.10989990E+02 .C00037: // (0) .long 0x40000000 // 2.00000000E+00 .C362436: // (0) .long 0x3ecccccd // 4.00000006E-01 .Czscale1024: // (0) .long 0x49800000 // 1.04857600E+06 .Czscale: // (0) .long 0x497fffff // 1.04857588E+06 .Ctexscale: // (0) .long 0x477fffff // 6.55359883E+04 .tri_entry: .string "triangle entry" .byte 0x0 .tri_preplanarize: .string "preplanarize" .byte 0x0 .tri_edgeized: .string "edgized triangle" .byte 0x0 .tri_zbufized: .string "zbuffered triangle" .byte 0x0 .tri_planarized: .string "planarized something" .byte 0x0 .preplane_gotc: .string "halfway thru preplane" .byte 0x0 .plane_loadedvs: .string "planarize - have loaded fv1 etc." .byte 0x0 .bini_full: .string "bin full" .byte 0x0 .bini_doneminimax: .string "binitize, done minimax" .byte 0x0 .bini_notfull: .string "bin not full" .byte 0x0 .bini_start: .string "bin start binitize" .byte 0x0 .bini_minimax: .string "bin got minimaxes" .byte 0x0 .bini_endfull: .string "end of bin full" .byte 0x0 .bini_more_x: .string "more than 1 x-bin" .byte 0x0 .bini_more_y: .string "more than 1 y-bin" .byte 0x0 .bini_x_loop: .string "x-loop in binitize" .byte 0x0 .bini_check_usage: .string "check usage count" .byte 0x0 .r5r6r7opcodes: .string "r5 r6 r7 have opcodes?" .byte 0x0 .bini_pipe_minimax: .string "computed minimax piped" .byte 0x0