 /* 
  * UAE - The Un*x Amiga Emulator
  * 
  * Optimized blitter minterm function generator
  * 
  * Copyright 1995,1996 Bernd Schmidt
  * Copyright 1996 Alessandro Bissacco
  */

#include "sysconfig.h"
#include "sysdeps.h"

#include "config.h"
#include "options.h"
/*#include "custom.h"*/

UWORD dmacon;
/* Here is the minterm table used in blitter function generation */
 
static unsigned char blttbl[]= {
    0x00, 0x0a, 0x2a, 0x30, 0x3a, 0x3c, 0x4a, 0x6a, 0x8a, 0x8c, 0x9a, 0xa8,
    0xaa, 0xb1, 0xca, 0xcc, 0xd8, 0xe2, 0xea, 0xf0, 0xfa, 0xfc
};

static int bitset(int mt, int bit)
{
    return mt & (1<<bit);
}

static int generate_expr(int minterm, int print)
{
    int result = 0;
    int firstor = 1;
    int bits = 0;
    int i;
    for(i=0; i<8; i++) {
	if (bitset(minterm, i) && !bitset(bits,i)) {
	    int j;
	    int dontcare = 0;
	    int firstand = 1;
	    int bitbucket[8], bitcount;
		
	    bits |= 1<<i;
     	    bitcount = 1; bitbucket[0] = i;
	    for(j=1; j<8; j *= 2) {
		int success = 1;
		int k;
		for(k=0; k < bitcount; k++) {			
		    if (!bitset(minterm, bitbucket[k] ^ j)) {
			success = 0;
		    }
		}
		if (success) {
		    int l;
		    dontcare |= j;
		    for(l=bitcount; l < bitcount*2; l++) {
			bitbucket[l] = bitbucket[l-bitcount] ^ j;
			bits |= 1 << bitbucket[l];
		    }
		    bitcount *= 2;
		}
	    }
	    if (firstor) {
		firstor = 0;
	    } else {
		if (print) printf(" | ");
	    }
	    for (j=1; j<8; j *= 2) {
		if (!(dontcare & j)) {
		    if (firstand) {
			firstand = 0;
			if (print) printf("(");
		    } else {
			if (print) printf(" & ");
		    }
		    if (!(i & j))
			if (print) printf("~");
		    if (print) printf("src%c", (j == 1 ? 'c' : j == 2 ? 'b' : 'a'));
		    result |= (j == 1 ? 4 : j == 2 ? 2 : 1);
		}
	    }
	    if (!firstand) {		    
		if (print) printf(")");
	    } else {
		if (print) printf("0xFFFF");
	    }
	}
    }
    if (firstor)
	if (print) printf("0");
    if (print) printf(";\n");
    return result;
}

static void generate_include(void)
{
    int minterm;
    printf("static __inline__ ULONG blit_func(ULONG srca, ULONG srcb, ULONG srcc, UBYTE mt)\n{\nswitch(mt){\n");
    for (minterm = 0; minterm < 256; minterm++) {
	printf("case 0x%x:\n", minterm);
	printf("\treturn ");
	generate_expr(minterm, 1);
    }
    printf("}\n");
    printf("return 0;\n"); /* No, sir, it doesn't! */
    printf("}\n");
}

static void generate_func(void)
{
    unsigned int i;
    printf("#include \"sysconfig.h\"\n");
    printf("#include \"sysdeps.h\"\n");
    printf("#include \"config.h\"\n");
    printf("#include \"options.h\"\n");
    printf("#include \"custom.h\"\n");
    printf("#include \"blitter.h\"\n");
    printf("#include \"blitfunc.h\"\n\n");

    for (i = 0; i < sizeof(blttbl); i++) { 
	int active = generate_expr(blttbl[i],0); 
	int a_is_on = active & 1, b_is_on = active & 2, c_is_on = active & 4; 
	
	printf("void blitdofast_%x(UBYTE *pta, UBYTE *ptb, UBYTE *ptc, UBYTE *ptd, struct bltinfo *b)\n",blttbl[i]); 
	printf("{\n");
	printf("int i,j;\n"); 
	
#if FAST_BLITTER == 3 || FAST_BLITTER == 5
	printf("if (b->hblitsize>1");
	if (a_is_on) printf(" && !b->blitashift && b->bltafwm==0xffff && b->bltalwm==0xffff"); 
	if (b_is_on) printf(" && !b->blitbshift"); 
	printf(") {\n"); 
	if (a_is_on) printf("ULONG srca=((ULONG)b->bltadat << 16) | b->bltadat;\n");
	if (b_is_on) printf("ULONG srcb=((ULONG)b->bltbdat << 16) | b->bltbdat;\n"); 
	if (c_is_on) printf("ULONG srcc=((ULONG)b->bltcdat << 16) | b->bltcdat;\n");
	printf("ULONG dest;\n"); 
	printf("int count=b->hblitsize/2, oddword=b->hblitsize&1;\n");
	printf("for (j=0;j<b->vblitsize;j++) {\n"); 
	printf("\tfor(i=0;i<count;i++) {\n"); 
	if (a_is_on) printf("\t\tif (pta) {srca=*((ULONG *)pta); pta += 4;}\n");
	if (b_is_on) printf("\t\tif (ptb) {srcb=*((ULONG *)ptb); ptb += 4;}\n"); 
	if (c_is_on) printf("\t\tif (ptc) {srcc=*((ULONG *)ptc); ptc += 4;}\n");
	printf("\t\tdest="); 
	generate_expr(blttbl[i],1);
	printf("\t\tif (dest) b->blitzero=0;\n"); 
	printf("\t\tif (ptd) {*(ULONG *)ptd=dest; ptd += 4;}\n");
	printf("\t}\n");
	printf("\tif (oddword) {\n");
	if (a_is_on) printf("\t\tif (pta) { srca=(ULONG)*(UWORD *)pta; pta += 2; }\n"); 
	if (b_is_on) printf("\t\tif (ptb) { srcb=(ULONG)*(UWORD *)ptb; ptb += 2; }\n"); 
	if (c_is_on) printf("\t\tif (ptc) { srcc=(ULONG)*(UWORD *)ptc; ptc += 2; }\n");
	printf("\t\tdest="); 
	generate_expr(blttbl[i],1);
	printf("\t\tif (dest) b->blitzero=0;\n"); 
	printf("\t\tif (ptd) { *(UWORD *)ptd= dest; ptd += 2; }\n");
	printf("\t}\n");
	if (a_is_on) printf("\tif (pta) pta += b->bltamod;\n"); 
	if (b_is_on) printf("\tif (ptb) ptb += b->bltbmod;\n"); 
	if (c_is_on) printf("\tif (ptc) ptc += b->bltcmod;\n");
	printf("\tif (ptd) ptd += b->bltdmod;\n"); 
	printf("}\n");
	if (a_is_on) printf("if (pta) b->bltadat = (*(pta-b->bltamod-2) << 8) | *(pta - b->bltamod - 1);\n"); /* Maybe not necessary, but I don't want problems */ 
	if (b_is_on) printf("if (ptb) b->bltbdat = (*(ptb-b->bltbmod-2) << 8) | *(ptb - b->bltbmod - 1);\n");
	if (c_is_on) printf("if (ptc) b->bltcdat = (*(ptc-b->bltcmod-2) << 8) | *(ptc - b->bltcmod - 1);\n");
	printf("if (ptd) b->bltddat = (*(ptd-b->bltdmod-2) << 8) | *(ptd - b->bltdmod - 1);\n");
	
	printf("} else\n"); 
#endif
	printf("{\n");
	
	printf("UWORD srca,srcb,srcc,bltaold,bltamask=b->bltafwm;\n");
	if (a_is_on) printf("if (b->hblitsize==1) bltamask&=b->bltalwm;\n");
	printf("for (j=0;j<b->vblitsize;j++) {\n");
	if (a_is_on) {
	    printf("\tif (pta) { b->bltadat=(*pta << 8) | (*(pta+1)); pta+=2; }\n");
	    if (b_is_on) printf("\tif (ptb) { b->bltbdat=(*ptb << 8) | (*(ptb+1)); ptb+=2; }\n");
	    if (c_is_on) printf("\tif (ptc) { b->bltcdat=(*ptc << 8) | (*(ptc+1)); ptc+=2; };\n");
	    printf("\tbltaold=b->bltadat & bltamask;\n");     
            printf("\tsrca=(((ULONG)b->blitpreva << 16) | bltaold) >> b->blitashift;\n");
	    if (b_is_on) printf("\tsrcb=(((ULONG)b->blitprevb << 16) | b->bltbdat) >> b->blitbshift;\n");
	    if (c_is_on) printf("\tsrcc=b->bltcdat;\n");
	    printf("\tb->bltddat=");
	    generate_expr(blttbl[i],1);
	    printf("\tb->blitpreva=bltaold;\n");
	    if (b_is_on) printf("\tb->blitprevb=b->bltbdat;\n");
	    printf("\tif (b->bltddat) b->blitzero=0;\n");
	    printf("\tif (ptd) { *ptd = b->bltddat >> 8; *(ptd+1) = b->bltddat; ptd+= 2; }\n");
	}
	if (a_is_on) printf("\tfor (i=2;i<b->hblitsize;i++) {\n");
	else printf("\tfor (i=0;i<b->hblitsize;i++) {\n");
	if (a_is_on) printf("\t\tif (pta) { b->bltadat=(*pta << 8) | (*(pta+1)); pta+=2; }\n");
	if (b_is_on) printf("\t\tif (ptb) { b->bltbdat=(*ptb << 8) | (*(ptb+1)); ptb+=2; }\n");
	if (c_is_on) printf("\t\tif (ptc) { b->bltcdat=(*ptc << 8) | (*(ptc+1)); ptc+=2; }\n");
        if (a_is_on) printf("\t\tsrca=(((ULONG)b->blitpreva<<16)|b->bltadat)>>b->blitashift;\n");
	if (b_is_on) printf("\t\tsrcb=(((ULONG)b->blitprevb<<16)|b->bltbdat)>>b->blitbshift;\n");
	if (c_is_on) printf("\t\tsrcc=b->bltcdat;\n");
	printf("\t\tb->bltddat=");
	generate_expr(blttbl[i],1);
	if (a_is_on) printf("\t\tb->blitpreva=b->bltadat;\n");
	if (b_is_on) printf("\t\tb->blitprevb=b->bltbdat;\n");
	printf("\t\tif (b->bltddat) b->blitzero=0;\n");
	printf("\t\tif (ptd) { *ptd = b->bltddat >> 8; *(ptd+1) = b->bltddat; ptd+= 2; }\n");
	printf("\t}\n");
	if (a_is_on) {
	    printf("\tif (b->hblitsize>1) {\n");
	    printf("\t\tif (pta) { b->bltadat=(*pta << 8) | (*(pta+1)); pta+=2; }\n");
	    if (b_is_on) printf("\t\tif (ptb) { b->bltbdat=(*ptb << 8) | (*(ptb+1)); ptb+=2; }\n");
	    if (c_is_on) printf("\t\tif (ptc) { b->bltcdat=(*ptc << 8) | (*(ptc+1)); ptc+=2; }\n");
	    printf("\t\tbltaold=b->bltadat & b->bltalwm;\n");     
            printf("\t\tsrca=(((ULONG)b->blitpreva << 16) | bltaold) >> b->blitashift;\n");
	    if (b_is_on) printf("\t\tsrcb=(((ULONG)b->blitprevb << 16) | b->bltbdat) >> b->blitbshift;\n");
	    if (c_is_on) printf("\t\tsrcc=b->bltcdat;\n");
	    printf("\t\tb->bltddat=");
	    generate_expr(blttbl[i],1);
	    printf("\t\tb->blitpreva=bltaold;\n");
	    if (b_is_on) printf("\t\tb->blitprevb=b->bltbdat;\n");
	    printf("\t\tif (b->bltddat) b->blitzero=0;\n");
	    printf("\t\tif (ptd) { *ptd = b->bltddat >> 8; *(ptd+1) = b->bltddat; ptd+= 2; }\n");
	    printf("\t}\n");
	}
	if (a_is_on) printf("\tif (pta) pta += b->bltamod;\n");
	if (b_is_on) printf("\tif (ptb) ptb += b->bltbmod;\n");
	if (c_is_on) printf("\tif (ptc) ptc += b->bltcmod;\n");
	printf("\tif (ptd) ptd+=b->bltdmod;\n");
	printf("}\n");
	printf("}\n");
	printf("}\n");
	
	
	printf("void blitdofast_desc_%x(UBYTE *pta, UBYTE *ptb, UBYTE *ptc, UBYTE *ptd, struct bltinfo *b)\n",blttbl[i]);
	printf("{\n");
	printf("int i,j;\n");
	
#if FAST_BLITTER == 3 || FAST_BLITTER == 5
	printf("if (b->hblitsize>1");
	if (a_is_on) printf(" && !b->blitashift && b->bltafwm==0xffff && b->bltalwm==0xffff"); 
	if (b_is_on) printf(" && !b->blitbshift"); 
	printf(") {\n"); 
	if (a_is_on) printf("ULONG srca=((ULONG)b->bltadat << 16) | b->bltadat;\n");
	if (b_is_on) printf("ULONG srcb=((ULONG)b->bltbdat << 16) | b->bltbdat;\n"); 
	if (c_is_on) printf("ULONG srcc=((ULONG)b->bltcdat << 16) | b->bltcdat;\n");
	printf("ULONG dest;\n"); 
	printf("int count=b->hblitsize/2, oddword=b->hblitsize&1;\n");
	printf("for (j=0;j<b->vblitsize;j++) {\n"); 
	printf("\tfor(i=0;i<count;i++) {\n"); 
	if (a_is_on) printf("\t\tif (pta) {srca=*((ULONG *)(pta-2)); pta -= 4;}\n");
	if (b_is_on) printf("\t\tif (ptb) {srcb=*((ULONG *)(ptb-2)); ptb -= 4;}\n"); 
	if (c_is_on) printf("\t\tif (ptc) {srcc=*((ULONG *)(ptc-2)); ptc -= 4;}\n");
	printf("\t\tdest="); 
	generate_expr(blttbl[i],1);
	printf("\t\tif (dest) b->blitzero=0;\n"); 
	printf("\t\tif (ptd) {*(ULONG *)(ptd-2)=dest; ptd -= 4;}\n");
	printf("\t}\n"); 
	printf("\tif (oddword) {\n");
	if (a_is_on) printf("\t\tif (pta) { srca=(ULONG)*(UWORD *)pta; pta -= 2; }\n");
	if (b_is_on) printf("\t\tif (ptb) { srcb=(ULONG)*(UWORD *)ptb; ptb -= 2; }\n"); 
	if (c_is_on) printf("\t\tif (ptc) { srcc=(ULONG)*(UWORD *)ptc; ptc -= 2; }\n");
	printf("\t\tdest="); 
	generate_expr(blttbl[i],1);
	printf("\t\tif (dest) b->blitzero=0;\n"); 
	printf("\t\tif (ptd) { *(UWORD *)ptd= dest; ptd -= 2; }\n");
	printf("\t}\n");
	if (a_is_on) printf("\tif (pta) pta -= b->bltamod;\n"); 
	if (b_is_on) printf("\tif (ptb) ptb -= b->bltbmod;\n"); 
	if (c_is_on) printf("\tif (ptc) ptc -= b->bltcmod;\n");
	printf("\tif (ptd) ptd-=b->bltdmod;\n"); 
	printf("}\n");
	if (a_is_on) printf("if (pta) b->bltadat = (*(pta + b->bltamod + 2) << 8) | *(pta + b->bltamod + 1);\n"); /* Maybe not necessary, but I don't want problems */
	if (b_is_on) printf("if (ptb) b->bltbdat = (*(ptb + b->bltbmod + 2) << 8) | *(ptb + b->bltbmod + 1);\n");
	if (c_is_on) printf("if (ptc) b->bltcdat = (*(ptc + b->bltcmod + 2) << 8) | *(ptc + b->bltcmod + 1);\n");
	printf("if (ptd) b->bltddat = (*(ptd + b->bltdmod + 2) << 8) | *(ptd + b->bltdmod + 1);\n");
	
	printf("} else\n"); 
#endif
	printf("{\n");
	
	printf("UWORD srca,srcb,srcc,bltaold,bltamask=b->bltafwm;\n");
	if (a_is_on) printf("if (b->hblitsize==1) bltamask&=b->bltalwm;\n");
	printf("for (j=0;j<b->vblitsize;j++) {\n");
	if (a_is_on) {
	    printf("\tif (pta) { b->bltadat = (*pta << 8) | *(pta+1); pta -= 2; }\n");
	    if (b_is_on) printf("\tif (ptb) { b->bltbdat = (*ptb << 8) | *(ptb+1); ptb -= 2; }\n");
	    if (c_is_on) printf("\tif (ptc) { b->bltcdat = (*ptc << 8) | *(ptc+1); ptc -= 2; }\n");
	    printf("\tbltaold=b->bltadat & bltamask;\n");     
            printf("\tsrca=(((ULONG)bltaold<<16)|b->blitpreva)>>(16-b->blitashift);\n");
	    if (b_is_on) printf("\tsrcb=(((ULONG)b->bltbdat<<16)|b->blitprevb)>>(16-b->blitbshift);\n");
	    if (c_is_on) printf("\tsrcc=b->bltcdat;\n");
	    printf("\tb->bltddat=");
	    generate_expr(blttbl[i],1);
	    printf("\tb->blitpreva=bltaold;\n");
	    if (b_is_on) printf("\tb->blitprevb=b->bltbdat;\n");
	    printf("\tif (b->bltddat) b->blitzero=0;\n");
	    printf("\tif (ptd) { *ptd = b->bltddat >> 8; *(ptd+1) = b->bltddat; ptd-= 2; }\n");
	}
	if (a_is_on) printf("\tfor (i=2;i<b->hblitsize;i++) {\n");
	else printf("\tfor (i=0;i<b->hblitsize;i++) {\n");
	if (a_is_on) printf("\t\tif (pta) { b->bltadat = (*pta << 8) | *(pta+1); pta -= 2; }\n");
	if (b_is_on) printf("\t\tif (ptb) { b->bltbdat = (*ptb << 8) | *(ptb+1); ptb -= 2; }\n");
	if (c_is_on) printf("\t\tif (ptc) { b->bltcdat = (*ptc << 8) | *(ptc+1); ptc -= 2; }\n");
        if (a_is_on) printf("\t\tsrca=(((ULONG)b->bltadat<<16)|b->blitpreva)>>(16-b->blitashift);\n");
	if (b_is_on) printf("\t\tsrcb=(((ULONG)b->bltbdat<<16)|b->blitprevb)>>(16-b->blitbshift);\n");
	if (c_is_on) printf("\t\tsrcc=b->bltcdat;\n");
	printf("\t\tb->bltddat=");
	generate_expr(blttbl[i],1);
	if (a_is_on) printf("\t\tb->blitpreva=b->bltadat;\n");
	if (b_is_on) printf("\t\tb->blitprevb=b->bltbdat;\n");
	printf("\t\tif (b->bltddat) b->blitzero=0;\n");
	printf("\t\tif (ptd) { *ptd = b->bltddat >> 8; *(ptd+1) = b->bltddat; ptd-= 2; }\n");
	printf("\t}\n");
	if (a_is_on) {
	    printf("\tif (b->hblitsize>1) {\n");
	    printf("\t\tif (pta) { b->bltadat = (*pta << 8) | *(pta+1); pta -= 2; }\n");
	    if (b_is_on) printf("\t\tif (ptb) { b->bltbdat = (*ptb << 8) | *(ptb+1); ptb -= 2; }\n");
	    if (c_is_on) printf("\t\tif (ptc) { b->bltcdat = (*ptc << 8) | *(ptc+1); ptc -= 2; }\n");
	    printf("\t\tbltaold=b->bltadat & b->bltalwm;\n");     
            printf("\t\tsrca=(((ULONG)bltaold<<16)|b->blitpreva)>>(16-b->blitashift);\n");
	    if (b_is_on) printf("\t\tsrcb=(((ULONG)b->bltbdat<<16)|b->blitprevb)>>(16-b->blitbshift);\n");
	    if (c_is_on) printf("\t\tsrcc=b->bltcdat;\n");
	    printf("\t\tb->bltddat=");
	    generate_expr(blttbl[i],1);
	    printf("\t\tb->blitpreva=bltaold;\n");
	    if (b_is_on) printf("\t\tb->blitprevb=b->bltbdat;\n");
	    printf("\t\tif (b->bltddat) b->blitzero=0;\n");
	    printf("\t\tif (ptd) { *ptd = b->bltddat >> 8; *(ptd+1) = b->bltddat; ptd-= 2; }\n");
	    printf("\t}\n");
	}
	if (a_is_on) printf("\tif (pta) pta-=b->bltamod;\n");
	if (b_is_on) printf("\tif (ptb) ptb-=b->bltbmod;\n");
	if (c_is_on) printf("\tif (ptc) ptc-=b->bltcmod;\n");
	printf("\tif (ptd) ptd-=b->bltdmod;\n");
	printf("}\n");
	printf("}\n");
	printf("}\n");
    }
}
	 
static void generate_table(void)
{
    unsigned int index = 0;
    unsigned int i;
    printf("#include \"sysconfig.h\"\n");
    printf("#include \"sysdeps.h\"\n");
    printf("#include \"config.h\"\n");
    printf("#include \"options.h\"\n");
    printf("#include \"custom.h\"\n");
    printf("#include \"blitter.h\"\n");
    printf("#include \"blitfunc.h\"\n\n");
    printf("blitter_func *blitfunc_dofast[256] = {\n");
    for (i = 0; i < 256; i++) {
	if (index < sizeof(blttbl) && i == blttbl[index]) {
	    printf("blitdofast_%x",i);
	    index++;
	}
	else printf("0");
	if (i < 255) printf(", ");
	if ((i & 7) == 7) printf("\n");
    }
    printf("};\n\n");
    
    index = 0;
    printf("blitter_func *blitfunc_dofast_desc[256] = {\n");
    for (i = 0; i < 256; i++) {
	if (index < sizeof(blttbl) && i == blttbl[index]) {
	    printf("blitdofast_desc_%x",i);
	    index++;
	}
	else printf("0");
	if (i < 255) printf(", ");
	if ((i & 7) == 7) printf("\n");
    }
    printf("};\n");
}

static void generate_header(void)
{
    unsigned int i;
    for (i = 0; i < sizeof(blttbl); i++) {
	printf("extern blitter_func blitdofast_%x;\n",blttbl[i]);
	printf("extern blitter_func blitdofast_desc_%x;\n",blttbl[i]);
    }
}

int main(int argc, char **argv)
{
    char mode = 'i';
    if (argc == 2) mode = *argv[1];
    switch (mode) {
     case 'i': generate_include();
	       break;
     case 'f': generate_func();
	       break;
     case 't': generate_table();
	       break;
     case 'h': generate_header();
	       break;
     default: abort();
    }
    return 0;
}

