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

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

unix.superglobalmegacorp.com

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