#define LOOP_LOW 8 /* 4, 8 and 16 now work in asm */

#if LOOP_LOW .eq. 16
#define _DCTFIR _dctfir16
#endif
#if LOOP_LOW .eq. 8
#define _DCTFIR _dctfir8
#endif
#if LOOP_LOW .eq. 4
#define _DCTFIR _dctfir4
#endif



#if 1
#define DCT_CALLER_SAVES
	.sect code,dct	// 217 words
	.export _dct
_dct:	// PROLOGUE
	ldx (I6)+1,NULL	// Room for Sp and Fp
	stx MR0,(I6)+1 ; sty I7,(I6)
	stx LR0,(I6)+1 ; sty I5,(I6)	// return address
	stx I6,(I6) ; sty I4,(I6)
	ldx (I6)+5,I4	// FP' = SP, reserve space
	ldc 512,MR0
	stx A0,(I6)+1 ; sty A1,(I6)
	stx B0,(I6)+1 ; sty B1,(I6)
	stx C0,(I6)+1 ; sty C1,(I6)
	stx D0,(I6)+1 ; sty D1,(I6)
	stx I0,(I6)+1 ; sty I1,(I6)
	stx I2,(I6)+1 ; sty I3,(I6)
	stx LC,(I6)+1 ; sty LS,(I6)
	stx LE,(I6)+1	; ldy (I4)-4,NULL
	//extra i6+1 so we can call auto function first, then increase i6

// void dct( s_int16 *all, u_int16 N ) {
//     s_int16 *in;
//     __y u_int16 NN;
//     s_int16 i;
//     __y const s_int16 *tw;
//     const u_int16 *dctmap;

//	i4:-4	N
//	i4:-3	all
//	i4:+1	in	NN
//	i4:+2	i	tw
//	i4:+3	dctmap	
//	i4:+4	k

//     tw = i_twiddle_iv;
//     for ( i = 2048; i > N; i >>= 1 )
// 	tw += i;

	.import _i_twiddle_iv

	ldx (i4)+6,B0	//i4:-4 N
	ldc _i_twiddle_iv,B1
	j $1
	ldc 2048,A1
$2:	add B1,A1,B1	//tw+=i;
	asr A1,A1
$1:	sub B0,A1,A0	//N - i
	ldc 0,A0
	jcc $2
	nop

//     i = 0;
//     for ( NN = N; NN > LOOP_LOW ; NN >>= 1, i++ )

	stx A0,(I4)-6	; sty B1,(i4)	//i4:+2 i tw
	ldx (I4)+5,A0	//i4:-4 N
	j LC2
	sty A0,(I4)	//i4:+1 NN

L2:
//  {
// 	dctmap = dcttype[i];
//         in = all;
//         for( ; in - all < N; )

	mv A1,I5
	ldx (I5),A0/*C*/
	stx A0,(I4)-6	//i4:+3 dctmap
	ldx (I4)+4,A0	//i4:-3 all
	j LC3
	stx A0,(I4)-4	//i4:+1 in

Ld4:
//  {
// 	    u_int16 k = 0;
//             for( k = 0; k < *dctmap; k++ ) {
// 		dctii(in, NN);
//                 in += NN;

	// Register parameter: C1, pass by value
	// Register parameter: I2, pass by value

	add a1,c1,a0	; ldx (i4)+3,i2	//i4:+1 in
	ldx (i4)-3,a1	; ldy (i6)+1,null	//i4:+4 k
	sub a1,ones,a1	; stx a0,(i4)+3		//i4:+1 in
	call _dctii
	stx A1,(I4)	//i4:+4 k

LC4:
	ldx (i4)-1,A1	//i4:+4 k
	ldx (I4)-2,I7	//i4:+3 dctmap
	ldx (I7),A0/*C*/ 
	sub A1,A0,B0
	nop
	jcc Ld4
	ldx (i4),a1	; ldy (i4),c1	//i4:+1 in NN

//             }
//             if ( in - all >= N )

//  {
//                 break;
	ldx (I4)-4,A0	//i4:+1 in
	ldx (I4)-1,A1			//i4:-3 all
	sub A0,A1,A0 ; ldx (I4)+5,A1	//i4:-4 N
	sub A0,A1,B0 ; ldy (I4)+1,A0	//i4:+1 NN
	ldy (I4),A1	//i4:+2 tw
	jcs LE3
	nop
//             }
// 	    dctiv(in, NN, tw);

	// Register parameter: I2, pass by value
	// Register parameter: A1, pass by value
	// Register parameter: A0, pass by value
	ldy (I4)-1,I2 ; ldx (I6)+1,NULL	//i4:+2 tw
	call _dctiv
	ldy (I4),A1 ; ldx (I4),A0	//i4:+1 NN

//             in += NN;
// 	    dctmap++;

	ldy (I4),A0 ; ldx (I4)+2,A1	//i4:+1 NN
	add A1,A0,A0	; ldx (I4)-2,A1	//i4:+3 dctmap
	sub A1,ONES,A1	; stx A0,(I4)+2	//i4:+1 in<-
	stx A1,(I4)-6	//i4:+3 dctmap
LC3:
	// in already in A0 (both branches)
	ldx (I4)-1,A1	//i4:-3 all
	sub A0,A1,A0 ; ldx (I4)+4,A1	//i4:-4 N
	sub A0,A1,B0 ; ldx (I4)+4,NULL	//->i4:+4 k
	ldc 0,A1
	jcc LC4
	stx A1,(I4)	//i4:+4 k = 0

//         }
//         tw += NN;

	ldx (I4)-3,NULL
	ldy (I4)+1,A0	//i4:+1 NN
	ldy (I4),A1	//i4:+2 tw
LE3:
	add A1,A0,A0
	sty A0,(I4)	; ldx (I4)-1,A0	//i4:+2 i ->tw
	sub A0,ONES,A0	; ldy (I4)+1,A1	//i4:+1 NN
	lsr A1,A1	; stx A0,(I4)-1	//i4:+2 i
	sty A1,(I4)	//i4:+1 NN
LC2:
	ldc LOOP_LOW,A0
	ldy (I4)+1,A1	//i4:+1 NN
	sub A0,A1,C0	; ldx (I4)+1,B0	//i4:+2 i
	.import _dcttype
	ldc _dcttype,A1
	jcc L2
	add A1,B0,A1

//     }
//     dctmap = dcttype[i];
//     in = all;
//     for ( ; in - all < N; )

	mv A1,I5
	ldx (I5),A0/*C*/
	stx A0,(I4)-6	//i4:+3 dctmap
	ldx (I4)+4,A0	//i4:-3 all
	j LC9
	stx A0,(I4)-4	//i4:+1 in

//  {
//         u_int16 k;
//         for ( k = 0; k < *dctmap; k++ ) {
// 	      dctfir(in, 0);
//            in += NN;

L10:
	// Register parameter: A0, pass by value
	// Register parameter: I2, pass by value
	call _DCTFIR
	ldx (I4),I2 ; ldy (I6)+1,NULL	//i4:+1 in

	ldx (I4)+3,A1	; ldy (I4),A0	//i4:+1 in NN
	add A1,A0,A0	; ldx (I4)-3,A1	//i4:+4 k
	sub A1,ONES,A1	; stx A0,(I4)+3	//i4:+1 in
	stx A1,(I4)-1	//i4:+4 k
LC10:
	// k already in A1
	ldx (I4)-2,I7	//i4:+3 dctmap
	ldx (I7),A0/*C*/
	sub A1,A0,B0	// k < *dctmap
	nop
	jcc L10	// <
	and NULL,NULL,A0

//         }
//         if ( in - all >= N )
//             break;

	ldx (I4)-4,A0	//i4:+1 in
	ldx (I4)-1,A1	//i4:-3 all
	sub A0,A1,A0 ; ldx (I4)+5,A1	//i4:-4 N
	sub A0,A1,B0
	nop
	jcs LC15
	nop

// 	dctfir(in, 1);

	// Register parameter: A0, pass by value
	// Register parameter: I2, pass by value
	call _DCTFIR
	sub NULL,ONES,A0 ; ldx (I4),I2	//i4:+1 in

//      in += NN;
// 	dctmap++;

	ldy (I4),A0	; ldx (I4)+2,A1	//i4:+1 in NN
	add A1,A0,A0	; ldx (I4)-2,A1	//i4:+3 dctmap
	sub A1,ONES,A1	; stx A0,(I4)+2	//i4:+1 in<-
	stx A1,(I4)-6	; ldy (I6)+1,NULL	//i4:+3 dctmap DCTFIR was auto
LC9:
	// in already in A0
	ldx (I4)-1,A1	//i4:-3 all
	sub A0,A1,A0 ; ldx (I4)+4,A1	//i4:-4 N
	sub A0,A1,B0 ; ldx (I4)+4,NULL
	ldc 0,A1
	jcc LC10
	stx A1,(I4)-1	//i4:+4 k = 0


//     }
//     NN <<= 1;

	j LC15
	ldx (I4)-2,NULL

L15:
//     for( i-- ; i >= 0; i-- ) {
//       in = all;
// 	 dctmap = dcttype[i];

	ldx (I4)+4,A0	//i4:-3 all
	stx A0,(I4)+1	//i4:+1 in
	ldx (I4)+1,B0	//i4:+2 i
	add A1,B0,A1	// #1 [] element size 1
	mv A1,I5
	ldx (I5),A1/*C*/
	j LC16
	stx A1,(I4)-6	//i4:+3 dctmap

L16:
//         for ( ; in - all < N; ) {
// 	       in += NN * *dctmap;
//             if ( in - all >= N )
//                 break;

	muluu A0,B0
	add NULL,P,B ; ldx (I4)-4,A1	//i4:+1 in
	add A1,B0,A0 ; ldx (I4)+4,A1	//i4:-3 all
	stx A0,(I4)-5	//i4:+1 in

	sub A0,A1,A0 ; ldx (I4)+5,A1	//i4:-4 N
	sub A0,A1,B0
	nop
	jcs LEd16
	nop

// 	    dctivpost(in, NN);
//          in += NN;
// 	    dctmap++;

	// Register parameter: D1, pass by value
	// Register parameter: D0, pass by value
	call _dctivpost
	ldx (I4),D0	; ldy (I4),D1	//i4:+1 in NN

	ldx (I4),A1	; ldy (I4)+2,A0	//i4:+1 in NN
	add A1,A0,A0	; ldx (I4)-2,A1	//i4:+3 dctmap
	sub A1,ONES,A1	; stx A0,(I4)+2	//i4:+1 in<-
	stx A1,(I4)-6	; ldy (i6)+1,null //i4:+3 dctmap, dctivpost was auto
LC16:
	// in already in A0 (both branches!)
	ldx (I4)-1,A1	//i4:-3 all
	sub A0,A1,A0 ; ldx (I4)+7,A1	//i4:-4 N
	sub A0,A1,B0 ; ldx (I4)-2,I0	//i4:+3 dctmap
	ldx (I0),A0/*C*/ ; ldy (I4),B0	//i4:+1 NN
	jcc L16
	nop

LEd16:
//         }
// 	NN <<= 1;

LC15:
	ldy (I4)+1,A0			//i4:+1 NN
	lsl A0,A0	; ldx (I4)-1,A1	//i4:+2 i
	add A1,ONES,A1	; sty A0,(I4)+1	//i4:+1 NN
	stx A1,(I4)-5	//i4:+2 i	// compare 0
	jge L15
	ldc _dcttype,A1

	ldx (i6)-1,null
	ldx (I6)-1,LE	; ldy (I4)+3,NULL
	ldx (I6)-1,LC ; ldy (I6),LS
	ldx (I6)-1,I2 ; ldy (I6),I3
	ldx (I6)-1,I0 ; ldy (I6),I1
	ldx (I6)-1,D0 ; ldy (I6),D1
	ldx (I6)-1,C0 ; ldy (I6),C1
	ldx (I6)-1,B0 ; ldy (I6),B1
	ldx (I6)-1,A0 ; ldy (I6),A1
	ldx (I4),I6 ; ldy (I4),I4
	ldx (I6)-1,NULL
	ldx (I6)-1,LR0 ; ldy (I6),I5
	jr
	ldx (I6)-1,MR0 ; ldy (I6),I7
#endif


#if LOOP_LOW .eq. 16
	.sect data_x,align64_const_x
	.align 4*16
	.export _costable_ii16
_costable_ii16:	// costable_ii, dct.c:174
	.uword 0x7fff, 0x7f62, 0x7d8a, 0x7a7c, 0x7641, 0x70e2, 0x6a6d, 0x62f1
	.uword 0x5a82, 0x5133, 0x471c, 0x3c56, 0x30fb, 0x2528, 0x18f8, 0xc8b
	.uword 0x0, 0xf375, 0xe708, 0xdad8, 0xcf05, 0xc3aa, 0xb8e4, 0xaecd
	.uword 0xa57e, 0x9d0f, 0x9593, 0x8f1e, 0x89bf, 0x8584, 0x8276, 0x809e
	.uword 0x8001, 0x809e, 0x8276, 0x8584, 0x89bf, 0x8f1e, 0x9593, 0x9d0f
	.uword 0xa57e, 0xaecd, 0xb8e4, 0xc3aa, 0xcf05, 0xdad8, 0xe708, 0xf375
	.uword 0x0, 0xc8b, 0x18f8, 0x2528, 0x30fb, 0x3c56, 0x471c, 0x5133
	.uword 0x5a82, 0x62f1, 0x6a6d, 0x70e2, 0x7641, 0x7a7c, 0x7d8a, 0x7f62
	.export _costable_iv16
_costable_iv16:	// costable_iv, dct.c:184
	.uword 0x7fd8, 0x7e9d, 0x7c29, 0x7884, 0x73b5, 0x6dc9, 0x66cf, 0x5ed7
	.uword 0x55f5, 0x4c3f, 0x41ce, 0x36ba, 0x2b1f, 0x1f19, 0x12c8, 0x647
	.uword 0xf9b9, 0xed38, 0xe0e7, 0xd4e1, 0xc946, 0xbe32, 0xb3c1, 0xaa0b
	.uword 0xa129, 0x9931, 0x9237, 0x8c4b, 0x877c, 0x83d7, 0x8163, 0x8028
	.uword 0x8028, 0x8163, 0x83d7, 0x877c, 0x8c4b, 0x9237, 0x9931, 0xa129
	.uword 0xaa0b, 0xb3c1, 0xbe32, 0xc946, 0xd4e1, 0xe0e7, 0xed38, 0xf9b9
	.uword 0x647, 0x12c8, 0x1f19, 0x2b1f, 0x36ba, 0x41ce, 0x4c3f, 0x55f5
	.uword 0x5ed7, 0x66cf, 0x6dc9, 0x73b5, 0x7884, 0x7c29, 0x7e9d, 0x7fd8
#endif
#if LOOP_LOW .eq. 8
	.sect data_x,align32_const_x
	.align 4*8
	.export _costable_ii8
_costable_ii8:
	.word  32767, 32138, 30273, 27245, 23170, 18204, 12539,  6392
	.word      0, -6392,-12539,-18204,-23170,-27245,-30273,-32138
	.word -32768,-32138,-30273,-27245,-23170,-18204,-12539, -6392
	.word      0,  6392, 12539, 18204, 23170, 27245, 30273, 32138

	.export _costable_iv8
_costable_iv8:
	.word  32610, 31357, 28898, 25330, 20787, 15446,  9512,  3211
	.word  -3211, -9512,-15446,-20787,-25330,-28898,-31357,-32610
	.word -32610,-31357,-28898,-25330,-20787,-15446, -9512, -3211
	.word   3211,  9512, 15446, 20787, 25330, 28898, 31357, 32610
	.export _dctfirmodtab8
_dctfirmodtab8:
	// 001 (In+m(12:6))%(m(5:0)+1)
	.word 0x201f,_costable_ii8+0,0x209f,_costable_ii8+1
	.word 0x211f,_costable_ii8+2,0x219f,_costable_ii8+3
	.word 0x221f,_costable_ii8+4,0x229f,_costable_ii8+5
	.word 0x231f,_costable_ii8+6,0x239f,_costable_ii8+7
	.word 0x205f,_costable_iv8+0,0x20df,_costable_iv8+1
	.word 0x215f,_costable_iv8+2,0x21df,_costable_iv8+3
	.word 0x225f,_costable_iv8+4,0x22df,_costable_iv8+5
	.word 0x235f,_costable_iv8+6,0x23df,_costable_iv8+7
#endif
#if LOOP_LOW .eq. 4
	.sect data_x,align16_const_x
	.align 4*4
	.export _costable_ii4
_costable_ii4:
	.word  32767,  30273,  23170,  12539,      0, -12539, -23170, -30273
	.word -32767, -30273, -23170, -12539,      0,  12539,  23170,  30273
	.export _costable_iv4
_costable_iv4:
	.word  32138,  27245,  18204,   6392,  -6392, -18204, -27245, -32138
	.word -32138, -27245, -18204,  -6392,   6392,  18204,  27245,  32138
	.export _dctfirmodtab4
_dctfirmodtab4:
	// 001 (In+m(12:6))%(m(5:0)+1)
	.word 0x200f,_costable_ii4+0,0x208f,_costable_ii4+1
	.word 0x210f,_costable_ii4+2,0x218f,_costable_ii4+3
	.word 0x204f,_costable_ii4+4,0x20cf,_costable_ii4+5
	.word 0x214f,_costable_ii4+6,0x21cf,_costable_ii4+7
#endif


// auto void dctfir(register __i2 s_int32 *in, register __a0 s_int16 iv) {
// auto void dctfir(register __i2 s_int16 *in, register __a0 s_int16 iv) {
//     register __b1 u_int16 jj;
//     register __i3 s_int32 *tmpP = firTmp;

	.sect code,dctfir	// 82 words
	.export _DCTFIR
_DCTFIR:
#ifdef DCT_CALLER_SAVES
	mv i6,i5	// firTmp
#else
	//ldx (I6)+1,NULL
	stx MR0,(I6)+1 ; sty a1,(I6)
	ldc 512,MR0
	stx B0,(I6)+1 ; sty B1,(I6)
	stx C0,(I6)+1 ; sty C1,(I6)
	stx D0,(I6)+1 ; sty D1,(I6)
	stx I2,(I6)+1 ; sty I3,(I6)
	stx LE,(I6)+1 ; sty LS,(I6)
	stx LC,(I6)+1
	mv i6,i5	// firTmp
#endif
	// allocated B1 as jj
	// allocated I5 as tmpP

//     jj = 0;
//     for ( ; jj < LOOP_LOW ; jj++ )

#if LOOP_LOW .eq. 16
	// 01 (In+m(13:6))%(m(5:0)*64+64)
	ldc LOOP_LOW,i7	//reserve space
	add A0,NULL,A0	; ldx (i6)*,null	// iv
	ldc 0x4000,b1	// modulo, (+2*jj+iv)&(4*16-1)
	jzs $13
	ldc _costable_ii16,i7

	// 01 (In+m(13:6))%(m(5:0)*64+64)
	ldc 0x4000+(1<<6),b1	// modulo, (+2*jj+iv)&(4*16-1)
	ldc _costable_iv16,i7
$13:
#endif
#if LOOP_LOW .eq. 8
	add A0,NULL,A0	; ldx (i6)+(8-1),null	// iv, reserve space
	ldc _dctfirmodtab8+0,i3
	jzs $13
	ldc -16,b1

	ldc _dctfirmodtab8+16,i3
$13:
#endif
#if LOOP_LOW .eq. 4
	add A0,NULL,A0	; ldx (i6)+(4-1),null	// iv, reserve space
	ldc _dctfirmodtab4+0,i3
	jzs $13
	ldc -16,b1

	ldc _dctfirmodtab4+8,i3
$13:
#endif

#if LOOP_LOW .eq. 16
	sty i4,(i6)+1
	ldc 1,i4
	ldc (2<<6),a0
	mv i7,i0	// costab+jj (jj starts from 0)
	ldc LOOP_LOW-1,LS
	LOOP LS,$14-1
	stx i2,(i6)	; sty a0,(i6)
#else
	//8 and 4 use mod table
	and c,null,c	; ldx (i6)+1,null
	ldx (i3)+1,i1	; sty i4,(i6)+1
	ldx (i3)+1,i0	// costab+jj
	stx c0,(i6)	; sty c0,(i6)
	and d,null,d	; ldx (i0)*,a1	; ldy (I2),A0	// data hi
	ldc LOOP_LOW-1,LS
	LOOP LS,$14-1
	ldc 1,i4
#endif

//  {
// 	const __y s_int16 *costab = iv ? costable_iv : costable_ii;
// 	register  long long s = 0;
// 	register u_int16 tt = jj;
// 	register u_int16 adder = 2*jj + iv;
// 	register s_int32 *inp = in;
// 	u_int16 kk;

// 	for ( kk = 0; kk < LOOP_LOW ; kk++)
// 	{
// 	    s += (__fract s_int32)*inp++ * (__fract s_int16)costab[tt];

#if LOOP_LOW .eq. 16
	and c,null,c	; mv b1,i1
	and d,null,d	; ldx (i0)*,a1	; ldy (I2),A0	// data hi
	mulss a0,a1	; ldx (I2)+1,a0

	macus a0,a1,d	; ldx (i0)*,a1	; ldy (I2),a0	// data lo
	macss a0,a1,c	; ldx (I2)+1,a0
	macus a0,a1,d	; ldx (i0)*,a1	; ldy (I2),a0	// data lo
	macss a0,a1,c	; ldx (I2)+1,a0
	macus a0,a1,d	; ldx (i0)*,a1	; ldy (I2),a0	// data lo
	macss a0,a1,c	; ldx (I2)+1,a0
	macus a0,a1,d	; ldx (i0)*,a1	; ldy (I2),a0	// data lo
	macss a0,a1,c	; ldx (I2)+1,a0

	macus a0,a1,d	; ldx (i0)*,a1	; ldy (I2),a0	// data lo
	macss a0,a1,c	; ldx (I2)+1,a0
	macus a0,a1,d	; ldx (i0)*,a1	; ldy (I2),a0	// data lo
	macss a0,a1,c	; ldx (I2)+1,a0
	macus a0,a1,d	; ldx (i0)*,a1	; ldy (I2),a0	// data lo
	macss a0,a1,c	; ldx (I2)+1,a0
	macus a0,a1,d	; ldx (i0)*,a1	; ldy (I2),a0	// data lo
	macss a0,a1,c	; ldx (I2)+1,a0

	macus a0,a1,d	; ldx (i0)*,a1	; ldy (I2),a0	// data lo
	macss a0,a1,c	; ldx (I2)+1,a0
	macus a0,a1,d	; ldx (i0)*,a1	; ldy (I2),a0	// data lo
	macss a0,a1,c	; ldx (I2)+1,a0
	macus a0,a1,d	; ldx (i0)*,a1	; ldy (I2),a0	// data lo
	macss a0,a1,c	; ldx (I2)+1,a0
	macus a0,a1,d	; ldx (i0)*,a1	; ldy (I2),a0	// data lo
	macss a0,a1,c	; ldx (I2)+1,a0
	macus a0,a1,d	; ldx (i0)*,a1	; ldy (I2),a0	// data lo
	macss a0,a1,c	; ldx (I2)+1,a0
	macus a0,a1,d	; ldx (i0)*,a1	; ldy (I2),a0	// data lo
	macss a0,a1,c	; ldx (I2)+1,a0
	macus a0,a1,d	; ldx (i0)*,a1	; ldy (I2),a0	// data lo

	macss a0,a1,c	; ldx (I2),a0
	macus a0,a1,d	; ldx (i6),i2
	add c,p,c	; ldy (i6),a0	//ldc (2<<6),a0
	mv c2,c1 ; add c1,null,c0	// scale low half
	add c,d,d	; ldx (i7)+1,null	// combine halves
	add B1,A0,B1	; stx D0,(I5)	; sty D1,(I5)*
	mv i7,i0	// costab+jj
#endif
#if LOOP_LOW .eq. 8
	mulss a0,a1	; ldx (I2)+1,a0
	macus a0,a1,d	; ldx (i0)*,a1	; ldy (I2),a0	// data lo
	macss a0,a1,c	; ldx (I2)+1,a0
	macus a0,a1,d	; ldx (i0)*,a1	; ldy (I2),a0	// data lo
	macss a0,a1,c	; ldx (I2)+1,a0
	macus a0,a1,d	; ldx (i0)*,a1	; ldy (I2),a0	// data lo
	macss a0,a1,c	; ldx (I2)+1,a0
	macus a0,a1,d	; ldx (i0)*,a1	; ldy (I2),a0	// data lo
	macss a0,a1,c	; ldx (I2)+1,a0
	macus a0,a1,d	; ldx (i0)*,a1	; ldy (I2),a0	// data lo
	macss a0,a1,c	; ldx (I2)+1,a0
	macus a0,a1,d	; ldx (i0)*,a1	; ldy (I2),a0	// data lo
	macss a0,a1,c	; ldx (I2)+1,a0
	macus a0,a1,d	; ldx (i0)*,a1	; ldy (I2),a0	// data lo

	macss a0,a1,c	; ldx (I2)-7,a0
	macus a0,a1,d	; ldx (i3)+1,i1
	add c,p,c	; ldx (i3)+1,i0
	ashl c,b1,c	; ldx (i0)*,a1	; ldy (I2),A0 // scale low // data hi
	add c,d,d	; ldx (i6),c1	; ldy (i6),c0	// combine halves
	and d,null,d	; stx D0,(I5)	; sty D1,(I5)*
	
#endif
#if LOOP_LOW .eq. 4
	mulss a0,a1	; ldx (I2)+1,a0
	macus a0,a1,d	; ldx (i0)*,a1	; ldy (I2),a0	// data lo
	macss a0,a1,c	; ldx (I2)+1,a0
	macus a0,a1,d	; ldx (i0)*,a1	; ldy (I2),a0	// data lo
	macss a0,a1,c	; ldx (I2)+1,a0
	macus a0,a1,d	; ldx (i0)*,a1	; ldy (I2),a0	// data lo

	macss a0,a1,c	; ldx (I2)-3,a0
	macus a0,a1,d	; ldx (i3)+1,i1
	add c,p,c	; ldx (i3)+1,i0
	ashl c,b1,c	; ldx (i0)*,a1	; ldy (I2),A0	// scale low, data hi
	add c,d,d	; ldx (i6),c1	; ldy (i6),c0	// combine halves
	and d,null,d	; stx D0,(I5)	; sty D1,(I5)*
#endif

// 	}
// 	*tmpP++ = (s>>1);

$14:


//     }
//     for ( jj = 0; jj < LOOP_LOW ; jj++ )

#if LOOP_LOW .eq. 16
	ldx (i5)-7,null	; ldy (i6)-1,null
	ldx (i5)-7,null
	ldx (i5)-2,null
#endif
#if LOOP_LOW .eq. 8
	ldx (i5)-4,null	; ldy (i6)-1,null
	ldx (i5)-4,null
#endif
#if LOOP_LOW .eq. 4
	ldx (i5)-4,null	; ldy (i6)-1,null
#endif
	ldc LOOP_LOW-1,LS
	loop LS,$15-1
	ldc 0xc000|(LOOP_LOW/2),i3	// bitreverse 16>>1

	ldx (i5)+1,a0	; ldy (i5),a1
	stx a0,(i2)*	; sty a1,(i2)
$15:

#ifdef DCT_CALLER_SAVES
#if LOOP_LOW .eq. 4
	jr
	ldy (i6)-5,i4
#else
	ldc -LOOP_LOW-1,i7
	jr
	ldy (i6)*,i4
#endif
#else/*DCT_CALLER_SAVES*/
#if LOOP_LOW .eq. 4
	ldy (i6)-5,i4
#else
	ldc -LOOP_LOW-1,i7
	ldy (i6)*,i4
#endif
	ldx (I6)-1,LC
	ldx (I6)-1,LE ; ldy (I6),LS
	ldx (I6)-1,I2 ; ldy (I6),I3
	ldx (I6)-1,D0 ; ldy (I6),D1
	ldx (I6)-1,C0 ; ldy (I6),C1
	ldx (I6)-1,B0 ; ldy (I6),B1
	jr
	ldx (I6)-1,MR0 ; ldy (I6),a1
#endif


#if 1

// auto void dctivpost(register __d0 s_int32 *in, register __d1 s_int16 NN);
// auto void dctivpost(register __d0 s_int16 *in, register __d1 s_int16 NN);

	.sect code,dctivpost	// 159 words
	.export _dctivpost
_dctivpost:
#ifdef DCT_CALLER_SAVES
#else
	//ldx (I6)+1,NULL
	stx A0,(I6)+1 ; sty A1,(I6)
	stx B0,(I6)+1 ; sty B1,(I6)
	stx C0,(I6)+1 ; sty C1,(I6)
	stx I0,(I6)+1 ; sty I1,(I6)
	stx I2,(I6)+1 ; sty I3,(I6)
	stx LE,(I6)+1 ; sty LS,(I6)
	stx LC,(I6)+1 ; sty mr0,(i6)
	ldc 512,MR0
#endif

	// allocated D0 as inp
	// allocated D1 as N

//     {
// 	register s_int32 u;
// 	register s_int32 *no2 = inp+N/2;
// 	register s_int32 *no4 = inp+N/4;
// 	register s_int32 *nm1 = inp+N-1;
// 	r15 = *no2;
// 	u = *no4;
// 	*no4 = u + *nm1;
// 	*no2 = u - *nm1;

	asr D1,A0
	add a0,D0,a1
	asr A0,A0	; mv a1,I2
	add A0,D0,A0	; ldx (I2),c0	; ldy (I2),c1
	add D0,d1,A0	; mv A0,I1
	stx c0,(i6)+1 ; sty c1,(i6)	// r15
	add a0,ones,a0 ; ldx (I1),B0	; ldy (I1),B1
	mv a0,i0
	ldx (I0),A0	; ldy (I0),A1
	add A,B,A	; ldx (I0),c0	; ldy (I0),c1
	sub b,c,A	; stx A0,(I1)	; sty A1,(I1)
	sub NULL,ONES,A0	; stx A0,(I2)	; sty A1,(I2)
//     }
//     NN = N/4-1;
//     for ( n = 0; n < NN; n++ )

	asr D1,a0	; stx d0,(i6) ; sty d1,(i6)
	ldc 0xc000-1,c0
	add c0,d1,a1	; ldx (i6)+1,null
	ldc 0xc000,c0
	add c0,a0,a1	; mv a1,i3	// bit-reverse, NN backward
	asr a0,a0	; mv a1,i1	// bit-reverse, NN forward

	mv d0,i0 ; mv d0,i2	// in

	ldx (i0)*,null
	ldx (i0)*,null	; ldy (i2)*,null
	ldx (i0)*,null	; ldy (i2)*,null

	add A0,ONES,A0	; mv i0,i5	//wp
	add A0,ONES,A0	; mv i2,i7	//xp
	ldx (i0)*,null	; ldy (i2)*,null
	loop A0,L43-1
	ldx (i0),c0	; ldy (i0),c1	// u


//  {
// 	register s_int32 *wp = &in[bitrev(4*n+3,br+1)];
// 	register s_int32 *up = &in[bitrev(4*n+4,br+1)];
// 	register s_int32 *vp = &in[bitrev(-4*n-3,br+1)];
// 	register s_int32 *xp = &in[bitrev(-4*n-2,br+1)];
// 	u = *up;
// 	v = *vp;
// 	*up = u-v;
// 	u = u + v;
// 	v = *wp;
// 	*wp = u;
// 	u = *xp;
// 	*vp = u-v;
// 	*xp = u+v;

	ldx (i2),b0	; ldy (i2),b1	// v
	add c,b,a	; ldx (i5),d0	; ldy (i5),d1	// w
	sub c,b,b	; stx a0,(i5)	; sty a1,(i5)
	stx b0,(i0)	; sty i2,(i6)
	sty b1,(i0)	; ldx (i2)*,null
	ldy (i6),i5	; ldx (i2)*,null
	ldy (i7),b1	; ldx (i2)*,null
	ldx (i7),b0	; sty i2,(i6)	// x
	sub b,d,a	; ldy (i0)*,null
	add d,b,c	; ldy (i0)*,null
	sty c1,(i7)	; ldx (i0)*,null
	stx c0,(i7)	; ldy (i6),i7	// mv i2,i7
	stx a0,(i5)	; sty i0,(i6)
	sty a1,(i5)	; ldx (i0)*,null	//wp
	ldx (i0),c0	; ldy (i6),i5	// mv i0,i5
	ldy (i0),c1	; ldx (i2)*,null	// u
	// 16 -- (theoretical min 16 if same mem)
L43:

//     }
//     inp[N-1] = r15;
	ldy (i6)-1,null
	ldx (i6)-1,d0 ; ldy (i6),d1
	add D0,D1,B0
	mv b0,i5
	ldx (i6),a0	; ldy (i5)-1,null
	stx A0,(I5)	; ldy (i6)-1,a1	// r15

#ifdef DCT_CALLER_SAVES
	jr
	sty A1,(I5)
#else
	sty A1,(I5)
	ldx (I6)-1,LC ; ldy (i6),mr0
	ldx (I6)-1,LE ; ldy (I6),LS
	ldx (I6)-1,I2 ; ldy (I6),I3
	ldx (I6)-1,I0 ; ldy (I6),I1
	ldx (I6)-1,C0 ; ldy (I6),C1
	ldx (I6)-1,B0 ; ldy (I6),B1
	jr
	ldx (I6)-1,A0 ; ldy (I6),A1
#endif
#endif

#if 1
// auto void dctiv(register __a0 s_int32 *in, register __a1 s_int16 NN, register __i2 __y const s_int16 *tw);
// auto void dctiv(register __a0 s_int16 *in, register __a1 s_int16 NN, register __i2 __y const s_int16 *tw);

	.sect code,dctiv	// 146 words
	.export _dctiv
_dctiv:
#ifdef DCT_CALLER_SAVES
#else
	//ldx (I6)+1,NULL
	stx B0,(I6)+1 ; sty B1,(I6)
	stx C0,(I6)+1 ; sty C1,(I6)
	stx D0,(I6)+1 ; sty D1,(I6)
	stx I0,(I6)+1 ; sty I1,(I6)
	stx I2,(I6)+1 ; sty I3,(I6)
	stx LE,(I6)+1 ; sty LS,(I6)
	stx LC,(I6)+1 ; sty mr0,(i6)
	ldc 512,MR0
#endif

//     register __y s_int16 const *twp = tw;
//     s_int16 n;
//     register s_int32 *up = &in[0];
//     register s_int32 *vp = &in[NN-1];

	// allocated I2 as twp
	// allocated I4 as up
	// allocated I0 as vp

	add A1,ONES,b1	; stx i4,(i6)+1
	add A0,b1,A0	; mv a0,i4
	ldc -16,d0
	asr A1,A1	; stx d0,(i6)
	asr A1,A1	; mv A0,I0
	ldc 1,i3
	ldc 1,i5
	and d,null,d	; ldx (I4),C0	; ldy (I2)*,A0/*C*/
	add A1,ONES,A1	; mv i0,i7
	ldx (i7)+1,null
	loop A1,L37-1
	mulus c0,a0	; ldx (I0),B0	; ldy (I2),A1/*C*/

//     NN = NN/4;
//     for( n = 0; n < NN; n++ )
//  {
// 	register s_int32 u = *up;
// 	register s_int32 v = *vp;

	// allocated C as u
	// allocated B as v

// 	*up++ = ((__fract s_int32)u*(__fract s_int16)twp[0]
// 		 +(__fract s_int32)v*(__fract s_int16)twp[1]);
// 	*vp-- = ((__fract s_int32)u*(__fract s_int16)twp[1]
// 		 -(__fract s_int32)v*(__fract s_int16)twp[0]);

	ldc 16384,d0
	macus b0,a1,d	; ldx (i6),a1	; ldy (I4),C1
	macss c1,a0,d	; ldy (i0)-1,B1
	ashl d,a1,d	; ldy (i2)*,a1
	macss b1,a1,d	; mv mr0,mr0	// keep Carry
	macus b0,a0,d	; mv mr0,mr0	// keep Carry for lslc
	lslc d,d
	and d,null,d	; stx d0,(I4)*	; sty d1,(I4)
	ldc 16384,d0
	msuus c0,a1,d	; ldx (i7)-1,null
	macss b1,a0,d	; ldx (i6),a0
	ashl d,a0,d	; ldx (I4),C0	; ldy (I2)*,A0/*C*/
	msuss c1,a1,d	; mv mr0,mr0	// keep Carry
	macus c0,a0,d	; mv mr0,mr0	// keep Carry for lslc
	lslc d,d	; ldx (I0),B0	; ldy (I2),A1/*C*/
	and d,null,d	; stx d0,(I7)	; sty d1,(I7)
	ldc 16384,d0

// 	u = *up;
// 	v = *vp;

// 	*up++ = ((__fract s_int32)u*(__fract s_int16)twp[2]
// 		 +(__fract s_int32)v*(__fract s_int16)twp[3]);
// 	*vp-- = ((__fract s_int32)v*(__fract s_int16)twp[2]
// 		 -(__fract s_int32)u*(__fract s_int16)twp[3]);
// 	twp += 4;

	macus b0,a1,d	; ldx (i6),a1	; ldy (I4),C1
	macss c1,a0,d	; ldy (i0)-1,B1
	ashl d,a1,d	; ldy (i2)*,a1
	macss b1,a1,d	; mv mr0,mr0	// keep Carry
	macus b0,a0,d	; mv mr0,mr0	// keep Carry for lslc
	lslc d,d
	and d,null,d	; stx d0,(I4)* ; sty d1,(I4)
	ldc 16384,d0
	macus c0,a1,d	; ldy (i7)-1,null
	msuss b1,a0,d	; ldx (i6),a0
	ashl d,a0,d	; ldx (I4),C0	; ldy (I2)*,A0/*C*/
	macss c1,a1,d	; mv mr0,mr0	// keep Carry
	msuus c0,a0,d	; mv mr0,mr0	// keep Carry for lslc
	lslc d,d	; ldx (I0),B0	; ldy (I2),A1/*C*/
	and d,null,d	; stx d0,(I7)	; sty d1,(I7)

	// 36 cycles / 4 butterflies -> 28 cycles -> 32
L37:

#ifdef DCT_CALLER_SAVES
	ldx (i6)-1,null
	jr
	ldx (i6)-1,i4
#else
	ldx (i6)-1,null
	ldx (i6)-1,i4
	ldx (I6)-1,LC ; ldy (i6),mr0
	ldx (I6)-1,LE ; ldy (I6),LS
	ldx (I6)-1,I2 ; ldy (I6),I3
	ldx (I6)-1,I0 ; ldy (I6),I1
	ldx (I6)-1,D0 ; ldy (I6),D1
	ldx (I6)-1,C0 ; ldy (I6),C1
	jr
	ldx (I6)-1,B0 ; ldy (I6),B1
#endif
#endif

#if 1
// auto void dctii(register __i2 s_int32 *in, register __c1 s_int16 NN);
// auto void dctii(register __i2 s_int16 *in, register __c1 s_int16 NN);

	.sect code,dctii	// 79 words
	.export _dctii
_dctii:
#ifdef DCT_CALLER_SAVES
#else
	//ldx (I6)+1,NULL
	stx A0,(I6)+1 ; sty A1,(I6)
	stx B0,(I6)+1 ; sty B1,(I6)
	stx C0,(I6)+1 ; sty mr0,(I6)
	stx d0,(I6)+1 ; sty d1,(I6)
	stx I0,(I6)+1 ; sty I1,(I6)
	stx I2,(I6)+1 ; sty I3,(I6)
	stx LE,(I6)+1 ; sty LS,(I6)
	stx LC,(I6)
	ldc 512,MR0
#endif

//     register s_int32 *up = &in[0];
//     register s_int32 *vp = &in[NN-1];
//     register s_int32 *wp = &in[NN/2];
//     register s_int32 *xp = &in[NN/2-1];
//     s_int16 n;

	// allocated I2 as up
	// allocated I1 as vp
	// allocated I7 as wp
	// allocated I5 as xp

	add c1,ONES,A1	; mv i2,b0
	add b0,A1,c0
	asr c1,A1	; mv c0,i5
	add b0,A1,A0
	add A1,ONES,A1	; mv a0,i7
	add b0,A1,A0
	asr c1,A0	; mv A0,I1
	asr A0,A0
	add A0,ONES,A0	; ldx (I2),C0	; ldy (I2),C1
	ldc -2,i0
	loop A0,L35-1
	ldc 2,i3
	
//     NN = NN/4;
//     for( n = 0; n < NN; n++ )
//  {
// 	register s_int32 u = *up;
// 	register s_int32 v = *vp;

	// allocated C as u
	// allocated B as v
// 	*up = u + v;
// 	u = u - v;
// 	v = *wp;
// 	*wp = u;
// 	u = *xp;
// 	*xp = u + v;
// 	*vp = u - v;
// 	up += 2;
// 	vp -= 2;
// 	wp += 2;
// 	xp -= 2;

	ldx (I5),B0	; ldy (I5),B1
	add B,C,A	; ldx (I7),d0	; ldy (I7),d1
	sub C,B,B	; stx A0,(I2)	; sty A1,(I2)*
	stx B0,(I7)	; sty B1,(I7)+2

	ldx (I1),B0	; ldy (I1),B1
	add D,B,A	; ldx (I2),C0	; ldy (I2),C1
	sub B,D,B	; stx A0,(I1)	; sty A1,(I1)*
	stx B0,(I5)	; sty B1,(I5)-2

L35:
#ifdef DCT_CALLER_SAVES
	jr
	ldx (i6)-1,null
#else
	ldx (I6)-1,LC
	ldx (I6)-1,LE ; ldy (I6),LS
	ldx (I6)-1,I2 ; ldy (I6),I3
	ldx (I6)-1,I0 ; ldy (I6),I1
	ldx (I6)-1,d0 ; ldy (I6),d1
	ldx (I6)-1,C0 ; ldy (I6),mr0
	ldx (I6)-1,B0 ; ldy (I6),B1
	jr
	ldx (I6)-1,A0 ; ldy (I6),A1
#endif
#endif

	.end
