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

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

unix.superglobalmegacorp.com

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