home *** CD-ROM | disk | FTP | other *** search
- /*
- * UAE - The Un*x Amiga Emulator
- *
- * Custom chip emulation
- *
- * (c) 1995 Bernd Schmidt, Alessandro Bissacco
- */
-
- #include "sysconfig.h"
- #include "sysdeps.h"
-
- #include "config.h"
- #include "options.h"
- #include "events.h"
- #include "memory.h"
- #include "custom.h"
- #include "blitter.h"
- #include "blit.h"
- #undef FAST_BLITTER
- UWORD bltsize, oldvblts;
- UWORD bltcon0,bltcon1;
- ULONG bltapt,bltbpt,bltcpt,bltdpt;
- #define FAST_BLITTER 1
- static UWORD blitlpos,blinea,blineb;
- static CPTR bltcnxlpt,bltdnxlpt;
- static int blitline,blitfc,blitfill,blitife,blitdesc,blitsing;
- static int blitonedot,blitsign;
- static long int bltwait;
-
- struct bltinfo blt_info;
-
- static UBYTE blit_filltable[256][4][2];
-
- enum blitter_states bltstate;
-
- void build_blitfilltable(void)
- {
- unsigned int d, fillmask;
- int i;
- for (d = 0; d < 256; d++) {
- for (i = 0; i < 4; i++) {
- int fc = i & 1;
- UBYTE data = d;
- for (fillmask = 1; fillmask != 0x100; fillmask <<= 1) {
- UWORD tmp = data;
- if (fc) {
- if (i & 2)
- data |= fillmask;
- else
- data ^= fillmask;
- }
- if (tmp & fillmask) fc = !fc;
- }
- blit_filltable[d][i][0] = data;
- blit_filltable[d][i][1] = fc;
- }
- }
- }
-
- static __inline__ UWORD *blit_xlateptr(CPTR bltpt, int bytecount)
- {
- if (!chipmem_bank.check(bltpt,bytecount)) return NULL;
- return chipmem_bank.xlateaddr(bltpt);
- }
-
- static __inline__ UWORD *blit_xlateptr_desc(CPTR bltpt, int bytecount)
- {
- if (!chipmem_bank.check(bltpt-bytecount, bytecount)) return NULL;
- return chipmem_bank.xlateaddr(bltpt);
- }
-
- static void blitter_dofast(void)
- {
- int i,j;
- UWORD *bltadatpt = 0, *bltbdatpt = 0, *bltcdatpt = 0, *bltddatpt = 0;
- UWORD blitahold, blitbhold, bltaold;
- UBYTE mt = bltcon0 & 0xFF;
-
- if (bltcon0 & 0x800) {
- bltadatpt = blit_xlateptr(bltapt, (blt_info.hblitsize*2+blt_info.bltamod)*blt_info.vblitsize);
- bltapt += (blt_info.hblitsize*2+blt_info.bltamod)*blt_info.vblitsize;
- }
- if (bltcon0 & 0x400) {
- bltbdatpt = blit_xlateptr(bltbpt, (blt_info.hblitsize*2+blt_info.bltbmod)*blt_info.vblitsize);
- bltbpt += (blt_info.hblitsize*2+blt_info.bltbmod)*blt_info.vblitsize;
- }
- if (bltcon0 & 0x200) {
- bltcdatpt = blit_xlateptr(bltcpt, (blt_info.hblitsize*2+blt_info.bltcmod)*blt_info.vblitsize);
- bltcpt += (blt_info.hblitsize*2+blt_info.bltcmod)*blt_info.vblitsize;
- }
- if (bltcon0 & 0x100) {
- bltddatpt = blit_xlateptr(bltdpt, (blt_info.hblitsize*2+blt_info.bltdmod)*blt_info.vblitsize);
- bltdpt += (blt_info.hblitsize*2+blt_info.bltdmod)*blt_info.vblitsize;
- }
-
- if (blitfunc_dofast[mt] && !blitfill)
- (*blitfunc_dofast[mt])(bltadatpt,bltbdatpt,bltcdatpt,bltddatpt,&blt_info);
- else {
- WORD bltamodw = blt_info.bltamod/2, bltbmodw = blt_info.bltbmod/2, bltcmodw = blt_info.bltcmod/2, bltdmodw = blt_info.bltdmod/2;
- /*if (!blitfill) fprintf(stderr, "minterm %x not present\n",mt); */
- for (j = 0; j < blt_info.vblitsize; j++) {
- blitfc = !!(bltcon1 & 0x4);
- for (i = 0; i < blt_info.hblitsize; i++) {
- if (bltadatpt) blt_info.bltadat = *bltadatpt++;
- if (bltbdatpt) blt_info.bltbdat = *bltbdatpt++;
- if (bltcdatpt) blt_info.bltcdat = *bltcdatpt++;
- bltaold = blt_info.bltadat;
- if (i == 0) bltaold &= blt_info.bltafwm;
- if (i== blt_info.hblitsize-1) bltaold &= blt_info.bltalwm;
- blitahold = (((ULONG)blt_info.blitpreva << 16) | bltaold) >> blt_info.blitashift;
- blitbhold = (((ULONG)blt_info.blitprevb << 16) | blt_info.bltbdat) >> blt_info.blitbshift;
- blt_info.bltddat = blit_func(blitahold, blitbhold, blt_info.bltcdat, mt);
- if (blitfill) {
- UWORD d = blt_info.bltddat;
- int ifemode = blitife ? 2 : 0;
- int fc1 = blit_filltable[d & 255][ifemode + blitfc][1];
- blt_info.bltddat = (blit_filltable[d & 255][ifemode + blitfc][0]
- + (blit_filltable[d >> 8][ifemode + fc1][0] << 8));
- blitfc = blit_filltable[d >> 8][ifemode + fc1][1];
- }
- blt_info.blitpreva = bltaold; blt_info.blitprevb = blt_info.bltbdat;
- if (blt_info.bltddat) blt_info.blitzero = 0;
- if (bltddatpt) *bltddatpt++ = blt_info.bltddat;
- }
- if (bltadatpt) bltadatpt += bltamodw;
- if (bltbdatpt) bltbdatpt += bltbmodw;
- if (bltcdatpt) bltcdatpt += bltcmodw;
- if (bltddatpt) bltddatpt += bltdmodw;
- }
- }
- bltstate = BLT_done;
- }
-
- static void blitter_dofast_desc(void)
- {
- int i,j;
- UWORD *bltadatpt = 0, *bltbdatpt = 0, *bltcdatpt = 0, *bltddatpt = 0;
- UWORD blitahold, blitbhold, bltaold;
- WORD bltamodw = blt_info.bltamod/2, bltbmodw = blt_info.bltbmod/2, bltcmodw = blt_info.bltcmod/2, bltdmodw = blt_info.bltdmod/2;
- UBYTE mt = bltcon0 & 0xFF;
-
- if (bltcon0 & 0x800) {
- bltadatpt = blit_xlateptr_desc(bltapt, (blt_info.hblitsize*2+blt_info.bltamod)*blt_info.vblitsize);
- bltapt -= (blt_info.hblitsize*2+blt_info.bltamod)*blt_info.vblitsize;
- }
- if (bltcon0 & 0x400) {
- bltbdatpt = blit_xlateptr_desc(bltbpt, (blt_info.hblitsize*2+blt_info.bltbmod)*blt_info.vblitsize);
- bltbpt -= (blt_info.hblitsize*2+blt_info.bltbmod)*blt_info.vblitsize;
- }
- if (bltcon0 & 0x200) {
- bltcdatpt = blit_xlateptr_desc(bltcpt, (blt_info.hblitsize*2+blt_info.bltcmod)*blt_info.vblitsize);
- bltcpt -= (blt_info.hblitsize*2+blt_info.bltcmod)*blt_info.vblitsize;
- }
- if (bltcon0 & 0x100) {
- bltddatpt = blit_xlateptr_desc(bltdpt, (blt_info.hblitsize*2+blt_info.bltdmod)*blt_info.vblitsize);
- bltdpt -= (blt_info.hblitsize*2+blt_info.bltdmod)*blt_info.vblitsize;
- }
- if (blitfunc_dofast_desc[mt] && !blitfill)
- (*blitfunc_dofast_desc[mt])(bltadatpt,bltbdatpt,bltcdatpt,bltddatpt,&blt_info);
- else {
- WORD bltamodw = blt_info.bltamod/2, bltbmodw = blt_info.bltbmod/2, bltcmodw = blt_info.bltcmod/2, bltdmodw = blt_info.bltdmod/2;
- /* if (!blitfill) fprintf(stderr, "minterm %x not present\n",mt);*/
- for (j = 0; j < blt_info.vblitsize; j++) {
- blitfc = !!(bltcon1 & 0x4);
- for (i = 0; i < blt_info.hblitsize; i++) {
- if (bltadatpt) blt_info.bltadat = *bltadatpt--;
- if (bltbdatpt) blt_info.bltbdat = *bltbdatpt--;
- if (bltcdatpt) blt_info.bltcdat = *bltcdatpt--;
- bltaold = blt_info.bltadat;
- if (i == 0) bltaold &= blt_info.bltafwm;
- if (i== blt_info.hblitsize-1) bltaold &= blt_info.bltalwm;
- blitahold = (((ULONG)bltaold << 16) | blt_info.blitpreva) >> (16-blt_info.blitashift);
- blitbhold = (((ULONG)blt_info.bltbdat << 16) | blt_info.blitprevb) >> (16-blt_info.blitbshift);
- blt_info.bltddat = blit_func(blitahold, blitbhold, blt_info.bltcdat, mt);
- if (blitfill) {
- UWORD d = blt_info.bltddat;
- int ifemode = blitife ? 2 : 0;
- int fc1 = blit_filltable[d & 255][ifemode + blitfc][1];
- blt_info.bltddat = (blit_filltable[d & 255][ifemode + blitfc][0]
- + (blit_filltable[d >> 8][ifemode + fc1][0] << 8));
- blitfc = blit_filltable[d >> 8][ifemode + fc1][1];
- }
- blt_info.blitpreva = bltaold; blt_info.blitprevb = blt_info.bltbdat;
- if (blt_info.bltddat) blt_info.blitzero = 0;
- if (bltddatpt) *bltddatpt-- = blt_info.bltddat;
- }
- if (bltadatpt) bltadatpt -= bltamodw;
- if (bltbdatpt) bltbdatpt -= bltbmodw;
- if (bltcdatpt) bltcdatpt -= bltcmodw;
- if (bltddatpt) bltddatpt -= bltdmodw;
- }
- }
- bltstate = BLT_done;
- }
-
- static int blitter_read(void)
- {
- if (bltcon0 & 0xe00){
- if (!dmaen(DMA_BLITTER)) return 1; /* blitter stopped */
- if (!blitline){
- if (bltcon0 & 0x800) blt_info.bltadat = chipmem_bank.wget(bltapt);
- if (bltcon0 & 0x400) blt_info.bltbdat = chipmem_bank.wget(bltbpt);
- }
- if (bltcon0 & 0x200) blt_info.bltcdat = chipmem_bank.wget(bltcpt);
- }
- bltstate = BLT_work;
- return (bltcon0 & 0xE00) != 0;
- }
-
- static int blitter_write(void)
- {
- if (blt_info.bltddat) blt_info.blitzero = 0;
- if ((bltcon0 & 0x100) || blitline){
- if (!dmaen(DMA_BLITTER)) return 1;
- chipmem_bank.wput(bltdpt, blt_info.bltddat);
- }
- bltstate = BLT_next;
- return (bltcon0 & 0x100) != 0;
- }
-
- static void blitter_blit(void)
- {
- UWORD blitahold,blitbhold,blitchold;
- UWORD bltaold;
-
- if (blitdesc) {
- UWORD bltamask = 0xffff;
-
- if (!blitlpos) { bltamask &= blt_info.bltafwm; }
- if (blitlpos == (blt_info.hblitsize - 1)) { bltamask &= blt_info.bltalwm; }
- bltaold = blt_info.bltadat & bltamask;
-
- blitahold = (((ULONG)bltaold << 16) | blt_info.blitpreva) >> (16-blt_info.blitashift);
- blitbhold = (((ULONG)blt_info.bltbdat << 16) | blt_info.blitprevb) >> (16-blt_info.blitbshift);
- blitchold = blt_info.bltcdat;
- } else {
- UWORD bltamask = 0xffff;
-
- if (!blitlpos) { bltamask &= blt_info.bltafwm; }
- if (blitlpos == (blt_info.hblitsize - 1)) { bltamask &= blt_info.bltalwm; }
- bltaold = blt_info.bltadat & bltamask;
-
- blitahold = (((ULONG)blt_info.blitpreva << 16) | bltaold) >> blt_info.blitashift;
- blitbhold = (((ULONG)blt_info.blitprevb << 16) | blt_info.bltbdat) >> blt_info.blitbshift;
- blitchold = blt_info.bltcdat;
- }
- blt_info.bltddat = 0;
- blt_info.bltddat = blit_func(blitahold, blitbhold, blitchold, bltcon0 & 0xFF);
- if (blitfill){
- UWORD fillmask;
- for (fillmask = 1; fillmask; fillmask <<= 1){
- UWORD tmp = blt_info.bltddat;
- if (blitfc) {
- if (blitife)
- blt_info.bltddat |= fillmask;
- else
- blt_info.bltddat ^= fillmask;
- }
- if (tmp & fillmask) blitfc = !blitfc;
- }
- }
- bltstate = BLT_write;
- blt_info.blitpreva = bltaold; blt_info.blitprevb = blt_info.bltbdat;
- }
-
- static void blitter_nxblit(void)
- {
- bltstate = BLT_read;
- if (blitdesc){
- if (++blitlpos == blt_info.hblitsize) {
- if (--blt_info.vblitsize == 0) {
- bltstate = BLT_done;
- #if FAST_BLITTER == 0
- custom_bank.wput(0xDFF09C,0x8040);
- #endif
- }
- blitfc = bltcon1 & 0x4;
-
- blitlpos = 0;
- if (bltcon0 & 0x800) bltapt -= 2+blt_info.bltamod;
- if (bltcon0 & 0x400) bltbpt -= 2+blt_info.bltbmod;
- if (bltcon0 & 0x200) bltcpt -= 2+blt_info.bltcmod;
- if (bltcon0 & 0x100) bltdpt -= 2+blt_info.bltdmod;
- } else {
- if (bltcon0 & 0x800) bltapt -= 2;
- if (bltcon0 & 0x400) bltbpt -= 2;
- if (bltcon0 & 0x200) bltcpt -= 2;
- if (bltcon0 & 0x100) bltdpt -= 2;
- }
- } else {
- if (++blitlpos == blt_info.hblitsize) {
- if (--blt_info.vblitsize == 0) {
- bltstate = BLT_done;
- #if FAST_BLITTER == 0
- custom_bank.wput(0xDFF09C,0x8040);
- #endif
- }
- blitlpos = 0;
- if (bltcon0 & 0x800) bltapt += 2+blt_info.bltamod;
- if (bltcon0 & 0x400) bltbpt += 2+blt_info.bltbmod;
- if (bltcon0 & 0x200) bltcpt += 2+blt_info.bltcmod;
- if (bltcon0 & 0x100) bltdpt += 2+blt_info.bltdmod;
- } else {
- if (bltcon0 & 0x800) bltapt += 2;
- if (bltcon0 & 0x400) bltbpt += 2;
- if (bltcon0 & 0x200) bltcpt += 2;
- if (bltcon0 & 0x100) bltdpt += 2;
- }
- }
- }
-
- static __inline__ void blitter_line_incx(void)
- {
- blinea >>= 1;
- if (!blinea) {
- blinea = 0x8000;
- bltcnxlpt += 2;
- bltdnxlpt += 2;
- }
- }
-
- static __inline__ void blitter_line_decx(void)
- {
- blinea <<= 1;
- if (!blinea) {
- blinea = 1;
- bltcnxlpt -= 2;
- bltdnxlpt -= 2;
- }
- }
-
- static __inline__ void blitter_line_decy(void)
- {
- bltcnxlpt -= blt_info.bltcmod;
- bltdnxlpt -= blt_info.bltcmod; /* ??? am I wrong or doesn't KS1.3 set bltdmod? */
- blitonedot = 0;
- }
-
- static __inline__ void blitter_line_incy(void)
- {
- bltcnxlpt += blt_info.bltcmod;
- bltdnxlpt += blt_info.bltcmod; /* ??? */
- blitonedot = 0;
- }
-
- static void blitter_line(void)
- {
- UWORD blitahold = blinea, blitbhold = blineb & 1 ? 0xFFFF : 0, blitchold = blt_info.bltcdat;
- blt_info.bltddat = 0;
-
- if (blitsing && blitonedot) blitahold = 0;
- blitonedot = 1;
- blt_info.bltddat = blit_func(blitahold, blitbhold, blitchold, bltcon0 & 0xFF);
- if (!blitsign){
- bltapt += (WORD)blt_info.bltamod;
- if (bltcon1 & 0x10){
- if (bltcon1 & 0x8)
- blitter_line_decy();
- else
- blitter_line_incy();
- } else {
- if (bltcon1 & 0x8)
- blitter_line_decx();
- else
- blitter_line_incx();
- }
- } else {
- bltapt += (WORD)blt_info.bltbmod;
- }
- if (bltcon1 & 0x10){
- if (bltcon1 & 0x4)
- blitter_line_decx();
- else
- blitter_line_incx();
- } else {
- if (bltcon1 & 0x4)
- blitter_line_decy();
- else
- blitter_line_incy();
- }
- blitsign = 0 > (WORD)bltapt;
- bltstate = BLT_write;
- }
-
- static __inline__ void blitter_nxline(void)
- {
- bltcpt = bltcnxlpt;
- bltdpt = bltdnxlpt;
- blineb = (blineb << 1) | (blineb >> 15);
- if (--blt_info.vblitsize == 0) {
- bltstate = BLT_done;
- #if FAST_BLITTER == 0
- custom_bank.wput(0xDFF09C,0x8040);
- #endif
- } else {
- bltstate = BLT_read;
- }
- }
-
- static void blit_init(void)
- {
- blitlpos = 0;
- blt_info.blitzero = 1; blt_info.blitpreva = blt_info.blitprevb = 0;
- blitline = bltcon1 & 1;
- blt_info.blitashift = bltcon0 >> 12; blt_info.blitbshift = bltcon1 >> 12;
-
- if (blitline) {
- if (blt_info.hblitsize != 2)
- fprintf(stderr, "weird hblitsize in linemode: %d\n", blt_info.hblitsize);
- bltcnxlpt = bltcpt;
- bltdnxlpt = bltdpt;
- blitsing = bltcon1 & 0x2;
- blinea = blt_info.bltadat >> blt_info.blitashift;
- blineb = (blt_info.bltbdat >> blt_info.blitbshift) | (blt_info.bltbdat << (16-blt_info.blitbshift));
- #if 0
- if (blineb != 0xFFFF && blineb != 0)
- fprintf(stderr, "%x %x %d %x\n", blineb, blt_info.bltbdat, blt_info.blitbshift, bltcon1);
- #endif
- blitsign = bltcon1 & 0x40;
- blitonedot = 0;
- } else {
- blitfc = !!(bltcon1 & 0x4);
- blitife = bltcon1 & 0x8;
- blitfill = bltcon1 & 0x18;
- if ((bltcon1 & 0x18) == 0x18) {
- /* Digital "Trash" demo does this; others too. Apparently, no
- * negative effects. */
- static int warn = 1;
- if (warn)
- fprintf(stderr, "warning: weird fill mode (further messages suppressed)\n");
- warn = 0;
- }
- blitdesc = bltcon1 & 0x2;
- if (blitfill && !blitdesc)
- fprintf(stderr, "warning: blitter fill without desc\n");
- }
- }
-
- static void actually_do_blit(void)
- {
- if (blitline) {
- do {
- blitter_read();
- blitter_line();
- blitter_write();
- blitter_nxline();
- } while (bltstate != BLT_done);
- } else {
- /*blitcount[bltcon0 & 0xff]++; blitter debug */
- if (blitdesc) blitter_dofast_desc();
- else blitter_dofast();
- }
- }
-
- void blitter_handler(void)
- {
- if (!dmaen(DMA_BLITTER)) {
- eventtab[ev_blitter].active = 1;
- eventtab[ev_blitter].oldcycles = cycles;
- eventtab[ev_blitter].evtime = 10; /* wait a little */
- return; /* gotta come back later. */
- }
- actually_do_blit();
-
- INTREQ(0x8040);
- eventtab[ev_blitter].active = 0;
- specialflags &= ~SPCFLAG_BLTNASTY;
- }
-
- void do_blitter(void)
- {
- #if FAST_BLITTER == 0
- /* I'm not sure all this bltstate stuff is really necessary.
- * Most programs should be OK if the blit is done as soon as BLTSIZE is
- * written to, and the BLTFINISH bit is set some time after that.
- * This code here is nowhere near exact.
- */
- do {
- switch(bltstate) {
- case BLT_init:
- blit_init();
- bltstate = BLT_read;
- /* fall through */
- case BLT_read:
- if (blitter_read())
- break;
- /* fall through */
- case BLT_work:
- if (blitline)
- blitter_line();
- else
- blitter_blit();
- /* fall through */
- case BLT_write:
- if (blitter_write())
- break;
- /* fall through */
- case BLT_next:
- if (blitline)
- blitter_nxline();
- else
- blitter_nxblit();
- break;
- case BLT_done:
- specialflags &= ~SPCFLAG_BLIT;
- break;
- }
- } while(bltstate != BLT_done && dmaen(DMA_BLITTER)
- && dmaen(DMA_BLITPRI)); /* blitter nasty -> no time for CPU */
- #else
- {
- long int blit_cycles = 2;
-
- if (!blitline) {
- if (bltcon0 & 0x400)
- blit_cycles++;
- if ((bltcon0 & 0x300) == 0x300)
- blit_cycles++;
- blit_cycles *= blt_info.vblitsize * blt_info.hblitsize;
- }
- blit_init();
-
- eventtab[ev_blitter].active = 1;
- eventtab[ev_blitter].oldcycles = cycles;
- eventtab[ev_blitter].evtime = blit_cycles;
- events_schedule();
-
- specialflags &= ~SPCFLAG_BLIT;
- if (dmaen(DMA_BLITPRI))
- specialflags |= SPCFLAG_BLTNASTY;
- }
- #endif
- }
-
- void maybe_blit(void)
- {
- static int warned = 0;
- if (bltstate == BLT_done)
- return;
-
- if (!warned) {
- warned = 1;
- fprintf(stderr, "warning: Program does not wait for blitter (no further messages)\n");
- }
- if (!eventtab[ev_blitter].active)
- printf("FOO!!?\n");
- actually_do_blit();
- eventtab[ev_blitter].active = 0;
- specialflags &= ~SPCFLAG_BLTNASTY;
- }
-