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

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

unix.superglobalmegacorp.com

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