Commit pandora source code

This commit is contained in:
Chips-fr 2015-05-13 18:47:23 +00:00
parent f10bc4f2bf
commit e86cde6318
276 changed files with 263292 additions and 0 deletions

969
src/blitter.cpp Normal file
View file

@ -0,0 +1,969 @@
/*
* UAE - The Un*x Amiga Emulator
*
* Custom chip emulation
*
* (c) 1995 Bernd Schmidt, Alessandro Bissacco
* (c) 2002 - 2005 Toni Wilen
*/
//#define USE_BLITTER_EXTRA_INLINE
#define STOP_WHEN_NASTY
#include "sysconfig.h"
#include "sysdeps.h"
#include "options.h"
#include "uae.h"
#include "memory.h"
#include "custom.h"
#include "events.h"
#include "newcpu.h"
#include "blitter.h"
#include "blit.h"
#include "savestate.h"
// Do some statistics
/*
int count_blitter_normal[256];
int count_blitter_fast[256];
int count_blitter_desc_normal[256];
int count_blitter_desc_fast[256];
int count_blitter_line[256];
void dump_blitter_stat(void)
{
int i;
printf("count_blitter_normal:\n");
for(i=0; i<256; ++i)
{
if(count_blitter_normal[i])
printf(" 0x%02x: %d\n", i, count_blitter_normal[i]);
}
printf("count_blitter_fast:\n");
for(i=0; i<256; ++i)
{
if(count_blitter_fast[i])
printf(" 0x%02x: %d\n", i, count_blitter_fast[i]);
}
printf("count_blitter_desc_normal:\n");
for(i=0; i<256; ++i)
{
if(count_blitter_desc_normal[i])
printf(" 0x%02x: %d\n", i, count_blitter_desc_normal[i]);
}
printf("count_blitter_desc_fast:\n");
for(i=0; i<256; ++i)
{
if(count_blitter_desc_fast[i])
printf(" 0x%02x: %d\n", i, count_blitter_desc_fast[i]);
}
printf("count_blitter_line:\n");
for(i=0; i<256; ++i)
{
if(count_blitter_line[i])
printf(" 0x%02x: %d\n", i, count_blitter_line[i]);
}
}
*/
uae_u16 bltcon0, bltcon1;
uae_u32 bltapt, bltbpt, bltcpt, bltdpt;
uae_u32 preva = 0, prevb = 0;
int blinea_shift, blitsign;
static uae_u16 blinea, blineb;
static int blitline, blitfc, blitfill, blitife, blitsing, blitdesc;
static int blitonedot;
static int blit_ch;
struct bltinfo blt_info;
static uae_u8 blit_filltable[256][4][2];
uae_u32 blit_masktable[BLITTER_MAX_WORDS];
enum blitter_states bltstate;
static long int blit_cyclecounter;
// blitter_slowdown doesn't work at the moment
//static int blit_slowdown;
static long blit_firstline_cycles;
static long blit_first_cycle;
static int blit_last_cycle, blit_dmacount, blit_dmacount2;
static int blit_nod;
static const int *blit_diag;
static int ddat1use;
// New vars for blitter mode "partial"
static int blit_total_required_cycles; // Estimated number of cycles of entire blitter op
static int blit_cycles_per_op; // Number of cycles per blitter op
static int blit_cycles_per_vsize; // Number of cycles per line
static int blit_vblitsize_done; // Number of vblitsize-lines are done
static unsigned long blit_cycle_at_start;
static unsigned long blit_init_cycles; // Cycles required for blitter initialisation
static unsigned long blit_cycle_current;
static unsigned long blit_cycle_entered_wait; // At this cycle, blitter entered in wait-state because of disabled DMA
/*
Blitter Idle Cycle:
Cycles that are free cycles (available for CPU) and
are not used by any other Agnus DMA channel. Blitter
idle cycle is not "used" by blitter, CPU can still use
it normally if it needs the bus.
same in both block and line modes
number of cycles, initial cycle, main cycle
*/
#define DIAGSIZE 10
static const int blit_cycle_diagram[][DIAGSIZE] =
{
{ 2, 0,0, 0,0 }, /* 0 -- */
{ 2, 0,0, 0,4 }, /* 1 -D */
{ 2, 0,3, 0,3 }, /* 2 -C */
{ 3, 0,3,0, 0,3,4 }, /* 3 -CD */
{ 3, 0,2,0, 0,2,0 }, /* 4 -B- */
{ 3, 0,2,0, 0,2,4 }, /* 5 -BD */
{ 3, 0,2,3, 0,2,3 }, /* 6 -BC */
{ 4, 0,2,3,0, 0,2,3,4 }, /* 7 -BCD */
{ 2, 1,0, 1,0 }, /* 8 A- */
{ 2, 1,0, 1,4 }, /* 9 AD */
{ 2, 1,3, 1,3 }, /* A AC */
{ 3, 1,3,0, 1,3,4, }, /* B ACD */
{ 3, 1,2,0, 1,2,0 }, /* C AB- */
{ 3, 1,2,0, 1,2,4 }, /* D ABD */
{ 3, 1,2,3, 1,2,3 }, /* E ABC */
{ 4, 1,2,3,0, 1,2,3,4 } /* F ABCD */
};
/*
following 4 channel combinations in fill mode have extra
idle cycle added (still requires free bus cycle)
*/
static const int blit_cycle_diagram_fill[][DIAGSIZE] =
{
{ 0 }, /* 0 */
{ 3, 0,0,0, 0,4,0 }, /* 1 */
{ 0 }, /* 2 */
{ 0 }, /* 3 */
{ 0 }, /* 4 */
{ 4, 0,2,0,0, 0,2,4,0 }, /* 5 */
{ 0 }, /* 6 */
{ 0 }, /* 7 */
{ 0 }, /* 8 */
{ 3, 1,0,0, 1,4,0 }, /* 9 */
{ 0 }, /* A */
{ 0 }, /* B */
{ 0 }, /* C */
{ 4, 1,2,0,0, 1,2,4,0 }, /* D */
{ 0 }, /* E */
{ 0 }, /* F */
};
/*
-C-D C-D- ... C-D- --
line draw takes 4 cycles (-C-D)
idle cycles do the same as above, 2 dma fetches
(read from C, write to D, but see below)
Oddities:
- first word is written to address pointed by BLTDPT
but all following writes go to address pointed by BLTCPT!
(some kind of internal copy because all bus cyles are
using normal BLTDDAT)
- BLTDMOD is ignored by blitter (BLTCMOD is used)
- state of D-channel enable bit does not matter!
- disabling A-channel freezes the content of BPLAPT
- C-channel disabled: nothing is written
There is one tricky situation, writing to DFF058 just before
last D write cycle (which is normally free) does not disturb
blitter operation, final D is still written correctly before
blitter starts normally (after 2 idle cycles)
There is at least one demo that does this..
*/
// 5 = internal "processing cycle"
static const int blit_cycle_diagram_line[] =
{
4, 0,3,5,4, 0,3,5,4
};
void build_blitfilltable (void)
{
unsigned int d, fillmask;
int i;
for (i = 0; i < BLITTER_MAX_WORDS; i++)
blit_masktable[i] = 0xFFFF;
for (d = 0; d < 256; d++) {
for (i = 0; i < 4; i++) {
int fc = i & 1;
uae_u8 data = d;
for (fillmask = 1; fillmask != 0x100; fillmask <<= 1) {
uae_u16 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__ void blitter_done (void)
{
ddat1use = 0;
bltstate = BLT_done;
blitter_done_notify ();
INTREQ(0x8040);
eventtab[ev_blitter].active = 0;
unset_special (&regs, SPCFLAG_BLTNASTY);
#ifdef BLITTER_DEBUG
write_log ("vpos=%d, cycles %d, missed %d, total %d\n",
vpos, blit_cyclecounter, blit_misscyclecounter, blit_cyclecounter + blit_misscyclecounter);
#endif
}
static void blitter_dofast(void)
{
int i,j;
uaecptr bltadatptr = 0, bltbdatptr = 0, bltcdatptr = 0, bltddatptr = 0;
uae_u8 mt = bltcon0 & 0xFF;
blit_masktable[BLITTER_MAX_WORDS - 1] = blt_info.bltafwm;
blit_masktable[BLITTER_MAX_WORDS - blt_info.hblitsize] &= blt_info.bltalwm;
if (bltcon0 & 0x800) {
bltadatptr = bltapt;
bltapt += (blt_info.hblitsize*2 + blt_info.bltamod)*blt_info.vblitsize;
}
if (bltcon0 & 0x400) {
bltbdatptr = bltbpt;
bltbpt += (blt_info.hblitsize*2 + blt_info.bltbmod)*blt_info.vblitsize;
}
if (bltcon0 & 0x200) {
bltcdatptr = bltcpt;
bltcpt += (blt_info.hblitsize*2 + blt_info.bltcmod)*blt_info.vblitsize;
}
if (bltcon0 & 0x100) {
bltddatptr = bltdpt;
bltdpt += (blt_info.hblitsize*2 + blt_info.bltdmod)*blt_info.vblitsize;
}
if (blitfunc_dofast[mt] && !blitfill) {
// count_blitter_fast[mt]++;
(*blitfunc_dofast[mt])(bltadatptr, bltbdatptr, bltcdatptr, bltddatptr, &blt_info);
} else
{
// count_blitter_normal[mt]++;
uae_u32 blitbhold = blt_info.bltbhold;
uaecptr dstp = 0;
uae_u32 *blit_masktable_p = blit_masktable + BLITTER_MAX_WORDS - blt_info.hblitsize;
for (j = blt_info.vblitsize; j--;) {
blitfc = !!(bltcon1 & 0x4);
for (i = blt_info.hblitsize; i--;) {
uae_u32 bltadat, blitahold;
if (bltadatptr) {
blt_info.bltadat = bltadat = CHIPMEM_AGNUS_WGET_CUSTOM (bltadatptr);
bltadatptr += 2;
} else
bltadat = blt_info.bltadat;
bltadat &= blit_masktable_p[i];
blitahold = (((uae_u32)preva << 16) | bltadat) >> blt_info.blitashift;
preva = bltadat;
if (bltbdatptr) {
uae_u16 bltbdat;
blt_info.bltbdat = bltbdat = CHIPMEM_AGNUS_WGET_CUSTOM (bltbdatptr);
bltbdatptr += 2;
blitbhold = (((uae_u32)prevb << 16) | bltbdat) >> blt_info.blitbshift;
prevb = bltbdat;
}
if (bltcdatptr) {
blt_info.bltcdat = CHIPMEM_AGNUS_WGET_CUSTOM (bltcdatptr);
bltcdatptr += 2;
}
if (dstp)
CHIPMEM_AGNUS_WPUT_CUSTOM (dstp, blt_info.bltddat);
blt_info.bltddat = blit_func (blitahold, blitbhold, blt_info.bltcdat, mt);
if (blitfill) {
uae_u16 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];
}
if (blt_info.bltddat)
blt_info.blitzero = 0;
if (bltddatptr) {
dstp = bltddatptr;
bltddatptr += 2;
}
}
if (bltadatptr) bltadatptr += blt_info.bltamod;
if (bltbdatptr) bltbdatptr += blt_info.bltbmod;
if (bltcdatptr) bltcdatptr += blt_info.bltcmod;
if (bltddatptr) bltddatptr += blt_info.bltdmod;
}
if (dstp)
CHIPMEM_AGNUS_WPUT_CUSTOM (dstp, blt_info.bltddat);
blt_info.bltbhold = blitbhold;
}
blit_masktable[BLITTER_MAX_WORDS - 1] = 0xFFFF;
blit_masktable[BLITTER_MAX_WORDS - blt_info.hblitsize] = 0xFFFF;
bltstate = BLT_done;
}
static void blitter_dofast_desc(void)
{
int i,j;
uaecptr bltadatptr = 0, bltbdatptr = 0, bltcdatptr = 0, bltddatptr = 0;
uae_u8 mt = bltcon0 & 0xFF;
blit_masktable[BLITTER_MAX_WORDS - 1] = blt_info.bltafwm;
blit_masktable[BLITTER_MAX_WORDS - blt_info.hblitsize] &= blt_info.bltalwm;
if (bltcon0 & 0x800) {
bltadatptr = bltapt;
bltapt -= (blt_info.hblitsize*2 + blt_info.bltamod)*blt_info.vblitsize;
}
if (bltcon0 & 0x400) {
bltbdatptr = bltbpt;
bltbpt -= (blt_info.hblitsize*2 + blt_info.bltbmod)*blt_info.vblitsize;
}
if (bltcon0 & 0x200) {
bltcdatptr = bltcpt;
bltcpt -= (blt_info.hblitsize*2 + blt_info.bltcmod)*blt_info.vblitsize;
}
if (bltcon0 & 0x100) {
bltddatptr = bltdpt;
bltdpt -= (blt_info.hblitsize*2 + blt_info.bltdmod)*blt_info.vblitsize;
}
if (blitfunc_dofast_desc[mt] && !blitfill) {
// count_blitter_desc_fast[mt]++;
(*blitfunc_dofast_desc[mt])(bltadatptr, bltbdatptr, bltcdatptr, bltddatptr, &blt_info);
} else
{
// count_blitter_desc_normal[mt]++;
uae_u32 blitbhold = blt_info.bltbhold;
uaecptr dstp = 0;
uae_u32 *blit_masktable_p = blit_masktable + BLITTER_MAX_WORDS - blt_info.hblitsize;
for (j = blt_info.vblitsize; j--;) {
blitfc = !!(bltcon1 & 0x4);
for (i = blt_info.hblitsize; i--;) {
uae_u32 bltadat, blitahold;
if (bltadatptr) {
blt_info.bltadat = bltadat = CHIPMEM_AGNUS_WGET_CUSTOM (bltadatptr);
bltadatptr -= 2;
} else
bltadat = blt_info.bltadat;
bltadat &= blit_masktable_p[i];
blitahold = (((uae_u32)bltadat << 16) | preva) >> blt_info.blitdownashift;
preva = bltadat;
if (bltbdatptr) {
uae_u16 bltbdat;
blt_info.bltbdat = bltbdat = CHIPMEM_AGNUS_WGET_CUSTOM (bltbdatptr);
bltbdatptr -= 2;
blitbhold = (((uae_u32)bltbdat << 16) | prevb) >> blt_info.blitdownbshift;
prevb = bltbdat;
}
if (bltcdatptr) {
blt_info.bltcdat = blt_info.bltbdat = CHIPMEM_AGNUS_WGET_CUSTOM (bltcdatptr);
bltcdatptr -= 2;
}
if (dstp)
CHIPMEM_AGNUS_WPUT_CUSTOM (dstp, blt_info.bltddat);
blt_info.bltddat = blit_func (blitahold, blitbhold, blt_info.bltcdat, mt);
if (blitfill) {
uae_u16 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];
}
if (blt_info.bltddat)
blt_info.blitzero = 0;
if (bltddatptr) {
dstp = bltddatptr;
bltddatptr -= 2;
}
}
if (bltadatptr) bltadatptr -= blt_info.bltamod;
if (bltbdatptr) bltbdatptr -= blt_info.bltbmod;
if (bltcdatptr) bltcdatptr -= blt_info.bltcmod;
if (bltddatptr) bltddatptr -= blt_info.bltdmod;
}
if (dstp)
CHIPMEM_AGNUS_WPUT_CUSTOM (dstp, blt_info.bltddat);
blt_info.bltbhold = blitbhold;
}
blit_masktable[BLITTER_MAX_WORDS - 1] = 0xFFFF;
blit_masktable[BLITTER_MAX_WORDS - blt_info.hblitsize] = 0xFFFF;
bltstate = BLT_done;
}
STATIC_INLINE void blitter_read(void)
{
if (bltcon0 & 0x200) {
blt_info.bltcdat = CHIPMEM_AGNUS_WGET_CUSTOM(bltcpt);
}
}
STATIC_INLINE void blitter_write(void)
{
if (blt_info.bltddat)
blt_info.blitzero = 0;
/* D-channel state has no effect on linedraw, but C must be enabled or nothing is drawn! */
if (bltcon0 & 0x200) {
CHIPMEM_AGNUS_WPUT_CUSTOM(bltdpt, blt_info.bltddat);
}
}
STATIC_INLINE void blitter_line_incx(void)
{
if (++blinea_shift == 16) {
blinea_shift = 0;
bltcpt += 2;
}
}
STATIC_INLINE void blitter_line_decx(void)
{
if (blinea_shift-- == 0) {
blinea_shift = 15;
bltcpt -= 2;
}
}
STATIC_INLINE void blitter_line_decy(void)
{
bltcpt -= blt_info.bltcmod;
blitonedot = 0;
}
STATIC_INLINE void blitter_line_incy(void)
{
bltcpt += blt_info.bltcmod;
blitonedot = 0;
}
static int blitter_line(void)
{
uae_u16 blitahold = (blinea & blt_info.bltafwm) >> blinea_shift;
blt_info.bltbhold = (blineb & 1) ? 0xFFFF : 0;
int blitlinepixel = !blitsing || (blitsing && !blitonedot);
blt_info.bltddat = blit_func (blitahold, blt_info.bltbhold, blt_info.bltcdat, bltcon0 & 0xFF);
blitonedot++;
if (bltcon0 & 0x800) {
if (blitsign)
bltapt += (uae_s16)blt_info.bltbmod;
else
bltapt += (uae_s16)blt_info.bltamod;
}
if (!blitsign) {
if (bltcon1 & 0x10) {
if (bltcon1 & 0x8)
blitter_line_decy ();
else
blitter_line_incy ();
} else {
if (bltcon1 & 0x8)
blitter_line_decx ();
else
blitter_line_incx ();
}
}
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 > (uae_s16)bltapt;
return blitlinepixel;
}
STATIC_INLINE void blitter_nxline(void)
{
blineb = (blineb << 1) | (blineb >> 15);
blt_info.vblitsize--;
}
static void actually_do_blit(void)
{
if (blitline) {
// count_blitter_line[bltcon0 & 0xFF]++;
do {
blitter_read ();
if (ddat1use)
bltdpt = bltcpt;
ddat1use = 1;
if (blitter_line ()) {
blitter_write ();
}
blitter_nxline ();
if (blt_info.vblitsize == 0)
bltstate = BLT_done;
} while (bltstate != BLT_done);
if(!currprefs.pandora_partial_blits)
bltdpt = bltcpt;
} else {
if (blitdesc)
blitter_dofast_desc ();
else
blitter_dofast ();
bltstate = BLT_done;
}
}
static __inline__ void blitter_doit(void)
{
actually_do_blit ();
blitter_done();
}
void blitter_handler(void)
{
static int blitter_stuck;
if (!dmaen (DMA_BLITTER)) {
eventtab[ev_blitter].active = 1;
eventtab[ev_blitter].oldcycles = get_cycles ();
eventtab[ev_blitter].evtime = 10 * CYCLE_UNIT + get_cycles (); /* wait a little */
blitter_stuck++;
if (blitter_stuck < 20000 || !currprefs.immediate_blits)
return; /* gotta come back later. */
/* "free" blitter in immediate mode if it has been "stuck" ~3 frames
* fixes some JIT game incompatibilities
*/
}
blitter_stuck = 0;
if(currprefs.pandora_partial_blits)
{
blitter_do_partial(1);
return;
}
// blitter_slowdown doesn't work at the moment
// if (blit_slowdown > 0 && !currprefs.immediate_blits) {
// eventtab[ev_blitter].active = 1;
// eventtab[ev_blitter].oldcycles = get_cycles ();
// eventtab[ev_blitter].evtime = blit_slowdown * CYCLE_UNIT + get_cycles (); /* wait a little */
// blit_slowdown = -1;
// return;
// }
blitter_doit();
}
static void blitter_force_finish (void)
{
uae_u16 odmacon;
if (bltstate == BLT_done)
return;
if (bltstate != BLT_done) {
/* blitter is currently running
* force finish (no blitter state support yet)
*/
odmacon = dmacon;
dmacon |= DMA_MASTER | DMA_BLITTER;
write_log ("forcing blitter finish\n");
// if (currprefs.blitter_cycle_exact) {
// int rounds = 10000;
// while (bltstate != BLT_done && rounds > 0) {
// memset (cycle_line, 0, maxhpos);
// decide_blitter (maxhpos);
// rounds--;
// }
// if (rounds == 0)
// write_log ("blitter froze!?\n");
// } else {
actually_do_blit ();
// }
blitter_done ();
dmacon = odmacon;
}
}
static __inline__ void blit_bltset (int con)
{
int i;
if (con & 2) {
blitdesc = bltcon1 & 2;
blt_info.blitbshift = bltcon1 >> 12;
blt_info.blitdownbshift = 16 - blt_info.blitbshift;
}
if (con & 1) {
blt_info.blitashift = bltcon0 >> 12;
blt_info.blitdownashift = 16 - blt_info.blitashift;
}
blit_ch = (bltcon0 & 0x0f00) >> 8;
blitline = bltcon1 & 1;
blitfill = !!(bltcon1 & 0x18);
if (blitline) {
blit_diag = blit_cycle_diagram_line;
} else {
if (con & 2) {
blitfc = !!(bltcon1 & 0x4);
blitife = !!(bltcon1 & 0x8);
if ((bltcon1 & 0x18) == 0x18) {
blitife = 0;
}
}
blit_diag = blitfill && blit_cycle_diagram_fill[blit_ch][0] ? blit_cycle_diagram_fill[blit_ch] : blit_cycle_diagram[blit_ch];
}
blit_dmacount = blit_dmacount2 = 0;
blit_nod = 1;
for (i = 0; i < blit_diag[0]; i++) {
int v = blit_diag[1 + blit_diag[0] + i];
if (v <= 4)
blit_dmacount++;
if (v > 0 && v < 4)
blit_dmacount2++;
if (v == 4)
blit_nod = 0;
}
if (blit_dmacount2 == 0) {
ddat1use = 0;
}
}
static void blitter_start_init(void)
{
blt_info.blitzero = 1;
preva = 0;
prevb = 0;
blit_bltset (1 | 2);
ddat1use = 0;
if (blitline) {
blinea = blt_info.bltadat;
blineb = (blt_info.bltbdat >> blt_info.blitbshift) | (blt_info.bltbdat << (16 - blt_info.blitbshift));
blitonedot = 0;
blitsing = bltcon1 & 0x2;
}
}
void do_blitter(void)
{
int cycles;
bltstate = BLT_done;
blit_firstline_cycles = blit_first_cycle = get_cycles ();
blit_last_cycle = 0;
blit_cyclecounter = 0;
blitter_start_init ();
if(currprefs.pandora_partial_blits)
{
blit_cycle_entered_wait = 0;
if(blitline)
{
blit_cycles_per_op = blit_dmacount2 + (blit_nod ? 0 : 1);
//blit_cycles_per_op = blit_diag[0];
blit_cycles_per_vsize = blit_cycles_per_op;
blit_init_cycles = 2; // HRM says nothing about how much cycles required for blitter initialisation
}
else
{
blit_cycles_per_op = blit_dmacount2 + (blit_nod ? 0 : 1);
//blit_cycles_per_op = blit_diag[0];
blit_cycles_per_vsize = blit_cycles_per_op * blt_info.hblitsize;
blit_init_cycles = 2; // HRM says nothing about how much cycles required for blitter initialisation
// Used from code below so that maybe_blit behaves same as in normal mode
blit_firstline_cycles = blit_first_cycle + (blit_diag[0] * blt_info.hblitsize) * CYCLE_UNIT;
}
blit_total_required_cycles = blit_cycles_per_vsize * blt_info.vblitsize;
blit_cyclecounter = blit_init_cycles + blit_total_required_cycles;
blit_init_cycles *= CYCLE_UNIT;
blit_vblitsize_done = 0;
}
else
{
if (blitline) {
cycles = blt_info.vblitsize;
} else {
cycles = blt_info.vblitsize * blt_info.hblitsize;
blit_firstline_cycles = blit_first_cycle + (blit_diag[0] * blt_info.hblitsize) * CYCLE_UNIT;
}
blit_cyclecounter = cycles * (blit_dmacount2 + (blit_nod ? 0 : 1));
}
bltstate = BLT_init;
// blitter_slowdown doesn't work at the moment
// blit_slowdown = 0;
if (dmaen(DMA_BLITPRI))
set_special (&regs, SPCFLAG_BLTNASTY);
else
unset_special (&regs, SPCFLAG_BLTNASTY);
if(!dmaen (DMA_BLITTER))
return;
bltstate = BLT_work;
if (blitline && blt_info.hblitsize != 2) {
blitter_done ();
return;
}
if (currprefs.immediate_blits) {
blitter_doit ();
return;
}
if(currprefs.pandora_partial_blits)
{
blit_cycle_at_start = get_cycles();
blit_cycle_current = blit_cycle_at_start;
}
eventtab[ev_blitter].active = 1;
eventtab[ev_blitter].oldcycles = get_cycles ();
eventtab[ev_blitter].evtime = blit_cyclecounter * CYCLE_UNIT + get_cycles ();
events_schedule();
}
void blitter_dma_disabled(void)
{
if(bltstate != BLT_work || !currprefs.pandora_partial_blits)
return;
// execute blitter till current cycle
blitter_do_partial(0);
if(bltstate == BLT_work)
{
// We still have something to do...
bltstate = BLT_waitDMA;
blit_cycle_entered_wait = get_cycles();
eventtab[ev_blitter].active = 0;
events_schedule();
}
}
void blitter_dma_enabled(void)
{
if(bltstate != BLT_waitDMA || !currprefs.pandora_partial_blits)
return;
bltstate = BLT_work;
// Add cycles we waited to current cycles...
unsigned long cycles_waited = get_cycles() - blit_cycle_entered_wait;
blit_cycle_current += cycles_waited;
eventtab[ev_blitter].active = 1;
eventtab[ev_blitter].evtime += cycles_waited;
events_schedule();
blit_cycle_entered_wait = 0;
}
void blitter_do_partial(int do_all)
{
if(bltstate != BLT_work && bltstate != BLT_waitDMA)
return;
if (!dmaen (DMA_BLITTER) && !do_all)
return;
unsigned long curr_cpu_cycles = get_cycles();
if((curr_cpu_cycles < blit_cycle_current + blit_init_cycles) && !do_all)
return; // Blitter not finished with initialisation
if(blit_init_cycles > 0)
{
blit_cycle_current += blit_init_cycles;
blit_init_cycles = 0;
}
int num_lines = 0;
while(curr_cpu_cycles > blit_cycle_current || do_all)
{
num_lines++;
blit_cycle_current += blit_cycles_per_vsize * CYCLE_UNIT;
if(num_lines + blit_vblitsize_done >= blt_info.vblitsize)
break;
}
if(num_lines > 0)
{
int tmp_vblitsize = blt_info.vblitsize;
blt_info.vblitsize = num_lines;
actually_do_blit();
blt_info.vblitsize = tmp_vblitsize;
blit_vblitsize_done += num_lines;
if(blit_vblitsize_done >= blt_info.vblitsize)
{
if(blitline)
bltdpt = bltcpt;
blitter_done();
}
else
bltstate = BLT_work; // still not finished
}
}
// Called only from custom.cpp if blitter DMA is now enabled
void blitter_check_start (void)
{
if (bltstate != BLT_init)
return;
// do the same as in do_blitter after dmaen check
bltstate = BLT_work;
if (blitline && blt_info.hblitsize != 2) {
blitter_done ();
return;
}
if (currprefs.immediate_blits) {
blitter_doit ();
return;
}
if(currprefs.pandora_partial_blits)
{
blit_cycle_at_start = get_cycles();
blit_cycle_current = blit_cycle_at_start;
}
eventtab[ev_blitter].active = 1;
eventtab[ev_blitter].oldcycles = get_cycles ();
eventtab[ev_blitter].evtime = blit_cyclecounter * CYCLE_UNIT + get_cycles ();
events_schedule();
}
void maybe_blit (int hack)
{
if (bltstate == BLT_done)
return;
if (savestate_state)
return;
if (hack && get_cycles() < blit_firstline_cycles)
return;
blitter_handler ();
}
int blitnasty (void)
{
int cycles, ccnt;
if (bltstate == BLT_done)
return 0;
if (!dmaen (DMA_BLITTER))
return 0;
if (blit_last_cycle >= blit_diag[0] && blit_dmacount == blit_diag[0])
return 0;
cycles = (get_cycles () - blit_first_cycle) / CYCLE_UNIT;
ccnt = 0;
while (blit_last_cycle < cycles) {
int c;
if (blit_last_cycle < blit_diag[0])
c = blit_diag[1 + blit_last_cycle];
else
c = blit_diag[1 + blit_diag[0] + ((blit_last_cycle - blit_diag[0]) % blit_diag[0])];
blit_last_cycle++;
if (!c)
ccnt++;
}
return ccnt;
}
// blitter_slowdown doesn't work at the moment (causes gfx glitches in Shadow of the Beast)
/* very approximate emulation of blitter slowdown caused by bitplane DMA */
/*
void blitter_slowdown (int ddfstrt, int ddfstop, int totalcycles, int freecycles)
{
}
*/
#ifdef SAVESTATE
uae_u8 *restore_blitter (uae_u8 *src)
{
uae_u32 flags = restore_u32();
bltstate = (flags & 1) ? BLT_init : BLT_done;
return src;
}
void restore_blitter_finish(void)
{
if (bltstate == BLT_init) {
write_log ("blitter was started but DMA was inactive during save\n");
do_blitter ();
}
}
uae_u8 *save_blitter (int *len, uae_u8 *dstptr)
{
uae_u8 *dstbak,*dst;
int forced;
forced = 0;
if (bltstate != BLT_done && bltstate != BLT_init) {
write_log ("blitter is active, forcing immediate finish\n");
/* blitter is active just now but we don't have blitter state support yet */
blitter_force_finish ();
forced = 2;
}
if (dstptr)
dstbak = dst = dstptr;
else
dstbak = dst = (uae_u8 *)malloc (16);
save_u32(((bltstate != BLT_done) ? 0 : 1) | forced);
*len = dst - dstbak;
return dstbak;
}
#endif /* SAVESTATE */