Annotation of uae/custom.c, revision 1.1.1.1

1.1       root        1:  /* 
                      2:   * UAE - The Un*x Amiga Emulator
                      3:   * 
                      4:   * Custom chip emulation
                      5:   * 
                      6:   * (c) 1995 Bernd Schmidt, Alessandro Bissacco
                      7:   */
                      8: 
                      9: #include <ctype.h>
                     10: #ifdef __unix
                     11: #include <sys/time.h>
                     12: #include <unistd.h>
                     13: #endif
                     14: #include <stdio.h>
                     15: #include <string.h>
                     16: #include <stdlib.h>
                     17: #include <assert.h>
                     18: 
                     19: #include "config.h"
                     20: #include "amiga.h"
                     21: #include "options.h"
                     22: #include "events.h"
                     23: #include "memory.h"
                     24: #include "custom.h"
                     25: #include "cia.h"
                     26: #include "disk.h"
                     27: #include "blit.h"
                     28: #include "xwin.h"
                     29: #include "os.h"
                     30: 
                     31: #define DMA_AUD0      0x0001
                     32: #define DMA_AUD1      0x0002
                     33: #define DMA_AUD2      0x0004
                     34: #define DMA_AUD3      0x0008
                     35: #define DMA_DISK      0x0010
                     36: #define DMA_SPRITE    0x0020
                     37: #define DMA_BLITTER   0x0040
                     38: #define DMA_COPPER    0x0080
                     39: #define DMA_BITPLANE  0x0100
                     40: #define DMA_BLITPRI   0x0400
                     41: 
                     42: /* These are default values for mouse emulation.
                     43:  * The first two are default values for mstepx and mstepy.
                     44:  * The second line set the orizontal and vertical offset for amiga and X 
                     45:  * pointer matching
                     46:  */
                     47:    
                     48: #define defstepx (1<<16)
                     49: #define defstepy (1<<16)
                     50: #ifndef __mac__
                     51: #define defxoffs 0
                     52: #define defyoffs 0
                     53: #else
                     54: #define defxoffs 210
                     55: #define defyoffs 85
                     56: #endif
                     57: 
                     58: /* Values below define mouse auto calibration process.
                     59:  * They are not critical, change them if you want.
                     60:  * The most important is calweight, which sets mouse adjustement rate */ 
                     61: 
                     62: static const int docal = 60, xcaloff = 40, ycaloff = 20;
                     63: static const int calweight = 3;
                     64: 
                     65: static int lastsampledmx, lastsampledmy;
                     66: 
                     67:  /*
                     68:   * Events
                     69:   */
                     70: 
                     71: unsigned long int cycles, nextevent, nextev_count, specialflags;
                     72: int vpos;
                     73: UWORD lof;
                     74: 
                     75: struct ev eventtab[ev_max];
                     76: 
                     77: bool copper_active;
                     78: 
                     79: static const int maxhpos = 227,maxvpos = 312;
                     80: static const int dskdelay = 2; /* FIXME: ??? */
                     81: static const int minfirstline = 29;
                     82: 
                     83:  /* 
                     84:   * hardware register values that are visible/can be written to by someone
                     85:   */
                     86: 
                     87: static UWORD cregs[256];
                     88: 
                     89: static UWORD dmacon,intena,intreq,adkcon;
                     90: 
                     91: static ULONG cop1lc,cop2lc,copcon;
                     92: 
                     93: static CPTR  bpl1pt,bpl2pt,bpl3pt,bpl4pt,bpl5pt,bpl6pt;
                     94: static ULONG bpl1dat,bpl2dat,bpl3dat,bpl4dat,bpl5dat,bpl6dat;
                     95: static UWORD bplcon0,bplcon1,bplcon2,bplcon3;
                     96: static UWORD diwstrt,diwstop,ddfstrt,ddfstop;
                     97: static WORD  bpl1mod,bpl2mod;
                     98: 
                     99: static UWORD sprdata[8], sprdatb[8], sprctl[8], sprpos[8];
                    100: static ULONG sprpt[8];
                    101: static bool sprarmed[8], sprptset[8];
                    102: /* Kludge. FIXME: How does sprite restart after vsync work? */
                    103: static int spron[8]; 
                    104: 
                    105: static UWORD bltadat,bltbdat,bltcdat,bltddat,bltafwm,bltalwm,bltsize;
                    106: static WORD  bltamod,bltbmod,bltcmod,bltdmod;
                    107: static UWORD bltcon0,bltcon1;
                    108: static ULONG bltapt,bltbpt,bltcpt,bltdpt,bltcnxlpt,bltdnxlpt;
                    109: 
                    110: static ULONG dskpt;
                    111: static UWORD dsklen,dsksync;
                    112: 
                    113: static int joy0x, joy1x, joy0y, joy1y;
                    114: static int lastspr0x,lastspr0y,lastdiffx,lastdiffy,spr0pos,spr0ctl;
                    115: static int mstepx,mstepy,xoffs=defxoffs,yoffs=defyoffs;
                    116: static int sprvbfl;
                    117: 
                    118: static enum { normal_mouse, dont_care_mouse, follow_mouse} mousestate;
                    119: 
                    120: xcolnr acolors[64];
                    121: UWORD color_regs[32];
                    122: 
                    123:  /*
                    124:   * "hidden" hardware registers
                    125:   */
                    126: 
                    127: static int dblpf_ind1[64], dblpf_ind2[64];
                    128: 
                    129: static ULONG coplc;
                    130: static UWORD copi1,copi2;
                    131: 
                    132: static enum {
                    133:     COP_stop, COP_read, COP_wait, COP_move, COP_skip
                    134: } copstate;
                    135: 
                    136: static UWORD vblitsize,hblitsize,blitpreva,blitprevb;
                    137: static UWORD blitlpos,blitashift,blitbshift,blinea,blineb;
                    138: static bool blitline,blitfc,blitzero,blitfill,blitife,blitdesc,blitsing;
                    139: static bool blitonedot,blitsign;
                    140: static long int bltwait;
                    141: 
                    142: static int dsklength;
                    143: 
                    144: static enum {
                    145:     BLT_done, BLT_init, BLT_read, BLT_work, BLT_write, BLT_next
                    146: } bltstate;
                    147: 
                    148: static int plffirstline,plflastline,plfstrt,plfstop,plflinelen;
                    149: static int diwfirstword,diwlastword;
                    150: static int plf1pri, plf2pri;
                    151: 
                    152: int dskdmaen; /* used in cia.c */
                    153: static UWORD dskmfm,dskbyte,dsktime;
                    154: static bool dsksynced;
                    155: 
                    156: static int bpldelay1;
                    157: static int bpldelay2;
                    158: static bool bplhires;
                    159: static int bplplanecnt;
                    160: 
                    161: static bool pfield_fullline,pfield_linedone;
                    162: static bool pfield_linedmaon;
                    163: static int pfield_lastpart_hpos;
                    164: 
                    165: unsigned char apixels[1000]; /* includes a lot of safety padding */
                    166: char spixels[1000]; /* for sprites */
                    167: char spixstate[1000]; /* more sprites */
                    168: 
                    169:  /*
                    170:   * Statistics
                    171:   */
                    172: 
                    173: static unsigned long int msecs = 0, frametime = 0, timeframes = 0;
                    174: static unsigned long int seconds_base;
                    175: bool bogusframe;
                    176: 
                    177:  /*
                    178:   * helper functions
                    179:   */
                    180: 
                    181: static void pfield_doline_slow(int);
                    182: static void pfield_doline(void);
                    183: static void pfield_hsync(int);
                    184: 
                    185: bool inhibit_frame;
                    186: static int framecnt = 0;
                    187: 
                    188: static __inline__ void count_frame(void)
                    189: {
                    190:     if (inhibit_frame) 
                    191:        framecnt = 1;
                    192:     else {     
                    193:        framecnt++;
                    194:        if (framecnt == framerate)
                    195:            framecnt = 0;
                    196:     }
                    197: }
                    198: 
                    199: static __inline__ void setclr(UWORD *p, UWORD val)
                    200: {
                    201:     if (val & 0x8000) {
                    202:        *p |= val & 0x7FFF;
                    203:     } else {
                    204:        *p &= ~val;
                    205:     }
                    206: }
                    207: 
                    208: bool dmaen(UWORD dmamask)
                    209: {
                    210:     return (dmamask & dmacon) && (dmacon & 0x200);
                    211: }
                    212: 
                    213: static __inline__ int current_hpos(void)
                    214: {
                    215:     return cycles - eventtab[ev_hsync].oldcycles;
                    216: }
                    217: 
                    218: static void calcdiw(void)
                    219: {
                    220:     diwfirstword = (diwstrt & 0xFF) * 2 - 0x60;
                    221:     diwlastword  = (diwstop & 0xFF) * 2 + 0x200 - 0x60;
                    222:     if (diwfirstword < 0) diwfirstword = 0;
                    223: 
                    224:     plffirstline = diwstrt >> 8;
                    225:     plflastline = diwstop >> 8;
                    226: #if 0
                    227:     /* This happens far too often. */
                    228:     if (plffirstline < minfirstline) {
                    229:        fprintf(stderr, "Warning: Playfield begins before line %d!\n", minfirstline);
                    230:        plffirstline = minfirstline;
                    231:     }
                    232: #endif
                    233:     if ((plflastline & 0x80) == 0) plflastline |= 0x100;
                    234: #if 0 /* Turrican does this */
                    235:     if (plflastline > 313) {
                    236:        fprintf(stderr, "Warning: Playfield out of range!\n");
                    237:        plflastline = 313;
                    238:     }
                    239: #endif
                    240:     plfstrt = ddfstrt;
                    241:     plfstop = ddfstop;
                    242:     if (plfstrt < 0x18) plfstrt = 0x18;
                    243:     if (plfstop > 0xD8) plfstop = 0xD8;
                    244:     if (plfstrt > plfstop) plfstrt = plfstop;
                    245:     
                    246:     /* 
                    247:      * Prize question: What are the next lines supposed to be?
                    248:      * I can't seem to get it right.
                    249:      */
                    250: #if 0
                    251:     /* Pretty good guess, but wrong. */
                    252:     plflinelen = (plfstop-plfstrt+15) & ~7;
                    253:     plfstrt &= ~(bplhires ? 3 : 7);
                    254:     plfstop &= ~(bplhires ? 3 : 7);
                    255: #endif
                    256:     plfstrt &= ~(bplhires ? 3 : 3);
                    257:     plfstop &= ~(bplhires ? 3 : 3);
                    258:     plflinelen = (plfstop-plfstrt+15) & ~7;
                    259: }
                    260: 
                    261: static void pfield_may_need_update(bool colreg)
                    262: {
                    263:     int i;
                    264:     
                    265:     /* Ignore, if this happened before or after the DDF window */
                    266:     if (framecnt != 0 || !pfield_linedmaon || current_hpos() <= plfstrt
                    267:        || vpos < plffirstline || vpos >= plflastline)
                    268:     {  
                    269:        return;
                    270:     }
                    271:     /* 
                    272:      * If a color reg was modified, it is only important if we are within
                    273:      * the DIW.
                    274:      */
                    275:     if (current_hpos() <= (diwfirstword+0x60)/4 && colreg)
                    276:        return;
                    277: 
                    278:     /*
                    279:      * If we are past the DDF window, me might as well draw the complete
                    280:      * line now.
                    281:      */
                    282:     if (current_hpos() > plfstrt + plflinelen && pfield_fullline) {
                    283:        if (!pfield_linedone)
                    284:            pfield_doline();
                    285:        pfield_linedone = true;
                    286:        return;
                    287:     }
                    288:        
                    289:     if (pfield_fullline) {
                    290:        pfield_lastpart_hpos = 0;
                    291:        memset(apixels, 0, sizeof(apixels));
                    292:        pfield_fullline = false;
                    293:     } else {   
                    294:        assert(pfield_lastpart_hpos <= current_hpos());
                    295:     }
                    296:     for (i = pfield_lastpart_hpos; i < current_hpos(); i++) {
                    297:        pfield_doline_slow(i);
                    298:     }
                    299:     pfield_lastpart_hpos = current_hpos();
                    300: }
                    301: 
                    302: /* Apparently, the DMA bit is tested by the hardware at some point,
                    303:  * presumably at the ddfstart position, to determine whether it
                    304:  * ought to draw the line.
                    305:  * This is probably not completely correct, but should not matter
                    306:  * very much.
                    307:  */
                    308: static void pfield_calclinedma(void)
                    309: {
                    310:     if (current_hpos() >= plfstrt)
                    311:        return;
                    312:     
                    313:     pfield_linedmaon = dmaen(DMA_BITPLANE);
                    314: }
                    315: 
                    316:  /* 
                    317:   * register functions
                    318:   */
                    319: 
                    320: static UWORD DMACONR(void)
                    321: {
                    322:     return (dmacon | (bltstate==BLT_done ? 0 : 0x4000)
                    323:            | (blitzero ? 0x2000 : 0));
                    324: }
                    325: static UWORD INTENAR(void) { return intena; }
                    326: static UWORD INTREQR(void) { return intreq; }
                    327: static UWORD ADKCONR(void) { return adkcon; }
                    328: static UWORD VPOSR(void) { return (vpos >> 8) | lof; }
                    329: static void  VPOSW(UWORD v)  { lof = v & 0x8000; }
                    330: static UWORD VHPOSR(void) { return (vpos << 8) | current_hpos(); } 
                    331: 
                    332: static void  COP1LCH(UWORD v) { cop1lc= (cop1lc & 0xffff) | ((ULONG)v << 16); }
                    333: static void  COP1LCL(UWORD v) { cop1lc= (cop1lc & ~0xffff) | v; }
                    334: static void  COP2LCH(UWORD v) { cop2lc= (cop2lc & 0xffff) | ((ULONG)v << 16); }
                    335: static void  COP2LCL(UWORD v) { cop2lc= (cop2lc & ~0xffff) | v; }
                    336: 
                    337: static void  COPJMP1(UWORD a)
                    338: {
                    339:     coplc = cop1lc; copstate = COP_read; 
                    340:     eventtab[ev_copper].active = 1; eventtab[ev_copper].oldcycles = cycles;
                    341:     eventtab[ev_copper].evtime = 4; events_schedule();
                    342:     copper_active = true;
                    343: }
                    344: static void  COPJMP2(UWORD a)
                    345: {
                    346:     coplc = cop2lc; copstate = COP_read; 
                    347:     eventtab[ev_copper].active = 1; eventtab[ev_copper].oldcycles = cycles;
                    348:     eventtab[ev_copper].evtime = 4; events_schedule();
                    349:     copper_active = true;
                    350: }
                    351: 
                    352: static void  DMACON(UWORD v) 
                    353: {
                    354:     UWORD oldcon = dmacon;
                    355:     setclr(&dmacon,v); dmacon &= 0x1FFF;
                    356:     pfield_calclinedma();
                    357:     
                    358:     if ((dmacon & DMA_COPPER) > (oldcon & DMA_COPPER)) { 
                    359:        COPJMP1(0); /* @@@ not sure how this works */
                    360:     }
                    361:     if (copper_active && !eventtab[ev_copper].active) {
                    362:        eventtab[ev_copper].active = true;
                    363:        eventtab[ev_copper].oldcycles = cycles;
                    364:        eventtab[ev_copper].evtime = 1;
                    365:        events_schedule();
                    366:     }
                    367: }
                    368: static void  INTENA(UWORD v) { setclr(&intena,v); specialflags |= SPCFLAG_INT; }
                    369: static void  INTREQ(UWORD v) { setclr(&intreq,v); specialflags |= SPCFLAG_INT; }
                    370: static void  ADKCON(UWORD v) { setclr(&adkcon,v); }
                    371: 
                    372: static void  BPL1PTH(UWORD v) { bpl1pt= (bpl1pt & 0xffff) | ((ULONG)v << 16); }
                    373: static void  BPL1PTL(UWORD v) { bpl1pt= (bpl1pt & ~0xffff) | v; }
                    374: static void  BPL2PTH(UWORD v) { bpl2pt= (bpl2pt & 0xffff) | ((ULONG)v << 16); }
                    375: static void  BPL2PTL(UWORD v) { bpl2pt= (bpl2pt & ~0xffff) | v; }
                    376: static void  BPL3PTH(UWORD v) { bpl3pt= (bpl3pt & 0xffff) | ((ULONG)v << 16); }
                    377: static void  BPL3PTL(UWORD v) { bpl3pt= (bpl3pt & ~0xffff) | v; }
                    378: static void  BPL4PTH(UWORD v) { bpl4pt= (bpl4pt & 0xffff) | ((ULONG)v << 16); }
                    379: static void  BPL4PTL(UWORD v) { bpl4pt= (bpl4pt & ~0xffff) | v; }
                    380: static void  BPL5PTH(UWORD v) { bpl5pt= (bpl5pt & 0xffff) | ((ULONG)v << 16); }
                    381: static void  BPL5PTL(UWORD v) { bpl5pt= (bpl5pt & ~0xffff) | v; }
                    382: static void  BPL6PTH(UWORD v) { bpl6pt= (bpl6pt & 0xffff) | ((ULONG)v << 16); }
                    383: static void  BPL6PTL(UWORD v) { bpl6pt= (bpl6pt & ~0xffff) | v; }
                    384: 
                    385: /*
                    386:  * I've seen the listing of an example program that changes 
                    387:  * from lo- to hires while a line is being drawn. That's
                    388:  * awful, but we want to emulate it.
                    389:  */
                    390: static void  BPLCON0(UWORD v) 
                    391: {
                    392:     pfield_may_need_update(false);
                    393:     bplcon0 = v;
                    394:     bplhires = (bplcon0 & 0x8000) == 0x8000; 
                    395:     bplplanecnt = (bplcon0 & 0x7000) >> 12; 
                    396:     calcdiw(); /* This should go away. */
                    397: }
                    398: static void  BPLCON1(UWORD v) 
                    399: {
                    400:     pfield_may_need_update(false);
                    401:     bplcon1 = v; 
                    402:     bpldelay1 = bplcon1 & 0xF; 
                    403:     bpldelay2 = (bplcon1 >> 4) & 0xF; 
                    404: }
                    405: static void  BPLCON2(UWORD v) 
                    406: {
                    407:     pfield_may_need_update(false); 
                    408:     bplcon2 = v;
                    409:     plf1pri = 1 << 2*(v & 7);
                    410:     plf2pri = 1 << 2*((v>>3) & 7);
                    411: }
                    412: static void  BPLCON3(UWORD v) { pfield_may_need_update(false); bplcon3 = v; }
                    413: 
                    414: static void  BPL1MOD(UWORD v) { pfield_may_need_update(false); bpl1mod = v; }
                    415: static void  BPL2MOD(UWORD v) { pfield_may_need_update(false); bpl2mod = v; }
                    416: 
                    417: static void  BPL1DAT(UWORD v) { bpl1dat = v; }
                    418: static void  BPL2DAT(UWORD v) { bpl2dat = v; }
                    419: static void  BPL3DAT(UWORD v) { bpl3dat = v; }
                    420: static void  BPL4DAT(UWORD v) { bpl4dat = v; }
                    421: static void  BPL5DAT(UWORD v) { bpl5dat = v; }
                    422: static void  BPL6DAT(UWORD v) { bpl6dat = v; }
                    423: 
                    424: /* We call pfield_may_need_update() from here. Actually, 
                    425:  * I have no idea what happens if someone changes ddf or
                    426:  * diw mid-line, and I don't really want to know. I doubt
                    427:  * that this sort of thing was ever used to create a
                    428:  * useful effect.
                    429:  */
                    430: static void  DIWSTRT(UWORD v) { pfield_may_need_update(false); diwstrt = v; calcdiw(); }
                    431: static void  DIWSTOP(UWORD v) { pfield_may_need_update(false); diwstop = v; calcdiw(); }
                    432: static void  DDFSTRT(UWORD v) { pfield_may_need_update(false); ddfstrt = v; calcdiw(); }
                    433: static void  DDFSTOP(UWORD v) { pfield_may_need_update(false); ddfstop = v; calcdiw(); }
                    434: 
                    435: static void  BLTADAT(UWORD v) { bltadat = v; }
                    436: static void  BLTBDAT(UWORD v) { bltbdat = v; }
                    437: static void  BLTCDAT(UWORD v) { bltcdat = v; }
                    438: 
                    439: static void  BLTAMOD(UWORD v) { bltamod = v; }
                    440: static void  BLTBMOD(UWORD v) { bltbmod = v; }
                    441: static void  BLTCMOD(UWORD v) { bltcmod = v; }
                    442: static void  BLTDMOD(UWORD v) { bltdmod = v; }
                    443: 
                    444: static void  BLTCON0(UWORD v) { bltcon0 = v; }
                    445: static void  BLTCON1(UWORD v) { bltcon1 = v; }
                    446: 
                    447: static void  BLTAFWM(UWORD v) { bltafwm = v; }
                    448: static void  BLTALWM(UWORD v) { bltalwm = v; }
                    449: 
                    450: static void  BLTAPTH(UWORD v) { bltapt= (bltapt & 0xffff) | ((ULONG)v << 16); }
                    451: static void  BLTAPTL(UWORD v) { bltapt= (bltapt & ~0xffff) | (v); }
                    452: static void  BLTBPTH(UWORD v) { bltbpt= (bltbpt & 0xffff) | ((ULONG)v << 16); }
                    453: static void  BLTBPTL(UWORD v) { bltbpt= (bltbpt & ~0xffff) | (v); }
                    454: static void  BLTCPTH(UWORD v) { bltcpt= (bltcpt & 0xffff) | ((ULONG)v << 16); }
                    455: static void  BLTCPTL(UWORD v) { bltcpt= (bltcpt & ~0xffff) | (v); }
                    456: static void  BLTDPTH(UWORD v) { bltdpt= (bltdpt & 0xffff) | ((ULONG)v << 16); }
                    457: static void  BLTDPTL(UWORD v) { bltdpt= (bltdpt & ~0xffff) | (v); }
                    458: static void  BLTSIZE(UWORD v) { bltsize = v; bltstate = BLT_init; specialflags |= SPCFLAG_BLIT; }
                    459: 
                    460: static void  SPRxCTL(UWORD v, int num) { pfield_may_need_update(false); sprctl[num] = v; sprarmed[num] = false; spron[num] |= 2; }
                    461: static void  SPRxPOS(UWORD v, int num) { pfield_may_need_update(false); sprpos[num] = v; }
                    462: static void  SPRxDATA(UWORD v, int num) { pfield_may_need_update(false); sprdata[num] = v; sprarmed[num] = true; }
                    463: static void  SPRxDATB(UWORD v, int num) { pfield_may_need_update(false); sprdatb[num] = v; }
                    464: static void  SPRxPTH(UWORD v, int num) { sprpt[num] &= 0xffff; sprpt[num] |= (ULONG)v << 16; spron[num] |= 1; }
                    465: static void  SPRxPTL(UWORD v, int num) { sprpt[num] &= ~0xffff; sprpt[num] |= v; spron[num] |= 1; }
                    466: 
                    467: static void  COLOR(UWORD v, int num)
                    468: {
                    469:     pfield_may_need_update(true);
                    470:     color_regs[num] = v;
                    471:     acolors[num] = xcolors[v];
                    472:     acolors[num+32] = xcolors[(v >> 1) & 0x777];
                    473: }
                    474: 
                    475: static void  DSKSYNC(UWORD v) { dsksync = v; }
                    476: static void  DSKDAT(UWORD v) { dskmfm = v; }
                    477: static void  DSKPTH(UWORD v) { dskpt = (dskpt & 0xffff) | ((ULONG)v << 16); }
                    478: static void  DSKPTL(UWORD v) { dskpt = (dskpt & ~0xffff) | (v); }
                    479: 
                    480: static void  DSKLEN(UWORD v) 
                    481: {
                    482:     if (v & 0x8000) { dskdmaen++; } else { dskdmaen = 0; }
                    483:     dsktime = dskdelay; dsksynced = false;
                    484:     dsklen = dsklength = v; dsklength &= 0x3fff;
                    485:     if (dskdmaen == 2 && dsksync != 0x4489 && (adkcon & 0x400)) {
                    486:        printf("Non-standard sync: %04x len: %x\n", dsksync, dsklength);
                    487:     }
                    488:     if (dsklen & 0x4000) DISK_InitWrite();
                    489:     if (dskdmaen) specialflags |= SPCFLAG_DISK;
                    490: }
                    491: 
                    492: static UWORD DSKBYTR(void)
                    493: {
                    494:     UWORD v = (dsklen >> 1) & 0x6000;
                    495:     v |= dskbyte;
                    496:     dskbyte &= ~0x8000;
                    497:     if (dsksync == dskmfm) v |= 0x1000;
                    498:     return v;
                    499: }
                    500: 
                    501: static UWORD DSKDATR(void) { return dskmfm; }
                    502: static UWORD POTGOR(void)
                    503: {
                    504:     if (!buttonstate[2]) {     
                    505:        return 0xffff;
                    506:     } else {
                    507:        return 0xbbff;
                    508:     }
                    509: }
                    510: 
                    511: static UWORD JOY0DAT(void) { return joy0x + (joy0y << 8); }
                    512: static UWORD JOY1DAT(void)
                    513: {
                    514: #ifdef HAVE_JOYSTICK
                    515:     UWORD dir;
                    516:     bool button;
                    517:     read_joystick(&dir, &button);
                    518:     buttonstate[1] = button;
                    519:     return dir;
                    520: #else
                    521:     return joy1x + (joy1y << 8);
                    522: #endif
                    523: }
                    524: static void JOYTEST(UWORD v)
                    525: {
                    526:     joy0x = joy1x = v & 0xFC;
                    527:     joy0y = joy1y = (v >> 8) & 0xFC;    
                    528: }
                    529: static void AUD0LCH(UWORD v) { audlc[0] = (audlc[0] & 0xffff) | ((ULONG)v << 16); }
                    530: static void AUD0LCL(UWORD v) { audlc[0] = (audlc[0] & ~0xffff) | v; }
                    531: static void AUD1LCH(UWORD v) { audlc[1] = (audlc[1] & 0xffff) | ((ULONG)v << 16); }
                    532: static void AUD1LCL(UWORD v) { audlc[1] = (audlc[1] & ~0xffff) | v; }
                    533: static void AUD2LCH(UWORD v) { audlc[2] = (audlc[2] & 0xffff) | ((ULONG)v << 16); }
                    534: static void AUD2LCL(UWORD v) { audlc[2] = (audlc[2] & ~0xffff) | v; }
                    535: static void AUD3LCH(UWORD v) { audlc[3] = (audlc[3] & 0xffff) | ((ULONG)v << 16); }
                    536: static void AUD3LCL(UWORD v) { audlc[3] = (audlc[3] & ~0xffff) | v; }
                    537: static void AUD0PER(UWORD v) { audper[0] = v; }
                    538: static void AUD1PER(UWORD v) { audper[1] = v; }
                    539: static void AUD2PER(UWORD v) { audper[2] = v; }
                    540: static void AUD3PER(UWORD v) { audper[3] = v; }
                    541: static void AUD0VOL(UWORD v) { audvol[0] = v; }
                    542: static void AUD1VOL(UWORD v) { audvol[1] = v; }
                    543: static void AUD2VOL(UWORD v) { audvol[2] = v; }
                    544: static void AUD3VOL(UWORD v) { audvol[3] = v; }
                    545: static void AUD0LEN(UWORD v) { audlen[0] = v; }
                    546: static void AUD1LEN(UWORD v) { audlen[1] = v; }
                    547: static void AUD2LEN(UWORD v) { audlen[2] = v; }
                    548: static void AUD3LEN(UWORD v) { audlen[3] = v; }
                    549: 
                    550: /* Custom chip memory bank */
                    551: 
                    552: static ULONG custom_lget(CPTR) REGPARAM;
                    553: static UWORD custom_wget(CPTR) REGPARAM;
                    554: static UBYTE custom_bget(CPTR) REGPARAM;
                    555: static void  custom_lput(CPTR, ULONG) REGPARAM;
                    556: static void  custom_wput(CPTR, UWORD) REGPARAM;
                    557: static void  custom_bput(CPTR, UBYTE) REGPARAM;
                    558: 
                    559: addrbank custom_bank = {
                    560:     custom_lget, custom_wget, custom_bget,
                    561:     custom_lput, custom_wput, custom_bput,
                    562:     default_xlate, default_check
                    563: };
                    564: 
                    565: UWORD custom_wget(CPTR addr)
                    566: {
                    567: #ifdef DUALCPU
                    568:     customacc = true;
                    569: #endif
                    570:     switch(addr & 0x1FE) {
                    571:      case 0x002: return DMACONR();
                    572:      case 0x004: return VPOSR();
                    573:      case 0x006: return VHPOSR();
                    574:        
                    575:      case 0x008: return DSKDATR();
                    576:      case 0x016: return POTGOR();
                    577:      case 0x01A: return DSKBYTR();
                    578:      case 0x01C: return INTENAR();
                    579:      case 0x01E: return INTREQR();
                    580:      case 0x010: return ADKCONR();
                    581:      case 0x00A: return JOY0DAT();
                    582:      case 0x00C: return JOY1DAT();
                    583:      default:
                    584:        custom_wput(addr,0);
                    585:        return 0xffff;
                    586:     }
                    587: }
                    588: 
                    589: UBYTE custom_bget(CPTR addr)
                    590: {
                    591:     return custom_wget(addr & 0xfffe) >> (addr & 1 ? 0 : 8);
                    592: }
                    593: 
                    594: ULONG custom_lget(CPTR addr)
                    595: {
                    596:     return ((ULONG)custom_wget(addr & 0xfffe) << 16) | custom_wget((addr+2) & 0xfffe);
                    597: }
                    598: 
                    599: void custom_wput(CPTR addr, UWORD value)
                    600: {
                    601: #ifdef DUALCPU
                    602:     customacc = true;
                    603: #endif
                    604:     addr &= 0x1FE;
                    605:     cregs[addr>>1] = value;
                    606:     switch(addr) {     
                    607:      case 0x020: DSKPTH(value); break;
                    608:      case 0x022: DSKPTL(value); break;
                    609:      case 0x024: DSKLEN(value); break;
                    610:      case 0x026: DSKDAT(value); break;
                    611:        
                    612:      case 0x02A: VPOSW(value); break;
                    613:        
                    614:      case 0x040: BLTCON0(value); break;
                    615:      case 0x042: BLTCON1(value); break;
                    616:        
                    617:      case 0x044: BLTAFWM(value); break;
                    618:      case 0x046: BLTALWM(value); break;
                    619:        
                    620:      case 0x050: BLTAPTH(value); break;
                    621:      case 0x052: BLTAPTL(value); break;
                    622:      case 0x04C: BLTBPTH(value); break;
                    623:      case 0x04E: BLTBPTL(value); break;
                    624:      case 0x048: BLTCPTH(value); break;
                    625:      case 0x04A: BLTCPTL(value); break;
                    626:      case 0x054: BLTDPTH(value); break;
                    627:      case 0x056: BLTDPTL(value); break;
                    628:        
                    629:      case 0x058: BLTSIZE(value); break;
                    630:        
                    631:      case 0x064: BLTAMOD(value); break;
                    632:      case 0x062: BLTBMOD(value); break;
                    633:      case 0x060: BLTCMOD(value); break;
                    634:      case 0x066: BLTDMOD(value); break;
                    635:        
                    636:      case 0x070: BLTCDAT(value); break;
                    637:      case 0x072: BLTBDAT(value); break;
                    638:      case 0x074: BLTADAT(value); break;
                    639:                        
                    640:      case 0x07E: DSKSYNC(value); break;
                    641: 
                    642:      case 0x080: COP1LCH(value); break;
                    643:      case 0x082: COP1LCL(value); break;
                    644:      case 0x084: COP2LCH(value); break;
                    645:      case 0x086: COP2LCL(value); break;
                    646:        
                    647:      case 0x088: COPJMP1(value); break;
                    648:      case 0x08A: COPJMP2(value); break;
                    649:        
                    650:      case 0x08E: DIWSTRT(value); break;
                    651:      case 0x090: DIWSTOP(value); break;
                    652:      case 0x092: DDFSTRT(value); break;
                    653:      case 0x094: DDFSTOP(value); break;
                    654:        
                    655:      case 0x096: DMACON(value); break;
                    656:      case 0x09A: INTENA(value); break;
                    657:      case 0x09C: INTREQ(value); break;
                    658:      case 0x09E: ADKCON(value); break;
                    659:        
                    660:      case 0x0A0: AUD0LCH(value); break;
                    661:      case 0x0A2: AUD0LCL(value); break;
                    662:      case 0x0A4: AUD0LEN(value); break;
                    663:      case 0x0A6: AUD0PER(value); break;
                    664:      case 0x0A8: AUD0VOL(value); break;
                    665:        
                    666:      case 0x0B0: AUD1LCH(value); break;
                    667:      case 0x0B2: AUD1LCL(value); break;
                    668:      case 0x0B4: AUD1LEN(value); break;
                    669:      case 0x0B6: AUD1PER(value); break;
                    670:      case 0x0B8: AUD1VOL(value); break;
                    671:        
                    672:      case 0x0C0: AUD2LCH(value); break;
                    673:      case 0x0C2: AUD2LCL(value); break;
                    674:      case 0x0C4: AUD2LEN(value); break;
                    675:      case 0x0C6: AUD2PER(value); break;
                    676:      case 0x0C8: AUD2VOL(value); break;
                    677:        
                    678:      case 0x0D0: AUD3LCH(value); break;
                    679:      case 0x0D2: AUD3LCL(value); break;
                    680:      case 0x0D4: AUD3LEN(value); break;
                    681:      case 0x0D6: AUD3PER(value); break;
                    682:      case 0x0D8: AUD3VOL(value); break;
                    683:        
                    684:      case 0x0E0: BPL1PTH(value); break;
                    685:      case 0x0E2: BPL1PTL(value); break;
                    686:      case 0x0E4: BPL2PTH(value); break;
                    687:      case 0x0E6: BPL2PTL(value); break;
                    688:      case 0x0E8: BPL3PTH(value); break;
                    689:      case 0x0EA: BPL3PTL(value); break;
                    690:      case 0x0EC: BPL4PTH(value); break;
                    691:      case 0x0EE: BPL4PTL(value); break;
                    692:      case 0x0F0: BPL5PTH(value); break;
                    693:      case 0x0F2: BPL5PTL(value); break;
                    694:      case 0x0F4: BPL6PTH(value); break;
                    695:      case 0x0F6: BPL6PTL(value); break;
                    696:        
                    697:      case 0x100: BPLCON0(value); break;
                    698:      case 0x102: BPLCON1(value); break;
                    699:      case 0x104: BPLCON2(value); break;
                    700:      case 0x106: BPLCON3(value); break;
                    701:        
                    702:      case 0x108: BPL1MOD(value); break;
                    703:      case 0x10A: BPL2MOD(value); break;
                    704: 
                    705:      case 0x110: BPL1DAT(value); break;
                    706:      case 0x112: BPL2DAT(value); break;
                    707:      case 0x114: BPL3DAT(value); break;
                    708:      case 0x116: BPL4DAT(value); break;
                    709:      case 0x118: BPL5DAT(value); break;
                    710:      case 0x11A: BPL6DAT(value); break;
                    711:        
                    712:      case 0x180: case 0x182: case 0x184: case 0x186: case 0x188: case 0x18A:
                    713:      case 0x18C: case 0x18E: case 0x190: case 0x192: case 0x194: case 0x196:
                    714:      case 0x198: case 0x19A: case 0x19C: case 0x19E: case 0x1A0: case 0x1A2:
                    715:      case 0x1A4: case 0x1A6: case 0x1A8: case 0x1AA: case 0x1AC: case 0x1AE:
                    716:      case 0x1B0: case 0x1B2: case 0x1B4: case 0x1B6: case 0x1B8: case 0x1BA:
                    717:      case 0x1BC: case 0x1BE: 
                    718:        COLOR(value & 0xFFF, (addr & 0x3E) / 2);
                    719:        break;  
                    720:      case 0x120: case 0x124: case 0x128: case 0x12C: 
                    721:      case 0x130: case 0x134: case 0x138: case 0x13C:
                    722:        SPRxPTH(value, (addr - 0x120) / 4);
                    723:        break;
                    724:      case 0x122: case 0x126: case 0x12A: case 0x12E: 
                    725:      case 0x132: case 0x136: case 0x13A: case 0x13E:
                    726:        SPRxPTL(value, (addr - 0x122) / 4);
                    727:        break;
                    728:      case 0x140: case 0x148: case 0x150: case 0x158: 
                    729:      case 0x160: case 0x168: case 0x170: case 0x178:
                    730:        SPRxPOS(value, (addr - 0x140) / 8);
                    731:        break;
                    732:      case 0x142: case 0x14A: case 0x152: case 0x15A: 
                    733:      case 0x162: case 0x16A: case 0x172: case 0x17A:
                    734:        SPRxCTL(value, (addr - 0x142) / 8);
                    735:        break;
                    736:      case 0x144: case 0x14C: case 0x154: case 0x15C:
                    737:      case 0x164: case 0x16C: case 0x174: case 0x17C:
                    738:        SPRxDATA(value, (addr - 0x144) / 8);
                    739:        break;
                    740:      case 0x146: case 0x14E: case 0x156: case 0x15E: 
                    741:      case 0x166: case 0x16E: case 0x176: case 0x17E:
                    742:        SPRxDATB(value, (addr - 0x146) / 8);
                    743:        break;
                    744:        
                    745:      case 0x36: JOYTEST(value); break; 
                    746:     }
                    747: }
                    748: 
                    749: void custom_bput(CPTR addr, UBYTE value)
                    750: {
                    751:     /* Yes, there are programs that do this. The programmers should be shot.
                    752:      * This might actually work sometimes. */
                    753:     UWORD rval = value;
                    754:     CPTR raddr = addr & 0x1FE;
                    755:     if (addr & 1) {
                    756:        rval |= cregs[raddr >> 1] & 0xFF00;
                    757:     } else {
                    758:        rval <<= 8;
                    759:        rval |= cregs[raddr >> 1] & 0xFF;
                    760:     }
                    761:     custom_wput(raddr, rval);
                    762: }
                    763: 
                    764: void custom_lput(CPTR addr, ULONG value)
                    765: {
                    766:     custom_wput(addr & 0xfffe, value >> 16);
                    767:     custom_wput((addr+2) & 0xfffe, (UWORD)value);
                    768: }
                    769: 
                    770: static bool copcomp(void)
                    771: {
                    772:     UWORD vp = vpos & (((copi2 >> 8) & 0x7F) | 0x80);
                    773:     UWORD hp = current_hpos() & (copi2 & 0xFE);
                    774:     UWORD vcmp = copi1 >> 8;
                    775:     UWORD hcmp = copi1 & 0xFE;
                    776:     return (vp > vcmp || (vp == vcmp && hp >= hcmp)) && ((copi2 & 0x8000) || !(DMACONR() & 0x4000));
                    777: }
                    778: 
                    779: /*
                    780:  * Calculate the minimum number of cycles after which the
                    781:  * copper comparison becomes true. This is quite tricky. I hope it works.
                    782:  */
                    783: static int calc_copcomp_true(int currvpos, int currhpos)
                    784: {    
                    785:     UWORD vp = currvpos & (((copi2 >> 8) & 0x7F) | 0x80);
                    786:     UWORD hp = currhpos & (copi2 & 0xFE);
                    787:     UWORD vcmp = copi1 >> 8;
                    788:     UWORD hcmp = copi1 & 0xFE;
                    789: 
                    790:     int cycleadd = maxhpos - currhpos;
                    791:     int coptime = 0;
                    792: 
                    793:     if ((vp > vcmp || (vp == vcmp && hp >= hcmp)) && ((copi2 & 0x8000) || !(DMACONR() & 0x4000)))
                    794:        return 0;    
                    795:     
                    796:     try_again:
                    797:     
                    798:     while (vp < vcmp) {
                    799:        currvpos++;
                    800:        if (currvpos > maxvpos + 1)
                    801:            return -1;
                    802:        currhpos = 0;
                    803:        coptime += cycleadd;
                    804:        cycleadd = maxhpos;
                    805:        vp = currvpos & (((copi2 >> 8) & 0x7F) | 0x80);
                    806:     }
                    807:     hp = currhpos & (copi2 & 0xFE);
                    808:     if (!(vp > vcmp)) {        
                    809:        while (hp < hcmp) {
                    810:            currhpos++;
                    811:            if (currhpos > maxhpos) {
                    812:                /* Now, what? There might be a good position on the
                    813:                 * next line. But it can also be the FFFF FFFE
                    814:                 * case.
                    815:                 */
                    816:                currhpos = 0;
                    817:                currvpos++;
                    818:                vp = currvpos & (((copi2 >> 8) & 0x7F) | 0x80);
                    819:                goto try_again;
                    820:            }
                    821:            coptime++;
                    822:            hp = currhpos & (copi2 & 0xFE);
                    823:        }
                    824:     }
                    825:     if (coptime == 0) /* waiting for the blitter */
                    826:        return 1;
                    827:     
                    828:     return coptime;
                    829: }
                    830: 
                    831: static void copper_read(void)
                    832: {
                    833:     if (dmaen(DMA_COPPER)){
                    834:        copi1 = chipmem_bank.wget(coplc); 
                    835:        copi2 = chipmem_bank.wget(coplc+2);
                    836:        coplc += 4;
                    837:        eventtab[ev_copper].oldcycles = cycles;
                    838:        eventtab[ev_copper].evtime = (copi1 & 1) ? (copi2 & 1) ? 4 : 6 : 4;
                    839:        copstate = (copi1 & 1) ? (copi2 & 1) ? COP_skip : COP_wait : COP_move;
                    840:     } else {
                    841:        copstate = COP_read;
                    842:        eventtab[ev_copper].active = false;
                    843:     }
                    844: }
                    845: 
                    846: static void do_copper(void)
                    847: {    
                    848:     switch(copstate){
                    849:      case COP_read:
                    850:        copper_read();
                    851:        break;
                    852:      case COP_move:
                    853:        if (copi1 >= (copcon & 2 ? 0x40 : 0x80))
                    854:            custom_bank.wput(copi1,copi2);
                    855:        copper_read();
                    856:        break;
                    857:      case COP_skip:
                    858:        if (copcomp())
                    859:            coplc += 4;
                    860:        copper_read();
                    861:        break;
                    862:      case COP_wait: {      
                    863:         int coptime = calc_copcomp_true(vpos, current_hpos());
                    864:         if (coptime < 0) {
                    865:             copstate = COP_stop;
                    866:             eventtab[ev_copper].active = false;
                    867:             copper_active = false;
                    868:         } else {            
                    869:             if (!coptime)
                    870:                 copper_read();
                    871:             else {
                    872:                 eventtab[ev_copper].evtime = coptime;
                    873:                 eventtab[ev_copper].oldcycles = cycles;
                    874:             }
                    875:         }
                    876:         break;
                    877:      }
                    878:      case COP_stop:
                    879:        eventtab[ev_copper].active = false;
                    880:        copper_active = false;
                    881:        break;
                    882:     }
                    883: }
                    884: 
                    885: static __inline__ bool blitter_read(void)
                    886: {
                    887:     if (bltcon0 & 0xe00){
                    888:        if (!dmaen(DMA_BLITTER)) return true; /* blitter stopped */
                    889:        if (!blitline){
                    890:            if (bltcon0 & 0x800) bltadat = chipmem_bank.wget(bltapt);
                    891:            if (bltcon0 & 0x400) bltbdat = chipmem_bank.wget(bltbpt);
                    892:        }
                    893:        if (bltcon0 & 0x200) bltcdat = chipmem_bank.wget(bltcpt);
                    894:     }
                    895:     bltstate = BLT_work;
                    896:     return (bltcon0 & 0xE00) != 0;
                    897: }
                    898: 
                    899: static __inline__ bool blitter_write(void)
                    900: {
                    901:     if (bltddat) blitzero = false;
                    902:     if ((bltcon0 & 0x100) || blitline){
                    903:        if (!dmaen(DMA_BLITTER)) return true;
                    904:        chipmem_bank.wput(bltdpt,bltddat);
                    905:     }
                    906:     bltstate = BLT_next;
                    907:     return (bltcon0 & 0x100) != 0;
                    908: }
                    909: 
                    910: static void blitter_blit(void)
                    911: {
                    912:     UWORD blitahold,blitbhold,blitchold;
                    913:     UWORD bltaold;
                    914:     
                    915:     if (blitdesc) {
                    916:        UWORD bltamask = 0xffff;
                    917:        
                    918:        if (!blitlpos) { bltamask &= bltafwm; }
                    919:        if (blitlpos == (hblitsize - 1)) { bltamask &= bltalwm; }
                    920:        bltaold = bltadat & bltamask;
                    921: 
                    922:        blitahold = (((ULONG)bltaold << 16) | blitpreva) >> (16-blitashift);
                    923:        blitbhold = (((ULONG)bltbdat << 16) | blitprevb) >> (16-blitbshift);
                    924:        blitchold = bltcdat;
                    925:     } else {
                    926:        UWORD bltamask = 0xffff;
                    927:        
                    928:        if (!blitlpos) { bltamask &= bltafwm; }
                    929:        if (blitlpos == (hblitsize - 1)) { bltamask &= bltalwm; }
                    930:        bltaold = bltadat & bltamask;
                    931: 
                    932:        blitahold = (((ULONG)blitpreva << 16) | bltaold) >> blitashift;
                    933:        blitbhold = (((ULONG)blitprevb << 16) | bltbdat) >> blitbshift;
                    934:        blitchold = bltcdat;
                    935:     }
                    936:     bltddat = 0;
                    937:     bltddat = blit_func(blitahold, blitbhold, blitchold, bltcon0 & 0xFF);
                    938:     if (blitfill){
                    939:        UWORD fillmask;
                    940:        for (fillmask = 1; fillmask; fillmask <<= 1){
                    941:            UWORD tmp = bltddat;
                    942:            if (blitfc) {
                    943:                if (blitife)
                    944:                    bltddat |= fillmask;
                    945:                else
                    946:                    bltddat ^= fillmask;
                    947:            }
                    948:            if (tmp & fillmask) blitfc = !blitfc;
                    949:        }
                    950:     }
                    951:     bltstate = BLT_write;
                    952:     blitpreva = bltaold; blitprevb = bltbdat;
                    953: }
                    954: 
                    955: static void blitter_nxblit(void)
                    956: {
                    957:     bltstate = BLT_read;
                    958:     if (blitdesc){
                    959:        if (++blitlpos == hblitsize) {
                    960:            if (--vblitsize == 0) {
                    961:                bltstate = BLT_done;
                    962: #ifdef NO_FAST_BLITTER
                    963:                custom_bank.wput(0xDFF09C,0x8040);
                    964: #endif
                    965:            }
                    966:            blitfc = bltcon1 & 0x4;
                    967: 
                    968:            blitlpos = 0;
                    969:            if (bltcon0 & 0x800) bltapt -= 2+bltamod; 
                    970:            if (bltcon0 & 0x400) bltbpt -= 2+bltbmod; 
                    971:            if (bltcon0 & 0x200) bltcpt -= 2+bltcmod; 
                    972:            if (bltcon0 & 0x100) bltdpt -= 2+bltdmod;
                    973:        } else {
                    974:            if (bltcon0 & 0x800) bltapt -= 2; 
                    975:            if (bltcon0 & 0x400) bltbpt -= 2; 
                    976:            if (bltcon0 & 0x200) bltcpt -= 2; 
                    977:            if (bltcon0 & 0x100) bltdpt -= 2;       
                    978:        }
                    979:     } else {
                    980:        if (++blitlpos == hblitsize) {
                    981:            if (--vblitsize == 0) { 
                    982:                bltstate = BLT_done;
                    983: #ifdef NO_FAST_BLITTER
                    984:                custom_bank.wput(0xDFF09C,0x8040);
                    985: #endif
                    986:            }
                    987:            blitlpos = 0;
                    988:            if (bltcon0 & 0x800) bltapt += 2+bltamod; 
                    989:            if (bltcon0 & 0x400) bltbpt += 2+bltbmod; 
                    990:            if (bltcon0 & 0x200) bltcpt += 2+bltcmod; 
                    991:            if (bltcon0 & 0x100) bltdpt += 2+bltdmod;
                    992:        } else {
                    993:            if (bltcon0 & 0x800) bltapt += 2; 
                    994:            if (bltcon0 & 0x400) bltbpt += 2; 
                    995:            if (bltcon0 & 0x200) bltcpt += 2; 
                    996:            if (bltcon0 & 0x100) bltdpt += 2;
                    997:        }
                    998:     }
                    999: }
                   1000: 
                   1001: static __inline__ void blitter_line_incx(int a)
                   1002: {
                   1003:     blinea >>= 1;
                   1004:     if (!blinea) {
                   1005:        blinea = 0x8000;
                   1006:        bltcnxlpt += 2;
                   1007:        bltdnxlpt += 2;
                   1008:     }
                   1009: }
                   1010: 
                   1011: static __inline__ void blitter_line_decx(int shm)
                   1012: {
                   1013:     if (shm) blineb = (blineb << 2) | (blineb >> 14);
                   1014:     blinea <<= 1;
                   1015:     if (!blinea) {
                   1016:        blinea = 1;
                   1017:        bltcnxlpt -= 2;
                   1018:        bltdnxlpt -= 2;
                   1019:     }
                   1020: }
                   1021: 
                   1022: static __inline__ void blitter_line_decy(int shm)
                   1023: {
                   1024:     if (shm) blineb = (blineb >> 1) | (blineb << 15);
                   1025:     bltcnxlpt -= bltcmod;
                   1026:     bltdnxlpt -= bltcmod; /* ??? am I wrong or doesn't KS1.3 set bltdmod? */
                   1027:     blitonedot = 0;
                   1028: }
                   1029: 
                   1030: static __inline__ void blitter_line_incy(int shm)
                   1031: {
                   1032:     if (shm) blineb = (blineb >> 1) | (blineb << 15);
                   1033:     bltcnxlpt += bltcmod;
                   1034:     bltdnxlpt += bltcmod; /* ??? */
                   1035:     blitonedot = 0;
                   1036: }
                   1037: 
                   1038: static void blitter_line(void)
                   1039: {
                   1040:     UWORD blitahold = blinea, blitbhold = blineb, blitchold = bltcdat;
                   1041:     bltddat = 0;
                   1042:     
                   1043:     if (blitsing && blitonedot) blitahold = 0;
                   1044:     blitonedot = 1;
                   1045:     bltddat = blit_func(blitahold, blitbhold, blitchold, bltcon0 & 0xFF);
                   1046:     if (!blitsign){
                   1047:        bltapt += (WORD)bltamod;
                   1048:        if (bltcon1 & 0x10){
                   1049:            if (bltcon1 & 0x8)
                   1050:                blitter_line_decy(0);
                   1051:            else
                   1052:                blitter_line_incy(0);
                   1053:        } else {
                   1054:            if (bltcon1 & 0x8)
                   1055:                blitter_line_decx(0);
                   1056:            else 
                   1057:                blitter_line_incx(0);
                   1058:        }
                   1059:     } else {
                   1060:        bltapt += (WORD)bltbmod;
                   1061:     }
                   1062:     if (bltcon1 & 0x10){
                   1063:        if (bltcon1 & 0x4)
                   1064:            blitter_line_decx(1);
                   1065:        else
                   1066:            blitter_line_incx(1);
                   1067:     } else {
                   1068:        if (bltcon1 & 0x4)
                   1069:            blitter_line_decy(1);
                   1070:        else
                   1071:            blitter_line_incy(1);
                   1072:     }
                   1073:     blitsign = 0 > (WORD)bltapt;
                   1074:     bltstate = BLT_write;
                   1075: }
                   1076: 
                   1077: static __inline__ void blitter_nxline(void)
                   1078: {
                   1079:     if (--vblitsize == 0) {
                   1080:        bltstate = BLT_done;
                   1081: #ifdef NO_FAST_BLITTER
                   1082:        custom_bank.wput(0xDFF09C,0x8040);
                   1083: #endif
                   1084:     } else {
                   1085:        bltstate = BLT_read;
                   1086:        bltcpt = bltcnxlpt;
                   1087:        bltdpt = bltdnxlpt;
                   1088:     }
                   1089: }
                   1090: 
                   1091: static void blit_init(void)
                   1092: {
                   1093:     vblitsize = bltsize >> 6;
                   1094:     hblitsize = bltsize & 0x3F;
                   1095:     if (!vblitsize) vblitsize = 1024;
                   1096:     if (!hblitsize) hblitsize = 64;
                   1097:     blitlpos = 0;
                   1098:     blitzero = true; blitpreva = blitprevb = 0;
                   1099:     blitline = bltcon1 & 1;
                   1100:     blitashift = bltcon0 >> 12; blitbshift = bltcon1 >> 12;
                   1101:     
                   1102:     if (blitline) {
                   1103:        bltcnxlpt = bltcpt;
                   1104:        bltdnxlpt = bltdpt;
                   1105:        blitsing = bltcon1 & 0x2;
                   1106:        blinea = bltadat >> blitashift;
                   1107:        blineb = (bltbdat >> blitbshift) | (bltbdat << (16-blitbshift));
                   1108:        blitsign = bltcon1 & 0x40; 
                   1109:        blitonedot = false;
                   1110:        bltamod &= 0xfffe; bltbmod &= 0xfffe; bltapt &= 0xfffe;
                   1111:     } else {
                   1112:        blitfc = bltcon1 & 0x4;
                   1113:        blitife = bltcon1 & 0x8;
                   1114:        blitfill = bltcon1 & 0x18;
                   1115: 
                   1116:        if ((bltcon1 & 0x18) == 0x18) {
                   1117:            /* Digital "Trash" demo does this; others too. Apparently, no
                   1118:             * negative effects. */
                   1119:            static bool warn = true;
                   1120:            if (warn)
                   1121:                fprintf(stderr, "warning: weird fill mode (further messages suppressed)\n");
                   1122:            warn = false;
                   1123:        }
                   1124:        blitdesc = bltcon1 & 0x2;
                   1125:        if (blitfill && !blitdesc)
                   1126:            fprintf(stderr, "warning: blitter fill without desc\n");
                   1127:     }
                   1128: }
                   1129: 
                   1130: #ifdef DEFERRED_INT
                   1131: 
                   1132: static UWORD deferred_bits;
                   1133: 
                   1134: static void defer_int_handler(void)
                   1135: {
                   1136:     INTREQ(0x8000 | deferred_bits);
                   1137:     deferred_bits = 0;
                   1138:     eventtab[ev_deferint].active = false;
                   1139: }
                   1140: #endif
                   1141: 
                   1142: void do_blitter(void)
                   1143: {
                   1144: #ifdef NO_FAST_BLITTER
                   1145:     /* I'm not sure all this bltstate stuff is really necessary.
                   1146:      * Most programs should be OK if the blit is done as soon as BLTSIZE is
                   1147:      * written to, and the BLTFINISH bit is set some time after that.
                   1148:      * This code here is nowhere near exact.
                   1149:      */
                   1150:     do {       
                   1151:        switch(bltstate) {
                   1152:         case BLT_init:
                   1153:            blit_init();
                   1154:            bltstate = BLT_read;
                   1155:            /* fall through */
                   1156:         case BLT_read:
                   1157:            if (blitter_read())
                   1158:                break;
                   1159:            /* fall through */
                   1160:         case BLT_work:
                   1161:            if (blitline)
                   1162:                blitter_line(); 
                   1163:            else 
                   1164:                blitter_blit();
                   1165:            /* fall through */
                   1166:         case BLT_write:
                   1167:            if (blitter_write())
                   1168:                break;
                   1169:            /* fall through */
                   1170:         case BLT_next:
                   1171:            if (blitline)
                   1172:                blitter_nxline();
                   1173:            else 
                   1174:                blitter_nxblit();
                   1175:            break;
                   1176:         case BLT_done:
                   1177:            specialflags &= ~SPCFLAG_BLIT;
                   1178:            break;
                   1179:        }
                   1180:     } while(bltstate != BLT_done && dmaen(DMA_BLITTER)
                   1181:            && dmaen(DMA_BLITPRI));  /* blitter nasty -> no time for CPU */
                   1182: #else
                   1183:     if (bltstate == BLT_init) {
                   1184:        blit_init();
                   1185:        bltstate =  BLT_read;
                   1186:     }
                   1187:     if (!dmaen(DMA_BLITTER))
                   1188:        return; /* gotta come back later. */
                   1189: 
                   1190:     if (blitline) {
                   1191:        do {
                   1192:            blitter_read();
                   1193:            blitter_line();
                   1194:            blitter_write();
                   1195:            blitter_nxline();
                   1196:        } while (bltstate != BLT_done);
                   1197:     } else {
                   1198:        do {    
                   1199:            blitter_read();
                   1200:            blitter_blit();
                   1201:            blitter_write();
                   1202:            blitter_nxblit();
                   1203:        } while (bltstate != BLT_done);
                   1204:     }
                   1205:     eventtab[ev_deferint].active = true;
                   1206:     eventtab[ev_deferint].oldcycles = cycles;
                   1207:     eventtab[ev_deferint].evtime = 10; /* whatever */
                   1208:     deferred_bits |= 0x40;
                   1209:     events_schedule();
                   1210: 
                   1211:     specialflags &= ~SPCFLAG_BLIT;
                   1212: #endif
                   1213: }
                   1214: 
                   1215: void do_disk(void)
                   1216: {
                   1217: #ifdef NO_FAST_FLOPPY
                   1218:     if (dskdmaen > 1 && dmaen(0x10)){
                   1219:        if (--dsktime == 0) {
                   1220:            dsktime = dskdelay;
                   1221:            if (dsklen & 0x4000){
                   1222:                UWORD dsksync_check;
                   1223:                DISK_GetData(&dsksync_check, &dskbyte);
                   1224:                dskbyte |= 0x8000;
                   1225:                if (dsksynced || !(adkcon & 0x400)) {
                   1226:                    *mfmwrite++ = chipmem_bank.wget(dskpt); dskpt += 2;
                   1227:                    if (--dsklength == 0) {
                   1228:                        DISK_WriteData();
                   1229:                        custom_bank.wput(0xDFF09C, 0x8002); /*INTREQ->DSKBLK */
                   1230:                        dskdmaen = 0;
                   1231:                        specialflags &= ~SPCFLAG_DISK;
                   1232:                    }
                   1233:                }
                   1234:                if (dsksync_check == dsksync) {
                   1235:                    custom_bank.wput(0xDFF09C, 0x9000);
                   1236:                    dsksynced = true;
                   1237:                }
                   1238:            } else {
                   1239:                DISK_GetData(&dskmfm, &dskbyte);
                   1240:                dskbyte |= 0x8000;
                   1241:                if (dsksynced || !(adkcon & 0x400)){
                   1242:                    chipmem_bank.wput(dskpt, dskmfm); dskpt += 2;
                   1243:                    if (--dsklength == 0) {
                   1244:                        custom_bank.wput(0xDFF09C, 0x8002);
                   1245:                        dskdmaen = 0;
                   1246:                        specialflags &= ~SPCFLAG_DISK;
                   1247:                    }
                   1248:                }
                   1249:                if (dskmfm == dsksync) {
                   1250:                    custom_bank.wput(0xDFF09C,0x9000);
                   1251:                    dsksynced = true;
                   1252:                }
                   1253:            }
                   1254:        }
                   1255:     }
                   1256: #else
                   1257:     if (dskdmaen > 1 && dmaen(0x10)){
                   1258:        /* Just don't get into an infinite loop if the code below screws up */
                   1259:        int ntries = 100000; 
                   1260:        
                   1261:        while (--ntries > 0 && (specialflags & SPCFLAG_DISK)) {
                   1262:            if (dsklen & 0x4000){
                   1263:                UWORD dsksync_check;
                   1264:                DISK_GetData(&dsksync_check, &dskbyte);
                   1265:                dskbyte |= 0x8000;
                   1266:                if (dsksynced || !(adkcon & 0x400)) {
                   1267:                    *mfmwrite++ = chipmem_bank.wget(dskpt); dskpt += 2;
                   1268:                    if (--dsklength == 0) {
                   1269:                        DISK_WriteData();
                   1270:                        dskdmaen = 0;
                   1271:                        specialflags &= ~SPCFLAG_DISK;
                   1272:                        eventtab[ev_deferint].active = true;
                   1273:                        eventtab[ev_deferint].oldcycles = cycles;
                   1274:                        eventtab[ev_deferint].evtime = 10; /* whatever */
                   1275:                        events_schedule ();
                   1276:                        deferred_bits |= 0x0002;
                   1277:                    }
                   1278:                }
                   1279:                if (dsksync_check == dsksync) {
                   1280:                    /* This is pretty pointless... */
                   1281:                    custom_bank.wput(0xDFF09C, 0x9000);
                   1282:                    dsksynced = true;
                   1283:                }
                   1284:            } else {
                   1285:                DISK_GetData(&dskmfm, &dskbyte);
                   1286:                dskbyte |= 0x8000;
                   1287:                if (dsksynced || !(adkcon & 0x400)){
                   1288:                    chipmem_bank.wput(dskpt, dskmfm); dskpt += 2;
                   1289:                    if (--dsklength == 0) {
                   1290:                        eventtab[ev_deferint].active = true;
                   1291:                        eventtab[ev_deferint].oldcycles = cycles;
                   1292:                        eventtab[ev_deferint].evtime = 10; /* whatever */
                   1293:                        events_schedule ();
                   1294:                        deferred_bits |= 0x0002;
                   1295:                        dskdmaen = 0;
                   1296:                        specialflags &= ~SPCFLAG_DISK;
                   1297:                    }
                   1298:                }
                   1299:                if (dskmfm == dsksync) {
                   1300:                    /* This is pretty pointless... */
                   1301:                    custom_bank.wput(0xDFF09C,0x9000);
                   1302:                    dsksynced = true;
                   1303:                }
                   1304:            }
                   1305:        }
                   1306:     }
                   1307: #endif
                   1308: }
                   1309: 
                   1310: static __inline__ void pfield_fetchdata(void)
                   1311: {
                   1312:     if (dmaen(0x100) && pfield_linedmaon) {
                   1313:        switch(bplplanecnt){
                   1314:         case 6:
                   1315:            bpl6dat = chipmem_bank.wget(bpl6pt); bpl6pt += 2; bpl6dat <<= 5;
                   1316:         case 5:
                   1317:            bpl5dat = chipmem_bank.wget(bpl5pt); bpl5pt += 2; bpl5dat <<= 4;
                   1318:         case 4:
                   1319:            bpl4dat = chipmem_bank.wget(bpl4pt); bpl4pt += 2; bpl4dat <<= 3;
                   1320:         case 3:
                   1321:            bpl3dat = chipmem_bank.wget(bpl3pt); bpl3pt += 2; bpl3dat <<= 2;
                   1322:         case 2:
                   1323:            bpl2dat = chipmem_bank.wget(bpl2pt); bpl2pt += 2; bpl2dat <<= 1;
                   1324:         case 1:
                   1325:            bpl1dat = chipmem_bank.wget(bpl1pt); bpl1pt += 2;
                   1326:        }
                   1327:     }
                   1328: }
                   1329: 
                   1330: static void pfield_hsync(int plfline)
                   1331: {
                   1332: }
                   1333: 
                   1334: static void do_sprites(int currvp)
                   1335: {   
                   1336:     int spr;
                   1337:     for(spr = 0; spr < 8; spr++) {
                   1338:        int vstart = (sprpos[spr] >> 8) | ((sprctl[spr] << 6) & 0x100);
                   1339:        int vstop = (sprctl[spr] >> 8) | ((sprctl[spr] << 7) & 0x100);
                   1340:        if ((vstart <= currvp && vstop >= currvp) || spron[spr] == 1) {
                   1341:            if (dmaen(0x20)) {
                   1342:                UWORD data1 = chipmem_bank.wget(sprpt[spr]);
                   1343:                UWORD data2 = chipmem_bank.wget(sprpt[spr]+2);
                   1344:                sprpt[spr] += 4;
                   1345:                
                   1346:                if (vstop != currvp && spron[spr] != 1) {
                   1347:                    SPRxDATB(data2, spr);
                   1348:                    SPRxDATA(data1, spr);
                   1349:                    if (!spr && !sprvbfl && ((sprpos[0]&0xff)<<2)>0x60) {
                   1350:                        sprvbfl=2; 
                   1351:                        spr0ctl=sprctl[0]; 
                   1352:                        spr0pos=sprpos[0]; 
                   1353:                    }
                   1354:                } else {
                   1355:                    SPRxPOS(data1, spr);
                   1356:                    SPRxCTL(data2, spr);
                   1357:                }
                   1358: 
                   1359: #if 0
                   1360:                if (vstop != currvp && !sprptset[spr]) {
                   1361:                    SPRxDATB(data2, spr);
                   1362:                    SPRxDATA(data1, spr);
                   1363:                    if (!spr && !sprvbfl && ((sprpos[0]&0xff)<<2)>0x60) {
                   1364:                        sprvbfl=2; 
                   1365:                        spr0ctl=sprctl[0]; 
                   1366:                        spr0pos=sprpos[0]; 
                   1367:                    }
                   1368:                } else {
                   1369:                    SPRxPOS(data1, spr);
                   1370:                    SPRxCTL(data2, spr);
                   1371:                    sprptset[spr] = false;
                   1372:                }
                   1373: #endif
                   1374:            }
                   1375:        }
                   1376:     }
                   1377: }
                   1378: 
                   1379: static void pfield_modulos(void)
                   1380: {
                   1381:     switch(bplplanecnt){
                   1382:      case 6:
                   1383:        bpl6pt += bpl2mod;
                   1384:      case 5:
                   1385:        bpl5pt += bpl1mod;
                   1386:      case 4:
                   1387:        bpl4pt += bpl2mod;
                   1388:      case 3:
                   1389:        bpl3pt += bpl1mod;
                   1390:      case 2:
                   1391:        bpl2pt += bpl2mod;
                   1392:      case 1:
                   1393:        bpl1pt += bpl1mod;
                   1394:     }   
                   1395: }
                   1396: 
                   1397: static void pfield_linetoscr(int pix, int stoppos)
                   1398: {
                   1399:     if (bplcon0 & 0x800 && bplplanecnt == 6) {
                   1400:        /* HAM */
                   1401:        static UWORD lastcolor;
                   1402:        while (pix < diwfirstword && pix < stoppos) {
                   1403:            DrawPixel((pix++)-16, acolors[0]);
                   1404:            lastcolor = color_regs[0];
                   1405:        }
                   1406:        while (pix < diwlastword && pix < stoppos) {
                   1407:            int pv = apixels[pix];
                   1408:            switch(pv & 0x30) {
                   1409:             case 0x00: lastcolor = color_regs[pv]; break;
                   1410:             case 0x10: lastcolor &= 0xFF0; lastcolor |= (pv & 0xF); break;
                   1411:             case 0x20: lastcolor &= 0x0FF; lastcolor |= (pv & 0xF) << 8; break;
                   1412:             case 0x30: lastcolor &= 0xF0F; lastcolor |= (pv & 0xF) << 4; break;
                   1413:            }
                   1414:            
                   1415:            if (spixstate[pix]) {
                   1416:                DrawPixel(pix-16, acolors[spixels[pix]+16]);
                   1417:                spixels[pix] = spixstate[pix] = 0;
                   1418:            } else {
                   1419:                DrawPixel(pix-16, xcolors[lastcolor]);
                   1420:            }
                   1421:            pix++;
                   1422:        }
                   1423:        while (pix < stoppos) {
                   1424:            DrawPixel((pix++)-16, acolors[0]);
                   1425:        }
                   1426:     } else {       
                   1427:        if (bplcon0 & 0x400) {
                   1428:            int *lookup = (bplcon2 & 0x40) ? dblpf_ind2 : dblpf_ind1;
                   1429:            /* Dual playfield */
                   1430:            while (pix < diwfirstword && pix < stoppos) {
                   1431:                DrawPixel((pix++)-16, acolors[0]);
                   1432:            }
                   1433:            while (pix < diwlastword && pix < stoppos) {
                   1434:                if (spixstate[pix]) {
                   1435:                    DrawPixel(pix-16, acolors[spixels[pix]+16]);
                   1436:                    spixels[pix] = spixstate[pix] = 0;
                   1437:                } else {
                   1438:                    DrawPixel(pix-16, acolors[lookup[apixels[pix]]]);
                   1439:                }
                   1440:                pix++;
                   1441:            }
                   1442:            while (pix < stoppos) {
                   1443:                DrawPixel((pix++)-16, acolors[0]);
                   1444:            }
                   1445:        } else {        
                   1446:            while (pix < diwfirstword && pix < stoppos) {
                   1447:                DrawPixel((pix++)-16, acolors[0]);
                   1448:            }
                   1449:            while (pix < diwlastword && pix < stoppos) {
                   1450:                if (spixstate[pix]) {
                   1451:                    if (apixels[pix] == 0 || spixstate[pix] < plf2pri)
                   1452:                        DrawPixel(pix-16, acolors[spixels[pix]+16]);
                   1453:                    else
                   1454:                        DrawPixel(pix-16, acolors[apixels[pix]]);
                   1455:                    spixels[pix] = spixstate[pix] = 0;
                   1456:                } else {                    
                   1457:                    DrawPixel(pix-16, acolors[apixels[pix]]);
                   1458:                }
                   1459:                pix++;
                   1460:            }
                   1461:            while (pix < stoppos) {
                   1462:                DrawPixel((pix++)-16, acolors[0]);
                   1463:            }
                   1464:        }
                   1465:     }
                   1466: }
                   1467: 
                   1468: static void pfield_sprite (int num, int sprxp, UWORD data, UWORD datb)
                   1469: {
                   1470:     int i;
                   1471:     for(i = 15; i >= 0; i--) {
                   1472:        int sprxpos = sprxp + i*2;
                   1473:        if ((sprctl[num] & 0x80) && (num & 1)) {
                   1474:            /* Attached sprite */
                   1475:            int col = ((data << 2) & 4) + ((datb << 3) & 8);
                   1476:            if (col) {
                   1477:                spixels[sprxpos] = col;
                   1478:                spixels[sprxpos+1] = col;
                   1479:                spixstate[sprxpos] = 1 << num;
                   1480:                spixstate[sprxpos+1] = 1 << num;
                   1481:            }
                   1482:            spixstate[sprxpos] |= 1 << (num-1);
                   1483:            spixstate[sprxpos+1] |= 1 << (num-1);
                   1484:        } else {                        
                   1485:            int col = (data & 1) | ((datb << 1) & 2);
                   1486:            if (spixstate[sprxpos] & (1 << num)) {
                   1487:                /* finish attached sprite */
                   1488:                /* Did the upper half of the sprite have any bits set? */
                   1489:                if (spixstate[sprxpos] & (1 << (num+1)))
                   1490:                    col += spixels[sprxpos];
                   1491:                if (!col) {
                   1492:                    spixstate[sprxpos] = spixstate[sprxpos+1] &= ~(3 << num);
                   1493:                }
                   1494:            } else {
                   1495:                if (col) {
                   1496:                    col |= (num & 6) << 1;
                   1497:                }
                   1498:            }
                   1499:            if (col) {
                   1500:                spixels[sprxpos] = col;
                   1501:                spixels[sprxpos+1] = col;
                   1502:                spixstate[sprxpos] = 1<<num;
                   1503:                spixstate[sprxpos+1] = 1<<num;
                   1504:            }
                   1505:        }
                   1506:        data >>= 1;
                   1507:        datb >>= 1;
                   1508:     }   
                   1509: }
                   1510: 
                   1511: void pfield_doline_slow(int currhpos)
                   1512: {
                   1513:     int xpos = currhpos * 4 - 0x60;
                   1514:     static int nextpos = -1;
                   1515:     static int linepos;
                   1516:     static bool paststop = false;
                   1517:     
                   1518:     if (vpos < plffirstline || vpos >= plflastline) 
                   1519:        return;
                   1520:     
                   1521:     if (currhpos == plfstrt) { 
                   1522:        nextpos = currhpos;
                   1523:        linepos = 0;
                   1524:        paststop = false;
                   1525:     }
                   1526:     if (currhpos == nextpos) {    
                   1527:        if (linepos >= plflinelen) {
                   1528:            nextpos = -1;
                   1529:            pfield_modulos();
                   1530:        } else {            
                   1531:            nextpos += bplhires ? 4 : 8;
                   1532:            linepos += bplhires ? 4 : 8;
                   1533:            
                   1534:            pfield_fetchdata();
                   1535:            
                   1536:            if (bplhires) {
                   1537:                int offs1 = 2 + xpos + 16 + bpldelay1*2; /* Never trust compilers, kids! */
                   1538:                int offs2 = 2 + xpos + 16 + bpldelay2*2;
                   1539:                
                   1540:                int pix;
                   1541:                for(pix = 15; pix >= 0; pix--) {
                   1542:                    switch(bplplanecnt) {
                   1543:                     case 4:
                   1544:                        apixels[pix + offs2] |= bpl4dat & 0x8; bpl4dat >>= 1;
                   1545:                     case 3:
                   1546:                        apixels[pix + offs1] |= bpl3dat & 0x4; bpl3dat >>= 1;
                   1547:                     case 2:
                   1548:                        apixels[pix + offs2] |= bpl2dat & 0x2; bpl2dat >>= 1;
                   1549:                     case 1:
                   1550:                        apixels[pix + offs1] |= bpl1dat & 0x1; bpl1dat >>= 1;
                   1551:                    }
                   1552:                }
                   1553:            } else {
                   1554:                int offs1 = 2 + xpos + 32 + bpldelay1*2;
                   1555:                int offs2 = 2 + xpos + 32 + bpldelay2*2;
                   1556:                
                   1557:                int pix;
                   1558:                for(pix = 30; pix >= 0; pix -= 2) {
                   1559:                    switch(bplplanecnt) {
                   1560:                     case 6:
                   1561:                        apixels[pix + offs2] |= bpl6dat & 0x20;
                   1562:                        apixels[pix + offs2 + 1] |= bpl6dat & 0x20; bpl6dat >>= 1;
                   1563:                     case 5:
                   1564:                        apixels[pix + offs1] |= bpl5dat & 0x10;
                   1565:                        apixels[pix + offs1 + 1] |= bpl5dat & 0x10; bpl5dat >>= 1;
                   1566:                     case 4:
                   1567:                        apixels[pix + offs2] |= bpl4dat & 0x8;
                   1568:                        apixels[pix + offs2 + 1] |= bpl4dat & 0x8; bpl4dat >>= 1;
                   1569:                     case 3:
                   1570:                        apixels[pix + offs1] |= bpl3dat & 0x4; 
                   1571:                        apixels[pix + offs1 + 1] |= bpl3dat & 0x4; bpl3dat >>= 1;
                   1572:                     case 2:
                   1573:                        apixels[pix + offs2] |= bpl2dat & 0x2; 
                   1574:                        apixels[pix + offs2 + 1] |= bpl2dat & 0x2; bpl2dat >>= 1;
                   1575:                     case 1:
                   1576:                        apixels[pix + offs1] |= bpl1dat & 0x1; 
                   1577:                        apixels[pix + offs1 + 1] |= bpl1dat & 0x1; bpl1dat >>= 1;
                   1578:                    }
                   1579:                }
                   1580:            }   
                   1581:        }
                   1582:     }
                   1583:     if (xpos > 0x60) { /* sprites can't appear that far to the left */
                   1584:        int spr;
                   1585:        for(spr = 7; spr >= 0; spr--) {
                   1586:            if (sprarmed[spr] && xpos == ((sprpos[spr] & 0xFF) * 4) - 0x60) {
                   1587:                int sprxp = xpos + 2 + (sprctl[spr] & 1)*2;
                   1588:                pfield_sprite (spr, sprxp, sprdata[spr], sprdatb[spr]);
                   1589:            }
                   1590:        }
                   1591:     }
                   1592:     
                   1593:     if (xpos >= 16 && xpos <= 812) {
                   1594:        pfield_linetoscr (xpos, xpos+4);
                   1595:     }
                   1596: }
                   1597: 
                   1598: static __inline__ UWORD *pfield_xlateptr(CPTR plpt, int bytecount)
                   1599: {
                   1600:     if (!chipmem_bank.check(plpt,bytecount)) {
                   1601:        fprintf(stderr, "Warning: Bad playfield pointer\n");
                   1602:        return NULL;
                   1603:     }
                   1604:     return chipmem_bank.xlateaddr(plpt);
                   1605: }
                   1606: 
                   1607: /*
                   1608:  * A few hand-unrolled loops...
                   1609:  */
                   1610: static __inline__ void pfield_orword_hires(UWORD **plfptr, 
                   1611:                                           unsigned char **dataptr, int bit)
                   1612: {
                   1613:     UWORD data = *(*plfptr)++;
                   1614:     unsigned char *pixptr = *dataptr;
                   1615:     
                   1616:     if (data & 0x8000) *pixptr |= bit;
                   1617:     pixptr++;
                   1618:     if (data & 0x4000) *pixptr |= bit;
                   1619:     pixptr++;
                   1620:     if (data & 0x2000) *pixptr |= bit;
                   1621:     pixptr++;
                   1622:     if (data & 0x1000) *pixptr |= bit;
                   1623:     pixptr++;
                   1624:     if (data & 0x800) *pixptr |= bit;
                   1625:     pixptr++;
                   1626:     if (data & 0x400) *pixptr |= bit;
                   1627:     pixptr++;
                   1628:     if (data & 0x200) *pixptr |= bit;
                   1629:     pixptr++;
                   1630:     if (data & 0x100) *pixptr |= bit;
                   1631:     pixptr++;
                   1632:     if (data & 0x80) *pixptr |= bit;
                   1633:     pixptr++;
                   1634:     if (data & 0x40) *pixptr |= bit;
                   1635:     pixptr++;
                   1636:     if (data & 0x20) *pixptr |= bit;
                   1637:     pixptr++;
                   1638:     if (data & 0x10) *pixptr |= bit;
                   1639:     pixptr++;
                   1640:     if (data & 0x8) *pixptr |= bit;
                   1641:     pixptr++;
                   1642:     if (data & 0x4) *pixptr |= bit;
                   1643:     pixptr++;
                   1644:     if (data & 0x2) *pixptr |= bit;
                   1645:     pixptr++;
                   1646:     if (data & 0x1) *pixptr |= bit;
                   1647:     pixptr++;
                   1648:     *dataptr = pixptr;
                   1649: }
                   1650: 
                   1651: static __inline__ void pfield_orword_lores(UWORD **plfptr,
                   1652:                                           unsigned char **dataptr, int bit)
                   1653: {
                   1654:     UWORD data = *(*plfptr)++;
                   1655:     unsigned char *pixptr = *dataptr;
                   1656:     if (data & 0x8000) { *pixptr |= bit; *(pixptr+1) |= bit; }
                   1657:     pixptr+=2;
                   1658:     if (data & 0x4000) { *pixptr |= bit; *(pixptr+1) |= bit; }
                   1659:     pixptr+=2;
                   1660:     if (data & 0x2000) { *pixptr |= bit; *(pixptr+1) |= bit; }
                   1661:     pixptr+=2;
                   1662:     if (data & 0x1000) { *pixptr |= bit; *(pixptr+1) |= bit; }
                   1663:     pixptr+=2;
                   1664:     if (data & 0x800) { *pixptr |= bit; *(pixptr+1) |= bit; }
                   1665:     pixptr+=2;
                   1666:     if (data & 0x400) { *pixptr |= bit; *(pixptr+1) |= bit; }
                   1667:     pixptr+=2;
                   1668:     if (data & 0x200) { *pixptr |= bit; *(pixptr+1) |= bit; }
                   1669:     pixptr+=2;
                   1670:     if (data & 0x100) { *pixptr |= bit; *(pixptr+1) |= bit; }
                   1671:     pixptr+=2;
                   1672:     if (data & 0x80) { *pixptr |= bit; *(pixptr+1) |= bit; }
                   1673:     pixptr+=2;
                   1674:     if (data & 0x40) { *pixptr |= bit; *(pixptr+1) |= bit; }
                   1675:     pixptr+=2;
                   1676:     if (data & 0x20) { *pixptr |= bit; *(pixptr+1) |= bit; }
                   1677:     pixptr+=2;
                   1678:     if (data & 0x10) { *pixptr |= bit; *(pixptr+1) |= bit; }
                   1679:     pixptr+=2;
                   1680:     if (data & 0x8) { *pixptr |= bit; *(pixptr+1) |= bit; }
                   1681:     pixptr+=2;
                   1682:     if (data & 0x4) { *pixptr |= bit; *(pixptr+1) |= bit; }
                   1683:     pixptr+=2;
                   1684:     if (data & 0x2) { *pixptr |= bit; *(pixptr+1) |= bit; }
                   1685:     pixptr+=2;
                   1686:     if (data & 0x1) { *pixptr |= bit; *(pixptr+1) |= bit; }
                   1687:     pixptr+=2;
                   1688:     *dataptr = pixptr;
                   1689: }
                   1690: 
                   1691: static __inline__ void pfield_setword_hires(UWORD **plfptr, 
                   1692:                                            unsigned char **dataptr, int bit)
                   1693: {
                   1694:     UWORD data = *(*plfptr)++;
                   1695:     unsigned char *pixptr = *dataptr; 
                   1696:     if (data & 0x8000) *pixptr++ = bit;
                   1697:     else *pixptr++ = 0;
                   1698:     if (data & 0x4000) *pixptr++ = bit;
                   1699:     else *pixptr++ = 0;
                   1700:     if (data & 0x2000) *pixptr++ = bit;
                   1701:     else *pixptr++ = 0;
                   1702:     if (data & 0x1000) *pixptr++ = bit;
                   1703:     else *pixptr++ = 0;
                   1704:     if (data & 0x800) *pixptr++ = bit;
                   1705:     else *pixptr++ = 0;
                   1706:     if (data & 0x400) *pixptr++ = bit;
                   1707:     else *pixptr++ = 0;
                   1708:     if (data & 0x200) *pixptr++ = bit;
                   1709:     else *pixptr++ = 0;
                   1710:     if (data & 0x100) *pixptr++ = bit;
                   1711:     else *pixptr++ = 0;
                   1712:     if (data & 0x80) *pixptr++ = bit;
                   1713:     else *pixptr++ = 0;
                   1714:     if (data & 0x40) *pixptr++ = bit;
                   1715:     else *pixptr++ = 0;
                   1716:     if (data & 0x20) *pixptr++ = bit;
                   1717:     else *pixptr++ = 0;
                   1718:     if (data & 0x10) *pixptr++ = bit;
                   1719:     else *pixptr++ = 0;
                   1720:     if (data & 0x8) *pixptr++ = bit;
                   1721:     else *pixptr++ = 0;
                   1722:     if (data & 0x4) *pixptr++ = bit;
                   1723:     else *pixptr++ = 0;
                   1724:     if (data & 0x2) *pixptr++ = bit;
                   1725:     else *pixptr++ = 0;
                   1726:     if (data & 0x1) *pixptr++ = bit;
                   1727:     else *pixptr++ = 0;
                   1728:     *dataptr = pixptr;
                   1729: }
                   1730:        
                   1731: static __inline__ void pfield_setword_lores(UWORD **plfptr,
                   1732:                                            unsigned char **dataptr, int bit)
                   1733: {
                   1734:     UWORD data = *(*plfptr)++;
                   1735:     unsigned char *pixptr = *dataptr;
                   1736:     
                   1737:     if (data & 0x8000) { *pixptr++ = bit; *pixptr++ = bit; }
                   1738:     else { *pixptr++ = 0; *pixptr++ = 0; }
                   1739:     if (data & 0x4000) { *pixptr++ = bit; *pixptr++ = bit; }
                   1740:     else { *pixptr++ = 0; *pixptr++ = 0; }
                   1741:     if (data & 0x2000) { *pixptr++ = bit; *pixptr++ = bit; }
                   1742:     else { *pixptr++ = 0; *pixptr++ = 0; }
                   1743:     if (data & 0x1000) { *pixptr++ = bit; *pixptr++ = bit; }
                   1744:     else { *pixptr++ = 0; *pixptr++ = 0; }
                   1745:     if (data & 0x800) { *pixptr++ = bit; *pixptr++ = bit; }
                   1746:     else { *pixptr++ = 0; *pixptr++ = 0; }
                   1747:     if (data & 0x400) { *pixptr++ = bit; *pixptr++ = bit; }
                   1748:     else { *pixptr++ = 0; *pixptr++ = 0; }
                   1749:     if (data & 0x200) { *pixptr++ = bit; *pixptr++ = bit; }
                   1750:     else { *pixptr++ = 0; *pixptr++ = 0; }
                   1751:     if (data & 0x100) { *pixptr++ = bit; *pixptr++ = bit; }
                   1752:     else { *pixptr++ = 0; *pixptr++ = 0; }
                   1753:     if (data & 0x80) { *pixptr++ = bit; *pixptr++ = bit; }
                   1754:     else { *pixptr++ = 0; *pixptr++ = 0; }
                   1755:     if (data & 0x40) { *pixptr++ = bit; *pixptr++ = bit; }
                   1756:     else { *pixptr++ = 0; *pixptr++ = 0; }
                   1757:     if (data & 0x20) { *pixptr++ = bit; *pixptr++ = bit; }
                   1758:     else { *pixptr++ = 0; *pixptr++ = 0; }
                   1759:     if (data & 0x10) { *pixptr++ = bit; *pixptr++ = bit; }
                   1760:     else { *pixptr++ = 0; *pixptr++ = 0; }
                   1761:     if (data & 0x8) { *pixptr++ = bit; *pixptr++ = bit; }
                   1762:     else { *pixptr++ = 0; *pixptr++ = 0; }
                   1763:     if (data & 0x4) { *pixptr++ = bit; *pixptr++ = bit; }
                   1764:     else { *pixptr++ = 0; *pixptr++ = 0; }
                   1765:     if (data & 0x2) { *pixptr++ = bit; *pixptr++ = bit; }
                   1766:     else { *pixptr++ = 0; *pixptr++ = 0; }
                   1767:     if (data & 0x1) { *pixptr++ = bit; *pixptr++ = bit; }
                   1768:     else { *pixptr++ = 0; *pixptr++ = 0; }
                   1769:     
                   1770:     *dataptr = pixptr;
                   1771: }
                   1772: 
                   1773: static void pfield_doline(void)
                   1774: {
                   1775:     int xpos = plfstrt * 4 - 0x60;
                   1776:     int spr;
                   1777:     int linelen;
                   1778: 
                   1779:     if (vpos < plffirstline || vpos >= plflastline) 
                   1780:        return;
                   1781: 
                   1782:     if (dmaen(0x100) && pfield_linedmaon) {    
                   1783:        /*
                   1784:         * We want to use real pointers, but we don't want to get segfaults
                   1785:          * because of them.
                   1786:          */
                   1787:        UWORD *r_bpl1pt,*r_bpl2pt,*r_bpl3pt,*r_bpl4pt,*r_bpl5pt,*r_bpl6pt;
                   1788:        int bytecount = plflinelen / (bplhires ? 4 : 8) * 2;
                   1789:        switch (bplplanecnt) {      
                   1790:         case 6:
                   1791:            r_bpl6pt = pfield_xlateptr(bpl6pt, bytecount);
                   1792:            if (r_bpl6pt == NULL)
                   1793:                return;
                   1794:         case 5: 
                   1795:            r_bpl5pt = pfield_xlateptr(bpl5pt, bytecount);
                   1796:            if (r_bpl5pt == NULL)
                   1797:                return;
                   1798:         case 4:
                   1799:            r_bpl4pt = pfield_xlateptr(bpl4pt, bytecount);
                   1800:            if (r_bpl4pt == NULL)
                   1801:                return;
                   1802:         case 3:
                   1803:            r_bpl3pt = pfield_xlateptr(bpl3pt, bytecount);
                   1804:            if (r_bpl3pt == NULL)
                   1805:                return;
                   1806:         case 2: 
                   1807:            r_bpl2pt = pfield_xlateptr(bpl2pt, bytecount);
                   1808:            if (r_bpl2pt == NULL)
                   1809:                return;
                   1810:         case 1:
                   1811:            r_bpl1pt = pfield_xlateptr(bpl1pt, bytecount);
                   1812:            if (r_bpl1pt == NULL)
                   1813:                return;
                   1814:        } 
                   1815:        switch (bplplanecnt) {      
                   1816:         case 6: bpl6pt += bytecount + bpl2mod;
                   1817:         case 5: bpl5pt += bytecount + bpl1mod;
                   1818:         case 4: bpl4pt += bytecount + bpl2mod;
                   1819:         case 3: bpl3pt += bytecount + bpl1mod;
                   1820:         case 2: bpl2pt += bytecount + bpl2mod;
                   1821:         case 1: bpl1pt += bytecount + bpl1mod;
                   1822:        }
                   1823:  
                   1824:        if (bplhires) { 
                   1825:            int xpos1 = 2 + xpos + 16 + bpldelay1*2;
                   1826:            int xpos2 = 2 + xpos + 16 + bpldelay2*2;
                   1827:            unsigned char *xp1ptr = apixels+xpos1;
                   1828:            unsigned char *xp2ptr = apixels+xpos2;
                   1829: 
                   1830:            if (bplplanecnt > 0) {
                   1831:                unsigned char *app = xp1ptr;
                   1832:                for (linelen = plflinelen; linelen > 0; linelen-=4) {
                   1833:                    pfield_setword_hires(&r_bpl1pt, &app, 1);
                   1834:                }
                   1835:                if (bplplanecnt > 2) {
                   1836:                    unsigned char *app = xp1ptr;
                   1837:                    for (linelen = plflinelen; linelen > 0; linelen-=4) {
                   1838:                        pfield_orword_hires(&r_bpl3pt, &app, 4);
                   1839:                    }
                   1840:                }
                   1841:                if (bplplanecnt > 1) {
                   1842:                    unsigned char *app = xp2ptr;
                   1843:                    for (linelen = plflinelen; linelen > 0; linelen-=4) {
                   1844:                        pfield_orword_hires(&r_bpl2pt, &app, 2);
                   1845:                    }
                   1846:                }
                   1847:                if (bplplanecnt > 3) {
                   1848:                    unsigned char *app = xp2ptr;
                   1849:                    for (linelen = plflinelen; linelen > 0; linelen-=4) {
                   1850:                        pfield_orword_hires(&r_bpl4pt, &app, 8);
                   1851:                    }
                   1852:                }
                   1853:            } else {
                   1854:                memset(apixels, 0, sizeof(apixels));
                   1855:            }
                   1856:        } else {
                   1857:            int xpos1 = 2 + xpos + 32 + bpldelay1*2;
                   1858:            int xpos2 = 2 + xpos + 32 + bpldelay2*2;
                   1859:            unsigned char *xp1ptr = apixels+xpos1;
                   1860:            unsigned char *xp2ptr = apixels+xpos2;
                   1861:            if (bplplanecnt > 0) {
                   1862:                unsigned char *app = xp1ptr;
                   1863:                for (linelen = plflinelen; linelen > 0; linelen-=8) {
                   1864:                    pfield_setword_lores(&r_bpl1pt, &app, 1);
                   1865:                }
                   1866:                if (bplplanecnt > 2) {
                   1867:                    unsigned char *app = xp1ptr;
                   1868:                    for (linelen = plflinelen; linelen > 0; linelen-=8) {
                   1869:                        pfield_orword_lores(&r_bpl3pt, &app, 4);
                   1870:                    }
                   1871:                }
                   1872:                if (bplplanecnt > 4) {
                   1873:                    unsigned char *app = xp1ptr;
                   1874:                    for (linelen = plflinelen; linelen > 0; linelen-=8) {
                   1875:                        pfield_orword_lores(&r_bpl5pt, &app, 16);
                   1876:                    }
                   1877:                }
                   1878:                if (bplplanecnt > 1) {
                   1879:                    unsigned char *app = xp2ptr;
                   1880:                    for (linelen = plflinelen; linelen > 0; linelen-=8) {
                   1881:                        pfield_orword_lores(&r_bpl2pt, &app, 2);
                   1882:                    }
                   1883:                }
                   1884:                if (bplplanecnt > 3) {
                   1885:                    unsigned char *app = xp2ptr;
                   1886:                    for (linelen = plflinelen; linelen > 0; linelen-=8) {
                   1887:                        pfield_orword_lores(&r_bpl4pt, &app, 8);
                   1888:                    }
                   1889:                }
                   1890:                if (bplplanecnt > 5) {
                   1891:                    unsigned char *app = xp2ptr;
                   1892:                    for (linelen = plflinelen; linelen > 0; linelen-=8) {
                   1893:                        pfield_orword_lores(&r_bpl6pt, &app, 32);
                   1894:                    }
                   1895:                }
                   1896:            } else {
                   1897:                memset(apixels, 0, sizeof(apixels));
                   1898:            }
                   1899:        }
                   1900:     }
                   1901:     for(spr = 7; spr >= 0; spr--) {
                   1902:        if (sprarmed[spr]) {
                   1903:            int sprxp = ((sprpos[spr] & 0xFF) * 4) - 0x60 + 2 + (sprctl[spr] & 1)*2;
                   1904:            int i;
                   1905:            /* Ugh. Nasty bug. Let's rather lose some sprites than trash
                   1906:             * memory. */
                   1907:            if (sprxp < 0)
                   1908:                continue;
                   1909:            pfield_sprite (spr, sprxp, sprdata[spr], sprdatb[spr]);
                   1910:        }
                   1911:     }
                   1912:     
                   1913:     pfield_linetoscr (16, 812);
                   1914: }
                   1915: 
                   1916: static void setdontcare(void)
                   1917: {
                   1918:     printf("Don't care mouse mode set\n");
                   1919:     mousestate=dont_care_mouse;
                   1920:     lastspr0x=lastmx; lastspr0y=lastmy;
                   1921:     mstepx=defstepx; mstepy=defstepy;
                   1922: }
                   1923: 
                   1924: static void setfollow(void)
                   1925: {
                   1926:     printf("Follow sprite mode set\n");
                   1927:     mousestate=follow_mouse;
                   1928:     lastdiffx=lastdiffy=0;
                   1929:     sprvbfl=0;
                   1930:     spr0ctl=spr0pos=0;
                   1931:     mstepx=defstepx; mstepy=defstepy;
                   1932: }
                   1933: 
                   1934: void togglemouse(void)
                   1935: {
                   1936:     switch(mousestate) {
                   1937:      case dont_care_mouse: setfollow(); break;
                   1938:      case follow_mouse: setdontcare(); break;
                   1939:     }
                   1940: }          
                   1941: 
                   1942: #if 0 /* Mouse calibrations works well enough without this. */
                   1943: void mousesetup(void)
                   1944: {
                   1945:     if (mousestate != follow_mouse) return;
                   1946:     char buf[80];
                   1947:     printf("\nMouse pointer centering.\n\n");
                   1948:     printf("Current values: xoffs=0x%x yoffs=0x%x\n", xoffs, yoffs);
                   1949:     printf("New values (y/n)?";
                   1950:     cin.get(buf,80,'\n');
                   1951:     if (toupper(buf[0]) != 'Y') return;
                   1952:     cout << "\nxoffs= "; cin>>xoffs;
                   1953:     cout << "yoffs= "; cin>>yoffs;
                   1954:     cout << "\n";
                   1955: }
                   1956: #endif
                   1957: 
                   1958: static __inline__ int adjust(int val)
                   1959: {
                   1960:     if (val>127)
                   1961:        return 127; 
                   1962:     else if (val<-127)
                   1963:        return -127;
                   1964:     return val;
                   1965: }
                   1966: 
                   1967: static void vsync_handler(void)
                   1968: {
                   1969:     int spr0x = ((spr0pos & 0xff) << 2) | ((spr0ctl & 1) << 1);
                   1970:     int spr0y = ((spr0pos >> 8) | ((spr0ctl & 4) << 6)) << 1;
                   1971:     int diffx, diffy;
                   1972:     int i;
                   1973:     
                   1974:     handle_events();
                   1975: #ifdef HAVE_JOYSTICK
                   1976:     {
                   1977:        UWORD dir;
                   1978:        bool button;
                   1979:        read_joystick(&dir, &button);
                   1980:        buttonstate[1] = button;
                   1981:     }
                   1982: #endif
                   1983: 
                   1984:     if (produce_sound)
                   1985:        flush_sound ();
                   1986:     
                   1987:     switch (mousestate) {
                   1988:      case normal_mouse:
                   1989:        diffx = lastmx - lastsampledmx;
                   1990:        diffy = lastmy - lastsampledmy;
                   1991:        if (!newmousecounters) {        
                   1992:            if (diffx > 127) diffx = 127;
                   1993:            if (diffx < -127) diffx = -127;
                   1994:            joy0x += diffx;
                   1995:            if (diffy > 127) diffy = 127;
                   1996:            if (diffy < -127) diffy = -127;
                   1997:            joy0y += diffy;
                   1998:        }
                   1999:        lastsampledmx += diffx; lastsampledmy += diffy;
                   2000:        break;
                   2001: 
                   2002:      case dont_care_mouse:
                   2003:        diffx = adjust (((lastmx-lastspr0x) * mstepx) >> 16);
                   2004:        diffy = adjust (((lastmy-lastspr0y) * mstepy) >> 16);
                   2005:        lastspr0x=lastmx; lastspr0y=lastmy;
                   2006:        joy0x+=diffx; joy0y+=diffy;
                   2007:        break;
                   2008:        
                   2009:      case follow_mouse:
                   2010:        if (sprvbfl && sprvbfl-- >1) {
                   2011:            int mouseypos;
                   2012:            
                   2013:            if ((lastdiffx > docal || lastdiffx < -docal) && lastspr0x != spr0x 
                   2014:                && spr0x > plfstrt*4+34+xcaloff && spr0x < plfstop*4-xcaloff)
                   2015:            {  
                   2016:                int val = (lastdiffx << 16) / (spr0x - lastspr0x);
                   2017:                if (val>=0x8000) mstepx=(mstepx*(calweight-1)+val)/calweight;
                   2018:            }
                   2019:            if ((lastdiffy > docal || lastdiffy < -docal) && lastspr0y != spr0y
                   2020:                && spr0y>plffirstline+ycaloff && spr0y<plflastline-ycaloff) 
                   2021:            { 
                   2022:                int val = (lastdiffy<<16) / (spr0y-lastspr0y);
                   2023:                if (val>=0x8000) mstepy=(mstepy*(calweight-1)+val)/calweight;
                   2024:            }
                   2025:            mouseypos = lastmy;
                   2026: 
                   2027:            /* Calculations might be incorrect */
                   2028:            if(dont_want_aspect)
                   2029:                mouseypos *= 2;
                   2030: 
                   2031:            /* cout<<" mstepx= "<<mstepx<<" mstepy= "<<mstepy<<"\n";*/
                   2032:            diffx = adjust ((((lastmx + 0x70 + xoffs - spr0x) & ~1) * mstepx) >> 16);
                   2033:            diffy = adjust ((((mouseypos + yoffs - spr0y+minfirstline*2) & ~1) * mstepy) >> 16);
                   2034:            lastspr0x=spr0x; lastspr0y=spr0y;
                   2035:            lastdiffx=diffx; lastdiffy=diffy;
                   2036:            joy0x+=diffx; joy0y+=diffy; 
                   2037:        }
                   2038:        break;
                   2039:     }
                   2040:  
                   2041:     INTREQ(0x8020);
                   2042:     if (bplcon0 & 4) lof ^= 0x8000;
                   2043:     COPJMP1(0);
                   2044:     
                   2045:     for (i = 0; i < 8; i++)
                   2046:        spron[i] = 0;
                   2047: 
                   2048:     if (framecnt == 0)
                   2049:        flush_screen ();
                   2050:     count_frame();    
                   2051: #ifdef __unix
                   2052:     {
                   2053:        struct timeval tv;
                   2054:        unsigned long int newtime;
                   2055:        
                   2056:        gettimeofday(&tv,NULL); 
                   2057:        newtime = (tv.tv_sec-seconds_base) * 1000 + tv.tv_usec / 1000;
                   2058:        
                   2059:        if (!bogusframe) {      
                   2060:            frametime += newtime - msecs;
                   2061:            timeframes++;
                   2062:        }
                   2063:        msecs = newtime;
                   2064:        bogusframe = false;
                   2065:     }
                   2066: #endif
                   2067:     CIA_vsync_handler();
                   2068: }
                   2069: 
                   2070: static void hsync_handler(void)
                   2071: {
                   2072:     eventtab[ev_hsync].oldcycles = cycles;
                   2073:     CIA_hsync_handler();
                   2074:     
                   2075:     if(produce_sound)
                   2076:        do_sound ();
                   2077: 
                   2078:     if (framecnt == 0 && vpos >= plffirstline && vpos < plflastline 
                   2079:        && vpos >= minfirstline) 
                   2080:     {
                   2081:        /* Finish the line, if we started doing it with the slow update.
                   2082:         * Otherwise, draw it entirely. */
                   2083:        if (pfield_fullline) {      
                   2084:            if (!pfield_linedone) {             
                   2085:                pfield_doline();
                   2086:            }
                   2087:        } else {
                   2088:            int i;
                   2089:            for(i = pfield_lastpart_hpos; i < maxhpos; i++)
                   2090:                pfield_doline_slow(i);
                   2091:        }
                   2092:        flush_line ();
                   2093:     }
                   2094:     pfield_calclinedma();
                   2095:     pfield_fullline = true;
                   2096:     pfield_linedone = false;
                   2097:     pfield_lastpart_hpos = 0;
                   2098: 
                   2099:     if (++vpos == (maxvpos + (lof != 0))) {
                   2100:        vpos = 0;
                   2101:        vsync_handler();
                   2102:     }
                   2103:     
                   2104:     /* Tell the graphics code about the next line. */
                   2105:     if (framecnt == 0 && vpos >= plffirstline && vpos < plflastline
                   2106:        && vpos >= minfirstline) 
                   2107:     {
                   2108:        if (dont_want_aspect) {
                   2109:            prepare_line(vpos - minfirstline, false);
                   2110:        } else {
                   2111:            if (bplcon0 & 4) {
                   2112:                if(lof) {
                   2113:                    prepare_line((vpos-minfirstline)*2, false);
                   2114:                } else {
                   2115:                    prepare_line((vpos-minfirstline)*2+1, false);
                   2116:                }
                   2117:            } else {
                   2118:                prepare_line((vpos-minfirstline)*2, true);
                   2119:            }
                   2120:        }
                   2121:     }
                   2122: 
                   2123:     /* do_sprites must be called after pfield_lastpart_hpos
                   2124:      * is set to 0. */
                   2125:     if (vpos > 0) do_sprites(vpos);
                   2126: }
                   2127: 
                   2128: void customreset(void)
                   2129: {
                   2130:     int i;
                   2131: #ifdef __unix
                   2132:     struct timeval tv;
                   2133: #endif
                   2134:     inhibit_frame = 0;
                   2135:     CIA_reset();
                   2136:     cycles = 0; specialflags = 0;
                   2137:     
                   2138:     vpos = 0; lof = 0;
                   2139:     
                   2140:     if (needmousehack()) {
                   2141:        if (mousestate != follow_mouse) setfollow();
                   2142:     } else {
                   2143:        mousestate = normal_mouse;
                   2144:     }
                   2145: 
                   2146:     memset(spixels, 0, sizeof(spixels));
                   2147:     memset(spixstate, 0, sizeof(spixstate));
                   2148:     
                   2149:     prepare_line(0, false); /* Get the graphics stuff in a sane state */
                   2150:     
                   2151:     dmacon = intena = 0;
                   2152:     bltstate = BLT_done;
                   2153:     copstate = COP_stop;
                   2154:     copcon = 0;
                   2155:     dskdmaen = 0;
                   2156:     cycles = 0;
                   2157:     for(i = ev_copper; i < ev_max; i++) {
                   2158:        eventtab[i].active = false;
                   2159:        eventtab[i].oldcycles = 0;
                   2160:     }
                   2161:     copper_active = false;
                   2162:     eventtab[ev_cia].handler = CIA_handler;
                   2163:     eventtab[ev_copper].handler = do_copper;
                   2164:     eventtab[ev_hsync].handler = hsync_handler;
                   2165:     eventtab[ev_hsync].evtime = maxhpos;
                   2166:     eventtab[ev_hsync].active = true;
                   2167: #ifdef DEFERRED_INT
                   2168:     eventtab[ev_deferint].handler = defer_int_handler;
                   2169:     eventtab[ev_deferint].active = false;
                   2170:     deferred_bits = 0;
                   2171: #endif
                   2172:     events_schedule();
                   2173:     
                   2174: #ifdef __unix
                   2175:     gettimeofday(&tv,NULL);
                   2176:     seconds_base = tv.tv_sec;
                   2177:     bogusframe = true;
                   2178: #endif
                   2179: }
                   2180: 
                   2181: void dumpcustom(void)
                   2182: {
                   2183: 
                   2184:     printf("DMACON: %x INTENA: %x INTREQ: %x VPOS: %x HPOS: %x\n", DMACONR(),
                   2185:           intena, intreq, vpos, current_hpos());
                   2186:     if (timeframes) { 
                   2187:        printf("Average frame time: %d ms [frames: %d time: %d]\n", 
                   2188:               frametime/timeframes, timeframes, frametime);
                   2189:     }
                   2190: }
                   2191: 
                   2192: int intlev(void)
                   2193: {
                   2194:     UWORD imask = intreq & intena;
                   2195:     if (imask && (intena & 0x4000)){
                   2196:        if (imask & 0x2000) return 6;
                   2197:        if (imask & 0x1800) return 5;
                   2198:        if (imask & 0x0780) return 4;
                   2199:        if (imask & 0x0070) return 3;
                   2200:        if (imask & 0x0008) return 2;
                   2201:        if (imask & 0x0007) return 1;
                   2202:     }
                   2203:     return -1;
                   2204: }
                   2205: 
                   2206: void custom_init(void)
                   2207: {
                   2208:     int num;
                   2209:     setfollow();
                   2210:     customreset();
                   2211:     for (num = 0; num < 64; num++) {   
                   2212:        int plane1 = (num & 1) | ((num >> 1) & 2) | ((num >> 2) & 4);
                   2213:        int plane2 = ((num >> 1) & 1) | ((num >> 2) & 2) | ((num >> 3) & 4);
                   2214:        if (plane2 > 0) plane2 += 8;
                   2215:        dblpf_ind1[num] = plane1 == 0 ? plane2 : plane1;
                   2216:        dblpf_ind2[num] = plane2 == 0 ? plane1 : plane2;
                   2217:     }
                   2218: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.