Files
CydandClaude Fable 5 db7745fcd0 sda4: commit the Glaze developer hard-drive dump
Un-ignored: the dev drive is the ground truth the restoration and
emulator work constantly reference (DPL3/LIBDPL + VRENDER i860 renderer
source, BT/RP live+dev game trees, VGL_LABS pod boot, scene/audio
content). Kept in-repo for the pod-owner community.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 19:41:15 -05:00

1315 lines
37 KiB
Scheme

// 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