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

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"
1.1.1.2   root       25: #include "readcpu.h"
1.1       root       26: #include "newcpu.h"
                     27: #include "cia.h"
                     28: #include "disk.h"
                     29: #include "blitter.h"
                     30: #include "xwin.h"
1.1.1.3   root       31: #include "joystick.h"
                     32: #include "audio.h"
1.1       root       33: #include "keybuf.h"
                     34: #include "serial.h"
1.1.1.2   root       35: #include "osemu.h"
1.1.1.3   root       36: #include "autoconf.h"
                     37: #include "gui.h"
                     38: #include "picasso96.h"
1.1.1.4   root       39: #include "drawing.h"
1.1.1.2   root       40: 
1.1.1.6   root       41: static unsigned int n_consecutive_skipped = 0;
                     42: static unsigned int total_skipped = 0;
                     43: 
1.1.1.3   root       44: #define SPRITE_COLLISIONS
1.1.1.2   root       45: 
1.1.1.3   root       46: /* Mouse and joystick emulation */
1.1.1.2   root       47: 
1.1.1.3   root       48: int buttonstate[3];
                     49: static int mouse_x, mouse_y;
                     50: int joy0button, joy1button;
                     51: unsigned int joy0dir, joy1dir;
                     52: 
                     53: /* Events */
1.1       root       54: 
1.1.1.4   root       55: unsigned long int cycles, nextevent, is_lastline;
                     56: static int rpt_did_reset;
1.1.1.2   root       57: struct ev eventtab[ev_max];
                     58: 
1.1.1.3   root       59: frame_time_t vsynctime, vsyncmintime;
                     60: 
1.1.1.4   root       61: static int vpos;
                     62: static uae_u16 lof;
                     63: static int next_lineno;
                     64: static enum nln_how nextline_how;
                     65: static int lof_changed = 0;
1.1       root       66: 
1.1.1.3   root       67: static uae_u32 sprtaba[256],sprtabb[256];
                     68: 
1.1.1.2   root       69: /*
                     70:  * Hardware registers of all sorts.
                     71:  */
1.1       root       72: 
1.1.1.4   root       73: static void custom_wput_1 (int, uaecptr, uae_u32) REGPARAM;
                     74: 
1.1.1.3   root       75: static uae_u16 cregs[256];
1.1       root       76: 
1.1.1.3   root       77: uae_u16 intena,intreq;
                     78: uae_u16 dmacon;
                     79: uae_u16 adkcon; /* used by audio code */
1.1       root       80: 
1.1.1.3   root       81: static uae_u32 cop1lc,cop2lc,copcon;
1.1.1.7   root       82:  
                     83: int maxhpos = MAXHPOS_PAL;
                     84: int maxvpos = MAXVPOS_PAL;
                     85: int minfirstline = MINFIRSTLINE_PAL;
                     86: int vblank_endline = VBLANK_ENDLINE_PAL;
                     87: int vblank_hz = VBLANK_HZ_PAL;
                     88: unsigned long syncbase;
                     89: static int fmode;
                     90: static unsigned int beamcon0, new_beamcon0;
                     91: static int ntscmode = 0;
                     92: 
                     93: #define MAX_SPRITES 32
1.1       root       94: 
1.1.1.2   root       95: /* This is but an educated guess. It seems to be correct, but this stuff
                     96:  * isn't documented well. */
1.1.1.3   root       97: enum sprstate { SPR_stop, SPR_restart, SPR_waiting_start, SPR_waiting_stop };
1.1.1.10  root       98: 
                     99: struct sprite {
                    100:     uaecptr pt;
                    101:     int on;
                    102:     int xpos;
                    103:     int vstart;
                    104:     int vstop;
                    105:     int armed;
                    106:     enum sprstate state;
                    107: };
                    108: 
                    109: static struct sprite spr[8];
                    110: 
                    111: static int sprite_vblank_endline = VBLANK_ENDLINE_NTSC + 2;
1.1       root      112: 
1.1.1.7   root      113: static unsigned int sprdata[MAX_SPRITES], sprdatb[MAX_SPRITES], sprctl[MAX_SPRITES], sprpos[MAX_SPRITES];
1.1.1.10  root      114: static int sprite_last_drawn_at[MAX_SPRITES];
1.1.1.7   root      115: static int last_sprite_point, nr_armed;
                    116: 
1.1.1.6   root      117: static uae_u32 bpl1dat, bpl2dat, bpl3dat, bpl4dat, bpl5dat, bpl6dat, bpl7dat, bpl8dat;
                    118: static uae_s16 bpl1mod, bpl2mod;
1.1       root      119: 
1.1.1.3   root      120: static uaecptr bplpt[8];
1.1.1.10  root      121: uae_u8 *real_bplpt[8];
1.1       root      122: 
                    123: /*static int blitcount[256];  blitter debug */
                    124: 
1.1.1.2   root      125: static struct color_entry current_colors;
1.1.1.6   root      126: static unsigned int bplcon0, bplcon1, bplcon2, bplcon3, bplcon4;
1.1.1.3   root      127: static int nr_planes_from_bplcon0, corrected_nr_planes_from_bplcon0;
1.1.1.4   root      128: static unsigned int diwstrt, diwstop, diwhigh;
                    129: static int diwhigh_written;
                    130: static unsigned int ddfstrt, ddfstop;
1.1.1.7   root      131: 
1.1.1.4   root      132: /* The display and data fetch windows */
1.1       root      133: 
1.1.1.4   root      134: enum diw_states
                    135: {
                    136:     DIW_waiting_start, DIW_waiting_stop
                    137: };
1.1       root      138: 
1.1.1.6   root      139: static int plffirstline, plflastline, plfstrt, plfstop, plflinelen;
1.1.1.9   root      140: static int last_diw_pix_hpos, last_ddf_pix_hpos;
1.1.1.6   root      141: int diwfirstword, diwlastword;
1.1.1.4   root      142: static enum diw_states diwstate, hdiwstate;
1.1       root      143: 
1.1.1.4   root      144: /* Sprite collisions */
                    145: uae_u16 clxdat, clxcon;
                    146: int clx_sprmask;
                    147: 
                    148: enum copper_states {
                    149:     COP_stop,
1.1.1.10  root      150:     COP_read1, COP_read2,
1.1.1.4   root      151:     COP_bltwait,
1.1.1.9   root      152:     COP_wait
1.1.1.4   root      153: };
                    154: 
                    155: struct copper {
                    156:     /* The current instruction words.  */
                    157:     unsigned int i1, i2;
                    158:     enum copper_states state;
                    159:     /* Instruction pointer.  */
                    160:     uaecptr ip;
1.1.1.10  root      161:     int hpos, vpos;
1.1.1.4   root      162:     unsigned int ignore_next;
1.1.1.10  root      163:     int vcmp, hcmp;
1.1.1.4   root      164: };
                    165: 
                    166: static struct copper cop_state;
1.1.1.10  root      167: static int copper_enabled_thisline;
                    168: static int cop_min_waittime;
1.1       root      169: 
                    170: /*
                    171:  * Statistics
                    172:  */
                    173: 
1.1.1.2   root      174: /* Used also by bebox.cpp */
1.1.1.6   root      175: unsigned long int msecs = 0, frametime = 0, lastframetime = 0, timeframes = 0;
1.1       root      176: static unsigned long int seconds_base;
                    177: int bogusframe;
                    178: 
1.1.1.4   root      179: 
                    180: static int current_change_set;
                    181: 
                    182: #ifdef OS_WITHOUT_MEMORY_MANAGEMENT
                    183: /* sam: Those arrays uses around 7Mb of BSS... That seems  */
                    184: /* too much for AmigaDOS (uae crashes as soon as one loads */
                    185: /* it. So I use a different strategy here (realloc the     */
                    186: /* arrays when needed. That strategy might be usefull for  */
                    187: /* computer with low memory.                               */
                    188: struct sprite_draw  *sprite_positions[2];
                    189: struct color_change *color_changes[2];
                    190: struct delay_change *delay_changes;
                    191: static int max_sprite_draw = 400;
                    192: static int delta_sprite_draw = 0;
                    193: static int max_color_change = 400;
                    194: static int delta_color_change = 0;
                    195: static int max_delay_change = 100;
                    196: static int delta_delay_change = 0;
                    197: #else
                    198: struct sprite_draw sprite_positions[2][MAX_REG_CHANGE];
                    199: struct color_change color_changes[2][MAX_REG_CHANGE];
                    200: /* We don't remember those across frames, that would be too much effort.
                    201:  * We simply redraw the line whenever we see one of these. */
                    202: struct delay_change delay_changes[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: 
                    209: struct sprite_draw *curr_sprite_positions, *prev_sprite_positions;
                    210: struct color_change *curr_color_changes, *prev_color_changes;
                    211: struct draw_info *curr_drawinfo, *prev_drawinfo;
                    212: struct color_entry *curr_color_tables, *prev_color_tables;
                    213: 
                    214: static int next_color_change, next_sprite_draw, next_delay_change;
                    215: static int next_color_entry, remembered_color_entry;
                    216: static int color_src_match, color_dest_match, color_compare_result;
                    217: 
                    218: /* These few are only needed during/at the end of the scanline, and don't
                    219:  * have to be remembered. */
1.1.1.7   root      220: static int decided_bpl1mod, decided_bpl2mod, decided_nr_planes, decided_res;
1.1.1.4   root      221: 
1.1.1.5   root      222: static char thisline_changed;
                    223: 
1.1.1.4   root      224: 
                    225: #ifdef SMART_UPDATE
1.1.1.5   root      226: #define MARK_LINE_CHANGED do { thisline_changed = 1; } while (0)
1.1.1.4   root      227: #else
1.1.1.5   root      228: #define MARK_LINE_CHANGED do { ; } while (0)
1.1.1.4   root      229: #endif
                    230: 
                    231: static struct decision thisline_decision;
                    232: static int modulos_added, plane_decided, color_decided, very_broken_program;
                    233: 
1.1       root      234: /*
                    235:  * helper functions
                    236:  */
                    237: 
1.1.1.4   root      238: int rpt_available = 0;
1.1.1.3   root      239: 
1.1.1.4   root      240: void reset_frame_rate_hack (void)
                    241: {
                    242:     if (currprefs.m68k_speed != -1)
                    243:        return;
                    244: 
                    245:     if (! rpt_available) {
                    246:        currprefs.m68k_speed = 0;
                    247:        return;
                    248:     }
1.1.1.3   root      249: 
1.1.1.4   root      250:     rpt_did_reset = 1;
                    251:     is_lastline = 0;
                    252:     vsyncmintime = read_processor_time() + vsynctime;
                    253:     write_log ("Resetting frame rate hack\n");
                    254: }
1.1       root      255: 
1.1.1.3   root      256: void check_prefs_changed_custom (void)
                    257: {
1.1.1.7   root      258:     currprefs.gfx_framerate = changed_prefs.gfx_framerate;
1.1.1.3   root      259:     /* Not really the right place... */
1.1.1.6   root      260:     if (currprefs.jport0 != changed_prefs.jport0
                    261:        || currprefs.jport1 != changed_prefs.jport1) {
                    262:        currprefs.jport0 = changed_prefs.jport0;
                    263:        currprefs.jport1 = changed_prefs.jport1;
1.1.1.3   root      264:        joystick_setting_changed ();
1.1       root      265:     }
1.1.1.3   root      266:     currprefs.immediate_blits = changed_prefs.immediate_blits;
                    267:     currprefs.blits_32bit_enabled = changed_prefs.blits_32bit_enabled;
                    268:        
1.1       root      269: }
                    270: 
1.1.1.8   root      271: STATIC_INLINE void setclr (uae_u16 *p, uae_u16 val)
1.1       root      272: {
1.1.1.6   root      273:     if (val & 0x8000)
1.1       root      274:        *p |= val & 0x7FFF;
1.1.1.6   root      275:     else
1.1       root      276:        *p &= ~val;
                    277: }
                    278: 
1.1.1.3   root      279: __inline__ int current_hpos (void)
1.1       root      280: {
                    281:     return cycles - eventtab[ev_hsync].oldcycles;
                    282: }
                    283: 
1.1.1.8   root      284: STATIC_INLINE uae_u8 *pfield_xlateptr (uaecptr plpt, int bytecount)
1.1.1.2   root      285: {
1.1.1.4   root      286:     if (!chipmem_bank.check (plpt, bytecount)) {
1.1.1.2   root      287:        static int count = 0;
1.1.1.3   root      288:        if (!count)
                    289:            count++, write_log ("Warning: Bad playfield pointer\n");
1.1.1.2   root      290:        return NULL;
                    291:     }
1.1.1.4   root      292:     return chipmem_bank.xlateaddr (plpt);
1.1.1.2   root      293: }
                    294: 
1.1.1.8   root      295: STATIC_INLINE void docols (struct color_entry *colentry)
1.1.1.3   root      296: {
                    297:     int i;
1.1.1.11! root      298: 
        !           299:     if (currprefs.chipset_mask & CSMASK_AGA) {
        !           300:         for (i = 0; i < 256; i++) {
        !           301:            int v = color_reg_get (colentry, i);
        !           302:            if(v < 0 || v > 16777215)
        !           303:                continue;
        !           304:            colentry->acolors[i] = CONVERT_RGB (v);
        !           305:        }
        !           306:     } else {
        !           307:         for (i = 0; i < 32; i++) {
        !           308:            int v = color_reg_get (colentry, i);
        !           309:            if (v < 0 || v > 4095)
        !           310:                continue;
        !           311:            colentry->acolors[i] = xcolors[v];
        !           312:        }
1.1.1.3   root      313:     }
                    314: }
                    315: 
                    316: void notice_new_xcolors (void)
                    317: {
                    318:     int i;
                    319: 
                    320:     docols(&current_colors);
1.1.1.4   root      321: /*    docols(&colors_for_drawing);*/
1.1.1.7   root      322:     for (i = 0; i < (MAXVPOS + 1)*2; i++) {
1.1.1.3   root      323:        docols(color_tables[0]+i);
                    324:        docols(color_tables[1]+i);
                    325:     }
                    326: }
                    327: 
1.1.1.4   root      328: static void do_sprites (int currvp, int currhp);
1.1.1.2   root      329: 
                    330: static void remember_ctable (void)
                    331: {
                    332:     if (remembered_color_entry == -1) {
                    333:        /* The colors changed since we last recorded a color map. Record a
                    334:         * new one. */
1.1.1.11! root      335:        color_reg_cpy (curr_color_tables + next_color_entry, &current_colors);
1.1.1.2   root      336:        remembered_color_entry = next_color_entry++;
                    337:     }
                    338:     thisline_decision.ctable = remembered_color_entry;
                    339:     if (color_src_match == -1 || color_dest_match != remembered_color_entry
                    340:        || line_decisions[next_lineno].ctable != color_src_match)
                    341:     {
                    342:        /* The remembered comparison didn't help us - need to compare again. */
                    343:        int oldctable = line_decisions[next_lineno].ctable;
                    344:        int changed = 0;
                    345: 
1.1.1.3   root      346:        if (oldctable == -1) {
1.1.1.2   root      347:            changed = 1;
                    348:            color_src_match = color_dest_match = -1;
                    349:        } else {
1.1.1.11! root      350:            color_compare_result = color_reg_cmp (&prev_color_tables[oldctable], &current_colors) != 0;
1.1.1.3   root      351:            if (color_compare_result)
                    352:                changed = 1;
                    353:            color_src_match = oldctable;
1.1.1.2   root      354:            color_dest_match = remembered_color_entry;
1.1.1.3   root      355:        }
1.1.1.5   root      356:        thisline_changed |= changed;
1.1.1.3   root      357:     } else {
                    358:        /* We know the result of the comparison */
                    359:        if (color_compare_result)
1.1.1.5   root      360:            thisline_changed = 1;
1.1.1.3   root      361:     }
                    362: }
                    363: 
                    364: static void remember_ctable_for_border (void)
                    365: {
                    366:     remember_ctable ();
1.1.1.2   root      367: }
                    368: 
1.1.1.3   root      369: /* Called to determine the state of the horizontal display window state
                    370:  * machine at the current position. It might have changed since we last
                    371:  * checked.  */
1.1.1.4   root      372: static void decide_diw (int hpos)
1.1.1.2   root      373: {
1.1.1.9   root      374:     int pix_hpos = PIXEL_XPOS (hpos);
1.1.1.3   root      375:     if (hdiwstate == DIW_waiting_start && thisline_decision.diwfirstword == -1
1.1.1.9   root      376:        && pix_hpos >= diwfirstword && last_diw_pix_hpos < diwfirstword)
1.1.1.3   root      377:     {
1.1.1.2   root      378:        thisline_decision.diwfirstword = diwfirstword;
1.1.1.3   root      379:        hdiwstate = DIW_waiting_stop;
1.1.1.2   root      380:        /* Decide playfield delays only at DIW start, because they don't matter before and
                    381:         * some programs change them after DDF start but before DIW start. */
                    382:        thisline_decision.bplcon1 = bplcon1;
                    383:        if (thisline_decision.diwfirstword != line_decisions[next_lineno].diwfirstword)
1.1.1.5   root      384:            MARK_LINE_CHANGED;
1.1.1.2   root      385:        thisline_decision.diwlastword = -1;
                    386:     }
1.1.1.3   root      387:     if (hdiwstate == DIW_waiting_stop && thisline_decision.diwlastword == -1
1.1.1.9   root      388:        && pix_hpos >= diwlastword && last_diw_pix_hpos < diwlastword)
1.1.1.3   root      389:     {
1.1.1.2   root      390:        thisline_decision.diwlastword = diwlastword;
1.1.1.3   root      391:        hdiwstate = DIW_waiting_start;
1.1.1.2   root      392:        if (thisline_decision.diwlastword != line_decisions[next_lineno].diwlastword)
1.1.1.5   root      393:            MARK_LINE_CHANGED;
1.1.1.2   root      394:     }
1.1.1.9   root      395:     last_diw_pix_hpos = pix_hpos;
1.1.1.2   root      396: }
                    397: 
1.1.1.4   root      398: /* Called when we know that the line is not in the border and we want to draw
                    399:  * it.  The data fetch starting position and length are passed as parameters. */
1.1.1.8   root      400: STATIC_INLINE void decide_as_playfield (int startpos, int len)
1.1.1.2   root      401: {
                    402:     thisline_decision.which = 1;
                    403: 
                    404:     /* The latter condition might be able to happen in interlaced frames. */
                    405:     if (vpos >= minfirstline && (thisframe_first_drawn_line == -1 || vpos < thisframe_first_drawn_line))
                    406:        thisframe_first_drawn_line = vpos;
                    407:     thisframe_last_drawn_line = vpos;
                    408: 
                    409:     thisline_decision.plfstrt = startpos;
                    410:     thisline_decision.plflinelen = len;
                    411: 
                    412:     /* These are for comparison. */
                    413:     thisline_decision.bplcon0 = bplcon0;
                    414:     thisline_decision.bplcon2 = bplcon2;
                    415:     thisline_decision.bplcon4 = bplcon4;
1.1.1.11! root      416:     thisline_decision.fmode = fmode;
1.1.1.2   root      417: 
                    418: #ifdef SMART_UPDATE
                    419:     if (line_decisions[next_lineno].plfstrt != thisline_decision.plfstrt
                    420:        || line_decisions[next_lineno].plflinelen != thisline_decision.plflinelen
                    421:        || line_decisions[next_lineno].bplcon0 != thisline_decision.bplcon0
                    422:        || line_decisions[next_lineno].bplcon2 != thisline_decision.bplcon2
                    423:        || line_decisions[next_lineno].bplcon4 != thisline_decision.bplcon4
1.1.1.11! root      424:        || line_decisions[next_lineno].fmode != thisline_decision.fmode
1.1.1.2   root      425:        )
                    426: #endif /* SMART_UPDATE */
1.1.1.5   root      427:        thisline_changed = 1;
1.1.1.2   root      428: }
                    429: 
1.1.1.3   root      430: /* Called when we already decided whether the line is playfield or border,
                    431:  * but are no longer sure that this was such a good idea. This can make a
1.1.1.4   root      432:  * difference only for very badly written software.
                    433:  * 
                    434:  * We try to handle two cases:
                    435:  * a) bitplane DMA gets turned off during a line which was decided as plane
                    436:  * b) bitplane DMA turns on for all or some planes, either after the line was
                    437:  *    decided as border, or after we made an incorrect nr_planes decision.
                    438:  * 
                    439:  * Examples of programs which need this: Majic 12 "Ray of Hope 2" demo
                    440:  * (final large scrolltext) and Masterblazer (menu screen).
                    441:  * 
                    442:  * There's no hope of catching all cases; we'd need a cycle based emulation
                    443:  * for that. I'm getting increasingly convinced that that would be a good
                    444:  * idea.
                    445:  */
                    446: static int broken_plane_sub[8];
                    447: 
                    448: static void init_broken_program (void)
1.1.1.2   root      449: {
1.1.1.4   root      450:     int i;
                    451:     if (very_broken_program)
                    452:        return;
                    453:     very_broken_program = 1;
                    454:     for (i = 0; i < 8; i++)
                    455:        broken_plane_sub[i] = i >= decided_nr_planes || thisline_decision.which != 1 ? -1 : 0;
                    456: }
                    457: 
                    458: static void adjust_broken_program (int hpos)
                    459: {
                    460:     int tmp1, tmp2;
                    461:     int i;
1.1.1.9   root      462: 
                    463:     /* Magic again... :-/ */
                    464:     hpos += 4;
                    465: 
1.1.1.7   root      466:     if (decided_res == RES_HIRES) {
1.1.1.4   root      467:        tmp1 = hpos & 3;
                    468:        tmp2 = hpos & ~3;
1.1.1.7   root      469:     } else if (decided_res == RES_SUPERHIRES) {
                    470:        tmp1 = hpos & 1;
                    471:        tmp2 = hpos & ~1;
1.1.1.4   root      472:     } else {
                    473:        tmp1 = hpos & 7;
                    474:        tmp2 = hpos & ~7;
                    475:     }
                    476:     for (i = 0; i < decided_nr_planes; i++) {
                    477:        if (broken_plane_sub[i] != -1)
                    478:            continue;
1.1.1.7   root      479:        /* FIXME: superhires, AGA playfields */
                    480:        /* Actually, I don't want to support this crap for AGA if we can avoid it.  */
                    481:        if (decided_res == RES_HIRES) {
1.1.1.4   root      482:            broken_plane_sub[i] = (tmp2 - thisline_decision.plfstrt) / 4 * 2;
                    483:            switch (i) {
                    484:             case 3: broken_plane_sub[i] += 2; break; /* @@@ break was missing */
                    485:             case 2: broken_plane_sub[i] += (tmp1 >= 3 ? 2 : 0); break;
                    486:             case 1: broken_plane_sub[i] += (tmp1 >= 2 ? 2 : 0); break;
                    487:             case 0: break;
                    488:            }
                    489:        } else {
                    490:            broken_plane_sub[i] = (tmp2 - thisline_decision.plfstrt) / 8 * 2;
                    491:            switch (i) {
                    492:             case 5: broken_plane_sub[i] += (tmp1 >= 3 ? 2 : 0); break;
                    493:             case 4: broken_plane_sub[i] += (tmp1 >= 7 ? 2 : 0); break;
                    494:             case 3: broken_plane_sub[i] += (tmp1 >= 2 ? 2 : 0); break;
                    495:             case 2: broken_plane_sub[i] += (tmp1 >= 6 ? 2 : 0); break;
                    496:             case 1: broken_plane_sub[i] += (tmp1 >= 4 ? 2 : 0); break;
                    497:             case 0: break;
                    498:            }
                    499:        }
                    500:     }
                    501: }
1.1.1.2   root      502: 
1.1.1.8   root      503: STATIC_INLINE void set_decided_res (void)
1.1.1.7   root      504: {
                    505:     decided_res = RES_LORES;
                    506:     if (bplcon0 & 0x8000)
                    507:        decided_res = RES_HIRES;
                    508:     if (bplcon0 & 0x40)
                    509:        decided_res = RES_SUPERHIRES;
                    510: }
                    511: 
1.1.1.8   root      512: STATIC_INLINE void post_decide_line (int hpos)
1.1.1.4   root      513: {
                    514:     if (thisline_decision.which == 1
                    515:        && hpos < thisline_decision.plfstrt + thisline_decision.plflinelen
1.1.1.6   root      516:        && (GET_PLANES (bplcon0) == 0 || !dmaen (DMA_BITPLANE)))
1.1.1.2   root      517:     {
                    518:        /* This is getting gross... */
1.1.1.4   root      519:        thisline_decision.plflinelen = hpos - thisline_decision.plfstrt;
1.1.1.2   root      520:        thisline_decision.plflinelen &= 7;
                    521:        if (thisline_decision.plflinelen == 0)
                    522:            thisline_decision.which = -1;
                    523:        /* ... especially THIS! */
                    524:        modulos_added = 1;
                    525:        return;
                    526:     }
1.1.1.3   root      527: 
1.1.1.4   root      528:     if (diwstate == DIW_waiting_start
1.1.1.6   root      529:        || GET_PLANES (bplcon0) == 0
1.1.1.4   root      530:        || !dmaen (DMA_BITPLANE)
                    531:        || hpos >= thisline_decision.plfstrt + thisline_decision.plflinelen)
1.1.1.2   root      532:        return;
1.1.1.4   root      533: 
                    534:     if (thisline_decision.which == 1
                    535:        && hpos > thisline_decision.plfstrt
                    536:        && decided_nr_planes < nr_planes_from_bplcon0)
                    537:     {
1.1.1.7   root      538:        set_decided_res ();
1.1.1.4   root      539:        init_broken_program ();
                    540:        decided_nr_planes = nr_planes_from_bplcon0;
1.1.1.6   root      541:        thisline_decision.bplcon0 &= 0xFEF;
                    542:        thisline_decision.bplcon0 |= bplcon0 & 0xF010;
1.1.1.4   root      543:        adjust_broken_program (hpos);
1.1.1.5   root      544:        MARK_LINE_CHANGED; /* Play safe. */
1.1.1.4   root      545:        return;
                    546:     }
1.1.1.10  root      547: 
1.1.1.4   root      548:     if (thisline_decision.which != -1)
                    549:        return;
                    550: 
1.1.1.2   root      551: #if 0 /* Can't warn because Kickstart 1.3 does it at reset time ;-) */
1.1.1.4   root      552:     {
                    553:        static int warned = 0;
                    554:        if (!warned) {
                    555:            write_log ("That program you are running is _really_ broken.\n");
                    556:            warned = 1;
                    557:        }
1.1.1.2   root      558:     }
                    559: #endif
1.1.1.4   root      560:     init_broken_program ();
1.1.1.2   root      561: 
1.1.1.3   root      562:     decided_nr_planes = nr_planes_from_bplcon0;
1.1.1.6   root      563:     thisline_decision.bplcon0 &= 0xFEF;
                    564:     thisline_decision.bplcon0 |= bplcon0 & 0xF010;
1.1.1.2   root      565: 
1.1.1.5   root      566:     MARK_LINE_CHANGED; /* Play safe. */
1.1.1.4   root      567:     decide_as_playfield (plfstrt, plflinelen);
                    568:     adjust_broken_program (hpos);
1.1.1.2   root      569: }
                    570: 
1.1.1.4   root      571: static void decide_line_1 (int hpos)
1.1.1.2   root      572: {
1.1.1.4   root      573:     do_sprites (vpos, hpos);
1.1.1.2   root      574: 
                    575:     /* Surprisingly enough, this seems to be correct here - putting this into
                    576:      * decide_diw() results in garbage. */
                    577:     if (diwstate == DIW_waiting_start && vpos == plffirstline) {
                    578:        diwstate = DIW_waiting_stop;
                    579:     }
                    580:     if (diwstate == DIW_waiting_stop && vpos == plflastline) {
                    581:        diwstate = DIW_waiting_start;
                    582:     }
                    583: 
                    584:     if (framecnt != 0) {
                    585: /*     thisline_decision.which = -2; This doesn't do anything but hurt, I think. */
                    586:        return;
                    587:     }
1.1.1.3   root      588: 
                    589:     if (!dmaen(DMA_BITPLANE) || diwstate == DIW_waiting_start || nr_planes_from_bplcon0 == 0) {
1.1.1.2   root      590:        /* We don't want to draw this one. */
                    591:        thisline_decision.which = -1;
1.1.1.3   root      592:        thisline_decision.plfstrt = plfstrt;
                    593:        thisline_decision.plflinelen = plflinelen;
1.1.1.2   root      594:        return;
                    595:     }
                    596: 
1.1.1.7   root      597:     set_decided_res ();
1.1.1.3   root      598:     decided_nr_planes = nr_planes_from_bplcon0;
1.1.1.2   root      599: #if 0
1.1.1.3   root      600:     /* The blitter gets slower if there's high bitplane activity.
1.1.1.2   root      601:      * @@@ but the values must be different. FIXME */
                    602:     if (bltstate != BLT_done
1.1.1.7   root      603:        && ((decided_res == RES_HIRES && decided_nr_planes > 2)
                    604:            || (decided_res == RES_LORES && decided_nr_planes > 4)))
1.1.1.2   root      605:     {
                    606:        int pl = decided_nr_planes;
                    607:        unsigned int n = (eventtab[ev_blitter].evtime-cycles);
                    608:        if (n > plflinelen)
                    609:            n = plflinelen;
                    610:        n >>= 1;
1.1.1.7   root      611:        if (decided_res == RES_HIRES)
1.1.1.2   root      612:            pl <<= 1;
                    613:        if (pl == 8)
                    614:            eventtab[ev_blitter].evtime += plflinelen;
                    615:        else if (pl == 6)
                    616:            eventtab[ev_blitter].evtime += n*2;
                    617:        else if (pl == 5)
                    618:            eventtab[ev_blitter].evtime += n*3/2;
                    619:        events_schedule();
                    620:     }
                    621: #endif
                    622:     decide_as_playfield (plfstrt, plflinelen);
                    623: }
                    624: 
1.1.1.3   root      625: /* Main entry point for deciding how to draw a line. May either do
                    626:  * nothing, decide the line as border, or decide the line as playfield. */
1.1.1.8   root      627: STATIC_INLINE void decide_line (int hpos)
1.1.1.2   root      628: {
1.1.1.4   root      629:     if (thisline_decision.which == 0 && hpos >= plfstrt)
                    630:        decide_line_1 (hpos);
1.1.1.2   root      631: }
                    632: 
1.1.1.3   root      633: /* Called when a color is about to be changed (write to a color register),
                    634:  * but the new color has not been entered into the table yet. */
1.1.1.4   root      635: static void record_color_change (int hpos, int regno, unsigned long value)
1.1.1.3   root      636: {
                    637:     /* Early positions don't appear on-screen. */
1.1.1.4   root      638:     if (framecnt != 0 || vpos < minfirstline || hpos < 0x18
1.1.1.3   root      639:        /*|| currprefs.emul_accuracy == 0*/)
                    640:        return;
                    641: 
1.1.1.4   root      642:     decide_diw (hpos);
                    643:     decide_line (hpos);
1.1.1.3   root      644: 
                    645:     /* See if we can record the color table, but have not done so yet.
                    646:      * @@@ There might be a minimal performance loss in case someone changes
                    647:      * a color exactly at the start of the DIW. I don't think it can actually
                    648:      * fail to work even in this case, but I'm not 100% sure.
                    649:      * @@@ There might be a slightly larger performance loss if we're drawing
                    650:      * this line as border... especially if there are changes in colors != 0
                    651:      * we might end up setting line_changed for no reason. FIXME */
                    652:     if (thisline_decision.diwfirstword >= 0
                    653:        && thisline_decision.which != 0)
                    654:     {
                    655:        if (thisline_decision.ctable == -1)
                    656:            remember_ctable ();
                    657:     }
                    658: 
                    659:     /* Changes outside the DIW can be ignored if the modified color is not the
                    660:      * background color, or if the accuracy is < 2. */
                    661:     if ((regno != 0 || currprefs.emul_accuracy < 2)
                    662:        && (diwstate == DIW_waiting_start || thisline_decision.diwfirstword < 0
                    663:            || thisline_decision.diwlastword >= 0
                    664:            || thisline_decision.which == 0
1.1.1.4   root      665:            || (thisline_decision.which == 1 && hpos >= thisline_decision.plfstrt + thisline_decision.plflinelen)))
1.1.1.3   root      666:        return;
                    667: 
                    668:     /* If the border is changed the first time before the DIW, record the
                    669:      * original starting border value. */
                    670:     if (regno == 0 && thisline_decision.color0 == 0xFFFFFFFFul && thisline_decision.diwfirstword < 0) {
1.1.1.11! root      671:        thisline_decision.color0 = color_reg_get (&current_colors, 0);
1.1.1.3   root      672:        if (line_decisions[next_lineno].color0 != value)
1.1.1.5   root      673:            thisline_changed = 1;
1.1.1.3   root      674:     }
                    675:     /* Anything else gets recorded in the color_changes table. */
                    676: #ifdef OS_WITHOUT_MEMORY_MANAGEMENT
1.1.1.4   root      677:     if (next_color_change >= max_color_change) {
1.1.1.3   root      678:        ++delta_color_change;
                    679:        return;
                    680:     }
                    681: #endif
1.1.1.4   root      682:     curr_color_changes[next_color_change].linepos = hpos;
1.1.1.3   root      683:     curr_color_changes[next_color_change].regno = regno;
                    684:     curr_color_changes[next_color_change++].value = value;
                    685: }
                    686: 
                    687: /* Stupid hack to get some Sanity demos working. */
1.1.1.4   root      688: static void decide_delay (int hpos)
1.1.1.2   root      689: {
                    690:     static int warned;
                    691: 
                    692:     /* Don't do anything if we're outside the DIW. */
                    693:     if (thisline_decision.diwfirstword == -1 || thisline_decision.diwlastword > 0)
                    694:        return;
1.1.1.4   root      695:     decide_line (hpos);
1.1.1.2   root      696:     /* Half-hearted attempt to get things right even when post_decide_line() changes
                    697:      * the decision afterwards. */
                    698:     if (thisline_decision.which != 1) {
                    699:        thisline_decision.bplcon1 = bplcon1;
                    700:        return;
                    701:     }
                    702:     /* @@@ Could check here for DDF stopping earlier than DIW */
1.1.1.3   root      703: 
                    704: #ifdef OS_WITHOUT_MEMORY_MANAGEMENT
1.1.1.4   root      705:     if (next_delay_change >= max_delay_change) {
1.1.1.3   root      706:        ++delta_delay_change;
                    707:        return;
                    708:     }
                    709: #endif
1.1.1.4   root      710:     delay_changes[next_delay_change].linepos = hpos;
1.1.1.2   root      711:     delay_changes[next_delay_change++].value = bplcon1;
                    712:     if (!warned) {
                    713:        warned = 1;
1.1.1.3   root      714:        write_log ("Program is torturing BPLCON1.\n");
1.1.1.2   root      715:     }
                    716: }
                    717: 
                    718: /*
1.1.1.4   root      719:  * The decision which bitplane pointers to use is not made at plfstrt, since
1.1.1.2   root      720:  * data fetch does not start for all planes at this point. Therefore, we wait
                    721:  * for the end of the ddf area or the first write to any of the bitplane
                    722:  * pointer registers, whichever comes last, before we decide which plane pointers
                    723:  * to use.
                    724:  * Call decide_line() before this function.
                    725:  */
1.1.1.4   root      726: static void decide_plane (int hpos)
1.1.1.2   root      727: {
                    728:     int i, bytecount;
                    729: 
                    730:     if (framecnt != 0 || plane_decided)
                    731:        return;
                    732: 
                    733:     if (decided_nr_planes == -1 /* Still undecided */
1.1.1.4   root      734:        || hpos < thisline_decision.plfstrt + thisline_decision.plflinelen)
1.1.1.2   root      735:        return;
                    736: 
                    737:     plane_decided = 1;
                    738: 
1.1.1.7   root      739:     bytecount = plflinelen / RES_SHIFT (decided_res) * 2;
1.1.1.2   root      740: 
                    741:     if (bytecount > MAX_WORDS_PER_LINE * 2) {
                    742:        /* Can't happen. */
                    743:        static int warned = 0;
                    744:        if (!warned)
1.1.1.3   root      745:            write_log ("Mysterious bug in decide_plane(). Please report.\n");
1.1.1.7   root      746:        warned = 1;
1.1.1.2   root      747:        bytecount = 0;
                    748:     }
                    749:     if (!very_broken_program) {
1.1.1.3   root      750:        uae_u8 *dataptr = line_data[next_lineno];
1.1.1.2   root      751:        for (i = 0; i < decided_nr_planes; i++, dataptr += MAX_WORDS_PER_LINE*2) {
1.1.1.3   root      752:            uaecptr pt = bplpt[i];
1.1.1.10  root      753:            uae_u8 *real_ptr = pfield_xlateptr (pt, bytecount);
1.1.1.2   root      754:            if (real_ptr == NULL)
1.1.1.10  root      755:                real_ptr = pfield_xlateptr (0, 0);
1.1.1.2   root      756: #ifdef SMART_UPDATE
1.1.1.3   root      757: #if 1
1.1.1.5   root      758:            if (thisline_changed)
1.1.1.2   root      759:                memcpy (dataptr, real_ptr, bytecount);
1.1.1.3   root      760:            else
                    761: #endif
1.1.1.5   root      762:                thisline_changed |= memcmpy (dataptr, real_ptr, bytecount);
1.1.1.2   root      763: #else
                    764:            real_bplpt[i] = real_ptr;
                    765: #endif
                    766:        }
1.1       root      767:     } else {
1.1.1.3   root      768:        uae_u8 *dataptr = line_data[next_lineno];
1.1.1.2   root      769:        for (i = 0; i < decided_nr_planes; i++, dataptr += MAX_WORDS_PER_LINE*2) {
1.1.1.3   root      770:            uaecptr pt = bplpt[i];
                    771:            uae_u8 *real_ptr;
                    772: 
1.1.1.4   root      773:            pt -= broken_plane_sub[i];
                    774:            real_ptr = pfield_xlateptr (pt, bytecount);
1.1.1.2   root      775:            if (real_ptr == NULL)
                    776:                real_ptr = pfield_xlateptr(0, 0);
                    777: #ifdef SMART_UPDATE
1.1.1.5   root      778:            if (!thisline_changed)
                    779:                thisline_changed |= memcmpy (dataptr, real_ptr, bytecount);
1.1.1.2   root      780:            else
                    781:                memcpy (dataptr, real_ptr, bytecount);
                    782: #else
                    783:            real_bplpt[i] = real_ptr;
                    784: #endif
                    785:        }
                    786:     }
                    787: }
                    788: 
                    789: /*
                    790:  * Called from the BPLxMOD routines, after a new value has been written.
                    791:  * This routine decides whether the new value is already relevant for the
                    792:  * current line.
                    793:  */
1.1.1.4   root      794: static void decide_modulos (int hpos)
1.1.1.2   root      795: {
                    796:     /* All this effort just for the Sanity WOC demo... */
1.1.1.4   root      797:     decide_line (hpos);
1.1.1.9   root      798:     if (decided_nr_planes != -1
                    799:        && hpos >= thisline_decision.plfstrt + thisline_decision.plflinelen)
1.1.1.2   root      800:        return;
                    801:     decided_bpl1mod = bpl1mod;
                    802:     decided_bpl2mod = bpl2mod;
                    803: }
                    804: 
                    805: /*
1.1.1.3   root      806:  * Add the modulos to the bitplane pointers if data fetch is already
                    807:  * finished for the current line.
                    808:  * Call decide_plane() before calling this, so that we won't use the
                    809:  * new values of the plane pointers for the current line.
1.1.1.2   root      810:  */
1.1.1.4   root      811: static void do_modulos (int hpos)
1.1.1.2   root      812: {
                    813:     /* decided_nr_planes is != -1 if this line should be drawn by the
1.1.1.3   root      814:      * display hardware, regardless of whether it fits on the emulated screen.
1.1.1.2   root      815:      */
                    816:     if (decided_nr_planes != -1 && plane_decided && !modulos_added
1.1.1.4   root      817:        && hpos >= thisline_decision.plfstrt + thisline_decision.plflinelen)
1.1.1.2   root      818:     {
1.1.1.7   root      819:        int bytecount = thisline_decision.plflinelen / RES_SHIFT (decided_res) * 2;
1.1.1.2   root      820:        int add1 = bytecount + decided_bpl1mod;
                    821:        int add2 = bytecount + decided_bpl2mod;
                    822: 
                    823:        if (!very_broken_program) {
                    824:            switch (decided_nr_planes) {
                    825:             case 8: bplpt[7] += add2;
                    826:             case 7: bplpt[6] += add1;
                    827:             case 6: bplpt[5] += add2;
                    828:             case 5: bplpt[4] += add1;
                    829:             case 4: bplpt[3] += add2;
                    830:             case 3: bplpt[2] += add1;
                    831:             case 2: bplpt[1] += add2;
                    832:             case 1: bplpt[0] += add1;
                    833:            }
1.1.1.4   root      834:        } else switch (decided_nr_planes) {
                    835:             case 8: bplpt[7] += add2 - broken_plane_sub[7];
                    836:             case 7: bplpt[6] += add1 - broken_plane_sub[6];
                    837:             case 6: bplpt[5] += add2 - broken_plane_sub[5];
                    838:             case 5: bplpt[4] += add1 - broken_plane_sub[4];
                    839:             case 4: bplpt[3] += add2 - broken_plane_sub[3];
                    840:             case 3: bplpt[2] += add1 - broken_plane_sub[2];
                    841:             case 2: bplpt[1] += add2 - broken_plane_sub[1];
                    842:             case 1: bplpt[0] += add1 - broken_plane_sub[0];
1.1.1.2   root      843:        }
                    844: 
                    845:        modulos_added = 1;
                    846:     }
                    847: }
                    848: 
1.1.1.8   root      849: STATIC_INLINE void record_sprite (int spr, int sprxp)
1.1.1.2   root      850: {
1.1.1.3   root      851:     int pos = next_sprite_draw;
                    852:     unsigned int data, datb;
1.1.1.2   root      853: 
1.1.1.3   root      854: #ifdef OS_WITHOUT_MEMORY_MANAGEMENT
                    855:     if(pos >= max_sprite_draw) {
                    856:        ++delta_sprite_draw;
1.1.1.2   root      857:        return;
1.1.1.3   root      858:     }
                    859: #endif
                    860:     /* XXX FIXME, this isn't very clever, but it might do */
                    861:     for (;;) {
                    862:        if (pos == curr_drawinfo[next_lineno].first_sprite_draw)
                    863:            break;
                    864:        if (curr_sprite_positions[pos-1].linepos < sprxp)
                    865:            break;
                    866:        if (curr_sprite_positions[pos-1].linepos == sprxp
                    867:            && curr_sprite_positions[pos-1].num > spr)
                    868:            break;
                    869:        printf("Foo\n");
                    870:        pos--;
                    871:     }
                    872:     if (pos != next_sprite_draw) {
                    873:        int pos2 = next_sprite_draw;
                    874:        while (pos2 != pos) {
                    875:            curr_sprite_positions[pos2] = curr_sprite_positions[pos2-1];
                    876:            pos2--;
                    877:        }
                    878:     }
                    879:     curr_sprite_positions[pos].linepos = sprxp;
                    880:     curr_sprite_positions[pos].num = spr;
                    881:     curr_sprite_positions[pos].ctl = sprctl[spr];
1.1.1.7   root      882:     data = sprdata[spr];
                    883:     datb = sprdatb[spr];
1.1.1.3   root      884:     curr_sprite_positions[pos].datab = ((sprtaba[data & 0xFF] << 16) | sprtaba[data >> 8]
                    885:                                        | (sprtabb[datb & 0xFF] << 16) | sprtabb[datb >> 8]);
                    886:     next_sprite_draw++;
                    887: }
1.1.1.2   root      888: 
1.1.1.4   root      889: static void decide_sprites (int hpos)
1.1.1.3   root      890: {
1.1.1.7   root      891:     int nrs[MAX_SPRITES], posns[MAX_SPRITES];
                    892:     int count, i;
1.1.1.4   root      893:     int point = PIXEL_XPOS (hpos);
1.1.1.2   root      894: 
1.1.1.4   root      895:     if (framecnt != 0 || hpos < 0x14 || nr_armed == 0 || point == last_sprite_point)
1.1.1.2   root      896:        return;
                    897: 
1.1.1.4   root      898:     decide_diw (hpos);
                    899:     decide_line (hpos);
1.1.1.3   root      900: 
                    901:     if (thisline_decision.which != 1)
1.1.1.2   root      902:        return;
                    903: 
1.1.1.3   root      904:     count = 0;
                    905:     for (i = 0; i < 8; i++) {
1.1.1.10  root      906:        int sprxp = spr[i].xpos;
1.1.1.3   root      907:        int j, bestp;
1.1.1.2   root      908: 
1.1.1.10  root      909:        if (! spr[i].armed || sprxp < 0 || sprxp > point || last_sprite_point >= sprxp)
1.1.1.3   root      910:            continue;
                    911:        if ((thisline_decision.diwfirstword >= 0 && sprxp + sprite_width < thisline_decision.diwfirstword)
                    912:            || (thisline_decision.diwlastword >= 0 && sprxp > thisline_decision.diwlastword))
                    913:            continue;
1.1.1.2   root      914: 
1.1.1.3   root      915:        for (bestp = 0; bestp < count; bestp++) {
                    916:            if (posns[bestp] > sprxp)
                    917:                break;
                    918:            if (posns[bestp] == sprxp && nrs[bestp] < i)
                    919:                break;
                    920:        }
                    921:        for (j = count; j > bestp; j--) {
                    922:            posns[j] = posns[j-1];
                    923:            nrs[j] = nrs[j-1];
                    924:        }
                    925:        posns[j] = sprxp;
                    926:        nrs[j] = i;
                    927:        count++;
                    928:     }
                    929:     for (i = 0; i < count; i++)
1.1.1.4   root      930:        record_sprite (nrs[i], posns[i]);
1.1.1.3   root      931:     last_sprite_point = point;
1.1.1.2   root      932: }
                    933: 
1.1.1.3   root      934: /* End of a horizontal scan line. Finish off all decisions that were not
                    935:  * made yet. */
1.1.1.2   root      936: static void finish_decisions (void)
                    937: {
                    938:     struct draw_info *dip;
                    939:     struct draw_info *dip_old;
                    940:     struct decision *dp;
                    941:     int changed;
1.1.1.4   root      942:     int hpos = current_hpos ();
1.1.1.2   root      943: 
                    944:     if (framecnt != 0)
                    945:        return;
                    946: 
1.1.1.4   root      947:     decide_diw (hpos);
1.1.1.2   root      948:     if (thisline_decision.which == 0)
1.1.1.4   root      949:        decide_line_1 (hpos);
1.1.1.3   root      950: 
                    951:     /* Large DIWSTOP values can cause the stop position never to be
                    952:      * reached, so the state machine always stays in the same state and
                    953:      * there's a more-or-less full-screen DIW. */
                    954:     if (hdiwstate == DIW_waiting_stop) {
                    955:        thisline_decision.diwlastword = max_diwlastword;
                    956:        if (thisline_decision.diwlastword != line_decisions[next_lineno].diwlastword)
1.1.1.5   root      957:            MARK_LINE_CHANGED;
1.1.1.3   root      958:     }
                    959: 
1.1.1.2   root      960:     if (line_decisions[next_lineno].which != thisline_decision.which)
1.1.1.5   root      961:        thisline_changed = 1;
1.1.1.4   root      962:     decide_plane (hpos);
1.1.1.2   root      963: 
                    964:     dip = curr_drawinfo + next_lineno;
                    965:     dip_old = prev_drawinfo + next_lineno;
                    966:     dp = line_decisions + next_lineno;
1.1.1.5   root      967:     changed = thisline_changed;
1.1.1.2   root      968: 
                    969:     if (thisline_decision.which == 1) {
1.1.1.4   root      970:        record_diw_line (diwfirstword, diwlastword);
1.1.1.2   root      971: 
1.1.1.4   root      972:        decide_sprites (hpos);
1.1.1.3   root      973: 
1.1.1.2   root      974:        if (thisline_decision.bplcon1 != line_decisions[next_lineno].bplcon1)
                    975:            changed = 1;
                    976:     }
                    977: 
                    978:     dip->last_color_change = next_color_change;
                    979:     dip->last_delay_change = next_delay_change;
                    980:     dip->last_sprite_draw = next_sprite_draw;
1.1.1.3   root      981: 
                    982:     if (thisline_decision.ctable == -1) {
                    983:        if (thisline_decision.which == 1)
                    984:            remember_ctable ();
                    985:        else
                    986:            remember_ctable_for_border ();
                    987:     }
1.1.1.2   root      988:     if (thisline_decision.which == -1 && thisline_decision.color0 == 0xFFFFFFFFul)
1.1.1.11! root      989:        thisline_decision.color0 = color_reg_get (&current_colors, 0);
1.1.1.2   root      990: 
                    991:     dip->nr_color_changes = next_color_change - dip->first_color_change;
                    992:     dip->nr_sprites = next_sprite_draw - dip->first_sprite_draw;
                    993: 
                    994:     if (dip->first_delay_change != dip->last_delay_change)
                    995:        changed = 1;
                    996:     if (!changed
                    997:        && (dip->nr_color_changes != dip_old->nr_color_changes
1.1.1.3   root      998:            || (dip->nr_color_changes > 0
                    999:                && memcmp (curr_color_changes + dip->first_color_change,
                   1000:                           prev_color_changes + dip_old->first_color_change,
                   1001:                           dip->nr_color_changes * sizeof *curr_color_changes) != 0)))
1.1.1.2   root     1002:        changed = 1;
                   1003:     if (!changed && thisline_decision.which == 1
                   1004:        && (dip->nr_sprites != dip_old->nr_sprites
                   1005:            || (dip->nr_sprites > 0
1.1.1.3   root     1006:                && memcmp (curr_sprite_positions + dip->first_sprite_draw,
                   1007:                           prev_sprite_positions + dip_old->first_sprite_draw,
                   1008:                           dip->nr_sprites * sizeof *curr_sprite_positions) != 0)))
1.1.1.2   root     1009:        changed = 1;
1.1.1.10  root     1010:     if (thisline_decision.plfleft != line_decisions[next_lineno].plfleft)
                   1011:        changed = 1;
1.1.1.2   root     1012: 
                   1013:     if (changed) {
1.1.1.5   root     1014:        thisline_changed = 1;
1.1.1.2   root     1015:        *dp = thisline_decision;
                   1016:     } else
                   1017:        /* The only one that may differ: */
                   1018:        dp->ctable = thisline_decision.ctable;
                   1019: }
                   1020: 
1.1.1.3   root     1021: /* Set the state of all decisions to "undecided" for a new scanline. */
1.1.1.2   root     1022: static void reset_decisions (void)
                   1023: {
                   1024:     if (framecnt != 0)
                   1025:        return;
                   1026:     thisline_decision.which = 0;
                   1027:     decided_bpl1mod = bpl1mod;
                   1028:     decided_bpl2mod = bpl2mod;
                   1029:     decided_nr_planes = -1;
                   1030: 
1.1.1.10  root     1031:     thisline_decision.plfleft = -1;
                   1032: 
1.1.1.7   root     1033:     /* decided_res shouldn't be touched before it's initialized by decide_line(). */
1.1.1.2   root     1034:     thisline_decision.diwfirstword = -1;
                   1035:     thisline_decision.diwlastword = -2;
1.1.1.3   root     1036:     if (hdiwstate == DIW_waiting_stop) {
                   1037:        thisline_decision.diwfirstword = PIXEL_XPOS (DISPLAY_LEFT_SHIFT/2);
                   1038:        if (thisline_decision.diwfirstword != line_decisions[next_lineno].diwfirstword)
1.1.1.5   root     1039:            MARK_LINE_CHANGED;
1.1.1.3   root     1040:     }
1.1.1.2   root     1041:     thisline_decision.ctable = -1;
                   1042:     thisline_decision.color0 = 0xFFFFFFFFul;
                   1043: 
1.1.1.5   root     1044:     thisline_changed = 0;
1.1.1.2   root     1045:     curr_drawinfo[next_lineno].first_color_change = next_color_change;
                   1046:     curr_drawinfo[next_lineno].first_delay_change = next_delay_change;
                   1047:     curr_drawinfo[next_lineno].first_sprite_draw = next_sprite_draw;
                   1048: 
1.1.1.3   root     1049:     /* memset(sprite_last_drawn_at, 0, sizeof sprite_last_drawn_at); */
                   1050:     last_sprite_point = 0;
1.1.1.2   root     1051:     modulos_added = 0;
                   1052:     plane_decided = 0;
                   1053:     color_decided = 0;
                   1054:     very_broken_program = 0;
1.1.1.9   root     1055: 
                   1056:     last_diw_pix_hpos = -1;
                   1057:     last_ddf_pix_hpos = -1;
1.1.1.2   root     1058: }
                   1059: 
1.1.1.3   root     1060: /* Initialize the decision array, once before the emulator really starts. */
1.1.1.2   root     1061: static void init_decisions (void)
                   1062: {
                   1063:     size_t i;
                   1064:     for (i = 0; i < sizeof line_decisions / sizeof *line_decisions; i++) {
                   1065:        line_decisions[i].which = -2;
1.1       root     1066:     }
1.1.1.2   root     1067: }
                   1068: 
1.1.1.7   root     1069: /* set PAL or NTSC timing variables */
                   1070: 
                   1071: static void init_hz (void)
                   1072: {
                   1073:     int isntsc;
                   1074: 
                   1075:     beamcon0 = new_beamcon0;
                   1076:     init_decisions ();
                   1077: 
                   1078:     isntsc = beamcon0 & 0x20 ? 0 : 1;
                   1079:     if (!isntsc) {
                   1080:        maxvpos = MAXVPOS_PAL;
                   1081:        maxhpos = MAXHPOS_PAL;
                   1082:        minfirstline = MINFIRSTLINE_PAL;
                   1083:        vblank_endline = VBLANK_ENDLINE_PAL;
                   1084:        vblank_hz = VBLANK_HZ_PAL;
                   1085:     } else {
                   1086:        maxvpos = MAXVPOS_NTSC;
                   1087:        maxhpos = MAXHPOS_NTSC;
                   1088:        minfirstline = MINFIRSTLINE_NTSC;
                   1089:        vblank_endline = VBLANK_ENDLINE_NTSC;
                   1090:        vblank_hz = VBLANK_HZ_NTSC;
                   1091:     }
                   1092:     vsynctime = syncbase / vblank_hz;
                   1093: 
                   1094:     write_log ("Using %s timing\n", isntsc ? "NTSC" : "PAL");
                   1095: }
                   1096: 
1.1.1.11! root     1097: void expand_fetchmodes (int fmode, int bplcon0)
1.1.1.2   root     1098: {
1.1.1.11! root     1099:     int res;
        !          1100: 
        !          1101:     if (bplcon0 & 0x8000)
        !          1102:        res = 1;
        !          1103:     else if (bplcon0 & 0x0040)
        !          1104:        res = 2;
        !          1105:     else
        !          1106:        res = 0;
        !          1107:     switch (fmode & 3) {
        !          1108:        case 3:
        !          1109:            fetchmode = 2;
        !          1110:            switch (res) {
        !          1111:            case 2: prefetch = 1<<3; fetchsize = 1<<3; fetchstart_shift = 3; break;
        !          1112:            case 1: prefetch = 1<<3; fetchsize = 1<<4; fetchstart_shift = 4; break;
        !          1113:            case 0: prefetch = 1<<3; fetchsize = 1<<5; fetchstart_shift = 5; break;
        !          1114:            }
        !          1115:            break;
        !          1116:        case 2:
        !          1117:        case 1:
        !          1118:            fetchmode = 1;
        !          1119:            switch (res) {
        !          1120:            case 2: prefetch = 1<<2; fetchsize = 1<<3; fetchstart_shift = 2; break;
        !          1121:            case 1: prefetch = 1<<3; fetchsize = 1<<3; fetchstart_shift = 3; break;
        !          1122:            case 0: prefetch = 1<<3; fetchsize = 1<<4; fetchstart_shift = 4; break;
        !          1123:            }
        !          1124:            break;
        !          1125:        case 0:
        !          1126:            fetchmode = 0;
        !          1127:            switch (res) {
        !          1128:            case 2: prefetch = 1<<1; fetchsize = 1<<3; fetchstart_shift = 1; break;
        !          1129:            case 1: prefetch = 1<<2; fetchsize = 1<<3; fetchstart_shift = 2; break;
        !          1130:            case 0: prefetch = 1<<3; fetchsize = 1<<3; fetchstart_shift = 3; break;
        !          1131:            }
        !          1132:            break;
        !          1133:        }
        !          1134:     fetchstart = 1 << fetchstart_shift;
        !          1135: }
1.1.1.7   root     1136: 
1.1.1.11! root     1137: static void calcdiw (void)
        !          1138: {
        !          1139:     int fetch;
1.1.1.4   root     1140:     int hstrt = diwstrt & 0xFF;
                   1141:     int hstop = diwstop & 0xFF;
                   1142:     int vstrt = diwstrt >> 8;
                   1143:     int vstop = diwstop >> 8;
                   1144: 
                   1145:     if (diwhigh_written) {
                   1146:        hstrt |= ((diwhigh >> 5) & 1) << 8;
                   1147:        hstop |= ((diwhigh >> 13) & 1) << 8;
                   1148:        vstrt |= (diwhigh & 7) << 8;
                   1149:        vstop |= ((diwhigh >> 8) & 7) << 8;
                   1150:     } else {
                   1151:        hstop += 0x100;
                   1152:        if ((vstop & 0x80) == 0)
                   1153:            vstop |= 0x100;
                   1154:     }
                   1155: 
1.1.1.10  root     1156:     diwfirstword = coord_hw_to_window_x (hstrt - 1);
                   1157:     diwlastword = coord_hw_to_window_x (hstop - 1);
1.1.1.2   root     1158: 
                   1159:     if (diwlastword > max_diwlastword)
                   1160:        diwlastword = max_diwlastword;
                   1161:     if (diwfirstword < 0)
                   1162:        diwfirstword = 0;
                   1163:     if (diwlastword < 0)
                   1164:        diwlastword = 0;
1.1.1.3   root     1165: 
1.1.1.4   root     1166:     plffirstline = vstrt;
                   1167:     plflastline = vstop;
                   1168: 
1.1       root     1169: #if 0
                   1170:     /* This happens far too often. */
                   1171:     if (plffirstline < minfirstline) {
                   1172:        fprintf(stderr, "Warning: Playfield begins before line %d!\n", minfirstline);
                   1173:        plffirstline = minfirstline;
                   1174:     }
                   1175: #endif
1.1.1.4   root     1176: 
1.1       root     1177: #if 0 /* Turrican does this */
                   1178:     if (plflastline > 313) {
1.1.1.4   root     1179:        fprintf (stderr, "Warning: Playfield out of range!\n");
1.1       root     1180:        plflastline = 313;
                   1181:     }
                   1182: #endif
1.1.1.2   root     1183:     plfstrt = ddfstrt;
                   1184:     plfstop = ddfstop;
1.1       root     1185:     if (plfstrt < 0x18) plfstrt = 0x18;
1.1.1.3   root     1186:     if (plfstop < 0x18) plfstop = 0x18;
1.1       root     1187:     if (plfstop > 0xD8) plfstop = 0xD8;
1.1.1.11! root     1188:     if (plfstrt > plfstop) plfstrt = plfstop;
1.1       root     1189: 
1.1.1.11! root     1190:     expand_fetchmodes (fmode, bplcon0);
        !          1191:     fetch = fetchsize >> fetchstart_shift;
        !          1192:     plflinelen = ((((plfstop - plfstrt + fetchstart - 1) >> fetchstart_shift)
        !          1193:                   + fetch + (fetch - 1)) & ~(fetch - 1) ) << fetchstart_shift;
1.1       root     1194: }
                   1195: 
1.1.1.4   root     1196: /* Mousehack stuff */
1.1.1.2   root     1197: 
1.1.1.4   root     1198: #define defstepx (1<<16)
                   1199: #define defstepy (1<<16)
                   1200: #define defxoffs 0
                   1201: #define defyoffs 0
1.1.1.3   root     1202: 
1.1.1.4   root     1203: static const int docal = 60, xcaloff = 40, ycaloff = 20;
                   1204: static const int calweight = 3;
                   1205: static int lastsampledmx, lastsampledmy;
                   1206: static int lastspr0x,lastspr0y,lastdiffx,lastdiffy,spr0pos,spr0ctl;
                   1207: static int mstepx,mstepy,xoffs=defxoffs,yoffs=defyoffs;
                   1208: static int sprvbfl;
1.1.1.2   root     1209: 
1.1.1.4   root     1210: int lastmx, lastmy;
                   1211: int newmousecounters;
                   1212: int ievent_alive = 0;
1.1       root     1213: 
1.1.1.4   root     1214: static enum { unknown_mouse, normal_mouse, dont_care_mouse, follow_mouse } mousestate;
1.1       root     1215: 
1.1.1.4   root     1216: static void mousehack_setdontcare (void)
1.1       root     1217: {
1.1.1.4   root     1218:     if (mousestate == dont_care_mouse)
1.1.1.2   root     1219:        return;
                   1220: 
1.1.1.3   root     1221:     write_log ("Don't care mouse mode set\n");
                   1222:     mousestate = dont_care_mouse;
                   1223:     lastspr0x = lastmx; lastspr0y = lastmy;
                   1224:     mstepx = defstepx; mstepy = defstepy;
                   1225: }
                   1226: 
1.1.1.4   root     1227: static void mousehack_setfollow (void)
1.1.1.3   root     1228: {
1.1.1.4   root     1229:     if (mousestate == follow_mouse)
                   1230:        return;
                   1231: 
1.1.1.3   root     1232:     write_log ("Follow sprite mode set\n");
                   1233:     mousestate = follow_mouse;
                   1234:     lastdiffx = lastdiffy = 0;
                   1235:     sprvbfl = 0;
1.1.1.4   root     1236:     spr0ctl = spr0pos = 0;
1.1.1.3   root     1237:     mstepx = defstepx; mstepy = defstepy;
                   1238: }
                   1239: 
1.1.1.7   root     1240: static uae_u32 mousehack_helper (void)
1.1.1.3   root     1241: {
                   1242:     int mousexpos, mouseypos;
                   1243: 
                   1244: #ifdef PICASSO96
                   1245:     if (picasso_on) {
1.1.1.4   root     1246:        mousexpos = lastmx - picasso96_state.XOffset;
                   1247:        mouseypos = lastmy - picasso96_state.YOffset;
1.1.1.3   root     1248:     } else
                   1249: #endif
                   1250:     {
                   1251:        if (lastmy >= gfxvidinfo.height)
1.1.1.4   root     1252:            lastmy = gfxvidinfo.height - 1;
                   1253:        mouseypos = coord_native_to_amiga_y (lastmy) << 1;
                   1254:        mousexpos = coord_native_to_amiga_x (lastmx);
1.1.1.3   root     1255:     }
                   1256: 
                   1257:     switch (m68k_dreg (regs, 0)) {
                   1258:      case 0:
                   1259:        return ievent_alive ? -1 : needmousehack ();
                   1260:      case 1:
                   1261:        ievent_alive = 10;
                   1262:        return mousexpos;
                   1263:      case 2:
                   1264:        return mouseypos;
                   1265:     }
                   1266:     return 0;
                   1267: }
                   1268: 
1.1.1.4   root     1269: void togglemouse (void)
1.1.1.3   root     1270: {
1.1.1.4   root     1271:     switch (mousestate) {
                   1272:      case dont_care_mouse: mousehack_setfollow (); break;
                   1273:      case follow_mouse: mousehack_setdontcare (); break;
1.1.1.3   root     1274:      default: break; /* Nnnnnghh! */
                   1275:     }
                   1276: }
                   1277: 
1.1.1.8   root     1278: STATIC_INLINE int adjust (int val)
1.1.1.3   root     1279: {
1.1.1.4   root     1280:     if (val > 127)
1.1.1.3   root     1281:        return 127;
1.1.1.4   root     1282:     else if (val < -127)
1.1.1.3   root     1283:        return -127;
                   1284:     return val;
                   1285: }
                   1286: 
1.1.1.4   root     1287: static void do_mouse_hack (void)
1.1.1.3   root     1288: {
                   1289:     int spr0x = ((spr0pos & 0xff) << 2) | ((spr0ctl & 1) << 1);
                   1290:     int spr0y = ((spr0pos >> 8) | ((spr0ctl & 4) << 6)) << 1;
                   1291:     int diffx, diffy;
                   1292: 
                   1293:     if (ievent_alive > 0) {
                   1294:        mouse_x = mouse_y = 0;
                   1295:        return;
                   1296:     }
                   1297:     switch (mousestate) {
1.1.1.11! root     1298:     case normal_mouse:
1.1.1.3   root     1299:        diffx = lastmx - lastsampledmx;
                   1300:        diffy = lastmy - lastsampledmy;
                   1301:        if (!newmousecounters) {
                   1302:            if (diffx > 127) diffx = 127;
                   1303:            if (diffx < -127) diffx = -127;
                   1304:            mouse_x += diffx;
                   1305:            if (diffy > 127) diffy = 127;
                   1306:            if (diffy < -127) diffy = -127;
                   1307:            mouse_y += diffy;
                   1308:        }
                   1309:        lastsampledmx += diffx; lastsampledmy += diffy;
                   1310:        break;
                   1311: 
1.1.1.11! root     1312:     case dont_care_mouse:
1.1.1.4   root     1313:        diffx = adjust (((lastmx - lastspr0x) * mstepx) >> 16);
                   1314:        diffy = adjust (((lastmy - lastspr0y) * mstepy) >> 16);
                   1315:        lastspr0x = lastmx; lastspr0y = lastmy;
                   1316:        mouse_x += diffx; mouse_y += diffy;
1.1.1.3   root     1317:        break;
                   1318: 
1.1.1.11! root     1319:     case follow_mouse:
1.1.1.4   root     1320:        if (sprvbfl && sprvbfl-- > 1) {
1.1.1.3   root     1321:            int mousexpos, mouseypos;
                   1322: 
1.1.1.4   root     1323:            if ((lastdiffx > docal || lastdiffx < -docal)
                   1324:                && lastspr0x != spr0x
                   1325:                && spr0x > plfstrt*4 + 34 + xcaloff
                   1326:                && spr0x < plfstop*4 - xcaloff)
1.1.1.3   root     1327:            {
                   1328:                int val = (lastdiffx << 16) / (spr0x - lastspr0x);
1.1.1.4   root     1329:                if (val >= 0x8000)
                   1330:                    mstepx = (mstepx * (calweight - 1) + val) / calweight;
1.1.1.3   root     1331:            }
1.1.1.4   root     1332:            if ((lastdiffy > docal || lastdiffy < -docal)
                   1333:                && lastspr0y != spr0y
                   1334:                && spr0y > plffirstline + ycaloff
                   1335:                && spr0y < plflastline - ycaloff)
1.1.1.3   root     1336:            {
1.1.1.4   root     1337:                int val = (lastdiffy << 16) / (spr0y - lastspr0y);
                   1338:                if (val >= 0x8000)
                   1339:                    mstepy = (mstepy * (calweight - 1) + val) / calweight;
1.1.1.3   root     1340:            }
                   1341:            if (lastmy >= gfxvidinfo.height)
                   1342:                lastmy = gfxvidinfo.height-1;
1.1.1.4   root     1343:            mouseypos = coord_native_to_amiga_y (lastmy) << 1;
                   1344:            mousexpos = coord_native_to_amiga_x (lastmx);
1.1.1.3   root     1345:            diffx = adjust ((((mousexpos + xoffs - spr0x) & ~1) * mstepx) >> 16);
                   1346:            diffy = adjust ((((mouseypos + yoffs - spr0y) & ~1) * mstepy) >> 16);
1.1.1.4   root     1347:            lastspr0x = spr0x; lastspr0y = spr0y;
                   1348:            lastdiffx = diffx; lastdiffy = diffy;
                   1349:            mouse_x += diffx; mouse_y += diffy;
1.1.1.3   root     1350:        }
                   1351:        break;
1.1.1.4   root     1352:        
1.1.1.11! root     1353:     default:
1.1.1.4   root     1354:        abort ();
1.1.1.3   root     1355:     }
                   1356: }
                   1357: 
1.1.1.7   root     1358: static int timehack_alive = 0;
                   1359: 
                   1360: static uae_u32 timehack_helper (void)
                   1361: {
                   1362: #ifdef HAVE_GETTIMEOFDAY
                   1363:     struct timeval tv;
                   1364:     if (m68k_dreg (regs, 0) == 0)
                   1365:        return timehack_alive;
                   1366: 
                   1367:     timehack_alive = 10;
                   1368: 
                   1369:     gettimeofday (&tv, NULL);
                   1370:     put_long (m68k_areg (regs, 0), tv.tv_sec - (((365 * 8 + 2) * 24 - 2) * 60 * 60));
                   1371:     put_long (m68k_areg (regs, 0) + 4, tv.tv_usec);
                   1372:     return 0;
                   1373: #else
                   1374:     return 2;
                   1375: #endif
                   1376: }
                   1377: 
1.1.1.3   root     1378:  /*
1.1       root     1379:   * register functions
                   1380:   */
1.1.1.8   root     1381: STATIC_INLINE uae_u16 DENISEID (void)
1.1.1.7   root     1382: {
                   1383:     if (currprefs.chipset_mask & CSMASK_AGA)
                   1384:        return 0xF8;
                   1385:     if (currprefs.chipset_mask & CSMASK_ECS_DENISE)
                   1386:        return 0xFC;
                   1387:     return 0xFFFF;
                   1388: }
1.1.1.8   root     1389: STATIC_INLINE uae_u16 DMACONR (void)
1.1       root     1390: {
                   1391:     return (dmacon | (bltstate==BLT_done ? 0 : 0x4000)
                   1392:            | (blt_info.blitzero ? 0x2000 : 0));
                   1393: }
1.1.1.8   root     1394: STATIC_INLINE uae_u16 INTENAR (void)
1.1.1.4   root     1395: {
                   1396:     return intena;
                   1397: }
                   1398: uae_u16 INTREQR (void)
1.1       root     1399: {
1.1.1.9   root     1400:     return intreq /* | (currprefs.use_serial ? 0x0001 : 0) */;
1.1       root     1401: }
1.1.1.8   root     1402: STATIC_INLINE uae_u16 ADKCONR (void)
1.1.1.4   root     1403: {
                   1404:     return adkcon;
                   1405: }
1.1.1.8   root     1406: STATIC_INLINE uae_u16 VPOSR (void)
1.1       root     1407: {
1.1.1.7   root     1408:     unsigned int csbit = ntscmode ? 0x1000 : 0;
                   1409:     csbit |= (currprefs.chipset_mask & CSMASK_AGA) ? 0x2300 : 0;
                   1410:     csbit |= (currprefs.chipset_mask & CSMASK_ECS_AGNUS) ? 0x2000 : 0;
                   1411:     return (vpos >> 8) | lof | csbit;
1.1       root     1412: }
1.1.1.4   root     1413: static void VPOSW (uae_u16 v)
1.1.1.2   root     1414: {
                   1415:     if (lof != (v & 0x8000))
                   1416:        lof_changed = 1;
                   1417:     lof = v & 0x8000;
1.1.1.3   root     1418:     /*
                   1419:      * This register is much more fun on a real Amiga. You can program
                   1420:      * refresh rates with it ;) But I won't emulate this...
                   1421:      */
1.1.1.2   root     1422: }
1.1       root     1423: 
1.1.1.8   root     1424: STATIC_INLINE uae_u16 VHPOSR (void)
1.1.1.4   root     1425: {
                   1426:     return (vpos << 8) | current_hpos();
                   1427: }
                   1428: 
1.1.1.8   root     1429: STATIC_INLINE void COP1LCH (uae_u16 v) { cop1lc = (cop1lc & 0xffff) | ((uae_u32)v << 16); }
                   1430: STATIC_INLINE void COP1LCL (uae_u16 v) { cop1lc = (cop1lc & ~0xffff) | (v & 0xfffe); }
                   1431: STATIC_INLINE void COP2LCH (uae_u16 v) { cop2lc = (cop2lc & 0xffff) | ((uae_u32)v << 16); }
                   1432: STATIC_INLINE void COP2LCL (uae_u16 v) { cop2lc = (cop2lc & ~0xffff) | (v & 0xfffe); }
1.1.1.4   root     1433: 
1.1.1.9   root     1434: static void start_copper (void)
1.1.1.4   root     1435: {
1.1.1.10  root     1436:     int was_active = eventtab[ev_copper].active;
                   1437:     eventtab[ev_copper].active = 0;
                   1438:     if (was_active)
                   1439:        events_schedule ();
                   1440: 
1.1.1.4   root     1441:     cop_state.ignore_next = 0;
                   1442:     cop_state.state = COP_read1;
                   1443:     cop_state.vpos = vpos;
                   1444:     cop_state.hpos = current_hpos () & ~1;
1.1.1.9   root     1445: 
1.1.1.10  root     1446:     if (dmaen (DMA_COPPER)) {
                   1447:        copper_enabled_thisline = 1;
1.1.1.9   root     1448:        regs.spcflags |= SPCFLAG_COPPER;
1.1.1.10  root     1449:     }
1.1.1.9   root     1450: }
                   1451: 
                   1452: static void COPJMP1 (uae_u16 a)
                   1453: {
                   1454:     cop_state.ip = cop1lc;
                   1455:     start_copper ();
1.1.1.4   root     1456: }
                   1457: 
                   1458: static void COPJMP2 (uae_u16 a)
                   1459: {
                   1460:     cop_state.ip = cop2lc;
1.1.1.9   root     1461:     start_copper ();
1.1.1.4   root     1462: }
                   1463: 
1.1.1.8   root     1464: STATIC_INLINE void COPCON (uae_u16 a)
1.1.1.4   root     1465: {
                   1466:     copcon = a;
1.1       root     1467: }
1.1.1.4   root     1468: 
                   1469: static void DMACON (uae_u16 v)
1.1       root     1470: {
                   1471:     int i, need_resched = 0;
                   1472: 
1.1.1.3   root     1473:     uae_u16 oldcon = dmacon;
                   1474: 
1.1.1.4   root     1475:     decide_line (current_hpos ());
1.1       root     1476:     setclr(&dmacon,v); dmacon &= 0x1FFF;
1.1.1.3   root     1477:     /* ??? post_decide_line (); */
                   1478: 
                   1479:     /* FIXME? Maybe we need to think a bit more about the master DMA enable
1.1       root     1480:      * bit in these cases. */
1.1.1.10  root     1481:     if ((dmacon & DMA_COPPER) != (oldcon & DMA_COPPER)) {
                   1482:        if (eventtab[ev_copper].active)
                   1483:            need_resched = 1;
                   1484:        eventtab[ev_copper].active = 0;
                   1485:     }
1.1.1.3   root     1486:     if ((dmacon & DMA_COPPER) > (oldcon & DMA_COPPER)) {
1.1.1.4   root     1487:        cop_state.ip = cop1lc;
                   1488:        cop_state.ignore_next = 0;
                   1489:        cop_state.state = COP_read1;
                   1490:        cop_state.vpos = vpos;
                   1491:        cop_state.hpos = current_hpos () & ~1;
1.1.1.10  root     1492:        copper_enabled_thisline = 1;
1.1.1.9   root     1493:        regs.spcflags |= SPCFLAG_COPPER;
1.1       root     1494:     }
1.1.1.9   root     1495:     if (! (dmacon & DMA_COPPER)) {
1.1.1.10  root     1496:        copper_enabled_thisline = 0;
1.1.1.9   root     1497:        regs.spcflags &= ~SPCFLAG_COPPER;
                   1498:        cop_state.state = COP_stop;
                   1499:     }
                   1500: 
1.1       root     1501:     if ((dmacon & DMA_BLITPRI) > (oldcon & DMA_BLITPRI) && bltstate != BLT_done) {
                   1502:        static int count = 0;
                   1503:        if (!count) {
                   1504:            count = 1;
1.1.1.3   root     1505:            write_log ("warning: program is doing blitpri hacks.\n");
1.1       root     1506:        }
                   1507:        regs.spcflags |= SPCFLAG_BLTNASTY;
                   1508:     }
1.1.1.10  root     1509:     if ((dmacon & (DMA_BLITPRI | DMA_BLITTER | DMA_MASTER)) != (DMA_BLITPRI | DMA_BLITTER | DMA_MASTER))
1.1.1.9   root     1510:        regs.spcflags &= ~SPCFLAG_BLTNASTY;
1.1.1.4   root     1511: 
                   1512:     update_audio ();
                   1513: 
1.1       root     1514:     for (i = 0; i < 4; i++) {
                   1515:        struct audio_channel_data *cdp = audio_channel + i;
1.1.1.3   root     1516: 
1.1       root     1517:        cdp->dmaen = (dmacon & 0x200) && (dmacon & (1<<i));
                   1518:        if (cdp->dmaen) {
                   1519:            if (cdp->state == 0) {
                   1520:                cdp->state = 1;
                   1521:                cdp->pt = cdp->lc;
                   1522:                cdp->wper = cdp->per;
                   1523:                cdp->wlen = cdp->len;
                   1524:                cdp->data_written = 2;
1.1.1.4   root     1525:                cdp->evtime = eventtab[ev_hsync].evtime - cycles;
1.1       root     1526:            }
                   1527:        } else {
                   1528:            if (cdp->state == 1 || cdp->state == 5) {
                   1529:                cdp->state = 0;
1.1.1.7   root     1530:                cdp->last_sample = 0;
1.1       root     1531:                cdp->current_sample = 0;
                   1532:            }
                   1533:        }
                   1534:     }
1.1.1.4   root     1535: 
1.1       root     1536:     if (need_resched)
                   1537:        events_schedule();
                   1538: }
1.1.1.2   root     1539: 
1.1.1.3   root     1540: /*static int trace_intena = 0;*/
1.1.1.2   root     1541: 
1.1.1.8   root     1542: STATIC_INLINE void INTENA (uae_u16 v)
1.1.1.2   root     1543: {
1.1.1.3   root     1544: /*    if (trace_intena)
1.1.1.4   root     1545:        fprintf (stderr, "INTENA: %04x\n", v);*/
1.1.1.3   root     1546:     setclr(&intena,v); regs.spcflags |= SPCFLAG_INT;
1.1.1.2   root     1547: }
1.1.1.3   root     1548: void INTREQ (uae_u16 v)
1.1       root     1549: {
1.1.1.3   root     1550:     setclr(&intreq,v);
                   1551:     regs.spcflags |= SPCFLAG_INT;
1.1.1.4   root     1552:     if (( v & 0x8800) == 0x0800)
                   1553:        serdat &= 0xbfff;
1.1.1.3   root     1554: }
1.1       root     1555: 
1.1.1.3   root     1556: static void ADKCON (uae_u16 v)
                   1557: {
                   1558:     unsigned long t;
1.1.1.4   root     1559: 
                   1560:     update_audio ();
                   1561: 
1.1.1.3   root     1562:     setclr (&adkcon,v);
                   1563:     t = adkcon | (adkcon >> 4);
                   1564:     audio_channel[0].adk_mask = (((t >> 0) & 1) - 1);
                   1565:     audio_channel[1].adk_mask = (((t >> 1) & 1) - 1);
                   1566:     audio_channel[2].adk_mask = (((t >> 2) & 1) - 1);
                   1567:     audio_channel[3].adk_mask = (((t >> 3) & 1) - 1);
                   1568: }
1.1       root     1569: 
1.1.1.7   root     1570: static void BEAMCON0 (uae_u16 v)
                   1571: {
                   1572:     new_beamcon0 = v & 0x20;
                   1573: }
                   1574: 
1.1.1.4   root     1575: static void BPLPTH (int hpos, uae_u16 v, int num)
1.1.1.3   root     1576: {
1.1.1.4   root     1577:     decide_line (hpos);
                   1578:     decide_plane (hpos);
                   1579:     do_modulos (hpos);
                   1580:     bplpt[num] = (bplpt[num] & 0xffff) | ((uae_u32)v << 16);
1.1.1.3   root     1581: }
1.1.1.4   root     1582: static void BPLPTL (int hpos, uae_u16 v, int num)
1.1.1.3   root     1583: {
1.1.1.4   root     1584:     decide_line (hpos);
                   1585:     decide_plane (hpos);
                   1586:     do_modulos (hpos);
                   1587:     bplpt[num] = (bplpt[num] & ~0xffff) | (v & 0xfffe);
1.1.1.3   root     1588: }
1.1       root     1589: 
1.1.1.4   root     1590: static void BPLCON0 (int hpos, uae_u16 v)
1.1       root     1591: {
1.1.1.7   root     1592:     if (! (currprefs.chipset_mask & CSMASK_AGA)) {
                   1593:        v &= 0xFF0E;
                   1594:        /* The Sanity WOC demo needs this at one place (at the end of the "Party Effect")
                   1595:         * Disable bitplane DMA if someone tries to do more than 4 Hires bitplanes. */
                   1596:        if ((v & 0xF000) > 0xC000)
                   1597:            v &= 0xFFF;
                   1598:        /* Don't want 7 lores planes either. */
                   1599:        if ((v & 0x8000) == 0 && (v & 0x7000) == 0x7000)
                   1600:            v &= 0xEFFF;
                   1601:     }
1.1.1.2   root     1602:     if (bplcon0 == v)
1.1       root     1603:        return;
1.1.1.4   root     1604:     decide_line (hpos);
1.1.1.9   root     1605:     /* if ((bplcon0 ^ v) & 0x8000)*/
                   1606:        calcdiw ();
1.1.1.2   root     1607:     bplcon0 = v;
1.1.1.6   root     1608:     nr_planes_from_bplcon0 = GET_PLANES (v);
1.1.1.7   root     1609: 
                   1610:     if (currprefs.chipset_mask & CSMASK_AGA)
                   1611:        /* It's not clear how the copper timings are affected by the number
                   1612:         * of bitplanes on AGA machines */
                   1613:        corrected_nr_planes_from_bplcon0 = 4;
                   1614:     else
                   1615:        corrected_nr_planes_from_bplcon0 = nr_planes_from_bplcon0 << (bplcon0 & 0x8000 ? 1 : 0);
                   1616: 
1.1.1.4   root     1617:     post_decide_line (hpos);
1.1       root     1618: }
1.1.1.9   root     1619: 
1.1.1.8   root     1620: STATIC_INLINE void BPLCON1 (int hpos, uae_u16 v)
1.1       root     1621: {
1.1.1.2   root     1622:     if (bplcon1 == v)
1.1       root     1623:        return;
1.1.1.4   root     1624:     decide_diw (hpos);
1.1.1.2   root     1625:     bplcon1 = v;
1.1.1.4   root     1626:     decide_delay (hpos);
1.1       root     1627: }
1.1.1.8   root     1628: STATIC_INLINE void BPLCON2 (int hpos, uae_u16 v)
1.1       root     1629: {
1.1.1.7   root     1630:     if (bplcon2 == v)
                   1631:        return;
                   1632:     decide_line (hpos);
1.1.1.2   root     1633:     bplcon2 = v;
1.1       root     1634: }
1.1.1.8   root     1635: STATIC_INLINE void BPLCON3 (int hpos, uae_u16 v)
1.1       root     1636: {
1.1.1.7   root     1637:     if (bplcon3 == v)
                   1638:        return;
                   1639:     decide_line (hpos);
1.1.1.3   root     1640:     bplcon3 = v;
1.1       root     1641: }
1.1.1.8   root     1642: STATIC_INLINE void BPLCON4 (int hpos, uae_u16 v)
1.1       root     1643: {
1.1.1.7   root     1644:     if (! (currprefs.chipset_mask & CSMASK_AGA))
                   1645:        return;
                   1646:     if (bplcon4 == v)
                   1647:        return;
                   1648:     decide_line (hpos);
1.1.1.3   root     1649:     bplcon4 = v;
1.1       root     1650: }
                   1651: 
1.1.1.4   root     1652: static void BPL1MOD (int hpos, uae_u16 v)
1.1       root     1653: {
                   1654:     v &= ~1;
1.1.1.3   root     1655:     if ((uae_s16)bpl1mod == (uae_s16)v)
1.1       root     1656:        return;
                   1657:     bpl1mod = v;
1.1.1.4   root     1658:     decide_modulos (hpos);
1.1       root     1659: }
1.1.1.2   root     1660: 
1.1.1.4   root     1661: static void BPL2MOD (int hpos, uae_u16 v)
1.1.1.3   root     1662: {
1.1       root     1663:     v &= ~1;
1.1.1.3   root     1664:     if ((uae_s16)bpl2mod == (uae_s16)v)
1.1       root     1665:        return;
                   1666:     bpl2mod = v;
1.1.1.4   root     1667:     decide_modulos (hpos);
1.1       root     1668: }
                   1669: 
1.1.1.10  root     1670: STATIC_INLINE void BPL1DAT (uae_u16 v)
                   1671: {
                   1672:     bpl1dat = v;
                   1673:     if (thisline_decision.plfleft == -1)
                   1674:        thisline_decision.plfleft = current_hpos ();
                   1675: }
1.1.1.2   root     1676: /* We could do as well without those... */
1.1.1.8   root     1677: STATIC_INLINE void BPL2DAT (uae_u16 v) { bpl2dat = v; }
                   1678: STATIC_INLINE void BPL3DAT (uae_u16 v) { bpl3dat = v; }
                   1679: STATIC_INLINE void BPL4DAT (uae_u16 v) { bpl4dat = v; }
                   1680: STATIC_INLINE void BPL5DAT (uae_u16 v) { bpl5dat = v; }
                   1681: STATIC_INLINE void BPL6DAT (uae_u16 v) { bpl6dat = v; }
                   1682: STATIC_INLINE void BPL7DAT (uae_u16 v) { bpl7dat = v; }
                   1683: STATIC_INLINE void BPL8DAT (uae_u16 v) { bpl8dat = v; }
1.1       root     1684: 
1.1.1.4   root     1685: static void DIWSTRT (int hpos, uae_u16 v)
1.1       root     1686: {
1.1.1.4   root     1687:     if (diwstrt == v && ! diwhigh_written)
1.1       root     1688:        return;
1.1.1.4   root     1689:     decide_line (hpos);
                   1690:     diwhigh_written = 0;
1.1.1.3   root     1691:     diwstrt = v;
1.1.1.4   root     1692:     calcdiw ();
1.1       root     1693: }
1.1.1.4   root     1694: 
                   1695: static void DIWSTOP (int hpos, uae_u16 v)
1.1       root     1696: {
1.1.1.4   root     1697:     if (diwstop == v && ! diwhigh_written)
1.1       root     1698:        return;
1.1.1.4   root     1699:     decide_line (hpos);
                   1700:     diwhigh_written = 0;
1.1.1.3   root     1701:     diwstop = v;
1.1.1.4   root     1702:     calcdiw ();
                   1703: }
                   1704: 
                   1705: static void DIWHIGH (int hpos, uae_u16 v)
                   1706: {
1.1.1.7   root     1707:     if (! (currprefs.chipset_mask & CSMASK_ECS_DENISE))
                   1708:        return;
1.1.1.4   root     1709:     if (diwhigh_written && diwhigh == v)
                   1710:        return;
                   1711:     decide_line (hpos);
                   1712:     diwhigh_written = 1;
                   1713:     diwhigh = v;
                   1714:     calcdiw ();
1.1       root     1715: }
1.1.1.4   root     1716: 
                   1717: static void DDFSTRT (int hpos, uae_u16 v)
1.1.1.3   root     1718: {
1.1.1.11! root     1719:     v &= 0xFC;
1.1.1.2   root     1720:     if (ddfstrt == v)
1.1       root     1721:        return;
1.1.1.4   root     1722:     decide_line (hpos);
1.1.1.3   root     1723:     ddfstrt = v;
1.1.1.4   root     1724:     calcdiw ();
1.1       root     1725: }
1.1.1.4   root     1726: static void DDFSTOP (int hpos, uae_u16 v)
1.1.1.3   root     1727: {
1.1.1.11! root     1728:     v &= 0xFC;
1.1.1.2   root     1729:     if (ddfstop == v)
1.1       root     1730:        return;
1.1.1.4   root     1731:     decide_line (hpos);
1.1.1.2   root     1732:     ddfstop = v;
1.1.1.4   root     1733:     calcdiw ();
1.1       root     1734: }
                   1735: 
1.1.1.7   root     1736: static void FMODE (uae_u16 v)
                   1737: {
                   1738:     if (! (currprefs.chipset_mask & CSMASK_AGA))
                   1739:        return;
                   1740:     fmode = v;
                   1741:     calcdiw ();
                   1742: }
                   1743: 
1.1.1.4   root     1744: static void BLTADAT (uae_u16 v)
1.1       root     1745: {
1.1.1.2   root     1746:     maybe_blit();
                   1747: 
                   1748:     blt_info.bltadat = v;
1.1       root     1749: }
1.1.1.2   root     1750: /*
                   1751:  * "Loading data shifts it immediately" says the HRM. Well, that may
                   1752:  * be true for BLTBDAT, but not for BLTADAT - it appears the A data must be
                   1753:  * loaded for every word so that AFWM and ALWM can be applied.
                   1754:  */
1.1.1.4   root     1755: static void BLTBDAT (uae_u16 v)
1.1       root     1756: {
1.1.1.3   root     1757:     maybe_blit();
1.1.1.2   root     1758: 
                   1759:     if (bltcon1 & 2)
                   1760:        blt_info.bltbhold = v << (bltcon1 >> 12);
                   1761:     else
                   1762:        blt_info.bltbhold = v >> (bltcon1 >> 12);
                   1763:     blt_info.bltbdat = v;
1.1       root     1764: }
1.1.1.4   root     1765: static void BLTCDAT (uae_u16 v) { maybe_blit (); blt_info.bltcdat = v; }
1.1       root     1766: 
1.1.1.4   root     1767: static void BLTAMOD (uae_u16 v) { maybe_blit (); blt_info.bltamod = (uae_s16)(v & 0xFFFE); }
                   1768: static void BLTBMOD (uae_u16 v) { maybe_blit (); blt_info.bltbmod = (uae_s16)(v & 0xFFFE); }
                   1769: static void BLTCMOD (uae_u16 v) { maybe_blit (); blt_info.bltcmod = (uae_s16)(v & 0xFFFE); }
                   1770: static void BLTDMOD (uae_u16 v) { maybe_blit (); blt_info.bltdmod = (uae_s16)(v & 0xFFFE); }
1.1       root     1771: 
1.1.1.4   root     1772: static void BLTCON0 (uae_u16 v) { maybe_blit (); bltcon0 = v; blinea_shift = v >> 12; }
1.1.1.3   root     1773: /* The next category is "Most useless hardware register".
1.1       root     1774:  * And the winner is... */
1.1.1.7   root     1775: static void BLTCON0L (uae_u16 v)
                   1776: {
                   1777:     if (! (currprefs.chipset_mask & CSMASK_ECS_AGNUS))
                   1778:        return;
                   1779:     maybe_blit (); bltcon0 = (bltcon0 & 0xFF00) | (v & 0xFF);
                   1780: }
1.1.1.4   root     1781: static void BLTCON1 (uae_u16 v) { maybe_blit (); bltcon1 = v; }
                   1782: 
                   1783: static void BLTAFWM (uae_u16 v) { maybe_blit (); blt_info.bltafwm = v; }
                   1784: static void BLTALWM (uae_u16 v) { maybe_blit (); blt_info.bltalwm = v; }
1.1       root     1785: 
1.1.1.4   root     1786: static void BLTAPTH (uae_u16 v) { maybe_blit (); bltapt = (bltapt & 0xffff) | ((uae_u32)v << 16); }
                   1787: static void BLTAPTL (uae_u16 v) { maybe_blit (); bltapt = (bltapt & ~0xffff) | (v & 0xFFFE); }
                   1788: static void BLTBPTH (uae_u16 v) { maybe_blit (); bltbpt = (bltbpt & 0xffff) | ((uae_u32)v << 16); }
                   1789: static void BLTBPTL (uae_u16 v) { maybe_blit (); bltbpt = (bltbpt & ~0xffff) | (v & 0xFFFE); }
                   1790: static void BLTCPTH (uae_u16 v) { maybe_blit (); bltcpt = (bltcpt & 0xffff) | ((uae_u32)v << 16); }
                   1791: static void BLTCPTL (uae_u16 v) { maybe_blit (); bltcpt = (bltcpt & ~0xffff) | (v & 0xFFFE); }
                   1792: static void BLTDPTH (uae_u16 v) { maybe_blit (); bltdpt = (bltdpt & 0xffff) | ((uae_u32)v << 16); }
                   1793: static void BLTDPTL (uae_u16 v) { maybe_blit (); bltdpt = (bltdpt & ~0xffff) | (v & 0xFFFE); }
1.1       root     1794: 
1.1.1.4   root     1795: static void BLTSIZE (uae_u16 v)
1.1       root     1796: {
                   1797:     bltsize = v;
1.1.1.3   root     1798: 
1.1.1.4   root     1799:     maybe_blit ();
1.1       root     1800: 
                   1801:     blt_info.vblitsize = bltsize >> 6;
                   1802:     blt_info.hblitsize = bltsize & 0x3F;
                   1803:     if (!blt_info.vblitsize) blt_info.vblitsize = 1024;
                   1804:     if (!blt_info.hblitsize) blt_info.hblitsize = 64;
1.1.1.3   root     1805: 
                   1806:     bltstate = BLT_init;
1.1.1.4   root     1807:     do_blitter ();
1.1       root     1808: }
1.1.1.4   root     1809: 
                   1810: static void BLTSIZV (uae_u16 v)
1.1       root     1811: {
1.1.1.7   root     1812:     if (! (currprefs.chipset_mask & CSMASK_ECS_AGNUS))
                   1813:        return;
1.1.1.4   root     1814:     maybe_blit ();
1.1       root     1815:     oldvblts = v & 0x7FFF;
                   1816: }
1.1.1.4   root     1817: 
                   1818: static void BLTSIZH (uae_u16 v)
1.1       root     1819: {
1.1.1.7   root     1820:     if (! (currprefs.chipset_mask & CSMASK_ECS_AGNUS))
                   1821:        return;
1.1.1.4   root     1822:     maybe_blit ();
1.1       root     1823:     blt_info.hblitsize = v & 0x7FF;
                   1824:     blt_info.vblitsize = oldvblts;
                   1825:     if (!blt_info.vblitsize) blt_info.vblitsize = 32768;
                   1826:     if (!blt_info.hblitsize) blt_info.hblitsize = 0x800;
1.1.1.2   root     1827:     bltstate = BLT_init;
1.1.1.5   root     1828:     do_blitter ();
1.1       root     1829: }
1.1.1.4   root     1830: 
1.1.1.8   root     1831: STATIC_INLINE void SPRxCTL_1 (uae_u16 v, int num)
1.1       root     1832: {
1.1.1.2   root     1833:     int sprxp;
                   1834:     sprctl[num] = v;
1.1.1.10  root     1835:     nr_armed -= spr[num].armed;
                   1836:     spr[num].armed = 0;
1.1.1.3   root     1837:     if (sprpos[num] == 0 && v == 0) {
1.1.1.10  root     1838:        spr[num].state = SPR_stop;
                   1839:        spr[num].on = 0;
1.1.1.3   root     1840:     } else
1.1.1.10  root     1841:        spr[num].state = SPR_waiting_start;
1.1.1.2   root     1842: 
1.1.1.10  root     1843:     sprxp = coord_hw_to_window_x ((sprpos[num] & 0xFF) * 2 + (v & 1));
                   1844:     spr[num].xpos = sprxp;
                   1845:     spr[num].vstart = (sprpos[num] >> 8) | ((sprctl[num] << 6) & 0x100);
                   1846:     spr[num].vstop = (sprctl[num] >> 8) | ((sprctl[num] << 7) & 0x100);
1.1.1.2   root     1847: }
1.1.1.8   root     1848: STATIC_INLINE void SPRxPOS_1 (uae_u16 v, int num)
1.1.1.2   root     1849: {
                   1850:     int sprxp;
                   1851:     sprpos[num] = v;
1.1.1.10  root     1852:     sprxp = coord_hw_to_window_x ((v & 0xFF) * 2 + (sprctl[num] & 1));
                   1853:     spr[num].xpos = sprxp;
                   1854:     spr[num].vstart = (sprpos[num] >> 8) | ((sprctl[num] << 6) & 0x100);
1.1.1.2   root     1855: }
1.1.1.8   root     1856: STATIC_INLINE void SPRxDATA_1 (uae_u16 v, int num)
1.1.1.2   root     1857: {
                   1858:     sprdata[num] = v;
1.1.1.10  root     1859:     nr_armed += 1 - spr[num].armed;
                   1860:     spr[num].armed = 1;
1.1.1.2   root     1861: }
1.1.1.8   root     1862: STATIC_INLINE void SPRxDATB_1 (uae_u16 v, int num)
1.1.1.2   root     1863: {
                   1864:     sprdatb[num] = v;
                   1865: }
1.1.1.4   root     1866: static void SPRxDATA (int hpos, uae_u16 v, int num) { decide_sprites (hpos); SPRxDATA_1 (v, num); }
                   1867: static void SPRxDATB (int hpos, uae_u16 v, int num) { decide_sprites (hpos); SPRxDATB_1 (v, num); }
                   1868: static void SPRxCTL (int hpos, uae_u16 v, int num) { decide_sprites (hpos); SPRxCTL_1 (v, num); }
                   1869: static void SPRxPOS (int hpos, uae_u16 v, int num) { decide_sprites (hpos); SPRxPOS_1 (v, num); }
                   1870: static void SPRxPTH (int hpos, uae_u16 v, int num)
1.1       root     1871: {
1.1.1.4   root     1872:     decide_sprites (hpos);
1.1.1.10  root     1873:     spr[num].pt &= 0xffff;
                   1874:     spr[num].pt |= (uae_u32)v << 16;
1.1.1.3   root     1875: 
1.1.1.10  root     1876:     if (spr[num].state == SPR_stop || vpos < sprite_vblank_endline)
                   1877:        spr[num].state = SPR_restart;
                   1878:     spr[num].on = 1;
1.1       root     1879: }
1.1.1.4   root     1880: static void SPRxPTL (int hpos, uae_u16 v, int num)
1.1       root     1881: {
1.1.1.4   root     1882:     decide_sprites (hpos);
1.1.1.10  root     1883:     spr[num].pt &= ~0xffff;
                   1884:     spr[num].pt |= v;
1.1       root     1885: 
1.1.1.10  root     1886:     if (spr[num].state == SPR_stop || vpos < sprite_vblank_endline)
                   1887:        spr[num].state = SPR_restart;
                   1888:     spr[num].on = 1;
1.1.1.3   root     1889: }
1.1.1.4   root     1890: static void CLXCON (uae_u16 v)
1.1.1.3   root     1891: {
                   1892:     clxcon = v;
                   1893:     clx_sprmask = (((v >> 15) << 7) | ((v >> 14) << 5) | ((v >> 13) << 3) | ((v >> 12) << 1) | 0x55);
                   1894: }
1.1.1.4   root     1895: static uae_u16 CLXDAT (void)
1.1.1.3   root     1896: {
                   1897:     uae_u16 v = clxdat;
                   1898:     clxdat = 0;
                   1899:     return v;
                   1900: }
1.1.1.11! root     1901: 
1.1.1.4   root     1902: static void COLOR (int hpos, uae_u16 v, int num)
1.1       root     1903: {
1.1.1.3   root     1904: 
1.1       root     1905:     v &= 0xFFF;
1.1.1.11! root     1906:     if (currprefs.chipset_mask & CSMASK_AGA) {
        !          1907: 
1.1.1.4   root     1908:        int r,g,b;
                   1909:        int cr,cg,cb;
                   1910:        int colreg;
1.1.1.3   root     1911:        uae_u32 cval;
1.1.1.4   root     1912: 
1.1.1.11! root     1913:        /* writing is disabled when RDRAM=1 */
        !          1914:        if (bplcon2 & 0x0100) return;
        !          1915: 
1.1.1.2   root     1916:        colreg = ((bplcon3 >> 13) & 7) * 32 + num;
1.1       root     1917:        r = (v & 0xF00) >> 8;
                   1918:        g = (v & 0xF0) >> 4;
                   1919:        b = (v & 0xF) >> 0;
1.1.1.11! root     1920:        cr = current_colors.color_regs_aga[colreg] >> 16;
        !          1921:        cg = (current_colors.color_regs_aga[colreg] >> 8) & 0xFF;
        !          1922:        cb = current_colors.color_regs_aga[colreg] & 0xFF;
1.1       root     1923: 
1.1.1.2   root     1924:        if (bplcon3 & 0x200) {
1.1       root     1925:            cr &= 0xF0; cr |= r;
                   1926:            cg &= 0xF0; cg |= g;
                   1927:            cb &= 0xF0; cb |= b;
                   1928:        } else {
                   1929:            cr = r + (r << 4);
                   1930:            cg = g + (g << 4);
                   1931:            cb = b + (b << 4);
                   1932:        }
                   1933:        cval = (cr << 16) | (cg << 8) | cb;
1.1.1.11! root     1934:        if (cval == current_colors.color_regs_aga[colreg])
1.1       root     1935:            return;
1.1.1.5   root     1936: 
                   1937:        /* Call this with the old table still intact. */
1.1.1.11! root     1938:        record_color_change (hpos, colreg, cval);
1.1.1.5   root     1939:        remembered_color_entry = -1;
1.1.1.11! root     1940:        current_colors.color_regs_aga[colreg] = cval;
        !          1941:        current_colors.acolors[colreg] = CONVERT_RGB (cval);
        !          1942:    } else {
        !          1943:        if (current_colors.color_regs_ecs[num] == v)
1.1       root     1944:            return;
1.1.1.2   root     1945:        /* Call this with the old table still intact. */
1.1.1.4   root     1946:        record_color_change (hpos, num, v);
1.1.1.2   root     1947:        remembered_color_entry = -1;
1.1.1.11! root     1948:        current_colors.color_regs_ecs[num] = v;
1.1.1.2   root     1949:        current_colors.acolors[num] = xcolors[v];
1.1       root     1950:     }
                   1951: }
1.1.1.3   root     1952: 
                   1953: static uae_u16 potgo_value;
                   1954: 
1.1.1.4   root     1955: static void POTGO (uae_u16 v)
1.1       root     1956: {
1.1.1.3   root     1957:     potgo_value = v;
                   1958: }
                   1959: 
1.1.1.4   root     1960: static uae_u16 POTGOR (void)
1.1.1.3   root     1961: {
1.1.1.11! root     1962:     uae_u16 v = (potgo_value | (potgo_value >> 1)) & 0x5500;
        !          1963: 
        !          1964:     v |= (~potgo_value & 0xAA00) >> 1;
1.1.1.3   root     1965: 
1.1.1.6   root     1966:     if (JSEM_ISMOUSE (0, &currprefs)) {
1.1.1.3   root     1967:        if (buttonstate[2])
                   1968:            v &= 0xFBFF;
                   1969: 
                   1970:        if (buttonstate[1])
                   1971:            v &= 0xFEFF;
1.1.1.6   root     1972:     } else if (JSEM_ISJOY0 (0, &currprefs) || JSEM_ISJOY1 (0, &currprefs)) {
1.1.1.3   root     1973:        if (joy0button & 2) v &= 0xfbff;
                   1974:        if (joy0button & 4) v &= 0xfeff;
                   1975:     }
                   1976: 
1.1.1.6   root     1977:     if (JSEM_ISJOY0 (1, &currprefs) || JSEM_ISJOY1 (1, &currprefs)) {
1.1.1.3   root     1978:        if (joy1button & 2) v &= 0xbfff;
                   1979:        if (joy1button & 4) v &= 0xefff;
                   1980:     }
1.1       root     1981: 
                   1982:     return v;
                   1983: }
1.1.1.4   root     1984: 
                   1985: static uae_u16 POT0DAT (void)
1.1       root     1986: {
1.1.1.3   root     1987:     static uae_u16 cnt = 0;
1.1.1.6   root     1988:     if (JSEM_ISMOUSE (0, &currprefs)) {
1.1.1.3   root     1989:        if (buttonstate[2])
                   1990:            cnt = ((cnt + 1) & 0xFF) | (cnt & 0xFF00);
                   1991:        if (buttonstate[1])
                   1992:            cnt += 0x100;
                   1993:     }
                   1994: 
1.1       root     1995:     return cnt;
                   1996: }
1.1.1.4   root     1997: static uae_u16 JOY0DAT (void)
1.1       root     1998: {
1.1.1.6   root     1999:     if (JSEM_ISMOUSE (0, &currprefs)) {
1.1.1.4   root     2000:        do_mouse_hack ();
1.1.1.3   root     2001:        return ((uae_u8)mouse_x) + ((uae_u16)mouse_y << 8);
                   2002:     }
1.1       root     2003:     return joy0dir;
                   2004: }
1.1.1.4   root     2005: static uae_u16 JOY1DAT (void)
1.1       root     2006: {
1.1.1.6   root     2007:     if (JSEM_ISMOUSE (1, &currprefs)) {
1.1.1.4   root     2008:        do_mouse_hack ();
1.1.1.3   root     2009:        return ((uae_u8)mouse_x) + ((uae_u16)mouse_y << 8);
                   2010:     }
                   2011:     return joy1dir;
1.1       root     2012: }
1.1.1.4   root     2013: static void JOYTEST (uae_u16 v)
1.1       root     2014: {
1.1.1.6   root     2015:     if (JSEM_ISMOUSE (0, &currprefs)) {
1.1.1.3   root     2016:        mouse_x = v & 0xFC;
                   2017:        mouse_y = (v >> 8) & 0xFC;
1.1       root     2018:     }
                   2019: }
                   2020: 
1.1.1.4   root     2021: /* Determine which cycles are available for the copper in a display
                   2022:  * with a agiven number of planes.  */
                   2023: static int cycles_for_plane[9][8] = {
                   2024:     { 0, -1, 0, -1, 0, -1, 0, -1 },
                   2025:     { 0, -1, 0, -1, 0, -1, 0, -1 },
                   2026:     { 0, -1, 0, -1, 0, -1, 0, -1 },
                   2027:     { 0, -1, 0, -1, 0, -1, 0, -1 },
                   2028:     { 0, -1, 0, -1, 0, -1, 0, -1 },
1.1.1.9   root     2029:     { 0, -1, 0, -1, 0, -1, 1, -1 },
1.1.1.4   root     2030:     { 0, -1, 1, -1, 0, -1, 1, -1 },
                   2031:     { 1, -1, 1, -1, 1, -1, 1, -1 },
                   2032:     { 1, -1, 1, -1, 1, -1, 1, -1 }
                   2033: };
1.1.1.2   root     2034: 
1.1.1.4   root     2035: static unsigned int waitmasktab[256];
1.1.1.2   root     2036: 
1.1.1.8   root     2037: STATIC_INLINE int copper_in_playfield (enum diw_states diw, int hpos)
1.1.1.3   root     2038: {
1.1.1.4   root     2039:     return diw == DIW_waiting_stop && hpos >= plfstrt && hpos < plfstrt + plflinelen;
1.1       root     2040: }
                   2041: 
1.1.1.8   root     2042: STATIC_INLINE int copper_cant_read (enum diw_states diw, int hpos, int planes)
1.1       root     2043: {
1.1.1.4   root     2044:     int t;
1.1.1.2   root     2045: 
1.1.1.9   root     2046:     /* @@@ */
1.1.1.4   root     2047:     if (hpos >= ((maxhpos - 2) & ~1))
1.1.1.2   root     2048:        return 1;
1.1.1.3   root     2049: 
1.1.1.7   root     2050:     if (currprefs.chipset_mask & CSMASK_AGA)
                   2051:        /* FIXME */
                   2052:        return 0;
                   2053: 
1.1.1.4   root     2054:     if (! copper_in_playfield (diw, hpos))
                   2055:        return 0;
1.1.1.3   root     2056: 
1.1.1.4   root     2057:     t = cycles_for_plane[planes][hpos & 7];
                   2058: #if 0
                   2059:     if (t == -1)
                   2060:        abort ();
                   2061: #endif
                   2062:     return t;
1.1.1.2   root     2063: }
                   2064: 
1.1.1.10  root     2065: STATIC_INLINE int dangerous_reg (int reg)
                   2066: {
                   2067:     /* Safe:
                   2068:      * Bitplane pointers, control registers, modulos and data.
                   2069:      * Sprite pointers, control registers, and data.
                   2070:      * Color registers.  */
                   2071:     if (reg >= 0xE0 && reg < 0x1C0)
                   2072:        return 0;
                   2073:     return 1;
                   2074: }
                   2075: 
1.1.1.9   root     2076: static void update_copper (int until_hpos)
1.1.1.2   root     2077: {
1.1.1.10  root     2078:     int vp = vpos & (((cop_state.i2 >> 8) & 0x7F) | 0x80);
1.1.1.4   root     2079:     int c_hpos = cop_state.hpos;
1.1.1.2   root     2080: 
1.1.1.10  root     2081:     if (eventtab[ev_copper].active)
                   2082:        abort ();
                   2083: 
                   2084:     if (cop_state.state == COP_wait && vp < cop_state.vcmp)
                   2085:        abort ();
                   2086: 
                   2087:     until_hpos &= ~1;
                   2088: 
                   2089:     if (until_hpos > (maxhpos & ~1))
                   2090:        until_hpos = maxhpos & ~1;
1.1.1.3   root     2091: 
1.1.1.4   root     2092:     for (;;) {
1.1.1.10  root     2093:        int old_hpos = c_hpos;
                   2094:        int hp;
                   2095: 
                   2096:        if (c_hpos > until_hpos)
1.1.1.3   root     2097:            break;
                   2098: 
1.1.1.9   root     2099:        /* So we know about the vertical DIW.  */
                   2100:        decide_line (c_hpos);
1.1.1.3   root     2101: 
1.1.1.10  root     2102:        c_hpos += 2;
                   2103:        if (copper_cant_read (diwstate, old_hpos, corrected_nr_planes_from_bplcon0))
                   2104:            continue;
1.1.1.3   root     2105: 
1.1.1.10  root     2106:        switch (cop_state.state) {
1.1.1.9   root     2107:        case COP_read1:
                   2108:            cop_state.i1 = chipmem_bank.wget (cop_state.ip);
                   2109:            cop_state.ip += 2;
                   2110:            cop_state.state = COP_read2;
                   2111:            break;
                   2112: 
                   2113:        case COP_read2:
                   2114:            cop_state.i2 = chipmem_bank.wget (cop_state.ip);
                   2115:            cop_state.ip += 2;
1.1.1.10  root     2116:            cop_state.state = COP_read1;
1.1.1.9   root     2117:            if (cop_state.ignore_next) {
                   2118:                cop_state.ignore_next = 0;
                   2119:                break;
                   2120:            }
                   2121:            /* Perform moves immediately.  */
                   2122:            if ((cop_state.i1 & 1) == 0) {
1.1.1.11! root     2123:                unsigned int address = cop_state.i1 & 0x1FE;
        !          2124:                if (address < (copcon & 2 ? ((currprefs.chipset_mask & CSMASK_AGA) ? 0 : 0x40u) : 0x80u)) {
1.1.1.10  root     2125:                    cop_state.state = COP_stop; 
                   2126:                    copper_enabled_thisline = 0;
                   2127:                    regs.spcflags &= ~SPCFLAG_COPPER;
                   2128:                    goto out;
1.1.1.4   root     2129:                }
1.1.1.11! root     2130:                if (address == 0x88)
1.1.1.4   root     2131:                    cop_state.ip = cop1lc;
1.1.1.11! root     2132:                else if (address == 0x8A)
1.1.1.4   root     2133:                    cop_state.ip = cop2lc;
1.1.1.10  root     2134:                else
1.1.1.11! root     2135:                    custom_wput_1 (old_hpos, address, cop_state.i2);
1.1.1.10  root     2136:                /* That could have turned off the copper...  */
                   2137:                if (! copper_enabled_thisline)
                   2138:                    goto out;
1.1.1.9   root     2139:                break;
1.1.1.3   root     2140:            }
1.1.1.2   root     2141: 
1.1.1.9   root     2142:            vp = vpos & (((cop_state.i2 >> 8) & 0x7F) | 0x80);
1.1.1.10  root     2143:            hp = c_hpos & (cop_state.i2 & 0xFE);
                   2144:            cop_state.vcmp = (cop_state.i1 & (cop_state.i2 | 0x8000)) >> 8;
1.1.1.9   root     2145:            cop_state.hcmp = (cop_state.i1 & cop_state.i2 & 0xFE);
                   2146: 
                   2147:            if ((cop_state.i2 & 1) == 1) {
                   2148:                /* Skip instruction.  */
                   2149:                if ((vp > cop_state.vcmp || (vp == cop_state.vcmp && hp >= cop_state.hcmp))
                   2150:                    && ((cop_state.i2 & 0x8000) != 0 || ! (DMACONR() & 0x4000)))
                   2151:                    cop_state.ignore_next = 1;
1.1.1.2   root     2152:                break;
1.1.1.4   root     2153:            }
1.1.1.9   root     2154:            cop_state.state = COP_wait;
                   2155:            if (cop_state.i1 == 0xFFFF && cop_state.i2 == 0xFFFE) {
                   2156:                cop_state.state = COP_stop;
1.1.1.10  root     2157:                copper_enabled_thisline = 0;
                   2158:                regs.spcflags &= ~SPCFLAG_COPPER;
                   2159:                goto out;
1.1.1.2   root     2160:            }
1.1.1.9   root     2161:            if (vp < cop_state.vcmp) {
1.1.1.10  root     2162:                copper_enabled_thisline = 0;
1.1.1.9   root     2163:                regs.spcflags &= ~SPCFLAG_COPPER;
1.1.1.10  root     2164:                goto out;
1.1.1.2   root     2165:            }
1.1.1.10  root     2166:            if (vp > cop_state.vcmp)
1.1.1.9   root     2167:                break;
                   2168: 
1.1.1.10  root     2169:            /* Only enable shortcuts if there's no masking going on.  */
                   2170:            if (0 && (cop_state.i2 & 0xFE) == 0xFE) {
                   2171:                int time_remaining = until_hpos - c_hpos;
                   2172: 
                   2173:                /* Compute minimum number of cycles to wait.  */
                   2174:                cop_min_waittime = cop_state.hcmp - hp - 4;
                   2175:                if (cop_min_waittime <= 2 || time_remaining <= 0)
                   2176:                    break;
                   2177:                if (cop_min_waittime < time_remaining) {
                   2178:                    c_hpos += cop_min_waittime;
                   2179:                    break;
                   2180:                }
                   2181:                c_hpos += time_remaining;
                   2182:                cop_min_waittime -= time_remaining;
                   2183:                if (cop_min_waittime >= 8) {
                   2184:                    regs.spcflags &= ~SPCFLAG_COPPER;
                   2185:                    eventtab[ev_copper].active = 1;
                   2186:                    eventtab[ev_copper].oldcycles = cycles;
                   2187:                    eventtab[ev_copper].evtime = cycles + cop_min_waittime;
                   2188:                    events_schedule ();
                   2189:                    goto out;
                   2190:                }
                   2191:            }
                   2192:            break;
                   2193: 
                   2194:        case COP_wait:
                   2195:            if (vp < cop_state.vcmp)
                   2196:                abort ();
                   2197: 
                   2198:            hp = c_hpos & (cop_state.i2 & 0xFE);
1.1.1.9   root     2199:            if (vp == cop_state.vcmp && hp < cop_state.hcmp)
1.1.1.4   root     2200:                break;
1.1.1.10  root     2201: 
                   2202:            /* Now we know that the comparisons were successful.  We might still
                   2203:               have to wait for the blitter though.  */
                   2204:            if ((cop_state.i2 & 0x8000) == 0 && (DMACONR() & 0x4000)) {
1.1.1.9   root     2205:                /* We need to wait for the blitter.  */
1.1.1.4   root     2206:                cop_state.state = COP_bltwait;
1.1.1.10  root     2207:                copper_enabled_thisline = 0;
1.1.1.9   root     2208:                regs.spcflags &= ~SPCFLAG_COPPER;
1.1.1.10  root     2209:                goto out;
1.1.1.2   root     2210:            }
1.1.1.10  root     2211: 
                   2212:            cop_state.state = COP_read1;
1.1.1.4   root     2213:            break;
1.1.1.2   root     2214: 
1.1.1.4   root     2215:         default:
1.1.1.10  root     2216:            abort ();
1.1       root     2217:        }
1.1.1.4   root     2218:     }
1.1.1.10  root     2219: 
                   2220:   out:
1.1.1.4   root     2221:     cop_state.hpos = c_hpos;
1.1.1.10  root     2222: #if 0
                   2223:     /* The future, Conan?  */
                   2224:     if (cop_state.state == COP_read1 || cop_state.state == COP_read2) {
                   2225:        int ip = cop_state.ip;
                   2226:        int word = cop_state.i1;
                   2227: 
                   2228:        if (eventtab[ev_copper].active /* || ! (regs.spcflags & SPCFLAG_COPPER) */)
                   2229:            abort ();
                   2230: 
                   2231:        if (cop_state.state == COP_read2) {
                   2232:            ip += 2;
                   2233:            c_hpos += 2;
                   2234:            goto inner;
                   2235:        }
                   2236:        while (c_hpos < (maxhpos & ~1)) {
                   2237:            word = chipmem_bank.wget (ip);
                   2238:            ip += 4;
                   2239:            c_hpos += 4;
                   2240:          inner:
                   2241:            if ((word & 1) || dangerous_reg (word))
                   2242:                break;
                   2243:        }
                   2244:        cop_min_waittime = c_hpos - cop_state.hpos;
                   2245:        if (cop_min_waittime >= 8) {
                   2246:            regs.spcflags &= ~SPCFLAG_COPPER;
                   2247:            eventtab[ev_copper].active = 1;
                   2248:            eventtab[ev_copper].oldcycles = cycles;
                   2249:            eventtab[ev_copper].evtime = cycles + cop_min_waittime;
                   2250:            events_schedule ();
                   2251:        }
                   2252:     }
                   2253: #endif
1.1       root     2254: }
                   2255: 
1.1.1.9   root     2256: static void compute_spcflag_copper (void)
1.1       root     2257: {
1.1.1.10  root     2258:     copper_enabled_thisline = 0;
1.1.1.9   root     2259:     regs.spcflags &= ~SPCFLAG_COPPER;
1.1.1.10  root     2260:     if (! dmaen (DMA_COPPER) || cop_state.state == COP_stop || cop_state.state == COP_bltwait)
                   2261:        return;
                   2262: 
                   2263:     if (cop_state.state == COP_wait) {
                   2264:        int vp = vpos & (((cop_state.i2 >> 8) & 0x7F) | 0x80);
                   2265: 
                   2266:        if (vp < cop_state.vcmp)
                   2267:            return;
                   2268:        copper_enabled_thisline = 1;
                   2269: 
                   2270:        if (0 && vp == cop_state.vcmp) {
                   2271:            int hp = (cop_state.hpos + 2) & (cop_state.i2 & 0xFE);
                   2272:            cop_min_waittime = cop_state.hcmp - hp - 4;
                   2273: 
                   2274:            /* If possible, compute a minimum waiting time, and set the event
                   2275:               timer if it's sufficiently large to be worthwhile.  */
                   2276:            if ((cop_state.i2 & 0xFE) == 0xFE && cop_min_waittime >= 8) {
                   2277:                eventtab[ev_copper].active = 1;
                   2278:                eventtab[ev_copper].oldcycles = cycles;
                   2279:                eventtab[ev_copper].evtime = cycles + cop_min_waittime;
                   2280:                events_schedule ();
                   2281:                return;
                   2282:            }
                   2283:        }
                   2284:     }
                   2285: 
                   2286:     copper_enabled_thisline = 1;
                   2287:     regs.spcflags |= SPCFLAG_COPPER;
                   2288: }
                   2289: 
                   2290: static void copper_handler (void)
                   2291: {
                   2292:     /* This will take effect immediately, within the same cycle.  */
                   2293:     regs.spcflags |= SPCFLAG_COPPER;
                   2294: 
                   2295:     if (! copper_enabled_thisline)
                   2296:        abort ();
                   2297: 
                   2298:     if (cop_state.state == COP_wait) {
                   2299:        cop_state.hpos += cop_min_waittime;
                   2300:        if (cop_state.hpos > current_hpos ())
                   2301:            abort ();
                   2302:     }
                   2303: 
                   2304:     eventtab[ev_copper].active = 0;
1.1.1.3   root     2305: }
1.1.1.2   root     2306: 
1.1.1.4   root     2307: void blitter_done_notify (void)
1.1       root     2308: {
1.1.1.4   root     2309:     if (cop_state.state != COP_bltwait)
                   2310:        return;
1.1.1.10  root     2311: 
                   2312:     copper_enabled_thisline = 1;
1.1.1.9   root     2313:     regs.spcflags |= SPCFLAG_COPPER;
                   2314:     cop_state.state = COP_wait;
1.1.1.2   root     2315: }
                   2316: 
1.1.1.9   root     2317: void do_copper (void)
1.1.1.2   root     2318: {
1.1.1.4   root     2319:     int hpos = current_hpos ();
                   2320:     update_copper (hpos);
1.1.1.2   root     2321: }
                   2322: 
1.1.1.4   root     2323: static void do_sprites (int currvp, int currhp)
                   2324: {
                   2325:     int i;
                   2326:     int maxspr;
1.1.1.2   root     2327: 
1.1.1.4   root     2328: #if 0
                   2329:     if (currvp == 0)
                   2330:        return;
                   2331: #else
                   2332:     /* I don't know whether this is right. Some programs write the sprite pointers
                   2333:      * directly at the start of the copper list. With the currvp==0 check, the
                   2334:      * first two words of data are read on the second line in the frame. The problem
                   2335:      * occurs when the program jumps to another copperlist a few lines further down
                   2336:      * which _also_ writes the sprite pointer registers. This means that a) writing
                   2337:      * to the sprite pointers sets the state to SPR_restart; or b) that sprite DMA
                   2338:      * is disabled until the end of the vertical blanking interval. The HRM
                   2339:      * isn't clear - it says that the vertical sprite position can be set to any
                   2340:      * value, but this wouldn't be the first mistake... */
                   2341:     /* Update: I modified one of the programs to write the sprite pointers the
                   2342:      * second time only _after_ the VBlank interval, and it showed the same behaviour
                   2343:      * as it did unmodified under UAE with the above check. This indicates that the
                   2344:      * solution below is correct. */
1.1.1.9   root     2345:     /* Another update: seems like we have to use the NTSC value here (see Sanity Turmoil
                   2346:      * demo).  */
1.1.1.10  root     2347:     /* Maximum for Sanity Turmoil: 27.
                   2348:        Minimum for Sanity Arte: 22.  */
                   2349:     if (currvp < sprite_vblank_endline)
1.1.1.4   root     2350:        return;
1.1.1.2   root     2351: #endif
1.1.1.3   root     2352: 
1.1.1.4   root     2353:     /* The graph in the HRM, p. 195 seems to indicate that sprite 0 is
                   2354:      * fetched at cycle 0x14 and thus can't be disabled by bitplane DMA. */
                   2355:     maxspr = currhp/4 - 0x14/4;
                   2356:     if (maxspr < 0)
                   2357:        return;
                   2358:     if (maxspr > 8)
                   2359:        maxspr = 8;
1.1.1.2   root     2360: 
1.1.1.4   root     2361:     for (i = 0; i < maxspr; i++) {
                   2362:        int fetch = 0;
1.1.1.2   root     2363: 
1.1.1.10  root     2364:        if (spr[i].on == 0)
1.1.1.4   root     2365:            continue;
1.1.1.2   root     2366: 
1.1.1.10  root     2367:        if (spr[i].state == SPR_restart) {
1.1.1.4   root     2368:            fetch = 2;
1.1.1.10  root     2369:            spr[i].on = 1;
                   2370:        } else if ((spr[i].state == SPR_waiting_start && spr[i].vstart == vpos) || spr[i].state == SPR_waiting_stop) {
1.1.1.4   root     2371:            fetch = 1;
1.1.1.10  root     2372:            spr[i].state = SPR_waiting_stop;
1.1.1.2   root     2373:        }
1.1.1.10  root     2374:        if ((spr[i].state == SPR_waiting_stop || spr[i].state == SPR_waiting_start) && spr[i].vstop == vpos) {
1.1.1.4   root     2375:            fetch = 2;
1.1.1.10  root     2376:            spr[i].state = SPR_waiting_start;
1.1.1.2   root     2377:        }
1.1.1.3   root     2378: 
1.1.1.9   root     2379:        if (fetch && dmaen (DMA_SPRITE)) {
1.1.1.10  root     2380:            uae_u16 data1 = chipmem_bank.wget (spr[i].pt);
                   2381:            uae_u16 data2 = chipmem_bank.wget (spr[i].pt + 2);
                   2382:            spr[i].pt += 4;
1.1.1.3   root     2383: 
1.1.1.4   root     2384:            if (fetch == 1) {
                   2385:                /* Hack for X mouse auto-calibration */
                   2386:                if (i == 0 && !sprvbfl && ((sprpos[0] & 0xff) << 2) > 2 * DISPLAY_LEFT_SHIFT) {
1.1.1.9   root     2387:                    spr0ctl = sprctl[0];
                   2388:                    spr0pos = sprpos[0];
                   2389:                    sprvbfl = 2;
1.1.1.3   root     2390:                }
1.1.1.9   root     2391:                SPRxDATB_1 (data2, i);
                   2392:                SPRxDATA_1 (data1, i);
1.1.1.4   root     2393:            } else {
1.1.1.9   root     2394:                SPRxPOS_1 (data1, i);
                   2395:                SPRxCTL_1 (data2, i);
1.1.1.3   root     2396:            }
1.1       root     2397:        }
                   2398:     }
                   2399: }
                   2400: 
1.1.1.4   root     2401: static void init_sprites (void)
1.1       root     2402: {
1.1.1.4   root     2403:     int i;
1.1.1.2   root     2404: 
1.1.1.4   root     2405:     for (i = 0; i < 8; i++) {
                   2406:        /* ???? */
1.1.1.10  root     2407:        spr[i].state = SPR_stop;
                   2408:        spr[i].on = 0;
1.1.1.4   root     2409:     }
1.1.1.2   root     2410: 
1.1.1.4   root     2411:     memset (sprpos, 0, sizeof sprpos);
                   2412:     memset (sprctl, 0, sizeof sprctl);
                   2413: }
1.1.1.2   root     2414: 
1.1.1.3   root     2415: static void adjust_array_sizes (void)
1.1.1.2   root     2416: {
                   2417: #ifdef OS_WITHOUT_MEMORY_MANAGEMENT
1.1.1.3   root     2418:     if (delta_sprite_draw) {
                   2419:        void *p1,*p2;
                   2420:        int mcc = max_sprite_draw + 200 + delta_sprite_draw;
                   2421:        delta_sprite_draw = 0;
                   2422:        p1 = realloc (sprite_positions[0], mcc * sizeof (struct sprite_draw));
                   2423:        p2 = realloc (sprite_positions[1], mcc * sizeof (struct sprite_draw));
                   2424:        if (p1) sprite_positions[0] = p1;
                   2425:        if (p2) sprite_positions[1] = p2;
                   2426:        if (p1 && p2) {
                   2427:            fprintf (stderr, "new max_sprite_draw=%d\n",mcc);
1.1.1.2   root     2428:            max_sprite_draw = mcc;
                   2429:        }
                   2430:     }
1.1.1.3   root     2431:     if (delta_color_change) {
                   2432:        void *p1,*p2;
                   2433:        int mcc = max_color_change + 200 + delta_color_change;
                   2434:        delta_color_change = 0;
                   2435:        p1 = realloc (color_changes[0], mcc * sizeof (struct color_change));
                   2436:        p2 = realloc (color_changes[1], mcc * sizeof (struct color_change));
                   2437:        if (p1) color_changes[0] = p1;
                   2438:        if (p2) color_changes[1] = p2;
                   2439:        if (p1 && p2) {
                   2440:            fprintf (stderr, "new max_color_change=%d\n",mcc);
1.1.1.2   root     2441:            max_color_change = mcc;
1.1.1.3   root     2442:        }
                   2443:     }
                   2444:     if (delta_delay_change) {
                   2445:        void *p;
                   2446:        int mcc = max_delay_change + 200 + delta_delay_change;
                   2447:        delta_delay_change = 0;
                   2448:        p = realloc (delay_changes, mcc * sizeof (struct delay_change));
                   2449:        if (p) {
                   2450:            fprintf (stderr, "new max_delay_change=%d\n",mcc);
                   2451:            delay_changes = p;
                   2452:            max_delay_change = mcc;
                   2453:        }
1.1.1.2   root     2454:     }
                   2455: #endif
1.1.1.3   root     2456: }
                   2457: 
1.1.1.4   root     2458: static void init_hardware_frame (void)
1.1.1.3   root     2459: {
1.1.1.4   root     2460:     next_lineno = 0;
                   2461:     nextline_how = nln_normal;
                   2462:     diwstate = DIW_waiting_start;
                   2463:     hdiwstate = DIW_waiting_start;
                   2464: }
1.1.1.2   root     2465: 
1.1.1.4   root     2466: void init_hardware_for_drawing_frame (void)
                   2467: {
1.1.1.3   root     2468:     adjust_array_sizes ();
                   2469: 
1.1.1.2   root     2470:     next_color_change = 0;
                   2471:     next_delay_change = 0;
                   2472:     next_sprite_draw = 0;
1.1.1.3   root     2473: 
1.1.1.2   root     2474:     next_color_entry = 0;
                   2475:     remembered_color_entry = -1;
                   2476:     prev_sprite_positions = sprite_positions[current_change_set];
                   2477:     curr_sprite_positions = sprite_positions[current_change_set ^ 1];
                   2478:     prev_color_changes = color_changes[current_change_set];
                   2479:     curr_color_changes = color_changes[current_change_set ^ 1];
                   2480:     prev_color_tables = color_tables[current_change_set];
                   2481:     curr_color_tables = color_tables[current_change_set ^ 1];
1.1.1.3   root     2482: 
1.1.1.2   root     2483:     prev_drawinfo = line_drawinfo[current_change_set];
1.1.1.4   root     2484:     curr_drawinfo = line_drawinfo[current_change_set ^ 1];
                   2485:     current_change_set ^= 1;
1.1.1.3   root     2486: 
1.1.1.4   root     2487:     color_src_match = color_dest_match = -1;
1.1.1.3   root     2488: }
                   2489: 
1.1.1.2   root     2490: static void vsync_handler (void)
1.1       root     2491: {
1.1.1.4   root     2492:     if (currprefs.m68k_speed == -1) {
                   2493:        frame_time_t curr_time = read_processor_time ();
1.1.1.3   root     2494:        vsyncmintime += vsynctime;
                   2495:        /* @@@ Mathias? How do you think we should do this? */
                   2496:        /* If we are too far behind, or we just did a reset, adjust the
                   2497:         * needed time. */
1.1.1.4   root     2498:        if ((long int)(curr_time - vsyncmintime) > 0 || rpt_did_reset)
1.1.1.3   root     2499:            vsyncmintime = curr_time + vsynctime;
1.1.1.4   root     2500:        rpt_did_reset = 0;
1.1.1.3   root     2501:     }
1.1.1.4   root     2502: 
1.1.1.3   root     2503:     handle_events ();
1.1       root     2504: 
1.1.1.3   root     2505:     getjoystate (0, &joy0dir, &joy0button);
                   2506:     getjoystate (1, &joy1dir, &joy1button);
1.1       root     2507: 
1.1.1.4   root     2508:     INTREQ (0x8020);
1.1.1.3   root     2509:     if (bplcon0 & 4)
1.1.1.2   root     2510:        lof ^= 0x8000;
1.1.1.3   root     2511: 
1.1.1.4   root     2512:     vsync_handle_redraw (lof, lof_changed);
                   2513:     if (quit_program > 0)
1.1.1.3   root     2514:        return;
                   2515: 
1.1.1.4   root     2516:     {
1.1.1.3   root     2517:        static int cnt = 0;
                   2518:        if (cnt == 0) {
                   2519:            /* resolution_check_change (); */
                   2520:            DISK_check_change ();
                   2521:            cnt = 5;
                   2522:        }
                   2523:        cnt--;
1.1.1.2   root     2524:     }
1.1.1.3   root     2525: 
1.1.1.7   root     2526:     /* For now, let's only allow this to change at vsync time.  It gets too
                   2527:      * hairy otherwise.  */
                   2528:     if (beamcon0 != new_beamcon0)
                   2529:        init_hz ();
                   2530: 
1.1.1.2   root     2531:     lof_changed = 0;
1.1.1.3   root     2532: 
1.1.1.4   root     2533:     cop_state.ip = cop1lc;
                   2534:     cop_state.state = COP_read1;
                   2535:     cop_state.vpos = 0;
                   2536:     cop_state.hpos = 0;
                   2537:     cop_state.ignore_next = 0;
                   2538: 
                   2539:     init_hardware_frame ();
                   2540: 
1.1       root     2541: #ifdef HAVE_GETTIMEOFDAY
                   2542:     {
                   2543:        struct timeval tv;
                   2544:        unsigned long int newtime;
1.1.1.3   root     2545: 
1.1.1.9   root     2546:        gettimeofday (&tv,NULL);
1.1       root     2547:        newtime = (tv.tv_sec-seconds_base) * 1000 + tv.tv_usec / 1000;
1.1.1.3   root     2548: 
                   2549:        if (!bogusframe) {
1.1.1.6   root     2550:            lastframetime = newtime - msecs;
                   2551: 
                   2552: #if 0 /* This doesn't appear to work too well yet... later.  */
                   2553:            if (n_consecutive_skipped > currprefs.sound_pri_cutoff
                   2554:                || lastframetime < currprefs.sound_pri_time)
                   2555:            {
                   2556:                n_consecutive_skipped = 0;
                   2557:                clear_inhibit_frame (IHF_SOUNDADJUST);
                   2558:            } else {
                   2559:                n_consecutive_skipped++;
                   2560:                set_inhibit_frame (IHF_SOUNDADJUST);
                   2561:                total_skipped++;
                   2562:            }
                   2563: #endif
                   2564: 
                   2565:            frametime += lastframetime;
1.1       root     2566:            timeframes++;
1.1.1.6   root     2567: 
                   2568:            if ((timeframes & 127) == 0)
                   2569:                gui_fps (1000 * timeframes / frametime);
1.1       root     2570:        }
                   2571:        msecs = newtime;
                   2572:        bogusframe = 0;
                   2573:     }
                   2574: #endif
1.1.1.3   root     2575:     if (ievent_alive > 0)
                   2576:        ievent_alive--;
1.1.1.7   root     2577:     if (timehack_alive > 0)
                   2578:        timehack_alive--;
1.1       root     2579:     CIA_vsync_handler();
                   2580: }
                   2581: 
1.1.1.4   root     2582: static void hsync_handler (void)
1.1       root     2583: {
1.1.1.10  root     2584:     int copper_was_active = eventtab[ev_copper].active;
                   2585:     if (copper_was_active) {
                   2586:        /* Could happen if horizontal wait position is too large.  */
                   2587:        eventtab[ev_copper].active = 0;
                   2588:        if (cop_state.state != COP_wait)
                   2589:            copper_was_active = 0;
                   2590:     }
                   2591:     if (copper_enabled_thisline && ! copper_was_active)
                   2592:        update_copper (maxhpos);
                   2593: 
1.1.1.2   root     2594:     finish_decisions ();
1.1.1.4   root     2595:     do_modulos (current_hpos ());
1.1.1.2   root     2596: 
1.1.1.5   root     2597:     hsync_record_line_state (next_lineno, nextline_how, thisline_changed);
1.1       root     2598: 
                   2599:     eventtab[ev_hsync].evtime += cycles - eventtab[ev_hsync].oldcycles;
                   2600:     eventtab[ev_hsync].oldcycles = cycles;
1.1.1.8   root     2601:     CIA_hsync_handler ();
1.1.1.11! root     2602:     DISK_update ();
1.1.1.3   root     2603: 
                   2604:     if (currprefs.produce_sound > 0) {
1.1       root     2605:        int nr;
1.1.1.4   root     2606: 
                   2607:        update_audio ();
                   2608: 
1.1       root     2609:        /* Sound data is fetched at the beginning of each line */
                   2610:        for (nr = 0; nr < 4; nr++) {
                   2611:            struct audio_channel_data *cdp = audio_channel + nr;
1.1.1.3   root     2612: 
1.1       root     2613:            if (cdp->data_written == 2) {
                   2614:                cdp->data_written = 0;
                   2615:                cdp->nextdat = chipmem_bank.wget(cdp->pt);
                   2616:                cdp->pt += 2;
                   2617:                if (cdp->state == 2 || cdp->state == 3) {
                   2618:                    if (cdp->wlen == 1) {
                   2619:                        cdp->pt = cdp->lc;
                   2620:                        cdp->wlen = cdp->len;
                   2621:                        cdp->intreq2 = 1;
                   2622:                    } else
                   2623:                        cdp->wlen--;
                   2624:                }
                   2625:            }
                   2626:        }
                   2627:     }
1.1.1.4   root     2628: 
                   2629:     hardware_line_completed (next_lineno);
                   2630: 
1.1       root     2631:     if (++vpos == (maxvpos + (lof != 0))) {
                   2632:        vpos = 0;
                   2633:        vsync_handler();
                   2634:     }
1.1.1.2   root     2635: 
1.1.1.4   root     2636:     is_lastline = vpos + 1 == maxvpos + (lof != 0) && currprefs.m68k_speed == -1 && ! rpt_did_reset;
1.1.1.3   root     2637: 
1.1.1.4   root     2638:     if ((bplcon0 & 4) && currprefs.gfx_linedbl)
                   2639:        notice_interlace_seen ();
1.1.1.2   root     2640: 
                   2641:     if (framecnt == 0) {
1.1.1.4   root     2642:        int lineno = vpos;
                   2643:        nextline_how = nln_normal;
1.1.1.3   root     2644:        if (currprefs.gfx_linedbl) {
1.1       root     2645:            lineno *= 2;
1.1.1.5   root     2646:            nextline_how = currprefs.gfx_linedbl == 1 ? nln_doubled : nln_nblack;
1.1.1.2   root     2647:            if (bplcon0 & 4) {
                   2648:                if (!lof) {
                   2649:                    lineno++;
1.1.1.4   root     2650:                    nextline_how = nln_lower;
1.1.1.2   root     2651:                } else {
1.1.1.4   root     2652:                    nextline_how = nln_upper;
1.1.1.2   root     2653:                }
1.1       root     2654:            }
                   2655:        }
                   2656:        next_lineno = lineno;
1.1.1.2   root     2657:        reset_decisions ();
1.1       root     2658:     }
1.1.1.3   root     2659:     if (uae_int_requested) {
                   2660:        set_uae_int_flag ();
                   2661:        INTREQ (0xA000);
                   2662:     }
1.1.1.9   root     2663:     /* See if there's a chance of a copper wait ending this line.  */
                   2664:     cop_state.hpos = 0;
                   2665:     compute_spcflag_copper ();
1.1.1.3   root     2666: }
                   2667: 
                   2668: static void init_eventtab (void)
                   2669: {
                   2670:     int i;
                   2671: 
                   2672:     for(i = 0; i < ev_max; i++) {
                   2673:        eventtab[i].active = 0;
                   2674:        eventtab[i].oldcycles = 0;
                   2675:     }
1.1.1.4   root     2676: 
1.1.1.3   root     2677:     eventtab[ev_cia].handler = CIA_handler;
                   2678:     eventtab[ev_hsync].handler = hsync_handler;
                   2679:     eventtab[ev_hsync].evtime = maxhpos + cycles;
                   2680:     eventtab[ev_hsync].active = 1;
                   2681: 
1.1.1.10  root     2682:     eventtab[ev_copper].handler = copper_handler;
                   2683:     eventtab[ev_copper].active = 0;
1.1.1.3   root     2684:     eventtab[ev_blitter].handler = blitter_handler;
                   2685:     eventtab[ev_blitter].active = 0;
1.1.1.11! root     2686:     eventtab[ev_disk].handler = DISK_handler;
        !          2687:     eventtab[ev_disk].active = 0;
1.1.1.4   root     2688: 
1.1.1.3   root     2689:     events_schedule ();
1.1       root     2690: }
                   2691: 
1.1.1.3   root     2692: void customreset (void)
1.1       root     2693: {
1.1.1.4   root     2694:     int i;
1.1.1.11! root     2695:     int zero = 0;
1.1       root     2696: #ifdef HAVE_GETTIMEOFDAY
                   2697:     struct timeval tv;
                   2698: #endif
1.1.1.2   root     2699: 
1.1.1.11! root     2700:     if (currprefs.chipset_mask & CSMASK_AGA) {
        !          2701:        for (i = 0; i < 32; i++) {
        !          2702:            current_colors.color_regs_ecs[i] = 0;
        !          2703:            current_colors.acolors[i] = xcolors[0];
        !          2704:        }
        !          2705:     } else {
        !          2706:         for (i = 0; i < 256; i++) {
        !          2707:            current_colors.color_regs_aga[i] = 0;
        !          2708:            current_colors.acolors[i] = CONVERT_RGB (zero);
        !          2709:        }
1.1.1.9   root     2710:     }
1.1.1.3   root     2711: 
                   2712:     expamem_reset ();
1.1.1.4   root     2713: 
1.1.1.3   root     2714:     CIA_reset ();
                   2715:     cycles = 0;
1.1       root     2716:     regs.spcflags &= SPCFLAG_BRK;
1.1.1.3   root     2717: 
1.1.1.2   root     2718:     vpos = 0;
1.1       root     2719:     lof = 0;
1.1.1.3   root     2720: 
1.1.1.4   root     2721:     if (needmousehack ()) {
1.1.1.3   root     2722: #if 0
1.1.1.4   root     2723:        mousehack_setfollow();
1.1.1.3   root     2724: #else
1.1.1.4   root     2725:        mousehack_setdontcare();
1.1.1.3   root     2726: #endif
1.1       root     2727:     } else {
                   2728:        mousestate = normal_mouse;
                   2729:     }
1.1.1.3   root     2730:     ievent_alive = 0;
1.1.1.7   root     2731:     timehack_alive = 0;
1.1.1.3   root     2732: 
                   2733:     clx_sprmask = 0xFF;
                   2734:     clxdat = 0;
                   2735: 
1.1.1.10  root     2736:     /* Clear the armed flags of all sprites.  */
                   2737:     memset (spr, 0, sizeof spr);
1.1.1.3   root     2738:     nr_armed = 0;
1.1       root     2739: 
                   2740:     dmacon = intena = 0;
                   2741:     bltstate = BLT_done;
1.1.1.4   root     2742:     cop_state.state = COP_stop;
1.1.1.2   root     2743:     diwstate = DIW_waiting_start;
1.1.1.3   root     2744:     hdiwstate = DIW_waiting_start;
1.1       root     2745:     copcon = 0;
1.1.1.11! root     2746:     DSKLEN (0, 0);
1.1       root     2747:     cycles = 0;
1.1.1.3   root     2748: 
1.1.1.2   root     2749:     bplcon4 = 0x11; /* Get AGA chipset into ECS compatibility mode */
                   2750:     bplcon3 = 0xC00;
1.1       root     2751: 
1.1.1.7   root     2752:     new_beamcon0 = ntscmode ? 0x00 : 0x20;
                   2753:     init_hz ();
                   2754: 
                   2755:     audio_reset ();
                   2756: 
1.1.1.3   root     2757:     init_eventtab ();
1.1.1.2   root     2758: 
1.1.1.3   root     2759:     init_sprites ();
                   2760: 
1.1.1.2   root     2761:     init_hardware_frame ();
1.1.1.4   root     2762:     reset_drawing ();
                   2763: 
1.1.1.2   root     2764:     reset_decisions ();
1.1.1.3   root     2765: 
1.1       root     2766: #ifdef HAVE_GETTIMEOFDAY
1.1.1.4   root     2767:     gettimeofday (&tv, NULL);
1.1       root     2768:     seconds_base = tv.tv_sec;
                   2769:     bogusframe = 1;
                   2770: #endif
                   2771: }
                   2772: 
1.1.1.3   root     2773: void dumpcustom (void)
1.1       root     2774: {
1.1.1.6   root     2775:     write_log ("DMACON: %x INTENA: %x INTREQ: %x VPOS: %x HPOS: %x\n", DMACONR(),
                   2776:               (unsigned int)intena, (unsigned int)intreq, (unsigned int)vpos, (unsigned int)current_hpos());
                   2777:     write_log ("COP1LC: %08lx, COP2LC: %08lx\n", (unsigned long)cop1lc, (unsigned long)cop2lc);
1.1.1.3   root     2778:     if (timeframes) {
1.1.1.6   root     2779:        write_log ("Average frame time: %d ms [frames: %d time: %d]\n",
                   2780:                   frametime / timeframes, timeframes, frametime);
                   2781:        if (total_skipped)
                   2782:            write_log ("Skipped frames: %d\n", total_skipped);
1.1       root     2783:     }
1.1.1.3   root     2784:     dump_audio_bench ();
1.1.1.4   root     2785:     /*for (i=0; i<256; i++) if (blitcount[i]) fprintf (stderr, "minterm %x = %d\n",i,blitcount[i]);  blitter debug */
1.1       root     2786: }
                   2787: 
1.1.1.3   root     2788: int intlev (void)
1.1       root     2789: {
1.1.1.3   root     2790:     uae_u16 imask = intreq & intena;
1.1       root     2791:     if (imask && (intena & 0x4000)){
                   2792:        if (imask & 0x2000) return 6;
                   2793:        if (imask & 0x1800) return 5;
                   2794:        if (imask & 0x0780) return 4;
                   2795:        if (imask & 0x0070) return 3;
                   2796:        if (imask & 0x0008) return 2;
                   2797:        if (imask & 0x0007) return 1;
                   2798:     }
                   2799:     return -1;
                   2800: }
                   2801: 
1.1.1.4   root     2802: static void gen_custom_tables (void)
                   2803: {
                   2804:     int i;
                   2805:     for (i = 0; i < 256; i++) {
                   2806:        unsigned int j;
                   2807:        sprtaba[i] = ((((i >> 7) & 1) << 0)
                   2808:                      | (((i >> 6) & 1) << 2)
                   2809:                      | (((i >> 5) & 1) << 4)
                   2810:                      | (((i >> 4) & 1) << 6)
                   2811:                      | (((i >> 3) & 1) << 8)
                   2812:                      | (((i >> 2) & 1) << 10)
                   2813:                      | (((i >> 1) & 1) << 12)
                   2814:                      | (((i >> 0) & 1) << 14));
                   2815:        sprtabb[i] = sprtaba[i] * 2;
                   2816:        for (j = 0; j < 511; j = (j << 1) | 1)
                   2817:            if ((i & ~j) == 0)
                   2818:                waitmasktab[i] = ~j;
                   2819:     }
                   2820: }
                   2821: 
1.1.1.3   root     2822: void custom_init (void)
1.1       root     2823: {
1.1.1.7   root     2824:     uaecptr pos;
                   2825: 
1.1.1.4   root     2826: #ifdef OS_WITHOUT_MEMORY_MANAGEMENT
1.1       root     2827:     int num;
1.1.1.2   root     2828: 
1.1.1.4   root     2829:     for (num = 0; num < 2; num++) {
                   2830:        sprite_positions[num] = xmalloc (max_sprite_draw * sizeof (struct sprite_draw));
                   2831:        color_changes[num] = xmalloc (max_color_change * sizeof (struct color_change));
1.1.1.2   root     2832:     }
1.1.1.4   root     2833:     delay_changes = xmalloc (max_delay_change * sizeof (struct delay_change));
1.1.1.2   root     2834: #endif
1.1.1.3   root     2835: 
1.1.1.7   root     2836:     pos = here ();
                   2837: 
                   2838:     org (0xF0FF70);
                   2839:     calltrap (deftrap (mousehack_helper));
                   2840:     dw (RTS);
                   2841: 
                   2842:     org (0xF0FFA0);
                   2843:     calltrap (deftrap (timehack_helper));
                   2844:     dw (RTS);
                   2845: 
                   2846:     org (pos);
                   2847: 
1.1.1.2   root     2848:     init_decisions ();
                   2849: 
1.1.1.4   root     2850:     gen_custom_tables ();
                   2851:     build_blitfilltable ();
                   2852: 
                   2853:     drawing_init ();
                   2854: 
                   2855:     mousestate = unknown_mouse;
                   2856: 
                   2857:     if (needmousehack ())
                   2858:        mousehack_setfollow();
1.1       root     2859: }
                   2860: 
                   2861: /* Custom chip memory bank */
                   2862: 
1.1.1.4   root     2863: static uae_u32 custom_lget (uaecptr) REGPARAM;
                   2864: static uae_u32 custom_wget (uaecptr) REGPARAM;
                   2865: static uae_u32 custom_bget (uaecptr) REGPARAM;
                   2866: static void custom_lput (uaecptr, uae_u32) REGPARAM;
                   2867: static void custom_wput (uaecptr, uae_u32) REGPARAM;
                   2868: static void custom_bput (uaecptr, uae_u32) REGPARAM;
1.1       root     2869: 
                   2870: addrbank custom_bank = {
                   2871:     custom_lget, custom_wget, custom_bget,
                   2872:     custom_lput, custom_wput, custom_bput,
                   2873:     default_xlate, default_check
                   2874: };
                   2875: 
1.1.1.3   root     2876: uae_u32 REGPARAM2 custom_wget (uaecptr addr)
1.1       root     2877: {
1.1.1.4   root     2878:     switch (addr & 0x1FE) {
1.1       root     2879:      case 0x002: return DMACONR();
                   2880:      case 0x004: return VPOSR();
                   2881:      case 0x006: return VHPOSR();
1.1.1.3   root     2882: 
1.1.1.11! root     2883:      case 0x008: return DSKDATR(current_hpos());
1.1       root     2884: 
                   2885:      case 0x00A: return JOY0DAT();
                   2886:      case 0x00C: return JOY1DAT();
1.1.1.3   root     2887:      case 0x00E: return CLXDAT();
1.1       root     2888:      case 0x010: return ADKCONR();
                   2889: 
                   2890:      case 0x012: return POT0DAT();
                   2891:      case 0x016: return POTGOR();
                   2892:      case 0x018: return SERDATR();
1.1.1.11! root     2893:      case 0x01A: return DSKBYTR(current_hpos());
1.1       root     2894:      case 0x01C: return INTENAR();
                   2895:      case 0x01E: return INTREQR();
1.1.1.7   root     2896:      case 0x07C: return DENISEID();
1.1       root     2897:      default:
                   2898:        custom_wput(addr,0);
                   2899:        return 0xffff;
                   2900:     }
                   2901: }
                   2902: 
1.1.1.3   root     2903: uae_u32 REGPARAM2 custom_bget (uaecptr addr)
1.1       root     2904: {
                   2905:     return custom_wget(addr & 0xfffe) >> (addr & 1 ? 0 : 8);
                   2906: }
                   2907: 
1.1.1.3   root     2908: uae_u32 REGPARAM2 custom_lget (uaecptr addr)
1.1       root     2909: {
1.1.1.3   root     2910:     return ((uae_u32)custom_wget(addr & 0xfffe) << 16) | custom_wget((addr+2) & 0xfffe);
1.1       root     2911: }
                   2912: 
1.1.1.4   root     2913: void REGPARAM2 custom_wput_1 (int hpos, uaecptr addr, uae_u32 value)
1.1       root     2914: {
                   2915:     addr &= 0x1FE;
1.1.1.3   root     2916:     switch (addr) {
                   2917:      case 0x020: DSKPTH (value); break;
                   2918:      case 0x022: DSKPTL (value); break;
1.1.1.11! root     2919:      case 0x024: DSKLEN (value, current_hpos()); break;
1.1.1.3   root     2920:      case 0x026: DSKDAT (value); break;
                   2921: 
                   2922:      case 0x02A: VPOSW (value); break;
                   2923:      case 0x2E:  COPCON (value); break;
                   2924:      case 0x030: SERDAT (value); break;
                   2925:      case 0x032: SERPER (value); break;
                   2926:      case 0x34: POTGO (value); break;
                   2927:      case 0x040: BLTCON0 (value); break;
                   2928:      case 0x042: BLTCON1 (value); break;
                   2929: 
                   2930:      case 0x044: BLTAFWM (value); break;
                   2931:      case 0x046: BLTALWM (value); break;
                   2932: 
                   2933:      case 0x050: BLTAPTH (value); break;
                   2934:      case 0x052: BLTAPTL (value); break;
                   2935:      case 0x04C: BLTBPTH (value); break;
                   2936:      case 0x04E: BLTBPTL (value); break;
                   2937:      case 0x048: BLTCPTH (value); break;
                   2938:      case 0x04A: BLTCPTL (value); break;
                   2939:      case 0x054: BLTDPTH (value); break;
                   2940:      case 0x056: BLTDPTL (value); break;
                   2941: 
                   2942:      case 0x058: BLTSIZE (value); break;
                   2943: 
                   2944:      case 0x064: BLTAMOD (value); break;
                   2945:      case 0x062: BLTBMOD (value); break;
                   2946:      case 0x060: BLTCMOD (value); break;
                   2947:      case 0x066: BLTDMOD (value); break;
                   2948: 
                   2949:      case 0x070: BLTCDAT (value); break;
                   2950:      case 0x072: BLTBDAT (value); break;
                   2951:      case 0x074: BLTADAT (value); break;
                   2952: 
                   2953:      case 0x07E: DSKSYNC (value); break;
                   2954: 
                   2955:      case 0x080: COP1LCH (value); break;
                   2956:      case 0x082: COP1LCL (value); break;
                   2957:      case 0x084: COP2LCH (value); break;
                   2958:      case 0x086: COP2LCL (value); break;
                   2959: 
                   2960:      case 0x088: COPJMP1 (value); break;
                   2961:      case 0x08A: COPJMP2 (value); break;
                   2962: 
1.1.1.4   root     2963:      case 0x08E: DIWSTRT (hpos, value); break;
                   2964:      case 0x090: DIWSTOP (hpos, value); break;
                   2965:      case 0x092: DDFSTRT (hpos, value); break;
                   2966:      case 0x094: DDFSTOP (hpos, value); break;
1.1.1.3   root     2967: 
                   2968:      case 0x096: DMACON (value); break;
                   2969:      case 0x098: CLXCON (value); break;
                   2970:      case 0x09A: INTENA (value); break;
                   2971:      case 0x09C: INTREQ (value); break;
                   2972:      case 0x09E: ADKCON (value); break;
                   2973: 
                   2974:      case 0x0A0: AUDxLCH (0, value); break;
                   2975:      case 0x0A2: AUDxLCL (0, value); break;
                   2976:      case 0x0A4: AUDxLEN (0, value); break;
                   2977:      case 0x0A6: AUDxPER (0, value); break;
                   2978:      case 0x0A8: AUDxVOL (0, value); break;
                   2979:      case 0x0AA: AUDxDAT (0, value); break;
                   2980: 
                   2981:      case 0x0B0: AUDxLCH (1, value); break;
                   2982:      case 0x0B2: AUDxLCL (1, value); break;
                   2983:      case 0x0B4: AUDxLEN (1, value); break;
                   2984:      case 0x0B6: AUDxPER (1, value); break;
                   2985:      case 0x0B8: AUDxVOL (1, value); break;
                   2986:      case 0x0BA: AUDxDAT (1, value); break;
                   2987: 
                   2988:      case 0x0C0: AUDxLCH (2, value); break;
                   2989:      case 0x0C2: AUDxLCL (2, value); break;
                   2990:      case 0x0C4: AUDxLEN (2, value); break;
                   2991:      case 0x0C6: AUDxPER (2, value); break;
                   2992:      case 0x0C8: AUDxVOL (2, value); break;
                   2993:      case 0x0CA: AUDxDAT (2, value); break;
                   2994: 
                   2995:      case 0x0D0: AUDxLCH (3, value); break;
                   2996:      case 0x0D2: AUDxLCL (3, value); break;
                   2997:      case 0x0D4: AUDxLEN (3, value); break;
                   2998:      case 0x0D6: AUDxPER (3, value); break;
                   2999:      case 0x0D8: AUDxVOL (3, value); break;
                   3000:      case 0x0DA: AUDxDAT (3, value); break;
                   3001: 
1.1.1.4   root     3002:      case 0x0E0: BPLPTH (hpos, value, 0); break;
                   3003:      case 0x0E2: BPLPTL (hpos, value, 0); break;
                   3004:      case 0x0E4: BPLPTH (hpos, value, 1); break;
                   3005:      case 0x0E6: BPLPTL (hpos, value, 1); break;
                   3006:      case 0x0E8: BPLPTH (hpos, value, 2); break;
                   3007:      case 0x0EA: BPLPTL (hpos, value, 2); break;
                   3008:      case 0x0EC: BPLPTH (hpos, value, 3); break;
                   3009:      case 0x0EE: BPLPTL (hpos, value, 3); break;
                   3010:      case 0x0F0: BPLPTH (hpos, value, 4); break;
                   3011:      case 0x0F2: BPLPTL (hpos, value, 4); break;
                   3012:      case 0x0F4: BPLPTH (hpos, value, 5); break;
                   3013:      case 0x0F6: BPLPTL (hpos, value, 5); break;
1.1.1.6   root     3014:      case 0x0F8: BPLPTH (hpos, value, 6); break;
                   3015:      case 0x0FA: BPLPTL (hpos, value, 6); break;
                   3016:      case 0x0FC: BPLPTH (hpos, value, 7); break;
                   3017:      case 0x0FE: BPLPTL (hpos, value, 7); break;
1.1.1.4   root     3018: 
                   3019:      case 0x100: BPLCON0 (hpos, value); break;
                   3020:      case 0x102: BPLCON1 (hpos, value); break;
                   3021:      case 0x104: BPLCON2 (hpos, value); break;
                   3022:      case 0x106: BPLCON3 (hpos, value); break;
1.1.1.3   root     3023: 
1.1.1.4   root     3024:      case 0x108: BPL1MOD (hpos, value); break;
                   3025:      case 0x10A: BPL2MOD (hpos, value); break;
1.1.1.3   root     3026: 
                   3027:      case 0x110: BPL1DAT (value); break;
                   3028:      case 0x112: BPL2DAT (value); break;
                   3029:      case 0x114: BPL3DAT (value); break;
                   3030:      case 0x116: BPL4DAT (value); break;
                   3031:      case 0x118: BPL5DAT (value); break;
                   3032:      case 0x11A: BPL6DAT (value); break;
1.1.1.6   root     3033:      case 0x11C: BPL7DAT (value); break;
                   3034:      case 0x11E: BPL8DAT (value); break;
1.1       root     3035: 
                   3036:      case 0x180: case 0x182: case 0x184: case 0x186: case 0x188: case 0x18A:
                   3037:      case 0x18C: case 0x18E: case 0x190: case 0x192: case 0x194: case 0x196:
                   3038:      case 0x198: case 0x19A: case 0x19C: case 0x19E: case 0x1A0: case 0x1A2:
                   3039:      case 0x1A4: case 0x1A6: case 0x1A8: case 0x1AA: case 0x1AC: case 0x1AE:
                   3040:      case 0x1B0: case 0x1B2: case 0x1B4: case 0x1B6: case 0x1B8: case 0x1BA:
1.1.1.2   root     3041:      case 0x1BC: case 0x1BE:
1.1.1.4   root     3042:        COLOR (hpos, value & 0xFFF, (addr & 0x3E) / 2);
1.1.1.2   root     3043:        break;
                   3044:      case 0x120: case 0x124: case 0x128: case 0x12C:
1.1       root     3045:      case 0x130: case 0x134: case 0x138: case 0x13C:
1.1.1.4   root     3046:        SPRxPTH (hpos, value, (addr - 0x120) / 4);
1.1       root     3047:        break;
1.1.1.2   root     3048:      case 0x122: case 0x126: case 0x12A: case 0x12E:
1.1       root     3049:      case 0x132: case 0x136: case 0x13A: case 0x13E:
1.1.1.4   root     3050:        SPRxPTL (hpos, value, (addr - 0x122) / 4);
1.1       root     3051:        break;
1.1.1.2   root     3052:      case 0x140: case 0x148: case 0x150: case 0x158:
1.1       root     3053:      case 0x160: case 0x168: case 0x170: case 0x178:
1.1.1.4   root     3054:        SPRxPOS (hpos, value, (addr - 0x140) / 8);
1.1       root     3055:        break;
1.1.1.2   root     3056:      case 0x142: case 0x14A: case 0x152: case 0x15A:
1.1       root     3057:      case 0x162: case 0x16A: case 0x172: case 0x17A:
1.1.1.4   root     3058:        SPRxCTL (hpos, value, (addr - 0x142) / 8);
1.1       root     3059:        break;
                   3060:      case 0x144: case 0x14C: case 0x154: case 0x15C:
                   3061:      case 0x164: case 0x16C: case 0x174: case 0x17C:
1.1.1.4   root     3062:        SPRxDATA (hpos, value, (addr - 0x144) / 8);
1.1       root     3063:        break;
1.1.1.2   root     3064:      case 0x146: case 0x14E: case 0x156: case 0x15E:
1.1       root     3065:      case 0x166: case 0x16E: case 0x176: case 0x17E:
1.1.1.4   root     3066:        SPRxDATB (hpos, value, (addr - 0x146) / 8);
1.1       root     3067:        break;
1.1.1.3   root     3068: 
                   3069:      case 0x36: JOYTEST (value); break;
1.1.1.7   root     3070:      case 0x5A: BLTCON0L (value); break;
1.1.1.3   root     3071:      case 0x5C: BLTSIZV (value); break;
                   3072:      case 0x5E: BLTSIZH (value); break;
1.1.1.4   root     3073:      case 0x1E4: DIWHIGH (hpos, value); break;
                   3074:      case 0x10C: BPLCON4 (hpos, value); break;
1.1.1.7   root     3075:      case 0x1FC: FMODE (value); break;
1.1       root     3076:     }
                   3077: }
                   3078: 
1.1.1.4   root     3079: void REGPARAM2 custom_wput (uaecptr addr, uae_u32 value)
                   3080: {
                   3081:     int hpos = current_hpos ();
1.1.1.10  root     3082:     /* Need to let the copper advance to the current position, but only if it
                   3083:        isn't in a waiting state.  */
                   3084:     if (copper_enabled_thisline && ! eventtab[ev_copper].active)
                   3085:        update_copper (hpos);
1.1.1.4   root     3086:     custom_wput_1 (hpos, addr, value);
                   3087: }
                   3088: 
                   3089: void REGPARAM2 custom_bput (uaecptr addr, uae_u32 value)
1.1       root     3090: {
1.1.1.2   root     3091:     static int warned = 0;
                   3092:     /* Is this correct now? (There are people who bput things to the upper byte of AUDxVOL). */
1.1.1.3   root     3093:     uae_u16 rval = (value << 8) | (value & 0xFF);
1.1.1.9   root     3094:     custom_wput (addr, rval);
1.1.1.2   root     3095:     if (!warned)
1.1.1.3   root     3096:        write_log ("Byte put to custom register.\n"), warned++;
1.1       root     3097: }
                   3098: 
1.1.1.3   root     3099: void REGPARAM2 custom_lput(uaecptr addr, uae_u32 value)
1.1       root     3100: {
1.1.1.9   root     3101:     custom_wput (addr & 0xfffe, value >> 16);
                   3102:     custom_wput ((addr + 2) & 0xfffe, (uae_u16)value);
1.1       root     3103: }

unix.superglobalmegacorp.com

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