Annotation of uae/src/custom.c, revision 1.1.1.15

1.1       root        1:  /*
                      2:   * UAE - The Un*x Amiga Emulator
1.1.1.3   root        3:   *
1.1       root        4:   * Custom chip emulation
1.1.1.3   root        5:   *
1.1.1.15! root        6:   * Copyright 1995-2001 Bernd Schmidt
1.1.1.2   root        7:   * Copyright 1995 Alessandro Bissacco
1.1.1.15! root        8:   * Copyright 2000,2001 Toni Wilen
1.1       root        9:   */
                     10: 
                     11: #include "sysconfig.h"
                     12: #include "sysdeps.h"
                     13: 
                     14: #include <ctype.h>
                     15: #include <assert.h>
                     16: 
                     17: #include "config.h"
                     18: #include "options.h"
1.1.1.3   root       19: #include "threaddep/penguin.h"
                     20: #include "uae.h"
                     21: #include "gensound.h"
                     22: #include "sounddep/sound.h"
1.1       root       23: #include "events.h"
                     24: #include "memory.h"
                     25: #include "custom.h"
                     26: #include "newcpu.h"
                     27: #include "cia.h"
                     28: #include "disk.h"
                     29: #include "blitter.h"
                     30: #include "xwin.h"
1.1.1.3   root       31: #include "joystick.h"
                     32: #include "audio.h"
1.1       root       33: #include "keybuf.h"
                     34: #include "serial.h"
1.1.1.2   root       35: #include "osemu.h"
1.1.1.3   root       36: #include "autoconf.h"
                     37: #include "gui.h"
                     38: #include "picasso96.h"
1.1.1.4   root       39: #include "drawing.h"
1.1.1.15! root       40: #include "savestate.h"
1.1.1.2   root       41: 
1.1.1.6   root       42: static unsigned int n_consecutive_skipped = 0;
                     43: static unsigned int total_skipped = 0;
                     44: 
1.1.1.3   root       45: #define SPRITE_COLLISIONS
1.1.1.2   root       46: 
1.1.1.3   root       47: /* Mouse and joystick emulation */
1.1.1.2   root       48: 
1.1.1.3   root       49: int buttonstate[3];
                     50: static int mouse_x, mouse_y;
                     51: int joy0button, joy1button;
                     52: unsigned int joy0dir, joy1dir;
                     53: 
                     54: /* Events */
1.1       root       55: 
1.1.1.14  root       56: unsigned long int currcycle, nextevent, is_lastline;
1.1.1.4   root       57: static int rpt_did_reset;
1.1.1.2   root       58: struct ev eventtab[ev_max];
                     59: 
1.1.1.3   root       60: frame_time_t vsynctime, vsyncmintime;
                     61: 
1.1.1.4   root       62: static int vpos;
                     63: static uae_u16 lof;
                     64: static int next_lineno;
                     65: static enum nln_how nextline_how;
                     66: static int lof_changed = 0;
1.1       root       67: 
1.1.1.3   root       68: static uae_u32 sprtaba[256],sprtabb[256];
1.1.1.13  root       69: static uae_u32 sprite_ab_merge[256];
                     70: /* Tables for collision detection.  */
                     71: static uae_u32 sprclx[16], clxmask[16];
1.1.1.3   root       72: 
1.1.1.2   root       73: /*
                     74:  * Hardware registers of all sorts.
                     75:  */
1.1       root       76: 
1.1.1.4   root       77: static void custom_wput_1 (int, uaecptr, uae_u32) REGPARAM;
                     78: 
1.1.1.3   root       79: static uae_u16 cregs[256];
1.1       root       80: 
1.1.1.3   root       81: uae_u16 intena,intreq;
                     82: uae_u16 dmacon;
                     83: uae_u16 adkcon; /* used by audio code */
1.1       root       84: 
1.1.1.3   root       85: static uae_u32 cop1lc,cop2lc,copcon;
1.1.1.7   root       86:  
                     87: int maxhpos = MAXHPOS_PAL;
                     88: int maxvpos = MAXVPOS_PAL;
                     89: int minfirstline = MINFIRSTLINE_PAL;
                     90: int vblank_endline = VBLANK_ENDLINE_PAL;
                     91: int vblank_hz = VBLANK_HZ_PAL;
                     92: unsigned long syncbase;
                     93: static int fmode;
                     94: static unsigned int beamcon0, new_beamcon0;
                     95: 
1.1.1.15! root       96: #define MAX_SPRITES 8
1.1       root       97: 
1.1.1.2   root       98: /* This is but an educated guess. It seems to be correct, but this stuff
                     99:  * isn't documented well. */
1.1.1.3   root      100: enum sprstate { SPR_stop, SPR_restart, SPR_waiting_start, SPR_waiting_stop };
1.1.1.10  root      101: 
                    102: struct sprite {
                    103:     uaecptr pt;
                    104:     int on;
                    105:     int xpos;
                    106:     int vstart;
                    107:     int vstop;
                    108:     int armed;
                    109:     enum sprstate state;
                    110: };
                    111: 
                    112: static struct sprite spr[8];
                    113: 
                    114: static int sprite_vblank_endline = VBLANK_ENDLINE_NTSC + 2;
1.1       root      115: 
1.1.1.15! root      116: static unsigned int sprctl[MAX_SPRITES], sprpos[MAX_SPRITES];
        !           117: static uae_u16 sprdata[MAX_SPRITES][4], sprdatb[MAX_SPRITES][4];
1.1.1.10  root      118: static int sprite_last_drawn_at[MAX_SPRITES];
1.1.1.7   root      119: static int last_sprite_point, nr_armed;
1.1.1.15! root      120: static int sprite_width, sprres, sprite_buffer_res;
1.1.1.7   root      121: 
1.1.1.6   root      122: static uae_u32 bpl1dat, bpl2dat, bpl3dat, bpl4dat, bpl5dat, bpl6dat, bpl7dat, bpl8dat;
                    123: static uae_s16 bpl1mod, bpl2mod;
1.1       root      124: 
1.1.1.3   root      125: static uaecptr bplpt[8];
1.1.1.10  root      126: uae_u8 *real_bplpt[8];
1.1.1.15! root      127: /* Used as a debugging aid, to offset any bitplane temporarily.  */
        !           128: int bploff[8];
1.1       root      129: 
                    130: /*static int blitcount[256];  blitter debug */
                    131: 
1.1.1.2   root      132: static struct color_entry current_colors;
1.1.1.6   root      133: static unsigned int bplcon0, bplcon1, bplcon2, bplcon3, bplcon4;
1.1.1.3   root      134: static int nr_planes_from_bplcon0, corrected_nr_planes_from_bplcon0;
1.1.1.4   root      135: static unsigned int diwstrt, diwstop, diwhigh;
                    136: static int diwhigh_written;
                    137: static unsigned int ddfstrt, ddfstop;
1.1.1.7   root      138: 
1.1.1.4   root      139: /* The display and data fetch windows */
1.1       root      140: 
1.1.1.4   root      141: enum diw_states
                    142: {
                    143:     DIW_waiting_start, DIW_waiting_stop
                    144: };
1.1       root      145: 
1.1.1.13  root      146: static int plffirstline, plflastline;
                    147: static int plfstrt, plfstop;
                    148: static int last_diw_pix_hpos, last_ddf_pix_hpos, last_decide_line_hpos;
                    149: static int last_fetch_hpos, last_sprite_hpos;
1.1.1.6   root      150: int diwfirstword, diwlastword;
1.1.1.4   root      151: static enum diw_states diwstate, hdiwstate;
1.1       root      152: 
1.1.1.4   root      153: /* Sprite collisions */
1.1.1.14  root      154: static unsigned int clxdat, clxcon, clxcon2, clxcon_bpl_enable, clxcon_bpl_match;
                    155: static int clx_sprmask;
1.1.1.4   root      156: 
                    157: enum copper_states {
                    158:     COP_stop,
1.1.1.15! root      159:     COP_read1_in2,
        !           160:     COP_read1_wr_in4,
        !           161:     COP_read1_wr_in2,
        !           162:     COP_read1,
        !           163:     COP_read2_wr_in2,
        !           164:     COP_read2,
1.1.1.4   root      165:     COP_bltwait,
1.1.1.15! root      166:     COP_wait_in4,
        !           167:     COP_wait_in2,
        !           168:     COP_skip_in4,
        !           169:     COP_skip_in2,
        !           170:     COP_wait1,
        !           171:     COP_wait
1.1.1.4   root      172: };
                    173: 
                    174: struct copper {
                    175:     /* The current instruction words.  */
                    176:     unsigned int i1, i2;
1.1.1.15! root      177:     unsigned int saved_i1, saved_i2;
1.1.1.4   root      178:     enum copper_states state;
                    179:     /* Instruction pointer.  */
1.1.1.15! root      180:     uaecptr ip, saved_ip;
1.1.1.10  root      181:     int hpos, vpos;
1.1.1.4   root      182:     unsigned int ignore_next;
1.1.1.10  root      183:     int vcmp, hcmp;
1.1.1.15! root      184: 
        !           185:     /* When we schedule a copper event, knowing a few things about the future
        !           186:        of the copper list can reduce the number of sync_with_cpu calls
        !           187:        dramatically.  */
        !           188:     unsigned int first_sync;
        !           189:     unsigned int regtypes_modified;
1.1.1.4   root      190: };
                    191: 
1.1.1.15! root      192: #define REGTYPE_NONE 0
        !           193: #define REGTYPE_COLOR 1
        !           194: #define REGTYPE_SPRITE 2
        !           195: #define REGTYPE_PLANE 4
        !           196: #define REGTYPE_BLITTER 8
        !           197: #define REGTYPE_JOYPORT 16
        !           198: #define REGTYPE_DISK 32
        !           199: #define REGTYPE_POS 64
        !           200: #define REGTYPE_AUDIO 128
        !           201: 
        !           202: #define REGTYPE_ALL 255
        !           203: /* Always set in regtypes_modified, to enable a forced update when things like
        !           204:    DMACON, BPLCON0, COPJMPx get written.  */
        !           205: #define REGTYPE_FORCE 256
        !           206: 
        !           207: 
        !           208: static unsigned int regtypes[512];
        !           209: 
1.1.1.4   root      210: static struct copper cop_state;
1.1.1.10  root      211: static int copper_enabled_thisline;
                    212: static int cop_min_waittime;
1.1       root      213: 
                    214: /*
                    215:  * Statistics
                    216:  */
                    217: 
1.1.1.2   root      218: /* Used also by bebox.cpp */
1.1.1.6   root      219: unsigned long int msecs = 0, frametime = 0, lastframetime = 0, timeframes = 0;
1.1       root      220: static unsigned long int seconds_base;
                    221: int bogusframe;
1.1.1.12  root      222: int n_frames;
1.1.1.4   root      223: 
1.1.1.15! root      224: #define DEBUG_COPPER 0
        !           225: #if DEBUG_COPPER
        !           226: /* 10000 isn't enough!  */
        !           227: #define NR_COPPER_RECORDS 40000
        !           228: #else
        !           229: #define NR_COPPER_RECORDS 1
        !           230: #endif
        !           231: 
        !           232: /* Record copper activity for the debugger.  */
        !           233: struct cop_record
        !           234: {
        !           235:   int hpos, vpos;
        !           236:   uaecptr addr;
        !           237: };
        !           238: static struct cop_record cop_record[2][NR_COPPER_RECORDS];
        !           239: static int nr_cop_records[2];
        !           240: static int curr_cop_set;
        !           241: 
        !           242: /* Recording of custom chip register changes.  */
1.1.1.4   root      243: static int current_change_set;
                    244: 
                    245: #ifdef OS_WITHOUT_MEMORY_MANAGEMENT
                    246: /* sam: Those arrays uses around 7Mb of BSS... That seems  */
                    247: /* too much for AmigaDOS (uae crashes as soon as one loads */
                    248: /* it. So I use a different strategy here (realloc the     */
                    249: /* arrays when needed. That strategy might be usefull for  */
                    250: /* computer with low memory.                               */
1.1.1.13  root      251: struct sprite_entry  *sprite_entries[2];
1.1.1.4   root      252: struct color_change *color_changes[2];
1.1.1.13  root      253: static int max_sprite_entry = 400;
                    254: static int delta_sprite_entry = 0;
1.1.1.4   root      255: static int max_color_change = 400;
                    256: static int delta_color_change = 0;
                    257: #else
1.1.1.13  root      258: struct sprite_entry sprite_entries[2][MAX_SPR_PIXELS / 16];
1.1.1.4   root      259: struct color_change color_changes[2][MAX_REG_CHANGE];
                    260: #endif
                    261: 
1.1.1.7   root      262: struct decision line_decisions[2 * (MAXVPOS + 1) + 1];
                    263: struct draw_info line_drawinfo[2][2 * (MAXVPOS + 1) + 1];
                    264: struct color_entry color_tables[2][(MAXVPOS + 1) * 2];
1.1.1.4   root      265: 
1.1.1.13  root      266: static int next_sprite_entry = 0;
                    267: static int prev_next_sprite_entry;
                    268: static int next_sprite_forced = 1;
                    269: 
                    270: struct sprite_entry *curr_sprite_entries, *prev_sprite_entries;
1.1.1.4   root      271: struct color_change *curr_color_changes, *prev_color_changes;
                    272: struct draw_info *curr_drawinfo, *prev_drawinfo;
                    273: struct color_entry *curr_color_tables, *prev_color_tables;
                    274: 
1.1.1.13  root      275: static int next_color_change;
1.1.1.4   root      276: static int next_color_entry, remembered_color_entry;
                    277: static int color_src_match, color_dest_match, color_compare_result;
                    278: 
1.1.1.13  root      279: static uae_u32 thisline_changed;
1.1.1.4   root      280: 
                    281: #ifdef SMART_UPDATE
1.1.1.5   root      282: #define MARK_LINE_CHANGED do { thisline_changed = 1; } while (0)
1.1.1.4   root      283: #else
1.1.1.5   root      284: #define MARK_LINE_CHANGED do { ; } while (0)
1.1.1.4   root      285: #endif
                    286: 
                    287: static struct decision thisline_decision;
1.1.1.13  root      288: static int passed_plfstop, fetch_cycle;
                    289: 
                    290: enum fetchstate {
                    291:     fetch_not_started,
                    292:     fetch_started,
                    293:     fetch_was_plane0
                    294: } fetch_state;
1.1.1.4   root      295: 
1.1       root      296: /*
                    297:  * helper functions
                    298:  */
                    299: 
1.1.1.15! root      300: uae_u32 get_copper_address (int copno)
        !           301: {
        !           302:     switch (copno) {
        !           303:     case 1: return cop1lc;
        !           304:     case 2: return cop2lc;
        !           305:     default: return 0;
        !           306:     }
        !           307: }
        !           308: 
        !           309: STATIC_INLINE void record_copper (uaecptr addr, int hpos, int vpos)
        !           310: {
        !           311: #if DEBUG_COPPER
        !           312:     int t = nr_cop_records[curr_cop_set];
        !           313:     if (t < NR_COPPER_RECORDS) {
        !           314:        cop_record[curr_cop_set][t].addr = addr;
        !           315:        cop_record[curr_cop_set][t].hpos = hpos;
        !           316:        cop_record[curr_cop_set][t].vpos = vpos;
        !           317:        nr_cop_records[curr_cop_set] = t + 1;
        !           318:     }
        !           319: #endif
        !           320: }
        !           321: 
        !           322: int find_copper_record (uaecptr addr, int *phpos, int *pvpos)
        !           323: {
        !           324:     int s = curr_cop_set ^ 1;
        !           325:     int t = nr_cop_records[s];
        !           326:     int i;
        !           327:     for (i = 0; i < t; i++) {
        !           328:        if (cop_record[s][i].addr == addr) {
        !           329:            *phpos = cop_record[s][i].hpos;
        !           330:            *pvpos = cop_record[s][i].vpos;
        !           331:            return 1;
        !           332:        }
        !           333:     }
        !           334:     return 0;
        !           335: }
        !           336: 
1.1.1.4   root      337: int rpt_available = 0;
1.1.1.3   root      338: 
1.1.1.4   root      339: void reset_frame_rate_hack (void)
                    340: {
                    341:     if (currprefs.m68k_speed != -1)
                    342:        return;
                    343: 
                    344:     if (! rpt_available) {
                    345:        currprefs.m68k_speed = 0;
                    346:        return;
                    347:     }
1.1.1.3   root      348: 
1.1.1.4   root      349:     rpt_did_reset = 1;
                    350:     is_lastline = 0;
                    351:     vsyncmintime = read_processor_time() + vsynctime;
                    352:     write_log ("Resetting frame rate hack\n");
                    353: }
1.1       root      354: 
1.1.1.3   root      355: void check_prefs_changed_custom (void)
                    356: {
1.1.1.7   root      357:     currprefs.gfx_framerate = changed_prefs.gfx_framerate;
1.1.1.3   root      358:     /* Not really the right place... */
1.1.1.6   root      359:     if (currprefs.jport0 != changed_prefs.jport0
                    360:        || currprefs.jport1 != changed_prefs.jport1) {
                    361:        currprefs.jport0 = changed_prefs.jport0;
                    362:        currprefs.jport1 = changed_prefs.jport1;
1.1.1.3   root      363:        joystick_setting_changed ();
1.1       root      364:     }
1.1.1.3   root      365:     currprefs.immediate_blits = changed_prefs.immediate_blits;
                    366:     currprefs.blits_32bit_enabled = changed_prefs.blits_32bit_enabled;
1.1.1.15! root      367:     currprefs.collision_level = changed_prefs.collision_level;
        !           368:     currprefs.fast_copper = changed_prefs.fast_copper;
1.1       root      369: }
                    370: 
1.1.1.8   root      371: STATIC_INLINE void setclr (uae_u16 *p, uae_u16 val)
1.1       root      372: {
1.1.1.6   root      373:     if (val & 0x8000)
1.1       root      374:        *p |= val & 0x7FFF;
1.1.1.6   root      375:     else
1.1       root      376:        *p &= ~val;
                    377: }
                    378: 
1.1.1.3   root      379: __inline__ int current_hpos (void)
1.1       root      380: {
1.1.1.14  root      381:     return (get_cycles () - eventtab[ev_hsync].oldcycles) / CYCLE_UNIT;
1.1       root      382: }
                    383: 
1.1.1.8   root      384: STATIC_INLINE uae_u8 *pfield_xlateptr (uaecptr plpt, int bytecount)
1.1.1.2   root      385: {
1.1.1.4   root      386:     if (!chipmem_bank.check (plpt, bytecount)) {
1.1.1.2   root      387:        static int count = 0;
1.1.1.3   root      388:        if (!count)
                    389:            count++, write_log ("Warning: Bad playfield pointer\n");
1.1.1.2   root      390:        return NULL;
                    391:     }
1.1.1.4   root      392:     return chipmem_bank.xlateaddr (plpt);
1.1.1.2   root      393: }
                    394: 
1.1.1.8   root      395: STATIC_INLINE void docols (struct color_entry *colentry)
1.1.1.3   root      396: {
                    397:     int i;
1.1.1.11  root      398: 
                    399:     if (currprefs.chipset_mask & CSMASK_AGA) {
                    400:         for (i = 0; i < 256; i++) {
                    401:            int v = color_reg_get (colentry, i);
1.1.1.14  root      402:            if (v < 0 || v > 16777215)
1.1.1.11  root      403:                continue;
                    404:            colentry->acolors[i] = CONVERT_RGB (v);
                    405:        }
                    406:     } else {
                    407:         for (i = 0; i < 32; i++) {
                    408:            int v = color_reg_get (colentry, i);
                    409:            if (v < 0 || v > 4095)
                    410:                continue;
                    411:            colentry->acolors[i] = xcolors[v];
                    412:        }
1.1.1.3   root      413:     }
                    414: }
                    415: 
                    416: void notice_new_xcolors (void)
                    417: {
                    418:     int i;
                    419: 
                    420:     docols(&current_colors);
1.1.1.4   root      421: /*    docols(&colors_for_drawing);*/
1.1.1.7   root      422:     for (i = 0; i < (MAXVPOS + 1)*2; i++) {
1.1.1.3   root      423:        docols(color_tables[0]+i);
                    424:        docols(color_tables[1]+i);
                    425:     }
                    426: }
                    427: 
1.1.1.4   root      428: static void do_sprites (int currvp, int currhp);
1.1.1.2   root      429: 
                    430: static void remember_ctable (void)
                    431: {
                    432:     if (remembered_color_entry == -1) {
                    433:        /* The colors changed since we last recorded a color map. Record a
                    434:         * new one. */
1.1.1.11  root      435:        color_reg_cpy (curr_color_tables + next_color_entry, &current_colors);
1.1.1.2   root      436:        remembered_color_entry = next_color_entry++;
                    437:     }
                    438:     thisline_decision.ctable = remembered_color_entry;
                    439:     if (color_src_match == -1 || color_dest_match != remembered_color_entry
                    440:        || line_decisions[next_lineno].ctable != color_src_match)
                    441:     {
                    442:        /* The remembered comparison didn't help us - need to compare again. */
                    443:        int oldctable = line_decisions[next_lineno].ctable;
                    444:        int changed = 0;
                    445: 
1.1.1.3   root      446:        if (oldctable == -1) {
1.1.1.2   root      447:            changed = 1;
                    448:            color_src_match = color_dest_match = -1;
                    449:        } else {
1.1.1.11  root      450:            color_compare_result = color_reg_cmp (&prev_color_tables[oldctable], &current_colors) != 0;
1.1.1.3   root      451:            if (color_compare_result)
                    452:                changed = 1;
                    453:            color_src_match = oldctable;
1.1.1.2   root      454:            color_dest_match = remembered_color_entry;
1.1.1.3   root      455:        }
1.1.1.5   root      456:        thisline_changed |= changed;
1.1.1.3   root      457:     } else {
                    458:        /* We know the result of the comparison */
                    459:        if (color_compare_result)
1.1.1.5   root      460:            thisline_changed = 1;
1.1.1.3   root      461:     }
                    462: }
                    463: 
                    464: static void remember_ctable_for_border (void)
                    465: {
                    466:     remember_ctable ();
1.1.1.2   root      467: }
                    468: 
1.1.1.3   root      469: /* Called to determine the state of the horizontal display window state
                    470:  * machine at the current position. It might have changed since we last
                    471:  * checked.  */
1.1.1.4   root      472: static void decide_diw (int hpos)
1.1.1.2   root      473: {
1.1.1.13  root      474:     int pix_hpos = coord_diw_to_window_x (hpos * 2);
1.1.1.3   root      475:     if (hdiwstate == DIW_waiting_start && thisline_decision.diwfirstword == -1
1.1.1.9   root      476:        && pix_hpos >= diwfirstword && last_diw_pix_hpos < diwfirstword)
1.1.1.3   root      477:     {
1.1.1.13  root      478:        thisline_decision.diwfirstword = diwfirstword < 0 ? 0 : diwfirstword;
1.1.1.3   root      479:        hdiwstate = DIW_waiting_stop;
1.1.1.2   root      480:        thisline_decision.diwlastword = -1;
                    481:     }
1.1.1.3   root      482:     if (hdiwstate == DIW_waiting_stop && thisline_decision.diwlastword == -1
1.1.1.9   root      483:        && pix_hpos >= diwlastword && last_diw_pix_hpos < diwlastword)
1.1.1.3   root      484:     {
1.1.1.13  root      485:        thisline_decision.diwlastword = diwlastword < 0 ? 0 : diwlastword;
1.1.1.3   root      486:        hdiwstate = DIW_waiting_start;
1.1.1.2   root      487:     }
1.1.1.9   root      488:     last_diw_pix_hpos = pix_hpos;
1.1.1.2   root      489: }
                    490: 
1.1.1.13  root      491: /* The HRM says 0xD8, but that can't work... */
                    492: #define HARD_DDF_STOP (0xD4)
1.1.1.2   root      493: 
1.1.1.13  root      494: static void finish_playfield_line (void)
                    495: {
1.1.1.15! root      496:     int m1, m2;
        !           497: 
1.1.1.2   root      498:     /* The latter condition might be able to happen in interlaced frames. */
                    499:     if (vpos >= minfirstline && (thisframe_first_drawn_line == -1 || vpos < thisframe_first_drawn_line))
                    500:        thisframe_first_drawn_line = vpos;
                    501:     thisframe_last_drawn_line = vpos;
                    502: 
1.1.1.15! root      503:     if ((currprefs.chipset_mask & CSMASK_AGA) && (fmode & 0x4000)) {
        !           504:        if (((diwstrt >> 8) ^ vpos) & 1)
        !           505:            m1 = m2 = bpl2mod;
        !           506:        else
        !           507:            m1 = m2 = bpl1mod;
        !           508:     } else {
        !           509:        m1 = bpl1mod;
        !           510:        m2 = bpl2mod;
        !           511:     }
        !           512: 
1.1.1.13  root      513:     if (dmaen (DMA_BITPLANE))
                    514:        switch (nr_planes_from_bplcon0) {
1.1.1.15! root      515:        case 8: bplpt[7] += m2;
        !           516:        case 7: bplpt[6] += m1;
        !           517:        case 6: bplpt[5] += m2;
        !           518:        case 5: bplpt[4] += m1;
        !           519:        case 4: bplpt[3] += m2;
        !           520:        case 3: bplpt[2] += m1;
        !           521:        case 2: bplpt[1] += m2;
        !           522:        case 1: bplpt[0] += m1;
1.1.1.13  root      523:        }
1.1.1.2   root      524: 
                    525:     /* These are for comparison. */
                    526:     thisline_decision.bplcon0 = bplcon0;
                    527:     thisline_decision.bplcon2 = bplcon2;
1.1.1.14  root      528:     thisline_decision.bplcon3 = bplcon3;
1.1.1.2   root      529:     thisline_decision.bplcon4 = bplcon4;
                    530: 
                    531: #ifdef SMART_UPDATE
1.1.1.13  root      532:     if (line_decisions[next_lineno].plflinelen != thisline_decision.plflinelen
                    533:        || line_decisions[next_lineno].plfleft != thisline_decision.plfleft
1.1.1.2   root      534:        || line_decisions[next_lineno].bplcon0 != thisline_decision.bplcon0
                    535:        || line_decisions[next_lineno].bplcon2 != thisline_decision.bplcon2
1.1.1.14  root      536:        || line_decisions[next_lineno].bplcon3 != thisline_decision.bplcon3
1.1.1.2   root      537:        || line_decisions[next_lineno].bplcon4 != thisline_decision.bplcon4
                    538:        )
                    539: #endif /* SMART_UPDATE */
1.1.1.5   root      540:        thisline_changed = 1;
1.1.1.2   root      541: }
                    542: 
1.1.1.15! root      543: static int fetchmode;
1.1.1.14  root      544: 
1.1.1.15! root      545: /* The fetch unit mainly controls ddf stop.  It's the number of cycles that
        !           546:    are contained in an indivisible block during which ddf is active.  E.g.
        !           547:    if DDF starts at 0x30, and fetchunit is 8, then possible DDF stops are
        !           548:    0x30 + n * 8.  */
        !           549: static int fetchunit, fetchunit_mask;
        !           550: /* The delay before fetching the same bitplane again.  Can be larger than
        !           551:    the number of bitplanes; in that case there are additional empty cycles
        !           552:    with no data fetch (this happens for high fetchmodes and low
        !           553:    resolutions).  */
1.1.1.14  root      554: static int fetchstart, fetchstart_shift, fetchstart_mask;
1.1.1.15! root      555: /* fm_maxplane holds the maximum number of planes possible with the current
        !           556:    fetch mode.  This selects the cycle diagram:
        !           557:    8 planes: 73516240
        !           558:    4 planes: 3120
        !           559:    2 planes: 10.  */
1.1.1.14  root      560: static int fm_maxplane, fm_maxplane_shift;
                    561: 
1.1.1.15! root      562: /* The corresponding values, by fetchmode and display resolution.  */
        !           563: static int fetchunits[] = { 8,8,8,0, 16,8,8,0, 32,16,8,0 };
        !           564: static int fetchstarts[] = { 3,2,1,0, 4,3,2,0, 5,4,3,0 };
        !           565: static int fm_maxplanes[] = { 3,2,1,0, 3,3,2,0, 3,3,3,0 }; 
        !           566: 
        !           567: /* Used by the copper.  */
1.1.1.13  root      568: static int estimated_last_fetch_cycle;
1.1.1.15! root      569: static int cycle_diagram_shift;
1.1.1.4   root      570: 
1.1.1.13  root      571: static void estimate_last_fetch_cycle (int hpos)
1.1.1.2   root      572: {
1.1.1.14  root      573:     int fetchunit = fetchunits[fetchmode * 4 + GET_RES (bplcon0)];
                    574: 
1.1.1.13  root      575:     if (! passed_plfstop) {
                    576:        int stop = plfstop < hpos || plfstop > HARD_DDF_STOP ? HARD_DDF_STOP : plfstop;
                    577:        /* We know that fetching is up-to-date up until hpos, so we can use fetch_cycle.  */
                    578:        int fetch_cycle_at_stop = fetch_cycle + (stop - hpos);
1.1.1.14  root      579:        int starting_last_block_at = (fetch_cycle_at_stop + fetchunit - 1) & ~(fetchunit - 1);
1.1.1.13  root      580: 
1.1.1.14  root      581:        estimated_last_fetch_cycle = hpos + (starting_last_block_at - fetch_cycle) + fetchunit;
1.1.1.13  root      582:     } else {
1.1.1.14  root      583:        int starting_last_block_at = (fetch_cycle + fetchunit - 1) & ~(fetchunit - 1);
1.1.1.13  root      584:        if (passed_plfstop == 2)
1.1.1.14  root      585:            starting_last_block_at -= fetchunit;
1.1.1.13  root      586: 
1.1.1.14  root      587:        estimated_last_fetch_cycle = hpos + (starting_last_block_at - fetch_cycle) + fetchunit;
1.1.1.13  root      588:     }
1.1.1.4   root      589: }
                    590: 
1.1.1.14  root      591: static uae_u32 outword[MAX_PLANES];
1.1.1.13  root      592: static int out_nbits, out_offs;
1.1.1.14  root      593: static uae_u32 todisplay[MAX_PLANES][4];
                    594: static uae_u32 fetched[MAX_PLANES];
                    595: static uae_u32 fetched_aga0[MAX_PLANES];
                    596: static uae_u32 fetched_aga1[MAX_PLANES];
1.1.1.13  root      597: 
                    598: /* Expansions from bplcon0/bplcon1.  */
1.1.1.14  root      599: static int toscr_res, toscr_delay1, toscr_delay2, toscr_nr_planes, fetchwidth;
1.1.1.13  root      600: 
1.1.1.14  root      601: /* The number of bits left from the last fetched words.  
                    602:    This is an optimization - conceptually, we have to make sure the result is
                    603:    the same as if toscr is called in each clock cycle.  However, to speed this
                    604:    up, we accumulate display data; this variable keeps track of how much. 
                    605:    Thus, once we do call toscr_nbits (which happens at least every 16 bits),
                    606:    we can do more work at once.  */
1.1.1.13  root      607: static int toscr_nbits;
                    608: 
1.1.1.14  root      609: static int delayoffset;
                    610: 
                    611: STATIC_INLINE void compute_delay_offset (int hpos)
1.1.1.4   root      612: {
1.1.1.14  root      613:     /* this fixes most horizontal scrolling jerkyness but can't be correct */
1.1.1.15! root      614:     delayoffset = ((hpos - fm_maxplane - 0x18) & fetchstart_mask) << 1;
1.1.1.14  root      615:     delayoffset &= ~7;
                    616:     delayoffset &= 31;
1.1.1.13  root      617: }
1.1.1.9   root      618: 
1.1.1.15! root      619: static void expand_fmodes (void)
1.1.1.14  root      620: {
                    621:     int res = GET_RES(bplcon0);
                    622:     int fm = fetchmode;
                    623:     fetchunit = fetchunits[fm * 4 + res];
                    624:     fetchunit_mask = fetchunit - 1;
                    625:     fetchstart_shift = fetchstarts[fm * 4 + res];
                    626:     fetchstart = 1 << fetchstart_shift;
                    627:     fetchstart_mask = fetchstart - 1;
                    628:     fm_maxplane_shift = fm_maxplanes[fm * 4 + res];
                    629:     fm_maxplane = 1 << fm_maxplane_shift;
1.1.1.13  root      630: }
                    631: 
1.1.1.15! root      632: static int maxplanes_ocs[]={ 6,4,0,0 };
        !           633: static int maxplanes_ecs[]={ 6,4,2,0 };
        !           634: static int maxplanes_aga[]={ 8,4,2,0, 8,8,4,0, 8,8,8,0 };
        !           635: 
1.1.1.13  root      636: /* Expand bplcon0/bplcon1 into the toscr_xxx variables.  */
1.1.1.15! root      637: static void compute_toscr_delay_1 (void)
1.1.1.13  root      638: {
                    639:     int delay1 = (bplcon1 & 0x0f) | ((bplcon1 & 0x0c00) >> 6);
                    640:     int delay2 = ((bplcon1 >> 4) & 0x0f) | (((bplcon1 >> 4) & 0x0c00) >> 6);
                    641:     int delaymask;
1.1.1.14  root      642:     int fetchwidth = 16 << fetchmode;
1.1.1.13  root      643: 
1.1.1.14  root      644:     delay1 += delayoffset;
                    645:     delay2 += delayoffset;
                    646:     delaymask = (fetchwidth - 1) >> toscr_res;
1.1.1.13  root      647:     toscr_delay1 = (delay1 & delaymask) << toscr_res;
                    648:     toscr_delay2 = (delay2 & delaymask) << toscr_res;
1.1.1.15! root      649: }
        !           650: 
        !           651: static void compute_toscr_delay (int hpos)
        !           652: {
        !           653:     int v = bplcon0;
        !           654:     int *planes;
        !           655: 
        !           656:     if (currprefs.chipset_mask & CSMASK_AGA)
        !           657:        planes = maxplanes_aga;
        !           658:     else if (! (currprefs.chipset_mask & CSMASK_ECS_DENISE))
        !           659:        planes = maxplanes_ocs;
        !           660:     else
        !           661:        planes = maxplanes_ecs;
        !           662:     /* Disable bitplane DMA if planes > maxplanes.  This is needed e.g. by the
        !           663:        Sanity WOC demo (at the "Party Effect").  */
        !           664:     if (GET_PLANES(v) > planes[fetchmode*4 + GET_RES (v)])
        !           665:        v &= ~0x7010;
        !           666:     toscr_res = GET_RES (v);
        !           667: 
        !           668:     toscr_nr_planes = GET_PLANES (v);
        !           669: 
        !           670:     compute_toscr_delay_1 ();
        !           671: }
        !           672: 
        !           673: STATIC_INLINE void maybe_first_bpl1dat (int hpos)
        !           674: {
        !           675:     if (thisline_decision.plfleft == -1) {
        !           676:        thisline_decision.plfleft = hpos;
        !           677:        compute_delay_offset (hpos);
        !           678:        compute_toscr_delay_1 ();
        !           679:     }
        !           680: }
1.1.1.13  root      681: 
1.1.1.15! root      682: STATIC_INLINE void fetch (int nr, int fm)
        !           683: {
        !           684:     uaecptr p;
        !           685:     if (nr >= toscr_nr_planes)
        !           686:        return;
        !           687:     p = bplpt[nr] + bploff[nr];
        !           688:     switch (fm) {
        !           689:     case 0:
        !           690:        fetched[nr] = chipmem_wget (p);
        !           691:        bplpt[nr] += 2;
        !           692:        break;
        !           693:     case 1:
        !           694:        fetched_aga0[nr] = chipmem_lget (p);
        !           695:        bplpt[nr] += 4;
        !           696:        break;
        !           697:     case 2:
        !           698:        fetched_aga1[nr] = chipmem_lget (p);
        !           699:        fetched_aga0[nr] = chipmem_lget (p + 4);
        !           700:        bplpt[nr] += 8;
        !           701:        break;
        !           702:     }
        !           703:     if (nr == 0)
        !           704:        fetch_state = fetch_was_plane0;
1.1.1.13  root      705: }
                    706: 
                    707: static void clear_fetchbuffer (uae_u32 *ptr, int nwords)
                    708: {
                    709:     int i;
                    710: 
                    711:     if (! thisline_changed)
                    712:        for (i = 0; i < nwords; i++)
                    713:            if (ptr[i]) {
                    714:                thisline_changed = 1;
                    715:                break;
1.1.1.4   root      716:            }
1.1.1.13  root      717: 
                    718:     memset (ptr, 0, nwords * 4);
                    719: }
                    720: 
                    721: static void update_toscr_planes (void)
                    722: {
                    723:     if (toscr_nr_planes > thisline_decision.nr_planes) {
                    724:        int j;
                    725:        for (j = thisline_decision.nr_planes; j < toscr_nr_planes; j++)
                    726:            clear_fetchbuffer ((uae_u32 *)(line_data[next_lineno] + 2 * MAX_WORDS_PER_LINE * j), out_offs);
                    727: #if 0
                    728:        if (thisline_decision.nr_planes > 0)
                    729:            printf ("Planes from %d to %d\n", thisline_decision.nr_planes, toscr_nr_planes);
                    730: #endif
                    731:        thisline_decision.nr_planes = toscr_nr_planes;
1.1.1.4   root      732:     }
                    733: }
1.1.1.2   root      734: 
1.1.1.14  root      735: STATIC_INLINE void toscr_3_ecs (int nbits)
1.1.1.7   root      736: {
1.1.1.13  root      737:     int delay1 = toscr_delay1;
                    738:     int delay2 = toscr_delay2;
                    739:     int i;
                    740:     uae_u32 mask = 0xFFFF >> (16 - nbits);
                    741: 
                    742:     for (i = 0; i < toscr_nr_planes; i += 2) {
                    743:        outword[i] <<= nbits;
1.1.1.14  root      744:        outword[i] |= (todisplay[i][0] >> (16 - nbits + delay1)) & mask;
                    745:        todisplay[i][0] <<= nbits;
1.1.1.13  root      746:     }
                    747:     for (i = 1; i < toscr_nr_planes; i += 2) {
                    748:        outword[i] <<= nbits;
1.1.1.14  root      749:        outword[i] |= (todisplay[i][0] >> (16 - nbits + delay2)) & mask;
                    750:        todisplay[i][0] <<= nbits;
                    751:     }
                    752: }
                    753: 
                    754: STATIC_INLINE void shift32plus (uae_u32 *p, int n)
                    755: {
                    756:     uae_u32 t = p[1];
                    757:     t <<= n;
                    758:     t |= p[0] >> (32 - n);
                    759:     p[1] = t;
                    760: }
                    761: 
                    762: STATIC_INLINE void aga_shift (uae_u32 *p, int n, int fm)
                    763: {
                    764:     if (fm == 2) {
                    765:        shift32plus (p + 2, n);
                    766:        shift32plus (p + 1, n);
1.1.1.13  root      767:     }
1.1.1.14  root      768:     shift32plus (p + 0, n);
                    769:     p[0] <<= n;
                    770: }
                    771: 
                    772: STATIC_INLINE void toscr_3_aga (int nbits, int fm)
                    773: {
                    774:     int delay1 = toscr_delay1;
                    775:     int delay2 = toscr_delay2;
                    776:     int i;
                    777:     uae_u32 mask = 0xFFFF >> (16 - nbits);
                    778: 
                    779:     {
                    780:        int offs = (16 << fm) - nbits + delay1;
                    781:        int off1 = offs >> 5;
                    782:        if (off1 == 3)
                    783:            off1 = 2;
                    784:        offs -= off1 * 32;
                    785:        for (i = 0; i < toscr_nr_planes; i += 2) {
                    786:            uae_u32 t0 = todisplay[i][off1];
                    787:            uae_u32 t1 = todisplay[i][off1 + 1];
                    788:            uae_u64 t = (((uae_u64)t1) << 32) | t0;
                    789:            outword[i] <<= nbits;
                    790:            outword[i] |= (t >> offs) & mask;
                    791:            aga_shift (todisplay[i], nbits, fm);
                    792:        }
                    793:     }
                    794:     {
                    795:        int offs = (16 << fm) - nbits + delay2;
                    796:        int off1 = offs >> 5;
                    797:        if (off1 == 3)
                    798:            off1 = 2;
                    799:        offs -= off1 * 32;
                    800:        for (i = 1; i < toscr_nr_planes; i += 2) {
                    801:            uae_u32 t0 = todisplay[i][off1];
                    802:            uae_u32 t1 = todisplay[i][off1 + 1];
                    803:            uae_u64 t = (((uae_u64)t1) << 32) | t0;
                    804:            outword[i] <<= nbits;
                    805:            outword[i] |= (t >> offs) & mask;
                    806:            aga_shift (todisplay[i], nbits, fm);
                    807:        }
                    808:     }
                    809: }
                    810: 
                    811: static void toscr_2_0 (int nbits) { toscr_3_ecs (nbits); }
                    812: static void toscr_2_1 (int nbits) { toscr_3_aga (nbits, 1); }
                    813: static void toscr_2_2 (int nbits) { toscr_3_aga (nbits, 2); }
                    814: 
                    815: STATIC_INLINE void toscr_1 (int nbits, int fm)
                    816: {
                    817:     switch (fm) {
                    818:     case 0:
                    819:        toscr_2_0 (nbits);
                    820:        break;
                    821:     case 1:
                    822:        toscr_2_1 (nbits);
                    823:        break;
                    824:     case 2:
                    825:        toscr_2_2 (nbits);
                    826:        break;
                    827:     }
                    828: 
1.1.1.13  root      829:     out_nbits += nbits;
                    830:     if (out_nbits == 32) {
1.1.1.14  root      831:        int i;
1.1.1.13  root      832:        uae_u8 *dataptr = line_data[next_lineno] + out_offs * 4;
                    833:        /* Don't use toscr_nr_planes here; if the plane count drops during the
                    834:           line we still want the data to be correct for the full number of planes
                    835:           over the full width of the line.  */
                    836:        for (i = 0; i < thisline_decision.nr_planes; i++) {
                    837:            uae_u32 *dataptr32 = (uae_u32 *)dataptr;
                    838:            if (*dataptr32 != outword[i])
                    839:                thisline_changed = 1;
                    840:            *dataptr32 = outword[i];
                    841:            dataptr += MAX_WORDS_PER_LINE * 2;
                    842:        }
                    843:        out_offs++;
                    844:        out_nbits = 0;
                    845:     }
1.1.1.7   root      846: }
                    847: 
1.1.1.14  root      848: static void toscr_fm0 (int);
                    849: static void toscr_fm1 (int);
                    850: static void toscr_fm2 (int);
                    851: 
                    852: STATIC_INLINE void toscr (int nbits, int fm)
                    853: {
                    854:     switch (fm) {
                    855:     case 0: toscr_fm0 (nbits); break;
                    856:     case 1: toscr_fm1 (nbits); break;
                    857:     case 2: toscr_fm2 (nbits); break;
                    858:     }
                    859: }
                    860: 
                    861: STATIC_INLINE void toscr_0 (int nbits, int fm)
1.1.1.4   root      862: {
1.1.1.13  root      863:     int t;
1.1.1.14  root      864: 
1.1.1.13  root      865:     if (nbits > 16) {
1.1.1.14  root      866:        toscr (16, fm);
1.1.1.13  root      867:        nbits -= 16;
1.1.1.2   root      868:     }
1.1.1.3   root      869: 
1.1.1.13  root      870:     t = 32 - out_nbits;
                    871:     if (t < nbits) {
1.1.1.14  root      872:        toscr_1 (t, fm);
1.1.1.13  root      873:        nbits -= t;
                    874:     }
1.1.1.14  root      875:     toscr_1 (nbits, fm);
1.1.1.13  root      876: }
1.1.1.14  root      877: 
                    878: static void toscr_fm0 (int nbits) { toscr_0 (nbits, 0); }
                    879: static void toscr_fm1 (int nbits) { toscr_0 (nbits, 1); }
                    880: static void toscr_fm2 (int nbits) { toscr_0 (nbits, 2); }
                    881: 
                    882: static int flush_plane_data (int fm)
1.1.1.13  root      883: {
                    884:     int i = 0;
1.1.1.14  root      885:     int fetchwidth = 16 << fm;
1.1.1.4   root      886: 
1.1.1.13  root      887:     if (out_nbits <= 16) {
                    888:        i += 16;
1.1.1.14  root      889:        toscr_1 (16, fm);
1.1.1.13  root      890:     }
                    891:     if (out_nbits != 0) {
                    892:        i += 32 - out_nbits;
1.1.1.14  root      893:        toscr_1 (32 - out_nbits, fm);
1.1.1.4   root      894:     }
1.1.1.13  root      895:     i += 32;
1.1.1.10  root      896: 
1.1.1.14  root      897:     toscr_1 (16, fm);
                    898:     toscr_1 (16, fm);
1.1.1.13  root      899:     return i >> (1 + toscr_res);
                    900: }
                    901: 
1.1.1.14  root      902: STATIC_INLINE void flush_display (int fm)
                    903: {
                    904:     if (toscr_nbits > 0 && thisline_decision.plfleft != -1)
                    905:        toscr (toscr_nbits, fm);
                    906:     toscr_nbits = 0;
                    907: }
                    908: 
                    909: /* Called when all planes have been fetched, i.e. when a new block
                    910:    of data is available to be displayed.  The data in fetched[] is
                    911:    moved into todisplay[].  */
                    912: STATIC_INLINE void beginning_of_plane_block (int pos, int dma, int fm)
                    913: {
                    914:     int i;
                    915: 
                    916:     flush_display (fm);
                    917: 
                    918:     if (fm == 0)
                    919:        for (i = 0; i < MAX_PLANES; i++) 
                    920:            todisplay[i][0] |= fetched[i];
                    921:     else
                    922:        for (i = 0; i < MAX_PLANES; i++) {
                    923:            if (fm == 2)
                    924:                todisplay[i][1] = fetched_aga1[i];
                    925:            todisplay[i][0] = fetched_aga0[i];
                    926:        }
                    927: 
                    928:     maybe_first_bpl1dat (pos);
                    929: }
                    930: 
                    931: #define SPEEDUP
                    932: 
                    933: #ifdef SPEEDUP
                    934: 
1.1.1.13  root      935: /* The usual inlining tricks - don't touch unless you know what you are doing.  */
1.1.1.14  root      936: STATIC_INLINE void long_fetch_ecs (int plane, int nwords, int weird_number_of_bits, int dma)
1.1.1.13  root      937: {
1.1.1.15! root      938:     uae_u16 *real_pt = (uae_u16 *)pfield_xlateptr (bplpt[plane] + bploff[plane], nwords * 2);
1.1.1.14  root      939:     int delay = ((plane & 1) ? toscr_delay2 : toscr_delay1);
1.1.1.13  root      940:     int tmp_nbits = out_nbits;
1.1.1.14  root      941:     uae_u32 shiftbuffer = todisplay[plane][0];
1.1.1.13  root      942:     uae_u32 outval = outword[plane];
                    943:     uae_u32 fetchval = fetched[plane];
                    944:     uae_u32 *dataptr = (uae_u32 *)(line_data[next_lineno] + 2 * plane * MAX_WORDS_PER_LINE + 4 * out_offs);
                    945: 
1.1.1.14  root      946:     if (dma)
                    947:        bplpt[plane] += nwords * 2;
1.1.1.13  root      948: 
                    949:     if (real_pt == 0)
                    950:        /* @@@ Don't do this, fall back on chipmem_wget instead.  */
1.1.1.4   root      951:        return;
                    952: 
1.1.1.13  root      953:     while (nwords > 0) {
                    954:        int bits_left = 32 - tmp_nbits;
1.1.1.14  root      955:        uae_u32 t;
1.1.1.13  root      956: 
                    957:        shiftbuffer |= fetchval;
                    958: 
1.1.1.14  root      959:        t = (shiftbuffer >> delay) & 0xFFFF;
                    960: 
1.1.1.13  root      961:        if (weird_number_of_bits && bits_left < 16) {
                    962:            outval <<= bits_left;
1.1.1.14  root      963:            outval |= t >> (16 - bits_left);
1.1.1.13  root      964:            thisline_changed |= *dataptr ^ outval;
                    965:            *dataptr++ = outval;
                    966: 
1.1.1.14  root      967:            outval = t;
1.1.1.13  root      968:            tmp_nbits = 16 - bits_left;
1.1.1.14  root      969:            shiftbuffer <<= 16;
1.1.1.13  root      970:        } else {
1.1.1.14  root      971:            outval = (outval << 16) | t;
1.1.1.13  root      972:            shiftbuffer <<= 16;
                    973:            tmp_nbits += 16;
                    974:            if (tmp_nbits == 32) {
                    975:                thisline_changed |= *dataptr ^ outval;
                    976:                *dataptr++ = outval;
                    977:                tmp_nbits = 0;
                    978:            }
                    979:        }
                    980:        nwords--;
1.1.1.14  root      981:        if (dma) {
                    982:            fetchval = do_get_mem_word (real_pt);
                    983:            real_pt++;
                    984:        }
1.1.1.13  root      985:     }
                    986:     fetched[plane] = fetchval;
1.1.1.14  root      987:     todisplay[plane][0] = shiftbuffer;
1.1.1.13  root      988:     outword[plane] = outval;
1.1.1.2   root      989: }
                    990: 
1.1.1.14  root      991: STATIC_INLINE void long_fetch_aga (int plane, int nwords, int weird_number_of_bits, int fm, int dma)
                    992: {
1.1.1.15! root      993:     uae_u32 *real_pt = (uae_u32 *)pfield_xlateptr (bplpt[plane] + bploff[plane], nwords * 2);
1.1.1.14  root      994:     int delay = ((plane & 1) ? toscr_delay2 : toscr_delay1);
                    995:     int tmp_nbits = out_nbits;
                    996:     uae_u32 *shiftbuffer = todisplay[plane];
                    997:     uae_u32 outval = outword[plane];
                    998:     uae_u32 fetchval0 = fetched_aga0[plane];
                    999:     uae_u32 fetchval1 = fetched_aga1[plane];
                   1000:     uae_u32 *dataptr = (uae_u32 *)(line_data[next_lineno] + 2 * plane * MAX_WORDS_PER_LINE + 4 * out_offs);
                   1001:     int offs = (16 << fm) - 16 + delay;
                   1002:     int off1 = offs >> 5;
                   1003:     if (off1 == 3)
                   1004:        off1 = 2;
                   1005:     offs -= off1 * 32;
                   1006: 
                   1007:     if (dma)
                   1008:        bplpt[plane] += nwords * 2;
                   1009: 
                   1010:     if (real_pt == 0)
                   1011:        /* @@@ Don't do this, fall back on chipmem_wget instead.  */
                   1012:        return;
                   1013: 
                   1014:     while (nwords > 0) {
                   1015:        int i;
                   1016: 
                   1017:        shiftbuffer[0] = fetchval0;
                   1018:        if (fm == 2)
                   1019:            shiftbuffer[1] = fetchval1;
                   1020: 
                   1021:        for (i = 0; i < (1 << fm); i++) {
                   1022:            int bits_left = 32 - tmp_nbits;
1.1.1.13  root     1023: 
1.1.1.14  root     1024:            uae_u32 t0 = shiftbuffer[off1];
                   1025:            uae_u32 t1 = shiftbuffer[off1 + 1];
                   1026:            uae_u64 t = (((uae_u64)t1) << 32) | t0;
                   1027: 
                   1028:            t0 = (t >> offs) & 0xFFFF;
                   1029: 
                   1030:            if (weird_number_of_bits && bits_left < 16) {
                   1031:                outval <<= bits_left;
                   1032:                outval |= t0 >> (16 - bits_left);
                   1033: 
                   1034:                thisline_changed |= *dataptr ^ outval;
                   1035:                *dataptr++ = outval;
                   1036: 
                   1037:                outval = t0;
                   1038:                tmp_nbits = 16 - bits_left;
                   1039:                aga_shift (shiftbuffer, 16, fm);
                   1040:            } else {
                   1041:                outval = (outval << 16) | t0;
                   1042:                aga_shift (shiftbuffer, 16, fm);
                   1043:                tmp_nbits += 16;
                   1044:                if (tmp_nbits == 32) {
                   1045:                    thisline_changed |= *dataptr ^ outval;
                   1046:                    *dataptr++ = outval;
                   1047:                    tmp_nbits = 0;
                   1048:                }
                   1049:            }
                   1050:        }
                   1051: 
                   1052:        nwords -= 1 << fm;
                   1053: 
                   1054:        if (dma) {
                   1055:            if (fm == 1)
                   1056:                fetchval0 = do_get_mem_long (real_pt);
                   1057:            else {
                   1058:                fetchval1 = do_get_mem_long (real_pt);
                   1059:                fetchval0 = do_get_mem_long (real_pt + 1);
                   1060:            }
                   1061:            real_pt += fm;
                   1062:        }
                   1063:     }
                   1064:     fetched_aga0[plane] = fetchval0;
                   1065:     fetched_aga1[plane] = fetchval1;
                   1066:     outword[plane] = outval;
                   1067: }
                   1068: 
                   1069: static void long_fetch_ecs_0 (int hpos, int nwords, int dma) { long_fetch_ecs (hpos, nwords, 0, dma); }
                   1070: static void long_fetch_ecs_1 (int hpos, int nwords, int dma) { long_fetch_ecs (hpos, nwords, 1, dma); }
                   1071: static void long_fetch_aga_1_0 (int hpos, int nwords, int dma) { long_fetch_aga (hpos, nwords,  0, 1, dma); }
                   1072: static void long_fetch_aga_1_1 (int hpos, int nwords, int dma) { long_fetch_aga (hpos, nwords,  1, 1, dma); }
                   1073: static void long_fetch_aga_2_0 (int hpos, int nwords, int dma) { long_fetch_aga (hpos, nwords,  0, 2, dma); }
                   1074: static void long_fetch_aga_2_1 (int hpos, int nwords, int dma) { long_fetch_aga (hpos, nwords,  1, 2, dma); }
                   1075: 
                   1076: static void do_long_fetch (int hpos, int nwords, int dma, int fm)
1.1.1.2   root     1077: {
1.1.1.14  root     1078:     int added;
1.1.1.13  root     1079:     int i;
1.1.1.2   root     1080: 
1.1.1.14  root     1081:     flush_display (fm);
                   1082:     switch (fm) {
                   1083:     case 0:
                   1084:        if (out_nbits & 15) {
                   1085:            for (i = 0; i < toscr_nr_planes; i++)
                   1086:                long_fetch_ecs_1 (i, nwords, dma);
                   1087:        } else {
                   1088:            for (i = 0; i < toscr_nr_planes; i++)
                   1089:                long_fetch_ecs_0 (i, nwords, dma);
                   1090:        }
                   1091:        break;
                   1092:     case 1:
                   1093:        if (out_nbits & 15) {
                   1094:            for (i = 0; i < toscr_nr_planes; i++)
                   1095:                long_fetch_aga_1_1 (i, nwords, dma);
                   1096:        } else {
                   1097:            for (i = 0; i < toscr_nr_planes; i++)
                   1098:                long_fetch_aga_1_0 (i, nwords, dma);
                   1099:        }
                   1100:        break;
                   1101:     case 2:
                   1102:        if (out_nbits & 15) {
                   1103:            for (i = 0; i < toscr_nr_planes; i++)
                   1104:                long_fetch_aga_2_1 (i, nwords, dma);
                   1105:        } else {
                   1106:            for (i = 0; i < toscr_nr_planes; i++)
                   1107:                long_fetch_aga_2_0 (i, nwords, dma);
                   1108:        }
                   1109:        break;
1.1.1.2   root     1110:     }
1.1.1.13  root     1111: 
1.1.1.14  root     1112:     out_nbits += nwords * 16;
1.1.1.13  root     1113:     out_offs += out_nbits >> 5;
                   1114:     out_nbits &= 31;
1.1.1.14  root     1115: 
                   1116:     if (dma && toscr_nr_planes > 0)
                   1117:        fetch_state = fetch_was_plane0;
1.1.1.13  root     1118: }
                   1119: 
1.1.1.14  root     1120: #endif
1.1.1.13  root     1121: 
1.1.1.14  root     1122: /* make sure fetch that goes beyond maxhpos is finished */
                   1123: static void finish_final_fetch (int i, int fm)
                   1124: {
                   1125:     passed_plfstop = 3;
1.1.1.15! root     1126: 
        !          1127:     if (thisline_decision.plfleft != -1) {
        !          1128:        i += flush_plane_data (fm);
        !          1129:        thisline_decision.plfright = i;
        !          1130:        thisline_decision.plflinelen = out_offs;
        !          1131:        thisline_decision.bplres = toscr_res;
        !          1132:        finish_playfield_line ();
        !          1133:     }
1.1.1.14  root     1134: }
                   1135: 
                   1136: STATIC_INLINE int one_fetch_cycle_0 (int i, int ddfstop_to_test, int dma, int fm)
1.1.1.13  root     1137: {
                   1138:     if (! passed_plfstop && i == ddfstop_to_test)
                   1139:        passed_plfstop = 1;
                   1140: 
1.1.1.14  root     1141:     if ((fetch_cycle & fetchunit_mask) == 0) {
1.1.1.13  root     1142:        if (passed_plfstop == 2) {
1.1.1.14  root     1143:            finish_final_fetch (i, fm);
1.1.1.13  root     1144:            return 1;
                   1145:        }
                   1146:        if (passed_plfstop)
                   1147:            passed_plfstop++;
1.1.1.2   root     1148:     }
1.1.1.13  root     1149:     if (dma) {
1.1.1.14  root     1150:        /* fetchstart_mask can be larger than fm_maxplane if FMODE > 0.  This means
                   1151:           that the remaining cycles are idle; we'll fall through the whole switch
                   1152:           without doing anything.  */
                   1153:        int cycle_start = fetch_cycle & fetchstart_mask;
                   1154:        switch (fm_maxplane) {
                   1155:        case 8:
                   1156:            switch (cycle_start) {
                   1157:            case 0: fetch (7, fm); break;
                   1158:            case 1: fetch (3, fm); break;
                   1159:            case 2: fetch (5, fm); break;
                   1160:            case 3: fetch (1, fm); break;
                   1161:            case 4: fetch (6, fm); break;
                   1162:            case 5: fetch (2, fm); break;
                   1163:            case 6: fetch (4, fm); break;
                   1164:            case 7: fetch (0, fm); break;
                   1165:            }
                   1166:            break;
                   1167:        case 4:
                   1168:            switch (cycle_start) {
                   1169:            case 0: fetch (3, fm); break;
                   1170:            case 1: fetch (1, fm); break;
                   1171:            case 2: fetch (2, fm); break;
                   1172:            case 3: fetch (0, fm); break;
                   1173:            }
                   1174:            break;
                   1175:        case 2:
                   1176:            switch (cycle_start) {
                   1177:            case 0: fetch (1, fm); break;
                   1178:            case 1: fetch (0, fm); break;
                   1179:            }
                   1180:            break;
1.1.1.13  root     1181:        }
1.1.1.2   root     1182:     }
1.1.1.13  root     1183:     fetch_cycle++;
                   1184:     toscr_nbits += 2 << toscr_res;
1.1.1.15! root     1185: 
        !          1186:     if (toscr_nbits == 16)
        !          1187:        flush_display (fm);
        !          1188:     if (toscr_nbits > 16)
        !          1189:        abort ();
        !          1190: 
1.1.1.13  root     1191:     return 0;
                   1192: }
1.1.1.3   root     1193: 
1.1.1.14  root     1194: static int one_fetch_cycle_fm0 (int i, int ddfstop_to_test, int dma) { return one_fetch_cycle_0 (i, ddfstop_to_test, dma, 0); }
                   1195: static int one_fetch_cycle_fm1 (int i, int ddfstop_to_test, int dma) { return one_fetch_cycle_0 (i, ddfstop_to_test, dma, 1); }
                   1196: static int one_fetch_cycle_fm2 (int i, int ddfstop_to_test, int dma) { return one_fetch_cycle_0 (i, ddfstop_to_test, dma, 2); }
1.1.1.13  root     1197: 
1.1.1.14  root     1198: STATIC_INLINE int one_fetch_cycle (int i, int ddfstop_to_test, int dma, int fm)
                   1199: {
                   1200:     switch (fm) {
                   1201:     case 0: return one_fetch_cycle_fm0 (i, ddfstop_to_test, dma);
                   1202:     case 1: return one_fetch_cycle_fm1 (i, ddfstop_to_test, dma);
                   1203:     case 2: return one_fetch_cycle_fm2 (i, ddfstop_to_test, dma);
                   1204:     default: abort ();
                   1205:     }
1.1.1.13  root     1206: }
                   1207: 
1.1.1.14  root     1208: STATIC_INLINE void update_fetch (int until, int fm)
1.1.1.13  root     1209: {
                   1210:     int pos;
                   1211:     int dma = dmaen (DMA_BITPLANE);
                   1212: 
                   1213:     int ddfstop_to_test;
                   1214: 
                   1215:     if (framecnt != 0 || passed_plfstop == 3)
1.1.1.2   root     1216:        return;
1.1.1.13  root     1217: 
                   1218:     /* We need an explicit test against HARD_DDF_STOP here to guard against
                   1219:        programs that move the DDFSTOP before our current position before we
                   1220:        reach it.  */
                   1221:     ddfstop_to_test = HARD_DDF_STOP;
                   1222:     if (ddfstop >= last_fetch_hpos && ddfstop < HARD_DDF_STOP)
                   1223:        ddfstop_to_test = ddfstop;
                   1224: 
1.1.1.14  root     1225:     compute_toscr_delay (last_fetch_hpos);
1.1.1.13  root     1226:     update_toscr_planes ();
                   1227: 
                   1228:     pos = last_fetch_hpos;
1.1.1.15! root     1229:     cycle_diagram_shift = (last_fetch_hpos - fetch_cycle) & 7;
1.1.1.13  root     1230: 
1.1.1.14  root     1231:     /* First, a loop that prepares us for the speedup code.  We want to enter
                   1232:        the SPEEDUP case with fetch_state == fetch_was_plane0, and then unroll
                   1233:        whole blocks, so that we end on the same fetch_state again.  */
1.1.1.13  root     1234:     for (; ; pos++) {
1.1.1.14  root     1235:        if (pos == until) {
                   1236:            if (until >= maxhpos && passed_plfstop == 2) {
                   1237:                finish_final_fetch (pos, fm);
                   1238:                return;
                   1239:            }
                   1240:            flush_display (fm);
                   1241:            return;
                   1242:        }
1.1.1.13  root     1243: 
1.1.1.14  root     1244:        if (fetch_state == fetch_was_plane0)
1.1.1.13  root     1245:            break;
                   1246: 
                   1247:        fetch_state = fetch_started;
1.1.1.14  root     1248:        if (one_fetch_cycle (pos, ddfstop_to_test, dma, fm))
1.1.1.13  root     1249:            return;
1.1.1.14  root     1250:     }
1.1.1.13  root     1251: 
                   1252: #ifdef SPEEDUP
                   1253:     /* Unrolled version of the for loop below.  */
1.1.1.14  root     1254:     if (! passed_plfstop
                   1255:        && dma
1.1.1.15! root     1256:        && (fetch_cycle & fetchstart_mask) == (fm_maxplane & fetchstart_mask)
1.1.1.14  root     1257: # if 0
                   1258:        /* @@@ We handle this case, but the code would be simpler if we
                   1259:         * disallowed it - it may even be possible to guarantee that
                   1260:         * this condition never is false.  Later.  */
                   1261:        && (out_nbits & 15) == 0
                   1262: # endif
                   1263:        && toscr_nr_planes == thisline_decision.nr_planes)
                   1264:     {
1.1.1.15! root     1265:        int offs = (pos - fetch_cycle) & fetchunit_mask;
1.1.1.14  root     1266:        int ddf2 = ((ddfstop_to_test - offs + fetchunit - 1) & ~fetchunit_mask) + offs;
                   1267:        int ddf3 = ddf2 + fetchunit;
                   1268:        int stop = until < ddf2 ? until : until < ddf3 ? ddf2 : ddf3;
                   1269:        int count;
                   1270: 
                   1271:        count = stop - pos;
                   1272: 
                   1273:        if (count >= fetchstart) {
                   1274:            count &= ~fetchstart_mask;
                   1275: 
1.1.1.15! root     1276:            if (thisline_decision.plfleft == -1) {
1.1.1.14  root     1277:                compute_delay_offset (pos);
1.1.1.15! root     1278:                compute_toscr_delay_1 ();
        !          1279:            }
1.1.1.14  root     1280:            do_long_fetch (pos, count >> (3 - toscr_res), dma, fm);
                   1281: 
                   1282:            /* This must come _after_ do_long_fetch so as not to confuse flush_display
                   1283:               into thinking the first fetch has produced any output worth emitting to
                   1284:               the screen.  But the calculation of delay_offset must happen _before_.  */
                   1285:            maybe_first_bpl1dat (pos);
1.1.1.13  root     1286: 
                   1287:            if (pos <= ddfstop_to_test && pos + count > ddfstop_to_test)
                   1288:                passed_plfstop = 1;
1.1.1.14  root     1289:            if (pos <= ddfstop_to_test && pos + count > ddf2)
                   1290:                passed_plfstop = 2;
1.1.1.13  root     1291:            pos += count;
                   1292:            fetch_cycle += count;
                   1293:        }
1.1.1.2   root     1294:     }
                   1295: #endif
1.1.1.13  root     1296:     for (; pos < until; pos++) {
                   1297:        if (fetch_state == fetch_was_plane0)
1.1.1.14  root     1298:            beginning_of_plane_block (pos, dma, fm);
1.1.1.13  root     1299:        fetch_state = fetch_started;
                   1300: 
1.1.1.14  root     1301:        if (one_fetch_cycle (pos, ddfstop_to_test, dma, fm))
1.1.1.13  root     1302:            return;
                   1303:     }
1.1.1.14  root     1304:     if (until >= maxhpos && passed_plfstop == 2) {
                   1305:        finish_final_fetch (pos, fm);
                   1306:        return;
                   1307:     }
                   1308:     flush_display (fm);
1.1.1.2   root     1309: }
                   1310: 
1.1.1.14  root     1311: static void update_fetch_0 (int hpos) { update_fetch (hpos, 0); }
                   1312: static void update_fetch_1 (int hpos) { update_fetch (hpos, 1); }
                   1313: static void update_fetch_2 (int hpos) { update_fetch (hpos, 2); }
                   1314: 
1.1.1.13  root     1315: STATIC_INLINE void decide_fetch (int hpos)
                   1316: {
1.1.1.14  root     1317:     if (fetch_state != fetch_not_started && hpos > last_fetch_hpos) {
                   1318:        switch (fetchmode) {
                   1319:        case 0: update_fetch_0 (hpos); break;
                   1320:        case 1: update_fetch_1 (hpos); break;
                   1321:        case 2: update_fetch_2 (hpos); break;
                   1322:        default: abort ();
                   1323:        }
                   1324:     }
1.1.1.13  root     1325:     last_fetch_hpos = hpos;
                   1326: }
                   1327: 
                   1328: /* This function is responsible for turning on datafetch if necessary.  */
1.1.1.8   root     1329: STATIC_INLINE void decide_line (int hpos)
1.1.1.2   root     1330: {
1.1.1.15! root     1331:     if (hpos <= last_decide_line_hpos)
        !          1332:        return;
1.1.1.13  root     1333:     if (fetch_state != fetch_not_started)
                   1334:        return;
                   1335: 
                   1336:     /* Test if we passed the start of the DDF window.  */
                   1337:     if (last_decide_line_hpos < plfstrt && hpos >= plfstrt) {
                   1338:        /* First, take care of the vertical DIW.  Surprisingly enough, this seems to be
                   1339:           correct here - putting this into decide_diw() results in garbage.  */
                   1340:        if (diwstate == DIW_waiting_start && vpos == plffirstline) {
                   1341:            diwstate = DIW_waiting_stop;
                   1342:        }
                   1343:        if (diwstate == DIW_waiting_stop && vpos == plflastline) {
                   1344:            diwstate = DIW_waiting_start;
                   1345:        }
                   1346: 
1.1.1.15! root     1347:        /* If DMA isn't on by the time we reach plfstrt, then there's no
        !          1348:           bitplane DMA at all for the whole line.  */
        !          1349:        if (dmaen (DMA_BITPLANE)
        !          1350:            && diwstate == DIW_waiting_stop)
        !          1351:        {
1.1.1.13  root     1352:            fetch_state = fetch_started;
                   1353:            fetch_cycle = 0;
                   1354:            last_fetch_hpos = plfstrt;
                   1355:            out_nbits = 0;
                   1356:            out_offs = 0;
                   1357:            toscr_nbits = 0;
                   1358: 
1.1.1.14  root     1359:            compute_toscr_delay (last_fetch_hpos);
1.1.1.13  root     1360: 
                   1361:            /* If someone already wrote BPL1DAT, clear the area between that point and
                   1362:               the real fetch start.  */
1.1.1.14  root     1363:            if (framecnt == 0) {
                   1364:                if (thisline_decision.plfleft != -1) {
                   1365:                    out_nbits = (plfstrt - thisline_decision.plfleft) << (1 + toscr_res);
                   1366:                    out_offs = out_nbits >> 5;
                   1367:                    out_nbits &= 31;
                   1368:                }
                   1369:                update_toscr_planes ();
1.1.1.13  root     1370:            }
                   1371:            estimate_last_fetch_cycle (plfstrt);
                   1372:            last_decide_line_hpos = hpos;
                   1373:            do_sprites (vpos, plfstrt);
                   1374:            return;
                   1375:        }
                   1376:     }
                   1377: 
                   1378:     if (last_decide_line_hpos < 0x34)
                   1379:        do_sprites (vpos, hpos);
                   1380: 
                   1381:     last_decide_line_hpos = hpos;
1.1.1.2   root     1382: }
                   1383: 
1.1.1.3   root     1384: /* Called when a color is about to be changed (write to a color register),
                   1385:  * but the new color has not been entered into the table yet. */
1.1.1.4   root     1386: static void record_color_change (int hpos, int regno, unsigned long value)
1.1.1.3   root     1387: {
                   1388:     /* Early positions don't appear on-screen. */
1.1.1.4   root     1389:     if (framecnt != 0 || vpos < minfirstline || hpos < 0x18
1.1.1.3   root     1390:        /*|| currprefs.emul_accuracy == 0*/)
                   1391:        return;
                   1392: 
1.1.1.4   root     1393:     decide_diw (hpos);
                   1394:     decide_line (hpos);
1.1.1.3   root     1395: 
1.1.1.13  root     1396:     if (thisline_decision.ctable == -1)
                   1397:        remember_ctable ();
1.1.1.3   root     1398: 
                   1399: #ifdef OS_WITHOUT_MEMORY_MANAGEMENT
1.1.1.4   root     1400:     if (next_color_change >= max_color_change) {
1.1.1.3   root     1401:        ++delta_color_change;
                   1402:        return;
                   1403:     }
                   1404: #endif
1.1.1.4   root     1405:     curr_color_changes[next_color_change].linepos = hpos;
1.1.1.3   root     1406:     curr_color_changes[next_color_change].regno = regno;
                   1407:     curr_color_changes[next_color_change++].value = value;
                   1408: }
                   1409: 
1.1.1.15! root     1410: typedef int sprbuf_res_t, cclockres_t, hwres_t, bplres_t;
        !          1411: 
        !          1412: static void do_playfield_collisions (void)
        !          1413: {
        !          1414:     uae_u8 *ld = line_data[next_lineno];
        !          1415:     int i;
        !          1416: 
        !          1417:     if (clxcon_bpl_enable == 0) {
        !          1418:        clxdat |= 1;
        !          1419:        return;
        !          1420:     }
        !          1421:        
        !          1422:     for (i = thisline_decision.plfleft; i < thisline_decision.plfright; i += 2) {
        !          1423:        int j;
        !          1424:        uae_u32 total = 0xFFFFFFFF;
        !          1425:        for (j = 0; j < 8; j++) {
        !          1426:            uae_u32 t = 0;
        !          1427:            if ((clxcon_bpl_enable & (1 << j)) == 0)
        !          1428:                t = 0xFFFFFFFF;
        !          1429:            else if (j < thisline_decision.nr_planes) {
        !          1430:                t = *(uae_u32 *)(line_data[next_lineno] + 2 * i + 2 * j * MAX_WORDS_PER_LINE);
        !          1431:                t ^= ~(((clxcon_bpl_match >> j) & 1) - 1);
        !          1432:            }
        !          1433:            total &= t;
        !          1434:        }
        !          1435:        if (total)
        !          1436:            clxdat |= 1;        
        !          1437:     }
        !          1438: }
        !          1439: 
1.1.1.13  root     1440: /* Sprite-to-sprite collisions are taken care of in record_sprite.  This one does
                   1441:    playfield/sprite collisions.
                   1442:    That's the theory.  In practice this doesn't work yet.  I also suspect this code
                   1443:    is way too slow.  */
                   1444: static void do_sprite_collisions (void)
1.1.1.2   root     1445: {
1.1.1.13  root     1446:     int nr_sprites = curr_drawinfo[next_lineno].nr_sprites;
                   1447:     int first = curr_drawinfo[next_lineno].first_sprite_entry;
                   1448:     int i;
                   1449:     unsigned int collision_mask = clxmask[clxcon >> 12];
1.1.1.15! root     1450:     int bplres = GET_RES (bplcon0);
        !          1451:     hwres_t ddf_left = thisline_decision.plfleft * 2 << bplres;
        !          1452:     hwres_t hw_diwlast = coord_window_to_diw_x (thisline_decision.diwlastword);
        !          1453:     hwres_t hw_diwfirst = coord_window_to_diw_x (thisline_decision.diwfirstword);
        !          1454: 
        !          1455:     if (clxcon_bpl_enable == 0) {
        !          1456:        clxdat |= 0x1FE;
        !          1457:        return;
        !          1458:     }
1.1.1.2   root     1459: 
1.1.1.13  root     1460:     for (i = 0; i < nr_sprites; i++) {
                   1461:        struct sprite_entry *e = curr_sprite_entries + first + i;
1.1.1.15! root     1462:        sprbuf_res_t j;
        !          1463:        sprbuf_res_t minpos = e->pos;
        !          1464:        sprbuf_res_t maxpos = e->max;
        !          1465:        hwres_t minp1 = minpos >> sprite_buffer_res;
        !          1466:        hwres_t maxp1 = maxpos >> sprite_buffer_res;
        !          1467: 
        !          1468:        if (maxp1 > hw_diwlast)
        !          1469:            maxpos = hw_diwlast << sprite_buffer_res;
        !          1470:        if (maxp1 > thisline_decision.plfright * 2)
        !          1471:            maxpos = thisline_decision.plfright * 2 << sprite_buffer_res;
        !          1472:        if (minp1 < hw_diwfirst)
        !          1473:            minpos = hw_diwfirst << sprite_buffer_res;
        !          1474:        if (minp1 < thisline_decision.plfleft * 2)
        !          1475:            minpos = thisline_decision.plfleft * 2 << sprite_buffer_res;
1.1.1.13  root     1476: 
                   1477:        for (j = minpos; j < maxpos; j++) {
                   1478:            int sprpix = spixels[e->first_pixel + j - e->pos] & collision_mask;
                   1479:            int k;
1.1.1.15! root     1480:            int offs;
1.1.1.2   root     1481: 
1.1.1.13  root     1482:            if (sprpix == 0)
                   1483:                continue;
1.1.1.2   root     1484: 
1.1.1.15! root     1485:            offs = ((j << bplres) >> sprite_buffer_res) - ddf_left;
1.1.1.13  root     1486:            sprpix = sprite_ab_merge[sprpix & 255] | (sprite_ab_merge[sprpix >> 8] << 2);
                   1487:            sprpix <<= 1;
1.1.1.2   root     1488: 
1.1.1.13  root     1489:            /* Loop over number of playfields.  */
                   1490:            for (k = 0; k < 2; k++) {
                   1491:                int l;
                   1492:                int match = 1;
1.1.1.14  root     1493:                int planes = ((currprefs.chipset_mask & CSMASK_AGA) ? 8 : 6);
1.1.1.13  root     1494: 
1.1.1.15! root     1495:                for (l = k; match && l < planes; l += 2) {
1.1.1.14  root     1496:                    if (clxcon_bpl_enable & (1 << l)) {
1.1.1.13  root     1497:                        int t = 0;
                   1498:                        if (l < thisline_decision.nr_planes) {
                   1499:                            uae_u32 *ldata = (uae_u32 *)(line_data[next_lineno] + 2 * l * MAX_WORDS_PER_LINE);
                   1500:                            uae_u32 word = ldata[offs >> 5];
                   1501:                            t = (word >> (31 - (offs & 31))) & 1;
                   1502:                        }
1.1.1.14  root     1503:                        if (t != ((clxcon_bpl_match >> l) & 1))
1.1.1.13  root     1504:                            match = 0;
                   1505:                    }
1.1.1.15! root     1506:                }
1.1.1.13  root     1507:                if (match)
                   1508:                    clxdat |= sprpix;
                   1509:                sprpix <<= 4;
                   1510:            }
1.1.1.2   root     1511:        }
                   1512:     }
                   1513: }
                   1514: 
1.1.1.15! root     1515: static void expand_sprres (void)
        !          1516: {
        !          1517:     switch ((bplcon3 >> 6) & 3) {
        !          1518:     case 0: /* ECS defaults (LORES,HIRES=140ns,SHRES=70ns) */
        !          1519:        if ((currprefs.chipset_mask & CSMASK_ECS_DENISE) && GET_RES (bplcon0) == RES_SUPERHIRES)
        !          1520:            sprres = RES_HIRES;
        !          1521:        else
        !          1522:            sprres = RES_LORES;
        !          1523:        break;
        !          1524:     case 1:
        !          1525:        sprres = RES_LORES;
        !          1526:        break;
        !          1527:     case 2:
        !          1528:        sprres = RES_HIRES;
        !          1529:        break;
        !          1530:     case 3:
        !          1531:        sprres = RES_SUPERHIRES;
        !          1532:        break;
        !          1533:     }
        !          1534: }
        !          1535: 
        !          1536: STATIC_INLINE void record_sprite_1 (uae_u16 *buf, uae_u32 datab, int num, int dbl,
        !          1537:                                    unsigned int mask, int do_collisions, uae_u32 collision_mask)
        !          1538: {
        !          1539:     int j = 0;
        !          1540:     while (datab) {
        !          1541:        unsigned int tmp = *buf;
        !          1542:        unsigned int col = (datab & 3) << (2 * num);
        !          1543:        tmp |= col;
        !          1544:        if ((j & mask) == 0)
        !          1545:            *buf++ = tmp;
        !          1546:        if (dbl)
        !          1547:            *buf++ = tmp;
        !          1548:        j++;
        !          1549:        datab >>= 2;
        !          1550:        if (do_collisions) {
        !          1551:            tmp &= collision_mask;
        !          1552:            if (tmp) {
        !          1553:                unsigned int shrunk_tmp = sprite_ab_merge[tmp & 255] | (sprite_ab_merge[tmp >> 8] << 2);
        !          1554:                clxdat |= sprclx[shrunk_tmp];
        !          1555:            }
        !          1556:        }
        !          1557:     }
        !          1558: }
        !          1559: 
1.1.1.13  root     1560: /* DATAB contains the sprite data; 16 pixels in two-bit packets.  Bits 0/1
                   1561:    determine the color of the leftmost pixel, bits 2/3 the color of the next
                   1562:    etc.
                   1563:    This function assumes that for all sprites in a given line, SPRXP either
1.1.1.15! root     1564:    stays equal or increases between successive calls.
        !          1565: 
        !          1566:    The data is recorded either in lores pixels (if ECS), or in hires pixels
        !          1567:    (if AGA).  No support for SHRES sprites.  */
        !          1568: 
        !          1569: static void record_sprite (int line, int num, int sprxp, uae_u16 *data, uae_u16 *datb, unsigned int ctl)
1.1.1.2   root     1570: {
1.1.1.13  root     1571:     struct sprite_entry *e = curr_sprite_entries + next_sprite_entry;
                   1572:     int i;
                   1573:     int word_offs;
                   1574:     uae_u16 *buf;
                   1575:     uae_u32 collision_mask;
1.1.1.15! root     1576:     int width = sprite_width;
        !          1577:     int dbl = 0;
        !          1578:     unsigned int mask = 0;
1.1.1.13  root     1579: 
1.1.1.15! root     1580:     if (sprres != RES_LORES)
        !          1581:        thisline_decision.any_hires_sprites = 1;
        !          1582: 
        !          1583:     if (currprefs.chipset_mask & CSMASK_AGA) {
        !          1584:        width = (width << 1) >> sprres;
        !          1585:        dbl = sprite_buffer_res - sprres;
        !          1586:        mask = sprres == RES_SUPERHIRES ? 1 : 0;
        !          1587:     }
1.1.1.13  root     1588: 
                   1589:     /* Try to coalesce entries if they aren't too far apart.  */
1.1.1.15! root     1590:     if (! next_sprite_forced && e[-1].max + 16 >= sprxp) {
1.1.1.13  root     1591:        e--;
1.1.1.15! root     1592:     } else {
1.1.1.13  root     1593:        next_sprite_entry++;
                   1594:        e->pos = sprxp;
                   1595:        e->has_attached = 0;
                   1596:     }
1.1.1.15! root     1597: 
1.1.1.13  root     1598:     if (sprxp < e->pos)
                   1599:        abort ();
1.1.1.15! root     1600: 
        !          1601:     e->max = sprxp + width;
1.1.1.13  root     1602:     e[1].first_pixel = e->first_pixel + ((e->max - e->pos + 3) & ~3);
                   1603:     next_sprite_forced = 0;
                   1604: 
                   1605:     collision_mask = clxmask[clxcon >> 12];
                   1606:     word_offs = e->first_pixel + sprxp - e->pos;
1.1.1.15! root     1607: 
        !          1608:     for (i = 0; i < sprite_width; i += 16) {
        !          1609:        unsigned int da = *data;
        !          1610:        unsigned int db = *datb;
        !          1611:        uae_u32 datab = ((sprtaba[da & 0xFF] << 16) | sprtaba[da >> 8]
        !          1612:                         | (sprtabb[db & 0xFF] << 16) | sprtabb[db >> 8]);
        !          1613: 
        !          1614:        buf = spixels + word_offs + (i << dbl);
        !          1615:        if (currprefs.collision_level > 0 && collision_mask)
        !          1616:            record_sprite_1 (buf, datab, num, dbl, mask, 1, collision_mask);
        !          1617:        else
        !          1618:            record_sprite_1 (buf, datab, num, dbl, mask, 0, collision_mask);
        !          1619:        data++;
        !          1620:        datb++;
1.1.1.2   root     1621:     }
                   1622: 
1.1.1.13  root     1623:     /* We have 8 bits per pixel in spixstate, two for every sprite pair.  The
                   1624:        low order bit records whether the attach bit was set for this pair.  */
                   1625: 
                   1626:     if (ctl & (num << 7) & 0x80) {
                   1627:        uae_u32 state = 0x01010101 << (num - 1);
                   1628:        uae_u32 *stbuf = spixstate.words + (word_offs >> 2);
                   1629:        uae_u8 *stb1 = spixstate.bytes + word_offs;     
1.1.1.15! root     1630:        for (i = 0; i < width; i += 8) {
        !          1631:            stb1[0] |= state;
        !          1632:            stb1[1] |= state;
        !          1633:            stb1[2] |= state;
        !          1634:            stb1[3] |= state;
        !          1635:            stb1[4] |= state;
        !          1636:            stb1[5] |= state;
        !          1637:            stb1[6] |= state;
        !          1638:            stb1[7] |= state;
        !          1639:            stb1 += 8;
        !          1640:        }
1.1.1.13  root     1641:        e->has_attached = 1;
1.1.1.3   root     1642:     }
                   1643: }
1.1.1.2   root     1644: 
1.1.1.4   root     1645: static void decide_sprites (int hpos)
1.1.1.3   root     1646: {
1.1.1.7   root     1647:     int nrs[MAX_SPRITES], posns[MAX_SPRITES];
                   1648:     int count, i;
1.1.1.15! root     1649:     int point = hpos * 2;
        !          1650:     int width = sprite_width;
        !          1651:     int window_width = (width << lores_shift) >> sprres;
1.1.1.2   root     1652: 
1.1.1.4   root     1653:     if (framecnt != 0 || hpos < 0x14 || nr_armed == 0 || point == last_sprite_point)
1.1.1.2   root     1654:        return;
                   1655: 
1.1.1.4   root     1656:     decide_diw (hpos);
                   1657:     decide_line (hpos);
1.1.1.3   root     1658: 
1.1.1.13  root     1659: #if 0
                   1660:     /* This tries to detect whether the line is border, but that doesn't work, it's too early.  */
                   1661:     if (thisline_decision.plfleft == -1)
1.1.1.2   root     1662:        return;
1.1.1.13  root     1663: #endif
1.1.1.3   root     1664:     count = 0;
1.1.1.15! root     1665:     for (i = 0; i < MAX_SPRITES; i++) {
1.1.1.10  root     1666:        int sprxp = spr[i].xpos;
1.1.1.15! root     1667:        int hw_xp = (sprxp >> sprite_buffer_res);
        !          1668:        int window_xp = coord_hw_to_window_x (hw_xp) + (DIW_DDF_OFFSET << lores_shift);
1.1.1.3   root     1669:        int j, bestp;
1.1.1.2   root     1670: 
1.1.1.15! root     1671:        /* ??? It is uncertain where exactly sprite data is needed.  It appears
        !          1672:           to be used some time after the actual position given in SPRxPOS.
        !          1673:           How soon after is an open question.  For Battle Squadron, using a
        !          1674:           value of 5 seems to be enough to meet all timing constraints.
        !          1675:           This gives it 2 more color clock cycles until the data appears on
        !          1676:           the screen.  */
        !          1677:        hw_xp += 5;
        !          1678:        if (! spr[i].armed || sprxp < 0 || hw_xp <= last_sprite_point || hw_xp > point)
1.1.1.3   root     1679:            continue;
1.1.1.15! root     1680:        if ((thisline_decision.diwfirstword >= 0 && window_xp + window_width < thisline_decision.diwfirstword)
        !          1681:            || (thisline_decision.diwlastword >= 0 && window_xp > thisline_decision.diwlastword))
1.1.1.3   root     1682:            continue;
1.1.1.2   root     1683: 
1.1.1.13  root     1684:        /* Sort the sprites in order of ascending X position before recording them.  */
1.1.1.3   root     1685:        for (bestp = 0; bestp < count; bestp++) {
                   1686:            if (posns[bestp] > sprxp)
                   1687:                break;
                   1688:            if (posns[bestp] == sprxp && nrs[bestp] < i)
                   1689:                break;
                   1690:        }
                   1691:        for (j = count; j > bestp; j--) {
                   1692:            posns[j] = posns[j-1];
                   1693:            nrs[j] = nrs[j-1];
                   1694:        }
                   1695:        posns[j] = sprxp;
                   1696:        nrs[j] = i;
                   1697:        count++;
                   1698:     }
1.1.1.13  root     1699:     for (i = 0; i < count; i++) {
                   1700:        int nr = nrs[i];    
1.1.1.15! root     1701:        record_sprite (next_lineno, nr, spr[nr].xpos, sprdata[nr], sprdatb[nr], sprctl[nr]);
1.1.1.13  root     1702:     }
1.1.1.3   root     1703:     last_sprite_point = point;
1.1.1.2   root     1704: }
                   1705: 
1.1.1.13  root     1706: STATIC_INLINE int sprites_differ (struct draw_info *dip, struct draw_info *dip_old)
                   1707: {
                   1708:     struct sprite_entry *this_first = curr_sprite_entries + dip->first_sprite_entry;
                   1709:     struct sprite_entry *this_last = curr_sprite_entries + dip->last_sprite_entry;
                   1710:     struct sprite_entry *prev_first = prev_sprite_entries + dip_old->first_sprite_entry;
                   1711:     int npixels;
                   1712:     int i;
                   1713: 
                   1714:     if (dip->nr_sprites != dip_old->nr_sprites)
                   1715:        return 1;
                   1716:     
                   1717:     if (dip->nr_sprites == 0)
                   1718:        return 0;
                   1719: 
                   1720:     for (i = 0; i < dip->nr_sprites; i++)
                   1721:        if (this_first[i].pos != prev_first[i].pos
                   1722:            || this_first[i].max != prev_first[i].max
                   1723:            || this_first[i].has_attached != prev_first[i].has_attached)
                   1724:            return 1;
                   1725: 
                   1726:     npixels = this_last->first_pixel + (this_last->max - this_last->pos) - this_first->first_pixel;
                   1727:     if (memcmp (spixels + this_first->first_pixel, spixels + prev_first->first_pixel,
                   1728:                npixels * sizeof (uae_u16)) != 0)
                   1729:        return 1;
                   1730:     if (memcmp (spixstate.bytes + this_first->first_pixel, spixstate.bytes + prev_first->first_pixel, npixels) != 0)
                   1731:        return 1;
                   1732:     return 0;
                   1733: }
                   1734: 
                   1735: STATIC_INLINE int color_changes_differ (struct draw_info *dip, struct draw_info *dip_old)
                   1736: {
                   1737:     if (dip->nr_color_changes != dip_old->nr_color_changes)
                   1738:        return 1;
                   1739:     
                   1740:     if (dip->nr_color_changes == 0)
                   1741:        return 0;
                   1742:     if (memcmp (curr_color_changes + dip->first_color_change,
                   1743:                prev_color_changes + dip_old->first_color_change,
                   1744:                dip->nr_color_changes * sizeof *curr_color_changes) != 0)
                   1745:        return 1;
                   1746:     return 0;
                   1747: }
                   1748: 
1.1.1.3   root     1749: /* End of a horizontal scan line. Finish off all decisions that were not
                   1750:  * made yet. */
1.1.1.2   root     1751: static void finish_decisions (void)
                   1752: {
                   1753:     struct draw_info *dip;
                   1754:     struct draw_info *dip_old;
                   1755:     struct decision *dp;
                   1756:     int changed;
1.1.1.4   root     1757:     int hpos = current_hpos ();
1.1.1.2   root     1758: 
                   1759:     if (framecnt != 0)
                   1760:        return;
                   1761: 
1.1.1.4   root     1762:     decide_diw (hpos);
1.1.1.13  root     1763:     decide_line (hpos);
                   1764:     decide_fetch (hpos);
                   1765: 
                   1766:     if (thisline_decision.plfleft != -1 && thisline_decision.plflinelen == -1) {
                   1767:        if (fetch_state != fetch_not_started)
                   1768:            abort ();
                   1769:        thisline_decision.plfright = thisline_decision.plfleft;
                   1770:        thisline_decision.plflinelen = 0;
                   1771:        thisline_decision.bplres = RES_LORES;
                   1772:     }
1.1.1.3   root     1773: 
                   1774:     /* Large DIWSTOP values can cause the stop position never to be
                   1775:      * reached, so the state machine always stays in the same state and
                   1776:      * there's a more-or-less full-screen DIW. */
1.1.1.13  root     1777:     if (hdiwstate == DIW_waiting_stop || thisline_decision.diwlastword > max_diwlastword)
1.1.1.3   root     1778:        thisline_decision.diwlastword = max_diwlastword;
                   1779: 
1.1.1.13  root     1780:     if (thisline_decision.diwfirstword != line_decisions[next_lineno].diwfirstword)
                   1781:        MARK_LINE_CHANGED;
                   1782:     if (thisline_decision.diwlastword != line_decisions[next_lineno].diwlastword)
                   1783:        MARK_LINE_CHANGED;
1.1.1.2   root     1784: 
                   1785:     dip = curr_drawinfo + next_lineno;
                   1786:     dip_old = prev_drawinfo + next_lineno;
                   1787:     dp = line_decisions + next_lineno;
1.1.1.5   root     1788:     changed = thisline_changed;
1.1.1.2   root     1789: 
1.1.1.13  root     1790:     if (thisline_decision.plfleft != -1) {
                   1791:        record_diw_line (thisline_decision.diwfirstword, thisline_decision.diwlastword);
1.1.1.2   root     1792: 
1.1.1.4   root     1793:        decide_sprites (hpos);
1.1.1.2   root     1794:     }
                   1795: 
1.1.1.13  root     1796:     dip->last_sprite_entry = next_sprite_entry;
1.1.1.2   root     1797:     dip->last_color_change = next_color_change;
1.1.1.3   root     1798: 
                   1799:     if (thisline_decision.ctable == -1) {
1.1.1.13  root     1800:        if (thisline_decision.plfleft == -1)
1.1.1.3   root     1801:            remember_ctable_for_border ();
1.1.1.13  root     1802:        else
                   1803:            remember_ctable ();
1.1.1.3   root     1804:     }
1.1.1.2   root     1805: 
                   1806:     dip->nr_color_changes = next_color_change - dip->first_color_change;
1.1.1.13  root     1807:     dip->nr_sprites = next_sprite_entry - dip->first_sprite_entry;
1.1.1.2   root     1808: 
1.1.1.13  root     1809:     if (thisline_decision.plfleft != line_decisions[next_lineno].plfleft)
1.1.1.2   root     1810:        changed = 1;
1.1.1.13  root     1811:     if (! changed && color_changes_differ (dip, dip_old))
1.1.1.2   root     1812:        changed = 1;
1.1.1.13  root     1813:     if (!changed && thisline_decision.plfleft != -1 && sprites_differ (dip, dip_old))
1.1.1.10  root     1814:        changed = 1;
1.1.1.2   root     1815: 
                   1816:     if (changed) {
1.1.1.5   root     1817:        thisline_changed = 1;
1.1.1.2   root     1818:        *dp = thisline_decision;
                   1819:     } else
                   1820:        /* The only one that may differ: */
                   1821:        dp->ctable = thisline_decision.ctable;
                   1822: }
                   1823: 
1.1.1.3   root     1824: /* Set the state of all decisions to "undecided" for a new scanline. */
1.1.1.2   root     1825: static void reset_decisions (void)
                   1826: {
                   1827:     if (framecnt != 0)
                   1828:        return;
1.1.1.13  root     1829: 
1.1.1.15! root     1830:     thisline_decision.any_hires_sprites = 0;
1.1.1.13  root     1831:     thisline_decision.nr_planes = 0;
                   1832: 
1.1.1.10  root     1833:     thisline_decision.plfleft = -1;
1.1.1.13  root     1834:     thisline_decision.plflinelen = -1;
1.1.1.10  root     1835: 
1.1.1.7   root     1836:     /* decided_res shouldn't be touched before it's initialized by decide_line(). */
1.1.1.2   root     1837:     thisline_decision.diwfirstword = -1;
                   1838:     thisline_decision.diwlastword = -2;
1.1.1.3   root     1839:     if (hdiwstate == DIW_waiting_stop) {
1.1.1.13  root     1840:        thisline_decision.diwfirstword = 0;
1.1.1.3   root     1841:        if (thisline_decision.diwfirstword != line_decisions[next_lineno].diwfirstword)
1.1.1.5   root     1842:            MARK_LINE_CHANGED;
1.1.1.3   root     1843:     }
1.1.1.2   root     1844:     thisline_decision.ctable = -1;
                   1845: 
1.1.1.5   root     1846:     thisline_changed = 0;
1.1.1.2   root     1847:     curr_drawinfo[next_lineno].first_color_change = next_color_change;
1.1.1.13  root     1848:     curr_drawinfo[next_lineno].first_sprite_entry = next_sprite_entry;
                   1849:     next_sprite_forced = 1;
1.1.1.2   root     1850: 
1.1.1.3   root     1851:     /* memset(sprite_last_drawn_at, 0, sizeof sprite_last_drawn_at); */
                   1852:     last_sprite_point = 0;
1.1.1.13  root     1853:     fetch_state = fetch_not_started;
                   1854:     passed_plfstop = 0;
                   1855: 
                   1856:     memset (todisplay, 0, sizeof todisplay);
                   1857:     memset (fetched, 0, sizeof fetched);
1.1.1.14  root     1858:     memset (fetched_aga0, 0, sizeof fetched_aga0);
                   1859:     memset (fetched_aga1, 0, sizeof fetched_aga1);
1.1.1.13  root     1860:     memset (outword, 0, sizeof outword);
1.1.1.9   root     1861: 
1.1.1.13  root     1862:     last_decide_line_hpos = -1;
1.1.1.9   root     1863:     last_diw_pix_hpos = -1;
                   1864:     last_ddf_pix_hpos = -1;
1.1.1.13  root     1865:     last_sprite_hpos = -1;
                   1866:     last_fetch_hpos = -1;
1.1.1.2   root     1867: }
                   1868: 
1.1.1.7   root     1869: /* set PAL or NTSC timing variables */
                   1870: 
                   1871: static void init_hz (void)
                   1872: {
                   1873:     int isntsc;
                   1874: 
                   1875:     beamcon0 = new_beamcon0;
                   1876: 
                   1877:     isntsc = beamcon0 & 0x20 ? 0 : 1;
                   1878:     if (!isntsc) {
                   1879:        maxvpos = MAXVPOS_PAL;
                   1880:        maxhpos = MAXHPOS_PAL;
                   1881:        minfirstline = MINFIRSTLINE_PAL;
                   1882:        vblank_endline = VBLANK_ENDLINE_PAL;
                   1883:        vblank_hz = VBLANK_HZ_PAL;
                   1884:     } else {
                   1885:        maxvpos = MAXVPOS_NTSC;
                   1886:        maxhpos = MAXHPOS_NTSC;
                   1887:        minfirstline = MINFIRSTLINE_NTSC;
                   1888:        vblank_endline = VBLANK_ENDLINE_NTSC;
                   1889:        vblank_hz = VBLANK_HZ_NTSC;
                   1890:     }
                   1891:     vsynctime = syncbase / vblank_hz;
                   1892: 
                   1893:     write_log ("Using %s timing\n", isntsc ? "NTSC" : "PAL");
                   1894: }
                   1895: 
1.1.1.11  root     1896: static void calcdiw (void)
                   1897: {
1.1.1.4   root     1898:     int hstrt = diwstrt & 0xFF;
                   1899:     int hstop = diwstop & 0xFF;
                   1900:     int vstrt = diwstrt >> 8;
                   1901:     int vstop = diwstop >> 8;
                   1902: 
                   1903:     if (diwhigh_written) {
                   1904:        hstrt |= ((diwhigh >> 5) & 1) << 8;
                   1905:        hstop |= ((diwhigh >> 13) & 1) << 8;
                   1906:        vstrt |= (diwhigh & 7) << 8;
                   1907:        vstop |= ((diwhigh >> 8) & 7) << 8;
                   1908:     } else {
                   1909:        hstop += 0x100;
                   1910:        if ((vstop & 0x80) == 0)
                   1911:            vstop |= 0x100;
                   1912:     }
                   1913: 
1.1.1.13  root     1914:     diwfirstword = coord_diw_to_window_x (hstrt);
                   1915:     diwlastword = coord_diw_to_window_x (hstop);
1.1.1.2   root     1916:     if (diwfirstword < 0)
                   1917:        diwfirstword = 0;
1.1.1.3   root     1918: 
1.1.1.4   root     1919:     plffirstline = vstrt;
                   1920:     plflastline = vstop;
                   1921: 
1.1       root     1922: #if 0
                   1923:     /* This happens far too often. */
                   1924:     if (plffirstline < minfirstline) {
                   1925:        fprintf(stderr, "Warning: Playfield begins before line %d!\n", minfirstline);
                   1926:        plffirstline = minfirstline;
                   1927:     }
                   1928: #endif
1.1.1.4   root     1929: 
1.1       root     1930: #if 0 /* Turrican does this */
                   1931:     if (plflastline > 313) {
1.1.1.4   root     1932:        fprintf (stderr, "Warning: Playfield out of range!\n");
1.1       root     1933:        plflastline = 313;
                   1934:     }
                   1935: #endif
1.1.1.2   root     1936:     plfstrt = ddfstrt;
                   1937:     plfstop = ddfstop;
1.1.1.13  root     1938:     if (plfstrt < 0x18)
                   1939:        plfstrt = 0x18;
1.1       root     1940: }
                   1941: 
1.1.1.4   root     1942: /* Mousehack stuff */
1.1.1.2   root     1943: 
1.1.1.4   root     1944: #define defstepx (1<<16)
                   1945: #define defstepy (1<<16)
                   1946: #define defxoffs 0
                   1947: #define defyoffs 0
1.1.1.3   root     1948: 
1.1.1.4   root     1949: static const int docal = 60, xcaloff = 40, ycaloff = 20;
                   1950: static const int calweight = 3;
                   1951: static int lastsampledmx, lastsampledmy;
                   1952: static int lastspr0x,lastspr0y,lastdiffx,lastdiffy,spr0pos,spr0ctl;
                   1953: static int mstepx,mstepy,xoffs=defxoffs,yoffs=defyoffs;
                   1954: static int sprvbfl;
1.1.1.2   root     1955: 
1.1.1.4   root     1956: int lastmx, lastmy;
                   1957: int newmousecounters;
                   1958: int ievent_alive = 0;
1.1       root     1959: 
1.1.1.4   root     1960: static enum { unknown_mouse, normal_mouse, dont_care_mouse, follow_mouse } mousestate;
1.1       root     1961: 
1.1.1.4   root     1962: static void mousehack_setdontcare (void)
1.1       root     1963: {
1.1.1.4   root     1964:     if (mousestate == dont_care_mouse)
1.1.1.2   root     1965:        return;
                   1966: 
1.1.1.3   root     1967:     write_log ("Don't care mouse mode set\n");
                   1968:     mousestate = dont_care_mouse;
                   1969:     lastspr0x = lastmx; lastspr0y = lastmy;
                   1970:     mstepx = defstepx; mstepy = defstepy;
                   1971: }
                   1972: 
1.1.1.4   root     1973: static void mousehack_setfollow (void)
1.1.1.3   root     1974: {
1.1.1.4   root     1975:     if (mousestate == follow_mouse)
                   1976:        return;
                   1977: 
1.1.1.3   root     1978:     write_log ("Follow sprite mode set\n");
                   1979:     mousestate = follow_mouse;
                   1980:     lastdiffx = lastdiffy = 0;
                   1981:     sprvbfl = 0;
1.1.1.4   root     1982:     spr0ctl = spr0pos = 0;
1.1.1.3   root     1983:     mstepx = defstepx; mstepy = defstepy;
                   1984: }
                   1985: 
1.1.1.7   root     1986: static uae_u32 mousehack_helper (void)
1.1.1.3   root     1987: {
                   1988:     int mousexpos, mouseypos;
                   1989: 
                   1990: #ifdef PICASSO96
                   1991:     if (picasso_on) {
1.1.1.4   root     1992:        mousexpos = lastmx - picasso96_state.XOffset;
                   1993:        mouseypos = lastmy - picasso96_state.YOffset;
1.1.1.3   root     1994:     } else
                   1995: #endif
                   1996:     {
                   1997:        if (lastmy >= gfxvidinfo.height)
1.1.1.4   root     1998:            lastmy = gfxvidinfo.height - 1;
                   1999:        mouseypos = coord_native_to_amiga_y (lastmy) << 1;
                   2000:        mousexpos = coord_native_to_amiga_x (lastmx);
1.1.1.3   root     2001:     }
                   2002: 
                   2003:     switch (m68k_dreg (regs, 0)) {
1.1.1.15! root     2004:     case 0:
1.1.1.3   root     2005:        return ievent_alive ? -1 : needmousehack ();
1.1.1.15! root     2006:     case 1:
1.1.1.3   root     2007:        ievent_alive = 10;
                   2008:        return mousexpos;
1.1.1.15! root     2009:     case 2:
1.1.1.3   root     2010:        return mouseypos;
                   2011:     }
                   2012:     return 0;
                   2013: }
                   2014: 
1.1.1.4   root     2015: void togglemouse (void)
1.1.1.3   root     2016: {
1.1.1.4   root     2017:     switch (mousestate) {
                   2018:      case dont_care_mouse: mousehack_setfollow (); break;
                   2019:      case follow_mouse: mousehack_setdontcare (); break;
1.1.1.3   root     2020:      default: break; /* Nnnnnghh! */
                   2021:     }
                   2022: }
                   2023: 
1.1.1.8   root     2024: STATIC_INLINE int adjust (int val)
1.1.1.3   root     2025: {
1.1.1.4   root     2026:     if (val > 127)
1.1.1.3   root     2027:        return 127;
1.1.1.4   root     2028:     else if (val < -127)
1.1.1.3   root     2029:        return -127;
                   2030:     return val;
                   2031: }
                   2032: 
1.1.1.4   root     2033: static void do_mouse_hack (void)
1.1.1.3   root     2034: {
                   2035:     int spr0x = ((spr0pos & 0xff) << 2) | ((spr0ctl & 1) << 1);
                   2036:     int spr0y = ((spr0pos >> 8) | ((spr0ctl & 4) << 6)) << 1;
                   2037:     int diffx, diffy;
                   2038: 
                   2039:     if (ievent_alive > 0) {
                   2040:        mouse_x = mouse_y = 0;
                   2041:        return;
                   2042:     }
                   2043:     switch (mousestate) {
1.1.1.11  root     2044:     case normal_mouse:
1.1.1.3   root     2045:        diffx = lastmx - lastsampledmx;
                   2046:        diffy = lastmy - lastsampledmy;
                   2047:        if (!newmousecounters) {
                   2048:            if (diffx > 127) diffx = 127;
                   2049:            if (diffx < -127) diffx = -127;
                   2050:            mouse_x += diffx;
                   2051:            if (diffy > 127) diffy = 127;
                   2052:            if (diffy < -127) diffy = -127;
                   2053:            mouse_y += diffy;
                   2054:        }
                   2055:        lastsampledmx += diffx; lastsampledmy += diffy;
                   2056:        break;
                   2057: 
1.1.1.11  root     2058:     case dont_care_mouse:
1.1.1.4   root     2059:        diffx = adjust (((lastmx - lastspr0x) * mstepx) >> 16);
                   2060:        diffy = adjust (((lastmy - lastspr0y) * mstepy) >> 16);
                   2061:        lastspr0x = lastmx; lastspr0y = lastmy;
                   2062:        mouse_x += diffx; mouse_y += diffy;
1.1.1.3   root     2063:        break;
                   2064: 
1.1.1.11  root     2065:     case follow_mouse:
1.1.1.4   root     2066:        if (sprvbfl && sprvbfl-- > 1) {
1.1.1.3   root     2067:            int mousexpos, mouseypos;
                   2068: 
1.1.1.4   root     2069:            if ((lastdiffx > docal || lastdiffx < -docal)
                   2070:                && lastspr0x != spr0x
                   2071:                && spr0x > plfstrt*4 + 34 + xcaloff
                   2072:                && spr0x < plfstop*4 - xcaloff)
1.1.1.3   root     2073:            {
                   2074:                int val = (lastdiffx << 16) / (spr0x - lastspr0x);
1.1.1.4   root     2075:                if (val >= 0x8000)
                   2076:                    mstepx = (mstepx * (calweight - 1) + val) / calweight;
1.1.1.3   root     2077:            }
1.1.1.4   root     2078:            if ((lastdiffy > docal || lastdiffy < -docal)
                   2079:                && lastspr0y != spr0y
                   2080:                && spr0y > plffirstline + ycaloff
                   2081:                && spr0y < plflastline - ycaloff)
1.1.1.3   root     2082:            {
1.1.1.4   root     2083:                int val = (lastdiffy << 16) / (spr0y - lastspr0y);
                   2084:                if (val >= 0x8000)
                   2085:                    mstepy = (mstepy * (calweight - 1) + val) / calweight;
1.1.1.3   root     2086:            }
                   2087:            if (lastmy >= gfxvidinfo.height)
                   2088:                lastmy = gfxvidinfo.height-1;
1.1.1.4   root     2089:            mouseypos = coord_native_to_amiga_y (lastmy) << 1;
                   2090:            mousexpos = coord_native_to_amiga_x (lastmx);
1.1.1.3   root     2091:            diffx = adjust ((((mousexpos + xoffs - spr0x) & ~1) * mstepx) >> 16);
                   2092:            diffy = adjust ((((mouseypos + yoffs - spr0y) & ~1) * mstepy) >> 16);
1.1.1.4   root     2093:            lastspr0x = spr0x; lastspr0y = spr0y;
                   2094:            lastdiffx = diffx; lastdiffy = diffy;
                   2095:            mouse_x += diffx; mouse_y += diffy;
1.1.1.3   root     2096:        }
                   2097:        break;
1.1.1.4   root     2098:        
1.1.1.11  root     2099:     default:
1.1.1.4   root     2100:        abort ();
1.1.1.3   root     2101:     }
                   2102: }
                   2103: 
1.1.1.7   root     2104: static int timehack_alive = 0;
                   2105: 
                   2106: static uae_u32 timehack_helper (void)
                   2107: {
                   2108: #ifdef HAVE_GETTIMEOFDAY
                   2109:     struct timeval tv;
                   2110:     if (m68k_dreg (regs, 0) == 0)
                   2111:        return timehack_alive;
                   2112: 
                   2113:     timehack_alive = 10;
                   2114: 
                   2115:     gettimeofday (&tv, NULL);
                   2116:     put_long (m68k_areg (regs, 0), tv.tv_sec - (((365 * 8 + 2) * 24 - 2) * 60 * 60));
                   2117:     put_long (m68k_areg (regs, 0) + 4, tv.tv_usec);
                   2118:     return 0;
                   2119: #else
                   2120:     return 2;
                   2121: #endif
                   2122: }
                   2123: 
1.1.1.3   root     2124:  /*
1.1       root     2125:   * register functions
                   2126:   */
1.1.1.8   root     2127: STATIC_INLINE uae_u16 DENISEID (void)
1.1.1.7   root     2128: {
                   2129:     if (currprefs.chipset_mask & CSMASK_AGA)
                   2130:        return 0xF8;
                   2131:     if (currprefs.chipset_mask & CSMASK_ECS_DENISE)
                   2132:        return 0xFC;
                   2133:     return 0xFFFF;
                   2134: }
1.1.1.8   root     2135: STATIC_INLINE uae_u16 DMACONR (void)
1.1       root     2136: {
                   2137:     return (dmacon | (bltstate==BLT_done ? 0 : 0x4000)
                   2138:            | (blt_info.blitzero ? 0x2000 : 0));
                   2139: }
1.1.1.8   root     2140: STATIC_INLINE uae_u16 INTENAR (void)
1.1.1.4   root     2141: {
                   2142:     return intena;
                   2143: }
                   2144: uae_u16 INTREQR (void)
1.1       root     2145: {
1.1.1.9   root     2146:     return intreq /* | (currprefs.use_serial ? 0x0001 : 0) */;
1.1       root     2147: }
1.1.1.8   root     2148: STATIC_INLINE uae_u16 ADKCONR (void)
1.1.1.4   root     2149: {
                   2150:     return adkcon;
                   2151: }
1.1.1.8   root     2152: STATIC_INLINE uae_u16 VPOSR (void)
1.1       root     2153: {
1.1.1.14  root     2154:     unsigned int csbit = currprefs.ntscmode ? 0x1000 : 0;
1.1.1.7   root     2155:     csbit |= (currprefs.chipset_mask & CSMASK_AGA) ? 0x2300 : 0;
                   2156:     csbit |= (currprefs.chipset_mask & CSMASK_ECS_AGNUS) ? 0x2000 : 0;
                   2157:     return (vpos >> 8) | lof | csbit;
1.1       root     2158: }
1.1.1.4   root     2159: static void VPOSW (uae_u16 v)
1.1.1.2   root     2160: {
                   2161:     if (lof != (v & 0x8000))
                   2162:        lof_changed = 1;
                   2163:     lof = v & 0x8000;
1.1.1.3   root     2164:     /*
                   2165:      * This register is much more fun on a real Amiga. You can program
                   2166:      * refresh rates with it ;) But I won't emulate this...
                   2167:      */
1.1.1.2   root     2168: }
1.1       root     2169: 
1.1.1.8   root     2170: STATIC_INLINE uae_u16 VHPOSR (void)
1.1.1.4   root     2171: {
1.1.1.13  root     2172:     return (vpos << 8) | current_hpos ();
1.1.1.4   root     2173: }
                   2174: 
1.1.1.8   root     2175: STATIC_INLINE void COP1LCH (uae_u16 v) { cop1lc = (cop1lc & 0xffff) | ((uae_u32)v << 16); }
                   2176: STATIC_INLINE void COP1LCL (uae_u16 v) { cop1lc = (cop1lc & ~0xffff) | (v & 0xfffe); }
                   2177: STATIC_INLINE void COP2LCH (uae_u16 v) { cop2lc = (cop2lc & 0xffff) | ((uae_u32)v << 16); }
                   2178: STATIC_INLINE void COP2LCL (uae_u16 v) { cop2lc = (cop2lc & ~0xffff) | (v & 0xfffe); }
1.1.1.4   root     2179: 
1.1.1.9   root     2180: static void start_copper (void)
1.1.1.4   root     2181: {
1.1.1.10  root     2182:     int was_active = eventtab[ev_copper].active;
                   2183:     eventtab[ev_copper].active = 0;
                   2184:     if (was_active)
                   2185:        events_schedule ();
                   2186: 
1.1.1.4   root     2187:     cop_state.ignore_next = 0;
                   2188:     cop_state.state = COP_read1;
                   2189:     cop_state.vpos = vpos;
                   2190:     cop_state.hpos = current_hpos () & ~1;
1.1.1.9   root     2191: 
1.1.1.10  root     2192:     if (dmaen (DMA_COPPER)) {
                   2193:        copper_enabled_thisline = 1;
1.1.1.13  root     2194:        set_special (SPCFLAG_COPPER);
1.1.1.10  root     2195:     }
1.1.1.9   root     2196: }
                   2197: 
                   2198: static void COPJMP1 (uae_u16 a)
                   2199: {
                   2200:     cop_state.ip = cop1lc;
                   2201:     start_copper ();
1.1.1.4   root     2202: }
                   2203: 
                   2204: static void COPJMP2 (uae_u16 a)
                   2205: {
                   2206:     cop_state.ip = cop2lc;
1.1.1.9   root     2207:     start_copper ();
1.1.1.4   root     2208: }
                   2209: 
1.1.1.8   root     2210: STATIC_INLINE void COPCON (uae_u16 a)
1.1.1.4   root     2211: {
                   2212:     copcon = a;
1.1       root     2213: }
1.1.1.4   root     2214: 
1.1.1.13  root     2215: static void DMACON (int hpos, uae_u16 v)
1.1       root     2216: {
1.1.1.14  root     2217:     int i;
1.1       root     2218: 
1.1.1.3   root     2219:     uae_u16 oldcon = dmacon;
                   2220: 
1.1.1.13  root     2221:     decide_line (hpos);
                   2222:     decide_fetch (hpos);
                   2223: 
                   2224:     setclr (&dmacon, v);
                   2225:     dmacon &= 0x1FFF;
1.1.1.3   root     2226: 
                   2227:     /* FIXME? Maybe we need to think a bit more about the master DMA enable
1.1       root     2228:      * bit in these cases. */
1.1.1.10  root     2229:     if ((dmacon & DMA_COPPER) != (oldcon & DMA_COPPER)) {
                   2230:        eventtab[ev_copper].active = 0;
                   2231:     }
1.1.1.3   root     2232:     if ((dmacon & DMA_COPPER) > (oldcon & DMA_COPPER)) {
1.1.1.4   root     2233:        cop_state.ip = cop1lc;
                   2234:        cop_state.ignore_next = 0;
                   2235:        cop_state.state = COP_read1;
                   2236:        cop_state.vpos = vpos;
1.1.1.13  root     2237:        cop_state.hpos = hpos & ~1;
1.1.1.10  root     2238:        copper_enabled_thisline = 1;
1.1.1.13  root     2239:        set_special (SPCFLAG_COPPER);
1.1       root     2240:     }
1.1.1.9   root     2241:     if (! (dmacon & DMA_COPPER)) {
1.1.1.10  root     2242:        copper_enabled_thisline = 0;
1.1.1.13  root     2243:        unset_special (SPCFLAG_COPPER);
1.1.1.9   root     2244:        cop_state.state = COP_stop;
                   2245:     }
                   2246: 
1.1       root     2247:     if ((dmacon & DMA_BLITPRI) > (oldcon & DMA_BLITPRI) && bltstate != BLT_done) {
                   2248:        static int count = 0;
                   2249:        if (!count) {
                   2250:            count = 1;
1.1.1.3   root     2251:            write_log ("warning: program is doing blitpri hacks.\n");
1.1       root     2252:        }
1.1.1.13  root     2253:        set_special (SPCFLAG_BLTNASTY);
1.1       root     2254:     }
1.1.1.10  root     2255:     if ((dmacon & (DMA_BLITPRI | DMA_BLITTER | DMA_MASTER)) != (DMA_BLITPRI | DMA_BLITTER | DMA_MASTER))
1.1.1.13  root     2256:        unset_special (SPCFLAG_BLTNASTY);
1.1.1.4   root     2257: 
1.1.1.14  root     2258:     if (currprefs.produce_sound > 0) {
                   2259:        update_audio ();
1.1.1.3   root     2260: 
1.1.1.14  root     2261:        for (i = 0; i < 4; i++) {
                   2262:            struct audio_channel_data *cdp = audio_channel + i;
                   2263:            int chan_ena = (dmacon & 0x200) && (dmacon & (1<<i));
                   2264:            if (cdp->dmaen == chan_ena)
                   2265:                continue;
                   2266:            cdp->dmaen = chan_ena;
                   2267:            if (cdp->dmaen) {
                   2268:                if (cdp->state == 0) {
                   2269:                    cdp->state = 1;
                   2270:                    cdp->pt = cdp->lc;
                   2271:                    cdp->wper = cdp->per;
                   2272:                    cdp->wlen = cdp->len;
                   2273:                    cdp->data_written = 2;
                   2274:                    cdp->evtime = eventtab[ev_hsync].evtime - get_cycles ();
                   2275:                }
                   2276:            } else {
                   2277:                if (cdp->state == 1 || cdp->state == 5) {
                   2278:                    cdp->state = 0;
                   2279:                    cdp->last_sample = 0;
                   2280:                    cdp->current_sample = 0;
                   2281:                }
1.1       root     2282:            }
                   2283:        }
1.1.1.14  root     2284:        schedule_audio ();
1.1       root     2285:     }
1.1.1.14  root     2286:     events_schedule();
1.1       root     2287: }
1.1.1.2   root     2288: 
1.1.1.3   root     2289: /*static int trace_intena = 0;*/
1.1.1.2   root     2290: 
1.1.1.8   root     2291: STATIC_INLINE void INTENA (uae_u16 v)
1.1.1.2   root     2292: {
1.1.1.3   root     2293: /*    if (trace_intena)
1.1.1.4   root     2294:        fprintf (stderr, "INTENA: %04x\n", v);*/
1.1.1.13  root     2295:     setclr (&intena,v);
1.1.1.15! root     2296:     /* There's stupid code out there that does
        !          2297:         [some INTREQ bits at level 3 are set]
        !          2298:        clear all INTREQ bits
        !          2299:        Enable one INTREQ level 3 bit
        !          2300:        Set level 3 handler
        !          2301: 
        !          2302:        If we set SPCFLAG_INT for the clear, then by the time the enable happens,
        !          2303:        we'll have SPCFLAG_DOINT set, and the interrupt happens immediately, but
        !          2304:        it needs to happen one insn later, when the new L3 handler has been
        !          2305:        installed.  */
        !          2306:     if (v & 0x8000)
        !          2307:        set_special (SPCFLAG_INT);
        !          2308: }
        !          2309: 
        !          2310: void INTREQ_0 (uae_u16 v)
        !          2311: {
        !          2312:     setclr (&intreq,v);
1.1.1.13  root     2313:     set_special (SPCFLAG_INT);
1.1.1.2   root     2314: }
1.1.1.15! root     2315: 
1.1.1.3   root     2316: void INTREQ (uae_u16 v)
1.1       root     2317: {
1.1.1.15! root     2318:     INTREQ_0 (v);
1.1.1.13  root     2319:     if ((v & 0x8800) == 0x0800)
1.1.1.4   root     2320:        serdat &= 0xbfff;
1.1.1.15! root     2321:     rethink_cias ();
1.1.1.3   root     2322: }
1.1       root     2323: 
1.1.1.15! root     2324: static void update_adkmasks (void)
1.1.1.3   root     2325: {
                   2326:     unsigned long t;
1.1.1.4   root     2327: 
1.1.1.3   root     2328:     t = adkcon | (adkcon >> 4);
                   2329:     audio_channel[0].adk_mask = (((t >> 0) & 1) - 1);
                   2330:     audio_channel[1].adk_mask = (((t >> 1) & 1) - 1);
                   2331:     audio_channel[2].adk_mask = (((t >> 2) & 1) - 1);
                   2332:     audio_channel[3].adk_mask = (((t >> 3) & 1) - 1);
                   2333: }
1.1       root     2334: 
1.1.1.15! root     2335: static void ADKCON (uae_u16 v)
        !          2336: {
        !          2337:     if (currprefs.produce_sound > 0)
        !          2338:        update_audio ();
        !          2339: 
        !          2340:     setclr (&adkcon,v);
        !          2341:     update_adkmasks ();
        !          2342: }
        !          2343: 
1.1.1.7   root     2344: static void BEAMCON0 (uae_u16 v)
                   2345: {
                   2346:     new_beamcon0 = v & 0x20;
                   2347: }
                   2348: 
1.1.1.4   root     2349: static void BPLPTH (int hpos, uae_u16 v, int num)
1.1.1.3   root     2350: {
1.1.1.4   root     2351:     decide_line (hpos);
1.1.1.13  root     2352:     decide_fetch (hpos);
1.1.1.4   root     2353:     bplpt[num] = (bplpt[num] & 0xffff) | ((uae_u32)v << 16);
1.1.1.3   root     2354: }
1.1.1.4   root     2355: static void BPLPTL (int hpos, uae_u16 v, int num)
1.1.1.3   root     2356: {
1.1.1.4   root     2357:     decide_line (hpos);
1.1.1.13  root     2358:     decide_fetch (hpos);
1.1.1.4   root     2359:     bplpt[num] = (bplpt[num] & ~0xffff) | (v & 0xfffe);
1.1.1.3   root     2360: }
1.1       root     2361: 
1.1.1.4   root     2362: static void BPLCON0 (int hpos, uae_u16 v)
1.1       root     2363: {
1.1.1.15! root     2364:     if (! (currprefs.chipset_mask & CSMASK_ECS_DENISE))
        !          2365:        v &= ~0x00F1;
        !          2366:     else if (! (currprefs.chipset_mask & CSMASK_AGA))
        !          2367:        v &= ~0x00B1;
1.1.1.14  root     2368: 
1.1.1.2   root     2369:     if (bplcon0 == v)
1.1       root     2370:        return;
1.1.1.4   root     2371:     decide_line (hpos);
1.1.1.13  root     2372:     decide_fetch (hpos);
                   2373: 
1.1.1.2   root     2374:     bplcon0 = v;
1.1.1.6   root     2375:     nr_planes_from_bplcon0 = GET_PLANES (v);
1.1.1.7   root     2376: 
                   2377:     if (currprefs.chipset_mask & CSMASK_AGA)
                   2378:        /* It's not clear how the copper timings are affected by the number
                   2379:         * of bitplanes on AGA machines */
                   2380:        corrected_nr_planes_from_bplcon0 = 4;
                   2381:     else
1.1.1.14  root     2382:        corrected_nr_planes_from_bplcon0 = nr_planes_from_bplcon0 << GET_RES (bplcon0);
1.1.1.15! root     2383: 
        !          2384:     if (currprefs.chipset_mask & CSMASK_AGA) {
        !          2385:        decide_sprites (hpos);
        !          2386:        expand_sprres ();
        !          2387:     }
        !          2388: 
1.1.1.14  root     2389:     expand_fmodes ();
1.1       root     2390: }
1.1.1.9   root     2391: 
1.1.1.8   root     2392: STATIC_INLINE void BPLCON1 (int hpos, uae_u16 v)
1.1       root     2393: {
1.1.1.2   root     2394:     if (bplcon1 == v)
1.1       root     2395:        return;
1.1.1.13  root     2396:     decide_line (hpos);
                   2397:     decide_fetch (hpos);
1.1.1.2   root     2398:     bplcon1 = v;
1.1       root     2399: }
1.1.1.15! root     2400: 
1.1.1.8   root     2401: STATIC_INLINE void BPLCON2 (int hpos, uae_u16 v)
1.1       root     2402: {
1.1.1.7   root     2403:     if (bplcon2 == v)
                   2404:        return;
                   2405:     decide_line (hpos);
1.1.1.2   root     2406:     bplcon2 = v;
1.1       root     2407: }
1.1.1.15! root     2408: 
1.1.1.8   root     2409: STATIC_INLINE void BPLCON3 (int hpos, uae_u16 v)
1.1       root     2410: {
1.1.1.14  root     2411:     if (! (currprefs.chipset_mask & CSMASK_AGA))
                   2412:        return;
1.1.1.7   root     2413:     if (bplcon3 == v)
                   2414:        return;
                   2415:     decide_line (hpos);
1.1.1.15! root     2416:     decide_sprites (hpos);
1.1.1.3   root     2417:     bplcon3 = v;
1.1.1.15! root     2418:     expand_sprres ();
1.1       root     2419: }
1.1.1.15! root     2420: 
1.1.1.8   root     2421: STATIC_INLINE void BPLCON4 (int hpos, uae_u16 v)
1.1       root     2422: {
1.1.1.7   root     2423:     if (! (currprefs.chipset_mask & CSMASK_AGA))
                   2424:        return;
                   2425:     if (bplcon4 == v)
                   2426:        return;
                   2427:     decide_line (hpos);
1.1.1.3   root     2428:     bplcon4 = v;
1.1       root     2429: }
                   2430: 
1.1.1.4   root     2431: static void BPL1MOD (int hpos, uae_u16 v)
1.1       root     2432: {
                   2433:     v &= ~1;
1.1.1.3   root     2434:     if ((uae_s16)bpl1mod == (uae_s16)v)
1.1       root     2435:        return;
1.1.1.13  root     2436:     decide_line (hpos);
                   2437:     decide_fetch (hpos);
1.1       root     2438:     bpl1mod = v;
                   2439: }
1.1.1.2   root     2440: 
1.1.1.4   root     2441: static void BPL2MOD (int hpos, uae_u16 v)
1.1.1.3   root     2442: {
1.1       root     2443:     v &= ~1;
1.1.1.3   root     2444:     if ((uae_s16)bpl2mod == (uae_s16)v)
1.1       root     2445:        return;
1.1.1.13  root     2446:     decide_line (hpos);
                   2447:     decide_fetch (hpos);
1.1       root     2448:     bpl2mod = v;
                   2449: }
                   2450: 
1.1.1.13  root     2451: STATIC_INLINE void BPL1DAT (int hpos, uae_u16 v)
1.1.1.10  root     2452: {
1.1.1.13  root     2453:     decide_line (hpos);
1.1.1.10  root     2454:     bpl1dat = v;
1.1.1.13  root     2455: 
                   2456:     maybe_first_bpl1dat (hpos);
1.1.1.10  root     2457: }
1.1.1.2   root     2458: /* We could do as well without those... */
1.1.1.8   root     2459: STATIC_INLINE void BPL2DAT (uae_u16 v) { bpl2dat = v; }
                   2460: STATIC_INLINE void BPL3DAT (uae_u16 v) { bpl3dat = v; }
                   2461: STATIC_INLINE void BPL4DAT (uae_u16 v) { bpl4dat = v; }
                   2462: STATIC_INLINE void BPL5DAT (uae_u16 v) { bpl5dat = v; }
                   2463: STATIC_INLINE void BPL6DAT (uae_u16 v) { bpl6dat = v; }
                   2464: STATIC_INLINE void BPL7DAT (uae_u16 v) { bpl7dat = v; }
                   2465: STATIC_INLINE void BPL8DAT (uae_u16 v) { bpl8dat = v; }
1.1       root     2466: 
1.1.1.4   root     2467: static void DIWSTRT (int hpos, uae_u16 v)
1.1       root     2468: {
1.1.1.4   root     2469:     if (diwstrt == v && ! diwhigh_written)
1.1       root     2470:        return;
1.1.1.4   root     2471:     decide_line (hpos);
                   2472:     diwhigh_written = 0;
1.1.1.3   root     2473:     diwstrt = v;
1.1.1.4   root     2474:     calcdiw ();
1.1       root     2475: }
1.1.1.4   root     2476: 
                   2477: static void DIWSTOP (int hpos, uae_u16 v)
1.1       root     2478: {
1.1.1.4   root     2479:     if (diwstop == v && ! diwhigh_written)
1.1       root     2480:        return;
1.1.1.4   root     2481:     decide_line (hpos);
                   2482:     diwhigh_written = 0;
1.1.1.3   root     2483:     diwstop = v;
1.1.1.4   root     2484:     calcdiw ();
                   2485: }
                   2486: 
                   2487: static void DIWHIGH (int hpos, uae_u16 v)
                   2488: {
1.1.1.7   root     2489:     if (! (currprefs.chipset_mask & CSMASK_ECS_DENISE))
                   2490:        return;
1.1.1.4   root     2491:     if (diwhigh_written && diwhigh == v)
                   2492:        return;
                   2493:     decide_line (hpos);
                   2494:     diwhigh_written = 1;
                   2495:     diwhigh = v;
                   2496:     calcdiw ();
1.1       root     2497: }
1.1.1.4   root     2498: 
                   2499: static void DDFSTRT (int hpos, uae_u16 v)
1.1.1.3   root     2500: {
1.1.1.11  root     2501:     v &= 0xFC;
1.1.1.2   root     2502:     if (ddfstrt == v)
1.1       root     2503:        return;
1.1.1.4   root     2504:     decide_line (hpos);
1.1.1.3   root     2505:     ddfstrt = v;
1.1.1.4   root     2506:     calcdiw ();
1.1.1.15! root     2507:     if (ddfstop > 0xD4 && (ddfstrt & 4) == 4) {
        !          2508:        static int last_warned;
        !          2509:        last_warned = (last_warned + 1) & 4095;
        !          2510:        if (last_warned == 0)
        !          2511:            write_log ("WARNING! Very strange DDF values.\n");
        !          2512:     }
1.1       root     2513: }
1.1.1.15! root     2514: 
1.1.1.4   root     2515: static void DDFSTOP (int hpos, uae_u16 v)
1.1.1.3   root     2516: {
1.1.1.15! root     2517:     /* ??? "Virtual Meltdown" sets this to 0xD2 and expects it to behave
        !          2518:        differently from 0xD0.  RSI Megademo sets it to 0xd1 and expects it
        !          2519:        to behave like 0xd0.  So mask it with 0xFE.  */
        !          2520:     v &= ~1;
1.1.1.2   root     2521:     if (ddfstop == v)
1.1       root     2522:        return;
1.1.1.4   root     2523:     decide_line (hpos);
1.1.1.13  root     2524:     decide_fetch (hpos);
1.1.1.2   root     2525:     ddfstop = v;
1.1.1.4   root     2526:     calcdiw ();
1.1.1.13  root     2527:     if (fetch_state != fetch_not_started)
                   2528:        estimate_last_fetch_cycle (hpos);
1.1.1.15! root     2529:     if (ddfstop > 0xD4 && (ddfstrt & 4) == 4) {
        !          2530:        static int last_warned;
        !          2531:        last_warned = (last_warned + 1) & 4095;
        !          2532:        if (last_warned == 0)
        !          2533:            write_log ("WARNING! Very strange DDF values.\n");
1.1.1.14  root     2534:        write_log ("WARNING! Very strange DDF values.\n");
1.1.1.15! root     2535:     }
1.1       root     2536: }
                   2537: 
1.1.1.7   root     2538: static void FMODE (uae_u16 v)
                   2539: {
                   2540:     if (! (currprefs.chipset_mask & CSMASK_AGA))
1.1.1.14  root     2541:        v = 0;
1.1.1.13  root     2542: 
1.1.1.7   root     2543:     fmode = v;
1.1.1.14  root     2544:     sprite_width = GET_SPRITEWIDTH (fmode);
                   2545:     switch (fmode & 3) {
                   2546:     case 0:
                   2547:        fetchmode = 0;
                   2548:        break;
                   2549:     case 1:
                   2550:     case 2:
                   2551:        fetchmode = 1;
                   2552:        break;
                   2553:     case 3:
                   2554:        fetchmode = 2;
                   2555:        break;
                   2556:     }
                   2557:     expand_fmodes ();
1.1.1.7   root     2558: }
                   2559: 
1.1.1.4   root     2560: static void BLTADAT (uae_u16 v)
1.1       root     2561: {
1.1.1.13  root     2562:     maybe_blit ();
1.1.1.2   root     2563: 
                   2564:     blt_info.bltadat = v;
1.1       root     2565: }
1.1.1.2   root     2566: /*
                   2567:  * "Loading data shifts it immediately" says the HRM. Well, that may
                   2568:  * be true for BLTBDAT, but not for BLTADAT - it appears the A data must be
                   2569:  * loaded for every word so that AFWM and ALWM can be applied.
                   2570:  */
1.1.1.4   root     2571: static void BLTBDAT (uae_u16 v)
1.1       root     2572: {
1.1.1.13  root     2573:     maybe_blit ();
1.1.1.2   root     2574: 
                   2575:     if (bltcon1 & 2)
                   2576:        blt_info.bltbhold = v << (bltcon1 >> 12);
                   2577:     else
                   2578:        blt_info.bltbhold = v >> (bltcon1 >> 12);
                   2579:     blt_info.bltbdat = v;
1.1       root     2580: }
1.1.1.4   root     2581: static void BLTCDAT (uae_u16 v) { maybe_blit (); blt_info.bltcdat = v; }
1.1       root     2582: 
1.1.1.4   root     2583: static void BLTAMOD (uae_u16 v) { maybe_blit (); blt_info.bltamod = (uae_s16)(v & 0xFFFE); }
                   2584: static void BLTBMOD (uae_u16 v) { maybe_blit (); blt_info.bltbmod = (uae_s16)(v & 0xFFFE); }
                   2585: static void BLTCMOD (uae_u16 v) { maybe_blit (); blt_info.bltcmod = (uae_s16)(v & 0xFFFE); }
                   2586: static void BLTDMOD (uae_u16 v) { maybe_blit (); blt_info.bltdmod = (uae_s16)(v & 0xFFFE); }
1.1       root     2587: 
1.1.1.4   root     2588: static void BLTCON0 (uae_u16 v) { maybe_blit (); bltcon0 = v; blinea_shift = v >> 12; }
1.1.1.3   root     2589: /* The next category is "Most useless hardware register".
1.1       root     2590:  * And the winner is... */
1.1.1.7   root     2591: static void BLTCON0L (uae_u16 v)
                   2592: {
                   2593:     if (! (currprefs.chipset_mask & CSMASK_ECS_AGNUS))
                   2594:        return;
                   2595:     maybe_blit (); bltcon0 = (bltcon0 & 0xFF00) | (v & 0xFF);
                   2596: }
1.1.1.4   root     2597: static void BLTCON1 (uae_u16 v) { maybe_blit (); bltcon1 = v; }
                   2598: 
                   2599: static void BLTAFWM (uae_u16 v) { maybe_blit (); blt_info.bltafwm = v; }
                   2600: static void BLTALWM (uae_u16 v) { maybe_blit (); blt_info.bltalwm = v; }
1.1       root     2601: 
1.1.1.4   root     2602: static void BLTAPTH (uae_u16 v) { maybe_blit (); bltapt = (bltapt & 0xffff) | ((uae_u32)v << 16); }
                   2603: static void BLTAPTL (uae_u16 v) { maybe_blit (); bltapt = (bltapt & ~0xffff) | (v & 0xFFFE); }
                   2604: static void BLTBPTH (uae_u16 v) { maybe_blit (); bltbpt = (bltbpt & 0xffff) | ((uae_u32)v << 16); }
                   2605: static void BLTBPTL (uae_u16 v) { maybe_blit (); bltbpt = (bltbpt & ~0xffff) | (v & 0xFFFE); }
                   2606: static void BLTCPTH (uae_u16 v) { maybe_blit (); bltcpt = (bltcpt & 0xffff) | ((uae_u32)v << 16); }
                   2607: static void BLTCPTL (uae_u16 v) { maybe_blit (); bltcpt = (bltcpt & ~0xffff) | (v & 0xFFFE); }
                   2608: static void BLTDPTH (uae_u16 v) { maybe_blit (); bltdpt = (bltdpt & 0xffff) | ((uae_u32)v << 16); }
                   2609: static void BLTDPTL (uae_u16 v) { maybe_blit (); bltdpt = (bltdpt & ~0xffff) | (v & 0xFFFE); }
1.1       root     2610: 
1.1.1.4   root     2611: static void BLTSIZE (uae_u16 v)
1.1       root     2612: {
1.1.1.4   root     2613:     maybe_blit ();
1.1       root     2614: 
1.1.1.15! root     2615:     blt_info.vblitsize = v >> 6;
        !          2616:     blt_info.hblitsize = v & 0x3F;
1.1       root     2617:     if (!blt_info.vblitsize) blt_info.vblitsize = 1024;
                   2618:     if (!blt_info.hblitsize) blt_info.hblitsize = 64;
1.1.1.3   root     2619: 
                   2620:     bltstate = BLT_init;
1.1.1.4   root     2621:     do_blitter ();
1.1       root     2622: }
1.1.1.4   root     2623: 
                   2624: static void BLTSIZV (uae_u16 v)
1.1       root     2625: {
1.1.1.7   root     2626:     if (! (currprefs.chipset_mask & CSMASK_ECS_AGNUS))
                   2627:        return;
1.1.1.4   root     2628:     maybe_blit ();
1.1       root     2629:     oldvblts = v & 0x7FFF;
                   2630: }
1.1.1.4   root     2631: 
                   2632: static void BLTSIZH (uae_u16 v)
1.1       root     2633: {
1.1.1.7   root     2634:     if (! (currprefs.chipset_mask & CSMASK_ECS_AGNUS))
                   2635:        return;
1.1.1.4   root     2636:     maybe_blit ();
1.1       root     2637:     blt_info.hblitsize = v & 0x7FF;
                   2638:     blt_info.vblitsize = oldvblts;
                   2639:     if (!blt_info.vblitsize) blt_info.vblitsize = 32768;
                   2640:     if (!blt_info.hblitsize) blt_info.hblitsize = 0x800;
1.1.1.2   root     2641:     bltstate = BLT_init;
1.1.1.5   root     2642:     do_blitter ();
1.1       root     2643: }
1.1.1.4   root     2644: 
1.1.1.8   root     2645: STATIC_INLINE void SPRxCTL_1 (uae_u16 v, int num)
1.1       root     2646: {
1.1.1.2   root     2647:     int sprxp;
                   2648:     sprctl[num] = v;
1.1.1.10  root     2649:     nr_armed -= spr[num].armed;
                   2650:     spr[num].armed = 0;
1.1.1.3   root     2651:     if (sprpos[num] == 0 && v == 0) {
1.1.1.10  root     2652:        spr[num].state = SPR_stop;
                   2653:        spr[num].on = 0;
1.1.1.15! root     2654:     } else if (spr[num].state != SPR_waiting_stop) {
1.1.1.10  root     2655:        spr[num].state = SPR_waiting_start;
1.1.1.15! root     2656:        spr[num].on = 1;
        !          2657:     }
1.1.1.2   root     2658: 
1.1.1.15! root     2659:     sprxp = (sprpos[num] & 0xFF) * 2 + (v & 1);
        !          2660: 
        !          2661:     /* Quite a bit salad in this register... */
        !          2662:     if (currprefs.chipset_mask & CSMASK_AGA) {
        !          2663:        /* We ignore the SHRES 35ns increment for now; SHRES support doesn't
        !          2664:           work anyway, so we may as well restrict AGA sprites to a 70ns
        !          2665:           resolution.  */
        !          2666:        sprxp <<= 1;
        !          2667:        sprxp |= (v >> 4) & 1;
        !          2668:     }
1.1.1.10  root     2669:     spr[num].xpos = sprxp;
                   2670:     spr[num].vstart = (sprpos[num] >> 8) | ((sprctl[num] << 6) & 0x100);
                   2671:     spr[num].vstop = (sprctl[num] >> 8) | ((sprctl[num] << 7) & 0x100);
1.1.1.15! root     2672: 
1.1.1.2   root     2673: }
1.1.1.8   root     2674: STATIC_INLINE void SPRxPOS_1 (uae_u16 v, int num)
1.1.1.2   root     2675: {
                   2676:     int sprxp;
                   2677:     sprpos[num] = v;
1.1.1.15! root     2678:     sprxp = (v & 0xFF) * 2 + (sprctl[num] & 1);
        !          2679: 
        !          2680:     if (currprefs.chipset_mask & CSMASK_AGA) {
        !          2681:        sprxp <<= 1;
        !          2682:        sprxp |= (sprctl[num] >> 4) & 1;
        !          2683:     }
1.1.1.10  root     2684:     spr[num].xpos = sprxp;
                   2685:     spr[num].vstart = (sprpos[num] >> 8) | ((sprctl[num] << 6) & 0x100);
1.1.1.2   root     2686: }
1.1.1.8   root     2687: STATIC_INLINE void SPRxDATA_1 (uae_u16 v, int num)
1.1.1.2   root     2688: {
1.1.1.15! root     2689:     sprdata[num][0] = v;
1.1.1.10  root     2690:     nr_armed += 1 - spr[num].armed;
                   2691:     spr[num].armed = 1;
1.1.1.2   root     2692: }
1.1.1.8   root     2693: STATIC_INLINE void SPRxDATB_1 (uae_u16 v, int num)
1.1.1.2   root     2694: {
1.1.1.15! root     2695:     sprdatb[num][0] = v;
1.1.1.2   root     2696: }
1.1.1.4   root     2697: static void SPRxDATA (int hpos, uae_u16 v, int num) { decide_sprites (hpos); SPRxDATA_1 (v, num); }
                   2698: static void SPRxDATB (int hpos, uae_u16 v, int num) { decide_sprites (hpos); SPRxDATB_1 (v, num); }
                   2699: static void SPRxCTL (int hpos, uae_u16 v, int num) { decide_sprites (hpos); SPRxCTL_1 (v, num); }
                   2700: static void SPRxPOS (int hpos, uae_u16 v, int num) { decide_sprites (hpos); SPRxPOS_1 (v, num); }
                   2701: static void SPRxPTH (int hpos, uae_u16 v, int num)
1.1       root     2702: {
1.1.1.4   root     2703:     decide_sprites (hpos);
1.1.1.10  root     2704:     spr[num].pt &= 0xffff;
                   2705:     spr[num].pt |= (uae_u32)v << 16;
1.1.1.3   root     2706: 
1.1.1.10  root     2707:     if (spr[num].state == SPR_stop || vpos < sprite_vblank_endline)
                   2708:        spr[num].state = SPR_restart;
                   2709:     spr[num].on = 1;
1.1       root     2710: }
1.1.1.4   root     2711: static void SPRxPTL (int hpos, uae_u16 v, int num)
1.1       root     2712: {
1.1.1.4   root     2713:     decide_sprites (hpos);
1.1.1.10  root     2714:     spr[num].pt &= ~0xffff;
                   2715:     spr[num].pt |= v;
1.1       root     2716: 
1.1.1.10  root     2717:     if (spr[num].state == SPR_stop || vpos < sprite_vblank_endline)
                   2718:        spr[num].state = SPR_restart;
                   2719:     spr[num].on = 1;
1.1.1.3   root     2720: }
1.1.1.4   root     2721: static void CLXCON (uae_u16 v)
1.1.1.3   root     2722: {
                   2723:     clxcon = v;
1.1.1.14  root     2724:     clxcon_bpl_enable = (v >> 6) & 63;
                   2725:     clxcon_bpl_match = v & 63;
                   2726:     clx_sprmask = ((((v >> 15) & 1) << 7) | (((v >> 14) & 1) << 5) | (((v >> 13) & 1) << 3) | (((v >> 12) & 1) << 1) | 0x55);
                   2727: }
                   2728: static void CLXCON2 (uae_u16 v)
                   2729: {
                   2730:     if (!(currprefs.chipset_mask & CSMASK_AGA))
                   2731:        return;
                   2732:     clxcon2 = v;
                   2733:     clxcon_bpl_enable |= v & (0x40|0x80);
                   2734:     clxcon_bpl_match |= (v & (0x01|0x02)) << 6;
                   2735:  }
1.1.1.4   root     2736: static uae_u16 CLXDAT (void)
1.1.1.3   root     2737: {
                   2738:     uae_u16 v = clxdat;
                   2739:     clxdat = 0;
                   2740:     return v;
                   2741: }
1.1.1.11  root     2742: 
1.1.1.13  root     2743: static uae_u16 COLOR_READ (int num)
1.1       root     2744: {
1.1.1.13  root     2745:     int cr, cg, cb, colreg;
                   2746:     uae_u16 cval;
                   2747: 
                   2748:     if (!(currprefs.chipset_mask & CSMASK_AGA) || !(bplcon2 & 0x0100))
                   2749:        return 0xffff;
                   2750: 
                   2751:     colreg = ((bplcon3 >> 13) & 7) * 32 + num;
                   2752:     cr = current_colors.color_regs_aga[colreg] >> 16;
                   2753:     cg = (current_colors.color_regs_aga[colreg] >> 8) & 0xFF;
                   2754:     cb = current_colors.color_regs_aga[colreg] & 0xFF;
                   2755:     if (bplcon3 & 0x200)
                   2756:        cval = ((cr & 15) << 12) | ((cg & 15) << 4) | ((cb & 15) << 0);
                   2757:     else
                   2758:        cval = ((cr >> 4) << 12) | ((cg >> 4) << 4) | ((cb >> 4) << 0);
                   2759:     return cval;
                   2760: }
1.1.1.3   root     2761: 
1.1.1.13  root     2762: static void COLOR_WRITE (int hpos, uae_u16 v, int num)
                   2763: {
1.1       root     2764:     v &= 0xFFF;
1.1.1.11  root     2765:     if (currprefs.chipset_mask & CSMASK_AGA) {
1.1.1.4   root     2766:        int r,g,b;
                   2767:        int cr,cg,cb;
                   2768:        int colreg;
1.1.1.3   root     2769:        uae_u32 cval;
1.1.1.4   root     2770: 
1.1.1.11  root     2771:        /* writing is disabled when RDRAM=1 */
1.1.1.13  root     2772:        if (bplcon2 & 0x0100)
                   2773:            return;
1.1.1.11  root     2774: 
1.1.1.2   root     2775:        colreg = ((bplcon3 >> 13) & 7) * 32 + num;
1.1       root     2776:        r = (v & 0xF00) >> 8;
                   2777:        g = (v & 0xF0) >> 4;
                   2778:        b = (v & 0xF) >> 0;
1.1.1.11  root     2779:        cr = current_colors.color_regs_aga[colreg] >> 16;
                   2780:        cg = (current_colors.color_regs_aga[colreg] >> 8) & 0xFF;
                   2781:        cb = current_colors.color_regs_aga[colreg] & 0xFF;
1.1       root     2782: 
1.1.1.2   root     2783:        if (bplcon3 & 0x200) {
1.1       root     2784:            cr &= 0xF0; cr |= r;
                   2785:            cg &= 0xF0; cg |= g;
                   2786:            cb &= 0xF0; cb |= b;
                   2787:        } else {
                   2788:            cr = r + (r << 4);
                   2789:            cg = g + (g << 4);
                   2790:            cb = b + (b << 4);
                   2791:        }
                   2792:        cval = (cr << 16) | (cg << 8) | cb;
1.1.1.11  root     2793:        if (cval == current_colors.color_regs_aga[colreg])
1.1       root     2794:            return;
1.1.1.5   root     2795: 
                   2796:        /* Call this with the old table still intact. */
1.1.1.11  root     2797:        record_color_change (hpos, colreg, cval);
1.1.1.5   root     2798:        remembered_color_entry = -1;
1.1.1.11  root     2799:        current_colors.color_regs_aga[colreg] = cval;
                   2800:        current_colors.acolors[colreg] = CONVERT_RGB (cval);
                   2801:    } else {
                   2802:        if (current_colors.color_regs_ecs[num] == v)
1.1       root     2803:            return;
1.1.1.2   root     2804:        /* Call this with the old table still intact. */
1.1.1.4   root     2805:        record_color_change (hpos, num, v);
1.1.1.2   root     2806:        remembered_color_entry = -1;
1.1.1.11  root     2807:        current_colors.color_regs_ecs[num] = v;
1.1.1.2   root     2808:        current_colors.acolors[num] = xcolors[v];
1.1       root     2809:     }
                   2810: }
1.1.1.3   root     2811: 
                   2812: static uae_u16 potgo_value;
                   2813: 
1.1.1.4   root     2814: static void POTGO (uae_u16 v)
1.1       root     2815: {
1.1.1.3   root     2816:     potgo_value = v;
                   2817: }
                   2818: 
1.1.1.4   root     2819: static uae_u16 POTGOR (void)
1.1.1.3   root     2820: {
1.1.1.11  root     2821:     uae_u16 v = (potgo_value | (potgo_value >> 1)) & 0x5500;
                   2822: 
                   2823:     v |= (~potgo_value & 0xAA00) >> 1;
1.1.1.3   root     2824: 
1.1.1.6   root     2825:     if (JSEM_ISMOUSE (0, &currprefs)) {
1.1.1.3   root     2826:        if (buttonstate[2])
                   2827:            v &= 0xFBFF;
                   2828: 
                   2829:        if (buttonstate[1])
                   2830:            v &= 0xFEFF;
1.1.1.6   root     2831:     } else if (JSEM_ISJOY0 (0, &currprefs) || JSEM_ISJOY1 (0, &currprefs)) {
1.1.1.3   root     2832:        if (joy0button & 2) v &= 0xfbff;
                   2833:        if (joy0button & 4) v &= 0xfeff;
                   2834:     }
                   2835: 
1.1.1.6   root     2836:     if (JSEM_ISJOY0 (1, &currprefs) || JSEM_ISJOY1 (1, &currprefs)) {
1.1.1.3   root     2837:        if (joy1button & 2) v &= 0xbfff;
                   2838:        if (joy1button & 4) v &= 0xefff;
                   2839:     }
1.1       root     2840: 
                   2841:     return v;
                   2842: }
1.1.1.4   root     2843: 
                   2844: static uae_u16 POT0DAT (void)
1.1       root     2845: {
1.1.1.3   root     2846:     static uae_u16 cnt = 0;
1.1.1.6   root     2847:     if (JSEM_ISMOUSE (0, &currprefs)) {
1.1.1.3   root     2848:        if (buttonstate[2])
                   2849:            cnt = ((cnt + 1) & 0xFF) | (cnt & 0xFF00);
                   2850:        if (buttonstate[1])
                   2851:            cnt += 0x100;
                   2852:     }
                   2853: 
1.1       root     2854:     return cnt;
                   2855: }
1.1.1.4   root     2856: static uae_u16 JOY0DAT (void)
1.1       root     2857: {
1.1.1.6   root     2858:     if (JSEM_ISMOUSE (0, &currprefs)) {
1.1.1.4   root     2859:        do_mouse_hack ();
1.1.1.3   root     2860:        return ((uae_u8)mouse_x) + ((uae_u16)mouse_y << 8);
                   2861:     }
1.1       root     2862:     return joy0dir;
                   2863: }
1.1.1.4   root     2864: static uae_u16 JOY1DAT (void)
1.1       root     2865: {
1.1.1.6   root     2866:     if (JSEM_ISMOUSE (1, &currprefs)) {
1.1.1.4   root     2867:        do_mouse_hack ();
1.1.1.3   root     2868:        return ((uae_u8)mouse_x) + ((uae_u16)mouse_y << 8);
                   2869:     }
                   2870:     return joy1dir;
1.1       root     2871: }
1.1.1.4   root     2872: static void JOYTEST (uae_u16 v)
1.1       root     2873: {
1.1.1.6   root     2874:     if (JSEM_ISMOUSE (0, &currprefs)) {
1.1.1.3   root     2875:        mouse_x = v & 0xFC;
                   2876:        mouse_y = (v >> 8) & 0xFC;
1.1       root     2877:     }
                   2878: }
                   2879: 
1.1.1.15! root     2880: /* The copper code.  The biggest nightmare in the whole emulator.
        !          2881: 
        !          2882:    Alright.  The current theory:
        !          2883:    1. Copper moves happen 4 cycles after state READ2 is reached.
        !          2884:       It can't happen immediately when we reach READ2, because the
        !          2885:       data needs time to get back from the bus.  4 cycles appears
        !          2886:       to be the time a chip memory access takes on the Amiga.
        !          2887:    2. As stated in the HRM, a WAIT really does need an extra cycle
        !          2888:       to wake up.  This is implemented by _not_ falling through from
        !          2889:       a successful wait to READ1, but by starting the next cycle.
        !          2890:       (Note: the extra cycle for the WAIT apparently really needs a
        !          2891:       free cycle; i.e. contention with the bitplane fetch can slow
        !          2892:       it down).
        !          2893:    3. Apparently, to compensate for the extra wake up cycle, a WAIT
        !          2894:       will use the _incremented_ horizontal position, so the WAIT
        !          2895:       cycle normally finishes two clocks earlier than the position
        !          2896:       it was waiting for.  The extra cycle then takes us to the
        !          2897:       position that was waited for.
        !          2898:       If the earlier cycle is busy with a bitplane, things change a bit.
        !          2899:       E.g., waiting for position 0x50 in a 6 plane display: In cycle
        !          2900:       0x4e, we fetch BPL5, so the wait wakes up in 0x50, the extra cycle
        !          2901:       takes us to 0x54 (since 0x52 is busy), then we have READ1/READ2,
        !          2902:       and the next register write is at 0x5c.
        !          2903:    4. The last cycle in a line is not usable for the copper.
        !          2904:    5. A 4 cycle delay also applies to the WAIT instruction.  This means
        !          2905:       that the second of two back-to-back WAITs (or a WAIT whose
        !          2906:       condition is immediately true) takes 8 cycles.
        !          2907:    6. This also applies to a SKIP instruction.  The copper does not
        !          2908:       fetch the next instruction while waiting for the second word of
        !          2909:       a WAIT or a SKIP to arrive.
        !          2910:    7. A SKIP also seems to need an unexplained additional two cycles
        !          2911:       after its second word arrives; this is _not_ a memory cycle (I
        !          2912:       think, the documentation is pretty clear on this).
        !          2913:    8. Two additional cycles are inserted when writing to COPJMP1/2.  */
        !          2914: 
1.1.1.4   root     2915: /* Determine which cycles are available for the copper in a display
                   2916:  * with a agiven number of planes.  */
                   2917: static int cycles_for_plane[9][8] = {
                   2918:     { 0, -1, 0, -1, 0, -1, 0, -1 },
                   2919:     { 0, -1, 0, -1, 0, -1, 0, -1 },
                   2920:     { 0, -1, 0, -1, 0, -1, 0, -1 },
                   2921:     { 0, -1, 0, -1, 0, -1, 0, -1 },
                   2922:     { 0, -1, 0, -1, 0, -1, 0, -1 },
1.1.1.15! root     2923:     { 0, -1, 0, -1, 0, -1, 1, -1 },
1.1.1.4   root     2924:     { 0, -1, 1, -1, 0, -1, 1, -1 },
                   2925:     { 1, -1, 1, -1, 1, -1, 1, -1 },
                   2926:     { 1, -1, 1, -1, 1, -1, 1, -1 }
                   2927: };
1.1.1.2   root     2928: 
1.1.1.13  root     2929: STATIC_INLINE int copper_cant_read (int hpos, int planes)
1.1       root     2930: {
1.1.1.4   root     2931:     int t;
1.1.1.2   root     2932: 
1.1.1.15! root     2933:     if (hpos + 1 >= maxhpos)
1.1.1.2   root     2934:        return 1;
1.1.1.3   root     2935: 
1.1.1.7   root     2936:     if (currprefs.chipset_mask & CSMASK_AGA)
                   2937:        /* FIXME */
                   2938:        return 0;
                   2939: 
1.1.1.15! root     2940:     if (fetch_state == fetch_not_started || hpos < thisline_decision.plfleft)
        !          2941:        return 0;
        !          2942: 
        !          2943:     if ((passed_plfstop == 3 && hpos >= thisline_decision.plfright)
        !          2944:        || hpos >= estimated_last_fetch_cycle)
1.1.1.4   root     2945:        return 0;
1.1.1.3   root     2946: 
1.1.1.15! root     2947:     t = cycles_for_plane[planes][(hpos + cycle_diagram_shift) & 7];
1.1.1.4   root     2948: #if 0
                   2949:     if (t == -1)
                   2950:        abort ();
                   2951: #endif
                   2952:     return t;
1.1.1.2   root     2953: }
                   2954: 
1.1.1.10  root     2955: STATIC_INLINE int dangerous_reg (int reg)
                   2956: {
                   2957:     /* Safe:
                   2958:      * Bitplane pointers, control registers, modulos and data.
                   2959:      * Sprite pointers, control registers, and data.
                   2960:      * Color registers.  */
                   2961:     if (reg >= 0xE0 && reg < 0x1C0)
                   2962:        return 0;
                   2963:     return 1;
                   2964: }
                   2965: 
1.1.1.15! root     2966: #define FAST_COPPER 1
        !          2967: 
        !          2968: /* The future, Conan?
        !          2969:    We try to look ahead in the copper list to avoid doing continuous calls
        !          2970:    to updat_copper (which is what happens when SPCFLAG_COPPER is set).  If
        !          2971:    we find that the same effect can be achieved by setting a delayed event
        !          2972:    and then doing multiple copper insns in one batch, we can get a massive
        !          2973:    speedup.
        !          2974: 
        !          2975:    We don't try to be precise here.  All copper reads take exactly 2 cycles,
        !          2976:    the effect of bitplane contention is ignored.  Trying to get it exactly
        !          2977:    right would be much more complex and as such carry a huge risk of getting
        !          2978:    it subtly wrong; and it would also be more expensive - we want this code
        !          2979:    to be fast.  */
        !          2980: static void predict_copper (void)
        !          2981: {
        !          2982:     uaecptr ip = cop_state.ip;
        !          2983:     unsigned int c_hpos = cop_state.hpos;
        !          2984:     enum copper_states state = cop_state.state;
        !          2985:     unsigned int w1, w2, cycle_count;
        !          2986: 
        !          2987:     switch (state) {
        !          2988:     case COP_read1_wr_in2:
        !          2989:     case COP_read2_wr_in2:
        !          2990:     case COP_read1_wr_in4:
        !          2991:        if (dangerous_reg (cop_state.saved_i1))
        !          2992:            return;
        !          2993:        state = state == COP_read2_wr_in2 ? COP_read2 : COP_read1;
        !          2994:        break;
        !          2995: 
        !          2996:     case COP_read1_in2:
        !          2997:        c_hpos += 2;
        !          2998:        state = COP_read1;
        !          2999:        break;
        !          3000: 
        !          3001:     case COP_stop:
        !          3002:     case COP_bltwait:
        !          3003:     case COP_wait1:
        !          3004:     case COP_skip_in4:
        !          3005:     case COP_skip_in2:
        !          3006:        return;
        !          3007: 
        !          3008:     case COP_wait_in4:
        !          3009:        c_hpos += 2;
        !          3010:        /* fallthrough */
        !          3011:     case COP_wait_in2:
        !          3012:        c_hpos += 2;
        !          3013:        /* fallthrough */
        !          3014:     case COP_wait:
        !          3015:        state = COP_wait;
        !          3016:        break;
        !          3017: 
        !          3018:     default:
        !          3019:        break;
        !          3020:     }
        !          3021:     /* Only needed for COP_wait, but let's shut up the compiler.  */
        !          3022:     w1 = cop_state.saved_i1;
        !          3023:     w2 = cop_state.saved_i2;
        !          3024:     cop_state.first_sync = c_hpos;
        !          3025:     cop_state.regtypes_modified = REGTYPE_FORCE;
        !          3026: 
        !          3027:     /* Get this case out of the way, so that the loop below only has to deal
        !          3028:        with read1 and wait.  */
        !          3029:     if (state == COP_read2) {
        !          3030:        w1 = cop_state.i1;
        !          3031:        if (w1 & 1) {
        !          3032:            w2 = chipmem_wget (ip);
        !          3033:            if (w2 & 1)
        !          3034:                goto done;
        !          3035:            state = COP_wait;
        !          3036:            c_hpos += 4;
        !          3037:        } else if (dangerous_reg (w1)) {
        !          3038:            c_hpos += 4;
        !          3039:            goto done;
        !          3040:        } else {
        !          3041:            cop_state.regtypes_modified |= regtypes[w1 & 0x1FE];
        !          3042:            state = COP_read1;
        !          3043:            c_hpos += 2;
        !          3044:        }
        !          3045:        ip += 2;        
        !          3046:     }
        !          3047: 
        !          3048:     while (c_hpos + 1 < maxhpos) {
        !          3049:        if (state == COP_read1) {
        !          3050:            w1 = chipmem_wget (ip);
        !          3051:            if (w1 & 1) {
        !          3052:                w2 = chipmem_wget (ip + 2);
        !          3053:                if (w2 & 1)
        !          3054:                    break;
        !          3055:                state = COP_wait;
        !          3056:                c_hpos += 6;
        !          3057:            } else if (dangerous_reg (w1)) {
        !          3058:                c_hpos += 6;
        !          3059:                goto done;
        !          3060:            } else {
        !          3061:                cop_state.regtypes_modified |= regtypes[w1 & 0x1FE];
        !          3062:                c_hpos += 4;
        !          3063:            }
        !          3064:            ip += 4;
        !          3065:        } else if (state == COP_wait) {
        !          3066:            if ((w2 & 0xFE) != 0xFE)
        !          3067:                break;
        !          3068:            else {
        !          3069:                unsigned int vcmp = (w1 & (w2 | 0x8000)) >> 8;
        !          3070:                unsigned int hcmp = (w1 & 0xFE);
        !          3071: 
        !          3072:                unsigned int vp = vpos & (((w2 >> 8) & 0x7F) | 0x80);
        !          3073:                if (vp < vcmp) {
        !          3074:                    /* Whee.  We can wait until the end of the line!  */
        !          3075:                    c_hpos = maxhpos;
        !          3076:                } else if (vp > vcmp || hcmp <= c_hpos) {
        !          3077:                    state = COP_read1;
        !          3078:                    /* minimum wakeup time */
        !          3079:                    c_hpos += 2;
        !          3080:                } else {
        !          3081:                    state = COP_read1;
        !          3082:                    c_hpos = hcmp;
        !          3083:                }
        !          3084:                /* If this is the current instruction, remember that we don't
        !          3085:                   need to sync CPU and copper anytime soon.  */
        !          3086:                if (cop_state.ip == ip) {
        !          3087:                    cop_state.first_sync = c_hpos;
        !          3088:                }
        !          3089:            }
        !          3090:        } else
        !          3091:            abort ();
        !          3092:     }
        !          3093: 
        !          3094:   done:
        !          3095:     cycle_count = c_hpos - cop_state.hpos;
        !          3096:     if (cycle_count >= 8) {
        !          3097:        unset_special (SPCFLAG_COPPER);
        !          3098:        eventtab[ev_copper].active = 1;
        !          3099:        eventtab[ev_copper].oldcycles = get_cycles ();
        !          3100:        eventtab[ev_copper].evtime = get_cycles () + cycle_count * CYCLE_UNIT;
        !          3101:        events_schedule ();
        !          3102:     }
        !          3103: }
        !          3104: 
        !          3105: static void perform_copper_write (int old_hpos)
        !          3106: {
        !          3107:     int vp = vpos & (((cop_state.saved_i2 >> 8) & 0x7F) | 0x80);
        !          3108:     int hp;
        !          3109:     unsigned int address = cop_state.saved_i1 & 0x1FE;
        !          3110: 
        !          3111:     record_copper (cop_state.saved_ip - 4, old_hpos, vpos);
        !          3112: 
        !          3113:     if (address < (copcon & 2 ? ((currprefs.chipset_mask & CSMASK_AGA) ? 0 : 0x40u) : 0x80u)) {
        !          3114:        cop_state.state = COP_stop;     
        !          3115:        copper_enabled_thisline = 0;
        !          3116:        unset_special (SPCFLAG_COPPER);
        !          3117:        return;
        !          3118:     }
        !          3119: 
        !          3120:     if (address == 0x88) {
        !          3121:        cop_state.ip = cop1lc;
        !          3122:        cop_state.state = COP_read1_in2;
        !          3123:     } else if (address == 0x8A) {
        !          3124:        cop_state.ip = cop2lc;
        !          3125:        cop_state.state = COP_read1_in2;
        !          3126:     } else
        !          3127:        custom_wput_1 (old_hpos, address, cop_state.saved_i2);
        !          3128: }
1.1.1.13  root     3129: 
1.1.1.9   root     3130: static void update_copper (int until_hpos)
1.1.1.2   root     3131: {
1.1.1.15! root     3132:     int vp = vpos & (((cop_state.saved_i2 >> 8) & 0x7F) | 0x80);    
1.1.1.4   root     3133:     int c_hpos = cop_state.hpos;
1.1.1.2   root     3134: 
1.1.1.10  root     3135:     if (eventtab[ev_copper].active)
                   3136:        abort ();
                   3137: 
                   3138:     if (cop_state.state == COP_wait && vp < cop_state.vcmp)
                   3139:        abort ();
                   3140: 
                   3141:     until_hpos &= ~1;
                   3142: 
                   3143:     if (until_hpos > (maxhpos & ~1))
                   3144:        until_hpos = maxhpos & ~1;
1.1.1.3   root     3145: 
1.1.1.13  root     3146:     until_hpos += 2;
1.1.1.4   root     3147:     for (;;) {
1.1.1.10  root     3148:        int old_hpos = c_hpos;
                   3149:        int hp;
                   3150: 
1.1.1.13  root     3151:        if (c_hpos >= until_hpos)
1.1.1.3   root     3152:            break;
                   3153: 
1.1.1.13  root     3154:        /* So we know about the fetch state.  */
1.1.1.9   root     3155:        decide_line (c_hpos);
1.1.1.3   root     3156: 
1.1.1.15! root     3157:        switch (cop_state.state) {
        !          3158:        case COP_read1_in2:
        !          3159:            cop_state.state = COP_read1;
        !          3160:            break;
        !          3161:        case COP_read1_wr_in2:
        !          3162:            cop_state.state = COP_read1;
        !          3163:            perform_copper_write (old_hpos);
        !          3164:            /* That could have turned off the copper.  */
        !          3165:            if (! copper_enabled_thisline)
        !          3166:                goto out;
        !          3167: 
        !          3168:            break;
        !          3169:        case COP_read1_wr_in4:
        !          3170:            cop_state.state = COP_read1_wr_in2;
        !          3171:            break;
        !          3172:        case COP_read2_wr_in2:
        !          3173:            cop_state.state = COP_read2;
        !          3174:            perform_copper_write (old_hpos);
        !          3175:            /* That could have turned off the copper.  */
        !          3176:            if (! copper_enabled_thisline)
        !          3177:                goto out;
        !          3178: 
        !          3179:            break;
        !          3180:        case COP_wait_in2:
        !          3181:            cop_state.state = COP_wait1;
        !          3182:            break;
        !          3183:        case COP_wait_in4:
        !          3184:            cop_state.state = COP_wait_in2;
        !          3185:            break;
        !          3186:        case COP_skip_in2:
        !          3187:        {
        !          3188:            static int skipped_before;
        !          3189:            unsigned int vcmp, hcmp, vp1, hp1;
        !          3190:            cop_state.state = COP_read1_in2;
        !          3191: 
        !          3192:            vcmp = (cop_state.saved_i1 & (cop_state.saved_i2 | 0x8000)) >> 8;
        !          3193:            hcmp = (cop_state.saved_i1 & cop_state.saved_i2 & 0xFE);
        !          3194: 
        !          3195:            if (! skipped_before) {
        !          3196:                skipped_before = 1;
        !          3197:                write_log ("Program uses Copper SKIP instruction.\n");
        !          3198:            }
        !          3199: 
        !          3200:            vp1 = vpos & (((cop_state.saved_i2 >> 8) & 0x7F) | 0x80);
        !          3201:            hp1 = old_hpos & (cop_state.saved_i2 & 0xFE);
        !          3202: 
        !          3203:            if ((vp1 > vcmp || (vp1 == vcmp && hp1 >= hcmp))
        !          3204:                && ((cop_state.saved_i2 & 0x8000) != 0 || ! (DMACONR() & 0x4000)))
        !          3205:                cop_state.ignore_next = 1;
        !          3206:            break;
        !          3207:        }
        !          3208:        case COP_skip_in4:
        !          3209:            cop_state.state = COP_skip_in2;
        !          3210:            break;
        !          3211:        default:
        !          3212:            break;
        !          3213:        }
        !          3214: 
1.1.1.10  root     3215:        c_hpos += 2;
1.1.1.13  root     3216:        if (copper_cant_read (old_hpos, corrected_nr_planes_from_bplcon0))
1.1.1.10  root     3217:            continue;
1.1.1.3   root     3218: 
1.1.1.10  root     3219:        switch (cop_state.state) {
1.1.1.15! root     3220:        case COP_read1_wr_in4:
        !          3221:            abort ();
        !          3222: 
        !          3223:        case COP_read1_wr_in2:
1.1.1.9   root     3224:        case COP_read1:
1.1.1.15! root     3225:            cop_state.i1 = chipmem_wget (cop_state.ip);
1.1.1.9   root     3226:            cop_state.ip += 2;
1.1.1.15! root     3227:            cop_state.state = cop_state.state == COP_read1 ? COP_read2 : COP_read2_wr_in2;
1.1.1.9   root     3228:            break;
                   3229: 
1.1.1.15! root     3230:        case COP_read2_wr_in2:
        !          3231:            abort ();
        !          3232: 
1.1.1.9   root     3233:        case COP_read2:
1.1.1.15! root     3234:            cop_state.i2 = chipmem_wget (cop_state.ip);
1.1.1.9   root     3235:            cop_state.ip += 2;
                   3236:            if (cop_state.ignore_next) {
                   3237:                cop_state.ignore_next = 0;
1.1.1.15! root     3238:                cop_state.state = COP_read1;
1.1.1.9   root     3239:                break;
1.1.1.3   root     3240:            }
1.1.1.2   root     3241: 
1.1.1.15! root     3242:            cop_state.saved_i1 = cop_state.i1;
        !          3243:            cop_state.saved_i2 = cop_state.i2;
        !          3244:            cop_state.saved_ip = cop_state.ip;
        !          3245: 
        !          3246:            if (cop_state.i1 & 1) {
        !          3247:                if (cop_state.i2 & 1)
        !          3248:                    cop_state.state = COP_skip_in4;
        !          3249:                else
        !          3250:                    cop_state.state = COP_wait_in4;
        !          3251:            } else
        !          3252:                cop_state.state = COP_read1_wr_in4;
        !          3253:            break;
        !          3254: 
        !          3255:        case COP_wait1:
1.1.1.9   root     3256:            cop_state.state = COP_wait;
1.1.1.13  root     3257: 
1.1.1.15! root     3258:            cop_state.vcmp = (cop_state.saved_i1 & (cop_state.saved_i2 | 0x8000)) >> 8;
        !          3259:            cop_state.hcmp = (cop_state.saved_i1 & cop_state.saved_i2 & 0xFE);
        !          3260: 
        !          3261:            vp = vpos & (((cop_state.saved_i2 >> 8) & 0x7F) | 0x80);
1.1.1.13  root     3262: 
1.1.1.15! root     3263:            if (cop_state.saved_i1 == 0xFFFF && cop_state.saved_i2 == 0xFFFE) {
1.1.1.9   root     3264:                cop_state.state = COP_stop;
1.1.1.10  root     3265:                copper_enabled_thisline = 0;
1.1.1.13  root     3266:                unset_special (SPCFLAG_COPPER);
1.1.1.10  root     3267:                goto out;
1.1.1.2   root     3268:            }
1.1.1.9   root     3269:            if (vp < cop_state.vcmp) {
1.1.1.10  root     3270:                copper_enabled_thisline = 0;
1.1.1.13  root     3271:                unset_special (SPCFLAG_COPPER);
1.1.1.10  root     3272:                goto out;
1.1.1.2   root     3273:            }
1.1.1.10  root     3274: 
1.1.1.15! root     3275:            /* fall through */
        !          3276:        do_wait:
1.1.1.10  root     3277:        case COP_wait:
                   3278:            if (vp < cop_state.vcmp)
                   3279:                abort ();
                   3280: 
1.1.1.15! root     3281:            hp = c_hpos & (cop_state.saved_i2 & 0xFE);
        !          3282:            if (vp == cop_state.vcmp && hp < cop_state.hcmp) {
        !          3283:                /* Position not reached yet.  */
        !          3284:                if (currprefs.fast_copper && (cop_state.saved_i2 & 0xFE) == 0xFE) {
        !          3285:                    int wait_finish = cop_state.hcmp - 2;
        !          3286:                    /* This will leave c_hpos untouched if it's equal to wait_finish.  */
        !          3287:                    if (wait_finish < c_hpos)
        !          3288:                        abort ();
        !          3289:                    else if (wait_finish <= until_hpos) {
        !          3290:                        c_hpos = wait_finish;
        !          3291:                    } else
        !          3292:                        c_hpos = until_hpos;
        !          3293:                }             
1.1.1.4   root     3294:                break;
1.1.1.15! root     3295:            }
1.1.1.10  root     3296: 
                   3297:            /* Now we know that the comparisons were successful.  We might still
                   3298:               have to wait for the blitter though.  */
1.1.1.15! root     3299:            if ((cop_state.saved_i2 & 0x8000) == 0 && (DMACONR() & 0x4000)) {
1.1.1.9   root     3300:                /* We need to wait for the blitter.  */
1.1.1.4   root     3301:                cop_state.state = COP_bltwait;
1.1.1.10  root     3302:                copper_enabled_thisline = 0;
1.1.1.13  root     3303:                unset_special (SPCFLAG_COPPER);
1.1.1.10  root     3304:                goto out;
1.1.1.2   root     3305:            }
1.1.1.10  root     3306: 
1.1.1.15! root     3307:            record_copper (cop_state.ip - 4, old_hpos, vpos);
1.1.1.13  root     3308: 
1.1.1.10  root     3309:            cop_state.state = COP_read1;
1.1.1.4   root     3310:            break;
1.1.1.2   root     3311: 
1.1.1.13  root     3312:        default:
1.1.1.15! root     3313:            break;
1.1       root     3314:        }
1.1.1.4   root     3315:     }
1.1.1.10  root     3316: 
                   3317:   out:
1.1.1.4   root     3318:     cop_state.hpos = c_hpos;
1.1.1.10  root     3319: 
1.1.1.15! root     3320:     /* The test against maxhpos also prevents us from calling predict_copper
        !          3321:        when we are being called from hsync_handler, which would not only be
        !          3322:        stupid, but actively harmful.  */
        !          3323:     if (currprefs.fast_copper && (regs.spcflags & SPCFLAG_COPPER) && c_hpos + 8 < maxhpos)
        !          3324:        predict_copper ();
1.1       root     3325: }
                   3326: 
1.1.1.9   root     3327: static void compute_spcflag_copper (void)
1.1       root     3328: {
1.1.1.10  root     3329:     copper_enabled_thisline = 0;
1.1.1.13  root     3330:     unset_special (SPCFLAG_COPPER);
1.1.1.10  root     3331:     if (! dmaen (DMA_COPPER) || cop_state.state == COP_stop || cop_state.state == COP_bltwait)
                   3332:        return;
                   3333: 
                   3334:     if (cop_state.state == COP_wait) {
1.1.1.15! root     3335:        int vp = vpos & (((cop_state.saved_i2 >> 8) & 0x7F) | 0x80);
1.1.1.10  root     3336: 
                   3337:        if (vp < cop_state.vcmp)
                   3338:            return;
                   3339:     }
                   3340:     copper_enabled_thisline = 1;
1.1.1.15! root     3341: 
        !          3342:     if (currprefs.fast_copper)
        !          3343:        predict_copper ();
        !          3344: 
        !          3345:     if (! eventtab[ev_copper].active)
        !          3346:        set_special (SPCFLAG_COPPER);
1.1.1.10  root     3347: }
                   3348: 
                   3349: static void copper_handler (void)
                   3350: {
                   3351:     /* This will take effect immediately, within the same cycle.  */
1.1.1.13  root     3352:     set_special (SPCFLAG_COPPER);
1.1.1.10  root     3353: 
                   3354:     if (! copper_enabled_thisline)
                   3355:        abort ();
                   3356: 
                   3357:     eventtab[ev_copper].active = 0;
1.1.1.3   root     3358: }
1.1.1.2   root     3359: 
1.1.1.4   root     3360: void blitter_done_notify (void)
1.1       root     3361: {
1.1.1.4   root     3362:     if (cop_state.state != COP_bltwait)
                   3363:        return;
1.1.1.10  root     3364: 
                   3365:     copper_enabled_thisline = 1;
1.1.1.13  root     3366:     set_special (SPCFLAG_COPPER);
1.1.1.9   root     3367:     cop_state.state = COP_wait;
1.1.1.2   root     3368: }
                   3369: 
1.1.1.9   root     3370: void do_copper (void)
1.1.1.2   root     3371: {
1.1.1.4   root     3372:     int hpos = current_hpos ();
                   3373:     update_copper (hpos);
1.1.1.2   root     3374: }
                   3375: 
1.1.1.15! root     3376: /* ADDR is the address that is going to be read/written; this access is
        !          3377:    the reason why we want to update the copper.  This function is also
        !          3378:    used from hsync_handler to finish up the line; for this case, we check
        !          3379:    hpos against maxhpos.  */
        !          3380: STATIC_INLINE void sync_copper_with_cpu (int hpos, int do_schedule, unsigned int addr)
1.1.1.13  root     3381: {
1.1.1.15! root     3382:     /* Need to let the copper advance to the current position.  */
1.1.1.13  root     3383:     if (eventtab[ev_copper].active) {
1.1.1.15! root     3384:        if (hpos != maxhpos) {
        !          3385:            /* There might be reasons why we don't actually need to bother
        !          3386:               updating the copper.  */
        !          3387:            if (hpos < cop_state.first_sync)
        !          3388:                return;
        !          3389: 
        !          3390:            if ((cop_state.regtypes_modified & regtypes[addr & 0x1FE]) == 0)
        !          3391:                return;
1.1.1.13  root     3392:        }
1.1.1.15! root     3393: 
        !          3394:        eventtab[ev_copper].active = 0;
        !          3395:        if (do_schedule)
        !          3396:            events_schedule ();
        !          3397:        set_special (SPCFLAG_COPPER);
1.1.1.13  root     3398:     }
1.1.1.15! root     3399:     if (copper_enabled_thisline)
1.1.1.13  root     3400:        update_copper (hpos);
                   3401: }
                   3402: 
                   3403: static void do_sprites (int currvp, int hpos)
1.1.1.4   root     3404: {
                   3405:     int i;
1.1.1.13  root     3406:     int maxspr, minspr;
1.1.1.15! root     3407:     int sw = sprite_width >> 3; 
1.1.1.2   root     3408: 
1.1.1.4   root     3409:     /* I don't know whether this is right. Some programs write the sprite pointers
1.1.1.13  root     3410:      * directly at the start of the copper list. With the test against currvp, the
1.1.1.4   root     3411:      * first two words of data are read on the second line in the frame. The problem
                   3412:      * occurs when the program jumps to another copperlist a few lines further down
                   3413:      * which _also_ writes the sprite pointer registers. This means that a) writing
                   3414:      * to the sprite pointers sets the state to SPR_restart; or b) that sprite DMA
                   3415:      * is disabled until the end of the vertical blanking interval. The HRM
                   3416:      * isn't clear - it says that the vertical sprite position can be set to any
                   3417:      * value, but this wouldn't be the first mistake... */
                   3418:     /* Update: I modified one of the programs to write the sprite pointers the
                   3419:      * second time only _after_ the VBlank interval, and it showed the same behaviour
                   3420:      * as it did unmodified under UAE with the above check. This indicates that the
                   3421:      * solution below is correct. */
1.1.1.9   root     3422:     /* Another update: seems like we have to use the NTSC value here (see Sanity Turmoil
                   3423:      * demo).  */
1.1.1.10  root     3424:     /* Maximum for Sanity Turmoil: 27.
                   3425:        Minimum for Sanity Arte: 22.  */
                   3426:     if (currvp < sprite_vblank_endline)
1.1.1.4   root     3427:        return;
1.1.1.3   root     3428: 
1.1.1.4   root     3429:     /* The graph in the HRM, p. 195 seems to indicate that sprite 0 is
                   3430:      * fetched at cycle 0x14 and thus can't be disabled by bitplane DMA. */
1.1.1.13  root     3431:     maxspr = hpos / 4 - 0x14 / 4;
                   3432:     minspr = last_sprite_hpos / 4 - 0x14 / 4;
                   3433: 
1.1.1.15! root     3434:     if (minspr > MAX_SPRITES || maxspr < 0)
1.1.1.4   root     3435:        return;
1.1.1.13  root     3436: 
1.1.1.15! root     3437:     if (maxspr > MAX_SPRITES)
        !          3438:        maxspr = MAX_SPRITES;
1.1.1.13  root     3439:     if (minspr < 0)
                   3440:         minspr = 0;
1.1.1.2   root     3441: 
1.1.1.13  root     3442:     for (i = minspr; i < maxspr; i++) {
1.1.1.4   root     3443:        int fetch = 0;
1.1.1.2   root     3444: 
1.1.1.10  root     3445:        if (spr[i].on == 0)
1.1.1.4   root     3446:            continue;
1.1.1.2   root     3447: 
1.1.1.10  root     3448:        if (spr[i].state == SPR_restart) {
1.1.1.4   root     3449:            fetch = 2;
1.1.1.10  root     3450:            spr[i].on = 1;
                   3451:        } else if ((spr[i].state == SPR_waiting_start && spr[i].vstart == vpos) || spr[i].state == SPR_waiting_stop) {
1.1.1.4   root     3452:            fetch = 1;
1.1.1.10  root     3453:            spr[i].state = SPR_waiting_stop;
1.1.1.2   root     3454:        }
1.1.1.10  root     3455:        if ((spr[i].state == SPR_waiting_stop || spr[i].state == SPR_waiting_start) && spr[i].vstop == vpos) {
1.1.1.4   root     3456:            fetch = 2;
1.1.1.10  root     3457:            spr[i].state = SPR_waiting_start;
1.1.1.2   root     3458:        }
1.1.1.3   root     3459: 
1.1.1.9   root     3460:        if (fetch && dmaen (DMA_SPRITE)) {
1.1.1.15! root     3461:            uae_u16 data1 = chipmem_wget (spr[i].pt);
        !          3462:            uae_u16 data2 = chipmem_wget (spr[i].pt + sw);
1.1.1.3   root     3463: 
1.1.1.4   root     3464:            if (fetch == 1) {
                   3465:                /* Hack for X mouse auto-calibration */
                   3466:                if (i == 0 && !sprvbfl && ((sprpos[0] & 0xff) << 2) > 2 * DISPLAY_LEFT_SHIFT) {
1.1.1.9   root     3467:                    spr0ctl = sprctl[0];
                   3468:                    spr0pos = sprpos[0];
                   3469:                    sprvbfl = 2;
1.1.1.3   root     3470:                }
1.1.1.9   root     3471:                SPRxDATB_1 (data2, i);
                   3472:                SPRxDATA_1 (data1, i);
1.1.1.15! root     3473:                switch (sw)
        !          3474:                    {
        !          3475:                    case 64 >> 3:
        !          3476:                    sprdata[i][3] = chipmem_wget (spr[i].pt + 6);
        !          3477:                    sprdatb[i][3] = chipmem_wget (spr[i].pt + 6 + sw);
        !          3478:                    sprdata[i][2] = chipmem_wget (spr[i].pt + 4);
        !          3479:                    sprdatb[i][2] = chipmem_wget (spr[i].pt + 4 + sw);
        !          3480:                    /* fall through */
        !          3481:                    case 32 >> 3:
        !          3482:                    sprdata[i][1] = chipmem_wget (spr[i].pt + 2);
        !          3483:                    sprdatb[i][1] = chipmem_wget (spr[i].pt + 2 + sw);
        !          3484:                    break;
        !          3485:                }
1.1.1.4   root     3486:            } else {
1.1.1.9   root     3487:                SPRxPOS_1 (data1, i);
                   3488:                SPRxCTL_1 (data2, i);
1.1.1.3   root     3489:            }
1.1.1.15! root     3490:            spr[i].pt += sw * 2;
1.1       root     3491:        }
                   3492:     }
1.1.1.13  root     3493:     last_sprite_hpos = hpos;
1.1       root     3494: }
                   3495: 
1.1.1.4   root     3496: static void init_sprites (void)
1.1       root     3497: {
1.1.1.4   root     3498:     int i;
1.1.1.2   root     3499: 
1.1.1.15! root     3500:     for (i = 0; i < MAX_SPRITES; i++) {
1.1.1.4   root     3501:        /* ???? */
1.1.1.10  root     3502:        spr[i].state = SPR_stop;
                   3503:        spr[i].on = 0;
1.1.1.4   root     3504:     }
1.1.1.2   root     3505: 
1.1.1.4   root     3506:     memset (sprpos, 0, sizeof sprpos);
                   3507:     memset (sprctl, 0, sizeof sprctl);
                   3508: }
1.1.1.2   root     3509: 
1.1.1.3   root     3510: static void adjust_array_sizes (void)
1.1.1.2   root     3511: {
                   3512: #ifdef OS_WITHOUT_MEMORY_MANAGEMENT
1.1.1.13  root     3513:     if (delta_sprite_entry) {
1.1.1.3   root     3514:        void *p1,*p2;
1.1.1.13  root     3515:        int mcc = max_sprite_entry + 50 + delta_sprite_entry;
                   3516:        delta_sprite_entry = 0;
                   3517:        p1 = realloc (sprite_entries[0], mcc * sizeof (struct sprite_entry));
                   3518:        p2 = realloc (sprite_entries[1], mcc * sizeof (struct sprite_entry));
                   3519:        if (p1) sprite_entries[0] = p1;
                   3520:        if (p2) sprite_entries[1] = p2;
1.1.1.3   root     3521:        if (p1 && p2) {
1.1.1.13  root     3522:            fprintf (stderr, "new max_sprite_entry=%d\n",mcc);
                   3523:            max_sprite_entry = mcc;
1.1.1.2   root     3524:        }
                   3525:     }
1.1.1.3   root     3526:     if (delta_color_change) {
                   3527:        void *p1,*p2;
                   3528:        int mcc = max_color_change + 200 + delta_color_change;
                   3529:        delta_color_change = 0;
                   3530:        p1 = realloc (color_changes[0], mcc * sizeof (struct color_change));
                   3531:        p2 = realloc (color_changes[1], mcc * sizeof (struct color_change));
                   3532:        if (p1) color_changes[0] = p1;
                   3533:        if (p2) color_changes[1] = p2;
                   3534:        if (p1 && p2) {
                   3535:            fprintf (stderr, "new max_color_change=%d\n",mcc);
1.1.1.2   root     3536:            max_color_change = mcc;
1.1.1.3   root     3537:        }
                   3538:     }
1.1.1.2   root     3539: #endif
1.1.1.3   root     3540: }
                   3541: 
1.1.1.4   root     3542: static void init_hardware_frame (void)
1.1.1.3   root     3543: {
1.1.1.4   root     3544:     next_lineno = 0;
                   3545:     nextline_how = nln_normal;
                   3546:     diwstate = DIW_waiting_start;
                   3547:     hdiwstate = DIW_waiting_start;
                   3548: }
1.1.1.2   root     3549: 
1.1.1.4   root     3550: void init_hardware_for_drawing_frame (void)
                   3551: {
1.1.1.3   root     3552:     adjust_array_sizes ();
                   3553: 
1.1.1.13  root     3554:     /* Avoid this code in the first frame after a customreset.  */
                   3555:     if (prev_sprite_entries) {
                   3556:        int first_pixel = prev_sprite_entries[0].first_pixel;
                   3557:        int npixels = prev_sprite_entries[prev_next_sprite_entry].first_pixel - first_pixel;
                   3558:        memset (spixels + first_pixel, 0, npixels * sizeof *spixels);
                   3559:        memset (spixstate.bytes + first_pixel, 0, npixels * sizeof *spixstate.bytes);
                   3560:     }
                   3561:     prev_next_sprite_entry = next_sprite_entry;
1.1.1.3   root     3562: 
1.1.1.13  root     3563:     next_color_change = 0;
                   3564:     next_sprite_entry = 0;
1.1.1.2   root     3565:     next_color_entry = 0;
                   3566:     remembered_color_entry = -1;
1.1.1.13  root     3567: 
                   3568:     prev_sprite_entries = sprite_entries[current_change_set];
                   3569:     curr_sprite_entries = sprite_entries[current_change_set ^ 1];
1.1.1.2   root     3570:     prev_color_changes = color_changes[current_change_set];
                   3571:     curr_color_changes = color_changes[current_change_set ^ 1];
                   3572:     prev_color_tables = color_tables[current_change_set];
                   3573:     curr_color_tables = color_tables[current_change_set ^ 1];
1.1.1.3   root     3574: 
1.1.1.2   root     3575:     prev_drawinfo = line_drawinfo[current_change_set];
1.1.1.4   root     3576:     curr_drawinfo = line_drawinfo[current_change_set ^ 1];
                   3577:     current_change_set ^= 1;
1.1.1.3   root     3578: 
1.1.1.4   root     3579:     color_src_match = color_dest_match = -1;
1.1.1.13  root     3580: 
                   3581:     /* Use both halves of the array in alternating fashion.  */
                   3582:     curr_sprite_entries[0].first_pixel = current_change_set * MAX_SPR_PIXELS;
                   3583:     next_sprite_forced = 1;
1.1.1.3   root     3584: }
                   3585: 
1.1.1.15! root     3586: static void do_savestate(void);
        !          3587: 
1.1.1.2   root     3588: static void vsync_handler (void)
1.1       root     3589: {
1.1.1.15! root     3590: #if 0
        !          3591:     static int old_clxdat;
        !          3592:     if (clxdat != old_clxdat) {
        !          3593:        printf ("CLXDAT %04x\n", clxdat);
        !          3594:        old_clxdat = clxdat;
        !          3595:     }
        !          3596: #endif
1.1.1.12  root     3597:     n_frames++;
                   3598: 
1.1.1.4   root     3599:     if (currprefs.m68k_speed == -1) {
                   3600:        frame_time_t curr_time = read_processor_time ();
1.1.1.3   root     3601:        vsyncmintime += vsynctime;
                   3602:        /* @@@ Mathias? How do you think we should do this? */
                   3603:        /* If we are too far behind, or we just did a reset, adjust the
                   3604:         * needed time. */
1.1.1.4   root     3605:        if ((long int)(curr_time - vsyncmintime) > 0 || rpt_did_reset)
1.1.1.3   root     3606:            vsyncmintime = curr_time + vsynctime;
1.1.1.4   root     3607:        rpt_did_reset = 0;
1.1.1.3   root     3608:     }
1.1.1.4   root     3609: 
1.1.1.3   root     3610:     handle_events ();
1.1       root     3611: 
1.1.1.3   root     3612:     getjoystate (0, &joy0dir, &joy0button);
                   3613:     getjoystate (1, &joy1dir, &joy1button);
1.1       root     3614: 
1.1.1.4   root     3615:     INTREQ (0x8020);
1.1.1.3   root     3616:     if (bplcon0 & 4)
1.1.1.2   root     3617:        lof ^= 0x8000;
1.1.1.3   root     3618: 
1.1.1.4   root     3619:     vsync_handle_redraw (lof, lof_changed);
                   3620:     if (quit_program > 0)
1.1.1.3   root     3621:        return;
                   3622: 
1.1.1.4   root     3623:     {
1.1.1.3   root     3624:        static int cnt = 0;
                   3625:        if (cnt == 0) {
                   3626:            /* resolution_check_change (); */
                   3627:            DISK_check_change ();
                   3628:            cnt = 5;
                   3629:        }
                   3630:        cnt--;
1.1.1.2   root     3631:     }
1.1.1.3   root     3632: 
1.1.1.15! root     3633:     /* Start a new set of copper records.  */
        !          3634:     curr_cop_set ^= 1;
        !          3635:     nr_cop_records[curr_cop_set] = 0;
        !          3636: 
1.1.1.7   root     3637:     /* For now, let's only allow this to change at vsync time.  It gets too
                   3638:      * hairy otherwise.  */
                   3639:     if (beamcon0 != new_beamcon0)
                   3640:        init_hz ();
                   3641: 
1.1.1.2   root     3642:     lof_changed = 0;
1.1.1.3   root     3643: 
1.1.1.4   root     3644:     cop_state.ip = cop1lc;
                   3645:     cop_state.state = COP_read1;
                   3646:     cop_state.vpos = 0;
                   3647:     cop_state.hpos = 0;
                   3648:     cop_state.ignore_next = 0;
                   3649: 
                   3650:     init_hardware_frame ();
                   3651: 
1.1       root     3652: #ifdef HAVE_GETTIMEOFDAY
                   3653:     {
                   3654:        struct timeval tv;
                   3655:        unsigned long int newtime;
1.1.1.3   root     3656: 
1.1.1.9   root     3657:        gettimeofday (&tv,NULL);
1.1       root     3658:        newtime = (tv.tv_sec-seconds_base) * 1000 + tv.tv_usec / 1000;
1.1.1.3   root     3659: 
                   3660:        if (!bogusframe) {
1.1.1.6   root     3661:            lastframetime = newtime - msecs;
                   3662: 
                   3663: #if 0 /* This doesn't appear to work too well yet... later.  */
                   3664:            if (n_consecutive_skipped > currprefs.sound_pri_cutoff
                   3665:                || lastframetime < currprefs.sound_pri_time)
                   3666:            {
                   3667:                n_consecutive_skipped = 0;
                   3668:                clear_inhibit_frame (IHF_SOUNDADJUST);
                   3669:            } else {
                   3670:                n_consecutive_skipped++;
                   3671:                set_inhibit_frame (IHF_SOUNDADJUST);
                   3672:                total_skipped++;
                   3673:            }
                   3674: #endif
                   3675: 
                   3676:            frametime += lastframetime;
1.1       root     3677:            timeframes++;
1.1.1.6   root     3678: 
                   3679:            if ((timeframes & 127) == 0)
                   3680:                gui_fps (1000 * timeframes / frametime);
1.1       root     3681:        }
                   3682:        msecs = newtime;
                   3683:        bogusframe = 0;
                   3684:     }
                   3685: #endif
1.1.1.3   root     3686:     if (ievent_alive > 0)
                   3687:        ievent_alive--;
1.1.1.7   root     3688:     if (timehack_alive > 0)
                   3689:        timehack_alive--;
1.1.1.15! root     3690:     CIA_vsync_handler ();
1.1       root     3691: }
                   3692: 
1.1.1.4   root     3693: static void hsync_handler (void)
1.1       root     3694: {
1.1.1.15! root     3695:     /* Using 0x8A makes sure that we don't accidentally trip over the
        !          3696:        modified_regtypes check.  */
        !          3697:     sync_copper_with_cpu (maxhpos, 0, 0x8A);
1.1.1.10  root     3698: 
1.1.1.2   root     3699:     finish_decisions ();
1.1.1.15! root     3700:     if (thisline_decision.plfleft != -1) {
        !          3701:        if (currprefs.collision_level > 1)
        !          3702:            do_sprite_collisions ();
        !          3703:        if (currprefs.collision_level > 2)
        !          3704:            do_playfield_collisions ();
        !          3705:     }
1.1.1.5   root     3706:     hsync_record_line_state (next_lineno, nextline_how, thisline_changed);
1.1       root     3707: 
1.1.1.14  root     3708:     eventtab[ev_hsync].evtime += get_cycles () - eventtab[ev_hsync].oldcycles;
                   3709:     eventtab[ev_hsync].oldcycles = get_cycles ();
1.1.1.8   root     3710:     CIA_hsync_handler ();
1.1.1.3   root     3711: 
                   3712:     if (currprefs.produce_sound > 0) {
1.1       root     3713:        int nr;
1.1.1.4   root     3714: 
                   3715:        update_audio ();
                   3716: 
1.1       root     3717:        /* Sound data is fetched at the beginning of each line */
1.1.1.14  root     3718:        for (nr = 0; nr < 6; nr++) {
1.1       root     3719:            struct audio_channel_data *cdp = audio_channel + nr;
1.1.1.3   root     3720: 
1.1       root     3721:            if (cdp->data_written == 2) {
                   3722:                cdp->data_written = 0;
1.1.1.15! root     3723:                cdp->nextdat = chipmem_wget(cdp->pt);
1.1       root     3724:                cdp->pt += 2;
                   3725:                if (cdp->state == 2 || cdp->state == 3) {
                   3726:                    if (cdp->wlen == 1) {
                   3727:                        cdp->pt = cdp->lc;
                   3728:                        cdp->wlen = cdp->len;
                   3729:                        cdp->intreq2 = 1;
                   3730:                    } else
                   3731:                        cdp->wlen--;
                   3732:                }
                   3733:            }
                   3734:        }
                   3735:     }
1.1.1.4   root     3736: 
                   3737:     hardware_line_completed (next_lineno);
                   3738: 
1.1       root     3739:     if (++vpos == (maxvpos + (lof != 0))) {
                   3740:        vpos = 0;
1.1.1.15! root     3741:        vsync_handler ();
1.1       root     3742:     }
1.1.1.2   root     3743: 
1.1.1.15! root     3744:     DISK_update ();
        !          3745: 
1.1.1.4   root     3746:     is_lastline = vpos + 1 == maxvpos + (lof != 0) && currprefs.m68k_speed == -1 && ! rpt_did_reset;
1.1.1.3   root     3747: 
1.1.1.4   root     3748:     if ((bplcon0 & 4) && currprefs.gfx_linedbl)
                   3749:        notice_interlace_seen ();
1.1.1.2   root     3750: 
                   3751:     if (framecnt == 0) {
1.1.1.4   root     3752:        int lineno = vpos;
                   3753:        nextline_how = nln_normal;
1.1.1.3   root     3754:        if (currprefs.gfx_linedbl) {
1.1       root     3755:            lineno *= 2;
1.1.1.5   root     3756:            nextline_how = currprefs.gfx_linedbl == 1 ? nln_doubled : nln_nblack;
1.1.1.2   root     3757:            if (bplcon0 & 4) {
                   3758:                if (!lof) {
                   3759:                    lineno++;
1.1.1.4   root     3760:                    nextline_how = nln_lower;
1.1.1.2   root     3761:                } else {
1.1.1.4   root     3762:                    nextline_how = nln_upper;
1.1.1.2   root     3763:                }
1.1       root     3764:            }
                   3765:        }
                   3766:        next_lineno = lineno;
1.1.1.2   root     3767:        reset_decisions ();
1.1       root     3768:     }
1.1.1.3   root     3769:     if (uae_int_requested) {
                   3770:        set_uae_int_flag ();
                   3771:        INTREQ (0xA000);
                   3772:     }
1.1.1.9   root     3773:     /* See if there's a chance of a copper wait ending this line.  */
                   3774:     cop_state.hpos = 0;
                   3775:     compute_spcflag_copper ();
1.1.1.3   root     3776: }
                   3777: 
1.1.1.15! root     3778: static void init_regtypes (void)
        !          3779: {
        !          3780:     int i;
        !          3781:     for (i = 0; i < 512; i += 2) {
        !          3782:        regtypes[i] = REGTYPE_ALL;
        !          3783:        if ((i >= 0x20 && i < 0x28) || i == 0x08 || i == 0x7E)
        !          3784:            regtypes[i] = REGTYPE_DISK;
        !          3785:        else if (i >= 0x68 && i < 0x70)
        !          3786:            regtypes[i] = REGTYPE_NONE;
        !          3787:        else if (i >= 0x40 && i < 0x78)
        !          3788:            regtypes[i] = REGTYPE_BLITTER;
        !          3789:        else if (i >= 0xA0 && i < 0xE0 && (i & 0xF) < 0xE)
        !          3790:            regtypes[i] = REGTYPE_AUDIO;
        !          3791:        else if (i >= 0xA0 && i < 0xE0)
        !          3792:            regtypes[i] = REGTYPE_NONE;
        !          3793:        else if (i >= 0xE0 && i < 0x100)
        !          3794:            regtypes[i] = REGTYPE_PLANE;
        !          3795:        else if (i >= 0x120 && i < 0x180)
        !          3796:            regtypes[i] = REGTYPE_SPRITE;
        !          3797:        else if (i >= 0x180 && i < 0x1C0)
        !          3798:            regtypes[i] = REGTYPE_COLOR;
        !          3799:        else switch (i) {
        !          3800:        case 0x02:
        !          3801:            /* DMACONR - setting this to REGTYPE_BLITTER will cause it to
        !          3802:               conflict with DMACON (since that is REGTYPE_ALL), and the
        !          3803:               blitter registers (for the BBUSY bit), but nothing else,
        !          3804:               which is (I think) what we want.  */
        !          3805:            regtypes[i] = REGTYPE_BLITTER;
        !          3806:            break;
        !          3807:        case 0x04: case 0x06: case 0x2A: case 0x2C:
        !          3808:            regtypes[i] = REGTYPE_POS;
        !          3809:            break;
        !          3810:        case 0x0A: case 0x0C:
        !          3811:        case 0x12: case 0x14: case 0x16:
        !          3812:        case 0x36:
        !          3813:            regtypes[i] = REGTYPE_JOYPORT;
        !          3814:            break;
        !          3815:        case 0x104:
        !          3816:        case 0x102:
        !          3817:            regtypes[i] = REGTYPE_PLANE;
        !          3818:            break;
        !          3819:        case 0x88: case 0x8A:
        !          3820:        case 0x8E: case 0x90: case 0x92: case 0x94:
        !          3821:        case 0x96:
        !          3822:        case 0x100:
        !          3823:            regtypes[i] |= REGTYPE_FORCE;
        !          3824:            break;
        !          3825:        }
        !          3826:     }
        !          3827: }
        !          3828: 
        !          3829: void init_eventtab (void)
1.1.1.3   root     3830: {
                   3831:     int i;
                   3832: 
1.1.1.15! root     3833:     currcycle = 0;
        !          3834:     for (i = 0; i < ev_max; i++) {
1.1.1.3   root     3835:        eventtab[i].active = 0;
                   3836:        eventtab[i].oldcycles = 0;
                   3837:     }
1.1.1.4   root     3838: 
1.1.1.3   root     3839:     eventtab[ev_cia].handler = CIA_handler;
                   3840:     eventtab[ev_hsync].handler = hsync_handler;
1.1.1.14  root     3841:     eventtab[ev_hsync].evtime = maxhpos * CYCLE_UNIT + get_cycles ();
1.1.1.3   root     3842:     eventtab[ev_hsync].active = 1;
                   3843: 
1.1.1.10  root     3844:     eventtab[ev_copper].handler = copper_handler;
                   3845:     eventtab[ev_copper].active = 0;
1.1.1.3   root     3846:     eventtab[ev_blitter].handler = blitter_handler;
                   3847:     eventtab[ev_blitter].active = 0;
1.1.1.11  root     3848:     eventtab[ev_disk].handler = DISK_handler;
                   3849:     eventtab[ev_disk].active = 0;
1.1.1.14  root     3850:     eventtab[ev_audio].handler = audio_evhandler;
                   3851:     eventtab[ev_audio].active = 0;
1.1.1.3   root     3852:     events_schedule ();
1.1       root     3853: }
                   3854: 
1.1.1.3   root     3855: void customreset (void)
1.1       root     3856: {
1.1.1.4   root     3857:     int i;
1.1.1.11  root     3858:     int zero = 0;
1.1       root     3859: #ifdef HAVE_GETTIMEOFDAY
                   3860:     struct timeval tv;
                   3861: #endif
1.1.1.2   root     3862: 
1.1.1.15! root     3863:     if (! savestate_state) {
        !          3864:        currprefs.chipset_mask = changed_prefs.chipset_mask;
        !          3865:        if ((currprefs.chipset_mask & CSMASK_AGA) == 0) {
        !          3866:            for (i = 0; i < 32; i++) {
        !          3867:                current_colors.color_regs_ecs[i] = 0;
        !          3868:                current_colors.acolors[i] = xcolors[0];
        !          3869:            }
        !          3870:        } else {
        !          3871:             for (i = 0; i < 256; i++) {
        !          3872:                current_colors.color_regs_aga[i] = 0;
        !          3873:                current_colors.acolors[i] = CONVERT_RGB (zero);
        !          3874:            }
1.1.1.11  root     3875:        }
1.1.1.15! root     3876: 
        !          3877:        clx_sprmask = 0xFF;
        !          3878:        clxdat = 0;
        !          3879: 
        !          3880:        /* Clear the armed flags of all sprites.  */
        !          3881:        memset (spr, 0, sizeof spr);
        !          3882:        nr_armed = 0;
        !          3883: 
        !          3884:        dmacon = intena = 0;
        !          3885: 
        !          3886:        copcon = 0;
        !          3887:        DSKLEN (0, 0);
        !          3888: 
        !          3889:        bplcon4 = 0x11; /* Get AGA chipset into ECS compatibility mode */
        !          3890:        bplcon3 = 0xC00;
        !          3891: 
        !          3892:        FMODE (0);
        !          3893:        CLXCON (0);
1.1.1.9   root     3894:     }
1.1.1.3   root     3895: 
1.1.1.12  root     3896:     n_frames = 0;
                   3897: 
1.1.1.3   root     3898:     expamem_reset ();
1.1.1.4   root     3899: 
1.1.1.12  root     3900:     DISK_reset ();
1.1.1.3   root     3901:     CIA_reset ();
1.1.1.13  root     3902:     unset_special (~(SPCFLAG_BRK | SPCFLAG_MODE_CHANGE));
1.1.1.3   root     3903: 
1.1.1.2   root     3904:     vpos = 0;
1.1       root     3905:     lof = 0;
1.1.1.3   root     3906: 
1.1.1.4   root     3907:     if (needmousehack ()) {
1.1.1.3   root     3908: #if 0
1.1.1.4   root     3909:        mousehack_setfollow();
1.1.1.3   root     3910: #else
1.1.1.4   root     3911:        mousehack_setdontcare();
1.1.1.3   root     3912: #endif
1.1       root     3913:     } else {
                   3914:        mousestate = normal_mouse;
                   3915:     }
1.1.1.3   root     3916:     ievent_alive = 0;
1.1.1.7   root     3917:     timehack_alive = 0;
1.1.1.3   root     3918: 
1.1.1.13  root     3919:     curr_sprite_entries = 0;
                   3920:     prev_sprite_entries = 0;
                   3921:     sprite_entries[0][0].first_pixel = 0;
                   3922:     sprite_entries[1][0].first_pixel = MAX_SPR_PIXELS;
                   3923:     sprite_entries[0][1].first_pixel = 0;
                   3924:     sprite_entries[1][1].first_pixel = MAX_SPR_PIXELS;
                   3925:     memset (spixels, 0, sizeof spixels);
                   3926:     memset (&spixstate, 0, sizeof spixstate);
1.1       root     3927: 
                   3928:     bltstate = BLT_done;
1.1.1.4   root     3929:     cop_state.state = COP_stop;
1.1.1.2   root     3930:     diwstate = DIW_waiting_start;
1.1.1.3   root     3931:     hdiwstate = DIW_waiting_start;
1.1.1.14  root     3932:     currcycle = 0;
1.1.1.3   root     3933: 
1.1.1.14  root     3934:     new_beamcon0 = currprefs.ntscmode ? 0x00 : 0x20;
1.1.1.7   root     3935:     init_hz ();
                   3936: 
                   3937:     audio_reset ();
                   3938: 
1.1.1.3   root     3939:     init_sprites ();
                   3940: 
1.1.1.2   root     3941:     init_hardware_frame ();
1.1.1.4   root     3942:     reset_drawing ();
                   3943: 
1.1.1.2   root     3944:     reset_decisions ();
1.1.1.3   root     3945: 
1.1       root     3946: #ifdef HAVE_GETTIMEOFDAY
1.1.1.4   root     3947:     gettimeofday (&tv, NULL);
1.1       root     3948:     seconds_base = tv.tv_sec;
                   3949:     bogusframe = 1;
                   3950: #endif
1.1.1.15! root     3951: 
        !          3952:     init_regtypes ();
        !          3953: 
        !          3954:     sprite_buffer_res = currprefs.chipset_mask & CSMASK_AGA ? RES_HIRES : RES_LORES;
        !          3955:     if (savestate_state == STATE_RESTORE) {
        !          3956:        uae_u16 v;
        !          3957:        uae_u32 vv;
        !          3958: 
        !          3959:        update_adkmasks ();
        !          3960:        INTENA (0);
        !          3961:        INTREQ (0);
        !          3962: #if 0
        !          3963:        DMACON (0, 0);
        !          3964: #endif
        !          3965:        COPJMP1 (0);
        !          3966:        if (diwhigh)
        !          3967:            diwhigh_written = 1;
        !          3968:        v = bplcon0;
        !          3969:        BPLCON0 (0, 0);
        !          3970:        BPLCON0 (0, v);
        !          3971:        FMODE (v);
        !          3972:        if (!(currprefs.chipset_mask & CSMASK_AGA)) {
        !          3973:            for(i = 0 ; i < 32 ; i++)  {
        !          3974:                vv = current_colors.color_regs_ecs[i];
        !          3975:                current_colors.color_regs_ecs[i] = -1;
        !          3976:                record_color_change (0, i, vv);
        !          3977:                remembered_color_entry = -1;
        !          3978:                current_colors.color_regs_ecs[i] = vv;
        !          3979:                current_colors.acolors[i] = xcolors[vv];
        !          3980:            }
        !          3981:        } else {
        !          3982:            for(i = 0 ; i < 256 ; i++)  {
        !          3983:                vv = current_colors.color_regs_aga[i];
        !          3984:                current_colors.color_regs_aga[i] = -1;
        !          3985:                record_color_change (0, i, vv);
        !          3986:                remembered_color_entry = -1;
        !          3987:                current_colors.color_regs_aga[i] = vv;
        !          3988:                current_colors.acolors[i] = CONVERT_RGB(vv);
        !          3989:            }
        !          3990:        }
        !          3991:        calcdiw ();
        !          3992:        write_log ("State restored\n");
        !          3993:        dumpcustom ();
        !          3994:        for (i = 0; i < 8; i++)
        !          3995:            nr_armed += spr[i].armed != 0;
        !          3996:     }
        !          3997:     expand_sprres ();
1.1       root     3998: }
                   3999: 
1.1.1.3   root     4000: void dumpcustom (void)
1.1       root     4001: {
1.1.1.6   root     4002:     write_log ("DMACON: %x INTENA: %x INTREQ: %x VPOS: %x HPOS: %x\n", DMACONR(),
                   4003:               (unsigned int)intena, (unsigned int)intreq, (unsigned int)vpos, (unsigned int)current_hpos());
                   4004:     write_log ("COP1LC: %08lx, COP2LC: %08lx\n", (unsigned long)cop1lc, (unsigned long)cop2lc);
1.1.1.13  root     4005:     write_log ("DIWSTRT: %04x DIWSTOP: %04x DDFSTRT: %04x DDFSTOP: %04x\n",
                   4006:               (unsigned int)diwstrt, (unsigned int)diwstop, (unsigned int)ddfstrt, (unsigned int)ddfstop);
1.1.1.3   root     4007:     if (timeframes) {
1.1.1.6   root     4008:        write_log ("Average frame time: %d ms [frames: %d time: %d]\n",
                   4009:                   frametime / timeframes, timeframes, frametime);
                   4010:        if (total_skipped)
                   4011:            write_log ("Skipped frames: %d\n", total_skipped);
1.1       root     4012:     }
1.1.1.4   root     4013:     /*for (i=0; i<256; i++) if (blitcount[i]) fprintf (stderr, "minterm %x = %d\n",i,blitcount[i]);  blitter debug */
1.1       root     4014: }
                   4015: 
1.1.1.3   root     4016: int intlev (void)
1.1       root     4017: {
1.1.1.3   root     4018:     uae_u16 imask = intreq & intena;
1.1       root     4019:     if (imask && (intena & 0x4000)){
                   4020:        if (imask & 0x2000) return 6;
                   4021:        if (imask & 0x1800) return 5;
                   4022:        if (imask & 0x0780) return 4;
                   4023:        if (imask & 0x0070) return 3;
                   4024:        if (imask & 0x0008) return 2;
                   4025:        if (imask & 0x0007) return 1;
                   4026:     }
                   4027:     return -1;
                   4028: }
                   4029: 
1.1.1.4   root     4030: static void gen_custom_tables (void)
                   4031: {
                   4032:     int i;
                   4033:     for (i = 0; i < 256; i++) {
                   4034:        unsigned int j;
                   4035:        sprtaba[i] = ((((i >> 7) & 1) << 0)
                   4036:                      | (((i >> 6) & 1) << 2)
                   4037:                      | (((i >> 5) & 1) << 4)
                   4038:                      | (((i >> 4) & 1) << 6)
                   4039:                      | (((i >> 3) & 1) << 8)
                   4040:                      | (((i >> 2) & 1) << 10)
                   4041:                      | (((i >> 1) & 1) << 12)
                   4042:                      | (((i >> 0) & 1) << 14));
                   4043:        sprtabb[i] = sprtaba[i] * 2;
1.1.1.13  root     4044:        sprite_ab_merge[i] = (((i & 15) ? 1 : 0)
                   4045:                              | ((i & 240) ? 2 : 0));
1.1.1.4   root     4046:     }
1.1.1.13  root     4047:     for (i = 0; i < 16; i++) {
                   4048:        clxmask[i] = (((i & 1) ? 0xF : 0x3)
                   4049:                      | ((i & 2) ? 0xF0 : 0x30)
                   4050:                      | ((i & 4) ? 0xF00 : 0x300)
                   4051:                      | ((i & 8) ? 0xF000 : 0x3000));
                   4052:        sprclx[i] = (((i & 0x3) == 0x3 ? 1 : 0)
                   4053:                     | ((i & 0x5) == 0x5 ? 2 : 0)
                   4054:                     | ((i & 0x9) == 0x9 ? 4 : 0)
                   4055:                     | ((i & 0x6) == 0x6 ? 8 : 0)
                   4056:                     | ((i & 0xA) == 0xA ? 16 : 0)
                   4057:                     | ((i & 0xC) == 0xC ? 32 : 0)) << 9;
                   4058:     }
1.1.1.4   root     4059: }
                   4060: 
1.1.1.3   root     4061: void custom_init (void)
1.1       root     4062: {
1.1.1.7   root     4063:     uaecptr pos;
                   4064: 
1.1.1.4   root     4065: #ifdef OS_WITHOUT_MEMORY_MANAGEMENT
1.1       root     4066:     int num;
1.1.1.2   root     4067: 
1.1.1.4   root     4068:     for (num = 0; num < 2; num++) {
1.1.1.13  root     4069:        sprite_entries[num] = xmalloc (max_sprite_entry * sizeof (struct sprite_entry));
1.1.1.4   root     4070:        color_changes[num] = xmalloc (max_color_change * sizeof (struct color_change));
1.1.1.2   root     4071:     }
                   4072: #endif
1.1.1.3   root     4073: 
1.1.1.7   root     4074:     pos = here ();
                   4075: 
                   4076:     org (0xF0FF70);
                   4077:     calltrap (deftrap (mousehack_helper));
                   4078:     dw (RTS);
                   4079: 
                   4080:     org (0xF0FFA0);
                   4081:     calltrap (deftrap (timehack_helper));
                   4082:     dw (RTS);
                   4083: 
                   4084:     org (pos);
                   4085: 
1.1.1.4   root     4086:     gen_custom_tables ();
                   4087:     build_blitfilltable ();
                   4088: 
                   4089:     drawing_init ();
                   4090: 
                   4091:     mousestate = unknown_mouse;
                   4092: 
                   4093:     if (needmousehack ())
                   4094:        mousehack_setfollow();
1.1       root     4095: }
                   4096: 
                   4097: /* Custom chip memory bank */
                   4098: 
1.1.1.4   root     4099: static uae_u32 custom_lget (uaecptr) REGPARAM;
                   4100: static uae_u32 custom_wget (uaecptr) REGPARAM;
                   4101: static uae_u32 custom_bget (uaecptr) REGPARAM;
                   4102: static void custom_lput (uaecptr, uae_u32) REGPARAM;
                   4103: static void custom_wput (uaecptr, uae_u32) REGPARAM;
                   4104: static void custom_bput (uaecptr, uae_u32) REGPARAM;
1.1       root     4105: 
                   4106: addrbank custom_bank = {
                   4107:     custom_lget, custom_wget, custom_bget,
                   4108:     custom_lput, custom_wput, custom_bput,
1.1.1.15! root     4109:     default_xlate, default_check, NULL
1.1       root     4110: };
                   4111: 
1.1.1.13  root     4112: STATIC_INLINE uae_u32 REGPARAM2 custom_wget_1 (uaecptr addr)
1.1       root     4113: {
1.1.1.13  root     4114:     special_mem |= S_READ;
1.1.1.4   root     4115:     switch (addr & 0x1FE) {
1.1.1.13  root     4116:      case 0x002: return DMACONR ();
                   4117:      case 0x004: return VPOSR ();
                   4118:      case 0x006: return VHPOSR ();
                   4119: 
                   4120:      case 0x008: return DSKDATR (current_hpos ());
                   4121: 
                   4122:      case 0x00A: return JOY0DAT ();
                   4123:      case 0x00C: return JOY1DAT ();
                   4124:      case 0x00E: return CLXDAT ();
                   4125:      case 0x010: return ADKCONR ();
                   4126: 
                   4127:      case 0x012: return POT0DAT ();
                   4128:      case 0x016: return POTGOR ();
                   4129:      case 0x018: return SERDATR ();
                   4130:      case 0x01A: return DSKBYTR (current_hpos ());
                   4131:      case 0x01C: return INTENAR ();
                   4132:      case 0x01E: return INTREQR ();
                   4133:      case 0x07C: return DENISEID ();
                   4134: 
                   4135:      case 0x180: case 0x182: case 0x184: case 0x186: case 0x188: case 0x18A:
                   4136:      case 0x18C: case 0x18E: case 0x190: case 0x192: case 0x194: case 0x196:
                   4137:      case 0x198: case 0x19A: case 0x19C: case 0x19E: case 0x1A0: case 0x1A2:
                   4138:      case 0x1A4: case 0x1A6: case 0x1A8: case 0x1AA: case 0x1AC: case 0x1AE:
                   4139:      case 0x1B0: case 0x1B2: case 0x1B4: case 0x1B6: case 0x1B8: case 0x1BA:
                   4140:      case 0x1BC: case 0x1BE:
                   4141:        return COLOR_READ ((addr & 0x3E) / 2);
                   4142:        break;
                   4143: 
1.1       root     4144:      default:
1.1.1.13  root     4145:        custom_wput (addr, 0);
1.1       root     4146:        return 0xffff;
                   4147:     }
                   4148: }
                   4149: 
1.1.1.13  root     4150: uae_u32 REGPARAM2 custom_wget (uaecptr addr)
                   4151: {
1.1.1.15! root     4152:     sync_copper_with_cpu (current_hpos (), 1, addr);
1.1.1.13  root     4153:     return custom_wget_1 (addr);
                   4154: }
                   4155: 
1.1.1.3   root     4156: uae_u32 REGPARAM2 custom_bget (uaecptr addr)
1.1       root     4157: {
1.1.1.13  root     4158:     special_mem |= S_READ;
                   4159:     return custom_wget (addr & 0xfffe) >> (addr & 1 ? 0 : 8);
1.1       root     4160: }
                   4161: 
1.1.1.3   root     4162: uae_u32 REGPARAM2 custom_lget (uaecptr addr)
1.1       root     4163: {
1.1.1.13  root     4164:     special_mem |= S_READ;
                   4165:     return ((uae_u32)custom_wget (addr & 0xfffe) << 16) | custom_wget ((addr + 2) & 0xfffe);
1.1       root     4166: }
                   4167: 
1.1.1.4   root     4168: void REGPARAM2 custom_wput_1 (int hpos, uaecptr addr, uae_u32 value)
1.1       root     4169: {
                   4170:     addr &= 0x1FE;
1.1.1.3   root     4171:     switch (addr) {
                   4172:      case 0x020: DSKPTH (value); break;
                   4173:      case 0x022: DSKPTL (value); break;
1.1.1.13  root     4174:      case 0x024: DSKLEN (value, hpos); break;
1.1.1.3   root     4175:      case 0x026: DSKDAT (value); break;
                   4176: 
                   4177:      case 0x02A: VPOSW (value); break;
1.1.1.15! root     4178:      case 0x02E: COPCON (value); break;
1.1.1.3   root     4179:      case 0x030: SERDAT (value); break;
                   4180:      case 0x032: SERPER (value); break;
1.1.1.15! root     4181:      case 0x034: POTGO (value); break;
1.1.1.3   root     4182:      case 0x040: BLTCON0 (value); break;
                   4183:      case 0x042: BLTCON1 (value); break;
                   4184: 
                   4185:      case 0x044: BLTAFWM (value); break;
                   4186:      case 0x046: BLTALWM (value); break;
                   4187: 
                   4188:      case 0x050: BLTAPTH (value); break;
                   4189:      case 0x052: BLTAPTL (value); break;
                   4190:      case 0x04C: BLTBPTH (value); break;
                   4191:      case 0x04E: BLTBPTL (value); break;
                   4192:      case 0x048: BLTCPTH (value); break;
                   4193:      case 0x04A: BLTCPTL (value); break;
                   4194:      case 0x054: BLTDPTH (value); break;
                   4195:      case 0x056: BLTDPTL (value); break;
                   4196: 
                   4197:      case 0x058: BLTSIZE (value); break;
                   4198: 
                   4199:      case 0x064: BLTAMOD (value); break;
                   4200:      case 0x062: BLTBMOD (value); break;
                   4201:      case 0x060: BLTCMOD (value); break;
                   4202:      case 0x066: BLTDMOD (value); break;
                   4203: 
                   4204:      case 0x070: BLTCDAT (value); break;
                   4205:      case 0x072: BLTBDAT (value); break;
                   4206:      case 0x074: BLTADAT (value); break;
                   4207: 
                   4208:      case 0x07E: DSKSYNC (value); break;
                   4209: 
                   4210:      case 0x080: COP1LCH (value); break;
                   4211:      case 0x082: COP1LCL (value); break;
                   4212:      case 0x084: COP2LCH (value); break;
                   4213:      case 0x086: COP2LCL (value); break;
                   4214: 
                   4215:      case 0x088: COPJMP1 (value); break;
                   4216:      case 0x08A: COPJMP2 (value); break;
                   4217: 
1.1.1.4   root     4218:      case 0x08E: DIWSTRT (hpos, value); break;
                   4219:      case 0x090: DIWSTOP (hpos, value); break;
                   4220:      case 0x092: DDFSTRT (hpos, value); break;
                   4221:      case 0x094: DDFSTOP (hpos, value); break;
1.1.1.3   root     4222: 
1.1.1.13  root     4223:      case 0x096: DMACON (hpos, value); break;
1.1.1.3   root     4224:      case 0x098: CLXCON (value); break;
                   4225:      case 0x09A: INTENA (value); break;
                   4226:      case 0x09C: INTREQ (value); break;
                   4227:      case 0x09E: ADKCON (value); break;
                   4228: 
                   4229:      case 0x0A0: AUDxLCH (0, value); break;
                   4230:      case 0x0A2: AUDxLCL (0, value); break;
                   4231:      case 0x0A4: AUDxLEN (0, value); break;
                   4232:      case 0x0A6: AUDxPER (0, value); break;
                   4233:      case 0x0A8: AUDxVOL (0, value); break;
                   4234:      case 0x0AA: AUDxDAT (0, value); break;
                   4235: 
                   4236:      case 0x0B0: AUDxLCH (1, value); break;
                   4237:      case 0x0B2: AUDxLCL (1, value); break;
                   4238:      case 0x0B4: AUDxLEN (1, value); break;
                   4239:      case 0x0B6: AUDxPER (1, value); break;
                   4240:      case 0x0B8: AUDxVOL (1, value); break;
                   4241:      case 0x0BA: AUDxDAT (1, value); break;
                   4242: 
                   4243:      case 0x0C0: AUDxLCH (2, value); break;
                   4244:      case 0x0C2: AUDxLCL (2, value); break;
                   4245:      case 0x0C4: AUDxLEN (2, value); break;
                   4246:      case 0x0C6: AUDxPER (2, value); break;
                   4247:      case 0x0C8: AUDxVOL (2, value); break;
                   4248:      case 0x0CA: AUDxDAT (2, value); break;
                   4249: 
                   4250:      case 0x0D0: AUDxLCH (3, value); break;
                   4251:      case 0x0D2: AUDxLCL (3, value); break;
                   4252:      case 0x0D4: AUDxLEN (3, value); break;
                   4253:      case 0x0D6: AUDxPER (3, value); break;
                   4254:      case 0x0D8: AUDxVOL (3, value); break;
                   4255:      case 0x0DA: AUDxDAT (3, value); break;
                   4256: 
1.1.1.4   root     4257:      case 0x0E0: BPLPTH (hpos, value, 0); break;
                   4258:      case 0x0E2: BPLPTL (hpos, value, 0); break;
                   4259:      case 0x0E4: BPLPTH (hpos, value, 1); break;
                   4260:      case 0x0E6: BPLPTL (hpos, value, 1); break;
                   4261:      case 0x0E8: BPLPTH (hpos, value, 2); break;
                   4262:      case 0x0EA: BPLPTL (hpos, value, 2); break;
                   4263:      case 0x0EC: BPLPTH (hpos, value, 3); break;
                   4264:      case 0x0EE: BPLPTL (hpos, value, 3); break;
                   4265:      case 0x0F0: BPLPTH (hpos, value, 4); break;
                   4266:      case 0x0F2: BPLPTL (hpos, value, 4); break;
                   4267:      case 0x0F4: BPLPTH (hpos, value, 5); break;
                   4268:      case 0x0F6: BPLPTL (hpos, value, 5); break;
1.1.1.6   root     4269:      case 0x0F8: BPLPTH (hpos, value, 6); break;
                   4270:      case 0x0FA: BPLPTL (hpos, value, 6); break;
                   4271:      case 0x0FC: BPLPTH (hpos, value, 7); break;
                   4272:      case 0x0FE: BPLPTL (hpos, value, 7); break;
1.1.1.4   root     4273: 
                   4274:      case 0x100: BPLCON0 (hpos, value); break;
                   4275:      case 0x102: BPLCON1 (hpos, value); break;
                   4276:      case 0x104: BPLCON2 (hpos, value); break;
                   4277:      case 0x106: BPLCON3 (hpos, value); break;
1.1.1.3   root     4278: 
1.1.1.4   root     4279:      case 0x108: BPL1MOD (hpos, value); break;
                   4280:      case 0x10A: BPL2MOD (hpos, value); break;
1.1.1.3   root     4281: 
1.1.1.13  root     4282:      case 0x110: BPL1DAT (hpos, value); break;
1.1.1.3   root     4283:      case 0x112: BPL2DAT (value); break;
                   4284:      case 0x114: BPL3DAT (value); break;
                   4285:      case 0x116: BPL4DAT (value); break;
                   4286:      case 0x118: BPL5DAT (value); break;
                   4287:      case 0x11A: BPL6DAT (value); break;
1.1.1.6   root     4288:      case 0x11C: BPL7DAT (value); break;
                   4289:      case 0x11E: BPL8DAT (value); break;
1.1       root     4290: 
                   4291:      case 0x180: case 0x182: case 0x184: case 0x186: case 0x188: case 0x18A:
                   4292:      case 0x18C: case 0x18E: case 0x190: case 0x192: case 0x194: case 0x196:
                   4293:      case 0x198: case 0x19A: case 0x19C: case 0x19E: case 0x1A0: case 0x1A2:
                   4294:      case 0x1A4: case 0x1A6: case 0x1A8: case 0x1AA: case 0x1AC: case 0x1AE:
                   4295:      case 0x1B0: case 0x1B2: case 0x1B4: case 0x1B6: case 0x1B8: case 0x1BA:
1.1.1.2   root     4296:      case 0x1BC: case 0x1BE:
1.1.1.13  root     4297:        COLOR_WRITE (hpos, value & 0xFFF, (addr & 0x3E) / 2);
1.1.1.2   root     4298:        break;
                   4299:      case 0x120: case 0x124: case 0x128: case 0x12C:
1.1       root     4300:      case 0x130: case 0x134: case 0x138: case 0x13C:
1.1.1.4   root     4301:        SPRxPTH (hpos, value, (addr - 0x120) / 4);
1.1       root     4302:        break;
1.1.1.2   root     4303:      case 0x122: case 0x126: case 0x12A: case 0x12E:
1.1       root     4304:      case 0x132: case 0x136: case 0x13A: case 0x13E:
1.1.1.4   root     4305:        SPRxPTL (hpos, value, (addr - 0x122) / 4);
1.1       root     4306:        break;
1.1.1.2   root     4307:      case 0x140: case 0x148: case 0x150: case 0x158:
1.1       root     4308:      case 0x160: case 0x168: case 0x170: case 0x178:
1.1.1.4   root     4309:        SPRxPOS (hpos, value, (addr - 0x140) / 8);
1.1       root     4310:        break;
1.1.1.2   root     4311:      case 0x142: case 0x14A: case 0x152: case 0x15A:
1.1       root     4312:      case 0x162: case 0x16A: case 0x172: case 0x17A:
1.1.1.4   root     4313:        SPRxCTL (hpos, value, (addr - 0x142) / 8);
1.1       root     4314:        break;
                   4315:      case 0x144: case 0x14C: case 0x154: case 0x15C:
                   4316:      case 0x164: case 0x16C: case 0x174: case 0x17C:
1.1.1.4   root     4317:        SPRxDATA (hpos, value, (addr - 0x144) / 8);
1.1       root     4318:        break;
1.1.1.2   root     4319:      case 0x146: case 0x14E: case 0x156: case 0x15E:
1.1       root     4320:      case 0x166: case 0x16E: case 0x176: case 0x17E:
1.1.1.4   root     4321:        SPRxDATB (hpos, value, (addr - 0x146) / 8);
1.1       root     4322:        break;
1.1.1.3   root     4323: 
                   4324:      case 0x36: JOYTEST (value); break;
1.1.1.7   root     4325:      case 0x5A: BLTCON0L (value); break;
1.1.1.3   root     4326:      case 0x5C: BLTSIZV (value); break;
                   4327:      case 0x5E: BLTSIZH (value); break;
1.1.1.4   root     4328:      case 0x1E4: DIWHIGH (hpos, value); break;
                   4329:      case 0x10C: BPLCON4 (hpos, value); break;
1.1.1.7   root     4330:      case 0x1FC: FMODE (value); break;
1.1       root     4331:     }
                   4332: }
                   4333: 
1.1.1.4   root     4334: void REGPARAM2 custom_wput (uaecptr addr, uae_u32 value)
                   4335: {
                   4336:     int hpos = current_hpos ();
1.1.1.13  root     4337:     special_mem |= S_WRITE;
                   4338: 
1.1.1.15! root     4339:     sync_copper_with_cpu (hpos, 1, addr);
1.1.1.4   root     4340:     custom_wput_1 (hpos, addr, value);
                   4341: }
                   4342: 
                   4343: void REGPARAM2 custom_bput (uaecptr addr, uae_u32 value)
1.1       root     4344: {
1.1.1.2   root     4345:     static int warned = 0;
                   4346:     /* Is this correct now? (There are people who bput things to the upper byte of AUDxVOL). */
1.1.1.3   root     4347:     uae_u16 rval = (value << 8) | (value & 0xFF);
1.1.1.13  root     4348:     special_mem |= S_WRITE;
1.1.1.9   root     4349:     custom_wput (addr, rval);
1.1.1.2   root     4350:     if (!warned)
1.1.1.3   root     4351:        write_log ("Byte put to custom register.\n"), warned++;
1.1       root     4352: }
                   4353: 
1.1.1.3   root     4354: void REGPARAM2 custom_lput(uaecptr addr, uae_u32 value)
1.1       root     4355: {
1.1.1.13  root     4356:     special_mem |= S_WRITE;
1.1.1.9   root     4357:     custom_wput (addr & 0xfffe, value >> 16);
                   4358:     custom_wput ((addr + 2) & 0xfffe, (uae_u16)value);
1.1       root     4359: }
1.1.1.15! root     4360: 
        !          4361: void custom_prepare_savestate (void)
        !          4362: {
        !          4363:     /* force blitter to finish, no support for saving full blitter state yet */
        !          4364:     if (eventtab[ev_blitter].active) {
        !          4365:        unsigned int olddmacon = dmacon;
        !          4366:        dmacon |= DMA_BLITTER; /* ugh.. */
        !          4367:        blitter_handler ();
        !          4368:        dmacon = olddmacon;
        !          4369:     }
        !          4370: }
        !          4371: 
        !          4372: #define RB restore_u8 ()
        !          4373: #define RW restore_u16 ()
        !          4374: #define RL restore_u32 ()
        !          4375: 
        !          4376: uae_u8 *restore_custom (uae_u8 *src)
        !          4377: {
        !          4378:     uae_u16 dsklen, dskbytr, dskdatr;
        !          4379:     int dskpt;
        !          4380:     int i;
        !          4381: 
        !          4382:     audio_reset ();
        !          4383: 
        !          4384:     currprefs.chipset_mask = RL;
        !          4385:     RW;                                /* 000 ? */
        !          4386:     RW;                                /* 002 DMACONR */
        !          4387:     RW;                                /* 004 VPOSR */
        !          4388:     RW;                                /* 006 VHPOSR */
        !          4389:     dskdatr = RW;              /* 008 DSKDATR */
        !          4390:     RW;                                /* 00A JOY0DAT */
        !          4391:     RW;                                /* 00C JOY1DAT */
        !          4392:     clxdat = RW;               /* 00E CLXDAT */
        !          4393:     RW;                                /* 010 ADKCONR */
        !          4394:     RW;                                /* 012 POT0DAT* */
        !          4395:     RW;                                /* 014 POT1DAT* */
        !          4396:     RW;                                /* 016 POTINP* */
        !          4397:     RW;                                /* 018 SERDATR* */
        !          4398:     dskbytr = RW;              /* 01A DSKBYTR */
        !          4399:     RW;                                /* 01C INTENAR */
        !          4400:     RW;                                /* 01E INTREQR */
        !          4401:     dskpt = RL;                        /* 020-022 DSKPT */
        !          4402:     dsklen = RW;               /* 024 DSKLEN */
        !          4403:     RW;                                /* 026 DSKDAT */
        !          4404:     RW;                                /* 028 REFPTR */
        !          4405:     lof = RW;                  /* 02A VPOSW */
        !          4406:     RW;                                /* 02C VHPOSW */
        !          4407:     COPCON(RW);                        /* 02E COPCON */
        !          4408:     RW;                                /* 030 SERDAT* */
        !          4409:     RW;                                /* 032 SERPER* */
        !          4410:     POTGO(RW);                 /* 034 POTGO */
        !          4411:     RW;                                /* 036 JOYTEST* */
        !          4412:     RW;                                /* 038 STREQU */
        !          4413:     RW;                                /* 03A STRVHBL */
        !          4414:     RW;                                /* 03C STRHOR */
        !          4415:     RW;                                /* 03E STRLONG */
        !          4416:     BLTCON0(RW);               /* 040 BLTCON0 */
        !          4417:     BLTCON1(RW);               /* 042 BLTCON1 */
        !          4418:     BLTAFWM(RW);               /* 044 BLTAFWM */
        !          4419:     BLTALWM(RW);               /* 046 BLTALWM */
        !          4420:     BLTCPTH(RL);               /* 048-04B BLTCPT */
        !          4421:     BLTBPTH(RL);               /* 04C-04F BLTBPT */
        !          4422:     BLTAPTH(RL);               /* 050-053 BLTAPT */
        !          4423:     BLTDPTH(RL);               /* 054-057 BLTDPT */
        !          4424:     RW;                                /* 058 BLTSIZE */
        !          4425:     RW;                                /* 05A BLTCON0L */
        !          4426:     oldvblts = RW;             /* 05C BLTSIZV */
        !          4427:     RW;                                /* 05E BLTSIZH */
        !          4428:     BLTCMOD(RW);               /* 060 BLTCMOD */
        !          4429:     BLTBMOD(RW);               /* 062 BLTBMOD */
        !          4430:     BLTAMOD(RW);               /* 064 BLTAMOD */
        !          4431:     BLTDMOD(RW);               /* 066 BLTDMOD */
        !          4432:     RW;                                /* 068 ? */
        !          4433:     RW;                                /* 06A ? */
        !          4434:     RW;                                /* 06C ? */
        !          4435:     RW;                                /* 06E ? */
        !          4436:     BLTCDAT(RW);               /* 070 BLTCDAT */
        !          4437:     BLTBDAT(RW);               /* 072 BLTBDAT */
        !          4438:     BLTADAT(RW);               /* 074 BLTADAT */
        !          4439:     RW;                                /* 076 ? */
        !          4440:     RW;                                /* 078 ? */
        !          4441:     RW;                                /* 07A ? */
        !          4442:     RW;                                /* 07C LISAID */
        !          4443:     DSKSYNC(RW);               /* 07E DSKSYNC */
        !          4444:     cop1lc = RL;               /* 080/082 COP1LC */
        !          4445:     cop2lc = RL;               /* 084/086 COP2LC */
        !          4446:     RW;                                /* 088 ? */
        !          4447:     RW;                                /* 08A ? */
        !          4448:     RW;                                /* 08C ? */
        !          4449:     diwstrt = RW;              /* 08E DIWSTRT */
        !          4450:     diwstop = RW;              /* 090 DIWSTOP */
        !          4451:     ddfstrt = RW;              /* 092 DDFSTRT */
        !          4452:     ddfstop = RW;              /* 094 DDFSTOP */
        !          4453:     dmacon = RW & ~(0x2000|0x4000); /* 096 DMACON */
        !          4454:     CLXCON(RW);                        /* 098 CLXCON */
        !          4455:     intena = RW;               /* 09A INTENA */
        !          4456:     intreq = RW;               /* 09C INTREQ */
        !          4457:     adkcon = RW;               /* 09E ADKCON */
        !          4458:     for (i = 0; i < 8; i++)
        !          4459:        bplpt[i] = RL;
        !          4460:     bplcon0 = RW;              /* 100 BPLCON0 */
        !          4461:     bplcon1 = RW;              /* 102 BPLCON1 */
        !          4462:     bplcon2 = RW;              /* 104 BPLCON2 */
        !          4463:     bplcon3 = RW;              /* 106 BPLCON3 */
        !          4464:     bpl1mod = RW;              /* 108 BPL1MOD */
        !          4465:     bpl2mod = RW;              /* 10A BPL2MOD */
        !          4466:     bplcon4 = RW;              /* 10C BPLCON4 */
        !          4467:     RW;                                /* 10E CLXCON2* */
        !          4468:     for(i = 0; i < 8; i++)
        !          4469:        RW;                     /*     BPLXDAT */
        !          4470:     for(i = 0; i < 32; i++)
        !          4471:        current_colors.color_regs_ecs[i] = RW; /* 180 COLORxx */
        !          4472:     RW;                                /* 1C0 ? */
        !          4473:     RW;                                /* 1C2 ? */
        !          4474:     RW;                                /* 1C4 ? */
        !          4475:     RW;                                /* 1C6 ? */
        !          4476:     RW;                                /* 1C8 ? */
        !          4477:     RW;                                /* 1CA ? */
        !          4478:     RW;                                /* 1CC ? */
        !          4479:     RW;                                /* 1CE ? */
        !          4480:     RW;                                /* 1D0 ? */
        !          4481:     RW;                                /* 1D2 ? */
        !          4482:     RW;                                /* 1D4 ? */
        !          4483:     RW;                                /* 1D6 ? */
        !          4484:     RW;                                /* 1D8 ? */
        !          4485:     RW;                                /* 1DA ? */
        !          4486:     new_beamcon0 = RW;         /* 1DC BEAMCON0 */
        !          4487:     RW;                                /* 1DE ? */
        !          4488:     RW;                                /* 1E0 ? */
        !          4489:     RW;                                /* 1E2 ? */
        !          4490:     RW;                                /* 1E4 ? */
        !          4491:     RW;                                /* 1E6 ? */
        !          4492:     RW;                                /* 1E8 ? */
        !          4493:     RW;                                /* 1EA ? */
        !          4494:     RW;                                /* 1EC ? */
        !          4495:     RW;                                /* 1EE ? */
        !          4496:     RW;                                /* 1F0 ? */
        !          4497:     RW;                                /* 1F2 ? */
        !          4498:     RW;                                /* 1F4 ? */
        !          4499:     RW;                                /* 1F6 ? */
        !          4500:     RW;                                /* 1F8 ? */
        !          4501:     RW;                                /* 1FA ? */
        !          4502:     fmode = RW;                        /* 1FC FMODE */
        !          4503:     RW;                                /* 1FE ? */
        !          4504: 
        !          4505:     DISK_restore_custom (dskpt, dsklen, dskdatr, dskbytr);
        !          4506: 
        !          4507:     return src;
        !          4508: }
        !          4509: 
        !          4510: 
        !          4511: #define SB save_u8
        !          4512: #define SW save_u16
        !          4513: #define SL save_u32
        !          4514: 
        !          4515: extern uae_u16 serper;
        !          4516: 
        !          4517: uae_u8 *save_custom (int *len)
        !          4518: {
        !          4519:     uae_u8 *dstbak, *dst;
        !          4520:     int i;
        !          4521:     uae_u32 dskpt;
        !          4522:     uae_u16 dsklen, dsksync, dskdatr, dskbytr;
        !          4523: 
        !          4524:     DISK_save_custom (&dskpt, &dsklen, &dsksync, &dskdatr, &dskbytr);
        !          4525:     dstbak = dst = malloc (8+256*2);
        !          4526:     SL (currprefs.chipset_mask);
        !          4527:     SW (0);                    /* 000 ? */
        !          4528:     SW (dmacon);               /* 002 DMACONR */
        !          4529:     SW (VPOSR());              /* 004 VPOSR */
        !          4530:     SW (VHPOSR());             /* 006 VHPOSR */
        !          4531:     SW (dskdatr);              /* 008 DSKDATR */
        !          4532:     SW (JOY0DAT());            /* 00A JOY0DAT */
        !          4533:     SW (JOY1DAT());            /* 00C JOY1DAT */
        !          4534:     SW (clxdat);               /* 00E CLXDAT */
        !          4535:     SW (ADKCONR());            /* 010 ADKCONR */
        !          4536:     SW (POT0DAT());            /* 012 POT0DAT */
        !          4537:     SW (POT0DAT());            /* 014 POT1DAT */
        !          4538:     SW (0)     ;               /* 016 POTINP * */
        !          4539:     SW (0);                    /* 018 SERDATR * */
        !          4540:     SW (dskbytr);              /* 01A DSKBYTR */
        !          4541:     SW (INTENAR());            /* 01C INTENAR */
        !          4542:     SW (INTREQR());            /* 01E INTREQR */
        !          4543:     SL (dskpt);                        /* 020-023 DSKPT */
        !          4544:     SW (dsklen);               /* 024 DSKLEN */
        !          4545:     SW (0);                    /* 026 DSKDAT */
        !          4546:     SW (0);                    /* 028 REFPTR */
        !          4547:     SW (lof);                  /* 02A VPOSW */
        !          4548:     SW (0);                    /* 02C VHPOSW */
        !          4549:     SW (copcon);               /* 02E COPCON */
        !          4550:     SW (serper);               /* 030 SERDAT * */
        !          4551:     SW (serdat);               /* 032 SERPER * */
        !          4552:     SW (potgo_value);          /* 034 POTGO */
        !          4553:     SW (0);                    /* 036 JOYTEST * */
        !          4554:     SW (0);                    /* 038 STREQU */
        !          4555:     SW (0);                    /* 03A STRVBL */
        !          4556:     SW (0);                    /* 03C STRHOR */
        !          4557:     SW (0);                    /* 03E STRLONG */
        !          4558:     SW (bltcon0);              /* 040 BLTCON0 */
        !          4559:     SW (bltcon1);              /* 042 BLTCON1 */
        !          4560:     SW (blt_info.bltafwm);     /* 044 BLTAFWM */
        !          4561:     SW (blt_info.bltalwm);     /* 046 BLTALWM */
        !          4562:     SL (bltcpt);               /* 048-04B BLTCPT */
        !          4563:     SL (bltbpt);               /* 04C-04F BLTCPT */
        !          4564:     SL (bltapt);               /* 050-043 BLTCPT */
        !          4565:     SL (bltdpt);               /* 054-057 BLTCPT */
        !          4566:     SW (0);                    /* 058 BLTSIZE */
        !          4567:     SW (0);                    /* 05A BLTCON0L (use BLTCON0 instead) */
        !          4568:     SW (oldvblts);             /* 05C BLTSIZV */
        !          4569:     SW (blt_info.hblitsize);   /* 05E BLTSIZH */
        !          4570:     SW (blt_info.bltcmod);     /* 060 BLTCMOD */
        !          4571:     SW (blt_info.bltbmod);     /* 062 BLTBMOD */
        !          4572:     SW (blt_info.bltamod);     /* 064 BLTAMOD */
        !          4573:     SW (blt_info.bltdmod);     /* 066 BLTDMOD */
        !          4574:     SW (0);                    /* 068 ? */
        !          4575:     SW (0);                    /* 06A ? */
        !          4576:     SW (0);                    /* 06C ? */
        !          4577:     SW (0);                    /* 06E ? */
        !          4578:     SW (blt_info.bltcdat);     /* 070 BLTCDAT */
        !          4579:     SW (blt_info.bltbdat);     /* 072 BLTBDAT */
        !          4580:     SW (blt_info.bltadat);     /* 074 BLTADAT */
        !          4581:     SW (0);                    /* 076 ? */
        !          4582:     SW (0);                    /* 078 ? */
        !          4583:     SW (0);                    /* 07A ? */
        !          4584:     SW (DENISEID());           /* 07C DENISEID/LISAID */
        !          4585:     SW (dsksync);              /* 07E DSKSYNC */
        !          4586:     SL (cop1lc);               /* 080-083 COP1LC */
        !          4587:     SL (cop2lc);               /* 084-087 COP2LC */
        !          4588:     SW (0);                    /* 088 ? */
        !          4589:     SW (0);                    /* 08A ? */
        !          4590:     SW (0);                    /* 08C ? */
        !          4591:     SW (diwstrt);              /* 08E DIWSTRT */
        !          4592:     SW (diwstop);              /* 090 DIWSTOP */
        !          4593:     SW (ddfstrt);              /* 092 DDFSTRT */
        !          4594:     SW (ddfstop);              /* 094 DDFSTOP */
        !          4595:     SW (dmacon);               /* 096 DMACON */
        !          4596:     SW (clxcon);               /* 098 CLXCON */
        !          4597:     SW (intena);               /* 09A INTENA */
        !          4598:     SW (intreq);               /* 09C INTREQ */
        !          4599:     SW (adkcon);               /* 09E ADKCON */
        !          4600:     for (i = 0; i < 8; i++)
        !          4601:        SL (bplpt[i]);          /* 0E0-0FE BPLxPT */
        !          4602:     SW (bplcon0);              /* 100 BPLCON0 */
        !          4603:     SW (bplcon1);              /* 102 BPLCON1 */
        !          4604:     SW (bplcon2);              /* 104 BPLCON2 */
        !          4605:     SW (bplcon3);              /* 106 BPLCON3 */
        !          4606:     SW (bpl1mod);              /* 108 BPL1MOD */
        !          4607:     SW (bpl2mod);              /* 10A BPL2MOD */
        !          4608:     SW (bplcon4);              /* 10C BPLCON4 */
        !          4609:     SW (0);                    /* 10E CLXCON2 */
        !          4610:     for (i = 0;i < 8; i++)
        !          4611:        SW (0);                 /* 110 BPLxDAT */
        !          4612:     for ( i = 0; i < 32; i++)
        !          4613:        SW (current_colors.color_regs_ecs[i]); /* 180-1BE COLORxx */
        !          4614:     SW (0);                    /* 1C0 */
        !          4615:     SW (0);                    /* 1C2 */
        !          4616:     SW (0);                    /* 1C4 */
        !          4617:     SW (0);                    /* 1C6 */
        !          4618:     SW (0);                    /* 1C8 */
        !          4619:     SW (0);                    /* 1CA */
        !          4620:     SW (0);                    /* 1CC */
        !          4621:     SW (0);                    /* 1CE */
        !          4622:     SW (0);                    /* 1D0 */
        !          4623:     SW (0);                    /* 1D2 */
        !          4624:     SW (0);                    /* 1D4 */
        !          4625:     SW (0);                    /* 1D6 */
        !          4626:     SW (0);                    /* 1D8 */
        !          4627:     SW (0);                    /* 1DA */
        !          4628:     SW (beamcon0);             /* 1DC BEAMCON0 */
        !          4629:     SW (0);                    /* 1DE */
        !          4630:     SW (0);                    /* 1E0 */
        !          4631:     SW (0);                    /* 1E2 */
        !          4632:     SW (0);                    /* 1E4 */
        !          4633:     SW (0);                    /* 1E6 */
        !          4634:     SW (0);                    /* 1E8 */
        !          4635:     SW (0);                    /* 1EA */
        !          4636:     SW (0);                    /* 1EC */
        !          4637:     SW (0);                    /* 1EE */
        !          4638:     SW (0);                    /* 1F0 */
        !          4639:     SW (0);                    /* 1F2 */
        !          4640:     SW (0);                    /* 1F4 */
        !          4641:     SW (0);                    /* 1F6 */
        !          4642:     SW (0);                    /* 1F8 */
        !          4643:     SW (0);                    /* 1FA */
        !          4644:     SW (fmode);                        /* 1FC FMODE */
        !          4645:     SW (0xffff);               /* 1FE */
        !          4646: 
        !          4647:     *len = dst - dstbak;
        !          4648:     return dstbak;
        !          4649: }
        !          4650: 
        !          4651: uae_u8 *restore_custom_agacolors (uae_u8 *src)
        !          4652: {
        !          4653:     int i;
        !          4654: 
        !          4655:     for (i = 0; i < 256; i++)
        !          4656:        current_colors.color_regs_aga[i] = RL;
        !          4657:     return src;
        !          4658: }
        !          4659: 
        !          4660: uae_u8 *save_custom_agacolors (int *len)
        !          4661: {
        !          4662:     uae_u8 *dstbak, *dst;
        !          4663:     int i;
        !          4664: 
        !          4665:     dstbak = dst = malloc (256*4);
        !          4666:     for (i = 0; i < 256; i++)
        !          4667:        SL (current_colors.color_regs_aga[i]);
        !          4668:     *len = dst - dstbak;
        !          4669:     return dstbak;
        !          4670: }
        !          4671: 
        !          4672: uae_u8 *restore_custom_sprite (uae_u8 *src, int num)
        !          4673: {
        !          4674:     spr[num].pt = RL;          /* 120-13E SPRxPT */
        !          4675:     sprpos[num] = RW;          /* 1x0 SPRxPOS */
        !          4676:     sprctl[num] = RW;          /* 1x2 SPRxPOS */
        !          4677:     sprdata[num][0] = RW;      /* 1x4 SPRxDATA */
        !          4678:     sprdatb[num][0] = RW;      /* 1x6 SPRxDATB */
        !          4679:     sprdata[num][1] = RW;
        !          4680:     sprdatb[num][1] = RW;
        !          4681:     sprdata[num][2] = RW;
        !          4682:     sprdatb[num][2] = RW;
        !          4683:     sprdata[num][3] = RW;
        !          4684:     sprdatb[num][3] = RW;
        !          4685:     spr[num].armed = RB;
        !          4686:     return src;
        !          4687: }
        !          4688: 
        !          4689: uae_u8 *save_custom_sprite(int *len, int num)
        !          4690: {
        !          4691:     uae_u8 *dstbak, *dst;
        !          4692: 
        !          4693:     dstbak = dst = malloc (1 + 4 + 2 + 2 + 2 +2 + 3*2);
        !          4694:     SL (spr[num].pt);          /* 120-13E SPRxPT */
        !          4695:     SW (sprpos[num]);          /* 1x0 SPRxPOS */
        !          4696:     SW (sprctl[num]);          /* 1x2 SPRxPOS */
        !          4697:     SW (sprdata[num][0]);      /* 1x4 SPRxDATA */
        !          4698:     SW (sprdatb[num][0]);      /* 1x6 SPRxDATB */
        !          4699:     SW (sprdata[num][1]);
        !          4700:     SW (sprdatb[num][1]);
        !          4701:     SW (sprdata[num][2]);
        !          4702:     SW (sprdatb[num][2]);
        !          4703:     SW (sprdata[num][3]);
        !          4704:     SW (sprdatb[num][3]);
        !          4705:     SB (spr[num].armed ? 1 : 0);
        !          4706:     *len = dst - dstbak;
        !          4707:     return dstbak;
        !          4708: }

unix.superglobalmegacorp.com

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