/*

	copper.c - the User Copper Lists setup routines

*/


#define bw_lineMod  224    /* 256 - 32 */
#define bw_rowMod  -1792  /* 32=0+7*256+x => x=-1760. -1760-32=-1792 */
#define bw_blockMod 0


UWORD bwModeColors[] = {
    0x888,0x00D,0xDDD,0x000
};


void makeBWBlock(struct UCopList *ptr, short block)
{
    /* block = 0,1 or 2 */
    int i,l;

    l = (block<<6) + topLine;

    /* Assuming every block begins in line modulo */
    for (i=0; i<7; i++) {
	l += 7;
	CWAIT(ptr, l, 0);
	CMOVE(ptr, custom.bpl1mod, bw_rowMod);
	l++;
	CWAIT(ptr, l, 0);
	CMOVE(ptr, custom.bpl1mod, bw_lineMod);
    }
    l +=7;
    CWAIT(ptr, l, 0);
    CMOVE(ptr, custom.bpl1mod, bw_blockMod);
    l++;
    CWAIT(ptr, l, 0);
    CMOVE(ptr, custom.bpl1mod, bw_lineMod);

} /* end of makeBWBlock */



/*
	Handy routine to make copper write a longword
	(to a word-aligned address only, of course).

*/
void CMoveLong(struct UCopList *ptr, void *addr, ULONG value)
{
    union { ULONG v;
	    UWORD w[2]; } un;
    un.v = value;
    CMove(ptr, ((UWORD *)addr)++, un.w[0]);
    CBump(ptr);
    CMove(ptr, (UWORD *)addr, un.w[1]);
    CBump(ptr);

} /* End of CMoveLong */



void makeUCopList(struct UCopList **ptr, short depth, UWORD *col_list)
{
    register int i;
    int colNum = 1 << depth;

    /* Automatic deallocation at CloseScreen() or FreeVPortCopLists().
    Therefore allocate, rather than define "struct UCopList userCopList;"
    and DON'T use AllocRemember! */

    if ((*ptr = (struct UCopList *) AllocMem(sizeof(struct UCopList),
	MEMF_PUBLIC | MEMF_CLEAR )) == NULL)
	    cleanExit(memory_msg, RETURN_WARN);

    i = 20 + colNum + 2 * depth;
    /* Constant (with margin) + number of colours
	+ 2 words per bitplane address */

    i += 97;  /* add 3*4*8+1 for the line-reordering instructions */

    /* begin copper list */
    CINIT(*ptr, i);

    /* line before first spectrum screen line */
    CWAIT(*ptr, topLine - 1, 0);

    /* no bitplanes active, colour on */
    CMOVE(*ptr, custom.bplcon0, 0x0200);

    /* colour registers */
    for (i=0; i<colNum; i++)
	CMOVE(*ptr, custom.color[i], col_list[i]);

    {
	ULONG *p = custom.bplpt; /* bplpt is an array */
	/* set bitplane pointers */
	for (i=0; i<depth; i++)
	    CMoveLong(*ptr, p++, (ULONG)(bwBitMap.Planes[i]));
    }

    /* first spectrum screen line */
    CWAIT(*ptr, topLine, 0);

    /* set diwstrt/diwstop */
    /* 05 means line 5, which is a nice place to start... */
    /* 40 means line $140 = 320, which also is nice... */
    /* 50 makes a nice left edge, and E0 ($1E0) a good right one */
    CMOVE(*ptr, custom.diwstrt, 0x0550);
    CMOVE(*ptr, custom.diwstop, 0x40E0);

    {	/* set ddfstrt/ddfstop (low resolution) */
	UWORD s = 70;
	CMOVE(*ptr, custom.ddfstrt, s);
	CMOVE(*ptr, custom.ddfstop, s + ((SPSCR_WIDTH>>1)-8) );
    }

    /* bitplanes active, colour on */
    CMOVE(*ptr, custom.bplcon0, (depth<<12) | 0x0200 );

	/* black-and-white mode line reordering */
    /* begin in line modulo */
    CMOVE(*ptr, custom.bpl1mod, bw_lineMod);
    for (i=0; i<3; i++) makeBWBlock(*ptr, i);  /* 3 blocks, 0-2 */

    /* first line below spectrum screen */
    CWAIT(*ptr, topLine + SPSCR_HEIGHT, 0);

    /* No bitplanes active, colour on */
    CMOVE(*ptr, custom.bplcon0, 0x0200);

    /* end copper list */
    CEND(*ptr);

}	/* End of makeUCopList */



void getBwCopList(void)
{
    makeUCopList(&bwCopList, SPSCR_BWDEPTH, bwModeColors);

} /* End of getCopLists */

