--- uae/src/custom.c 2018/04/24 16:38:39 1.1 +++ uae/src/custom.c 2018/04/24 16:53:06 1.1.1.11 @@ -1,9 +1,10 @@ /* * UAE - The Un*x Amiga Emulator - * + * * Custom chip emulation - * - * (c) 1995 Bernd Schmidt, Alessandro Bissacco + * + * Copyright 1995-1998 Bernd Schmidt + * Copyright 1995 Alessandro Bissacco */ #include "sysconfig.h" @@ -14,791 +15,1505 @@ #include "config.h" #include "options.h" +#include "threaddep/penguin.h" +#include "uae.h" +#include "gensound.h" +#include "sounddep/sound.h" #include "events.h" #include "memory.h" #include "custom.h" +#include "readcpu.h" #include "newcpu.h" #include "cia.h" #include "disk.h" #include "blitter.h" #include "xwin.h" -#include "os.h" +#include "joystick.h" +#include "audio.h" #include "keybuf.h" #include "serial.h" +#include "osemu.h" +#include "autoconf.h" +#include "gui.h" +#include "picasso96.h" +#include "drawing.h" -/* #define EMULATE_AGA */ +static unsigned int n_consecutive_skipped = 0; +static unsigned int total_skipped = 0; -#ifndef EMULATE_AGA -#define AGA_CHIPSET 0 -#else -#define AGA_CHIPSET 1 -#endif +#define SPRITE_COLLISIONS -#define SMART_UPDATE 1 +/* Mouse and joystick emulation */ -#define MAX_PLANES 8 +int buttonstate[3]; +static int mouse_x, mouse_y; +int joy0button, joy1button; +unsigned int joy0dir, joy1dir; -#define PIXEL_XPOS(HPOS) (((HPOS)*2 - 0x30)*(use_lores ? 1 : 2)) +/* Events */ -/* These are default values for mouse calibration. - * The first two are default values for mstepx and mstepy. - * The second line set the orizontal and vertical offset for amiga and X - * pointer matching - */ - -#define defstepx (1<<16) -#define defstepy (1<<16) -#define defxoffs 0 -#define defyoffs 0 - -/* Values below define mouse auto calibration process. - * They are not critical, change them if you want. - * The most important is calweight, which sets mouse adjustement rate */ +unsigned long int cycles, nextevent, is_lastline; +static int rpt_did_reset; +struct ev eventtab[ev_max]; -static const int docal = 60, xcaloff = 40, ycaloff = 20; -static const int calweight = 3; -static int lastsampledmx, lastsampledmy; +frame_time_t vsynctime, vsyncmintime; - /* - * Events - */ +static int vpos; +static uae_u16 lof; +static int next_lineno; +static enum nln_how nextline_how; +static int lof_changed = 0; -unsigned long int cycles, nextevent; -int vpos; -UWORD lof; +static uae_u32 sprtaba[256],sprtabb[256]; -struct ev eventtab[ev_max]; +/* + * Hardware registers of all sorts. + */ -int copper_active; +static void custom_wput_1 (int, uaecptr, uae_u32) REGPARAM; -static const int dskdelay = 2; /* FIXME: ??? */ +static uae_u16 cregs[256]; - /* - * hardware register values that are visible/can be written to by someone - */ +uae_u16 intena,intreq; +uae_u16 dmacon; +uae_u16 adkcon; /* used by audio code */ +static uae_u32 cop1lc,cop2lc,copcon; + +int maxhpos = MAXHPOS_PAL; +int maxvpos = MAXVPOS_PAL; +int minfirstline = MINFIRSTLINE_PAL; +int vblank_endline = VBLANK_ENDLINE_PAL; +int vblank_hz = VBLANK_HZ_PAL; +unsigned long syncbase; static int fmode; +static unsigned int beamcon0, new_beamcon0; +static int ntscmode = 0; -static UWORD cregs[256]; +#define MAX_SPRITES 32 -UWORD intena,intreq; -UWORD dmacon; -UWORD adkcon; /* used by audio code */ +/* 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 }; + +struct sprite { + uaecptr pt; + int on; + int xpos; + int vstart; + int vstop; + int armed; + enum sprstate state; +}; -static ULONG cop1lc,cop2lc,copcon; +static struct sprite spr[8]; -/* Kludge. FIXME: How does sprite restart after vsync work? */ -static int spron[8]; -static CPTR sprpt[8]; +static int sprite_vblank_endline = VBLANK_ENDLINE_NTSC + 2; -static ULONG bpl1dat,bpl2dat,bpl3dat,bpl4dat,bpl5dat,bpl6dat,bpl7dat,bpl8dat; -static WORD bpl1mod,bpl2mod; +static unsigned int sprdata[MAX_SPRITES], sprdatb[MAX_SPRITES], sprctl[MAX_SPRITES], sprpos[MAX_SPRITES]; +static int sprite_last_drawn_at[MAX_SPRITES]; +static int last_sprite_point, nr_armed; -xcolnr acolors[64]; +static uae_u32 bpl1dat, bpl2dat, bpl3dat, bpl4dat, bpl5dat, bpl6dat, bpl7dat, bpl8dat; +static uae_s16 bpl1mod, bpl2mod; -UBYTE *r_bplpt[MAX_PLANES]; -static CPTR bplpt[MAX_PLANES]; +static uaecptr bplpt[8]; +uae_u8 *real_bplpt[8]; /*static int blitcount[256]; blitter debug */ -struct bplinfo { -#if AGA_CHIPSET == 0 - /* X86.S will break if this isn't at the beginning of the structure. */ - UWORD color_regs[32]; -#else - ULONG color_regs[256]; -#endif - UWORD bplcon0,bplcon1,bplcon2,bplcon3,bplcon4; - UWORD diwstrt,diwstop,ddfstrt,ddfstop; - - UWORD sprdata[8], sprdatb[8], sprctl[8], sprpos[8]; - int sprarmed[8]; -} bpl_info; - -struct line_description -{ - int inborder; - xcolnr bordercol; - struct bplinfo bpl_info; - struct mem_notify_node *mnn; - CPTR bplpt[MAX_PLANES]; - int linedata_valid; -}; +static struct color_entry current_colors; +static unsigned int bplcon0, bplcon1, bplcon2, bplcon3, bplcon4; +static int nr_planes_from_bplcon0, corrected_nr_planes_from_bplcon0; +static unsigned int diwstrt, diwstop, diwhigh; +static int diwhigh_written; +static unsigned int ddfstrt, ddfstop; -static int frame_redraw_necessary; +/* The display and data fetch windows */ -/* 50 words give you 800 horizontal pixels. An A500 can't do that, so it ought - * to be enough. */ -#define MAX_WORDS_PER_LINE 50 -static UBYTE line_data[numscrlines * 2][MAX_PLANES][MAX_WORDS_PER_LINE*2]; -static struct line_description linedescr[numscrlines * 2]; - -static ULONG dskpt; -static UWORD dsklen,dsksync; - -static int joy0x, joy1x, joy0y, joy1y; -int joy0button; -UWORD joy0dir; -static int lastspr0x,lastspr0y,lastdiffx,lastdiffy,spr0pos,spr0ctl; -static int mstepx,mstepy,xoffs=defxoffs,yoffs=defyoffs; -static int sprvbfl; +enum diw_states +{ + DIW_waiting_start, DIW_waiting_stop +}; -static enum { normal_mouse, dont_care_mouse, follow_mouse } mousestate; +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; + +/* Sprite collisions */ +uae_u16 clxdat, clxcon; +int clx_sprmask; + +enum copper_states { + COP_stop, + COP_read1, COP_read2, + COP_bltwait, + COP_wait +}; - /* - * "hidden" hardware registers - */ +struct copper { + /* The current instruction words. */ + unsigned int i1, i2; + enum copper_states state; + /* Instruction pointer. */ + uaecptr ip; + int hpos, vpos; + unsigned int ignore_next; + int vcmp, hcmp; +}; -int dblpf_ind1[256], dblpf_ind2[256], dblpf_2nd1[256], dblpf_2nd2[256]; -int dblpf_aga1[256], dblpf_aga2[256], linear_map_256[256], lots_of_twos[256]; +static struct copper cop_state; +static int copper_enabled_thisline; +static int cop_min_waittime; -int dblpfofs[] = { 0, 2, 4, 8, 16, 32, 64, 128 }; +/* + * Statistics + */ -static ULONG coplc; -static UWORD copi1,copi2; +/* Used also by bebox.cpp */ +unsigned long int msecs = 0, frametime = 0, lastframetime = 0, timeframes = 0; +static unsigned long int seconds_base; +int bogusframe; -static enum { - COP_stop, COP_read, COP_wait, COP_move, COP_skip -} copstate; -static int dsklength; +static int current_change_set; -int plffirstline,plflastline,plfstrt,plfstop,plflinelen; -int diwfirstword,diwlastword; -int plfpri[3]; +#ifdef OS_WITHOUT_MEMORY_MANAGEMENT +/* sam: Those arrays uses around 7Mb of BSS... That seems */ +/* too much for AmigaDOS (uae crashes as soon as one loads */ +/* it. So I use a different strategy here (realloc the */ +/* arrays when needed. That strategy might be usefull for */ +/* computer with low memory. */ +struct sprite_draw *sprite_positions[2]; +struct color_change *color_changes[2]; +struct delay_change *delay_changes; +static int max_sprite_draw = 400; +static int delta_sprite_draw = 0; +static int max_color_change = 400; +static int delta_color_change = 0; +static int max_delay_change = 100; +static int delta_delay_change = 0; +#else +struct sprite_draw sprite_positions[2][MAX_REG_CHANGE]; +struct color_change color_changes[2][MAX_REG_CHANGE]; +/* We don't remember those across frames, that would be too much effort. + * We simply redraw the line whenever we see one of these. */ +struct delay_change delay_changes[MAX_REG_CHANGE]; +#endif -int max_diwstop, prev_max_diwstop; +struct decision line_decisions[2 * (MAXVPOS + 1) + 1]; +struct draw_info line_drawinfo[2][2 * (MAXVPOS + 1) + 1]; +struct color_entry color_tables[2][(MAXVPOS + 1) * 2]; -int dskdmaen; /* used in cia.c */ +struct sprite_draw *curr_sprite_positions, *prev_sprite_positions; +struct color_change *curr_color_changes, *prev_color_changes; +struct draw_info *curr_drawinfo, *prev_drawinfo; +struct color_entry *curr_color_tables, *prev_color_tables; -int bpldelay1, bpldelay2; -int bplehb, bplham, bpldualpf, bpldualpfpri, bplplanecnt, bplhires; +static int next_color_change, next_sprite_draw, next_delay_change; +static int next_color_entry, remembered_color_entry; +static int color_src_match, color_dest_match, color_compare_result; -static int pfield_fullline,pfield_linedone; -static int pfield_linedmaon; -static int pfield_lastpart_hpos,last_sprite; -static int slowline_nextpos, slowline_linepos, slowline_lasttoscr; +/* These few are only needed during/at the end of the scanline, and don't + * have to be remembered. */ +static int decided_bpl1mod, decided_bpl2mod, decided_nr_planes, decided_res; -union { - /* Let's try to align this thing. */ - double uupzuq; - long int cruxmedo; - unsigned char apixels[1000]; -} pixdata; +static char thisline_changed; -char spixels[1000]; /* for sprites */ -char spixstate[1000]; /* more sprites */ -ULONG ham_linebuf[1000]; -ULONG aga_linebuf[1000], *aga_lbufptr; +#ifdef SMART_UPDATE +#define MARK_LINE_CHANGED do { thisline_changed = 1; } while (0) +#else +#define MARK_LINE_CHANGED do { ; } while (0) +#endif -char *xlinebuffer; -int next_lineno, linetoscreen, line_in_border; +static struct decision thisline_decision; +static int modulos_added, plane_decided, color_decided, very_broken_program; /* - * Statistics + * helper functions */ -static unsigned long int msecs = 0, frametime = 0, timeframes = 0; -static unsigned long int seconds_base; -int bogusframe; +int rpt_available = 0; -/* - * helper functions - */ +void reset_frame_rate_hack (void) +{ + if (currprefs.m68k_speed != -1) + return; -static void pfield_doline_slow(int); -static void pfield_doline(void); -static void do_sprites(int, int); + if (! rpt_available) { + currprefs.m68k_speed = 0; + return; + } -int inhibit_frame; -static int framecnt = 0; + rpt_did_reset = 1; + is_lastline = 0; + vsyncmintime = read_processor_time() + vsynctime; + write_log ("Resetting frame rate hack\n"); +} -static __inline__ void count_frame(void) +void check_prefs_changed_custom (void) { - if (inhibit_frame) - framecnt = 1; - else { - framecnt++; - if (framecnt >= framerate) - framecnt = 0; + currprefs.gfx_framerate = changed_prefs.gfx_framerate; + /* Not really the right place... */ + if (currprefs.jport0 != changed_prefs.jport0 + || currprefs.jport1 != changed_prefs.jport1) { + currprefs.jport0 = changed_prefs.jport0; + currprefs.jport1 = changed_prefs.jport1; + joystick_setting_changed (); } + currprefs.immediate_blits = changed_prefs.immediate_blits; + currprefs.blits_32bit_enabled = changed_prefs.blits_32bit_enabled; + } -static __inline__ void setclr(UWORD *p, UWORD val) +STATIC_INLINE void setclr (uae_u16 *p, uae_u16 val) { - if (val & 0x8000) { + if (val & 0x8000) *p |= val & 0x7FFF; - } else { + else *p &= ~val; - } } -static __inline__ int current_hpos(void) +__inline__ int current_hpos (void) { return cycles - eventtab[ev_hsync].oldcycles; } -static void calcdiw(void) +STATIC_INLINE uae_u8 *pfield_xlateptr (uaecptr plpt, int bytecount) +{ + if (!chipmem_bank.check (plpt, bytecount)) { + static int count = 0; + if (!count) + count++, write_log ("Warning: Bad playfield pointer\n"); + return NULL; + } + return chipmem_bank.xlateaddr (plpt); +} + +STATIC_INLINE void docols (struct color_entry *colentry) { - if (use_lores) { - diwfirstword = (bpl_info.diwstrt & 0xFF) - 0x30 - 1; - diwlastword = (bpl_info.diwstop & 0xFF) + 0x100 - 0x30 - 1; + int i; + + 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 { - diwfirstword = (bpl_info.diwstrt & 0xFF) * 2 - 0x60 - 2; - diwlastword = (bpl_info.diwstop & 0xFF) * 2 + 0x200 - 0x60 - 2; + for (i = 0; i < 32; i++) { + int v = color_reg_get (colentry, i); + if (v < 0 || v > 4095) + continue; + colentry->acolors[i] = xcolors[v]; + } } - if (diwfirstword < 0) diwfirstword = 0; - if (diwlastword > max_diwstop) max_diwstop = diwlastword; - - plffirstline = bpl_info.diwstrt >> 8; - plflastline = bpl_info.diwstop >> 8; -#if 0 - /* This happens far too often. */ - if (plffirstline < minfirstline) { - fprintf(stderr, "Warning: Playfield begins before line %d!\n", minfirstline); - plffirstline = minfirstline; +} + +void notice_new_xcolors (void) +{ + int i; + + docols(¤t_colors); +/* docols(&colors_for_drawing);*/ + for (i = 0; i < (MAXVPOS + 1)*2; i++) { + docols(color_tables[0]+i); + docols(color_tables[1]+i); } -#endif - if ((plflastline & 0x80) == 0) plflastline |= 0x100; -#if 0 /* Turrican does this */ - if (plflastline > 313) { - fprintf(stderr, "Warning: Playfield out of range!\n"); - plflastline = 313; +} + +static void do_sprites (int currvp, int currhp); + +static void remember_ctable (void) +{ + if (remembered_color_entry == -1) { + /* The colors changed since we last recorded a color map. Record a + * new one. */ + color_reg_cpy (curr_color_tables + next_color_entry, ¤t_colors); + remembered_color_entry = next_color_entry++; } -#endif - plfstrt = bpl_info.ddfstrt; - plfstop = bpl_info.ddfstop; - if (plfstrt < 0x18) plfstrt = 0x18; - if (plfstop > 0xD8) plfstop = 0xD8; - if (plfstrt > plfstop) plfstrt = plfstop; + thisline_decision.ctable = remembered_color_entry; + if (color_src_match == -1 || color_dest_match != remembered_color_entry + || line_decisions[next_lineno].ctable != color_src_match) + { + /* The remembered comparison didn't help us - need to compare again. */ + int oldctable = line_decisions[next_lineno].ctable; + int changed = 0; + + if (oldctable == -1) { + changed = 1; + color_src_match = color_dest_match = -1; + } else { + color_compare_result = color_reg_cmp (&prev_color_tables[oldctable], ¤t_colors) != 0; + if (color_compare_result) + changed = 1; + color_src_match = oldctable; + color_dest_match = remembered_color_entry; + } + thisline_changed |= changed; + } else { + /* We know the result of the comparison */ + if (color_compare_result) + thisline_changed = 1; + } +} - /* ! 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... */ - plfstrt &= ~3; - plfstop &= ~3; - if ((fmode & 3) == 0) - plflinelen = (plfstop-plfstrt+15) & ~7; - else if ((fmode & 3) == 3) - plflinelen = (plfstop-plfstrt+63) & ~31; - else - plflinelen = (plfstop-plfstrt+31) & ~15; - +static void remember_ctable_for_border (void) +{ + remember_ctable (); } -/* - * Screen update macros/functions +/* Called to determine the state of the horizontal display window state + * machine at the current position. It might have changed since we last + * checked. */ +static void decide_diw (int hpos) +{ + int pix_hpos = PIXEL_XPOS (hpos); + if (hdiwstate == DIW_waiting_start && thisline_decision.diwfirstword == -1 + && pix_hpos >= diwfirstword && last_diw_pix_hpos < diwfirstword) + { + thisline_decision.diwfirstword = diwfirstword; + hdiwstate = DIW_waiting_stop; + /* Decide playfield delays only at DIW start, because they don't matter before and + * some programs change them after DDF start but before DIW start. */ + thisline_decision.bplcon1 = bplcon1; + if (thisline_decision.diwfirstword != line_decisions[next_lineno].diwfirstword) + MARK_LINE_CHANGED; + thisline_decision.diwlastword = -1; + } + if (hdiwstate == DIW_waiting_stop && thisline_decision.diwlastword == -1 + && 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) +{ + thisline_decision.which = 1; + + /* The latter condition might be able to happen in interlaced frames. */ + if (vpos >= minfirstline && (thisframe_first_drawn_line == -1 || vpos < thisframe_first_drawn_line)) + thisframe_first_drawn_line = vpos; + thisframe_last_drawn_line = vpos; + + thisline_decision.plfstrt = startpos; + thisline_decision.plflinelen = len; + + /* These are for comparison. */ + thisline_decision.bplcon0 = bplcon0; + thisline_decision.bplcon2 = bplcon2; + thisline_decision.bplcon4 = bplcon4; + 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 + || line_decisions[next_lineno].bplcon4 != thisline_decision.bplcon4 + || line_decisions[next_lineno].fmode != thisline_decision.fmode + ) +#endif /* SMART_UPDATE */ + thisline_changed = 1; +} + +/* Called when we already decided whether the line is playfield or border, + * but are no longer sure that this was such a good idea. This can make a + * difference only for very badly written software. + * + * We try to handle two cases: + * a) bitplane DMA gets turned off during a line which was decided as plane + * b) bitplane DMA turns on for all or some planes, either after the line was + * decided as border, or after we made an incorrect nr_planes decision. + * + * Examples of programs which need this: Majic 12 "Ray of Hope 2" demo + * (final large scrolltext) and Masterblazer (menu screen). + * + * There's no hope of catching all cases; we'd need a cycle based emulation + * for that. I'm getting increasingly convinced that that would be a good + * idea. */ +static int broken_plane_sub[8]; -static void decode_ham6 (int pix, int stoppos) +static void init_broken_program (void) { - static UWORD lastcolor; - ULONG *buf = ham_linebuf; - - if (!bplham || bplplanecnt != 6) + int i; + if (very_broken_program) return; - - if (pix <= diwfirstword) { - pix = diwfirstword; - lastcolor = bpl_info.color_regs[0]; - } - - while (pix < diwlastword && pix < stoppos) { - int pv = pixdata.apixels[pix]; - switch(pv & 0x30) { - case 0x00: lastcolor = bpl_info.color_regs[pv]; break; - case 0x10: lastcolor &= 0xFF0; lastcolor |= (pv & 0xF); break; - case 0x20: lastcolor &= 0x0FF; lastcolor |= (pv & 0xF) << 8; break; - case 0x30: lastcolor &= 0xF0F; lastcolor |= (pv & 0xF) << 4; break; - } - - buf[pix++] = lastcolor; - } -} - -static void decode_ham_aga (int pix, int stoppos) -{ - static ULONG lastcolor; - ULONG *buf = ham_linebuf; - - if (!bplham || (bplplanecnt != 6 && bplplanecnt != 8)) - return; - - if (pix <= diwfirstword) { - pix = diwfirstword; - lastcolor = bpl_info.color_regs[0]; - } - - if (bplplanecnt == 6) { - /* HAM 6 */ - while (pix < diwlastword && pix < stoppos) { - int pv = pixdata.apixels[pix]; - switch(pv & 0x30) { - case 0x00: lastcolor = bpl_info.color_regs[pv]; break; - case 0x10: lastcolor &= 0xFFFF00; lastcolor |= (pv & 0xF)*0x11; break; - case 0x20: lastcolor &= 0x00FFFF; lastcolor |= (pv & 0xF)*0x11 << 16; break; - case 0x30: lastcolor &= 0xFF00FF; lastcolor |= (pv & 0xF)*0x11 << 8; break; - } - buf[pix++] = lastcolor; - } - } else if (bplplanecnt == 8) { - /* HAM 8 */ - while (pix < diwlastword && pix < stoppos) { - int pv = pixdata.apixels[pix]; - switch(pv & 0x3) { - case 0x0: lastcolor = bpl_info.color_regs[pv >> 2]; break; - case 0x1: lastcolor &= 0xFFFF03; lastcolor |= (pv & 0xFC); break; - case 0x2: lastcolor &= 0x03FFFF; lastcolor |= (pv & 0xFC) << 16; break; - case 0x3: lastcolor &= 0xFF03FF; lastcolor |= (pv & 0xFC) << 8; break; - } - buf[pix++] = lastcolor; - } - } -} - -#define LINE_TO_SCR(NAME, TYPE, DO_DOUBLE) \ -static void NAME(int pix, int stoppos, int offset) \ -{ \ - TYPE *buf = (TYPE *)xlinebuffer; \ - int oldpix = pix; \ - buf -= pix; \ - if (DO_DOUBLE) offset /= sizeof(TYPE); \ - while (pix < diwfirstword && pix < stoppos) { \ - TYPE d = acolors[0]; \ - buf[pix] = d; if (DO_DOUBLE) buf[pix+offset] = d; \ - pix++; \ - } \ - if (bplham && bplplanecnt == 6) { \ - /* HAM 6 */ \ - while (pix < diwlastword && pix < stoppos) { \ - TYPE d = xcolors[ham_linebuf[pix]]; \ - buf[pix] = d; if (DO_DOUBLE) buf[pix+offset] = d; \ - pix++; \ - } \ - } else if (bpldualpf) { \ - /* Dual playfield */ \ - int *lookup = bpldualpfpri ? dblpf_ind2 : dblpf_ind1; \ - while (pix < diwlastword && pix < stoppos) { \ - int pixcol = pixdata.apixels[pix]; \ - TYPE d; \ - if (spixstate[pix]) { \ - d = acolors[pixcol]; \ - } else { \ - d = acolors[lookup[pixcol]]; \ - } \ - buf[pix] = d; if (DO_DOUBLE) buf[pix+offset] = d; \ - pix++; \ - } \ - } else { \ - while (pix < diwlastword && pix < stoppos) { \ - TYPE d = acolors[pixdata.apixels[pix]]; \ - buf[pix] = d; if (DO_DOUBLE) buf[pix+offset] = d; \ - pix++; \ - } \ - } \ - while (pix < stoppos) { \ - TYPE d = acolors[0]; \ - buf[pix] = d; if (DO_DOUBLE) buf[pix+offset] = d; \ - pix++; \ - } \ - xlinebuffer = (char *)(((TYPE *)xlinebuffer) + pix - oldpix); \ + very_broken_program = 1; + for (i = 0; i < 8; i++) + broken_plane_sub[i] = i >= decided_nr_planes || thisline_decision.which != 1 ? -1 : 0; } -/* WARNING: Not too much of this will work correctly yet. */ - -static void pfield_linetoscr_aga(int pix, int stoppos) +static void adjust_broken_program (int hpos) { - ULONG *buf = aga_lbufptr; + int tmp1, tmp2; int i; - int xor = (UBYTE)(bpl_info.bplcon4 >> 8); - int oldpix = pix; \ - buf -= pix; \ + /* Magic again... :-/ */ + hpos += 4; - for (i = 0; i < stoppos; i++) - pixdata.apixels[i] ^= xor; - - while (pix < diwfirstword && pix < stoppos) { - buf[pix++] = bpl_info.color_regs[0]; - } - if (bplham) { - while (pix < diwlastword && pix < stoppos) { - ULONG d = ham_linebuf[pix]; - buf[pix] = d; - pix++; - } - } else if (bpldualpf) { - /* Dual playfield */ - int *lookup = bpldualpfpri ? dblpf_aga2 : dblpf_aga1; - int *lookup_no = bpldualpfpri ? dblpf_2nd2 : dblpf_2nd1; - while (pix < diwlastword && pix < stoppos) { - int pixcol = pixdata.apixels[pix]; - int pfno = lookup_no[pixcol]; - - if (spixstate[pix]) { - buf[pix] = bpl_info.color_regs[pixcol]; - } else { - int val = lookup[pixdata.apixels[pix]]; - if (pfno == 2) - val += dblpfofs[(bpl_info.bplcon2 >> 10) & 7]; - buf[pix] = bpl_info.color_regs[val]; - } - pix++; - } - } else if (bplehb) { - while (pix < diwlastword && pix < stoppos) { - int pixcol = pixdata.apixels[pix]; - ULONG d = bpl_info.color_regs[pixcol]; - /* What about sprites? */ - if (pixcol & 0x20) - d = (d & 0x777777) >> 1; - buf[pix] = d; - pix++; - } + if (decided_res == RES_HIRES) { + tmp1 = hpos & 3; + tmp2 = hpos & ~3; + } else if (decided_res == RES_SUPERHIRES) { + tmp1 = hpos & 1; + tmp2 = hpos & ~1; } else { - while (pix < diwlastword && pix < stoppos) { - int pixcol = pixdata.apixels[pix]; - buf[pix] = bpl_info.color_regs[pixcol]; - pix++; - } + tmp1 = hpos & 7; + tmp2 = hpos & ~7; } - while (pix < stoppos) { - buf[pix++] = bpl_info.color_regs[0]; + for (i = 0; i < decided_nr_planes; i++) { + if (broken_plane_sub[i] != -1) + continue; + /* FIXME: superhires, AGA playfields */ + /* Actually, I don't want to support this crap for AGA if we can avoid it. */ + if (decided_res == RES_HIRES) { + broken_plane_sub[i] = (tmp2 - thisline_decision.plfstrt) / 4 * 2; + switch (i) { + case 3: broken_plane_sub[i] += 2; break; /* @@@ break was missing */ + case 2: broken_plane_sub[i] += (tmp1 >= 3 ? 2 : 0); break; + case 1: broken_plane_sub[i] += (tmp1 >= 2 ? 2 : 0); break; + case 0: break; + } + } else { + broken_plane_sub[i] = (tmp2 - thisline_decision.plfstrt) / 8 * 2; + switch (i) { + case 5: broken_plane_sub[i] += (tmp1 >= 3 ? 2 : 0); break; + case 4: broken_plane_sub[i] += (tmp1 >= 7 ? 2 : 0); break; + case 3: broken_plane_sub[i] += (tmp1 >= 2 ? 2 : 0); break; + case 2: broken_plane_sub[i] += (tmp1 >= 6 ? 2 : 0); break; + case 1: broken_plane_sub[i] += (tmp1 >= 4 ? 2 : 0); break; + case 0: break; + } + } } - aga_lbufptr += pix - oldpix; } -static void aga_translate32(int start, int stop) +STATIC_INLINE void set_decided_res (void) { - memcpy (((ULONG *)xlinebuffer) + start, aga_linebuf + start, 4*(stop-start)); + decided_res = RES_LORES; + if (bplcon0 & 0x8000) + decided_res = RES_HIRES; + if (bplcon0 & 0x40) + decided_res = RES_SUPERHIRES; } -static void aga_translate16(int start, int stop) +STATIC_INLINE void post_decide_line (int hpos) { - int i; - for (i = start; i < stop; i++) { - ULONG d = aga_linebuf[i]; - UWORD v = ((d & 0xF0) >> 4) | ((d & 0xF000) >> 8) | ((d & 0xF00000) >> 12); - ((UWORD *)xlinebuffer)[i] = xcolors[v]; + if (thisline_decision.which == 1 + && hpos < thisline_decision.plfstrt + thisline_decision.plflinelen + && (GET_PLANES (bplcon0) == 0 || !dmaen (DMA_BITPLANE))) + { + /* This is getting gross... */ + thisline_decision.plflinelen = hpos - thisline_decision.plfstrt; + thisline_decision.plflinelen &= 7; + if (thisline_decision.plflinelen == 0) + thisline_decision.which = -1; + /* ... especially THIS! */ + modulos_added = 1; + return; + } + + if (diwstate == DIW_waiting_start + || GET_PLANES (bplcon0) == 0 + || !dmaen (DMA_BITPLANE) + || hpos >= thisline_decision.plfstrt + thisline_decision.plflinelen) + return; + + if (thisline_decision.which == 1 + && hpos > thisline_decision.plfstrt + && decided_nr_planes < nr_planes_from_bplcon0) + { + set_decided_res (); + init_broken_program (); + decided_nr_planes = nr_planes_from_bplcon0; + thisline_decision.bplcon0 &= 0xFEF; + thisline_decision.bplcon0 |= bplcon0 & 0xF010; + adjust_broken_program (hpos); + MARK_LINE_CHANGED; /* Play safe. */ + return; + } + + if (thisline_decision.which != -1) + return; + +#if 0 /* Can't warn because Kickstart 1.3 does it at reset time ;-) */ + { + static int warned = 0; + if (!warned) { + write_log ("That program you are running is _really_ broken.\n"); + warned = 1; + } } +#endif + init_broken_program (); + + decided_nr_planes = nr_planes_from_bplcon0; + thisline_decision.bplcon0 &= 0xFEF; + thisline_decision.bplcon0 |= bplcon0 & 0xF010; + + MARK_LINE_CHANGED; /* Play safe. */ + decide_as_playfield (plfstrt, plflinelen); + adjust_broken_program (hpos); } -static void aga_translate8(int start, int stop) +static void decide_line_1 (int hpos) { - int i; - for (i = start; i < stop; i++) { - ULONG d = aga_linebuf[i]; - UWORD v = ((d & 0xF0) >> 4) | ((d & 0xF000) >> 8) | ((d & 0xF00000) >> 12); - ((UBYTE *)xlinebuffer)[i] = xcolors[v]; + do_sprites (vpos, hpos); + + /* Surprisingly enough, this seems to be correct here - putting this into + * decide_diw() results in garbage. */ + if (diwstate == DIW_waiting_start && vpos == plffirstline) { + diwstate = DIW_waiting_stop; + } + if (diwstate == DIW_waiting_stop && vpos == plflastline) { + diwstate = DIW_waiting_start; + } + + if (framecnt != 0) { +/* thisline_decision.which = -2; This doesn't do anything but hurt, I think. */ + return; + } + + if (!dmaen(DMA_BITPLANE) || diwstate == DIW_waiting_start || nr_planes_from_bplcon0 == 0) { + /* We don't want to draw this one. */ + thisline_decision.which = -1; + thisline_decision.plfstrt = plfstrt; + thisline_decision.plflinelen = plflinelen; + return; + } + + set_decided_res (); + decided_nr_planes = nr_planes_from_bplcon0; +#if 0 + /* The blitter gets slower if there's high bitplane activity. + * @@@ but the values must be different. FIXME */ + if (bltstate != BLT_done + && ((decided_res == RES_HIRES && decided_nr_planes > 2) + || (decided_res == RES_LORES && decided_nr_planes > 4))) + { + int pl = decided_nr_planes; + unsigned int n = (eventtab[ev_blitter].evtime-cycles); + if (n > plflinelen) + n = plflinelen; + n >>= 1; + if (decided_res == RES_HIRES) + pl <<= 1; + if (pl == 8) + eventtab[ev_blitter].evtime += plflinelen; + else if (pl == 6) + eventtab[ev_blitter].evtime += n*2; + else if (pl == 5) + eventtab[ev_blitter].evtime += n*3/2; + events_schedule(); } +#endif + decide_as_playfield (plfstrt, plflinelen); } +/* 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) +{ + if (thisline_decision.which == 0 && hpos >= plfstrt) + decide_line_1 (hpos); +} +/* Called when a color is about to be changed (write to a color register), + * but the new color has not been entered into the table yet. */ +static void record_color_change (int hpos, int regno, unsigned long value) +{ + /* Early positions don't appear on-screen. */ + if (framecnt != 0 || vpos < minfirstline || hpos < 0x18 + /*|| currprefs.emul_accuracy == 0*/) + return; -#define FILL_LINE(NAME, TYPE) \ -static void NAME(char *buf) \ -{ \ - TYPE *b = (TYPE *)buf; \ - int i;\ - int maxpos = gfxvidinfo.maxlinetoscr; \ - xcolnr col = acolors[0]; \ - if (!maxpos) maxpos = 796; \ - for (i = 0; i < maxpos; i++) \ - *b++ = col; \ + decide_diw (hpos); + decide_line (hpos); + + /* See if we can record the color table, but have not done so yet. + * @@@ There might be a minimal performance loss in case someone changes + * a color exactly at the start of the DIW. I don't think it can actually + * fail to work even in this case, but I'm not 100% sure. + * @@@ There might be a slightly larger performance loss if we're drawing + * this line as border... especially if there are changes in colors != 0 + * we might end up setting line_changed for no reason. FIXME */ + if (thisline_decision.diwfirstword >= 0 + && thisline_decision.which != 0) + { + if (thisline_decision.ctable == -1) + remember_ctable (); + } + + /* Changes outside the DIW can be ignored if the modified color is not the + * background color, or if the accuracy is < 2. */ + if ((regno != 0 || currprefs.emul_accuracy < 2) + && (diwstate == DIW_waiting_start || thisline_decision.diwfirstword < 0 + || thisline_decision.diwlastword >= 0 + || thisline_decision.which == 0 + || (thisline_decision.which == 1 && hpos >= thisline_decision.plfstrt + thisline_decision.plflinelen))) + return; + + /* 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 = color_reg_get (¤t_colors, 0); + if (line_decisions[next_lineno].color0 != value) + thisline_changed = 1; + } + /* Anything else gets recorded in the color_changes table. */ +#ifdef OS_WITHOUT_MEMORY_MANAGEMENT + if (next_color_change >= max_color_change) { + ++delta_color_change; + return; + } +#endif + curr_color_changes[next_color_change].linepos = hpos; + curr_color_changes[next_color_change].regno = regno; + curr_color_changes[next_color_change++].value = value; +} + +/* Stupid hack to get some Sanity demos working. */ +static void decide_delay (int hpos) +{ + static int warned; + + /* Don't do anything if we're outside the DIW. */ + if (thisline_decision.diwfirstword == -1 || thisline_decision.diwlastword > 0) + return; + decide_line (hpos); + /* Half-hearted attempt to get things right even when post_decide_line() changes + * the decision afterwards. */ + if (thisline_decision.which != 1) { + thisline_decision.bplcon1 = bplcon1; + return; + } + /* @@@ Could check here for DDF stopping earlier than DIW */ + +#ifdef OS_WITHOUT_MEMORY_MANAGEMENT + if (next_delay_change >= max_delay_change) { + ++delta_delay_change; + return; + } +#endif + delay_changes[next_delay_change].linepos = hpos; + delay_changes[next_delay_change++].value = bplcon1; + if (!warned) { + warned = 1; + write_log ("Program is torturing BPLCON1.\n"); + } } -LINE_TO_SCR(pfield_linetoscr_8, UBYTE, 0) -LINE_TO_SCR(pfield_linetoscr_16, UWORD, 0) -LINE_TO_SCR(pfield_linetoscr_32, ULONG, 0) -LINE_TO_SCR(pfield_linetoscr_8_double_slow, UBYTE, 1) -LINE_TO_SCR(pfield_linetoscr_16_double_slow, UWORD, 1) -LINE_TO_SCR(pfield_linetoscr_32_double_slow, ULONG, 1) +/* + * The decision which bitplane pointers to use is not made at plfstrt, since + * data fetch does not start for all planes at this point. Therefore, we wait + * for the end of the ddf area or the first write to any of the bitplane + * pointer registers, whichever comes last, before we decide which plane pointers + * to use. + * Call decide_line() before this function. + */ +static void decide_plane (int hpos) +{ + int i, bytecount; -FILL_LINE(fill_line_8, UBYTE) -FILL_LINE(fill_line_16, UWORD) -FILL_LINE(fill_line_32, ULONG) + if (framecnt != 0 || plane_decided) + return; -#define pfield_linetoscr_full8 pfield_linetoscr_8 -#define pfield_linetoscr_full16 pfield_linetoscr_16 -#define pfield_linetoscr_full32 pfield_linetoscr_32 + if (decided_nr_planes == -1 /* Still undecided */ + || hpos < thisline_decision.plfstrt + thisline_decision.plflinelen) + return; -#define pfield_linetoscr_full8_double pfield_linetoscr_8_double_slow -#define pfield_linetoscr_full16_double pfield_linetoscr_16_double_slow -#define pfield_linetoscr_full32_double pfield_linetoscr_32_double_slow + plane_decided = 1; -#if 1 && defined(X86_ASSEMBLY) -#undef pfield_linetoscr_full8 -#undef pfield_linetoscr_full16 -extern void pfield_linetoscr_full8(int, int, int) __asm__("pfield_linetoscr_full8"); -extern void pfield_linetoscr_full16(int, int, int) __asm__("pfield_linetoscr_full16"); -#undef pfield_linetoscr_full8_double -#undef pfield_linetoscr_full16_double + bytecount = plflinelen / RES_SHIFT (decided_res) * 2; -static void pfield_linetoscr_full8_double(int start, int stop, int offset) + if (bytecount > MAX_WORDS_PER_LINE * 2) { + /* Can't happen. */ + static int warned = 0; + if (!warned) + write_log ("Mysterious bug in decide_plane(). Please report.\n"); + warned = 1; + bytecount = 0; + } + if (!very_broken_program) { + 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); + if (real_ptr == NULL) + real_ptr = pfield_xlateptr (0, 0); +#ifdef SMART_UPDATE +#if 1 + if (thisline_changed) + memcpy (dataptr, real_ptr, bytecount); + else +#endif + thisline_changed |= memcmpy (dataptr, real_ptr, bytecount); +#else + real_bplpt[i] = real_ptr; +#endif + } + } else { + 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; + + pt -= broken_plane_sub[i]; + real_ptr = pfield_xlateptr (pt, bytecount); + if (real_ptr == NULL) + real_ptr = pfield_xlateptr(0, 0); +#ifdef SMART_UPDATE + if (!thisline_changed) + thisline_changed |= memcmpy (dataptr, real_ptr, bytecount); + else + memcpy (dataptr, real_ptr, bytecount); +#else + real_bplpt[i] = real_ptr; +#endif + } + } +} + +/* + * Called from the BPLxMOD routines, after a new value has been written. + * This routine decides whether the new value is already relevant for the + * current line. + */ +static void decide_modulos (int hpos) { - char *oldxlb = (char *)xlinebuffer; - pfield_linetoscr_full8(start,stop,offset); - xlinebuffer = oldxlb + offset; - pfield_linetoscr_full8(start,stop,offset); + /* All this effort just for the Sanity WOC demo... */ + decide_line (hpos); + if (decided_nr_planes != -1 + && hpos >= thisline_decision.plfstrt + thisline_decision.plflinelen) + return; + decided_bpl1mod = bpl1mod; + decided_bpl2mod = bpl2mod; } -static void pfield_linetoscr_full16_double(int start, int stop, int offset) + +/* + * Add the modulos to the bitplane pointers if data fetch is already + * finished for the current line. + * Call decide_plane() before calling this, so that we won't use the + * new values of the plane pointers for the current line. + */ +static void do_modulos (int hpos) { - char *oldxlb = (char *)xlinebuffer; - pfield_linetoscr_full16(start,stop,offset); - xlinebuffer = oldxlb + offset; - pfield_linetoscr_full16(start,stop,offset); + /* decided_nr_planes is != -1 if this line should be drawn by the + * display hardware, regardless of whether it fits on the emulated screen. + */ + if (decided_nr_planes != -1 && plane_decided && !modulos_added + && hpos >= thisline_decision.plfstrt + thisline_decision.plflinelen) + { + int bytecount = thisline_decision.plflinelen / RES_SHIFT (decided_res) * 2; + int add1 = bytecount + decided_bpl1mod; + int add2 = bytecount + decided_bpl2mod; + + if (!very_broken_program) { + switch (decided_nr_planes) { + case 8: bplpt[7] += add2; + case 7: bplpt[6] += add1; + case 6: bplpt[5] += add2; + case 5: bplpt[4] += add1; + case 4: bplpt[3] += add2; + case 3: bplpt[2] += add1; + case 2: bplpt[1] += add2; + case 1: bplpt[0] += add1; + } + } else switch (decided_nr_planes) { + case 8: bplpt[7] += add2 - broken_plane_sub[7]; + case 7: bplpt[6] += add1 - broken_plane_sub[6]; + case 6: bplpt[5] += add2 - broken_plane_sub[5]; + case 5: bplpt[4] += add1 - broken_plane_sub[4]; + case 4: bplpt[3] += add2 - broken_plane_sub[3]; + case 3: bplpt[2] += add1 - broken_plane_sub[2]; + case 2: bplpt[1] += add2 - broken_plane_sub[1]; + case 1: bplpt[0] += add1 - broken_plane_sub[0]; + } + + modulos_added = 1; + } } -#endif -static __inline__ void fill_line(int y) +STATIC_INLINE void record_sprite (int spr, int sprxp) { - switch (gfxvidinfo.pixbytes) { - case 1: fill_line_8(gfxvidinfo.bufmem + gfxvidinfo.rowbytes * y); break; - case 2: fill_line_16(gfxvidinfo.bufmem + gfxvidinfo.rowbytes * y); break; - case 4: fill_line_32(gfxvidinfo.bufmem + gfxvidinfo.rowbytes * y); break; + int pos = next_sprite_draw; + unsigned int data, datb; + +#ifdef OS_WITHOUT_MEMORY_MANAGEMENT + if(pos >= max_sprite_draw) { + ++delta_sprite_draw; + return; } +#endif + /* XXX FIXME, this isn't very clever, but it might do */ + for (;;) { + if (pos == curr_drawinfo[next_lineno].first_sprite_draw) + break; + if (curr_sprite_positions[pos-1].linepos < sprxp) + break; + if (curr_sprite_positions[pos-1].linepos == sprxp + && curr_sprite_positions[pos-1].num > spr) + break; + printf("Foo\n"); + pos--; + } + if (pos != next_sprite_draw) { + int pos2 = next_sprite_draw; + while (pos2 != pos) { + curr_sprite_positions[pos2] = curr_sprite_positions[pos2-1]; + pos2--; + } + } + curr_sprite_positions[pos].linepos = sprxp; + curr_sprite_positions[pos].num = spr; + curr_sprite_positions[pos].ctl = sprctl[spr]; + data = sprdata[spr]; + datb = sprdatb[spr]; + curr_sprite_positions[pos].datab = ((sprtaba[data & 0xFF] << 16) | sprtaba[data >> 8] + | (sprtabb[datb & 0xFF] << 16) | sprtabb[datb >> 8]); + next_sprite_draw++; } -static void pfield_do_linetoscr(int start, int stop) +static void decide_sprites (int hpos) { - int factor = use_lores ? 1 : 2; - int oldstop = stop; - int real_start, real_stop; - - start = PIXEL_XPOS(start); - if (start < 8*factor) - start = 8*factor; - stop = PIXEL_XPOS(stop); - if (stop > 406*factor) - stop = 406*factor; - - if (start >= stop) + int nrs[MAX_SPRITES], posns[MAX_SPRITES]; + int count, i; + int point = PIXEL_XPOS (hpos); + + if (framecnt != 0 || hpos < 0x14 || nr_armed == 0 || point == last_sprite_point) return; - if (stop <= gfxvidinfo.x_adjust) + + decide_diw (hpos); + decide_line (hpos); + + if (thisline_decision.which != 1) return; - - slowline_lasttoscr = oldstop; - if (start < gfxvidinfo.x_adjust) - real_start = gfxvidinfo.x_adjust; - else - real_start = start; - - if (gfxvidinfo.maxlinetoscr) { - real_stop = gfxvidinfo.x_adjust + gfxvidinfo.maxlinetoscr; - if (real_stop > stop) - real_stop = stop; + count = 0; + for (i = 0; i < 8; i++) { + int sprxp = spr[i].xpos; + int j, bestp; + + 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)) + continue; + + for (bestp = 0; bestp < count; bestp++) { + if (posns[bestp] > sprxp) + break; + if (posns[bestp] == sprxp && nrs[bestp] < i) + break; + } + for (j = count; j > bestp; j--) { + posns[j] = posns[j-1]; + nrs[j] = nrs[j-1]; + } + posns[j] = sprxp; + nrs[j] = i; + count++; + } + for (i = 0; i < count; i++) + record_sprite (nrs[i], posns[i]); + last_sprite_point = point; +} + +/* End of a horizontal scan line. Finish off all decisions that were not + * made yet. */ +static void finish_decisions (void) +{ + struct draw_info *dip; + struct draw_info *dip_old; + struct decision *dp; + int changed; + int hpos = current_hpos (); + + if (framecnt != 0) + return; + + decide_diw (hpos); + if (thisline_decision.which == 0) + decide_line_1 (hpos); + + /* Large DIWSTOP values can cause the stop position never to be + * reached, so the state machine always stays in the same state and + * there's a more-or-less full-screen DIW. */ + if (hdiwstate == DIW_waiting_stop) { + thisline_decision.diwlastword = max_diwlastword; + if (thisline_decision.diwlastword != line_decisions[next_lineno].diwlastword) + MARK_LINE_CHANGED; + } + + if (line_decisions[next_lineno].which != thisline_decision.which) + thisline_changed = 1; + decide_plane (hpos); + + dip = curr_drawinfo + next_lineno; + dip_old = prev_drawinfo + next_lineno; + dp = line_decisions + next_lineno; + changed = thisline_changed; + + if (thisline_decision.which == 1) { + record_diw_line (diwfirstword, diwlastword); + + decide_sprites (hpos); + + if (thisline_decision.bplcon1 != line_decisions[next_lineno].bplcon1) + changed = 1; + } + + dip->last_color_change = next_color_change; + dip->last_delay_change = next_delay_change; + dip->last_sprite_draw = next_sprite_draw; + + if (thisline_decision.ctable == -1) { + if (thisline_decision.which == 1) + remember_ctable (); + else + remember_ctable_for_border (); + } + if (thisline_decision.which == -1 && thisline_decision.color0 == 0xFFFFFFFFul) + 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; + + if (dip->first_delay_change != dip->last_delay_change) + changed = 1; + if (!changed + && (dip->nr_color_changes != dip_old->nr_color_changes + || (dip->nr_color_changes > 0 + && memcmp (curr_color_changes + dip->first_color_change, + prev_color_changes + dip_old->first_color_change, + dip->nr_color_changes * sizeof *curr_color_changes) != 0))) + changed = 1; + if (!changed && thisline_decision.which == 1 + && (dip->nr_sprites != dip_old->nr_sprites + || (dip->nr_sprites > 0 + && memcmp (curr_sprite_positions + dip->first_sprite_draw, + 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; + *dp = thisline_decision; } else - real_stop = stop; + /* The only one that may differ: */ + dp->ctable = thisline_decision.ctable; +} -#if AGA_CHIPSET == 0 - if (start == 8*factor && stop == 406*factor) { - switch (gfxvidinfo.pixbytes) { - case 1: pfield_linetoscr_full8 (real_start, real_stop, 0); break; - case 2: pfield_linetoscr_full16 (real_start, real_stop, 0); break; - case 4: pfield_linetoscr_full32 (real_start, real_stop, 0); break; - } +/* Set the state of all decisions to "undecided" for a new scanline. */ +static void reset_decisions (void) +{ + if (framecnt != 0) + return; + thisline_decision.which = 0; + decided_bpl1mod = bpl1mod; + 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; + if (hdiwstate == DIW_waiting_stop) { + thisline_decision.diwfirstword = PIXEL_XPOS (DISPLAY_LEFT_SHIFT/2); + if (thisline_decision.diwfirstword != line_decisions[next_lineno].diwfirstword) + MARK_LINE_CHANGED; + } + thisline_decision.ctable = -1; + thisline_decision.color0 = 0xFFFFFFFFul; + + thisline_changed = 0; + curr_drawinfo[next_lineno].first_color_change = next_color_change; + curr_drawinfo[next_lineno].first_delay_change = next_delay_change; + curr_drawinfo[next_lineno].first_sprite_draw = next_sprite_draw; + + /* memset(sprite_last_drawn_at, 0, sizeof sprite_last_drawn_at); */ + last_sprite_point = 0; + modulos_added = 0; + 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. */ +static void init_decisions (void) +{ + size_t i; + for (i = 0; i < sizeof line_decisions / sizeof *line_decisions; i++) { + line_decisions[i].which = -2; + } +} + +/* set PAL or NTSC timing variables */ + +static void init_hz (void) +{ + int isntsc; + + beamcon0 = new_beamcon0; + init_decisions (); + + isntsc = beamcon0 & 0x20 ? 0 : 1; + if (!isntsc) { + maxvpos = MAXVPOS_PAL; + maxhpos = MAXHPOS_PAL; + minfirstline = MINFIRSTLINE_PAL; + vblank_endline = VBLANK_ENDLINE_PAL; + vblank_hz = VBLANK_HZ_PAL; } else { - if (real_start >= real_stop) - return; - switch (gfxvidinfo.pixbytes) { - case 1: pfield_linetoscr_8 (real_start, real_stop, 0); break; - case 2: pfield_linetoscr_16 (real_start, real_stop, 0); break; - case 4: pfield_linetoscr_32 (real_start, real_stop, 0); break; - } + maxvpos = MAXVPOS_NTSC; + maxhpos = MAXHPOS_NTSC; + minfirstline = MINFIRSTLINE_NTSC; + vblank_endline = VBLANK_ENDLINE_NTSC; + vblank_hz = VBLANK_HZ_NTSC; } -#else - pfield_linetoscr_aga(real_start, real_stop); -#endif + vsynctime = syncbase / vblank_hz; + + write_log ("Using %s timing\n", isntsc ? "NTSC" : "PAL"); } -static void pfield_do_linetoscr_full(int double_line) +void expand_fetchmodes (int fmode, int bplcon0) { - int factor = use_lores ? 1 : 2; - int stop, start; - - start = 8*factor; - stop = 406*factor; - - if (start < gfxvidinfo.x_adjust) - start = gfxvidinfo.x_adjust; - - if (gfxvidinfo.maxlinetoscr) { - int tmp = gfxvidinfo.x_adjust + gfxvidinfo.maxlinetoscr; - if (tmp < stop) - stop = tmp; - } - -#if AGA_CHIPSET == 0 - if (double_line) { - switch (gfxvidinfo.pixbytes) { - case 1: pfield_linetoscr_full8_double (start, stop, gfxvidinfo.rowbytes); break; - case 2: pfield_linetoscr_full16_double (start, stop, gfxvidinfo.rowbytes); break; - case 4: pfield_linetoscr_full32_double (start, stop, gfxvidinfo.rowbytes); break; - } - } else - switch (gfxvidinfo.pixbytes) { - case 1: pfield_linetoscr_full8 (start, stop, 0); break; - case 2: pfield_linetoscr_full16 (start, stop, 0); break; - case 4: pfield_linetoscr_full32 (start, stop, 0); break; - } -#else - pfield_linetoscr_aga(start, stop); + 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; + int vstop = diwstop >> 8; + + if (diwhigh_written) { + hstrt |= ((diwhigh >> 5) & 1) << 8; + hstop |= ((diwhigh >> 13) & 1) << 8; + vstrt |= (diwhigh & 7) << 8; + vstop |= ((diwhigh >> 8) & 7) << 8; + } else { + hstop += 0x100; + if ((vstop & 0x80) == 0) + vstop |= 0x100; + } + + diwfirstword = coord_hw_to_window_x (hstrt - 1); + diwlastword = coord_hw_to_window_x (hstop - 1); + + if (diwlastword > max_diwlastword) + diwlastword = max_diwlastword; + if (diwfirstword < 0) + diwfirstword = 0; + if (diwlastword < 0) + diwlastword = 0; + + plffirstline = vstrt; + plflastline = vstop; + +#if 0 + /* This happens far too often. */ + if (plffirstline < minfirstline) { + fprintf(stderr, "Warning: Playfield begins before line %d!\n", minfirstline); + plffirstline = minfirstline; + } +#endif + +#if 0 /* Turrican does this */ + if (plflastline > 313) { + fprintf (stderr, "Warning: Playfield out of range!\n"); + plflastline = 313; + } #endif + plfstrt = ddfstrt; + plfstop = ddfstop; + if (plfstrt < 0x18) plfstrt = 0x18; + if (plfstop < 0x18) plfstop = 0x18; + if (plfstop > 0xD8) plfstop = 0xD8; + 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; } -/* - * This function is called whenever a hardware register that controls the - * screen display is modified. Usually, this routine does nothing. But in - * some cases, e.g., when a color changes in mid-screen, as in copper-plasma - * effects, this function switches the update method from the fast full-line - * update to the much slower single-color-clock update. - */ -static void pfield_may_need_update(int colreg) +/* Mousehack stuff */ + +#define defstepx (1<<16) +#define defstepy (1<<16) +#define defxoffs 0 +#define defyoffs 0 + +static const int docal = 60, xcaloff = 40, ycaloff = 20; +static const int calweight = 3; +static int lastsampledmx, lastsampledmy; +static int lastspr0x,lastspr0y,lastdiffx,lastdiffy,spr0pos,spr0ctl; +static int mstepx,mstepy,xoffs=defxoffs,yoffs=defyoffs; +static int sprvbfl; + +int lastmx, lastmy; +int newmousecounters; +int ievent_alive = 0; + +static enum { unknown_mouse, normal_mouse, dont_care_mouse, follow_mouse } mousestate; + +static void mousehack_setdontcare (void) { - int i; - - /* Ignore, if this happened before or after the DDF window */ - /* @@@ This breaks some copper plasmas. Not good... maybe a config - * option is needed. */ - if (framecnt != 0 || !pfield_linedmaon || current_hpos() <= plfstrt - || vpos < plffirstline || vpos < minfirstline || vpos >= plflastline - || next_lineno >= gfxvidinfo.maxline) + if (mousestate == dont_care_mouse) + return; + + write_log ("Don't care mouse mode set\n"); + mousestate = dont_care_mouse; + lastspr0x = lastmx; lastspr0y = lastmy; + mstepx = defstepx; mstepy = defstepy; +} + +static void mousehack_setfollow (void) +{ + if (mousestate == follow_mouse) + return; + + write_log ("Follow sprite mode set\n"); + mousestate = follow_mouse; + lastdiffx = lastdiffy = 0; + sprvbfl = 0; + spr0ctl = spr0pos = 0; + mstepx = defstepx; mstepy = defstepy; +} + +static uae_u32 mousehack_helper (void) +{ + int mousexpos, mouseypos; + +#ifdef PICASSO96 + if (picasso_on) { + mousexpos = lastmx - picasso96_state.XOffset; + mouseypos = lastmy - picasso96_state.YOffset; + } else +#endif { - return; + if (lastmy >= gfxvidinfo.height) + lastmy = gfxvidinfo.height - 1; + mouseypos = coord_native_to_amiga_y (lastmy) << 1; + mousexpos = coord_native_to_amiga_x (lastmx); } - /* - * If a color reg was modified, it is only important if we are within - * the DIW. - */ - if (PIXEL_XPOS(current_hpos()) <= diwfirstword && colreg) - return; - /* - * If we are past the DDF window, me might as well draw the complete - * line now. - */ - if (current_hpos() > plfstrt + plflinelen && pfield_fullline) { - if (!pfield_linedone) - pfield_doline(); - pfield_linedone = 1; - return; - } - - do_sprites(vpos, current_hpos()); - if (pfield_fullline) { - pfield_lastpart_hpos = 0; - memset(pixdata.apixels, 0, sizeof(pixdata.apixels)); - memset(spixstate,0,sizeof spixstate); - pfield_fullline = 0; - slowline_nextpos = -1; - slowline_linepos = 0; - slowline_lasttoscr = 0; - } else { - assert(pfield_lastpart_hpos <= current_hpos()); - } - for (i = pfield_lastpart_hpos; i < current_hpos(); i++) { - pfield_doline_slow(i); - } - if (colreg) { - pfield_do_linetoscr(slowline_lasttoscr, current_hpos()); - } - pfield_lastpart_hpos = current_hpos(); -} - -/* Apparently, the DMA bit is tested by the hardware at some point, - * presumably at the ddfstart position, to determine whether it - * ought to draw the line. - * This is probably not completely correct, but should not matter - * very much. - */ -static void pfield_calclinedma(void) + switch (m68k_dreg (regs, 0)) { + case 0: + return ievent_alive ? -1 : needmousehack (); + case 1: + ievent_alive = 10; + return mousexpos; + case 2: + return mouseypos; + } + return 0; +} + +void togglemouse (void) { - if (current_hpos() >= plfstrt) - return; - - pfield_linedmaon = dmaen(DMA_BITPLANE); + switch (mousestate) { + case dont_care_mouse: mousehack_setfollow (); break; + case follow_mouse: mousehack_setdontcare (); break; + default: break; /* Nnnnnghh! */ + } } - /* +STATIC_INLINE int adjust (int val) +{ + if (val > 127) + return 127; + else if (val < -127) + return -127; + return val; +} + +static void do_mouse_hack (void) +{ + int spr0x = ((spr0pos & 0xff) << 2) | ((spr0ctl & 1) << 1); + int spr0y = ((spr0pos >> 8) | ((spr0ctl & 4) << 6)) << 1; + int diffx, diffy; + + if (ievent_alive > 0) { + mouse_x = mouse_y = 0; + return; + } + switch (mousestate) { + case normal_mouse: + diffx = lastmx - lastsampledmx; + diffy = lastmy - lastsampledmy; + if (!newmousecounters) { + if (diffx > 127) diffx = 127; + if (diffx < -127) diffx = -127; + mouse_x += diffx; + if (diffy > 127) diffy = 127; + if (diffy < -127) diffy = -127; + mouse_y += diffy; + } + lastsampledmx += diffx; lastsampledmy += diffy; + break; + + 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: + if (sprvbfl && sprvbfl-- > 1) { + int mousexpos, mouseypos; + + if ((lastdiffx > docal || lastdiffx < -docal) + && lastspr0x != spr0x + && spr0x > plfstrt*4 + 34 + xcaloff + && spr0x < plfstop*4 - xcaloff) + { + int val = (lastdiffx << 16) / (spr0x - lastspr0x); + if (val >= 0x8000) + mstepx = (mstepx * (calweight - 1) + val) / calweight; + } + if ((lastdiffy > docal || lastdiffy < -docal) + && lastspr0y != spr0y + && spr0y > plffirstline + ycaloff + && spr0y < plflastline - ycaloff) + { + int val = (lastdiffy << 16) / (spr0y - lastspr0y); + if (val >= 0x8000) + mstepy = (mstepy * (calweight - 1) + val) / calweight; + } + if (lastmy >= gfxvidinfo.height) + lastmy = gfxvidinfo.height-1; + mouseypos = coord_native_to_amiga_y (lastmy) << 1; + mousexpos = coord_native_to_amiga_x (lastmx); + diffx = adjust ((((mousexpos + xoffs - spr0x) & ~1) * mstepx) >> 16); + diffy = adjust ((((mouseypos + yoffs - spr0y) & ~1) * mstepy) >> 16); + lastspr0x = spr0x; lastspr0y = spr0y; + lastdiffx = diffx; lastdiffy = diffy; + mouse_x += diffx; mouse_y += diffy; + } + break; + + default: + abort (); + } +} + +static int timehack_alive = 0; + +static uae_u32 timehack_helper (void) +{ +#ifdef HAVE_GETTIMEOFDAY + struct timeval tv; + if (m68k_dreg (regs, 0) == 0) + return timehack_alive; + + timehack_alive = 10; + + gettimeofday (&tv, NULL); + put_long (m68k_areg (regs, 0), tv.tv_sec - (((365 * 8 + 2) * 24 - 2) * 60 * 60)); + put_long (m68k_areg (regs, 0) + 4, tv.tv_usec); + return 0; +#else + return 2; +#endif +} + + /* * register functions */ - -static UWORD DMACONR(void) +STATIC_INLINE uae_u16 DENISEID (void) +{ + if (currprefs.chipset_mask & CSMASK_AGA) + return 0xF8; + if (currprefs.chipset_mask & CSMASK_ECS_DENISE) + return 0xFC; + return 0xFFFF; +} +STATIC_INLINE uae_u16 DMACONR (void) { return (dmacon | (bltstate==BLT_done ? 0 : 0x4000) | (blt_info.blitzero ? 0x2000 : 0)); } -static UWORD INTENAR(void) { return intena; } -UWORD INTREQR(void) +STATIC_INLINE uae_u16 INTENAR (void) { - return intreq | (use_serial ? 0x0001 : 0); + return intena; } -static UWORD ADKCONR(void) { return adkcon; } -static UWORD VPOSR(void) +uae_u16 INTREQR (void) { -#if AGA_CHIPSET == 1 - return (vpos >> 8) | lof | 0x2300; -#elif defined (ECS_AGNUS) - return (vpos >> 8) | lof | 0x2000; -#else - return (vpos >> 8) | lof; -#endif + return intreq /* | (currprefs.use_serial ? 0x0001 : 0) */; +} +STATIC_INLINE uae_u16 ADKCONR (void) +{ + return adkcon; +} +STATIC_INLINE uae_u16 VPOSR (void) +{ + unsigned int csbit = ntscmode ? 0x1000 : 0; + csbit |= (currprefs.chipset_mask & CSMASK_AGA) ? 0x2300 : 0; + csbit |= (currprefs.chipset_mask & CSMASK_ECS_AGNUS) ? 0x2000 : 0; + return (vpos >> 8) | lof | csbit; +} +static void VPOSW (uae_u16 v) +{ + if (lof != (v & 0x8000)) + lof_changed = 1; + lof = v & 0x8000; + /* + * This register is much more fun on a real Amiga. You can program + * refresh rates with it ;) But I won't emulate this... + */ } -static void VPOSW(UWORD v) { lof = v & 0x8000; } -static UWORD VHPOSR(void) { return (vpos << 8) | current_hpos(); } -static void COP1LCH(UWORD v) { cop1lc= (cop1lc & 0xffff) | ((ULONG)v << 16); } -static void COP1LCL(UWORD v) { cop1lc= (cop1lc & ~0xffff) | v; } -static void COP2LCH(UWORD v) { cop2lc= (cop2lc & 0xffff) | ((ULONG)v << 16); } -static void COP2LCL(UWORD v) { cop2lc= (cop2lc & ~0xffff) | v; } +STATIC_INLINE uae_u16 VHPOSR (void) +{ + return (vpos << 8) | current_hpos(); +} -static void COPJMP1(UWORD a) +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) { - coplc = cop1lc; copstate = COP_read; - eventtab[ev_copper].active = 1; eventtab[ev_copper].oldcycles = cycles; - eventtab[ev_copper].evtime = 4 + cycles; events_schedule(); - copper_active = 1; + int was_active = eventtab[ev_copper].active; + eventtab[ev_copper].active = 0; + if (was_active) + events_schedule (); + + cop_state.ignore_next = 0; + cop_state.state = COP_read1; + cop_state.vpos = vpos; + cop_state.hpos = current_hpos () & ~1; + + if (dmaen (DMA_COPPER)) { + copper_enabled_thisline = 1; + regs.spcflags |= SPCFLAG_COPPER; + } } -static void COPJMP2(UWORD a) + +static void COPJMP1 (uae_u16 a) { - coplc = cop2lc; copstate = COP_read; - eventtab[ev_copper].active = 1; eventtab[ev_copper].oldcycles = cycles; - eventtab[ev_copper].evtime = 4 + cycles; events_schedule(); - copper_active = 1; + cop_state.ip = cop1lc; + start_copper (); } -static void DMACON(UWORD v) +static void COPJMP2 (uae_u16 a) +{ + cop_state.ip = cop2lc; + start_copper (); +} + +STATIC_INLINE void COPCON (uae_u16 a) +{ + copcon = a; +} + +static void DMACON (uae_u16 v) { int i, need_resched = 0; - UWORD oldcon = dmacon; + uae_u16 oldcon = dmacon; + + decide_line (current_hpos ()); setclr(&dmacon,v); dmacon &= 0x1FFF; - pfield_calclinedma(); - - /* FIXME? Maybe we need to think a bit more about the master DMA enable + /* ??? post_decide_line (); */ + + /* 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)) { - COPJMP1(0); + if ((dmacon & DMA_COPPER) != (oldcon & DMA_COPPER)) { + if (eventtab[ev_copper].active) + need_resched = 1; + eventtab[ev_copper].active = 0; } - if ((dmacon & DMA_SPRITE) > (oldcon & DMA_SPRITE)) { - int i; - for (i = 0; i < 8; i++) - spron[i] = 1; + if ((dmacon & DMA_COPPER) > (oldcon & DMA_COPPER)) { + cop_state.ip = cop1lc; + cop_state.ignore_next = 0; + cop_state.state = COP_read1; + cop_state.vpos = vpos; + cop_state.hpos = current_hpos () & ~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) { count = 1; - fprintf(stderr, "warning: program is doing blitpri hacks.\n"); + write_log ("warning: program is doing blitpri hacks.\n"); } regs.spcflags |= SPCFLAG_BLTNASTY; } -#ifndef DONT_WANT_SOUND + if ((dmacon & (DMA_BLITPRI | DMA_BLITTER | DMA_MASTER)) != (DMA_BLITPRI | DMA_BLITTER | DMA_MASTER)) + regs.spcflags &= ~SPCFLAG_BLTNASTY; + + update_audio (); + for (i = 0; i < 4; i++) { struct audio_channel_data *cdp = audio_channel + i; - + cdp->dmaen = (dmacon & 0x200) && (dmacon & (1<dmaen) { if (cdp->state == 0) { @@ -807,280 +1522,406 @@ static void DMACON(UWORD v) cdp->wper = cdp->per; cdp->wlen = cdp->len; cdp->data_written = 2; - eventtab[ev_aud0 + i].oldcycles = eventtab[ev_hsync].oldcycles; - eventtab[ev_aud0 + i].evtime = eventtab[ev_hsync].evtime; - eventtab[ev_aud0 + i].active = 1; - need_resched = 1; /* not _really_ necessary here, but... */ + cdp->evtime = eventtab[ev_hsync].evtime - cycles; } } else { if (cdp->state == 1 || cdp->state == 5) { cdp->state = 0; + cdp->last_sample = 0; cdp->current_sample = 0; - eventtab[ev_aud0 + i].active = 0; - need_resched = 1; } } } -#endif - if (copper_active && !eventtab[ev_copper].active) { - eventtab[ev_copper].active = 1; - eventtab[ev_copper].oldcycles = cycles; - eventtab[ev_copper].evtime = 1 + cycles; - need_resched = 1; - } + if (need_resched) events_schedule(); } -static void INTENA(UWORD v) { setclr(&intena,v); regs.spcflags |= SPCFLAG_INT; } -void INTREQ(UWORD v) + +/*static int trace_intena = 0;*/ + +STATIC_INLINE void INTENA (uae_u16 v) +{ +/* if (trace_intena) + fprintf (stderr, "INTENA: %04x\n", v);*/ + setclr(&intena,v); regs.spcflags |= SPCFLAG_INT; +} +void INTREQ (uae_u16 v) { - setclr(&intreq,v); - regs.spcflags |= SPCFLAG_INT; - if ((v&0x8800)==0x0800) serdat&=0xbfff; - } + setclr(&intreq,v); + regs.spcflags |= SPCFLAG_INT; + if (( v & 0x8800) == 0x0800) + serdat &= 0xbfff; +} -static void ADKCON(UWORD v) { setclr(&adkcon,v); } +static void ADKCON (uae_u16 v) +{ + unsigned long t; -static void BPLPTH(UWORD v, int num) { bplpt[num] = (bplpt[num] & 0xffff) | ((ULONG)v << 16); } -static void BPLPTL(UWORD v, int num) { bplpt[num] = (bplpt[num] & ~0xffff) | (v & 0xFFFE); } + update_audio (); -/* - * I've seen the listing of an example program that changes - * from lo- to hires while a line is being drawn. That's - * awful, but we want to emulate it. - */ -static void BPLCON0(UWORD v) + setclr (&adkcon,v); + t = adkcon | (adkcon >> 4); + audio_channel[0].adk_mask = (((t >> 0) & 1) - 1); + audio_channel[1].adk_mask = (((t >> 1) & 1) - 1); + audio_channel[2].adk_mask = (((t >> 2) & 1) - 1); + audio_channel[3].adk_mask = (((t >> 3) & 1) - 1); +} + +static void BEAMCON0 (uae_u16 v) { - if (bpl_info.bplcon0 == v) + new_beamcon0 = v & 0x20; +} + +static void BPLPTH (int hpos, uae_u16 v, int num) +{ + decide_line (hpos); + decide_plane (hpos); + do_modulos (hpos); + bplpt[num] = (bplpt[num] & 0xffff) | ((uae_u32)v << 16); +} +static void BPLPTL (int hpos, uae_u16 v, int num) +{ + decide_line (hpos); + decide_plane (hpos); + do_modulos (hpos); + bplpt[num] = (bplpt[num] & ~0xffff) | (v & 0xfffe); +} + +static void BPLCON0 (int hpos, uae_u16 v) +{ + if (! (currprefs.chipset_mask & CSMASK_AGA)) { + v &= 0xFF0E; + /* The Sanity WOC demo needs this at one place (at the end of the "Party Effect") + * Disable bitplane DMA if someone tries to do more than 4 Hires bitplanes. */ + if ((v & 0xF000) > 0xC000) + v &= 0xFFF; + /* Don't want 7 lores planes either. */ + if ((v & 0x8000) == 0 && (v & 0x7000) == 0x7000) + v &= 0xEFFF; + } + if (bplcon0 == v) return; - pfield_may_need_update(0); - bpl_info.bplcon0 = v; - bplhires = (v & 0x8000) == 0x8000; - bplplanecnt = (v & 0x7000) >> 12; - bplham = (v & 0x800) == 0x800; - bpldualpf = (v & 0x400) == 0x400; - bplehb = (v & 0xFDC0) == 0x6000 && !(bpl_info.bplcon2 & 0x200); /* see below */ - calcdiw(); /* This should go away. */ + decide_line (hpos); + /* if ((bplcon0 ^ v) & 0x8000)*/ + calcdiw (); + bplcon0 = v; + nr_planes_from_bplcon0 = GET_PLANES (v); + + if (currprefs.chipset_mask & CSMASK_AGA) + /* It's not clear how the copper timings are affected by the number + * of bitplanes on AGA machines */ + corrected_nr_planes_from_bplcon0 = 4; + else + corrected_nr_planes_from_bplcon0 = nr_planes_from_bplcon0 << (bplcon0 & 0x8000 ? 1 : 0); + + post_decide_line (hpos); } -static void BPLCON1(UWORD v) + +STATIC_INLINE void BPLCON1 (int hpos, uae_u16 v) { - if (bpl_info.bplcon1 == v) + if (bplcon1 == v) return; - pfield_may_need_update(0); - bpl_info.bplcon1 = v; - bpldelay1 = v & 0xF; - bpldelay2 = (v >> 4) & 0xF; + decide_diw (hpos); + bplcon1 = v; + decide_delay (hpos); } -static void BPLCON2(UWORD v) +STATIC_INLINE void BPLCON2 (int hpos, uae_u16 v) { - if (bpl_info.bplcon2 == v) + if (bplcon2 == v) return; - pfield_may_need_update(0); - bpl_info.bplcon2 = v; - bpldualpfpri = (v & 0x40) == 0x40; - plfpri[1] = 1 << 2*(v & 7); - plfpri[2] = 1 << 2*((v>>3) & 7); - bplehb = (bpl_info.bplcon0 & 0xFDC0) == 0x6000 && !(v & 0x200); /* see above */ + decide_line (hpos); + bplcon2 = v; } -static void BPLCON3(UWORD v) +STATIC_INLINE void BPLCON3 (int hpos, uae_u16 v) { - if (bpl_info.bplcon3 == v) + if (bplcon3 == v) return; - pfield_may_need_update(0); - bpl_info.bplcon3 = v; + decide_line (hpos); + bplcon3 = v; } -static void BPLCON4(UWORD v) +STATIC_INLINE void BPLCON4 (int hpos, uae_u16 v) { - if (bpl_info.bplcon4 == v) + if (! (currprefs.chipset_mask & CSMASK_AGA)) return; - pfield_may_need_update(0); - bpl_info.bplcon4 = v; + if (bplcon4 == v) + return; + decide_line (hpos); + bplcon4 = v; } -static void BPL1MOD(UWORD v) +static void BPL1MOD (int hpos, uae_u16 v) { v &= ~1; - if (bpl1mod == v) + if ((uae_s16)bpl1mod == (uae_s16)v) return; - pfield_may_need_update(0); bpl1mod = v; + decide_modulos (hpos); } -static void BPL2MOD(UWORD v) -{ + +static void BPL2MOD (int hpos, uae_u16 v) +{ v &= ~1; - if (bpl2mod == v) + if ((uae_s16)bpl2mod == (uae_s16)v) return; - pfield_may_need_update(0); bpl2mod = v; + decide_modulos (hpos); } -static void BPL1DAT(UWORD v) { bpl1dat = v; } -static void BPL2DAT(UWORD v) { bpl2dat = v; } -static void BPL3DAT(UWORD v) { bpl3dat = v; } -static void BPL4DAT(UWORD v) { bpl4dat = v; } -static void BPL5DAT(UWORD v) { bpl5dat = v; } -static void BPL6DAT(UWORD v) { bpl6dat = v; } - -/* We call pfield_may_need_update() from here. Actually, - * I have no idea what happens if someone changes ddf or - * diw mid-line, and I don't really want to know. I doubt - * that this sort of thing was ever used to create a - * useful effect. - */ -static void DIWSTRT(UWORD v) +STATIC_INLINE void BPL1DAT (uae_u16 v) { - if (bpl_info.diwstrt == v) + bpl1dat = v; + if (thisline_decision.plfleft == -1) + thisline_decision.plfleft = current_hpos (); +} +/* We could do as well without those... */ +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) +{ + if (diwstrt == v && ! diwhigh_written) + return; + decide_line (hpos); + diwhigh_written = 0; + diwstrt = v; + calcdiw (); +} + +static void DIWSTOP (int hpos, uae_u16 v) +{ + if (diwstop == v && ! diwhigh_written) + return; + decide_line (hpos); + diwhigh_written = 0; + diwstop = v; + calcdiw (); +} + +static void DIWHIGH (int hpos, uae_u16 v) +{ + if (! (currprefs.chipset_mask & CSMASK_ECS_DENISE)) + return; + if (diwhigh_written && diwhigh == v) return; - pfield_may_need_update(0); - bpl_info.diwstrt = v; - calcdiw(); + decide_line (hpos); + diwhigh_written = 1; + diwhigh = v; + calcdiw (); } -static void DIWSTOP(UWORD v) + +static void DDFSTRT (int hpos, uae_u16 v) { - if (bpl_info.diwstop == v) + v &= 0xFC; + if (ddfstrt == v) return; - pfield_may_need_update(0); - bpl_info.diwstop = v; - calcdiw(); + decide_line (hpos); + ddfstrt = v; + calcdiw (); } -static void DDFSTRT(UWORD v) -{ - if (bpl_info.ddfstrt == v) +static void DDFSTOP (int hpos, uae_u16 v) +{ + v &= 0xFC; + if (ddfstop == v) return; - pfield_may_need_update(0); - bpl_info.ddfstrt = v; - calcdiw(); + decide_line (hpos); + ddfstop = v; + calcdiw (); } -static void DDFSTOP(UWORD v) -{ - if (bpl_info.ddfstop == v) + +static void FMODE (uae_u16 v) +{ + if (! (currprefs.chipset_mask & CSMASK_AGA)) return; - pfield_may_need_update(0); - bpl_info.ddfstop = v; - calcdiw(); + fmode = v; + calcdiw (); } -static void BLTADAT(UWORD v) +static void BLTADAT (uae_u16 v) { - maybe_blit(); - blt_info.bltadat = v; + maybe_blit(); + + blt_info.bltadat = v; } -static void BLTBDAT(UWORD v) +/* + * "Loading data shifts it immediately" says the HRM. Well, that may + * be true for BLTBDAT, but not for BLTADAT - it appears the A data must be + * loaded for every word so that AFWM and ALWM can be applied. + */ +static void BLTBDAT (uae_u16 v) { - maybe_blit(); - blt_info.bltbdat = v; + maybe_blit(); + + if (bltcon1 & 2) + blt_info.bltbhold = v << (bltcon1 >> 12); + else + blt_info.bltbhold = v >> (bltcon1 >> 12); + blt_info.bltbdat = v; } -static void BLTCDAT(UWORD v) { maybe_blit(); blt_info.bltcdat = v; } +static void BLTCDAT (uae_u16 v) { maybe_blit (); blt_info.bltcdat = v; } -static void BLTAMOD(UWORD v) { maybe_blit(); blt_info.bltamod = v & 0xFFFE; } -static void BLTBMOD(UWORD v) { maybe_blit(); blt_info.bltbmod = v & 0xFFFE; } -static void BLTCMOD(UWORD v) { maybe_blit(); blt_info.bltcmod = v & 0xFFFE; } -static void BLTDMOD(UWORD v) { maybe_blit(); blt_info.bltdmod = v & 0xFFFE; } +static void BLTAMOD (uae_u16 v) { maybe_blit (); blt_info.bltamod = (uae_s16)(v & 0xFFFE); } +static void BLTBMOD (uae_u16 v) { maybe_blit (); blt_info.bltbmod = (uae_s16)(v & 0xFFFE); } +static void BLTCMOD (uae_u16 v) { maybe_blit (); blt_info.bltcmod = (uae_s16)(v & 0xFFFE); } +static void BLTDMOD (uae_u16 v) { maybe_blit (); blt_info.bltdmod = (uae_s16)(v & 0xFFFE); } -static void BLTCON0(UWORD v) { maybe_blit(); bltcon0 = v; blinea_shift = v >> 12; } -/* The next category is "Most useless hardware register". +static void BLTCON0 (uae_u16 v) { maybe_blit (); bltcon0 = v; blinea_shift = v >> 12; } +/* The next category is "Most useless hardware register". * And the winner is... */ -static void BLTCON0L(UWORD v) { maybe_blit(); bltcon0 = (bltcon0 & 0xFF00) | (v & 0xFF); } -static void BLTCON1(UWORD v) { maybe_blit(); bltcon1 = v; } +static void BLTCON0L (uae_u16 v) +{ + if (! (currprefs.chipset_mask & CSMASK_ECS_AGNUS)) + return; + maybe_blit (); bltcon0 = (bltcon0 & 0xFF00) | (v & 0xFF); +} +static void BLTCON1 (uae_u16 v) { maybe_blit (); bltcon1 = v; } -static void BLTAFWM(UWORD v) { maybe_blit(); blt_info.bltafwm = v; } -static void BLTALWM(UWORD v) { maybe_blit(); blt_info.bltalwm = v; } +static void BLTAFWM (uae_u16 v) { maybe_blit (); blt_info.bltafwm = v; } +static void BLTALWM (uae_u16 v) { maybe_blit (); blt_info.bltalwm = v; } -static void BLTAPTH(UWORD v) { maybe_blit(); bltapt= (bltapt & 0xffff) | ((ULONG)(v & 0x1F) << 16); } -static void BLTAPTL(UWORD v) { maybe_blit(); bltapt= (bltapt & ~0xffff) | (v & 0xFFFE); } -static void BLTBPTH(UWORD v) { maybe_blit(); bltbpt= (bltbpt & 0xffff) | ((ULONG)(v & 0x1F) << 16); } -static void BLTBPTL(UWORD v) { maybe_blit(); bltbpt= (bltbpt & ~0xffff) | (v & 0xFFFE); } -static void BLTCPTH(UWORD v) { maybe_blit(); bltcpt= (bltcpt & 0xffff) | ((ULONG)(v & 0x1F) << 16); } -static void BLTCPTL(UWORD v) { maybe_blit(); bltcpt= (bltcpt & ~0xffff) | (v & 0xFFFE); } -static void BLTDPTH(UWORD v) { maybe_blit(); bltdpt= (bltdpt & 0xffff) | ((ULONG)(v & 0x1F) << 16); } -static void BLTDPTL(UWORD v) { maybe_blit(); bltdpt= (bltdpt & ~0xffff) | (v & 0xFFFE); } -static void BLTSIZE(UWORD v) +static void BLTAPTH (uae_u16 v) { maybe_blit (); bltapt = (bltapt & 0xffff) | ((uae_u32)v << 16); } +static void BLTAPTL (uae_u16 v) { maybe_blit (); bltapt = (bltapt & ~0xffff) | (v & 0xFFFE); } +static void BLTBPTH (uae_u16 v) { maybe_blit (); bltbpt = (bltbpt & 0xffff) | ((uae_u32)v << 16); } +static void BLTBPTL (uae_u16 v) { maybe_blit (); bltbpt = (bltbpt & ~0xffff) | (v & 0xFFFE); } +static void BLTCPTH (uae_u16 v) { maybe_blit (); bltcpt = (bltcpt & 0xffff) | ((uae_u32)v << 16); } +static void BLTCPTL (uae_u16 v) { maybe_blit (); bltcpt = (bltcpt & ~0xffff) | (v & 0xFFFE); } +static void BLTDPTH (uae_u16 v) { maybe_blit (); bltdpt = (bltdpt & 0xffff) | ((uae_u32)v << 16); } +static void BLTDPTL (uae_u16 v) { maybe_blit (); bltdpt = (bltdpt & ~0xffff) | (v & 0xFFFE); } + +static void BLTSIZE (uae_u16 v) { bltsize = v; - - maybe_blit(); + + maybe_blit (); blt_info.vblitsize = bltsize >> 6; blt_info.hblitsize = bltsize & 0x3F; if (!blt_info.vblitsize) blt_info.vblitsize = 1024; if (!blt_info.hblitsize) blt_info.hblitsize = 64; - - bltstate = BLT_init; - regs.spcflags |= SPCFLAG_BLIT; + + bltstate = BLT_init; + do_blitter (); } -static void BLTSIZV(UWORD v) + +static void BLTSIZV (uae_u16 v) { - maybe_blit(); + if (! (currprefs.chipset_mask & CSMASK_ECS_AGNUS)) + return; + maybe_blit (); oldvblts = v & 0x7FFF; } -static void BLTSIZH(UWORD v) + +static void BLTSIZH (uae_u16 v) { - maybe_blit(); + if (! (currprefs.chipset_mask & CSMASK_ECS_AGNUS)) + return; + maybe_blit (); blt_info.hblitsize = v & 0x7FF; blt_info.vblitsize = oldvblts; if (!blt_info.vblitsize) blt_info.vblitsize = 32768; if (!blt_info.hblitsize) blt_info.hblitsize = 0x800; - bltstate = BLT_init; - regs.spcflags |= SPCFLAG_BLIT; + bltstate = BLT_init; + do_blitter (); } -static void SPRxCTL_1(UWORD v, int num) + +STATIC_INLINE void SPRxCTL_1 (uae_u16 v, int num) { - bpl_info.sprctl[num] = v; - bpl_info.sprarmed[num] = 0; - if (bpl_info.sprpos[num] == 0 && v == 0) - spron[num] = 0; - else - spron[num] |= 2; + int sprxp; + sprctl[num] = v; + nr_armed -= spr[num].armed; + spr[num].armed = 0; + if (sprpos[num] == 0 && v == 0) { + spr[num].state = SPR_stop; + spr[num].on = 0; + } else + spr[num].state = SPR_waiting_start; + + 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 void SPRxPOS_1(UWORD v, int num) +STATIC_INLINE void SPRxPOS_1 (uae_u16 v, int num) { - bpl_info.sprpos[num] = v; + int sprxp; + sprpos[num] = v; + 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 void SPRxDATA_1(UWORD v, int num) +STATIC_INLINE void SPRxDATA_1 (uae_u16 v, int num) { - bpl_info.sprdata[num] = v; - bpl_info.sprarmed[num] = 1; + sprdata[num] = v; + nr_armed += 1 - spr[num].armed; + spr[num].armed = 1; } -static void SPRxDATB_1(UWORD v, int num) +STATIC_INLINE void SPRxDATB_1 (uae_u16 v, int num) { - bpl_info.sprdatb[num] = v; + sprdatb[num] = v; } -static void SPRxCTL(UWORD v, int num) { pfield_may_need_update(0); SPRxCTL_1(v, num); } -static void SPRxPOS(UWORD v, int num) { pfield_may_need_update(0); SPRxPOS_1(v, num); } -static void SPRxDATA(UWORD v, int num){ pfield_may_need_update(0); SPRxDATA_1(v, num); } -static void SPRxDATB(UWORD v, int num){ pfield_may_need_update(0); SPRxDATB_1(v, num); } -static void SPRxPTH(UWORD v, int num) +static void SPRxDATA (int hpos, uae_u16 v, int num) { decide_sprites (hpos); SPRxDATA_1 (v, num); } +static void SPRxDATB (int hpos, uae_u16 v, int num) { decide_sprites (hpos); SPRxDATB_1 (v, num); } +static void SPRxCTL (int hpos, uae_u16 v, int num) { decide_sprites (hpos); SPRxCTL_1 (v, num); } +static void SPRxPOS (int hpos, uae_u16 v, int num) { decide_sprites (hpos); SPRxPOS_1 (v, num); } +static void SPRxPTH (int hpos, uae_u16 v, int num) { - sprpt[num] &= 0xffff; - sprpt[num] |= (ULONG)v << 16; - if (!spron[num]) spron[num] = 1; + decide_sprites (hpos); + spr[num].pt &= 0xffff; + spr[num].pt |= (uae_u32)v << 16; + + if (spr[num].state == SPR_stop || vpos < sprite_vblank_endline) + spr[num].state = SPR_restart; + spr[num].on = 1; } -static void SPRxPTL(UWORD v, int num) +static void SPRxPTL (int hpos, uae_u16 v, int num) { - sprpt[num] &= ~0xffff; - sprpt[num] |= v; - if (!spron[num]) spron[num] = 1; + decide_sprites (hpos); + spr[num].pt &= ~0xffff; + spr[num].pt |= v; + + 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) +{ + clxcon = v; + clx_sprmask = (((v >> 15) << 7) | ((v >> 14) << 5) | ((v >> 13) << 3) | ((v >> 12) << 1) | 0x55); +} +static uae_u16 CLXDAT (void) +{ + uae_u16 v = clxdat; + clxdat = 0; + return v; } -static void COLOR(UWORD v, int num) +static void COLOR (int hpos, uae_u16 v, int num) { - int r,g,b; - int cr,cg,cb; - int colreg; - + v &= 0xFFF; -#if AGA_CHIPSET == 1 - { - ULONG cval; - colreg = ((bpl_info.bplcon3 >> 13) & 7) * 32 + num; + 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 = bpl_info.color_regs[colreg] >> 16; - cg = (bpl_info.color_regs[colreg] >> 8) & 0xFF; - cb = bpl_info.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 (bpl_info.bplcon3 & 0x200) { + if (bplcon3 & 0x200) { cr &= 0xF0; cr |= r; cg &= 0xF0; cg |= g; cb &= 0xF0; cb |= b; @@ -1090,1455 +1931,685 @@ static void COLOR(UWORD v, int num) cb = b + (b << 4); } cval = (cr << 16) | (cg << 8) | cb; - if (cval == bpl_info.color_regs[colreg]) + if (cval == current_colors.color_regs_aga[colreg]) return; - bpl_info.color_regs[colreg] = cval; - pfield_may_need_update(1); - } -#else - { - if (bpl_info.color_regs[num] == v) + + /* Call this with the old table still intact. */ + record_color_change (hpos, colreg, cval); + remembered_color_entry = -1; + current_colors.color_regs_aga[colreg] = cval; + current_colors.acolors[colreg] = CONVERT_RGB (cval); + } else { + if (current_colors.color_regs_ecs[num] == v) return; - pfield_may_need_update(1); - bpl_info.color_regs[num] = v; - acolors[num] = xcolors[v]; - acolors[num+32] = xcolors[(v >> 1) & 0x777]; + /* Call this with the old table still intact. */ + record_color_change (hpos, num, v); + remembered_color_entry = -1; + current_colors.color_regs_ecs[num] = v; + current_colors.acolors[num] = xcolors[v]; } -#endif } -static void DSKSYNC(UWORD v) { dsksync = v; } -static void DSKDAT(UWORD v) { fprintf(stderr, "DSKDAT written. Not good.\n"); } -static void DSKPTH(UWORD v) { dskpt = (dskpt & 0xffff) | ((ULONG)v << 16); } -static void DSKPTL(UWORD v) { dskpt = (dskpt & ~0xffff) | (v); } +static uae_u16 potgo_value; -static void DSKLEN(UWORD v) +static void POTGO (uae_u16 v) { - if (v & 0x8000) { - dskdmaen = dskdmaen == 1 ? 2 : 1; - } else { - dskdmaen = 0; - if (eventtab[ev_diskblk].active) - fprintf(stderr, "warning: Disk DMA aborted!\n"); - eventtab[ev_diskblk].active = 0; - events_schedule(); - - } - dsklen = dsklength = v; dsklength &= 0x3fff; - if (dskdmaen == 2 && dsksync != 0x4489 && (adkcon & 0x400)) { - fprintf(stderr, "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(); - } - } - } + potgo_value = v; } -static UWORD DSKBYTR(void) +static uae_u16 POTGOR (void) { - UWORD v = (dsklen >> 1) & 0x6000; - UWORD mfm, byte; - if (DISK_GetData(&mfm, &byte)) - v |= 0x8000; - v |= byte; - if (dsksync == mfm) v |= 0x1000; - return v; -} + uae_u16 v = (potgo_value | (potgo_value >> 1)) & 0x5500; -static UWORD DSKDATR(void) -{ - UWORD mfm, byte; - DISK_GetData(&mfm, &byte); - return mfm; -} -static UWORD POTGOR(void) -{ - UWORD v = 0xFF00; - if (buttonstate[2]) - v &= 0xFBFF; + v |= (~potgo_value & 0xAA00) >> 1; + + if (JSEM_ISMOUSE (0, &currprefs)) { + if (buttonstate[2]) + v &= 0xFBFF; + + if (buttonstate[1]) + v &= 0xFEFF; + } else if (JSEM_ISJOY0 (0, &currprefs) || JSEM_ISJOY1 (0, &currprefs)) { + if (joy0button & 2) v &= 0xfbff; + if (joy0button & 4) v &= 0xfeff; + } + + if (JSEM_ISJOY0 (1, &currprefs) || JSEM_ISJOY1 (1, &currprefs)) { + if (joy1button & 2) v &= 0xbfff; + if (joy1button & 4) v &= 0xefff; + } - if (buttonstate[1]) - v &= 0xFEFF; - return v; } -static UWORD POT0DAT(void) + +static uae_u16 POT0DAT (void) { - static UWORD cnt = 0; - if (buttonstate[2]) - cnt = ((cnt + 1) & 0xFF) | (cnt & 0xFF00); - if (buttonstate[1]) - cnt += 0x100; - + static uae_u16 cnt = 0; + if (JSEM_ISMOUSE (0, &currprefs)) { + if (buttonstate[2]) + cnt = ((cnt + 1) & 0xFF) | (cnt & 0xFF00); + if (buttonstate[1]) + cnt += 0x100; + } + return cnt; } -static UWORD JOY0DAT(void) { return joy0x + (joy0y << 8); } -static UWORD JOY1DAT(void) +static uae_u16 JOY0DAT (void) { + if (JSEM_ISMOUSE (0, &currprefs)) { + do_mouse_hack (); + return ((uae_u8)mouse_x) + ((uae_u16)mouse_y << 8); + } return joy0dir; } -static void JOYTEST(UWORD v) +static uae_u16 JOY1DAT (void) { - joy0x = joy1x = v & 0xFC; - joy0y = joy1y = (v >> 8) & 0xFC; -} -static void AUDxLCH(int nr, UWORD v) { audio_channel[nr].lc = (audio_channel[nr].lc & 0xffff) | ((ULONG)v << 16); } -static void AUDxLCL(int nr, UWORD v) { audio_channel[nr].lc = (audio_channel[nr].lc & ~0xffff) | (v & 0xFFFE); } -static void AUDxPER(int nr, UWORD v) -{ - static int warned = 0; - if (v <= 0) { - if (!warned) - fprintf(stderr, "Broken program accessing the sound hardware\n"), warned++; - v = 65535; + if (JSEM_ISMOUSE (1, &currprefs)) { + do_mouse_hack (); + return ((uae_u8)mouse_x) + ((uae_u16)mouse_y << 8); + } + return joy1dir; +} +static void JOYTEST (uae_u16 v) +{ + if (JSEM_ISMOUSE (0, &currprefs)) { + mouse_x = v & 0xFC; + mouse_y = (v >> 8) & 0xFC; } - - if (v < maxhpos/2 && produce_sound < 3) - v = maxhpos/2; - - audio_channel[nr].per = v; } -static void AUDxVOL(int nr, UWORD v) { audio_channel[nr].vol = v & 64 ? 63 : v & 63; } -static void AUDxLEN(int nr, UWORD v) { audio_channel[nr].len = v; } +/* Determine which cycles are available for the copper in a display + * with a agiven number of planes. */ +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, 0, -1, 0, -1, 0, -1 }, + { 0, -1, 0, -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 } +}; + +static unsigned int waitmasktab[256]; -static int copcomp(void) +STATIC_INLINE int copper_in_playfield (enum diw_states diw, int hpos) { - UWORD vp = vpos & (((copi2 >> 8) & 0x7F) | 0x80); - UWORD hp = current_hpos() & (copi2 & 0xFE); - UWORD vcmp = copi1 >> 8; - UWORD hcmp = copi1 & 0xFE; - return (vp > vcmp || (vp == vcmp && hp >= hcmp)) && ((copi2 & 0x8000) || !(DMACONR() & 0x4000)); + return diw == DIW_waiting_stop && hpos >= plfstrt && hpos < plfstrt + plflinelen; } -/* - * Calculate the minimum number of cycles after which the - * copper comparison becomes true. This is quite tricky. I hope it works. - */ -static int calc_copcomp_true(int currvpos, int currhpos) -{ - UWORD vp = currvpos & (((copi2 >> 8) & 0x7F) | 0x80); - UWORD hp = currhpos & (copi2 & 0xFE); - UWORD vcmp = copi1 >> 8; - UWORD hcmp = copi1 & 0xFE; - int copper_time_hpos; - int cycleadd = maxhpos - currhpos; - int coptime = 0; - - if ((vp > vcmp || (vp == vcmp && hp >= hcmp)) && ((copi2 & 0x8000) || !(DMACONR() & 0x4000))) - return 0; - - try_again: - - while (vp < vcmp) { - currvpos++; - if (currvpos > maxvpos + 1) - return -1; - currhpos = 0; - coptime += cycleadd; - cycleadd = maxhpos; - vp = currvpos & (((copi2 >> 8) & 0x7F) | 0x80); - } - if (coptime > 0 && bplhires && bplplanecnt == 4) - return coptime; - copper_time_hpos = currhpos; - hp = copper_time_hpos & (copi2 & 0xFE); - if (!(vp > vcmp)) { - while (hp < hcmp-2) { - currhpos++; - /* Copper DMA is turned off in Hires 4 bitplane mode */ - if (!bplhires || bplplanecnt < 4 || !dmaen(DMA_BITPLANE) - || currhpos < plfstrt-2 || currhpos > (plfstop+4)) - copper_time_hpos++; - - if (currhpos > maxhpos-4) { - /* Now, what? There might be a good position on the - * next line. But it can also be the FFFF FFFE - * case. - */ - currhpos = 0; - currvpos++; - vp = currvpos & (((copi2 >> 8) & 0x7F) | 0x80); - goto try_again; - } - coptime++; - hp = copper_time_hpos & (copi2 & 0xFE); - } - } - if (coptime == 0) /* waiting for the blitter */ - return 1; - - return coptime; -} - -static void copper_read(void) -{ - if (dmaen(DMA_COPPER)){ - copi1 = chipmem_bank.wget(coplc); - copi2 = chipmem_bank.wget(coplc+2); - coplc += 4; - eventtab[ev_copper].oldcycles = cycles; - eventtab[ev_copper].evtime = ((copi1 & 1) ? (copi2 & 1) ? 10 : 8 : 4) + cycles; - copstate = (copi1 & 1) ? (copi2 & 1) ? COP_skip : COP_wait : COP_move; - } else { - copstate = COP_read; - eventtab[ev_copper].active = 0; - } -} +STATIC_INLINE int copper_cant_read (enum diw_states diw, int hpos, int planes) +{ + int t; -static void do_copper(void) -{ - switch(copstate){ - case COP_read: - copper_read(); - break; - case COP_move: - if (copi1 >= (copcon & 2 ? 0x40 : 0x80)) { - custom_bank.wput(copi1,copi2); - copper_read(); - } else { - copstate = COP_stop; - eventtab[ev_copper].active = 0; - copper_active = 0; - } - break; - case COP_skip: - if (calc_copcomp_true(vpos, current_hpos()) == 0) - coplc += 4; - copper_read(); - break; - case COP_wait: { - int coptime = calc_copcomp_true(vpos, current_hpos()); - if (coptime < 0) { - copstate = COP_stop; - eventtab[ev_copper].active = 0; - copper_active = 0; - } else { - if (!coptime) - copper_read(); - else { - eventtab[ev_copper].evtime = coptime + cycles; - eventtab[ev_copper].oldcycles = cycles; - } - } - break; - } - case COP_stop: - eventtab[ev_copper].active = 0; - copper_active = 0; - break; - } -} + /* @@@ */ + if (hpos >= ((maxhpos - 2) & ~1)) + return 1; -static void diskblk_handler(void) -{ - regs.spcflags |= SPCFLAG_DISK; - eventtab[ev_diskblk].active = 0; + if (currprefs.chipset_mask & CSMASK_AGA) + /* FIXME */ + return 0; + + if (! copper_in_playfield (diw, hpos)) + return 0; + + t = cycles_for_plane[planes][hpos & 7]; +#if 0 + if (t == -1) + abort (); +#endif + return t; } -void do_disk(void) +STATIC_INLINE int dangerous_reg (int reg) { - if (dskdmaen != 2 && (regs.spcflags & SPCFLAG_DISK)) { - fprintf(stderr, "BUG!\n"); - return; - } - if (dmaen(0x10)){ - if (dsklen & 0x4000) { - if (!chipmem_bank.check (dskpt, 2*dsklength)) { - fprintf(stderr, "warning: Bad disk write DMA pointer\n"); - } else { - UBYTE *mfmp = get_real_address (dskpt); - int i; - DISK_InitWrite(); - - for (i = 0; i < dsklength; i++) { - UWORD d = (*mfmp << 8) + *(mfmp+1); - mfmwrite[i] = d; - mfmp += 2; - } - DISK_WriteData(dsklength); - } - } else { - int result = DISK_ReadMFM (dskpt); - } - regs.spcflags &= ~SPCFLAG_DISK; - INTREQ(0x9002); - dskdmaen = -1; - } + /* 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 __inline__ void pfield_fetchdata(void) +static void update_copper (int until_hpos) { - if (dmaen(0x100) && pfield_linedmaon) { - switch(bplplanecnt){ - case 8: - bpl8dat = chipmem_bank.wget(bplpt[7]); bplpt[7] += 2; bpl8dat <<= 7; - case 7: - bpl7dat = chipmem_bank.wget(bplpt[6]); bplpt[6] += 2; bpl7dat <<= 6; - case 6: - bpl6dat = chipmem_bank.wget(bplpt[5]); bplpt[5] += 2; bpl6dat <<= 5; - case 5: - bpl5dat = chipmem_bank.wget(bplpt[4]); bplpt[4] += 2; bpl5dat <<= 4; - case 4: - bpl4dat = chipmem_bank.wget(bplpt[3]); bplpt[3] += 2; bpl4dat <<= 3; - case 3: - bpl3dat = chipmem_bank.wget(bplpt[2]); bplpt[2] += 2; bpl3dat <<= 2; - case 2: - bpl2dat = chipmem_bank.wget(bplpt[1]); bplpt[1] += 2; bpl2dat <<= 1; - case 1: - bpl1dat = chipmem_bank.wget(bplpt[0]); bplpt[0] += 2; - } - } -} + int vp = vpos & (((cop_state.i2 >> 8) & 0x7F) | 0x80); + int c_hpos = cop_state.hpos; -static void do_sprites(int currvp, int currhp) -{ - int i; - int maxspr = currhp/4 - 0x18/4; - - if (currvp == 0) - return; - if (maxspr < 0) - return; - if (maxspr > 7) - maxspr = 7; - - for(i = last_sprite; i <= maxspr; i++) { - int vstart = (bpl_info.sprpos[i] >> 8) | ((bpl_info.sprctl[i] << 6) & 0x100); - int vstop = (bpl_info.sprctl[i] >> 8) | ((bpl_info.sprctl[i] << 7) & 0x100); - if ((vstart <= currvp && vstop >= currvp) || spron[i] == 1) { - if (dmaen(0x20)) { - UWORD data1 = chipmem_bank.wget(sprpt[i]); - UWORD data2 = chipmem_bank.wget(sprpt[i]+2); - sprpt[i] += 4; - - if (vstop != currvp && spron[i] != 1) { - /* Hack for X mouse auto-calibration */ - if (i == 0 && !sprvbfl && ((bpl_info.sprpos[0]&0xff)<<2)>0x60) { - spr0ctl=bpl_info.sprctl[0]; - spr0pos=bpl_info.sprpos[0]; - sprvbfl=2; - } - SPRxDATB_1(data2, i); - SPRxDATA_1(data1, i); - } else { - SPRxPOS_1(data1, i); - SPRxCTL_1(data2, i); - } - } - } - } - last_sprite = maxspr + 1; -} + if (eventtab[ev_copper].active) + abort (); -static __inline__ void pfield_modulos(int add) -{ - switch(bplplanecnt){ - case 8: - bplpt[7] += add + bpl2mod; - case 7: - bplpt[6] += add + bpl1mod; - case 6: - bplpt[5] += add + bpl2mod; - case 5: - bplpt[4] += add + bpl1mod; - case 4: - bplpt[3] += add + bpl2mod; - case 3: - bplpt[2] += add + bpl1mod; - case 2: - bplpt[1] += add + bpl2mod; - case 1: - bplpt[0] += add + bpl1mod; - } -} + if (cop_state.state == COP_wait && vp < cop_state.vcmp) + abort (); -#if AGA_CHIPSET == 0 -static void pfield_sprite (int num, int sprxp, UWORD data, UWORD datb, int lores) -{ - int i; + until_hpos &= ~1; - int *lookup = bpldualpf ? (bpldualpfpri ? dblpf_ind2 : dblpf_ind1) : linear_map_256; - int *lookup_no = bpldualpf ? (bpldualpfpri ? dblpf_2nd2 : dblpf_2nd1) : lots_of_twos; + if (until_hpos > (maxhpos & ~1)) + until_hpos = maxhpos & ~1; - for(i = 15; i >= 0; i--, data >>= 1, datb >>= 1) { - int sprxpos = sprxp + i*(lores ? 1 : 2); - int plno; - int col; - - /* When doing the slow line update, the following condition can - * happen. Lower-numbered sprites get the higher priority. */ - if (spixstate[sprxpos] & ((1 << num)-1)) - continue; + for (;;) { + int old_hpos = c_hpos; + int hp; - /* Check the priority, but only if we did not already put a sprite - * pixel at this position. If there's already a sprite pixel here, - * the priority was previously tested. */ - if (!spixstate[sprxpos]) { - /* ??? What about hires mode when one hires pixel is 0, enabling the - * sprite, and the other is != 0, blocking it? */ - plno = lookup_no[pixdata.apixels[sprxpos]]; - if (plno != 0 && (1 << num) >= plfpri[plno]) - continue; - } + if (c_hpos > until_hpos) + break; - if ((bpl_info.sprctl[num] & 0x80) && (num & 1)) { - /* Attached sprite */ - col = ((data << 2) & 4) + ((datb << 3) & 8); - spixstate[sprxpos] |= 1 << (num-1); - spixels[sprxpos] = col; - } else { - col = (data & 1) | ((datb << 1) & 2); - if (spixstate[sprxpos] & (1 << num)) { - /* Finish attached sprite */ - /* Did the upper half of the sprite have any bits set? */ - if (spixstate[sprxpos] & (1 << (num+1))) - col += spixels[sprxpos]; - /* Is there any sprite pixel at this position at all? */ - if (!col) { - spixstate[sprxpos] &= ~(3 << num); - } else - col += 16; - } else { - if (col) { - col |= 16 | ((num & 6) << 1); + /* So we know about the vertical DIW. */ + decide_line (c_hpos); + + 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: + 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; + break; + } + /* Perform moves immediately. */ + if ((cop_state.i1 & 1) == 0) { + 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; + } + + 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; + + /* 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; } } - } - if (col) { - pixdata.apixels[sprxpos] = col; - spixstate[sprxpos] |= 1<= 0; i--, data >>= 1, datb >>= 1) { - int sprxpos = sprxp + i*(lores ? 1 : 2); - int plno; - int col; - - /* When doing the slow line update, the following condition can - * happen. Lower-numbered sprites get the higher priority. */ - if (spixstate[sprxpos] & ((1 << num)-1)) - continue; + if (eventtab[ev_copper].active /* || ! (regs.spcflags & SPCFLAG_COPPER) */) + abort (); - /* Check the priority, but only if we did not already put a sprite - * pixel at this position. If there's already a sprite pixel here, - * the priority was previously tested. */ - if (!spixstate[sprxpos]) { - /* ??? What about hires mode when one hires pixel is 0, enabling the - * sprite, and the other is != 0, blocking it? */ - plno = lookup_no[pixdata.apixels[sprxpos]]; - if (plno != 0 && (1 << num) >= plfpri[plno]) - continue; + if (cop_state.state == COP_read2) { + ip += 2; + c_hpos += 2; + goto inner; } - - if ((bpl_info.sprctl[num] & 0x80) && (num & 1)) { - /* Attached sprite */ - col = ((data << 2) & 4) + ((datb << 3) & 8); - spixstate[sprxpos] |= 1 << (num-1); - spixels[sprxpos] = col; - } else { - col = (data & 1) | ((datb << 1) & 2); - if (spixstate[sprxpos] & (1 << num)) { - /* Finish attached sprite */ - /* Did the upper half of the sprite have any bits set? */ - if (spixstate[sprxpos] & (1 << (num+1))) - col += spixels[sprxpos]; - /* Is there any sprite pixel at this position at all? */ - if (!col) { - spixstate[sprxpos] &= ~(3 << num); - } else - col += ((bpl_info.bplcon4 << (num & 1 ? 4 : 0)) & 240); - } else { - if (col) { - col |= ((bpl_info.bplcon4 << (num & 1 ? 4 : 0)) & 240) | ((num & 6) << 1); - } - } + while (c_hpos < (maxhpos & ~1)) { + word = chipmem_bank.wget (ip); + ip += 4; + c_hpos += 4; + inner: + if ((word & 1) || dangerous_reg (word)) + break; } - if (col) { - pixdata.apixels[sprxpos] = col; - spixstate[sprxpos] |= 1<= 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 __inline__ UBYTE *pfield_xlateptr(CPTR plpt, int bytecount) -{ - if (!chipmem_bank.check(plpt,bytecount)) { - static int count = 0; - if (count < 5) { - count++; - fprintf(stderr, "Warning: Bad playfield pointer"); - if (count == 5) fprintf(stderr, " (no further warnings)"); - fprintf(stderr, "\n"); - } - return NULL; - } - return chipmem_bank.xlateaddr(plpt); } -static void pfield_doline_slow_h(int currhpos) +static void compute_spcflag_copper (void) { - int xpos = currhpos * 4 - 0x60; - - if (bplhires) { - int offs1 = xpos + 16 + bpldelay1*2; - int offs2 = xpos + 16 + bpldelay2*2; - - int pix; - for(pix = 15; pix >= 0; pix--) { - switch(bplplanecnt) { - case 8: - pixdata.apixels[pix + offs2] |= bpl8dat & 0x80; bpl8dat >>= 1; - case 7: - pixdata.apixels[pix + offs1] |= bpl7dat & 0x40; bpl7dat >>= 1; - case 6: - pixdata.apixels[pix + offs2] |= bpl6dat & 0x20; bpl6dat >>= 1; - case 5: - pixdata.apixels[pix + offs1] |= bpl5dat & 0x10; bpl5dat >>= 1; - case 4: - pixdata.apixels[pix + offs2] |= bpl4dat & 0x8; bpl4dat >>= 1; - case 3: - pixdata.apixels[pix + offs1] |= bpl3dat & 0x4; bpl3dat >>= 1; - case 2: - pixdata.apixels[pix + offs2] |= bpl2dat & 0x2; bpl2dat >>= 1; - case 1: - pixdata.apixels[pix + offs1] |= bpl1dat & 0x1; bpl1dat >>= 1; - } - } - } else { - int offs1 = xpos + 32 + bpldelay1*2; - int offs2 = xpos + 32 + bpldelay2*2; - - int pix; - for(pix = 30; pix >= 0; pix -= 2) { - switch(bplplanecnt) { - case 8: - pixdata.apixels[pix + offs2] |= bpl8dat & 0x80; - pixdata.apixels[pix + offs2 + 1] |= bpl8dat & 0x80; bpl8dat >>= 1; - case 7: - pixdata.apixels[pix + offs1] |= bpl7dat & 0x40; - pixdata.apixels[pix + offs1 + 1] |= bpl7dat & 0x40; bpl7dat >>= 1; - case 6: - pixdata.apixels[pix + offs2] |= bpl6dat & 0x20; - pixdata.apixels[pix + offs2 + 1] |= bpl6dat & 0x20; bpl6dat >>= 1; - case 5: - pixdata.apixels[pix + offs1] |= bpl5dat & 0x10; - pixdata.apixels[pix + offs1 + 1] |= bpl5dat & 0x10; bpl5dat >>= 1; - case 4: - pixdata.apixels[pix + offs2] |= bpl4dat & 0x8; - pixdata.apixels[pix + offs2 + 1] |= bpl4dat & 0x8; bpl4dat >>= 1; - case 3: - pixdata.apixels[pix + offs1] |= bpl3dat & 0x4; - pixdata.apixels[pix + offs1 + 1] |= bpl3dat & 0x4; bpl3dat >>= 1; - case 2: - pixdata.apixels[pix + offs2] |= bpl2dat & 0x2; - pixdata.apixels[pix + offs2 + 1] |= bpl2dat & 0x2; bpl2dat >>= 1; - case 1: - pixdata.apixels[pix + offs1] |= bpl1dat & 0x1; - pixdata.apixels[pix + offs1 + 1] |= bpl1dat & 0x1; bpl1dat >>= 1; - } - } - } -} - -static void pfield_doline_slow_l(int currhpos) -{ - int xpos = currhpos * 2 - 0x30; - - if (bplhires) { - int offs1 = xpos + 8 + bpldelay1; - int offs2 = xpos + 8 + bpldelay2; - - int pix; - for(pix = 7; pix >= 0; pix--) { - switch(bplplanecnt) { - case 8: - pixdata.apixels[pix + offs2] |= bpl8dat & 0x80; bpl8dat >>= 2; - case 7: - pixdata.apixels[pix + offs1] |= bpl7dat & 0x40; bpl7dat >>= 2; - case 6: - pixdata.apixels[pix + offs2] |= bpl6dat & 0x20; bpl6dat >>= 2; - case 5: - pixdata.apixels[pix + offs1] |= bpl5dat & 0x10; bpl5dat >>= 2; - case 4: - pixdata.apixels[pix + offs2] |= bpl4dat & 0x8; bpl4dat >>= 2; - case 3: - pixdata.apixels[pix + offs1] |= bpl3dat & 0x4; bpl3dat >>= 2; - case 2: - pixdata.apixels[pix + offs2] |= bpl2dat & 0x2; bpl2dat >>= 2; - case 1: - pixdata.apixels[pix + offs1] |= bpl1dat & 0x1; bpl1dat >>= 2; - } - } - } else { - int offs1 = xpos + 16 + bpldelay1; - int offs2 = xpos + 16 + bpldelay2; - - int pix; - for(pix = 15; pix >= 0; pix --) { - switch(bplplanecnt) { - case 8: - pixdata.apixels[pix + offs2] |= bpl8dat & 0x80; bpl8dat >>= 1; - case 7: - pixdata.apixels[pix + offs1] |= bpl7dat & 0x40; bpl7dat >>= 1; - case 6: - pixdata.apixels[pix + offs2] |= bpl6dat & 0x20; bpl6dat >>= 1; - case 5: - pixdata.apixels[pix + offs1] |= bpl5dat & 0x10; bpl5dat >>= 1; - case 4: - pixdata.apixels[pix + offs2] |= bpl4dat & 0x8; bpl4dat >>= 1; - case 3: - pixdata.apixels[pix + offs1] |= bpl3dat & 0x4; bpl3dat >>= 1; - case 2: - pixdata.apixels[pix + offs2] |= bpl2dat & 0x2; bpl2dat >>= 1; - case 1: - pixdata.apixels[pix + offs1] |= bpl1dat & 0x1; bpl1dat >>= 1; - } - } - } -} + copper_enabled_thisline = 0; + regs.spcflags &= ~SPCFLAG_COPPER; + if (! dmaen (DMA_COPPER) || cop_state.state == COP_stop || cop_state.state == COP_bltwait) + return; -ULONG hirestab_h[256][2]; -ULONG lorestab_h[256][4]; + if (cop_state.state == COP_wait) { + int vp = vpos & (((cop_state.i2 >> 8) & 0x7F) | 0x80); -ULONG hirestab_l[256][1]; -ULONG lorestab_l[256][2]; + if (vp < cop_state.vcmp) + return; + copper_enabled_thisline = 1; -static void gen_pfield_tables(void) -{ - int i; - union { - struct { - UBYTE a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p; - } foo; - struct { - ULONG a, b, c, d; - } bar; - } baz; - - for (i = 0; i < 256; i++) { - /* We lose every second pixel in HiRes if UAE runs in a 320x200 screen. */ - baz.foo.a = i & 64 ? 1 : 0; - baz.foo.b = i & 16 ? 1 : 0; - baz.foo.c = i & 4 ? 1 : 0; - baz.foo.d = i & 1 ? 1 : 0; - hirestab_l[i][0] = baz.bar.a; - - baz.foo.a = i & 128 ? 1 : 0; - baz.foo.b = i & 64 ? 1 : 0; - baz.foo.c = i & 32 ? 1 : 0; - baz.foo.d = i & 16 ? 1 : 0; - baz.foo.e = i & 8 ? 1 : 0; - baz.foo.f = i & 4 ? 1 : 0; - baz.foo.g = i & 2 ? 1 : 0; - baz.foo.h = i & 1 ? 1 : 0; - lorestab_l[i][0] = baz.bar.a; - lorestab_l[i][1] = baz.bar.b; - } - - for (i = 0; i < 256; i++) { - baz.foo.a = i & 128 ? 1 : 0; - baz.foo.b = i & 64 ? 1 : 0; - baz.foo.c = i & 32 ? 1 : 0; - baz.foo.d = i & 16 ? 1 : 0; - baz.foo.e = i & 8 ? 1 : 0; - baz.foo.f = i & 4 ? 1 : 0; - baz.foo.g = i & 2 ? 1 : 0; - baz.foo.h = i & 1 ? 1 : 0; - hirestab_h[i][0] = baz.bar.a; - hirestab_h[i][1] = baz.bar.b; - - baz.foo.a = i & 128 ? 1 : 0; - baz.foo.b = i & 128 ? 1 : 0; - baz.foo.c = i & 64 ? 1 : 0; - baz.foo.d = i & 64 ? 1 : 0; - baz.foo.e = i & 32 ? 1 : 0; - baz.foo.f = i & 32 ? 1 : 0; - baz.foo.g = i & 16 ? 1 : 0; - baz.foo.h = i & 16 ? 1 : 0; - baz.foo.i = i & 8 ? 1 : 0; - baz.foo.j = i & 8 ? 1 : 0; - baz.foo.k = i & 4 ? 1 : 0; - baz.foo.l = i & 4 ? 1 : 0; - baz.foo.m = i & 2 ? 1 : 0; - baz.foo.n = i & 2 ? 1 : 0; - baz.foo.o = i & 1 ? 1 : 0; - baz.foo.p = i & 1 ? 1 : 0; - lorestab_h[i][0] = baz.bar.a; - lorestab_h[i][1] = baz.bar.b; - lorestab_h[i][2] = baz.bar.c; - lorestab_h[i][3] = baz.bar.d; - } -} + if (0 && vp == cop_state.vcmp) { + int hp = (cop_state.hpos + 2) & (cop_state.i2 & 0xFE); + cop_min_waittime = cop_state.hcmp - hp - 4; -static __inline__ void pfield_orword_hires_h(int data, unsigned char *dp, int bit) -{ - ULONG *pixptr = (ULONG *)dp; - - *pixptr |= hirestab_h[data >> 8][0] << bit; - *(pixptr+1) |= hirestab_h[data >> 8][1] << bit; - *(pixptr+2) |= hirestab_h[data & 255][0] << bit; - *(pixptr+3) |= hirestab_h[data & 255][1] << bit; -} + /* 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; + } + } + } -static __inline__ void pfield_orword_lores_h(int data, unsigned char *dp, int bit) -{ - ULONG *pixptr = (ULONG *)dp; - - *pixptr |= lorestab_h[data >> 8][0] << bit; - *(pixptr+1) |= lorestab_h[data >> 8][1] << bit; - *(pixptr+2) |= lorestab_h[data >> 8][2] << bit; - *(pixptr+3) |= lorestab_h[data >> 8][3] << bit; - *(pixptr+4) |= lorestab_h[data & 255][0] << bit; - *(pixptr+5) |= lorestab_h[data & 255][1] << bit; - *(pixptr+6) |= lorestab_h[data & 255][2] << bit; - *(pixptr+7) |= lorestab_h[data & 255][3] << bit; + copper_enabled_thisline = 1; + regs.spcflags |= SPCFLAG_COPPER; } -static __inline__ void pfield_setword_hires_h(int data, unsigned char *dp, int bit) +static void copper_handler (void) { - ULONG *pixptr = (ULONG *)dp; - - *pixptr = hirestab_h[data >> 8][0] << bit; - *(pixptr+1) = hirestab_h[data >> 8][1] << bit; - *(pixptr+2) = hirestab_h[data & 255][0] << bit; - *(pixptr+3) = hirestab_h[data & 255][1] << bit; -} + /* This will take effect immediately, within the same cycle. */ + regs.spcflags |= SPCFLAG_COPPER; -static __inline__ void pfield_setword_lores_h(int data, unsigned char *dp, int bit) -{ - ULONG *pixptr = (ULONG *)dp; - - *pixptr = lorestab_h[data >> 8][0] << bit; - *(pixptr+1) = lorestab_h[data >> 8][1] << bit; - *(pixptr+2) = lorestab_h[data >> 8][2] << bit; - *(pixptr+3) = lorestab_h[data >> 8][3] << bit; - *(pixptr+4) = lorestab_h[data & 255][0] << bit; - *(pixptr+5) = lorestab_h[data & 255][1] << bit; - *(pixptr+6) = lorestab_h[data & 255][2] << bit; - *(pixptr+7) = lorestab_h[data & 255][3] << bit; -} + if (! copper_enabled_thisline) + abort (); -static __inline__ void pfield_orword_hires_l(int data, unsigned char *dp, int bit) -{ - ULONG *pixptr = (ULONG *)dp; + if (cop_state.state == COP_wait) { + cop_state.hpos += cop_min_waittime; + if (cop_state.hpos > current_hpos ()) + abort (); + } - *pixptr |= hirestab_l[data >> 8][0] << bit; - *(pixptr+1) |= hirestab_l[data & 255][0] << bit; + eventtab[ev_copper].active = 0; } -static __inline__ void pfield_orword_lores_l(int data, unsigned char *dp, int bit) +void blitter_done_notify (void) { - ULONG *pixptr = (ULONG *)dp; - - *pixptr |= lorestab_l[data >> 8][0] << bit; - *(pixptr+1) |= lorestab_l[data >> 8][1] << bit; - *(pixptr+2) |= lorestab_l[data & 255][0] << bit; - *(pixptr+3) |= lorestab_l[data & 255][1] << bit; -} - -static __inline__ void pfield_setword_hires_l(int data, unsigned char *dp, int bit) -{ - ULONG *pixptr = (ULONG *)dp; + if (cop_state.state != COP_bltwait) + return; - *pixptr = hirestab_l[data >> 8][0] << bit; - *(pixptr+1) = hirestab_l[data & 255][0] << bit; + copper_enabled_thisline = 1; + regs.spcflags |= SPCFLAG_COPPER; + cop_state.state = COP_wait; } -static __inline__ void pfield_setword_lores_l(int data, unsigned char *dp, int bit) +void do_copper (void) { - ULONG *pixptr = (ULONG *)dp; - - *pixptr = lorestab_l[data >> 8][0] << bit; - *(pixptr+1) = lorestab_l[data >> 8][1] << bit; - *(pixptr+2) = lorestab_l[data & 255][0] << bit; - *(pixptr+3) = lorestab_l[data & 255][1] << bit; -} - -#define DO_ONE_PLANE(POINTER, MULT, FUNC, DELAY, LL_SUB, P_ADD) { \ - int i; \ - unsigned int bpldat1; \ - UWORD data; \ - unsigned int bpldat2 = 0; \ - for (i = plflinelen; i > 0; i -= LL_SUB) { \ - bpldat1 = bpldat2; \ - bpldat2 = (*POINTER << 8) | *(POINTER+1); \ - POINTER+=2; \ - data = (bpldat1 << (16 - DELAY)) | (bpldat2 >> DELAY); \ - FUNC(data, app, MULT); \ - app += P_ADD; \ - } \ - data = bpldat2 << (16 - DELAY); \ - FUNC(data, app, MULT); \ + int hpos = current_hpos (); + update_copper (hpos); } -#if 1 -static void pfield_doline_h(void) +static void do_sprites (int currvp, int currhp) { - int xpos = plfstrt * 4 - 0x60; - int spr, sprites_seen; + int i; + int maxspr; - if (bplhires) { - if (bplplanecnt > 0) { - int xpos1 = xpos + 16 + (bpldelay1 >= 8 ? 16 : 0); - int xpos2 = xpos + 16 + (bpldelay2 >= 8 ? 16 : 0); - int delay1 = 2*(bpldelay1 & 7); - int delay2 = 2*(bpldelay2 & 7); - unsigned char *app = pixdata.apixels + xpos1; - - DO_ONE_PLANE(r_bplpt[0], 0, pfield_setword_hires_h, delay1, 4, 16); - if (bplplanecnt > 2) { - app = pixdata.apixels + xpos1; - DO_ONE_PLANE(r_bplpt[2], 2, pfield_orword_hires_h, delay1, 4, 16); - } -#if AGA_CHIPSET == 1 - if (bplplanecnt > 4) { - app = pixdata.apixels + xpos1; - DO_ONE_PLANE(r_bplpt[4], 4, pfield_orword_hires_h, delay1, 4, 16); - } - if (bplplanecnt > 6) { - app = pixdata.apixels + xpos1; - DO_ONE_PLANE(r_bplpt[6], 6, pfield_orword_hires_h, delay1, 4, 16); - } -#endif - if (bplplanecnt > 1) { - app = pixdata.apixels + xpos2; - DO_ONE_PLANE(r_bplpt[1], 1, pfield_orword_hires_h, delay2, 4, 16); - } - if (bplplanecnt > 3) { - app = pixdata.apixels + xpos2; - DO_ONE_PLANE(r_bplpt[3], 3, pfield_orword_hires_h, delay2, 4, 16); - } -#if AGA_CHIPSET == 1 - if (bplplanecnt > 5) { - app = pixdata.apixels + xpos2; - DO_ONE_PLANE(r_bplpt[5], 5, pfield_orword_hires_h, delay2, 4, 16); - } - if (bplplanecnt > 7) { - app = pixdata.apixels + xpos2; - DO_ONE_PLANE(r_bplpt[7], 7, pfield_orword_hires_h, delay2, 4, 16); - } -#endif - } else { - memset(pixdata.apixels, 0, sizeof(pixdata.apixels)); - } - } else { - if (bplplanecnt > 0) { - int x = xpos + 32; - unsigned char *app = pixdata.apixels + x; - - DO_ONE_PLANE(r_bplpt[0], 0, pfield_setword_lores_h, bpldelay1, 8, 32); - if (bplplanecnt > 2) { - app = pixdata.apixels + x; - DO_ONE_PLANE(r_bplpt[2], 2, pfield_orword_lores_h, bpldelay1, 8, 32); - } - if (bplplanecnt > 4) { - app = pixdata.apixels + x; - DO_ONE_PLANE(r_bplpt[4], 4, pfield_orword_lores_h, bpldelay1, 8, 32); - } -#if AGA_CHIPSET == 1 - if (bplplanecnt > 6) { - app = pixdata.apixels + x; - DO_ONE_PLANE(r_bplpt[6], 6, pfield_orword_lores_h, bpldelay1, 8, 32); - } -#endif - if (bplplanecnt > 1) { - app = pixdata.apixels + x; - DO_ONE_PLANE(r_bplpt[1], 1, pfield_orword_lores_h, bpldelay2, 8, 32); - } - if (bplplanecnt > 3) { - app = pixdata.apixels + x; - DO_ONE_PLANE(r_bplpt[3], 3, pfield_orword_lores_h, bpldelay2, 8, 32); - } - if (bplplanecnt > 5) { - app = pixdata.apixels + x; - DO_ONE_PLANE(r_bplpt[5], 5, pfield_orword_lores_h, bpldelay2, 8, 32); - } -#if AGA_CHIPSET == 1 - if (bplplanecnt > 7) { - app = pixdata.apixels + x; - DO_ONE_PLANE(r_bplpt[7], 7, pfield_orword_lores_h, bpldelay2, 8, 32); - } -#endif - } else { - memset(pixdata.apixels, 0, sizeof(pixdata.apixels)); - } - } - - decode_ham6 (16,812); - - linetoscreen = 1; - sprites_seen = 0; - - for(spr = 7; spr >= 0; spr--) { - if (bpl_info.sprarmed[spr]) { - int sprxp = ((bpl_info.sprpos[spr] & 0xFF) * 4) - 0x60 + (bpl_info.sprctl[spr] & 1)*2; - int i; - /* Ugh. Nasty bug. Let's rather lose some sprites than trash - * memory. */ - if (sprxp >= 0) { - if (!sprites_seen) { - sprites_seen = 1; - memset(spixstate,0,sizeof spixstate); - } - pfield_sprite (spr, sprxp, bpl_info.sprdata[spr], bpl_info.sprdatb[spr], 0); - } - } - } -} -#endif -static void pfield_doline_l(void) -{ - int xpos = plfstrt * 2 - 0x30; - int spr; - int sprites_seen; - - if (bplhires) { - if (bplplanecnt > 0) { - int xpos1 = xpos + 8 + (bpldelay1 >= 8 ? 8 : 0); - int xpos2 = xpos + 8 + (bpldelay2 >= 8 ? 8 : 0); - int delay1 = (bpldelay1 & 7) * 2; - int delay2 = (bpldelay2 & 7) * 2; - unsigned char *app = pixdata.apixels + xpos1; - - DO_ONE_PLANE(r_bplpt[0], 0, pfield_setword_hires_l, delay1, 4, 8); - if (bplplanecnt > 2) { - app = pixdata.apixels + xpos1; - DO_ONE_PLANE(r_bplpt[2], 2, pfield_orword_hires_l, delay1, 4, 8); - } -#if AGA_CHIPSET == 1 - if (bplplanecnt > 4) { - app = pixdata.apixels + xpos1; - DO_ONE_PLANE(r_bplpt[4], 4, pfield_orword_hires_l, delay1, 4, 8); - } - if (bplplanecnt > 6) { - app = pixdata.apixels + xpos1; - DO_ONE_PLANE(r_bplpt[6], 6, pfield_orword_hires_l, delay1, 4, 8); - } -#endif - if (bplplanecnt > 1) { - app = pixdata.apixels + xpos2; - DO_ONE_PLANE(r_bplpt[1], 1, pfield_orword_hires_l, delay2, 4, 8); - } - if (bplplanecnt > 3) { - app = pixdata.apixels + xpos2; - DO_ONE_PLANE(r_bplpt[3], 3, pfield_orword_hires_l, delay2, 4, 8); - } -#if AGA_CHIPSET == 1 - if (bplplanecnt > 5) { - app = pixdata.apixels + xpos2; - DO_ONE_PLANE(r_bplpt[5], 5, pfield_orword_hires_l, delay2, 4, 8); - } - if (bplplanecnt > 7) { - app = pixdata.apixels + xpos2; - DO_ONE_PLANE(r_bplpt[7], 7, pfield_orword_hires_l, delay2, 4, 8); - } -#endif - } else { - memset(pixdata.apixels, 0, sizeof(pixdata.apixels)); - } - } else { - if (bplplanecnt > 0) { - int x = xpos + 16; - int delay1 = bpldelay1; - int delay2 = bpldelay2; - unsigned char *app = pixdata.apixels + x; - DO_ONE_PLANE(r_bplpt[0], 0, pfield_setword_lores_l, delay1, 8, 16); - if (bplplanecnt > 2) { - app = pixdata.apixels + x; - DO_ONE_PLANE(r_bplpt[2], 2, pfield_orword_lores_l, delay1, 8, 16); - } - if (bplplanecnt > 4) { - app = pixdata.apixels + x; - DO_ONE_PLANE(r_bplpt[4], 4, pfield_orword_lores_l, delay1, 8, 16); - } -#if AGA_CHIPSET == 1 - if (bplplanecnt > 6) { - app = pixdata.apixels + x; - DO_ONE_PLANE(r_bplpt[6], 6, pfield_orword_lores_l, delay1, 8, 16); - } -#endif - if (bplplanecnt > 1) { - app = pixdata.apixels + x; - DO_ONE_PLANE(r_bplpt[1], 1, pfield_orword_lores_l, delay2, 8, 16); - } - if (bplplanecnt > 3) { - app = pixdata.apixels + x; - DO_ONE_PLANE(r_bplpt[3], 3, pfield_orword_lores_l, delay2, 8, 16); - } - if (bplplanecnt > 5) { - app = pixdata.apixels + x; - DO_ONE_PLANE(r_bplpt[5], 5, pfield_orword_lores_l, delay2, 8, 16); - } -#if AGA_CHIPSET == 1 - if (bplplanecnt > 7) { - app = pixdata.apixels + x; - DO_ONE_PLANE(r_bplpt[7], 7, pfield_orword_lores_l, delay2, 8, 16); - } +#if 0 + if (currvp == 0) + return; +#else + /* I don't know whether this is right. Some programs write the sprite pointers + * directly at the start of the copper list. With the currvp==0 check, the + * first two words of data are read on the second line in the frame. The problem + * occurs when the program jumps to another copperlist a few lines further down + * which _also_ writes the sprite pointer registers. This means that a) writing + * to the sprite pointers sets the state to SPR_restart; or b) that sprite DMA + * is disabled until the end of the vertical blanking interval. The HRM + * isn't clear - it says that the vertical sprite position can be set to any + * value, but this wouldn't be the first mistake... */ + /* Update: I modified one of the programs to write the sprite pointers the + * 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. */ + /* 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 - } else { - memset(pixdata.apixels, 0, sizeof(pixdata.apixels)); - } - } - decode_ham6 (8,406); + /* The graph in the HRM, p. 195 seems to indicate that sprite 0 is + * fetched at cycle 0x14 and thus can't be disabled by bitplane DMA. */ + maxspr = currhp/4 - 0x14/4; + if (maxspr < 0) + return; + if (maxspr > 8) + maxspr = 8; - linetoscreen = 1; - sprites_seen = 0; + for (i = 0; i < maxspr; i++) { + int fetch = 0; - for(spr = 7; spr >= 0; spr--) { - if (bpl_info.sprarmed[spr]) { - int sprxp = ((bpl_info.sprpos[spr] & 0xFF) * 2) - 0x30 + (bpl_info.sprctl[spr] & 1); - int i; - /* Ugh. Nasty bug. Let's rather lose some sprites than trash - * memory. */ - if (sprxp >= 0) { - if (!sprites_seen) { - sprites_seen = 1; - memset(spixstate,0,sizeof spixstate); + if (spr[i].on == 0) + continue; + + if (spr[i].state == SPR_restart) { + fetch = 2; + spr[i].on = 1; + } else if ((spr[i].state == SPR_waiting_start && spr[i].vstart == vpos) || spr[i].state == SPR_waiting_stop) { + fetch = 1; + spr[i].state = SPR_waiting_stop; + } + if ((spr[i].state == SPR_waiting_stop || spr[i].state == SPR_waiting_start) && spr[i].vstop == vpos) { + fetch = 2; + spr[i].state = SPR_waiting_start; + } + + 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; } - pfield_sprite (spr, sprxp, bpl_info.sprdata[spr], bpl_info.sprdatb[spr], 1); + SPRxDATB_1 (data2, i); + SPRxDATA_1 (data1, i); + } else { + SPRxPOS_1 (data1, i); + SPRxCTL_1 (data2, i); } } } } -static int bpl_data_differs(UBYTE *data, UBYTE *r_addr, int nbytes) -{ - return memcmpy(data, r_addr, nbytes); -} - -static __inline__ int bplinfo_differs(struct bplinfo *a, struct bplinfo *b) +static void init_sprites (void) { - int ncolors; int i; - if (a->bplcon0 != b->bplcon0 - || a->bplcon1 != b->bplcon1 - || a->bplcon2 != b->bplcon2 - || a->bplcon3 != b->bplcon3 - || a->bplcon4 != b->bplcon4 - || a->diwstrt != b->diwstrt - || a->diwstop != b->diwstop - || a->ddfstrt != b->ddfstrt - || a->ddfstop != b->ddfstop) - return 1; -#if 1 - /* This sometimes loses for sprite colors */ - ncolors = 1 << ((a->bplcon0 & 0x7000) >> 12); - if (ncolors == 64) - ncolors = (a->bplcon0 & 0x800) ? 16 : 32; - for (i = 0; i < ncolors; i++) - if (a->color_regs[i] != b->color_regs[i]) - return 1; -#else - /* ... and this will lose badly on few-color screens when we implement - * AGA. - */ - if (memcmp(a->color_regs, b->color_regs, sizeof a->color_regs) != 0) - return 1; -#endif for (i = 0; i < 8; i++) { - if (a->sprarmed[i] != b->sprarmed[i]) - return 1; - if (a->sprarmed[i] - && (a->sprctl[i] != b->sprctl[i] - || a->sprpos[i] != b->sprpos[i] - || a->sprdata[i] != b->sprdata[i] - || a->sprdatb[i] != b->sprdatb[i])) - return 1; + /* ???? */ + spr[i].state = SPR_stop; + spr[i].on = 0; } - return 0; + + memset (sprpos, 0, sizeof sprpos); + memset (sprctl, 0, sizeof sprctl); } -static void pfield_doline(void) +static void adjust_array_sizes (void) { - int bytecount = plflinelen / (bplhires ? 4 : 8) * 2; - int drawit = 0; - int i; - - if (vpos < plffirstline || vpos >= plflastline) - return; - - if (!dmaen(0x100) || !pfield_linedmaon) { - line_in_border = 1; - return; - } - - for (i = 0; i < bplplanecnt; i++) { - r_bplpt[i] = pfield_xlateptr(bplpt[i], bytecount); - if (r_bplpt[i] == NULL) - return; +#ifdef OS_WITHOUT_MEMORY_MANAGEMENT + if (delta_sprite_draw) { + void *p1,*p2; + int mcc = max_sprite_draw + 200 + delta_sprite_draw; + delta_sprite_draw = 0; + p1 = realloc (sprite_positions[0], mcc * sizeof (struct sprite_draw)); + p2 = realloc (sprite_positions[1], mcc * sizeof (struct sprite_draw)); + if (p1) sprite_positions[0] = p1; + if (p2) sprite_positions[1] = p2; + if (p1 && p2) { + fprintf (stderr, "new max_sprite_draw=%d\n",mcc); + max_sprite_draw = mcc; + } } - -#if SMART_UPDATE == 1 - drawit = bplinfo_differs(&bpl_info, &linedescr[next_lineno].bpl_info); - if (drawit) { - linedescr[next_lineno].bpl_info = bpl_info; + if (delta_color_change) { + void *p1,*p2; + int mcc = max_color_change + 200 + delta_color_change; + delta_color_change = 0; + p1 = realloc (color_changes[0], mcc * sizeof (struct color_change)); + p2 = realloc (color_changes[1], mcc * sizeof (struct color_change)); + if (p1) color_changes[0] = p1; + if (p2) color_changes[1] = p2; + if (p1 && p2) { + fprintf (stderr, "new max_color_change=%d\n",mcc); + max_color_change = mcc; + } } - drawit |= !linedescr[next_lineno].linedata_valid | frame_redraw_necessary; - - if (bytecount <= MAX_WORDS_PER_LINE * 2) { - linedescr[next_lineno].linedata_valid = 1; - for (i = 0; i < bplplanecnt; i++) - drawit |= bpl_data_differs(line_data[next_lineno][i],r_bplpt[i], - bytecount); - - } else { - linedescr[next_lineno].linedata_valid = 0; + if (delta_delay_change) { + void *p; + int mcc = max_delay_change + 200 + delta_delay_change; + delta_delay_change = 0; + p = realloc (delay_changes, mcc * sizeof (struct delay_change)); + if (p) { + fprintf (stderr, "new max_delay_change=%d\n",mcc); + delay_changes = p; + max_delay_change = mcc; + } } #endif - - pfield_modulos(bytecount); - -#if SMART_UPDATE != 0 - if (!drawit) - return; -#endif - - if (use_lores) - pfield_doline_l(); - else - pfield_doline_h(); } -static void pfield_doline_slow(int currhp) +static void init_hardware_frame (void) { - int xpos = PIXEL_XPOS(currhp); - - if (vpos < plffirstline || vpos >= plflastline) - return; - - if (currhp == plfstrt) - slowline_nextpos = currhp; - - if (currhp == slowline_nextpos) { - if (slowline_linepos >= plflinelen) { - /* The modulos must get added at exactly this point. */ - pfield_modulos(0); - slowline_nextpos = -1; - } else { - slowline_nextpos += bplhires ? 4 : 8; - slowline_linepos += bplhires ? 4 : 8; - - /* Hmmmm..... - * In theory, we could use the fast pfield_doline functions even - * in this case. We only need to do sprites, ham decoding and - * the line_to_scr stuff cycle-per-cycle. However, we would no - * longer be able to emulate tricks that switch lores/hires in - * the middle of a line, but I'm not sure whether this sort of - * thing actually works currently and whether it's worthwhile. - */ - - pfield_fetchdata(); - - if (use_lores) - pfield_doline_slow_l (currhp); - else - pfield_doline_slow_h (currhp); - /* @@@ need to test this */ - decode_ham6 (xpos, PIXEL_XPOS(slowline_nextpos)); - } - } - if (currhp > 48) { - int spr; - for(spr = 7; spr >= 0; spr--) { - if (bpl_info.sprarmed[spr] && currhp == (bpl_info.sprpos[spr] & 0xFF)) { - int sprxp = xpos + (bpl_info.sprctl[spr] & 1) * (use_lores ? 1 : 2); - pfield_sprite (spr, sprxp, bpl_info.sprdata[spr], bpl_info.sprdatb[spr], use_lores); - } - } - } + next_lineno = 0; + nextline_how = nln_normal; + diwstate = DIW_waiting_start; + hdiwstate = DIW_waiting_start; } -static int first_drawn_line, last_drawn_line; -static int first_block_line, last_block_line; - -static void init_frame (void) +void init_hardware_for_drawing_frame (void) { - int i; - int maxpos = use_lores ? 400 : 800; - int old_pmds = prev_max_diwstop; - - if (max_diwstop == 0) - max_diwstop = diwlastword; - - if (max_diwstop < (use_lores ? 320 : 640) || max_diwstop > maxpos) - prev_max_diwstop = maxpos; - else - prev_max_diwstop = max_diwstop; + adjust_array_sizes (); - max_diwstop = 0; + next_color_change = 0; + next_delay_change = 0; + next_sprite_draw = 0; - memset(spron, 0, sizeof spron); - memset(bpl_info.sprpos, 0, sizeof bpl_info.sprpos); - memset(bpl_info.sprctl, 0, sizeof bpl_info.sprctl); - last_drawn_line = 0; - first_drawn_line = 32767; - - first_block_line = last_block_line = -2; - calc_adjustment(); - if (frame_redraw_necessary) - frame_redraw_necessary--; - - if (old_pmds != prev_max_diwstop) { - frame_redraw_necessary |= (bpl_info.bplcon0 & 4 ? 2 : 1); - } -} + next_color_entry = 0; + remembered_color_entry = -1; + prev_sprite_positions = sprite_positions[current_change_set]; + curr_sprite_positions = sprite_positions[current_change_set ^ 1]; + prev_color_changes = color_changes[current_change_set]; + curr_color_changes = color_changes[current_change_set ^ 1]; + prev_color_tables = color_tables[current_change_set]; + curr_color_tables = color_tables[current_change_set ^ 1]; -/* - * A raster line has been built in the graphics buffer. Tell the graphics code - * to do anything necessary to display it. - */ + prev_drawinfo = line_drawinfo[current_change_set]; + curr_drawinfo = line_drawinfo[current_change_set ^ 1]; + current_change_set ^= 1; -static void do_flush_line (int lineno) -{ - if (lineno < first_drawn_line) - first_drawn_line = lineno; - if (lineno > last_drawn_line) - last_drawn_line = lineno; - - if (gfxvidinfo.maxblocklines == 0) - flush_line(lineno); - else { - if ((last_block_line+1) != lineno) { - if (first_block_line != -2) - flush_block (first_block_line, last_block_line); - first_block_line = lineno; - } - last_block_line = lineno; - if (last_block_line - first_block_line >= gfxvidinfo.maxblocklines) { - flush_block (first_block_line, last_block_line); - first_block_line = last_block_line = -2; - } - } + color_src_match = color_dest_match = -1; } -/* - * One Amiga frame has been finished. Tell the graphics code about it. - * Note that the actual flush_scren() call is a no-op for all reasonable - * systems. - */ - -static void do_flush_screen (int start, int stop) +static void vsync_handler (void) { - if (gfxvidinfo.maxblocklines != 0 && first_block_line != -2) { - flush_block (first_block_line, last_block_line); + if (currprefs.m68k_speed == -1) { + frame_time_t curr_time = read_processor_time (); + vsyncmintime += vsynctime; + /* @@@ Mathias? How do you think we should do this? */ + /* If we are too far behind, or we just did a reset, adjust the + * needed time. */ + if ((long int)(curr_time - vsyncmintime) > 0 || rpt_did_reset) + vsyncmintime = curr_time + vsynctime; + rpt_did_reset = 0; } - if (start <= stop) - flush_screen (start, stop); -} -static void setdontcare(void) -{ - fprintf(stderr, "Don't care mouse mode set\n"); - mousestate = dont_care_mouse; - lastspr0x = lastmx; lastspr0y = lastmy; - mstepx = defstepx; mstepy = defstepy; -} - -static void setfollow(void) -{ - fprintf(stderr, "Follow sprite mode set\n"); - mousestate = follow_mouse; - lastdiffx = lastdiffy = 0; - sprvbfl = 0; - spr0ctl=spr0pos = 0; - mstepx = defstepx; mstepy = defstepy; -} + handle_events (); -void togglemouse(void) -{ - switch(mousestate) { - case dont_care_mouse: setfollow(); break; - case follow_mouse: setdontcare(); break; - default: break; /* Nnnnnghh! */ - } -} + getjoystate (0, &joy0dir, &joy0button); + getjoystate (1, &joy1dir, &joy1button); -static __inline__ int adjust(int val) -{ - if (val>127) - return 127; - else if (val<-127) - return -127; - return val; -} + INTREQ (0x8020); + if (bplcon0 & 4) + lof ^= 0x8000; -static void do_mouse_hack(void) -{ - int spr0x = ((spr0pos & 0xff) << 2) | ((spr0ctl & 1) << 1); - int spr0y = ((spr0pos >> 8) | ((spr0ctl & 4) << 6)) << 1; - int diffx, diffy; - - switch (mousestate) { - case normal_mouse: - diffx = lastmx - lastsampledmx; - diffy = lastmy - lastsampledmy; - if (!newmousecounters) { - if (diffx > 127) diffx = 127; - if (diffx < -127) diffx = -127; - joy0x += diffx; - if (diffy > 127) diffy = 127; - if (diffy < -127) diffy = -127; - joy0y += diffy; - } - lastsampledmx += diffx; lastsampledmy += diffy; - break; + vsync_handle_redraw (lof, lof_changed); + if (quit_program > 0) + return; - case dont_care_mouse: - diffx = adjust (((lastmx-lastspr0x) * mstepx) >> 16); - diffy = adjust (((lastmy-lastspr0y) * mstepy) >> 16); - lastspr0x=lastmx; lastspr0y=lastmy; - joy0x+=diffx; joy0y+=diffy; - break; - - case follow_mouse: - if (sprvbfl && sprvbfl-- >1) { - int mousexpos, mouseypos; - - if ((lastdiffx > docal || lastdiffx < -docal) && lastspr0x != spr0x - && spr0x > plfstrt*4 + 34 + xcaloff && spr0x < plfstop*4 - xcaloff) - { - int val = (lastdiffx << 16) / (spr0x - lastspr0x); - if (val>=0x8000) mstepx=(mstepx*(calweight-1)+val)/calweight; - } - if ((lastdiffy > docal || lastdiffy < -docal) && lastspr0y != spr0y - && spr0y>plffirstline+ycaloff && spr0y=0x8000) mstepy=(mstepy*(calweight-1)+val)/calweight; - } - mousexpos = lastmx; - if (gfxvidinfo.x_adjust) - mousexpos += gfxvidinfo.x_adjust; - mouseypos = lastmy; - - if(!correct_aspect) - mouseypos *= 2; - if(use_lores) - mousexpos *= 2; - if (gfxvidinfo.x_adjust) - mousexpos -= 16; - - diffx = adjust ((((mousexpos + 0x70 + xoffs - spr0x) & ~1) * mstepx) >> 16); - diffy = adjust ((((mouseypos + yoffs - spr0y+minfirstline*2) & ~1) * mstepy) >> 16); - lastspr0x=spr0x; lastspr0y=spr0y; - lastdiffx=diffx; lastdiffy=diffy; - joy0x+=diffx; joy0y+=diffy; + { + static int cnt = 0; + if (cnt == 0) { + /* resolution_check_change (); */ + DISK_check_change (); + cnt = 5; } - break; + cnt--; } -} -static void vsync_handler(void) -{ - UWORD dir; - int button; + /* For now, let's only allow this to change at vsync time. It gets too + * hairy otherwise. */ + if (beamcon0 != new_beamcon0) + init_hz (); + + lof_changed = 0; - handle_events(); - getjoystate(&joy0dir, &joy0button); + cop_state.ip = cop1lc; + cop_state.state = COP_read1; + cop_state.vpos = 0; + cop_state.hpos = 0; + cop_state.ignore_next = 0; - do_mouse_hack(); - - INTREQ(0x8020); - if (bpl_info.bplcon0 & 4) lof ^= 0x8000; - COPJMP1(0); - - if (framecnt == 0) - do_flush_screen (first_drawn_line, last_drawn_line); + init_hardware_frame (); - count_frame(); - init_frame(); #ifdef HAVE_GETTIMEOFDAY { 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) { - frametime += newtime - msecs; + + if (!bogusframe) { + lastframetime = newtime - msecs; + +#if 0 /* This doesn't appear to work too well yet... later. */ + if (n_consecutive_skipped > currprefs.sound_pri_cutoff + || lastframetime < currprefs.sound_pri_time) + { + n_consecutive_skipped = 0; + clear_inhibit_frame (IHF_SOUNDADJUST); + } else { + n_consecutive_skipped++; + set_inhibit_frame (IHF_SOUNDADJUST); + total_skipped++; + } +#endif + + frametime += lastframetime; timeframes++; + + if ((timeframes & 127) == 0) + gui_fps (1000 * timeframes / frametime); } msecs = newtime; bogusframe = 0; } #endif + if (ievent_alive > 0) + ievent_alive--; + if (timehack_alive > 0) + timehack_alive--; CIA_vsync_handler(); } -static void hsync_handler(void) +static void hsync_handler (void) { - int lineno = vpos - minfirstline; - int lineisdouble = 0; - int line_was_doubled = 0; - - do_sprites(vpos, maxhpos); - last_sprite = 0; - - if (correct_aspect) { - lineno *= 2; - if (bpl_info.bplcon0 & 4) { - if(!lof) { - lineno++; - } - } else { - lineisdouble = 1; - } + 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 ()); + + hsync_record_line_state (next_lineno, nextline_how, thisline_changed); eventtab[ev_hsync].evtime += cycles - eventtab[ev_hsync].oldcycles; eventtab[ev_hsync].oldcycles = cycles; - CIA_hsync_handler(); - - if (produce_sound > 0) { + CIA_hsync_handler (); + DISK_update (); + + if (currprefs.produce_sound > 0) { int nr; + + update_audio (); + /* Sound data is fetched at the beginning of each line */ for (nr = 0; nr < 4; nr++) { struct audio_channel_data *cdp = audio_channel + nr; - + if (cdp->data_written == 2) { cdp->data_written = 0; cdp->nextdat = chipmem_bank.wget(cdp->pt); @@ -2555,227 +2626,168 @@ static void hsync_handler(void) } } - if (framecnt == 0 && vpos >= minfirstline && lineno < gfxvidinfo.maxline) { - if (vpos >= plffirstline && vpos < plflastline) - { - /* Finish the line, if we started doing it with the slow update. - * Otherwise, draw it entirely. */ - if (pfield_fullline) { - if (!pfield_linedone) { - /* This can turn on line_in_border if DMA is off */ - pfield_doline(); - } - if (linetoscreen) - pfield_do_linetoscr_full (line_was_doubled = lineisdouble); - } else { - int i; - for(i = pfield_lastpart_hpos; i < maxhpos; i++) - pfield_doline_slow(i); - pfield_do_linetoscr(slowline_lasttoscr, maxhpos); - /* The COLOR routine masks off the high nibble. This means - * that there will never be 0xFFFF in color_regs[0], and this - * means that the line will be drawn completely the next time - * we get into pfield_doline() - */ - linedescr[lineno].bpl_info.color_regs[0] = 0xFFFF; - linetoscreen = 1; - } - } else - line_in_border = 1; - - if (line_in_border && - (!linedescr[lineno].inborder - || linedescr[lineno].bordercol != acolors[0])) - { - linedescr[lineno].bordercol = acolors[0]; - linedescr[lineno].linedata_valid = 0; - - fill_line (lineno); - linetoscreen = 1; - } - - linedescr[lineno].inborder = line_in_border; - - if (linetoscreen) { -#if AGA_CHIPSET == 1 - switch (gfxvidinfo.pixbytes) { - case 1: aga_translate8 (0, aga_lbufptr-aga_linebuf); break; - case 2: aga_translate16 (0, aga_lbufptr-aga_linebuf); break; - case 4: aga_translate32 (0, aga_lbufptr-aga_linebuf); break; - } -#endif - do_flush_line (lineno); - } - if (lineisdouble) { - int drawit = 0; - - if (linedescr[lineno].inborder != linedescr[lineno+1].inborder - || (linedescr[lineno].inborder == 1 - && linedescr[lineno].bordercol != linedescr[lineno+1].bordercol)) { - drawit = 1; - - } else if (linedescr[lineno].inborder == 0 - && (linetoscreen - || (bplinfo_differs(&linedescr[lineno].bpl_info, - &linedescr[lineno+1].bpl_info)))) { - drawit = 1; - } - - if (drawit) { - linedescr[lineno+1].inborder = linedescr[lineno].inborder; - linedescr[lineno+1].bordercol = linedescr[lineno].bordercol; -#if SMART_UPDATE != 0 - linedescr[lineno+1].bpl_info = linedescr[lineno].bpl_info; -#endif - if (!line_was_doubled) { - if (line_in_border) - fill_line (lineno+1); - else - memcpy (gfxvidinfo.bufmem + (lineno+1)*gfxvidinfo.rowbytes, - gfxvidinfo.bufmem + lineno*gfxvidinfo.rowbytes, - gfxvidinfo.rowbytes); - } - do_flush_line (lineno+1); - } - } - } - - pfield_calclinedma(); + hardware_line_completed (next_lineno); if (++vpos == (maxvpos + (lof != 0))) { vpos = 0; vsync_handler(); } - - if (framecnt == 0) - { - lineno = vpos - minfirstline; - - if (correct_aspect) { + + is_lastline = vpos + 1 == maxvpos + (lof != 0) && currprefs.m68k_speed == -1 && ! rpt_did_reset; + + if ((bplcon0 & 4) && currprefs.gfx_linedbl) + notice_interlace_seen (); + + if (framecnt == 0) { + int lineno = vpos; + nextline_how = nln_normal; + if (currprefs.gfx_linedbl) { lineno *= 2; - if ((bpl_info.bplcon0 & 4) && !lof) { - lineno++; + nextline_how = currprefs.gfx_linedbl == 1 ? nln_doubled : nln_nblack; + if (bplcon0 & 4) { + if (!lof) { + lineno++; + nextline_how = nln_lower; + } else { + nextline_how = nln_upper; + } } } - xlinebuffer = gfxvidinfo.bufmem + gfxvidinfo.rowbytes * lineno; - aga_lbufptr = aga_linebuf; next_lineno = lineno; - linetoscreen = 0; - line_in_border = 0; - pfield_fullline = 1; - pfield_linedone = 0; - pfield_lastpart_hpos = 0; + reset_decisions (); + } + if (uae_int_requested) { + set_uae_int_flag (); + INTREQ (0xA000); } + /* 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) +{ + int i; + + for(i = 0; i < ev_max; i++) { + eventtab[i].active = 0; + eventtab[i].oldcycles = 0; + } + + eventtab[ev_cia].handler = CIA_handler; + 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_disk].handler = DISK_handler; + eventtab[ev_disk].active = 0; + + events_schedule (); } -void customreset(void) +void customreset (void) { int i; + int zero = 0; #ifdef HAVE_GETTIMEOFDAY struct timeval tv; #endif - inhibit_frame = 0; - expamem_reset(); - CIA_reset(); - cycles = 0; + + if (currprefs.chipset_mask & CSMASK_AGA) { + 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); + } + } + + expamem_reset (); + + CIA_reset (); + cycles = 0; regs.spcflags &= SPCFLAG_BRK; - - last_sprite = 0; - vpos = 0; + + vpos = 0; lof = 0; - next_lineno = 0; - max_diwstop = 0; - - if (needmousehack()) { - if (mousestate != follow_mouse) setfollow(); + + if (needmousehack ()) { +#if 0 + mousehack_setfollow(); +#else + mousehack_setdontcare(); +#endif } else { mousestate = normal_mouse; } + ievent_alive = 0; + timehack_alive = 0; - memset(spixstate, 0, sizeof(spixstate)); - - /*memset(blitcount, 0, sizeof(blitcount)); blitter debug */ - - for (i = 0; i < numscrlines*2; i++) { - linedescr[i].mnn = NULL; - linedescr[i].linedata_valid = 0; - linedescr[i].bpl_info.color_regs[0] = 0xFFFF; - linedescr[i].bplpt[0] = (CPTR)-1; - } - - xlinebuffer = gfxvidinfo.bufmem; + clx_sprmask = 0xFF; + clxdat = 0; + + /* Clear the armed flags of all sprites. */ + memset (spr, 0, sizeof spr); + nr_armed = 0; dmacon = intena = 0; bltstate = BLT_done; - copstate = COP_stop; + cop_state.state = COP_stop; + diwstate = DIW_waiting_start; + hdiwstate = DIW_waiting_start; copcon = 0; - dskdmaen = 0; + DSKLEN (0, 0); cycles = 0; - - memset(audio_channel, 0, sizeof audio_channel); - bpl_info.bplcon4 = 0x11; /* Get AGA chipset into ECS compatibility mode */ - bpl_info.bplcon3 = 0xC00; - for(i = 0; i < ev_max; i++) { - eventtab[i].active = 0; - eventtab[i].oldcycles = 0; - } - copper_active = 0; - 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; + bplcon4 = 0x11; /* Get AGA chipset into ECS compatibility mode */ + bplcon3 = 0xC00; + + new_beamcon0 = ntscmode ? 0x00 : 0x20; + init_hz (); + + audio_reset (); + + init_eventtab (); + + init_sprites (); + + init_hardware_frame (); + reset_drawing (); + + reset_decisions (); - 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; -#ifndef DONT_WANT_SOUND - eventtab[ev_aud0].handler = aud0_handler; - eventtab[ev_aud0].active = 0; - eventtab[ev_aud1].handler = aud1_handler; - eventtab[ev_aud1].active = 0; - eventtab[ev_aud2].handler = aud2_handler; - eventtab[ev_aud2].active = 0; - eventtab[ev_aud3].handler = aud3_handler; - eventtab[ev_aud3].active = 0; - if (sound_available) { - eventtab[ev_sample].active = 1; - eventtab[ev_sample].evtime += cycles; - eventtab[ev_sample].oldcycles = cycles; - } else { - eventtab[ev_sample].active = 0; - } -#endif - events_schedule(); - - init_frame(); #ifdef HAVE_GETTIMEOFDAY - gettimeofday(&tv,NULL); + gettimeofday (&tv, NULL); seconds_base = tv.tv_sec; bogusframe = 1; #endif } -void dumpcustom(void) +void dumpcustom (void) { - int i; - fprintf(stderr, "DMACON: %x INTENA: %x INTREQ: %x VPOS: %x HPOS: %x\n", DMACONR(), - intena, intreq, vpos, current_hpos()); - if (timeframes) { - fprintf(stderr, "Average frame time: %d ms [frames: %d time: %d]\n", - frametime/timeframes, timeframes, frametime); + write_log ("DMACON: %x INTENA: %x INTREQ: %x VPOS: %x HPOS: %x\n", DMACONR(), + (unsigned int)intena, (unsigned int)intreq, (unsigned int)vpos, (unsigned int)current_hpos()); + write_log ("COP1LC: %08lx, COP2LC: %08lx\n", (unsigned long)cop1lc, (unsigned long)cop2lc); + if (timeframes) { + write_log ("Average frame time: %d ms [frames: %d time: %d]\n", + frametime / timeframes, timeframes, frametime); + if (total_skipped) + write_log ("Skipped frames: %d\n", total_skipped); } - /*for (i=0; i<256; i++) if (blitcount[i]) fprintf(stderr, "minterm %x = %d\n",i,blitcount[i]); blitter debug */ + dump_audio_bench (); + /*for (i=0; i<256; i++) if (blitcount[i]) fprintf (stderr, "minterm %x = %d\n",i,blitcount[i]); blitter debug */ } -int intlev(void) +int intlev (void) { - UWORD imask = intreq & intena; + uae_u16 imask = intreq & intena; if (imask && (intena & 0x4000)){ if (imask & 0x2000) return 6; if (imask & 0x1800) return 5; @@ -2787,268 +2799,305 @@ int intlev(void) return -1; } -void custom_init(void) +static void gen_custom_tables (void) { + int i; + for (i = 0; i < 256; i++) { + unsigned int j; + sprtaba[i] = ((((i >> 7) & 1) << 0) + | (((i >> 6) & 1) << 2) + | (((i >> 5) & 1) << 4) + | (((i >> 4) & 1) << 6) + | (((i >> 3) & 1) << 8) + | (((i >> 2) & 1) << 10) + | (((i >> 1) & 1) << 12) + | (((i >> 0) & 1) << 14)); + sprtabb[i] = sprtaba[i] * 2; + for (j = 0; j < 511; j = (j << 1) | 1) + if ((i & ~j) == 0) + waitmasktab[i] = ~j; + } +} + +void custom_init (void) +{ + uaecptr pos; + +#ifdef OS_WITHOUT_MEMORY_MANAGEMENT int num; - if (needmousehack()) - setfollow(); - customreset(); - for (num = 0; num < 256; num++) { - int plane1 = (num & 1) | ((num >> 1) & 2) | ((num >> 2) & 4) | ((num >> 3) & 8); - int plane2 = ((num >> 1) & 1) | ((num >> 2) & 2) | ((num >> 3) & 4) | ((num >> 4) & 8); - dblpf_2nd1[num] = plane1 == 0 ? (plane2 == 0 ? 0 : 2) : 1; - dblpf_2nd2[num] = plane2 == 0 ? (plane1 == 0 ? 0 : 1) : 2; - dblpf_aga1[num] = plane1 == 0 ? plane2 : plane1; - dblpf_aga2[num] = plane2 == 0 ? plane1 : plane2; - if (plane2 > 0) plane2 += 8; - dblpf_ind1[num] = plane1 == 0 ? plane2 : plane1; - dblpf_ind2[num] = plane2 == 0 ? plane1 : plane2; - - lots_of_twos[num] = num == 0 ? 0 : 2; - linear_map_256[num] = num; + + for (num = 0; num < 2; num++) { + sprite_positions[num] = xmalloc (max_sprite_draw * sizeof (struct sprite_draw)); + color_changes[num] = xmalloc (max_color_change * sizeof (struct color_change)); } - build_blitfilltable(); - gen_pfield_tables(); + delay_changes = xmalloc (max_delay_change * sizeof (struct delay_change)); +#endif + + pos = here (); + + org (0xF0FF70); + calltrap (deftrap (mousehack_helper)); + dw (RTS); + + org (0xF0FFA0); + calltrap (deftrap (timehack_helper)); + dw (RTS); + + org (pos); + + init_decisions (); + + gen_custom_tables (); + build_blitfilltable (); + + drawing_init (); + + mousestate = unknown_mouse; + + if (needmousehack ()) + mousehack_setfollow(); } /* Custom chip memory bank */ -static ULONG custom_lget(CPTR) REGPARAM; -static UWORD custom_wget(CPTR) REGPARAM; -static UBYTE custom_bget(CPTR) REGPARAM; -static void custom_lput(CPTR, ULONG) REGPARAM; -static void custom_wput(CPTR, UWORD) REGPARAM; -static void custom_bput(CPTR, UBYTE) REGPARAM; +static uae_u32 custom_lget (uaecptr) REGPARAM; +static uae_u32 custom_wget (uaecptr) REGPARAM; +static uae_u32 custom_bget (uaecptr) REGPARAM; +static void custom_lput (uaecptr, uae_u32) REGPARAM; +static void custom_wput (uaecptr, uae_u32) REGPARAM; +static void custom_bput (uaecptr, uae_u32) REGPARAM; addrbank custom_bank = { - default_alget, default_awget, custom_lget, custom_wget, custom_bget, custom_lput, custom_wput, custom_bput, default_xlate, default_check }; -UWORD custom_wget(CPTR addr) +uae_u32 REGPARAM2 custom_wget (uaecptr addr) { - switch(addr & 0x1FE) { + switch (addr & 0x1FE) { case 0x002: return DMACONR(); 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(); + case 0x00E: return CLXDAT(); case 0x010: return ADKCONR(); 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(); - -#if AGA_CHIPSET == 1 - case 0x07C: return 0xF8; -#elif defined ECS_DENISE - case 0x07C: return 0xFC; -#endif + case 0x07C: return DENISEID(); default: custom_wput(addr,0); return 0xffff; } } -UBYTE custom_bget(CPTR addr) +uae_u32 REGPARAM2 custom_bget (uaecptr addr) { return custom_wget(addr & 0xfffe) >> (addr & 1 ? 0 : 8); } -ULONG custom_lget(CPTR addr) +uae_u32 REGPARAM2 custom_lget (uaecptr addr) { - return ((ULONG)custom_wget(addr & 0xfffe) << 16) | custom_wget((addr+2) & 0xfffe); + return ((uae_u32)custom_wget(addr & 0xfffe) << 16) | custom_wget((addr+2) & 0xfffe); } -void custom_wput(CPTR addr, UWORD value) +void REGPARAM2 custom_wput_1 (int hpos, uaecptr addr, uae_u32 value) { addr &= 0x1FE; - cregs[addr>>1] = value; - switch(addr) { - case 0x020: DSKPTH(value); break; - case 0x022: DSKPTL(value); break; - case 0x024: DSKLEN(value); break; - case 0x026: DSKDAT(value); break; - - case 0x02A: VPOSW(value); break; + switch (addr) { + case 0x020: DSKPTH (value); break; + case 0x022: DSKPTL (value); break; + case 0x024: DSKLEN (value, current_hpos()); break; + case 0x026: DSKDAT (value); break; + + case 0x02A: VPOSW (value); break; + case 0x2E: COPCON (value); break; + case 0x030: SERDAT (value); break; + case 0x032: SERPER (value); break; + case 0x34: POTGO (value); break; + case 0x040: BLTCON0 (value); break; + case 0x042: BLTCON1 (value); break; + + case 0x044: BLTAFWM (value); break; + case 0x046: BLTALWM (value); break; + + case 0x050: BLTAPTH (value); break; + case 0x052: BLTAPTL (value); break; + case 0x04C: BLTBPTH (value); break; + case 0x04E: BLTBPTL (value); break; + case 0x048: BLTCPTH (value); break; + case 0x04A: BLTCPTL (value); break; + case 0x054: BLTDPTH (value); break; + case 0x056: BLTDPTL (value); break; + + case 0x058: BLTSIZE (value); break; + + case 0x064: BLTAMOD (value); break; + case 0x062: BLTBMOD (value); break; + case 0x060: BLTCMOD (value); break; + case 0x066: BLTDMOD (value); break; + + case 0x070: BLTCDAT (value); break; + case 0x072: BLTBDAT (value); break; + case 0x074: BLTADAT (value); break; + + case 0x07E: DSKSYNC (value); break; + + case 0x080: COP1LCH (value); break; + case 0x082: COP1LCL (value); break; + case 0x084: COP2LCH (value); break; + case 0x086: COP2LCL (value); break; + + case 0x088: COPJMP1 (value); break; + case 0x08A: COPJMP2 (value); break; + + case 0x08E: DIWSTRT (hpos, value); break; + case 0x090: DIWSTOP (hpos, value); break; + case 0x092: DDFSTRT (hpos, value); break; + case 0x094: DDFSTOP (hpos, value); break; + + case 0x096: DMACON (value); break; + case 0x098: CLXCON (value); break; + case 0x09A: INTENA (value); break; + case 0x09C: INTREQ (value); break; + case 0x09E: ADKCON (value); break; + + case 0x0A0: AUDxLCH (0, value); break; + case 0x0A2: AUDxLCL (0, value); break; + case 0x0A4: AUDxLEN (0, value); break; + case 0x0A6: AUDxPER (0, value); break; + case 0x0A8: AUDxVOL (0, value); break; + case 0x0AA: AUDxDAT (0, value); break; + + case 0x0B0: AUDxLCH (1, value); break; + case 0x0B2: AUDxLCL (1, value); break; + case 0x0B4: AUDxLEN (1, value); break; + case 0x0B6: AUDxPER (1, value); break; + case 0x0B8: AUDxVOL (1, value); break; + case 0x0BA: AUDxDAT (1, value); break; + + case 0x0C0: AUDxLCH (2, value); break; + case 0x0C2: AUDxLCL (2, value); break; + case 0x0C4: AUDxLEN (2, value); break; + case 0x0C6: AUDxPER (2, value); break; + case 0x0C8: AUDxVOL (2, value); break; + case 0x0CA: AUDxDAT (2, value); break; + + case 0x0D0: AUDxLCH (3, value); break; + case 0x0D2: AUDxLCL (3, value); break; + case 0x0D4: AUDxLEN (3, value); break; + case 0x0D6: AUDxPER (3, value); break; + case 0x0D8: AUDxVOL (3, value); break; + case 0x0DA: AUDxDAT (3, value); break; + + case 0x0E0: BPLPTH (hpos, value, 0); break; + case 0x0E2: BPLPTL (hpos, value, 0); break; + case 0x0E4: BPLPTH (hpos, value, 1); break; + case 0x0E6: BPLPTL (hpos, value, 1); break; + case 0x0E8: BPLPTH (hpos, value, 2); break; + case 0x0EA: BPLPTL (hpos, value, 2); break; + case 0x0EC: BPLPTH (hpos, value, 3); break; + case 0x0EE: BPLPTL (hpos, value, 3); break; + case 0x0F0: BPLPTH (hpos, value, 4); break; + case 0x0F2: BPLPTL (hpos, value, 4); break; + case 0x0F4: BPLPTH (hpos, value, 5); break; + case 0x0F6: BPLPTL (hpos, value, 5); break; + case 0x0F8: BPLPTH (hpos, value, 6); break; + case 0x0FA: BPLPTL (hpos, value, 6); break; + case 0x0FC: BPLPTH (hpos, value, 7); break; + case 0x0FE: BPLPTL (hpos, value, 7); break; + + case 0x100: BPLCON0 (hpos, value); break; + case 0x102: BPLCON1 (hpos, value); break; + case 0x104: BPLCON2 (hpos, value); break; + case 0x106: BPLCON3 (hpos, value); break; + + case 0x108: BPL1MOD (hpos, value); break; + case 0x10A: BPL2MOD (hpos, value); break; + + case 0x110: BPL1DAT (value); break; + case 0x112: BPL2DAT (value); break; + case 0x114: BPL3DAT (value); break; + case 0x116: BPL4DAT (value); break; + case 0x118: BPL5DAT (value); break; + case 0x11A: BPL6DAT (value); break; + case 0x11C: BPL7DAT (value); break; + case 0x11E: BPL8DAT (value); break; - case 0x030: SERDAT(value); break; - case 0x032: SERPER(value); break; - - case 0x040: BLTCON0(value); break; - case 0x042: BLTCON1(value); break; - - case 0x044: BLTAFWM(value); break; - case 0x046: BLTALWM(value); break; - - case 0x050: BLTAPTH(value); break; - case 0x052: BLTAPTL(value); break; - case 0x04C: BLTBPTH(value); break; - case 0x04E: BLTBPTL(value); break; - case 0x048: BLTCPTH(value); break; - case 0x04A: BLTCPTL(value); break; - case 0x054: BLTDPTH(value); break; - case 0x056: BLTDPTL(value); break; - - case 0x058: BLTSIZE(value); break; - - case 0x064: BLTAMOD(value); break; - case 0x062: BLTBMOD(value); break; - case 0x060: BLTCMOD(value); break; - case 0x066: BLTDMOD(value); break; - - case 0x070: BLTCDAT(value); break; - case 0x072: BLTBDAT(value); break; - case 0x074: BLTADAT(value); break; - - case 0x07E: DSKSYNC(value); break; - - case 0x080: COP1LCH(value); break; - case 0x082: COP1LCL(value); break; - case 0x084: COP2LCH(value); break; - case 0x086: COP2LCL(value); break; - - case 0x088: COPJMP1(value); break; - case 0x08A: COPJMP2(value); break; - - case 0x08E: DIWSTRT(value); break; - case 0x090: DIWSTOP(value); break; - case 0x092: DDFSTRT(value); break; - case 0x094: DDFSTOP(value); break; - - case 0x096: DMACON(value); break; - case 0x09A: INTENA(value); break; - case 0x09C: INTREQ(value); break; - case 0x09E: ADKCON(value); break; - - case 0x0A0: AUDxLCH(0, value); break; - case 0x0A2: AUDxLCL(0, value); break; - case 0x0A4: AUDxLEN(0, value); break; - case 0x0A6: AUDxPER(0, value); break; - case 0x0A8: AUDxVOL(0, value); break; - case 0x0AA: AUDxDAT(0, value); break; - - case 0x0B0: AUDxLCH(1, value); break; - case 0x0B2: AUDxLCL(1, value); break; - case 0x0B4: AUDxLEN(1, value); break; - case 0x0B6: AUDxPER(1, value); break; - case 0x0B8: AUDxVOL(1, value); break; - case 0x0BA: AUDxDAT(1, value); break; - - case 0x0C0: AUDxLCH(2, value); break; - case 0x0C2: AUDxLCL(2, value); break; - case 0x0C4: AUDxLEN(2, value); break; - case 0x0C6: AUDxPER(2, value); break; - case 0x0C8: AUDxVOL(2, value); break; - case 0x0CA: AUDxDAT(2, value); break; - - case 0x0D0: AUDxLCH(3, value); break; - case 0x0D2: AUDxLCL(3, value); break; - case 0x0D4: AUDxLEN(3, value); break; - case 0x0D6: AUDxPER(3, value); break; - case 0x0D8: AUDxVOL(3, value); break; - case 0x0DA: AUDxDAT(3, value); break; - - case 0x0E0: BPLPTH(value, 0); break; - case 0x0E2: BPLPTL(value, 0); break; - case 0x0E4: BPLPTH(value, 1); break; - case 0x0E6: BPLPTL(value, 1); break; - case 0x0E8: BPLPTH(value, 2); break; - case 0x0EA: BPLPTL(value, 2); break; - case 0x0EC: BPLPTH(value, 3); break; - case 0x0EE: BPLPTL(value, 3); break; - case 0x0F0: BPLPTH(value, 4); break; - case 0x0F2: BPLPTL(value, 4); break; - case 0x0F4: BPLPTH(value, 5); break; - case 0x0F6: BPLPTL(value, 5); break; - - case 0x100: BPLCON0(value); break; - case 0x102: BPLCON1(value); break; - case 0x104: BPLCON2(value); break; - case 0x106: BPLCON3(value); break; - - case 0x108: BPL1MOD(value); break; - case 0x10A: BPL2MOD(value); break; - - case 0x110: BPL1DAT(value); break; - case 0x112: BPL2DAT(value); break; - case 0x114: BPL3DAT(value); break; - case 0x116: BPL4DAT(value); break; - case 0x118: BPL5DAT(value); break; - case 0x11A: BPL6DAT(value); break; - case 0x180: case 0x182: case 0x184: case 0x186: case 0x188: case 0x18A: case 0x18C: case 0x18E: case 0x190: case 0x192: case 0x194: case 0x196: case 0x198: case 0x19A: case 0x19C: case 0x19E: case 0x1A0: case 0x1A2: case 0x1A4: case 0x1A6: case 0x1A8: case 0x1AA: case 0x1AC: case 0x1AE: case 0x1B0: case 0x1B2: case 0x1B4: case 0x1B6: case 0x1B8: case 0x1BA: - case 0x1BC: case 0x1BE: - COLOR(value & 0xFFF, (addr & 0x3E) / 2); - break; - case 0x120: case 0x124: case 0x128: case 0x12C: + case 0x1BC: case 0x1BE: + COLOR (hpos, value & 0xFFF, (addr & 0x3E) / 2); + break; + case 0x120: case 0x124: case 0x128: case 0x12C: case 0x130: case 0x134: case 0x138: case 0x13C: - SPRxPTH(value, (addr - 0x120) / 4); + SPRxPTH (hpos, value, (addr - 0x120) / 4); break; - case 0x122: case 0x126: case 0x12A: case 0x12E: + case 0x122: case 0x126: case 0x12A: case 0x12E: case 0x132: case 0x136: case 0x13A: case 0x13E: - SPRxPTL(value, (addr - 0x122) / 4); + SPRxPTL (hpos, value, (addr - 0x122) / 4); break; - case 0x140: case 0x148: case 0x150: case 0x158: + case 0x140: case 0x148: case 0x150: case 0x158: case 0x160: case 0x168: case 0x170: case 0x178: - SPRxPOS(value, (addr - 0x140) / 8); + SPRxPOS (hpos, value, (addr - 0x140) / 8); break; - case 0x142: case 0x14A: case 0x152: case 0x15A: + case 0x142: case 0x14A: case 0x152: case 0x15A: case 0x162: case 0x16A: case 0x172: case 0x17A: - SPRxCTL(value, (addr - 0x142) / 8); + SPRxCTL (hpos, value, (addr - 0x142) / 8); break; case 0x144: case 0x14C: case 0x154: case 0x15C: case 0x164: case 0x16C: case 0x174: case 0x17C: - SPRxDATA(value, (addr - 0x144) / 8); + SPRxDATA (hpos, value, (addr - 0x144) / 8); break; - case 0x146: case 0x14E: case 0x156: case 0x15E: + case 0x146: case 0x14E: case 0x156: case 0x15E: case 0x166: case 0x16E: case 0x176: case 0x17E: - SPRxDATB(value, (addr - 0x146) / 8); + SPRxDATB (hpos, value, (addr - 0x146) / 8); break; - - case 0x36: JOYTEST(value); break; -#if defined(ECS_AGNUS) || (AGA_CHIPSET == 1) - case 0x5A: BLTCON0L(value); break; - case 0x5C: BLTSIZV(value); break; - case 0x5E: BLTSIZH(value); break; -#endif -#if AGA_CHIPSET == 1 - case 0x10C: BPLCON4(value); break; - case 0x1FC: fmode = value; break; -#endif + + case 0x36: JOYTEST (value); break; + case 0x5A: BLTCON0L (value); break; + case 0x5C: BLTSIZV (value); break; + case 0x5E: BLTSIZH (value); break; + case 0x1E4: DIWHIGH (hpos, value); break; + case 0x10C: BPLCON4 (hpos, value); break; + case 0x1FC: FMODE (value); break; } } -void custom_bput(CPTR addr, UBYTE value) +void REGPARAM2 custom_wput (uaecptr addr, uae_u32 value) { - /* Yes, there are programs that do this. The programmers should be shot. - * This might actually work sometimes. */ - UWORD rval = value; - CPTR raddr = addr & 0x1FE; - if (addr & 1) { - rval |= cregs[raddr >> 1] & 0xFF00; - } else { - rval <<= 8; - rval |= cregs[raddr >> 1] & 0xFF; - } - custom_wput(raddr, rval); + int hpos = current_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); } -void custom_lput(CPTR addr, ULONG value) +void REGPARAM2 custom_bput (uaecptr addr, uae_u32 value) { - custom_wput(addr & 0xfffe, value >> 16); - custom_wput((addr+2) & 0xfffe, (UWORD)value); + 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); + 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); +}