--- uae/src/custom.c 2018/04/24 16:47:31 1.1.1.7 +++ uae/src/custom.c 2018/04/24 16:54:59 1.1.1.12 @@ -64,8 +64,6 @@ static int next_lineno; static enum nln_how nextline_how; static int lof_changed = 0; -static const int dskdelay = 2; /* FIXME: ??? */ - static uae_u32 sprtaba[256],sprtabb[256]; /* @@ -97,22 +95,30 @@ static int ntscmode = 0; /* This is but an educated guess. It seems to be correct, but this stuff * isn't documented well. */ enum sprstate { SPR_stop, SPR_restart, SPR_waiting_start, SPR_waiting_stop }; -static enum sprstate sprst[8]; -static int spron[8]; -static uaecptr sprpt[8]; -static int sprxpos[8], sprvstart[8], sprvstop[8]; + +struct sprite { + uaecptr pt; + int on; + int xpos; + int vstart; + int vstop; + int armed; + enum sprstate state; +}; + +static struct sprite spr[8]; + +static int sprite_vblank_endline = VBLANK_ENDLINE_NTSC + 2; static unsigned int sprdata[MAX_SPRITES], sprdatb[MAX_SPRITES], sprctl[MAX_SPRITES], sprpos[MAX_SPRITES]; -static int sprarmed[MAX_SPRITES], sprite_last_drawn_at[MAX_SPRITES]; +static int sprite_last_drawn_at[MAX_SPRITES]; static int last_sprite_point, nr_armed; static uae_u32 bpl1dat, bpl2dat, bpl3dat, bpl4dat, bpl5dat, bpl6dat, bpl7dat, bpl8dat; static uae_s16 bpl1mod, bpl2mod; static uaecptr bplpt[8]; -#ifndef SMART_UPDATE -static char *real_bplpt[8]; -#endif +uae_u8 *real_bplpt[8]; /*static int blitcount[256]; blitter debug */ @@ -123,10 +129,6 @@ static unsigned int diwstrt, diwstop, di static int diwhigh_written; static unsigned int ddfstrt, ddfstop; -static uae_u32 dskpt; -static uae_u16 dsklen, dsksync; -static int dsklength; - /* The display and data fetch windows */ enum diw_states @@ -135,6 +137,7 @@ enum diw_states }; static int plffirstline, plflastline, plfstrt, plfstop, plflinelen; +static int last_diw_pix_hpos, last_ddf_pix_hpos; int diwfirstword, diwlastword; static enum diw_states diwstate, hdiwstate; @@ -144,9 +147,9 @@ int clx_sprmask; enum copper_states { COP_stop, - COP_rdelay1, COP_read1, COP_read2, + COP_read1, COP_read2, COP_bltwait, - COP_wait1, COP_wait1b, COP_wait2, + COP_wait }; struct copper { @@ -155,17 +158,14 @@ struct copper { enum copper_states state; /* Instruction pointer. */ uaecptr ip; - int hpos, vpos, count; + int hpos, vpos; unsigned int ignore_next; - unsigned int do_move; - enum diw_states vdiw; + int vcmp, hcmp; }; static struct copper cop_state; - -static void prepare_copper_1 (void); - -int dskdmaen; /* used in cia.c */ +static int copper_enabled_thisline; +static int cop_min_waittime; /* * Statistics @@ -175,7 +175,7 @@ int dskdmaen; /* used in cia.c */ unsigned long int msecs = 0, frametime = 0, lastframetime = 0, timeframes = 0; static unsigned long int seconds_base; int bogusframe; - +int n_frames; static int current_change_set; @@ -253,17 +253,6 @@ void reset_frame_rate_hack (void) write_log ("Resetting frame rate hack\n"); } -static __inline__ void prepare_copper (void) -{ - if (cop_state.vpos > vpos - || cop_state.state == COP_stop) - { - eventtab[ev_copper].active = 0; - return; - } - prepare_copper_1 (); -} - void check_prefs_changed_custom (void) { currprefs.gfx_framerate = changed_prefs.gfx_framerate; @@ -279,7 +268,7 @@ void check_prefs_changed_custom (void) } -static __inline__ void setclr (uae_u16 *p, uae_u16 val) +STATIC_INLINE void setclr (uae_u16 *p, uae_u16 val) { if (val & 0x8000) *p |= val & 0x7FFF; @@ -292,7 +281,7 @@ __inline__ int current_hpos (void) return cycles - eventtab[ev_hsync].oldcycles; } -static __inline__ uae_u8 *pfield_xlateptr (uaecptr plpt, int bytecount) +STATIC_INLINE uae_u8 *pfield_xlateptr (uaecptr plpt, int bytecount) { if (!chipmem_bank.check (plpt, bytecount)) { static int count = 0; @@ -303,17 +292,25 @@ static __inline__ uae_u8 *pfield_xlatept return chipmem_bank.xlateaddr (plpt); } -static __inline__ void docols (struct color_entry *colentry) +STATIC_INLINE void docols (struct color_entry *colentry) { -#if AGA_CHIPSET == 0 int i; - for (i = 0; i < 32; i++) { - int v = colentry->color_regs[i]; - if (v < 0 || v > 4095) - continue; - colentry->acolors[i] = xcolors[v]; + + if (currprefs.chipset_mask & CSMASK_AGA) { + for (i = 0; i < 256; i++) { + int v = color_reg_get (colentry, i); + if(v < 0 || v > 16777215) + continue; + colentry->acolors[i] = CONVERT_RGB (v); + } + } else { + for (i = 0; i < 32; i++) { + int v = color_reg_get (colentry, i); + if (v < 0 || v > 4095) + continue; + colentry->acolors[i] = xcolors[v]; + } } -#endif } void notice_new_xcolors (void) @@ -335,7 +332,7 @@ static void remember_ctable (void) if (remembered_color_entry == -1) { /* The colors changed since we last recorded a color map. Record a * new one. */ - memcpy (curr_color_tables + next_color_entry, ¤t_colors, sizeof current_colors); + color_reg_cpy (curr_color_tables + next_color_entry, ¤t_colors); remembered_color_entry = next_color_entry++; } thisline_decision.ctable = remembered_color_entry; @@ -350,9 +347,7 @@ static void remember_ctable (void) changed = 1; color_src_match = color_dest_match = -1; } else { - color_compare_result = memcmp (&prev_color_tables[oldctable].color_regs, - ¤t_colors.color_regs, - sizeof current_colors.color_regs) != 0; + color_compare_result = color_reg_cmp (&prev_color_tables[oldctable], ¤t_colors) != 0; if (color_compare_result) changed = 1; color_src_match = oldctable; @@ -376,8 +371,9 @@ static void remember_ctable_for_border ( * checked. */ static void decide_diw (int hpos) { + int pix_hpos = PIXEL_XPOS (hpos); if (hdiwstate == DIW_waiting_start && thisline_decision.diwfirstword == -1 - && PIXEL_XPOS (hpos) >= diwfirstword) + && pix_hpos >= diwfirstword && last_diw_pix_hpos < diwfirstword) { thisline_decision.diwfirstword = diwfirstword; hdiwstate = DIW_waiting_stop; @@ -389,18 +385,19 @@ static void decide_diw (int hpos) thisline_decision.diwlastword = -1; } if (hdiwstate == DIW_waiting_stop && thisline_decision.diwlastword == -1 - && PIXEL_XPOS (hpos) >= diwlastword) + && pix_hpos >= diwlastword && last_diw_pix_hpos < diwlastword) { thisline_decision.diwlastword = diwlastword; hdiwstate = DIW_waiting_start; if (thisline_decision.diwlastword != line_decisions[next_lineno].diwlastword) MARK_LINE_CHANGED; } + last_diw_pix_hpos = pix_hpos; } /* Called when we know that the line is not in the border and we want to draw * it. The data fetch starting position and length are passed as parameters. */ -static __inline__ void decide_as_playfield (int startpos, int len) +STATIC_INLINE void decide_as_playfield (int startpos, int len) { thisline_decision.which = 1; @@ -415,18 +412,16 @@ static __inline__ void decide_as_playfie /* These are for comparison. */ thisline_decision.bplcon0 = bplcon0; thisline_decision.bplcon2 = bplcon2; -#if AGA_CHIPSET == 1 thisline_decision.bplcon4 = bplcon4; -#endif + thisline_decision.fmode = fmode; #ifdef SMART_UPDATE if (line_decisions[next_lineno].plfstrt != thisline_decision.plfstrt || line_decisions[next_lineno].plflinelen != thisline_decision.plflinelen || line_decisions[next_lineno].bplcon0 != thisline_decision.bplcon0 || line_decisions[next_lineno].bplcon2 != thisline_decision.bplcon2 -#if AGA_CHIPSET == 1 || line_decisions[next_lineno].bplcon4 != thisline_decision.bplcon4 -#endif + || line_decisions[next_lineno].fmode != thisline_decision.fmode ) #endif /* SMART_UPDATE */ thisline_changed = 1; @@ -464,6 +459,10 @@ static void adjust_broken_program (int h { int tmp1, tmp2; int i; + + /* Magic again... :-/ */ + hpos += 4; + if (decided_res == RES_HIRES) { tmp1 = hpos & 3; tmp2 = hpos & ~3; @@ -501,7 +500,7 @@ static void adjust_broken_program (int h } } -static __inline__ void set_decided_res (void) +STATIC_INLINE void set_decided_res (void) { decided_res = RES_LORES; if (bplcon0 & 0x8000) @@ -510,7 +509,7 @@ static __inline__ void set_decided_res ( decided_res = RES_SUPERHIRES; } -static __inline__ void post_decide_line (int hpos) +STATIC_INLINE void post_decide_line (int hpos) { if (thisline_decision.which == 1 && hpos < thisline_decision.plfstrt + thisline_decision.plflinelen @@ -545,7 +544,7 @@ static __inline__ void post_decide_line MARK_LINE_CHANGED; /* Play safe. */ return; } - + if (thisline_decision.which != -1) return; @@ -625,7 +624,7 @@ static void decide_line_1 (int hpos) /* Main entry point for deciding how to draw a line. May either do * nothing, decide the line as border, or decide the line as playfield. */ -static __inline__ void decide_line (int hpos) +STATIC_INLINE void decide_line (int hpos) { if (thisline_decision.which == 0 && hpos >= plfstrt) decide_line_1 (hpos); @@ -669,7 +668,7 @@ static void record_color_change (int hpo /* If the border is changed the first time before the DIW, record the * original starting border value. */ if (regno == 0 && thisline_decision.color0 == 0xFFFFFFFFul && thisline_decision.diwfirstword < 0) { - thisline_decision.color0 = current_colors.color_regs[0]; + thisline_decision.color0 = color_reg_get (¤t_colors, 0); if (line_decisions[next_lineno].color0 != value) thisline_changed = 1; } @@ -751,9 +750,9 @@ static void decide_plane (int hpos) uae_u8 *dataptr = line_data[next_lineno]; for (i = 0; i < decided_nr_planes; i++, dataptr += MAX_WORDS_PER_LINE*2) { uaecptr pt = bplpt[i]; - uae_u8 *real_ptr = pfield_xlateptr(pt, bytecount); + uae_u8 *real_ptr = pfield_xlateptr (pt, bytecount); if (real_ptr == NULL) - real_ptr = pfield_xlateptr(0, 0); + real_ptr = pfield_xlateptr (0, 0); #ifdef SMART_UPDATE #if 1 if (thisline_changed) @@ -796,7 +795,8 @@ static void decide_modulos (int hpos) { /* All this effort just for the Sanity WOC demo... */ decide_line (hpos); - if (decided_nr_planes != -1 && hpos >= thisline_decision.plfstrt + thisline_decision.plflinelen) + if (decided_nr_planes != -1 + && hpos >= thisline_decision.plfstrt + thisline_decision.plflinelen) return; decided_bpl1mod = bpl1mod; decided_bpl2mod = bpl2mod; @@ -846,7 +846,7 @@ static void do_modulos (int hpos) } } -static __inline__ void record_sprite (int spr, int sprxp) +STATIC_INLINE void record_sprite (int spr, int sprxp) { int pos = next_sprite_draw; unsigned int data, datb; @@ -903,10 +903,10 @@ static void decide_sprites (int hpos) count = 0; for (i = 0; i < 8; i++) { - int sprxp = sprxpos[i]; + int sprxp = spr[i].xpos; int j, bestp; - if (!sprarmed[i] || sprxp < 0 || sprxp > point || last_sprite_point >= sprxp) + if (! spr[i].armed || sprxp < 0 || sprxp > point || last_sprite_point >= sprxp) continue; if ((thisline_decision.diwfirstword >= 0 && sprxp + sprite_width < thisline_decision.diwfirstword) || (thisline_decision.diwlastword >= 0 && sprxp > thisline_decision.diwlastword)) @@ -986,7 +986,7 @@ static void finish_decisions (void) remember_ctable_for_border (); } if (thisline_decision.which == -1 && thisline_decision.color0 == 0xFFFFFFFFul) - thisline_decision.color0 = current_colors.color_regs[0]; + thisline_decision.color0 = color_reg_get (¤t_colors, 0); dip->nr_color_changes = next_color_change - dip->first_color_change; dip->nr_sprites = next_sprite_draw - dip->first_sprite_draw; @@ -1007,6 +1007,8 @@ static void finish_decisions (void) prev_sprite_positions + dip_old->first_sprite_draw, dip->nr_sprites * sizeof *curr_sprite_positions) != 0))) changed = 1; + if (thisline_decision.plfleft != line_decisions[next_lineno].plfleft) + changed = 1; if (changed) { thisline_changed = 1; @@ -1026,6 +1028,8 @@ static void reset_decisions (void) decided_bpl2mod = bpl2mod; decided_nr_planes = -1; + thisline_decision.plfleft = -1; + /* decided_res shouldn't be touched before it's initialized by decide_line(). */ thisline_decision.diwfirstword = -1; thisline_decision.diwlastword = -2; @@ -1048,6 +1052,9 @@ static void reset_decisions (void) plane_decided = 0; color_decided = 0; very_broken_program = 0; + + last_diw_pix_hpos = -1; + last_ddf_pix_hpos = -1; } /* Initialize the decision array, once before the emulator really starts. */ @@ -1087,12 +1094,49 @@ static void init_hz (void) write_log ("Using %s timing\n", isntsc ? "NTSC" : "PAL"); } -/* Calculate display window and data fetch values from the corresponding - * hardware registers. */ -static void calcdiw (void) +void expand_fetchmodes (int fmode, int bplcon0) { - int mask, add, mask2, add2, plfold; + int res; + if (bplcon0 & 0x8000) + res = 1; + else if (bplcon0 & 0x0040) + res = 2; + else + res = 0; + switch (fmode & 3) { + case 3: + fetchmode = 2; + switch (res) { + case 2: prefetch = 1<<3; fetchsize = 1<<3; fetchstart_shift = 3; break; + case 1: prefetch = 1<<3; fetchsize = 1<<4; fetchstart_shift = 4; break; + case 0: prefetch = 1<<3; fetchsize = 1<<5; fetchstart_shift = 5; break; + } + break; + case 2: + case 1: + fetchmode = 1; + switch (res) { + case 2: prefetch = 1<<2; fetchsize = 1<<3; fetchstart_shift = 2; break; + case 1: prefetch = 1<<3; fetchsize = 1<<3; fetchstart_shift = 3; break; + case 0: prefetch = 1<<3; fetchsize = 1<<4; fetchstart_shift = 4; break; + } + break; + case 0: + fetchmode = 0; + switch (res) { + case 2: prefetch = 1<<1; fetchsize = 1<<3; fetchstart_shift = 1; break; + case 1: prefetch = 1<<2; fetchsize = 1<<3; fetchstart_shift = 2; break; + case 0: prefetch = 1<<3; fetchsize = 1<<3; fetchstart_shift = 3; break; + } + break; + } + fetchstart = 1 << fetchstart_shift; +} + +static void calcdiw (void) +{ + int fetch; int hstrt = diwstrt & 0xFF; int hstop = diwstop & 0xFF; int vstrt = diwstrt >> 8; @@ -1109,8 +1153,8 @@ static void calcdiw (void) vstop |= 0x100; } - diwfirstword = coord_hw_to_native_x (hstrt - 1); - diwlastword = coord_hw_to_native_x (hstop - 1); + diwfirstword = coord_hw_to_window_x (hstrt - 1); + diwlastword = coord_hw_to_window_x (hstop - 1); if (diwlastword > max_diwlastword) diwlastword = max_diwlastword; @@ -1136,85 +1180,23 @@ static void calcdiw (void) plflastline = 313; } #endif - plfstrt = ddfstrt; plfstop = ddfstop; - /* @@@ Toni... these ones might be wrong for AGA? */ if (plfstrt < 0x18) plfstrt = 0x18; if (plfstop < 0x18) plfstop = 0x18; if (plfstop > 0xD8) plfstop = 0xD8; + if (plfstrt > plfstop) plfstrt = plfstop; - /* ! If the masking operation is changed, the pfield_doline code could break - * on some systems (alignment) */ - /* This actually seems to be correct now, at least the non-AGA stuff... */ - - if ((fmode & 3) == 0) { - /* FMODE=0 */ - mask = ~7; - add = 15; - mask2 = ~3; - add2 = 0; - } else if ((fmode & 3) == 3) { - /* FMODE=3 */ - if(bplcon0 & 0x8000) { - mask = ~15; - add = 31; - mask2 = ~7; - add2 = 4; - } else { - mask = ~31; - add = 63; - mask2 = ~15; - add2 = 8; - } - } else { - /* FMODE=1/2 */ - if(bplcon0 & 0x8000) { - mask = ~15; - add = 31; - mask2 = ~15; - add2 = 4; - } else { - mask = ~15; - add = 31; - mask2 = ~15; - add2 = 8; - - } - } - /* ugh.. This works in every demo and game I have tested, but can't be correct, - * it looks too complex and stupid, does anybody know how this really works? (TW) - */ - plfold = plfstrt; - plfstrt &= mask2; - plfstrt += add2; - /* @@@ This one is different from the pre-AGA version. It shouldn't make - * a difference in OCS modes, though. */ - plfstop += plfstrt - plfold; - plfstop &= mask2; - plfstop += add2; - plflinelen = (plfstop-plfstrt+add) & mask; - - if (plfstrt > plfstop) - plfstrt = plfstop; - + expand_fetchmodes (fmode, bplcon0); + fetch = fetchsize >> fetchstart_shift; + plflinelen = ((((plfstop - plfstrt + fetchstart - 1) >> fetchstart_shift) + + fetch + (fetch - 1)) & ~(fetch - 1) ) << fetchstart_shift; #if 0 - if (plflinelen > 100 && (bplcon0 & 0x8000)) - write_log("vpos: %d fmode: %d, hires %d strt1 %d stop1 %d strt2 %d stop2 %d,plflinelen %d\n", - vpos,fmode&3,(bplcon0&0x8000)?1:0,ddfstrt,ddfstop,plfstrt,plfstop,plflinelen); + if (plfstrt + plflinelen != plfstop + fetchsize) + printf ("%d + %d vs %d + %d\n", plfstrt, plflinelen, plfstop, fetchsize); #endif } -/* - * lores,fmode=3 24 184 = 192 - * hires,fmode=3 40 200 = 176 - * hires,fmode=3 40 216 = 192 - * hires,fmode=1 56 200 = 160 - * hires,fmode=1 56 208 = 160 - * lores,fmode=1 48 200 = 176 - * lores,fmode=1 72 168 = 112 -*/ - /* Mousehack stuff */ #define defstepx (1<<16) @@ -1297,7 +1279,7 @@ void togglemouse (void) } } -static __inline__ int adjust (int val) +STATIC_INLINE int adjust (int val) { if (val > 127) return 127; @@ -1317,7 +1299,7 @@ static void do_mouse_hack (void) return; } switch (mousestate) { - case normal_mouse: + case normal_mouse: diffx = lastmx - lastsampledmx; diffy = lastmy - lastsampledmy; if (!newmousecounters) { @@ -1331,14 +1313,14 @@ static void do_mouse_hack (void) lastsampledmx += diffx; lastsampledmy += diffy; break; - case dont_care_mouse: + case dont_care_mouse: diffx = adjust (((lastmx - lastspr0x) * mstepx) >> 16); diffy = adjust (((lastmy - lastspr0y) * mstepy) >> 16); lastspr0x = lastmx; lastspr0y = lastmy; mouse_x += diffx; mouse_y += diffy; break; - case follow_mouse: + case follow_mouse: if (sprvbfl && sprvbfl-- > 1) { int mousexpos, mouseypos; @@ -1372,7 +1354,7 @@ static void do_mouse_hack (void) } break; - default: + default: abort (); } } @@ -1400,7 +1382,7 @@ static uae_u32 timehack_helper (void) /* * register functions */ -static __inline__ uae_u16 DENISEID (void) +STATIC_INLINE uae_u16 DENISEID (void) { if (currprefs.chipset_mask & CSMASK_AGA) return 0xF8; @@ -1408,24 +1390,24 @@ static __inline__ uae_u16 DENISEID (void return 0xFC; return 0xFFFF; } -static __inline__ uae_u16 DMACONR (void) +STATIC_INLINE uae_u16 DMACONR (void) { return (dmacon | (bltstate==BLT_done ? 0 : 0x4000) | (blt_info.blitzero ? 0x2000 : 0)); } -static __inline__ uae_u16 INTENAR (void) +STATIC_INLINE uae_u16 INTENAR (void) { return intena; } uae_u16 INTREQR (void) { - return intreq | (currprefs.use_serial ? 0x0001 : 0); + return intreq /* | (currprefs.use_serial ? 0x0001 : 0) */; } -static __inline__ uae_u16 ADKCONR (void) +STATIC_INLINE uae_u16 ADKCONR (void) { return adkcon; } -static __inline__ uae_u16 VPOSR (void) +STATIC_INLINE uae_u16 VPOSR (void) { unsigned int csbit = ntscmode ? 0x1000 : 0; csbit |= (currprefs.chipset_mask & CSMASK_AGA) ? 0x2300 : 0; @@ -1443,47 +1425,47 @@ static void VPOSW (uae_u16 v) */ } -static __inline__ uae_u16 VHPOSR (void) +STATIC_INLINE uae_u16 VHPOSR (void) { return (vpos << 8) | current_hpos(); } -static __inline__ void COP1LCH (uae_u16 v) { cop1lc = (cop1lc & 0xffff) | ((uae_u32)v << 16); } -static __inline__ void COP1LCL (uae_u16 v) { cop1lc = (cop1lc & ~0xffff) | (v & 0xfffe); } -static __inline__ void COP2LCH (uae_u16 v) { cop2lc = (cop2lc & 0xffff) | ((uae_u32)v << 16); } -static __inline__ void COP2LCL (uae_u16 v) { cop2lc = (cop2lc & ~0xffff) | (v & 0xfffe); } +STATIC_INLINE void COP1LCH (uae_u16 v) { cop1lc = (cop1lc & 0xffff) | ((uae_u32)v << 16); } +STATIC_INLINE void COP1LCL (uae_u16 v) { cop1lc = (cop1lc & ~0xffff) | (v & 0xfffe); } +STATIC_INLINE void COP2LCH (uae_u16 v) { cop2lc = (cop2lc & 0xffff) | ((uae_u32)v << 16); } +STATIC_INLINE void COP2LCL (uae_u16 v) { cop2lc = (cop2lc & ~0xffff) | (v & 0xfffe); } + +static void start_copper (void) +{ + int was_active = eventtab[ev_copper].active; + eventtab[ev_copper].active = 0; + if (was_active) + events_schedule (); -static void COPJMP1 (uae_u16 a) -{ - cop_state.ip = cop1lc; - cop_state.do_move = 0; cop_state.ignore_next = 0; cop_state.state = COP_read1; cop_state.vpos = vpos; cop_state.hpos = current_hpos () & ~1; - cop_state.count = current_hpos () & ~1; - prepare_copper (); - if (eventtab[ev_copper].evtime == cycles && eventtab[ev_copper].active) - abort (); - events_schedule (); + + if (dmaen (DMA_COPPER)) { + copper_enabled_thisline = 1; + regs.spcflags |= SPCFLAG_COPPER; + } +} + +static void COPJMP1 (uae_u16 a) +{ + cop_state.ip = cop1lc; + start_copper (); } static void COPJMP2 (uae_u16 a) { cop_state.ip = cop2lc; - cop_state.do_move = 0; - cop_state.ignore_next = 0; - cop_state.state = COP_read1; - cop_state.vpos = vpos; - cop_state.hpos = current_hpos () & ~1; - cop_state.count = current_hpos () & ~1; - prepare_copper (); - if (eventtab[ev_copper].evtime == cycles && eventtab[ev_copper].active) - abort (); - events_schedule (); + start_copper (); } -static __inline__ void COPCON (uae_u16 a) +STATIC_INLINE void COPCON (uae_u16 a) { copcon = a; } @@ -1500,19 +1482,26 @@ static void DMACON (uae_u16 v) /* FIXME? Maybe we need to think a bit more about the master DMA enable * bit in these cases. */ + if ((dmacon & DMA_COPPER) != (oldcon & DMA_COPPER)) { + if (eventtab[ev_copper].active) + need_resched = 1; + eventtab[ev_copper].active = 0; + } if ((dmacon & DMA_COPPER) > (oldcon & DMA_COPPER)) { cop_state.ip = cop1lc; - cop_state.do_move = 0; cop_state.ignore_next = 0; cop_state.state = COP_read1; cop_state.vpos = vpos; cop_state.hpos = current_hpos () & ~1; - cop_state.count = current_hpos () & ~1; - prepare_copper (); - if (eventtab[ev_copper].evtime == cycles && eventtab[ev_copper].active) - abort (); - need_resched = 1; + copper_enabled_thisline = 1; + regs.spcflags |= SPCFLAG_COPPER; } + if (! (dmacon & DMA_COPPER)) { + copper_enabled_thisline = 0; + regs.spcflags &= ~SPCFLAG_COPPER; + cop_state.state = COP_stop; + } + if ((dmacon & DMA_BLITPRI) > (oldcon & DMA_BLITPRI) && bltstate != BLT_done) { static int count = 0; if (!count) { @@ -1521,6 +1510,8 @@ static void DMACON (uae_u16 v) } regs.spcflags |= SPCFLAG_BLTNASTY; } + if ((dmacon & (DMA_BLITPRI | DMA_BLITTER | DMA_MASTER)) != (DMA_BLITPRI | DMA_BLITTER | DMA_MASTER)) + regs.spcflags &= ~SPCFLAG_BLTNASTY; update_audio (); @@ -1552,7 +1543,7 @@ static void DMACON (uae_u16 v) /*static int trace_intena = 0;*/ -static __inline__ void INTENA (uae_u16 v) +STATIC_INLINE void INTENA (uae_u16 v) { /* if (trace_intena) fprintf (stderr, "INTENA: %04x\n", v);*/ @@ -1615,6 +1606,8 @@ static void BPLCON0 (int hpos, uae_u16 v if (bplcon0 == v) return; decide_line (hpos); + /* if ((bplcon0 ^ v) & 0x8000)*/ + calcdiw (); bplcon0 = v; nr_planes_from_bplcon0 = GET_PLANES (v); @@ -1627,7 +1620,8 @@ static void BPLCON0 (int hpos, uae_u16 v post_decide_line (hpos); } -static __inline__ void BPLCON1 (int hpos, uae_u16 v) + +STATIC_INLINE void BPLCON1 (int hpos, uae_u16 v) { if (bplcon1 == v) return; @@ -1635,21 +1629,21 @@ static __inline__ void BPLCON1 (int hpos bplcon1 = v; decide_delay (hpos); } -static __inline__ void BPLCON2 (int hpos, uae_u16 v) +STATIC_INLINE void BPLCON2 (int hpos, uae_u16 v) { if (bplcon2 == v) return; decide_line (hpos); bplcon2 = v; } -static __inline__ void BPLCON3 (int hpos, uae_u16 v) +STATIC_INLINE void BPLCON3 (int hpos, uae_u16 v) { if (bplcon3 == v) return; decide_line (hpos); bplcon3 = v; } -static __inline__ void BPLCON4 (int hpos, uae_u16 v) +STATIC_INLINE void BPLCON4 (int hpos, uae_u16 v) { if (! (currprefs.chipset_mask & CSMASK_AGA)) return; @@ -1677,15 +1671,20 @@ static void BPL2MOD (int hpos, uae_u16 v decide_modulos (hpos); } +STATIC_INLINE void BPL1DAT (uae_u16 v) +{ + bpl1dat = v; + if (thisline_decision.plfleft == -1) + thisline_decision.plfleft = current_hpos (); +} /* We could do as well without those... */ -static __inline__ void BPL1DAT (uae_u16 v) { bpl1dat = v; } -static __inline__ void BPL2DAT (uae_u16 v) { bpl2dat = v; } -static __inline__ void BPL3DAT (uae_u16 v) { bpl3dat = v; } -static __inline__ void BPL4DAT (uae_u16 v) { bpl4dat = v; } -static __inline__ void BPL5DAT (uae_u16 v) { bpl5dat = v; } -static __inline__ void BPL6DAT (uae_u16 v) { bpl6dat = v; } -static __inline__ void BPL7DAT (uae_u16 v) { bpl7dat = v; } -static __inline__ void BPL8DAT (uae_u16 v) { bpl8dat = v; } +STATIC_INLINE void BPL2DAT (uae_u16 v) { bpl2dat = v; } +STATIC_INLINE void BPL3DAT (uae_u16 v) { bpl3dat = v; } +STATIC_INLINE void BPL4DAT (uae_u16 v) { bpl4dat = v; } +STATIC_INLINE void BPL5DAT (uae_u16 v) { bpl5dat = v; } +STATIC_INLINE void BPL6DAT (uae_u16 v) { bpl6dat = v; } +STATIC_INLINE void BPL7DAT (uae_u16 v) { bpl7dat = v; } +STATIC_INLINE void BPL8DAT (uae_u16 v) { bpl8dat = v; } static void DIWSTRT (int hpos, uae_u16 v) { @@ -1721,7 +1720,7 @@ static void DIWHIGH (int hpos, uae_u16 v static void DDFSTRT (int hpos, uae_u16 v) { - v &= (currprefs.chipset_mask & CSMASK_AGA) ? 0x1FC : 0xFC; + v &= 0xFC; if (ddfstrt == v) return; decide_line (hpos); @@ -1730,7 +1729,7 @@ static void DDFSTRT (int hpos, uae_u16 v } static void DDFSTOP (int hpos, uae_u16 v) { - v &= (currprefs.chipset_mask & CSMASK_AGA) ? 0x1FC : 0xFC; + v &= 0xFC; if (ddfstop == v) return; decide_line (hpos); @@ -1833,38 +1832,38 @@ static void BLTSIZH (uae_u16 v) do_blitter (); } -static __inline__ void SPRxCTL_1 (uae_u16 v, int num) +STATIC_INLINE void SPRxCTL_1 (uae_u16 v, int num) { int sprxp; sprctl[num] = v; - nr_armed -= sprarmed[num]; - sprarmed[num] = 0; + nr_armed -= spr[num].armed; + spr[num].armed = 0; if (sprpos[num] == 0 && v == 0) { - sprst[num] = SPR_stop; - spron[num] = 0; + spr[num].state = SPR_stop; + spr[num].on = 0; } else - sprst[num] = SPR_waiting_start; + spr[num].state = SPR_waiting_start; - sprxp = coord_hw_to_native_x ((sprpos[num] & 0xFF) * 2 + (v & 1)); - sprxpos[num] = sprxp; - sprvstart[num] = (sprpos[num] >> 8) | ((sprctl[num] << 6) & 0x100); - sprvstop[num] = (sprctl[num] >> 8) | ((sprctl[num] << 7) & 0x100); + sprxp = coord_hw_to_window_x ((sprpos[num] & 0xFF) * 2 + (v & 1)); + spr[num].xpos = sprxp; + spr[num].vstart = (sprpos[num] >> 8) | ((sprctl[num] << 6) & 0x100); + spr[num].vstop = (sprctl[num] >> 8) | ((sprctl[num] << 7) & 0x100); } -static __inline__ void SPRxPOS_1 (uae_u16 v, int num) +STATIC_INLINE void SPRxPOS_1 (uae_u16 v, int num) { int sprxp; sprpos[num] = v; - sprxp = coord_hw_to_native_x ((v & 0xFF) * 2 + (sprctl[num] & 1)); - sprxpos[num] = sprxp; - sprvstart[num] = (sprpos[num] >> 8) | ((sprctl[num] << 6) & 0x100); + sprxp = coord_hw_to_window_x ((v & 0xFF) * 2 + (sprctl[num] & 1)); + spr[num].xpos = sprxp; + spr[num].vstart = (sprpos[num] >> 8) | ((sprctl[num] << 6) & 0x100); } -static __inline__ void SPRxDATA_1 (uae_u16 v, int num) +STATIC_INLINE void SPRxDATA_1 (uae_u16 v, int num) { sprdata[num] = v; - nr_armed += 1 - sprarmed[num]; - sprarmed[num] = 1; + nr_armed += 1 - spr[num].armed; + spr[num].armed = 1; } -static __inline__ void SPRxDATB_1 (uae_u16 v, int num) +STATIC_INLINE void SPRxDATB_1 (uae_u16 v, int num) { sprdatb[num] = v; } @@ -1875,22 +1874,22 @@ static void SPRxPOS (int hpos, uae_u16 v static void SPRxPTH (int hpos, uae_u16 v, int num) { decide_sprites (hpos); - sprpt[num] &= 0xffff; - sprpt[num] |= (uae_u32)v << 16; + spr[num].pt &= 0xffff; + spr[num].pt |= (uae_u32)v << 16; - if (sprst[num] == SPR_stop || vpos < vblank_endline) - sprst[num] = SPR_restart; - spron[num] = 1; + if (spr[num].state == SPR_stop || vpos < sprite_vblank_endline) + spr[num].state = SPR_restart; + spr[num].on = 1; } static void SPRxPTL (int hpos, uae_u16 v, int num) { decide_sprites (hpos); - sprpt[num] &= ~0xffff; - sprpt[num] |= v; + spr[num].pt &= ~0xffff; + spr[num].pt |= v; - if (sprst[num] == SPR_stop || vpos < vblank_endline) - sprst[num] = SPR_restart; - spron[num] = 1; + if (spr[num].state == SPR_stop || vpos < sprite_vblank_endline) + spr[num].state = SPR_restart; + spr[num].on = 1; } static void CLXCON (uae_u16 v) { @@ -1903,25 +1902,28 @@ static uae_u16 CLXDAT (void) clxdat = 0; return v; } + static void COLOR (int hpos, uae_u16 v, int num) { v &= 0xFFF; -#if AGA_CHIPSET == 1 - { - /* XXX Broken */ + if (currprefs.chipset_mask & CSMASK_AGA) { + int r,g,b; int cr,cg,cb; int colreg; uae_u32 cval; + /* writing is disabled when RDRAM=1 */ + if (bplcon2 & 0x0100) return; + colreg = ((bplcon3 >> 13) & 7) * 32 + num; r = (v & 0xF00) >> 8; g = (v & 0xF0) >> 4; b = (v & 0xF) >> 0; - cr = current_colors.color_regs[colreg] >> 16; - cg = (current_colors.color_regs[colreg] >> 8) & 0xFF; - cb = current_colors.color_regs[colreg] & 0xFF; + cr = current_colors.color_regs_aga[colreg] >> 16; + cg = (current_colors.color_regs_aga[colreg] >> 8) & 0xFF; + cb = current_colors.color_regs_aga[colreg] & 0xFF; if (bplcon3 & 0x200) { cr &= 0xF0; cr |= r; @@ -1933,84 +1935,23 @@ static void COLOR (int hpos, uae_u16 v, cb = b + (b << 4); } cval = (cr << 16) | (cg << 8) | cb; - if (cval == current_colors.color_regs[colreg]) + if (cval == current_colors.color_regs_aga[colreg]) return; /* Call this with the old table still intact. */ - record_color_change (hpos, colreg, v); + record_color_change (hpos, colreg, cval); remembered_color_entry = -1; - current_colors.color_regs[colreg] = cval; -/* current_colors.acolors[colreg] = xcolors[v];*/ - } -#else - { - if (current_colors.color_regs[num] == v) + current_colors.color_regs_aga[colreg] = cval; + current_colors.acolors[colreg] = CONVERT_RGB (cval); + } else { + if (current_colors.color_regs_ecs[num] == v) return; /* Call this with the old table still intact. */ record_color_change (hpos, num, v); remembered_color_entry = -1; - current_colors.color_regs[num] = v; + current_colors.color_regs_ecs[num] = v; current_colors.acolors[num] = xcolors[v]; } -#endif -} - -static void DSKSYNC (uae_u16 v) { dsksync = v; } -static void DSKDAT (uae_u16 v) { write_log ("DSKDAT written. Not good.\n"); } -static void DSKPTH (uae_u16 v) { dskpt = (dskpt & 0xffff) | ((uae_u32)v << 16); } -static void DSKPTL (uae_u16 v) { dskpt = (dskpt & ~0xffff) | (v); } - -static void DSKLEN (uae_u16 v) -{ - if (v & 0x8000) { - dskdmaen = dskdmaen == 1 ? 2 : 1; - } else { - dskdmaen = 0; - if (eventtab[ev_diskblk].active) - write_log ("warning: Disk DMA aborted!\n"); - eventtab[ev_diskblk].active = 0; - events_schedule(); - - } - dsklen = dsklength = v; dsklength &= 0x3fff; - if (dskdmaen == 2 && dsksync != 0x4489 && (adkcon & 0x400)) { - write_log ("Non-standard sync: %04x len: %x\n", dsksync, dsklength); - } - if (dskdmaen > 1) { - if (dsklen & 0x4000) { - eventtab[ev_diskblk].active = 1; - eventtab[ev_diskblk].oldcycles = cycles; - eventtab[ev_diskblk].evtime = 40 + cycles; /* ??? */ - events_schedule(); - } else { - int result = DISK_PrepareReadMFM(dsklength, dsksync, adkcon & 0x400); - if (result) { - eventtab[ev_diskblk].active = 1; - eventtab[ev_diskblk].oldcycles = cycles; - eventtab[ev_diskblk].evtime = result + cycles; - events_schedule(); - } - } - } -} - -static uae_u16 DSKBYTR (void) -{ - uae_u16 v = (dsklen >> 1) & 0x6000; - uae_u16 mfm, byte; - if (DISK_GetData (&mfm, &byte)) - v |= 0x8000; - v |= byte; - if (dsksync == mfm) - v |= 0x1000; - return v; -} - -static uae_u16 DSKDATR (void) -{ - uae_u16 mfm, byte; - DISK_GetData (&mfm, &byte); - return mfm; } static uae_u16 potgo_value; @@ -2022,8 +1963,9 @@ static void POTGO (uae_u16 v) static uae_u16 POTGOR (void) { - uae_u16 v = (potgo_value | (potgo_value << 1)) & 0xAA00; - v |= v >> 1; + uae_u16 v = (potgo_value | (potgo_value >> 1)) & 0x5500; + + v |= (~potgo_value & 0xAA00) >> 1; if (JSEM_ISMOUSE (0, &currprefs)) { if (buttonstate[2]) @@ -2080,18 +2022,6 @@ static void JOYTEST (uae_u16 v) } } -/* - * Here starts the copper code. Can you believe it used to be worse? - */ - -static __inline__ void copper_adjust_diw (struct copper *cst) -{ - if (cst->vdiw == DIW_waiting_start && vpos == plffirstline) - cst->vdiw = DIW_waiting_stop; - if (cst->vdiw == DIW_waiting_stop && vpos == plflastline) - cst->vdiw = DIW_waiting_start; -} - /* Determine which cycles are available for the copper in a display * with a agiven number of planes. */ static int cycles_for_plane[9][8] = { @@ -2100,7 +2030,7 @@ static int cycles_for_plane[9][8] = { { 0, -1, 0, -1, 0, -1, 0, -1 }, { 0, -1, 0, -1, 0, -1, 0, -1 }, { 0, -1, 0, -1, 0, -1, 0, -1 }, - { 0, -1, 1, -1, 0, -1, 0, -1 }, + { 0, -1, 0, -1, 0, -1, 1, -1 }, { 0, -1, 1, -1, 0, -1, 1, -1 }, { 1, -1, 1, -1, 1, -1, 1, -1 }, { 1, -1, 1, -1, 1, -1, 1, -1 } @@ -2108,18 +2038,16 @@ static int cycles_for_plane[9][8] = { static unsigned int waitmasktab[256]; -#define COP_OFFSET 4 - -static __inline__ int copper_in_playfield (enum diw_states diw, int hpos) +STATIC_INLINE int copper_in_playfield (enum diw_states diw, int hpos) { - hpos -= COP_OFFSET; return diw == DIW_waiting_stop && hpos >= plfstrt && hpos < plfstrt + plflinelen; } -static __inline__ int copper_cant_read (enum diw_states diw, int hpos, int planes) +STATIC_INLINE int copper_cant_read (enum diw_states diw, int hpos, int planes) { int t; + /* @@@ */ if (hpos >= ((maxhpos - 2) & ~1)) return 1; @@ -2138,423 +2066,262 @@ static __inline__ int copper_cant_read ( return t; } -static void update_copper_1 (int until_hpos) +STATIC_INLINE int dangerous_reg (int reg) { - unsigned int vp, hp, vcmp, hcmp; + /* Safe: + * Bitplane pointers, control registers, modulos and data. + * Sprite pointers, control registers, and data. + * Color registers. */ + if (reg >= 0xE0 && reg < 0x1C0) + return 0; + return 1; +} + +static void update_copper (int until_hpos) +{ + int vp = vpos & (((cop_state.i2 >> 8) & 0x7F) | 0x80); int c_hpos = cop_state.hpos; - int c_vpos = cop_state.vpos; - vp = vpos & (((cop_state.i2 >> 8) & 0x7F) | 0x80); - hp = cop_state.count & (cop_state.i2 & 0xFE); - vcmp = ((cop_state.i1 & (cop_state.i2 | 0x8000)) >> 8); - hcmp = (cop_state.i1 & cop_state.i2 & 0xFE); + if (eventtab[ev_copper].active) + abort (); - if (cop_state.state == COP_wait2) - cop_state.state = COP_wait1b; + if (cop_state.state == COP_wait && vp < cop_state.vcmp) + abort (); - for (;;) { - if (c_hpos == (maxhpos & ~1)) { - c_hpos = 0; - cop_state.count = 0; - c_vpos++; - } + until_hpos &= ~1; - if (! dmaen (DMA_COPPER)) - cop_state.state = COP_stop; - - if (c_vpos > vpos - || c_hpos > until_hpos - || cop_state.state == COP_stop) - break; + if (until_hpos > (maxhpos & ~1)) + until_hpos = maxhpos & ~1; - if (c_hpos - COP_OFFSET == plfstrt) - copper_adjust_diw (&cop_state); + for (;;) { + int old_hpos = c_hpos; + int hp; - switch (cop_state.state) { - case COP_rdelay1: - cop_state.state = COP_read1; + if (c_hpos > until_hpos) break; - case COP_read1: - if (copper_cant_read (cop_state.vdiw, c_hpos, corrected_nr_planes_from_bplcon0)) - break; + /* So we know about the vertical DIW. */ + decide_line (c_hpos); - if (cop_state.do_move) { - cop_state.do_move = 0; - if (cop_state.i1 < (copcon & 2 ? ((currprefs.chipset_mask & CSMASK_AGA) ? 0 : 0x40u) : 0x80u)) { - cop_state.state = COP_stop; - break; - } - switch (cop_state.i1) { - case 0x088: - cop_state.ip = cop1lc; - cop_state.state = COP_rdelay1; - break; - case 0x08A: - cop_state.ip = cop2lc; - cop_state.state = COP_rdelay1; - break; - default: - custom_wput_1 (c_hpos, cop_state.i1, cop_state.i2); - break; - } - if (cop_state.state != COP_read1) - break; - } + c_hpos += 2; + if (copper_cant_read (diwstate, old_hpos, corrected_nr_planes_from_bplcon0)) + continue; + + switch (cop_state.state) { + case COP_read1: cop_state.i1 = chipmem_bank.wget (cop_state.ip); cop_state.ip += 2; cop_state.state = COP_read2; break; - case COP_read2: - if (copper_cant_read (cop_state.vdiw, c_hpos, corrected_nr_planes_from_bplcon0)) - break; + case COP_read2: cop_state.i2 = chipmem_bank.wget (cop_state.ip); cop_state.ip += 2; + cop_state.state = COP_read1; if (cop_state.ignore_next) { cop_state.ignore_next = 0; - cop_state.state = COP_read1; break; } + /* Perform moves immediately. */ if ((cop_state.i1 & 1) == 0) { - cop_state.state = COP_read1; - cop_state.do_move = 1; - } else { - vp = vpos & (((cop_state.i2 >> 8) & 0x7F) | 0x80); - hp = cop_state.count & (cop_state.i2 & 0xFE); - vcmp = ((cop_state.i1 & (cop_state.i2 | 0x8000)) >> 8); - hcmp = (cop_state.i1 & cop_state.i2 & 0xFE); - - if ((cop_state.i2 & 1) == 0) { - cop_state.state = COP_wait1; - if (cop_state.i1 == 0xFFFF && cop_state.i2 == 0xFFFE) - cop_state.state = COP_stop; - } else { - /* Skip instruction. */ - if ((vp > vcmp || (vp == vcmp && hp >= hcmp)) - && ((cop_state.i2 & 0x8000) != 0 || ! (DMACONR() & 0x4000))) - cop_state.ignore_next = 1; - cop_state.state = COP_read1; + unsigned int address = cop_state.i1 & 0x1FE; + if (address < (copcon & 2 ? ((currprefs.chipset_mask & CSMASK_AGA) ? 0 : 0x40u) : 0x80u)) { + cop_state.state = COP_stop; + copper_enabled_thisline = 0; + regs.spcflags &= ~SPCFLAG_COPPER; + goto out; } + if (address == 0x88) + cop_state.ip = cop1lc; + else if (address == 0x8A) + cop_state.ip = cop2lc; + else + custom_wput_1 (old_hpos, address, cop_state.i2); + /* That could have turned off the copper... */ + if (! copper_enabled_thisline) + goto out; + break; } - break; - case COP_wait1: - if (copper_cant_read (cop_state.vdiw, c_hpos, corrected_nr_planes_from_bplcon0)) + vp = vpos & (((cop_state.i2 >> 8) & 0x7F) | 0x80); + hp = c_hpos & (cop_state.i2 & 0xFE); + cop_state.vcmp = (cop_state.i1 & (cop_state.i2 | 0x8000)) >> 8; + cop_state.hcmp = (cop_state.i1 & cop_state.i2 & 0xFE); + + if ((cop_state.i2 & 1) == 1) { + /* Skip instruction. */ + if ((vp > cop_state.vcmp || (vp == cop_state.vcmp && hp >= cop_state.hcmp)) + && ((cop_state.i2 & 0x8000) != 0 || ! (DMACONR() & 0x4000))) + cop_state.ignore_next = 1; + break; + } + cop_state.state = COP_wait; + if (cop_state.i1 == 0xFFFF && cop_state.i2 == 0xFFFE) { + cop_state.state = COP_stop; + copper_enabled_thisline = 0; + regs.spcflags &= ~SPCFLAG_COPPER; + goto out; + } + if (vp < cop_state.vcmp) { + copper_enabled_thisline = 0; + regs.spcflags &= ~SPCFLAG_COPPER; + goto out; + } + if (vp > cop_state.vcmp) break; - /* fall through */ - - case COP_wait1b: - { - int do_wait2 = cop_state.state == COP_wait1b; - cop_state.state = COP_wait2; - if (vp == vcmp && corrected_nr_planes_from_bplcon0 < 8) { - int t = cop_state.count + 2; - int next_count = (t & waitmasktab[cop_state.i2 & 0xfe]) | hcmp; - int nexthpos; - if (next_count < t) - next_count = t; - nexthpos = c_hpos + next_count - cop_state.count; - if (nexthpos < (maxhpos & ~1)) { - if (c_hpos - COP_OFFSET < plfstrt && nexthpos - COP_OFFSET >= plfstrt) - copper_adjust_diw (&cop_state); - c_hpos = nexthpos; - cop_state.count = next_count; - do_wait2 = 1; - } - } - if (! do_wait2) + /* Only enable shortcuts if there's no masking going on. */ + if (0 && (cop_state.i2 & 0xFE) == 0xFE) { + int time_remaining = until_hpos - c_hpos; + + /* Compute minimum number of cycles to wait. */ + cop_min_waittime = cop_state.hcmp - hp - 4; + if (cop_min_waittime <= 2 || time_remaining <= 0) break; + if (cop_min_waittime < time_remaining) { + c_hpos += cop_min_waittime; + break; + } + c_hpos += time_remaining; + cop_min_waittime -= time_remaining; + if (cop_min_waittime >= 8) { + regs.spcflags &= ~SPCFLAG_COPPER; + eventtab[ev_copper].active = 1; + eventtab[ev_copper].oldcycles = cycles; + eventtab[ev_copper].evtime = cycles + cop_min_waittime; + events_schedule (); + goto out; + } } + break; - /* fall through */ + case COP_wait: + if (vp < cop_state.vcmp) + abort (); - case COP_wait2: - if (vp < vcmp) { - if (c_hpos - COP_OFFSET < plfstrt) - copper_adjust_diw (&cop_state); - - c_vpos++; - c_hpos = 0; - cop_state.count = 0; - continue; - } - hp = cop_state.count & (cop_state.i2 & 0xFE); - if (vp == vcmp && hp < hcmp) + hp = c_hpos & (cop_state.i2 & 0xFE); + if (vp == cop_state.vcmp && hp < cop_state.hcmp) break; - /* Now we know that the comparisons were successful. */ - if ((cop_state.i2 & 0x8000) == 0x8000 || ! (DMACONR() & 0x4000)) - cop_state.state = COP_read1; - else { - /* We need to wait for the blitter. It won't stop while - * we're in update_copper, so we _could_ as well proceed to - * until_hpos in one big step. There are some tricky - * issues to be considered, though, so use the slow method - * for now. */ + + /* Now we know that the comparisons were successful. We might still + have to wait for the blitter though. */ + if ((cop_state.i2 & 0x8000) == 0 && (DMACONR() & 0x4000)) { + /* We need to wait for the blitter. */ cop_state.state = COP_bltwait; + copper_enabled_thisline = 0; + regs.spcflags &= ~SPCFLAG_COPPER; + goto out; } + + cop_state.state = COP_read1; break; default: - /* Delay cycles. */ - break; + abort (); } - - c_hpos += 2; - if (corrected_nr_planes_from_bplcon0 < 8 || ! copper_in_playfield (cop_state.vdiw, c_hpos)) - cop_state.count += 2; } + + out: cop_state.hpos = c_hpos; - cop_state.vpos = c_vpos; -} +#if 0 + /* The future, Conan? */ + if (cop_state.state == COP_read1 || cop_state.state == COP_read2) { + int ip = cop_state.ip; + int word = cop_state.i1; -static __inline__ void update_copper (int until_hpos) -{ - if (cop_state.vpos > vpos - || cop_state.hpos > until_hpos - || cop_state.state == COP_stop) - return; - update_copper_1 (until_hpos); -} + if (eventtab[ev_copper].active /* || ! (regs.spcflags & SPCFLAG_COPPER) */) + abort (); -static int dangerous_reg (int reg) -{ - /* Safe: - * Bitplane pointers, control registers, modulos and data. - * Sprite pointers, control registers, and data. - * Color registers. */ - if (reg >= 0xE0 && reg < 0x1C0) - return 0; - return 1; + if (cop_state.state == COP_read2) { + ip += 2; + c_hpos += 2; + goto inner; + } + while (c_hpos < (maxhpos & ~1)) { + word = chipmem_bank.wget (ip); + ip += 4; + c_hpos += 4; + inner: + if ((word & 1) || dangerous_reg (word)) + break; + } + cop_min_waittime = c_hpos - cop_state.hpos; + if (cop_min_waittime >= 8) { + regs.spcflags &= ~SPCFLAG_COPPER; + eventtab[ev_copper].active = 1; + eventtab[ev_copper].oldcycles = cycles; + eventtab[ev_copper].evtime = cycles + cop_min_waittime; + events_schedule (); + } + } +#endif } -static void prepare_copper_1 (void) +static void compute_spcflag_copper (void) { - struct copper cst = cop_state; - unsigned int vp, hp, vcmp, hcmp; - - vp = vpos & (((cop_state.i2 >> 8) & 0x7F) | 0x80); - hp = cop_state.count & (cop_state.i2 & 0xFE); - vcmp = ((cop_state.i1 & (cop_state.i2 | 0x8000)) >> 8); - hcmp = (cop_state.i1 & cop_state.i2 & 0xFE); - - if (cst.state == COP_wait2) - cst.state = COP_wait1b; + copper_enabled_thisline = 0; + regs.spcflags &= ~SPCFLAG_COPPER; + if (! dmaen (DMA_COPPER) || cop_state.state == COP_stop || cop_state.state == COP_bltwait) + return; - for (;;) { - if (cst.hpos == (maxhpos & ~1)) { - cst.hpos = 0; - cst.count = 0; - cst.vpos++; - } + if (cop_state.state == COP_wait) { + int vp = vpos & (((cop_state.i2 >> 8) & 0x7F) | 0x80); - if (! dmaen (DMA_COPPER)) - cst.state = COP_stop; - - if (cst.vpos > vpos - || cst.state == COP_stop) - { - eventtab[ev_copper].active = 0; + if (vp < cop_state.vcmp) return; - } + copper_enabled_thisline = 1; - if (cst.hpos - COP_OFFSET == plfstrt) - copper_adjust_diw (&cst); + if (0 && vp == cop_state.vcmp) { + int hp = (cop_state.hpos + 2) & (cop_state.i2 & 0xFE); + cop_min_waittime = cop_state.hcmp - hp - 4; - switch (cst.state) { - case COP_rdelay1: - cst.state = COP_read1; - break; - - case COP_read1: - if (copper_cant_read (cst.vdiw, cst.hpos, corrected_nr_planes_from_bplcon0)) - break; - - if (cst.do_move) { - cst.do_move = 0; - if (cst.i1 < (copcon & 2 ? ((currprefs.chipset_mask & CSMASK_AGA) ? 0 : 0x40u) : 0x80u)) { - cst.state = COP_stop; - eventtab[ev_copper].active = 0; - return; - } else if (dangerous_reg (cst.i1)) { - eventtab[ev_copper].active = 1; - eventtab[ev_copper].oldcycles = cycles; - eventtab[ev_copper].evtime = cycles + cst.hpos - current_hpos () + (cst.vpos - cop_state.vpos) * maxhpos; - return; - } - } - - cst.i1 = chipmem_bank.wget (cst.ip); - cst.ip += 2; - cst.state = COP_read2; - break; - - case COP_read2: - if (copper_cant_read (cst.vdiw, cst.hpos, corrected_nr_planes_from_bplcon0)) - break; - cst.i2 = chipmem_bank.wget (cst.ip); - cst.ip += 2; - if (cst.ignore_next) { - cst.ignore_next = 0; - cst.state = COP_read1; - break; + /* If possible, compute a minimum waiting time, and set the event + timer if it's sufficiently large to be worthwhile. */ + if ((cop_state.i2 & 0xFE) == 0xFE && cop_min_waittime >= 8) { + eventtab[ev_copper].active = 1; + eventtab[ev_copper].oldcycles = cycles; + eventtab[ev_copper].evtime = cycles + cop_min_waittime; + events_schedule (); + return; } - if ((cst.i1 & 1) == 0) { - cst.state = COP_read1; - cst.do_move = 1; - } else { - vp = vpos & (((cst.i2 >> 8) & 0x7F) | 0x80); - hp = cst.count & (cst.i2 & 0xFE); - vcmp = ((cst.i1 & (cst.i2 | 0x8000)) >> 8); - hcmp = (cst.i1 & cst.i2 & 0xFE); - - if ((cst.i2 & 1) == 0) { - cst.state = COP_wait1; - if (cst.i1 == 0xFFFF && cst.i2 == 0xFFFE) - cst.state = COP_stop; - } else { - /* Skip instruction. */ - if ((vp > vcmp || (vp == vcmp && hp >= hcmp)) - && ((cst.i2 & 0x8000) != 0 || ! (DMACONR() & 0x4000))) - cst.ignore_next = 1; - cst.state = COP_read1; - } - } - break; - - case COP_wait1: - if (copper_cant_read (cst.vdiw, cst.hpos, corrected_nr_planes_from_bplcon0)) - break; - - /* fall through */ + } + } - case COP_wait1b: - { - int do_wait2 = cst.state == COP_wait1b; - cst.state = COP_wait2; - if (vp == vcmp && corrected_nr_planes_from_bplcon0 < 8) { - int t = cst.count + 2; - int next_count = (t & waitmasktab[cst.i2 & 0xfe]) | hcmp; - int nexthpos; - if (next_count < t) - next_count = t; - nexthpos = cst.hpos + next_count - cst.count; - if (nexthpos < (maxhpos & ~1)) { - if (cst.hpos - COP_OFFSET < plfstrt && nexthpos - COP_OFFSET >= plfstrt) - copper_adjust_diw (&cst); - cst.hpos = nexthpos; - cst.count = next_count; - do_wait2 = 1; - } - } - if (! do_wait2) - break; - } + copper_enabled_thisline = 1; + regs.spcflags |= SPCFLAG_COPPER; +} - /* fall through */ - - case COP_wait2: - if (vp < vcmp) { - if (cst.hpos - COP_OFFSET < plfstrt) - copper_adjust_diw (&cst); - - cst.vpos++; - cst.count = 0; - cst.hpos = 0; - continue; - } - hp = cst.count & (cst.i2 & 0xFE); - if (vp == vcmp && hp < hcmp) - break; -#if 0 - if (nexthpos != -1) - if (nexthpos != cst.count) - printf ("ERROR\n"); - nexthpos = -1; -#endif - /* Now we know that the comparisons were successful. */ - if ((cst.i2 & 0x8000) == 0x8000 || ! (DMACONR() & 0x4000)) - cst.state = COP_read1; - else { - /* We need to wait for the blitter. It won't stop while - * we're in update_copper, so we _could_ as well proceed to - * until_hpos in one big step. There are some tricky - * issues to be considered, though, so use the slow method - * for now. */ - cst.state = COP_bltwait; - } - break; +static void copper_handler (void) +{ + /* This will take effect immediately, within the same cycle. */ + regs.spcflags |= SPCFLAG_COPPER; - default: - /* Delay cycles. */ - break; - } + if (! copper_enabled_thisline) + abort (); - cst.hpos += 2; - if (corrected_nr_planes_from_bplcon0 < 8 || ! copper_in_playfield (cst.vdiw, cst.hpos)) - cst.count += 2; + if (cop_state.state == COP_wait) { + cop_state.hpos += cop_min_waittime; + if (cop_state.hpos > current_hpos ()) + abort (); } + + eventtab[ev_copper].active = 0; } void blitter_done_notify (void) { if (cop_state.state != COP_bltwait) return; - update_copper (current_hpos ()); - cop_state.state = COP_wait2; - eventtab[ev_copper].active = 1; - eventtab[ev_copper].oldcycles = cycles; - eventtab[ev_copper].evtime = (cycles + 2) & ~1; - events_schedule (); + + copper_enabled_thisline = 1; + regs.spcflags |= SPCFLAG_COPPER; + cop_state.state = COP_wait; } -static void do_copper (void) +void do_copper (void) { int hpos = current_hpos (); update_copper (hpos); - prepare_copper (); - if (eventtab[ev_copper].evtime == cycles && eventtab[ev_copper].active) - abort (); -} - -static void diskblk_handler (void) -{ - regs.spcflags |= SPCFLAG_DISK; - eventtab[ev_diskblk].active = 0; -} - -void do_disk (void) -{ - if (dskdmaen != 2 && (regs.spcflags & SPCFLAG_DISK)) { - static int warned = 0; - if (!warned) - warned++, write_log ("BUG!\n"); - return; - } - if (dmaen(0x10)){ - if (dsklen & 0x4000) { - if (!chipmem_bank.check (dskpt, 2*dsklength)) { - write_log ("warning: Bad disk write DMA pointer\n"); - } else { - uae_u8 *mfmp = get_real_address (dskpt); - int i; - DISK_InitWrite(); - - for (i = 0; i < dsklength; i++) { - uae_u16 d = (*mfmp << 8) + *(mfmp+1); - mfmwrite[i] = d; - mfmp += 2; - } - DISK_WriteData(dsklength); - } - } else { - DISK_ReadMFM (dskpt); - } - regs.spcflags &= ~SPCFLAG_DISK; - INTREQ(0x9002); - dskdmaen = -1; - } } static void do_sprites (int currvp, int currhp) @@ -2579,7 +2346,11 @@ static void do_sprites (int currvp, int * second time only _after_ the VBlank interval, and it showed the same behaviour * as it did unmodified under UAE with the above check. This indicates that the * solution below is correct. */ - if (currvp < vblank_endline) + /* Another update: seems like we have to use the NTSC value here (see Sanity Turmoil + * demo). */ + /* Maximum for Sanity Turmoil: 27. + Minimum for Sanity Arte: 22. */ + if (currvp < sprite_vblank_endline) return; #endif @@ -2594,38 +2365,38 @@ static void do_sprites (int currvp, int for (i = 0; i < maxspr; i++) { int fetch = 0; - if (spron[i] == 0) + if (spr[i].on == 0) continue; - if (sprst[i] == SPR_restart) { + if (spr[i].state == SPR_restart) { fetch = 2; - spron[i] = 1; - } else if ((sprst[i] == SPR_waiting_start && sprvstart[i] == vpos) || sprst[i] == SPR_waiting_stop) { + spr[i].on = 1; + } else if ((spr[i].state == SPR_waiting_start && spr[i].vstart == vpos) || spr[i].state == SPR_waiting_stop) { fetch = 1; - sprst[i] = SPR_waiting_stop; + spr[i].state = SPR_waiting_stop; } - if (sprst[i] == SPR_waiting_stop && sprvstop[i] == vpos) { + if ((spr[i].state == SPR_waiting_stop || spr[i].state == SPR_waiting_start) && spr[i].vstop == vpos) { fetch = 2; - sprst[i] = SPR_waiting_start; + spr[i].state = SPR_waiting_start; } - if (fetch && dmaen(DMA_SPRITE)) { - uae_u16 data1 = chipmem_bank.wget(sprpt[i]); - uae_u16 data2 = chipmem_bank.wget(sprpt[i]+2); - sprpt[i] += 4; + if (fetch && dmaen (DMA_SPRITE)) { + uae_u16 data1 = chipmem_bank.wget (spr[i].pt); + uae_u16 data2 = chipmem_bank.wget (spr[i].pt + 2); + spr[i].pt += 4; if (fetch == 1) { /* Hack for X mouse auto-calibration */ if (i == 0 && !sprvbfl && ((sprpos[0] & 0xff) << 2) > 2 * DISPLAY_LEFT_SHIFT) { - spr0ctl=sprctl[0]; - spr0pos=sprpos[0]; - sprvbfl=2; + spr0ctl = sprctl[0]; + spr0pos = sprpos[0]; + sprvbfl = 2; } - SPRxDATB_1(data2, i); - SPRxDATA_1(data1, i); + SPRxDATB_1 (data2, i); + SPRxDATA_1 (data1, i); } else { - SPRxPOS_1(data1, i); - SPRxCTL_1(data2, i); + SPRxPOS_1 (data1, i); + SPRxCTL_1 (data2, i); } } } @@ -2637,8 +2408,8 @@ static void init_sprites (void) for (i = 0; i < 8; i++) { /* ???? */ - sprst[i] = SPR_stop; - spron[i] = 0; + spr[i].state = SPR_stop; + spr[i].on = 0; } memset (sprpos, 0, sizeof sprpos); @@ -2722,6 +2493,8 @@ void init_hardware_for_drawing_frame (vo static void vsync_handler (void) { + n_frames++; + if (currprefs.m68k_speed == -1) { frame_time_t curr_time = read_processor_time (); vsyncmintime += vsynctime; @@ -2767,10 +2540,7 @@ static void vsync_handler (void) cop_state.state = COP_read1; cop_state.vpos = 0; cop_state.hpos = 0; - cop_state.count = 0; - cop_state.do_move = 0; cop_state.ignore_next = 0; - cop_state.vdiw = DIW_waiting_start; init_hardware_frame (); @@ -2779,7 +2549,7 @@ static void vsync_handler (void) struct timeval tv; unsigned long int newtime; - gettimeofday(&tv,NULL); + gettimeofday (&tv,NULL); newtime = (tv.tv_sec-seconds_base) * 1000 + tv.tv_usec / 1000; if (!bogusframe) { @@ -2817,7 +2587,15 @@ static void vsync_handler (void) static void hsync_handler (void) { - update_copper (maxhpos); + int copper_was_active = eventtab[ev_copper].active; + if (copper_was_active) { + /* Could happen if horizontal wait position is too large. */ + eventtab[ev_copper].active = 0; + if (cop_state.state != COP_wait) + copper_was_active = 0; + } + if (copper_enabled_thisline && ! copper_was_active) + update_copper (maxhpos); finish_decisions (); do_modulos (current_hpos ()); @@ -2826,7 +2604,8 @@ static void hsync_handler (void) eventtab[ev_hsync].evtime += cycles - eventtab[ev_hsync].oldcycles; eventtab[ev_hsync].oldcycles = cycles; - CIA_hsync_handler(); + CIA_hsync_handler (); + DISK_update (); if (currprefs.produce_sound > 0) { int nr; @@ -2887,10 +2666,9 @@ static void hsync_handler (void) set_uae_int_flag (); INTREQ (0xA000); } - update_copper (0); - prepare_copper (); - if (eventtab[ev_copper].evtime == cycles && eventtab[ev_copper].active) - abort (); + /* See if there's a chance of a copper wait ending this line. */ + cop_state.hpos = 0; + compute_spcflag_copper (); } static void init_eventtab (void) @@ -2903,17 +2681,16 @@ static void init_eventtab (void) } eventtab[ev_cia].handler = CIA_handler; - eventtab[ev_copper].handler = do_copper; eventtab[ev_hsync].handler = hsync_handler; eventtab[ev_hsync].evtime = maxhpos + cycles; eventtab[ev_hsync].active = 1; + eventtab[ev_copper].handler = copper_handler; + eventtab[ev_copper].active = 0; eventtab[ev_blitter].handler = blitter_handler; eventtab[ev_blitter].active = 0; - eventtab[ev_diskblk].handler = diskblk_handler; - eventtab[ev_diskblk].active = 0; - eventtab[ev_diskindex].handler = diskindex_handler; - eventtab[ev_diskindex].active = 0; + eventtab[ev_disk].handler = DISK_handler; + eventtab[ev_disk].active = 0; events_schedule (); } @@ -2921,18 +2698,31 @@ static void init_eventtab (void) void customreset (void) { int i; + int zero = 0; #ifdef HAVE_GETTIMEOFDAY struct timeval tv; #endif - for (i = 0; i < sizeof current_colors.color_regs / sizeof *current_colors.color_regs; i++) - current_colors.color_regs[i] = -1; + if ((currprefs.chipset_mask & CSMASK_AGA) == 0) { + for (i = 0; i < 32; i++) { + current_colors.color_regs_ecs[i] = 0; + current_colors.acolors[i] = xcolors[0]; + } + } else { + for (i = 0; i < 256; i++) { + current_colors.color_regs_aga[i] = 0; + current_colors.acolors[i] = CONVERT_RGB (zero); + } + } + + n_frames = 0; expamem_reset (); + DISK_reset (); CIA_reset (); cycles = 0; - regs.spcflags &= SPCFLAG_BRK; + regs.spcflags &= SPCFLAG_BRK | SPCFLAG_MODE_CHANGE; vpos = 0; lof = 0; @@ -2952,7 +2742,8 @@ void customreset (void) clx_sprmask = 0xFF; clxdat = 0; - memset (sprarmed, 0, sizeof sprarmed); + /* Clear the armed flags of all sprites. */ + memset (spr, 0, sizeof spr); nr_armed = 0; dmacon = intena = 0; @@ -2961,7 +2752,7 @@ void customreset (void) diwstate = DIW_waiting_start; hdiwstate = DIW_waiting_start; copcon = 0; - dskdmaen = 0; + DSKLEN (0, 0); cycles = 0; bplcon4 = 0x11; /* Get AGA chipset into ECS compatibility mode */ @@ -3098,7 +2889,7 @@ uae_u32 REGPARAM2 custom_wget (uaecptr a case 0x004: return VPOSR(); case 0x006: return VHPOSR(); - case 0x008: return DSKDATR(); + case 0x008: return DSKDATR(current_hpos()); case 0x00A: return JOY0DAT(); case 0x00C: return JOY1DAT(); @@ -3108,7 +2899,7 @@ uae_u32 REGPARAM2 custom_wget (uaecptr a case 0x012: return POT0DAT(); case 0x016: return POTGOR(); case 0x018: return SERDATR(); - case 0x01A: return DSKBYTR(); + case 0x01A: return DSKBYTR(current_hpos()); case 0x01C: return INTENAR(); case 0x01E: return INTREQR(); case 0x07C: return DENISEID(); @@ -3134,7 +2925,7 @@ void REGPARAM2 custom_wput_1 (int hpos, switch (addr) { case 0x020: DSKPTH (value); break; case 0x022: DSKPTL (value); break; - case 0x024: DSKLEN (value); break; + case 0x024: DSKLEN (value, current_hpos()); break; case 0x026: DSKDAT (value); break; case 0x02A: VPOSW (value); break; @@ -3297,7 +3088,10 @@ void REGPARAM2 custom_wput_1 (int hpos, void REGPARAM2 custom_wput (uaecptr addr, uae_u32 value) { int hpos = current_hpos (); - update_copper (hpos); + /* Need to let the copper advance to the current position, but only if it + isn't in a waiting state. */ + if (copper_enabled_thisline && ! eventtab[ev_copper].active) + update_copper (hpos); custom_wput_1 (hpos, addr, value); } @@ -3306,13 +3100,13 @@ void REGPARAM2 custom_bput (uaecptr addr static int warned = 0; /* Is this correct now? (There are people who bput things to the upper byte of AUDxVOL). */ uae_u16 rval = (value << 8) | (value & 0xFF); - custom_wput(addr, rval); + custom_wput (addr, rval); if (!warned) write_log ("Byte put to custom register.\n"), warned++; } void REGPARAM2 custom_lput(uaecptr addr, uae_u32 value) { - custom_wput(addr & 0xfffe, value >> 16); - custom_wput((addr+2) & 0xfffe, (uae_u16)value); + custom_wput (addr & 0xfffe, value >> 16); + custom_wput ((addr + 2) & 0xfffe, (uae_u16)value); }