--- uae/src/custom.c 2018/04/24 16:40:07 1.1.1.3 +++ uae/src/custom.c 2018/04/24 16:54:59 1.1.1.12 @@ -3,18 +3,10 @@ * * Custom chip emulation * - * Copyright 1995, 1996, 1997 Bernd Schmidt + * Copyright 1995-1998 Bernd Schmidt * Copyright 1995 Alessandro Bissacco */ - /* - * This file should be split into two parts. There are two concepts of a - * "frame" here: a hardware frame which emulates the display hardware of - * the A500, and a "drawing" frame, which renders data on the screen. You - * can have multiple hardware frames for one drawing frame, or completely - * inhibit drawing while hardware frames continue to be emulated. There - * should be a separate file "drawing.c" or something. - */ #include "sysconfig.h" #include "sysdeps.h" @@ -44,127 +36,41 @@ #include "autoconf.h" #include "gui.h" #include "picasso96.h" -#include "p2c.h" - -#ifdef X86_ASSEMBLY -#define LORES_HACK -#endif -#define SPRITE_COLLISIONS +#include "drawing.h" -/* - * Several people have tried this define, with not much success. Turning on - * AGA garbles the screen. A place you could start looking is the calcdiw() - * function - the AGA timing parameters are different, and apparently I - * haven't figured out the correct formula yet. Pity, the current one looks - * logical. - * - * @@@ Probably won't compile in this version. - */ - -/* #define EMULATE_AGA */ - -#ifndef EMULATE_AGA -#define AGA_CHIPSET 0 -#else -#define AGA_CHIPSET 1 -#endif +static unsigned int n_consecutive_skipped = 0; +static unsigned int total_skipped = 0; -#define SMART_UPDATE 1 - -#ifdef SUPPORT_PENGUINS -#undef SMART_UPDATE -#define SMART_UPDATE 1 -#endif - -#if AGA_CHIPSET == 1 -#define MAX_PLANES 8 -#else -#define MAX_PLANES 6 -#endif - -/* Fetched data spends 9 lores pixels somewhere in the chips before it appears - * on-screen. We don't emulate this. Instead, we cheat with the copper to - * compensate (much easier that way). */ -#define COPPER_MAGIC_FUDGE -9 -/* We ignore that many lores pixels at the start of the display. These are - * invisible anyway due to hardware DDF limits. */ -#define DISPLAY_LEFT_SHIFT 0x38 -static int lores_factor, lores_shift, sprite_width; - -#define PIXEL_XPOS(HPOS) (((HPOS)*2 - DISPLAY_LEFT_SHIFT) << lores_shift) - -/* @@@ Is maxhpos + 4 - 1 correct? (4 less isn't enough) */ -#define max_diwlastword (PIXEL_XPOS(maxhpos + 4 -1)) +#define SPRITE_COLLISIONS /* Mouse and joystick emulation */ -#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; - int buttonstate[3]; -int lastmx, lastmy; -int newmousecounters; -int ievent_alive = 0; - -static enum { normal_mouse, dont_care_mouse, follow_mouse } mousestate; - static int mouse_x, mouse_y; int joy0button, joy1button; unsigned int joy0dir, joy1dir; -static int lastspr0x,lastspr0y,lastdiffx,lastdiffy,spr0pos,spr0ctl; -static int mstepx,mstepy,xoffs=defxoffs,yoffs=defyoffs; -static int sprvbfl; - -/* Video buffer description structure. Filled in by the graphics system - * dependent code. */ - -struct vidbuf_description gfxvidinfo; /* Events */ -unsigned long int cycles, nextevent, is_lastline, did_reset; +unsigned long int cycles, nextevent, is_lastline; +static int rpt_did_reset; struct ev eventtab[ev_max]; frame_time_t vsynctime, vsyncmintime; -int vpos; -uae_u16 lof; -static int lof_changed = 0, interlace_seen = 0; - -static int copper_waiting_for_blitter, copper_active; -static const int dskdelay = 2; /* FIXME: ??? */ - -static int dblpf_ind1[256], dblpf_ind2[256], dblpf_2nd1[256], dblpf_2nd2[256]; -static int dblpf_aga1[256], dblpf_aga2[256], linear_map_256[256], lots_of_twos[256]; - -static int dblpfofs[] = { 0, 2, 4, 8, 16, 32, 64, 128 }; - -/* Big lookup tables for planar to chunky conversion. */ - -uae_u32 hirestab_h[256][2]; -uae_u32 lorestab_h[256][4]; - -uae_u32 hirestab_l[256][1]; -uae_u32 lorestab_l[256][2]; +static int vpos; +static uae_u16 lof; +static int next_lineno; +static enum nln_how nextline_how; +static int lof_changed = 0; static uae_u32 sprtaba[256],sprtabb[256]; -static uae_u32 clxtab[256]; - -/* The color lookup table. */ - -xcolnr xcolors[4096]; /* * Hardware registers of all sorts. */ -static int fmode; +static void custom_wput_1 (int, uaecptr, uae_u32) REGPARAM; static uae_u16 cregs[256]; @@ -173,123 +79,188 @@ 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; + +#define MAX_SPRITES 32 /* This is but an educated guess. It seems to be correct, but this stuff * isn't documented well. */ enum sprstate { SPR_stop, SPR_restart, SPR_waiting_start, SPR_waiting_stop }; -static enum sprstate sprst[8]; -static int spron[8]; -static uaecptr sprpt[8]; -static int sprxpos[8], sprvstart[8], sprvstop[8]; -static uae_u32 bpl1dat,bpl2dat,bpl3dat,bpl4dat,bpl5dat,bpl6dat,bpl7dat,bpl8dat; -static uae_s16 bpl1mod,bpl2mod; +struct sprite { + uaecptr pt; + int on; + int xpos; + int vstart; + int vstop; + int armed; + enum sprstate state; +}; + +static struct sprite spr[8]; + +static int sprite_vblank_endline = VBLANK_ENDLINE_NTSC + 2; + +static unsigned int sprdata[MAX_SPRITES], sprdatb[MAX_SPRITES], sprctl[MAX_SPRITES], sprpos[MAX_SPRITES]; +static int sprite_last_drawn_at[MAX_SPRITES]; +static int last_sprite_point, nr_armed; + +static uae_u32 bpl1dat, bpl2dat, bpl3dat, bpl4dat, bpl5dat, bpl6dat, bpl7dat, bpl8dat; +static uae_s16 bpl1mod, bpl2mod; static uaecptr bplpt[8]; -#ifndef SMART_UPDATE -static char *real_bplpt[8]; -#endif +uae_u8 *real_bplpt[8]; /*static int blitcount[256]; blitter debug */ -struct color_entry { -#if AGA_CHIPSET == 0 - /* X86.S expects this at the start of the structure. */ - xcolnr acolors[32]; - uae_u16 color_regs[32]; -#else - uae_u32 color_regs[256]; -#endif -}; - static struct color_entry current_colors; -struct color_entry colors_for_drawing; -static unsigned int bplcon0,bplcon1,bplcon2,bplcon3,bplcon4; +static unsigned int bplcon0, bplcon1, bplcon2, bplcon3, bplcon4; static int nr_planes_from_bplcon0, corrected_nr_planes_from_bplcon0; -static unsigned int diwstrt,diwstop,ddfstrt,ddfstop; -static unsigned int sprdata[8], sprdatb[8], sprctl[8], sprpos[8]; -static int sprarmed[8], sprite_last_drawn_at[8]; -static int last_sprite_point, nr_armed; -static uae_u16 clxdat, clxcon; -static int clx_sprmask; -static uae_u32 dskpt; -static uae_u16 dsklen,dsksync; - -static uae_u32 coplc; -static unsigned int copi1,copi2; - -static enum copper_states { - COP_stop, COP_read, COP_do_read, COP_read_ignore, COP_do_read_ignore, COP_wait, COP_morewait, COP_move, COP_skip -} copstate; -/* The time the copper needs for one cycle depends on bitplane DMA. Whenever - * possible, we calculate a fixed value and store it here. */ -static int copper_cycle_time; - -static int dsklength; - -static int plffirstline,plflastline,plfstrt,plfstop,plflinelen; -static int diwfirstword,diwlastword; -static enum { DIW_waiting_start, DIW_waiting_stop } diwstate, hdiwstate; - -int dskdmaen; /* used in cia.c */ - -/* 880 isn't a magic number, it's a safe number with some padding at the end. - * This used to be 1000, but that's excessive. (840 is too low). I'm too lazy - * to figure out the exact space needed. */ -union { - /* Let's try to align this thing. */ - double uupzuq; - long int cruxmedo; - unsigned char apixels[880]; -} pixdata; - -uae_u32 ham_linebuf[880]; -uae_u32 aga_linebuf[880], *aga_lbufptr; - -char *xlinebuffer; -int next_lineno; -static int nln_how; - -static int *amiga2aspect_line_map, *native2amiga_line_map; -static char *row_map[2049]; -static int max_drawn_amiga_line; +static unsigned int diwstrt, diwstop, diwhigh; +static int diwhigh_written; +static unsigned int ddfstrt, ddfstop; + +/* The display and data fetch windows */ + +enum diw_states +{ + DIW_waiting_start, DIW_waiting_stop +}; + +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 +}; + +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; +}; + +static struct copper cop_state; +static int copper_enabled_thisline; +static int cop_min_waittime; /* * Statistics */ /* Used also by bebox.cpp */ -unsigned long int msecs = 0, frametime = 0, timeframes = 0; +unsigned long int msecs = 0, frametime = 0, lastframetime = 0, timeframes = 0; static unsigned long int seconds_base; int bogusframe; +int n_frames; + +static int current_change_set; + +#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 + +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]; + +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; + +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; + +/* 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; + +static char thisline_changed; + + +#ifdef SMART_UPDATE +#define MARK_LINE_CHANGED do { thisline_changed = 1; } while (0) +#else +#define MARK_LINE_CHANGED do { ; } while (0) +#endif + +static struct decision thisline_decision; +static int modulos_added, plane_decided, color_decided, very_broken_program; /* * helper functions */ -int picasso_requested_on; -int picasso_on; +int rpt_available = 0; -uae_sem_t frame_sem, gui_sem, ihf_sem; -volatile int frame_do_semup; -volatile int inhibit_frame; +void reset_frame_rate_hack (void) +{ + if (currprefs.m68k_speed != -1) + return; -static int framecnt = 0; -static int frame_redraw_necessary; + if (! rpt_available) { + currprefs.m68k_speed = 0; + return; + } -static __inline__ void count_frame (void) -{ - framecnt++; - if (framecnt >= currprefs.framerate) - framecnt = 0; + rpt_did_reset = 1; + is_lastline = 0; + vsyncmintime = read_processor_time() + vsynctime; + write_log ("Resetting frame rate hack\n"); } void check_prefs_changed_custom (void) { - currprefs.framerate = changed_prefs.framerate; + currprefs.gfx_framerate = changed_prefs.gfx_framerate; /* Not really the right place... */ - if (currprefs.fake_joystick != changed_prefs.fake_joystick) { - currprefs.fake_joystick = changed_prefs.fake_joystick; + 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; @@ -297,13 +268,12 @@ void check_prefs_changed_custom (void) } -static __inline__ void setclr (uae_u16 *p, uae_u16 val) +STATIC_INLINE void setclr (uae_u16 *p, uae_u16 val) { - if (val & 0x8000) { + if (val & 0x8000) *p |= val & 0x7FFF; - } else { + else *p &= ~val; - } } __inline__ int current_hpos (void) @@ -311,131 +281,36 @@ __inline__ int current_hpos (void) return cycles - eventtab[ev_hsync].oldcycles; } -static __inline__ uae_u8 *pfield_xlateptr (uaecptr plpt, int bytecount) +STATIC_INLINE uae_u8 *pfield_xlateptr (uaecptr plpt, int bytecount) { - if (!chipmem_bank.check(plpt,bytecount)) { + 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 void calculate_copper_cycle_time (void) -{ - if (diwstate == DIW_waiting_start || !dmaen (DMA_BITPLANE)) { - copper_cycle_time = 2; - return; - } - copper_cycle_time = corrected_nr_planes_from_bplcon0 <= 4 ? 2 : -1; + return chipmem_bank.xlateaddr (plpt); } -/* line_draw_funcs: pfield_do_linetoscr, pfield_do_fill_line, decode_ham6 */ -typedef void (*line_draw_func)(int, int); - -#define LINE_UNDECIDED 1 -#define LINE_DECIDED 2 -#define LINE_DECIDED_DOUBLE 3 -#define LINE_AS_PREVIOUS 4 -#define LINE_BORDER_NEXT 5 -#define LINE_BORDER_PREV 6 -#define LINE_DONE 7 -#define LINE_DONE_AS_PREVIOUS 8 -#define LINE_REMEMBERED_AS_PREVIOUS 9 - -static char *line_drawn; -static char linestate[(maxvpos + 1)*2 + 1]; - -static int min_diwstart, max_diwstop, prev_x_adjust, linetoscr_x_adjust, linetoscr_right_x; -static int linetoscr_x_adjust_bytes; -static int thisframe_y_adjust, prev_y_adjust, thisframe_first_drawn_line, thisframe_last_drawn_line; -static int thisframe_y_adjust_real, max_ypos_thisframe, min_ypos_for_screen; -static int extra_y_adjust; - -static uae_u8 line_data[(maxvpos+1) * 2][MAX_PLANES * MAX_WORDS_PER_LINE * 2]; - -/* - * The idea behind this code is that at some point during each horizontal - * line, we decide how to draw this line. There are many more-or-less - * independent decisions, each of which can be taken at a different horizontal - * position. - * Sprites, color changes and bitplane delay changes are handled specially: - * There isn't a single decision, but a list of structures containing - * information on how to draw the line. - */ - -struct color_change { - int linepos; - int regno; - unsigned long value; -}; - -struct sprite_draw { - int linepos; - int num; - int ctl; - uae_u32 datab; -}; - -struct delay_change { - int linepos; - unsigned int value; -}; - -/* Way too much... */ -#define MAX_REG_CHANGE ((maxvpos+1) * 2 * maxhpos) -static int current_change_set; - -#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. */ -static struct sprite_draw *sprite_positions[2]; -static int max_sprite_draw = 400; -static int delta_sprite_draw = 0; -static struct color_change *color_changes[2]; -static int max_color_change = 400; -static int delta_color_change = 0; -static struct delay_change *delay_changes; -static int max_delay_change = 100; -static int delta_delay_change = 0; -#else -static struct sprite_draw sprite_positions[2][MAX_REG_CHANGE]; -static 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. */ -static struct delay_change delay_changes[MAX_REG_CHANGE]; -#endif -static struct sprite_draw *curr_sprite_positions, *prev_sprite_positions; -static struct color_change *curr_color_changes, *prev_color_changes; - -static int next_color_change, next_sprite_draw, next_delay_change; - -static struct color_entry color_tables[2][(maxvpos+1) * 2]; -static struct color_entry *curr_color_tables, *prev_color_tables; -static int next_color_entry, remembered_color_entry, drawing_color_matches; -static enum { color_match_acolors, color_match_full } color_match_type; -static int color_src_match, color_dest_match, color_compare_result; - -static int last_redraw_point; - -static int first_drawn_line, last_drawn_line; -static int first_block_line, last_block_line; - -static __inline__ void docols(struct color_entry *colentry) +STATIC_INLINE void docols (struct color_entry *colentry) { -#if AGA_CHIPSET == 0 int i; - for (i = 0; i < 32; i++) { - int v = colentry->color_regs[i]; - if (v < 0 || v > 4095) - continue; - colentry->acolors[i] = xcolors[v]; + + if (currprefs.chipset_mask & CSMASK_AGA) { + for (i = 0; i < 256; i++) { + int v = color_reg_get (colentry, i); + if(v < 0 || v > 16777215) + continue; + colentry->acolors[i] = CONVERT_RGB (v); + } + } else { + for (i = 0; i < 32; i++) { + int v = color_reg_get (colentry, i); + if (v < 0 || v > 4095) + continue; + colentry->acolors[i] = xcolors[v]; + } } -#endif } void notice_new_xcolors (void) @@ -443,91 +318,21 @@ void notice_new_xcolors (void) int i; docols(¤t_colors); - docols(&colors_for_drawing); - for (i = 0; i < (maxvpos+1)*2; i++) { +/* docols(&colors_for_drawing);*/ + for (i = 0; i < (MAXVPOS + 1)*2; i++) { docols(color_tables[0]+i); docols(color_tables[1]+i); } } -void notice_screen_contents_lost (void) -{ - frame_redraw_necessary = 2; -} - -static void init_regchanges (void) -{ - size_t i; - - next_color_change = 0; - next_sprite_draw = 0; - current_change_set = 0; - for (i = 0; i < sizeof linestate / sizeof *linestate; i++) - linestate[i] = LINE_UNDECIDED; -} - -/* struct decision contains things we save across drawing frames for - * comparison (smart update stuff). */ -struct decision { - unsigned long color0; - int which; - int plfstrt, plflinelen; - int diwfirstword, diwlastword; - int ctable; - - uae_u16 bplcon0, bplcon1, bplcon2; -#if 0 /* We don't need this. */ - uae_u16 bplcon3; -#endif -#if AGA_CHIPSET == 1 - uae_u16 bplcon4; -#endif -}; - -/* Anything related to changes in hw registers during the DDF for one - * line. */ -struct draw_info { - int first_sprite_draw, last_sprite_draw; - int first_color_change, last_color_change; - int first_delay_change, last_delay_change; - int nr_color_changes, nr_sprites; -}; - -/* 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_hires; - -/* These are generated by the drawing code from the line_decisions array for - * each line that needs to be drawn. */ -static int bplehb, bplham, bpldualpf, bpldualpfpri, bplplanecnt, bplhires; -static int bpldelay1, bpldelay2; -static int plfpri[3]; - -static struct decision line_decisions[2 * (maxvpos+1) + 1]; -static struct draw_info line_drawinfo[2][2 * (maxvpos+1) + 1]; -static struct draw_info *curr_drawinfo, *prev_drawinfo; -static struct decision *dp_for_drawing; -static struct draw_info *dip_for_drawing; - -static char line_changed[2 * (maxvpos+1)]; - -#ifdef SMART_UPDATE -#define MARK_LINE_CHANGED(l) do { line_changed[l] = 1; } while (0) -#else -#define MARK_LINE_CHANGED(l) do { } while (0) -#endif - -static struct decision thisline_decision; -static int modulos_added, plane_decided, color_decided, very_broken_program; - -static void do_sprites(int currvp, int currhp); +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. */ - memcpy (curr_color_tables + next_color_entry, ¤t_colors, sizeof current_colors); + color_reg_cpy (curr_color_tables + next_color_entry, ¤t_colors); remembered_color_entry = next_color_entry++; } thisline_decision.ctable = remembered_color_entry; @@ -542,72 +347,33 @@ static void remember_ctable (void) changed = 1; color_src_match = color_dest_match = -1; } else { - color_compare_result = memcmp (&prev_color_tables[oldctable].color_regs, - ¤t_colors.color_regs, - sizeof current_colors.color_regs) != 0; + color_compare_result = color_reg_cmp (&prev_color_tables[oldctable], ¤t_colors) != 0; if (color_compare_result) changed = 1; color_src_match = oldctable; color_dest_match = remembered_color_entry; } - if (changed) { - line_changed[next_lineno] = 1; - } + thisline_changed |= changed; } else { /* We know the result of the comparison */ if (color_compare_result) - line_changed[next_lineno] = 1; + thisline_changed = 1; } } static void remember_ctable_for_border (void) { remember_ctable (); -#if 0 - if (remembered_color_entry == -1) { - /* The colors changed since we last recorded a color map. Record a - * new one. */ - memcpy (curr_color_tables + next_color_entry, ¤t_colors, sizeof current_colors); - remembered_color_entry = next_color_entry++; - } - 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 = memcmp (&prev_color_tables[oldctable].color_regs, - ¤t_colors.color_regs, - sizeof current_colors.color_regs) != 0; - if (color_compare_result) - changed = 1; - color_src_match = oldctable; - color_dest_match = remembered_color_entry; - } - if (changed) { - line_changed[next_lineno] = 1; - } - } else { - /* We know the result of the comparison */ - if (color_compare_result) - line_changed[next_lineno] = 1; - } -#endif } /* 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 (void) +static void decide_diw (int hpos) { + int pix_hpos = PIXEL_XPOS (hpos); if (hdiwstate == DIW_waiting_start && thisline_decision.diwfirstword == -1 - && PIXEL_XPOS (current_hpos ()) >= diwfirstword) + && pix_hpos >= diwfirstword && last_diw_pix_hpos < diwfirstword) { thisline_decision.diwfirstword = diwfirstword; hdiwstate = DIW_waiting_stop; @@ -615,22 +381,23 @@ static void decide_diw (void) * 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 (next_lineno); + MARK_LINE_CHANGED; thisline_decision.diwlastword = -1; } if (hdiwstate == DIW_waiting_stop && thisline_decision.diwlastword == -1 - && PIXEL_XPOS (current_hpos ()) >= diwlastword) + && pix_hpos >= diwlastword && last_diw_pix_hpos < diwlastword) { thisline_decision.diwlastword = diwlastword; hdiwstate = DIW_waiting_start; if (thisline_decision.diwlastword != line_decisions[next_lineno].diwlastword) - MARK_LINE_CHANGED (next_lineno); + 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 it. - * The data fetch starting position and length are passed as parameters. */ -static __inline__ void decide_as_playfield (int startpos, int len) +/* 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; @@ -645,36 +412,111 @@ static __inline__ void decide_as_playfie /* These are for comparison. */ thisline_decision.bplcon0 = bplcon0; thisline_decision.bplcon2 = bplcon2; -#if AGA_CHIPSET == 1 thisline_decision.bplcon4 = bplcon4; -#endif + thisline_decision.fmode = fmode; #ifdef SMART_UPDATE if (line_decisions[next_lineno].plfstrt != thisline_decision.plfstrt || line_decisions[next_lineno].plflinelen != thisline_decision.plflinelen || line_decisions[next_lineno].bplcon0 != thisline_decision.bplcon0 || line_decisions[next_lineno].bplcon2 != thisline_decision.bplcon2 -#if AGA_CHIPSET == 1 || line_decisions[next_lineno].bplcon4 != thisline_decision.bplcon4 -#endif + || line_decisions[next_lineno].fmode != thisline_decision.fmode ) #endif /* SMART_UPDATE */ - line_changed[next_lineno] = 1; + 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. */ -static __inline__ void post_decide_line (void) + * 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 init_broken_program (void) { - static int warned = 0; - int tmp; + int i; + if (very_broken_program) + return; + very_broken_program = 1; + for (i = 0; i < 8; i++) + broken_plane_sub[i] = i >= decided_nr_planes || thisline_decision.which != 1 ? -1 : 0; +} + +static void adjust_broken_program (int hpos) +{ + int tmp1, tmp2; + int i; + + /* Magic again... :-/ */ + hpos += 4; + + if (decided_res == RES_HIRES) { + tmp1 = hpos & 3; + tmp2 = hpos & ~3; + } else if (decided_res == RES_SUPERHIRES) { + tmp1 = hpos & 1; + tmp2 = hpos & ~1; + } else { + tmp1 = hpos & 7; + tmp2 = hpos & ~7; + } + 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; + } + } + } +} - if (thisline_decision.which == 1 && current_hpos () < thisline_decision.plfstrt + thisline_decision.plflinelen - && ((bplcon0 & 0x7000) == 0 || !dmaen (DMA_BITPLANE))) +STATIC_INLINE void set_decided_res (void) +{ + decided_res = RES_LORES; + if (bplcon0 & 0x8000) + decided_res = RES_HIRES; + if (bplcon0 & 0x40) + decided_res = RES_SUPERHIRES; +} + +STATIC_INLINE void post_decide_line (int hpos) +{ + 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 = current_hpos() - thisline_decision.plfstrt; + thisline_decision.plflinelen = hpos - thisline_decision.plfstrt; thisline_decision.plflinelen &= 7; if (thisline_decision.plflinelen == 0) thisline_decision.which = -1; @@ -683,45 +525,60 @@ static __inline__ void post_decide_line return; } - if (thisline_decision.which != -1 || diwstate == DIW_waiting_start || (bplcon0 & 0x7000) == 0 - || !dmaen (DMA_BITPLANE) || current_hpos () >= thisline_decision.plfstrt + thisline_decision.plflinelen) + 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 ;-) */ - if (!warned) { - write_log ("That program you are running is _really_ broken.\n"); - warned = 1; + { + static int warned = 0; + if (!warned) { + write_log ("That program you are running is _really_ broken.\n"); + warned = 1; + } } #endif + init_broken_program (); - decided_hires = (bplcon0 & 0x8000) == 0x8000; decided_nr_planes = nr_planes_from_bplcon0; + thisline_decision.bplcon0 &= 0xFEF; + thisline_decision.bplcon0 |= bplcon0 & 0xF010; - /* Magic 12, Ray of Hope 2 demo does ugly things. Looks great from the - * outside, rotten inside. */ - if (decided_hires) { - tmp = current_hpos () & ~3; - very_broken_program = current_hpos () & 3; - } else { - tmp = current_hpos () & ~7; - very_broken_program = current_hpos () & 7; - } - MARK_LINE_CHANGED (next_lineno); /* Play safe. */ - decide_as_playfield (tmp, plflinelen + plfstrt - tmp); + MARK_LINE_CHANGED; /* Play safe. */ + decide_as_playfield (plfstrt, plflinelen); + adjust_broken_program (hpos); } -static void decide_line_1 (void) +static void decide_line_1 (int hpos) { - do_sprites(vpos, current_hpos ()); + 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; - calculate_copper_cycle_time (); } if (diwstate == DIW_waiting_stop && vpos == plflastline) { diwstate = DIW_waiting_start; - calculate_copper_cycle_time (); } if (framecnt != 0) { @@ -737,21 +594,21 @@ static void decide_line_1 (void) return; } - decided_hires = (bplcon0 & 0x8000) == 0x8000; + 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_hires && decided_nr_planes > 2) - || (!decided_hires && decided_nr_planes > 4))) + && ((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_hires) + if (decided_res == RES_HIRES) pl <<= 1; if (pl == 8) eventtab[ev_blitter].evtime += plflinelen; @@ -767,23 +624,23 @@ static void decide_line_1 (void) /* 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 (void) +STATIC_INLINE void decide_line (int hpos) { - if (thisline_decision.which == 0 && current_hpos() >= plfstrt) - decide_line_1 (); + 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 regno, unsigned long value) +static void record_color_change (int hpos, int regno, unsigned long value) { /* Early positions don't appear on-screen. */ - if (framecnt != 0 || vpos < minfirstline || current_hpos () < 0x18 + if (framecnt != 0 || vpos < minfirstline || hpos < 0x18 /*|| currprefs.emul_accuracy == 0*/) return; - decide_diw (); - decide_line (); + 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 @@ -805,37 +662,37 @@ static void record_color_change (int reg && (diwstate == DIW_waiting_start || thisline_decision.diwfirstword < 0 || thisline_decision.diwlastword >= 0 || thisline_decision.which == 0 - || (thisline_decision.which == 1 && current_hpos() >= thisline_decision.plfstrt + thisline_decision.plflinelen))) + || (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 = current_colors.color_regs[0]; + thisline_decision.color0 = color_reg_get (¤t_colors, 0); if (line_decisions[next_lineno].color0 != value) - line_changed[next_lineno] = 1; + thisline_changed = 1; } /* Anything else gets recorded in the color_changes table. */ #ifdef OS_WITHOUT_MEMORY_MANAGEMENT - if(next_color_change >= max_color_change) { + if (next_color_change >= max_color_change) { ++delta_color_change; return; } #endif - curr_color_changes[next_color_change].linepos = current_hpos (); + 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 (void) +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 (); + decide_line (hpos); /* Half-hearted attempt to get things right even when post_decide_line() changes * the decision afterwards. */ if (thisline_decision.which != 1) { @@ -845,12 +702,12 @@ static void decide_delay (void) /* @@@ Could check here for DDF stopping earlier than DIW */ #ifdef OS_WITHOUT_MEMORY_MANAGEMENT - if(next_delay_change >= max_delay_change) { + if (next_delay_change >= max_delay_change) { ++delta_delay_change; return; } #endif - delay_changes[next_delay_change].linepos = current_hpos (); + delay_changes[next_delay_change].linepos = hpos; delay_changes[next_delay_change++].value = bplcon1; if (!warned) { warned = 1; @@ -859,14 +716,14 @@ static void decide_delay (void) } /* - * The decision which bitplane pointers to use is not taken at plfstrt, since + * 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 (void) +static void decide_plane (int hpos) { int i, bytecount; @@ -874,34 +731,35 @@ static void decide_plane (void) return; if (decided_nr_planes == -1 /* Still undecided */ - || current_hpos () < thisline_decision.plfstrt + thisline_decision.plflinelen) + || hpos < thisline_decision.plfstrt + thisline_decision.plflinelen) return; plane_decided = 1; - bytecount = plflinelen / (decided_hires ? 4 : 8) * 2; + bytecount = plflinelen / RES_SHIFT (decided_res) * 2; 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); + uae_u8 *real_ptr = pfield_xlateptr (pt, bytecount); if (real_ptr == NULL) - real_ptr = pfield_xlateptr(0, 0); + real_ptr = pfield_xlateptr (0, 0); #ifdef SMART_UPDATE #if 1 - if (line_changed[next_lineno]) + if (thisline_changed) memcpy (dataptr, real_ptr, bytecount); else #endif - line_changed[next_lineno] |= memcmpy (dataptr, real_ptr, bytecount); + thisline_changed |= memcmpy (dataptr, real_ptr, bytecount); #else real_bplpt[i] = real_ptr; #endif @@ -912,29 +770,13 @@ static void decide_plane (void) uaecptr pt = bplpt[i]; uae_u8 *real_ptr; - if (decided_hires) { - switch (i) { - case 3: pt -= 2; - case 2: pt -= (very_broken_program >= 3 ? 2 : 0); break; - case 1: pt -= (very_broken_program >= 2 ? 2 : 0); break; - case 0: break; - } - } else { - switch (i) { - case 5: pt -= (very_broken_program >= 3 ? 2 : 0); break; - case 4: pt -= (very_broken_program >= 7 ? 2 : 0); break; - case 3: pt -= (very_broken_program >= 2 ? 2 : 0); break; - case 2: pt -= (very_broken_program >= 6 ? 2 : 0); break; - case 1: pt -= (very_broken_program >= 4 ? 2 : 0); break; - case 0: break; - } - } - real_ptr = pfield_xlateptr(pt, bytecount); + 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 (!line_changed[next_lineno]) - line_changed[next_lineno] |= memcmpy (dataptr, real_ptr, bytecount); + if (!thisline_changed) + thisline_changed |= memcmpy (dataptr, real_ptr, bytecount); else memcpy (dataptr, real_ptr, bytecount); #else @@ -949,11 +791,12 @@ static void decide_plane (void) * This routine decides whether the new value is already relevant for the * current line. */ -static void decide_modulos (void) +static void decide_modulos (int hpos) { /* All this effort just for the Sanity WOC demo... */ - decide_line (); - if (decided_nr_planes != -1 && current_hpos() >= thisline_decision.plfstrt + thisline_decision.plflinelen) + decide_line (hpos); + if (decided_nr_planes != -1 + && hpos >= thisline_decision.plfstrt + thisline_decision.plflinelen) return; decided_bpl1mod = bpl1mod; decided_bpl2mod = bpl2mod; @@ -965,15 +808,15 @@ static void decide_modulos (void) * 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 (void) +static void do_modulos (int hpos) { /* 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 - && current_hpos() >= thisline_decision.plfstrt + thisline_decision.plflinelen) + && hpos >= thisline_decision.plfstrt + thisline_decision.plflinelen) { - int bytecount = thisline_decision.plflinelen / (decided_hires ? 4 : 8) * 2; + int bytecount = thisline_decision.plflinelen / RES_SHIFT (decided_res) * 2; int add1 = bytecount + decided_bpl1mod; int add2 = bytecount + decided_bpl2mod; @@ -988,35 +831,22 @@ static void do_modulos (void) case 2: bplpt[1] += add2; case 1: bplpt[0] += add1; } - } else if (decided_hires) { /* @@@ used to be bplhires which is clearly wrong */ - 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 - 2; - case 3: bplpt[2] += add1 - (very_broken_program >= 3 ? 2 : 0); - case 2: bplpt[1] += add2 - (very_broken_program >= 2 ? 2 : 0); - case 1: bplpt[0] += add1; - } - } else { - switch (decided_nr_planes) { - case 8: bplpt[7] += add2; - case 7: bplpt[6] += add1; - case 6: bplpt[5] += add2 - (very_broken_program >= 3 ? 2 : 0); - case 5: bplpt[4] += add1 - (very_broken_program >= 7 ? 2 : 0); - case 4: bplpt[3] += add2 - (very_broken_program >= 2 ? 2 : 0); - case 3: bplpt[2] += add1 - (very_broken_program >= 6 ? 2 : 0); - case 2: bplpt[1] += add2 - (very_broken_program >= 4 ? 2 : 0); - 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; } } -static __inline__ void record_sprite (int spr, int sprxp) +STATIC_INLINE void record_sprite (int spr, int sprxp) { int pos = next_sprite_draw; unsigned int data, datb; @@ -1027,9 +857,6 @@ static __inline__ void record_sprite (in return; } #endif - data = sprdata[spr]; - datb = sprdatb[spr]; - /* XXX FIXME, this isn't very clever, but it might do */ for (;;) { if (pos == curr_drawinfo[next_lineno].first_sprite_draw) @@ -1052,31 +879,34 @@ static __inline__ void record_sprite (in 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 decide_sprites (void) +static void decide_sprites (int hpos) { - int nrs[8], posns[8], count, i; - int point = PIXEL_XPOS (current_hpos ()); + int nrs[MAX_SPRITES], posns[MAX_SPRITES]; + int count, i; + int point = PIXEL_XPOS (hpos); - if (framecnt != 0 || current_hpos() < 0x14 || nr_armed == 0 || point == last_sprite_point) + if (framecnt != 0 || hpos < 0x14 || nr_armed == 0 || point == last_sprite_point) return; - decide_diw (); - decide_line (); + decide_diw (hpos); + decide_line (hpos); if (thisline_decision.which != 1) return; count = 0; for (i = 0; i < 8; i++) { - int sprxp = sprxpos[i]; + int sprxp = spr[i].xpos; int j, bestp; - if (!sprarmed[i] || sprxp < 0 || sprxp > point || last_sprite_point >= sprxp) + if (! spr[i].armed || sprxp < 0 || sprxp > point || last_sprite_point >= sprxp) continue; if ((thisline_decision.diwfirstword >= 0 && sprxp + sprite_width < thisline_decision.diwfirstword) || (thisline_decision.diwlastword >= 0 && sprxp > thisline_decision.diwlastword)) @@ -1097,7 +927,7 @@ static void decide_sprites (void) count++; } for (i = 0; i < count; i++) - record_sprite(nrs[i], posns[i]); + record_sprite (nrs[i], posns[i]); last_sprite_point = point; } @@ -1109,13 +939,14 @@ static void finish_decisions (void) struct draw_info *dip_old; struct decision *dp; int changed; + int hpos = current_hpos (); if (framecnt != 0) return; - decide_diw (); + decide_diw (hpos); if (thisline_decision.which == 0) - decide_line_1 (); + 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 @@ -1123,25 +954,22 @@ static void finish_decisions (void) if (hdiwstate == DIW_waiting_stop) { thisline_decision.diwlastword = max_diwlastword; if (thisline_decision.diwlastword != line_decisions[next_lineno].diwlastword) - MARK_LINE_CHANGED (next_lineno); + MARK_LINE_CHANGED; } if (line_decisions[next_lineno].which != thisline_decision.which) - line_changed[next_lineno] = 1; - decide_plane (); + thisline_changed = 1; + decide_plane (hpos); dip = curr_drawinfo + next_lineno; dip_old = prev_drawinfo + next_lineno; dp = line_decisions + next_lineno; - changed = line_changed[next_lineno]; + changed = thisline_changed; if (thisline_decision.which == 1) { - if (diwlastword > max_diwstop) - max_diwstop = diwlastword; - if (diwfirstword < min_diwstart) - min_diwstart = diwfirstword; + record_diw_line (diwfirstword, diwlastword); - decide_sprites(); + decide_sprites (hpos); if (thisline_decision.bplcon1 != line_decisions[next_lineno].bplcon1) changed = 1; @@ -1158,7 +986,7 @@ static void finish_decisions (void) remember_ctable_for_border (); } if (thisline_decision.which == -1 && thisline_decision.color0 == 0xFFFFFFFFul) - thisline_decision.color0 = current_colors.color_regs[0]; + thisline_decision.color0 = color_reg_get (¤t_colors, 0); dip->nr_color_changes = next_color_change - dip->first_color_change; dip->nr_sprites = next_sprite_draw - dip->first_sprite_draw; @@ -1179,9 +1007,11 @@ static void finish_decisions (void) prev_sprite_positions + dip_old->first_sprite_draw, dip->nr_sprites * sizeof *curr_sprite_positions) != 0))) changed = 1; + if (thisline_decision.plfleft != line_decisions[next_lineno].plfleft) + changed = 1; if (changed) { - line_changed[next_lineno] = 1; + thisline_changed = 1; *dp = thisline_decision; } else /* The only one that may differ: */ @@ -1198,18 +1028,20 @@ static void reset_decisions (void) decided_bpl2mod = bpl2mod; decided_nr_planes = -1; - /* decided_hires shouldn't be touched before it's initialized by decide_line(). */ + 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 (next_lineno); + MARK_LINE_CHANGED; } thisline_decision.ctable = -1; thisline_decision.color0 = 0xFFFFFFFFul; - line_changed[next_lineno] = 0; + 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; @@ -1220,6 +1052,9 @@ static void reset_decisions (void) plane_decided = 0; color_decided = 0; very_broken_program = 0; + + last_diw_pix_hpos = -1; + last_ddf_pix_hpos = -1; } /* Initialize the decision array, once before the emulator really starts. */ @@ -1231,12 +1066,95 @@ static void init_decisions (void) } } -/* Calculate display window and data fetch values from the corresponding - * hardware registers. */ +/* 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 { + maxvpos = MAXVPOS_NTSC; + maxhpos = MAXHPOS_NTSC; + minfirstline = MINFIRSTLINE_NTSC; + vblank_endline = VBLANK_ENDLINE_NTSC; + vblank_hz = VBLANK_HZ_NTSC; + } + vsynctime = syncbase / vblank_hz; + + write_log ("Using %s timing\n", isntsc ? "NTSC" : "PAL"); +} + +void expand_fetchmodes (int fmode, int bplcon0) +{ + 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) { - diwfirstword = ((diwstrt & 0xFF) - DISPLAY_LEFT_SHIFT - 1) << lores_shift; - diwlastword = ((diwstop & 0xFF) + 0x100 - DISPLAY_LEFT_SHIFT - 1) << lores_shift; + 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; @@ -1245,8 +1163,9 @@ static void calcdiw (void) if (diwlastword < 0) diwlastword = 0; - plffirstline = diwstrt >> 8; - plflastline = diwstop >> 8; + plffirstline = vstrt; + plflastline = vstop; + #if 0 /* This happens far too often. */ if (plffirstline < minfirstline) { @@ -1254,10 +1173,10 @@ static void calcdiw (void) plffirstline = minfirstline; } #endif - if ((plflastline & 0x80) == 0) plflastline |= 0x100; + #if 0 /* Turrican does this */ if (plflastline > 313) { - fprintf(stderr, "Warning: Playfield out of range!\n"); + fprintf (stderr, "Warning: Playfield out of range!\n"); plflastline = 313; } #endif @@ -1268,725 +1187,75 @@ static void calcdiw (void) if (plfstop > 0xD8) plfstop = 0xD8; if (plfstrt > plfstop) plfstrt = plfstop; - /* ! If the masking operation is changed, the pfield_doline code could break - * on some systems (alignment) */ - /* This actually seems to be correct now, at least the non-AGA stuff... */ - plfstrt &= ~3; - plfstop &= ~3; - /* @@@ Start looking for AGA bugs here... (or maybe even in the above masking ops) */ - 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; -} - -/* - * Screen update macros/functions - */ - -static unsigned int ham_lastcolor; - -static void init_ham_decoding(int first) -{ - int pix = dp_for_drawing->diwfirstword; - ham_lastcolor = colors_for_drawing.color_regs[0]; - while (pix < first) { - int pv = pixdata.apixels[pix]; - switch(pv & 0x30) { - case 0x00: ham_lastcolor = colors_for_drawing.color_regs[pv]; break; - case 0x10: ham_lastcolor &= 0xFF0; ham_lastcolor |= (pv & 0xF); break; - case 0x20: ham_lastcolor &= 0x0FF; ham_lastcolor |= (pv & 0xF) << 8; break; - case 0x30: ham_lastcolor &= 0xF0F; ham_lastcolor |= (pv & 0xF) << 4; break; - } - pix++; - } -} - -static void decode_ham6 (int pix, int stoppos) -{ - uae_u32 *buf = ham_linebuf; - - if (!bplham || bplplanecnt != 6) - return; - - if (stoppos > dp_for_drawing->diwlastword) - stoppos = dp_for_drawing->diwlastword; - if (pix < dp_for_drawing->diwfirstword) { - ham_lastcolor = colors_for_drawing.color_regs[0]; - pix = dp_for_drawing->diwfirstword; - } -#ifdef LORES_HACK - if (currprefs.gfx_lores == 2) - pix <<= 1, stoppos <<= 1; -#endif - while (pix < stoppos) { - int pv = pixdata.apixels[pix]; - switch(pv & 0x30) { - case 0x00: ham_lastcolor = colors_for_drawing.color_regs[pv]; break; - case 0x10: ham_lastcolor &= 0xFF0; ham_lastcolor |= (pv & 0xF); break; - case 0x20: ham_lastcolor &= 0x0FF; ham_lastcolor |= (pv & 0xF) << 8; break; - case 0x30: ham_lastcolor &= 0xF0F; ham_lastcolor |= (pv & 0xF) << 4; break; - } - - buf[pix++] = ham_lastcolor; - } -} + expand_fetchmodes (fmode, bplcon0); + fetch = fetchsize >> fetchstart_shift; + plflinelen = ((((plfstop - plfstrt + fetchstart - 1) >> fetchstart_shift) + + fetch + (fetch - 1)) & ~(fetch - 1) ) << fetchstart_shift; #if 0 -static void decode_ham_aga (int pix, int stoppos) -{ - static uae_u32 lastcolor; - uae_u32 *buf = ham_linebuf; - - if (!bplham || (bplplanecnt != 6 && bplplanecnt != 8)) - return; - - if (pix <= dp_for_drawing->diwfirstword) { - pix = dp_for_drawing->diwfirstword; - lastcolor = colors_for_drawing.color_regs[0]; - } - - if (dp_for_drawing->bplplanecnt == 6) { - /* HAM 6 */ - while (pix < dp_for_drawing->diwlastword && pix < stoppos) { - int pv = pixdata.apixels[pix]; - switch(pv & 0x30) { - case 0x00: lastcolor = colors_for_drawing.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 (dp_for_drawing->bplplanecnt == 8) { - /* HAM 8 */ - while (pix < dp_for_drawing->diwlastword && pix < stoppos) { - int pv = pixdata.apixels[pix]; - switch(pv & 0x3) { - case 0x0: lastcolor = colors_for_drawing.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; - } - } -} + if (plfstrt + plflinelen != plfstop + fetchsize) + printf ("%d + %d vs %d + %d\n", plfstrt, plflinelen, plfstop, fetchsize); #endif - -#if AGA_CHIPSET != 0 -/* WARNING: Not too much of this will work correctly yet. */ - -static void pfield_linetoscr_aga(int pix, int stoppos) -{ - uae_u32 *buf = aga_lbufptr; - int i; - int xor = (uae_u8)(bplcon4 >> 8); - int oldpix = pix; \ - - buf -= pix; \ - - for (i = 0; i < stoppos; i++) - pixdata.apixels[i] ^= xor; - - while (pix < diwfirstword && pix < stoppos) { - buf[pix++] = colors_for_drawing.color_regs[0]; - } - if (bplham) { - while (pix < diwlastword && pix < stoppos) { - uae_u32 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] = colors_for_drawing.color_regs[pixcol]; - } else { - int val = lookup[pixdata.apixels[pix]]; - if (pfno == 2) - val += dblpfofs[(bplcon2 >> 10) & 7]; - buf[pix] = colors_for_drawing.color_regs[val]; - } - pix++; - } - } else if (bplehb) { - while (pix < diwlastword && pix < stoppos) { - int pixcol = pixdata.apixels[pix]; - uae_u32 d = colors_for_drawing.color_regs[pixcol]; - /* What about sprites? */ - if (pixcol & 0x20) - d = (d & 0x777777) >> 1; - buf[pix] = d; - pix++; - } - } else { - while (pix < diwlastword && pix < stoppos) { - int pixcol = pixdata.apixels[pix]; - buf[pix] = colors_for_drawing.color_regs[pixcol]; - pix++; - } - } - while (pix < stoppos) { - buf[pix++] = colors_for_drawing.color_regs[0]; - } - aga_lbufptr += pix - oldpix; -} - -static void aga_translate32(int start, int stop) -{ - memcpy (((uae_u32 *)xlinebuffer) + start, aga_linebuf + start, 4*(stop-start)); -} - -static void aga_translate16(int start, int stop) -{ - int i; - for (i = start; i < stop; i++) { - uae_u32 d = aga_linebuf[i]; - uae_u16 v = ((d & 0xF0) >> 4) | ((d & 0xF000) >> 8) | ((d & 0xF00000) >> 12); - ((uae_u16 *)xlinebuffer)[i] = xcolors[v]; - } -} - -static void aga_translate8(int start, int stop) -{ - int i; - for (i = start; i < stop; i++) { - uae_u32 d = aga_linebuf[i]; - uae_u16 v = ((d & 0xF0) >> 4) | ((d & 0xF000) >> 8) | ((d & 0xF00000) >> 12); - ((uae_u8 *)xlinebuffer)[i] = xcolors[v]; - } -} -#endif - -static int linetoscr_double_offset; - -#define LINE_TO_SCR(NAME, TYPE, DO_DOUBLE, CONVERT) \ -static void NAME(int pix, int lframe_end, int diw_end, int stoppos) \ -{ \ - TYPE *buf = ((TYPE *)xlinebuffer); \ - int oldpix = pix; \ - /* These are different for register-allocation purposes. */ \ - TYPE d1, d2; \ - int offset; \ -\ - if (DO_DOUBLE) offset = linetoscr_double_offset / sizeof(TYPE); \ -\ - d1 = CONVERT(colors_for_drawing.acolors[0]); \ - while (pix < lframe_end) { \ - buf[pix] = d1; if (DO_DOUBLE) buf[pix+offset] = d1; \ - pix++; \ - } \ - if (bplham && bplplanecnt == 6) { \ - /* HAM 6 */ \ - while (pix < diw_end) { \ - TYPE d = CONVERT(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 < diw_end) { \ - int pixcol = pixdata.apixels[pix]; \ - TYPE d; \ - d = CONVERT(colors_for_drawing.acolors[lookup[pixcol]]); \ - buf[pix] = d; if (DO_DOUBLE) buf[pix+offset] = d; \ - pix++; \ - } \ - } else if (bplehb) { \ - while (pix < diw_end) { \ - int p = pixdata.apixels[pix]; \ - TYPE d = CONVERT (colors_for_drawing.acolors[p]); \ - if (p >= 32) d = CONVERT(xcolors[(colors_for_drawing.color_regs[p-32] >> 1) & 0x777]); \ - buf[pix] = d; if (DO_DOUBLE) buf[pix+offset] = d; \ - pix++; \ - } \ - } else { \ - while (pix < diw_end) { \ - TYPE d = CONVERT (colors_for_drawing.acolors[pixdata.apixels[pix]]); \ - buf[pix] = d; if (DO_DOUBLE) buf[pix+offset] = d; \ - pix++; \ - } \ - } \ - d2 = CONVERT (colors_for_drawing.acolors[0]); \ - while (pix < stoppos) { \ - buf[pix] = d2; if (DO_DOUBLE) buf[pix+offset] = d2; \ - pix++; \ - } \ -} - -#define FILL_LINE(NAME, TYPE, CONVERT) \ -static void NAME(char *buf, int start, int stop) \ -{ \ - TYPE *b = (TYPE *)buf; \ - int i;\ - xcolnr col = colors_for_drawing.acolors[0]; \ - for (i = start; i < stop; i++) \ - b[i] = CONVERT (col); \ -} - -LINE_TO_SCR(pfield_linetoscr_8, uae_u8, 0,) -LINE_TO_SCR(pfield_linetoscr_16, uae_u16, 0,) -LINE_TO_SCR(pfield_linetoscr_32, uae_u32, 0,) -LINE_TO_SCR(pfield_linetoscr_8_double_slow, uae_u8, 1,) -LINE_TO_SCR(pfield_linetoscr_16_double_slow, uae_u16, 1,) -LINE_TO_SCR(pfield_linetoscr_32_double_slow, uae_u32, 1,) - -FILL_LINE(fill_line_8, uae_u8,) -FILL_LINE(fill_line_16, uae_u16,) -FILL_LINE(fill_line_32, uae_u32,) - -#ifdef HAVE_UAE_U24 -LINE_TO_SCR(pfield_linetoscr_24, uae_u24, 0, uae24_convert) -LINE_TO_SCR(pfield_linetoscr_24_double_slow, uae_u24, 1, uae24_convert) -FILL_LINE(fill_line_24, uae_u24, uae24_convert) -#else -/* Dummy versions */ -static void pfield_linetoscr_24 (int pix, int lframe_end, int diw_end, int stoppos) -{ -} -static void pfield_linetoscr_24_double_slow (int pix, int lframe_end, int diw_end, int stoppos) -{ -} -static void fill_line_24 (char *buf, int start, int stop) -{ -} -#endif - -static __inline__ void fill_line_full (void) -{ - switch (gfxvidinfo.pixbytes) { - case 1: fill_line_8(xlinebuffer, linetoscr_x_adjust, linetoscr_x_adjust + gfxvidinfo.width); break; - case 2: fill_line_16(xlinebuffer, linetoscr_x_adjust, linetoscr_x_adjust + gfxvidinfo.width); break; - case 3: fill_line_24(xlinebuffer, linetoscr_x_adjust, linetoscr_x_adjust + gfxvidinfo.width); break; - case 4: fill_line_32(xlinebuffer, linetoscr_x_adjust, linetoscr_x_adjust + gfxvidinfo.width); break; - } } -#define fill_line fill_line_full - -#define pfield_linetoscr_full8 pfield_linetoscr_8 -#define pfield_linetoscr_full16 pfield_linetoscr_16 -#define pfield_linetoscr_full24 pfield_linetoscr_24 -#define pfield_linetoscr_full32 pfield_linetoscr_32 - -#define pfield_linetoscr_full8_double pfield_linetoscr_8_double_slow -#define pfield_linetoscr_full16_double pfield_linetoscr_16_double_slow -#define pfield_linetoscr_full24_double pfield_linetoscr_24_double_slow -#define pfield_linetoscr_full32_double pfield_linetoscr_32_double_slow - -#if 1 && defined(X86_ASSEMBLY) -/* This version of fill_line is probably a win on all machines, but for - * now I'm cautious */ -#undef fill_line -static __inline__ void fill_line (void) -{ - int shift; - int nints, nrem; - int *start; - xcolnr val; - -#ifdef HAVE_UAE_U24 - if (gfxvidinfo.pixbytes == 3) { - fill_line_24 (xlinebuffer, linetoscr_x_adjust, linetoscr_x_adjust + gfxvidinfo.width); - return; - } -#endif - - shift = 0; - if (gfxvidinfo.pixbytes == 2) - shift = 1; - if (gfxvidinfo.pixbytes == 4) - shift = 2; - - nints = gfxvidinfo.width >> (2-shift); - nrem = nints & 7; - nints &= ~7; - start = (int *)(((char *)xlinebuffer) + (linetoscr_x_adjust << shift)); - val = colors_for_drawing.acolors[0]; - for (; nints > 0; nints -= 8, start+=8) { - *start = val; - *(start+1) = val; - *(start+2) = val; - *(start+3) = val; - *(start+4) = val; - *(start+5) = val; - *(start+6) = val; - *(start+7) = val; - } - - switch (nrem) { - case 7: - *start++ = val; - case 6: - *start++ = val; - case 5: - *start++ = val; - case 4: - *start++ = val; - case 3: - *start++ = val; - case 2: - *start++ = val; - case 1: - *start = val; - } -} +/* Mousehack stuff */ -#undef pfield_linetoscr_full8 -/* The types are lies, of course. */ -extern void pfield_linetoscr_normal_asm8(void) __asm__("pfield_linetoscr_normal_asm8"); -extern void pfield_linetoscr_ehb_asm8(void) __asm__("pfield_linetoscr_ehb_asm8"); -extern void pfield_linetoscr_ham6_asm8(void) __asm__("pfield_linetoscr_ham6_asm8"); -extern void pfield_linetoscr_dualpf_asm8(void) __asm__("pfield_linetoscr_dualpf_asm8"); -extern void pfield_linetoscr_hdouble_asm8(void) __asm__("pfield_linetoscr_hdouble_asm8"); -extern void pfield_linetoscr_hdouble_dpf_asm8(void) __asm__("pfield_linetoscr_hdouble_dpf_asm8"); -extern void pfield_linetoscr_hdouble_ehb_asm8(void) __asm__("pfield_linetoscr_hdouble_ehb_asm8"); -extern void pfield_linetoscr_asm8(void (*)(void), int, int, int, int, ...) __asm__("pfield_linetoscr_asm8"); - -static void pfield_linetoscr_full8(int pix, int lframe_end, int diw_end, int stoppos) -{ - int lframe_end_1, diw_end_1; - - lframe_end_1 = pix + ((lframe_end - pix) & ~3); - diw_end_1 = stoppos - ((stoppos - diw_end) & ~3); - - if (bplham && bplplanecnt == 6) { - pfield_linetoscr_asm8(pfield_linetoscr_ham6_asm8, pix, lframe_end_1, diw_end_1, stoppos); - } else if (bpldualpf) { -#ifdef LORES_HACK - if (currprefs.gfx_lores == 2) - pfield_linetoscr_asm8(pfield_linetoscr_hdouble_dpf_asm8, pix, lframe_end_1, diw_end_1, stoppos, - bpldualpfpri ? dblpf_ind2 : dblpf_ind1); - else -#endif - pfield_linetoscr_asm8(pfield_linetoscr_dualpf_asm8, pix, lframe_end_1, diw_end_1, stoppos, - bpldualpfpri ? dblpf_ind2 : dblpf_ind1); - } else if (bplehb) { -#ifdef LORES_HACK - if (currprefs.gfx_lores == 2) - pfield_linetoscr_asm8(pfield_linetoscr_hdouble_ehb_asm8, pix, lframe_end_1, diw_end_1, stoppos); - else -#endif - pfield_linetoscr_asm8(pfield_linetoscr_ehb_asm8, pix, lframe_end_1, diw_end_1, stoppos); - } else { -#ifdef LORES_HACK - if (currprefs.gfx_lores == 2) - pfield_linetoscr_asm8(pfield_linetoscr_hdouble_asm8, pix, lframe_end_1, diw_end_1, stoppos); - else -#endif - pfield_linetoscr_asm8(pfield_linetoscr_normal_asm8, pix, lframe_end_1, diw_end_1, stoppos); - } - - /* The assembly functions work on aligned data, so we may have to do some - * additional work at the edges. */ - if (lframe_end != lframe_end_1) { - int i, c = colors_for_drawing.acolors[0]; - for (i = lframe_end_1; i < lframe_end; i++) - xlinebuffer[i] = c; - } - if (diw_end != diw_end_1) { - int i, c = colors_for_drawing.acolors[0]; - for (i = diw_end; i < diw_end_1; i++) - xlinebuffer[i] = c; - } -} - -#undef pfield_linetoscr_full16 -extern void pfield_linetoscr_normal_asm16(void) __asm__("pfield_linetoscr_normal_asm16"); -extern void pfield_linetoscr_ehb_asm16(void) __asm__("pfield_linetoscr_ehb_asm16"); -extern void pfield_linetoscr_ham6_asm16(void) __asm__("pfield_linetoscr_ham6_asm16"); -extern void pfield_linetoscr_dualpf_asm16(void) __asm__("pfield_linetoscr_dualpf_asm16"); -extern void pfield_linetoscr_hdouble_asm16(void) __asm__("pfield_linetoscr_hdouble_asm16"); -extern void pfield_linetoscr_hdouble_dpf_asm16(void) __asm__("pfield_linetoscr_hdouble_dpf_asm16"); -extern void pfield_linetoscr_hdouble_ehb_asm16(void) __asm__("pfield_linetoscr_hdouble_ehb_asm16"); -extern void pfield_linetoscr_asm16(void (*)(void), int, int, int, int, ...) __asm__("pfield_linetoscr_asm16"); - -static void pfield_linetoscr_full16(int pix, int lframe_end, int diw_end, int stoppos) -{ - int lframe_end_1, diw_end_1; - - lframe_end_1 = pix + ((lframe_end - pix) & ~3); - diw_end_1 = stoppos - ((stoppos - diw_end) & ~3); - - if (bplham && bplplanecnt == 6) { - pfield_linetoscr_asm16(pfield_linetoscr_ham6_asm16, pix, lframe_end_1, diw_end_1, stoppos); - } else if (bpldualpf) { -#ifdef LORES_HACK - if (currprefs.gfx_lores == 2) - pfield_linetoscr_asm16(pfield_linetoscr_hdouble_dpf_asm16, pix, lframe_end_1, diw_end_1, stoppos, - bpldualpfpri ? dblpf_ind2 : dblpf_ind1); - else -#endif - pfield_linetoscr_asm16(pfield_linetoscr_dualpf_asm16, pix, lframe_end_1, diw_end_1, stoppos, - bpldualpfpri ? dblpf_ind2 : dblpf_ind1); - } else if (bplehb) { -#ifdef LORES_HACK - if (currprefs.gfx_lores == 2) - pfield_linetoscr_asm16(pfield_linetoscr_hdouble_ehb_asm16, pix, lframe_end_1, diw_end_1, stoppos); - else -#endif - pfield_linetoscr_asm16(pfield_linetoscr_ehb_asm16, pix, lframe_end_1, diw_end_1, stoppos); - } else { -#ifdef LORES_HACK - if (currprefs.gfx_lores == 2) - pfield_linetoscr_asm16(pfield_linetoscr_hdouble_asm16, pix, lframe_end_1, diw_end_1, stoppos); - else -#endif - pfield_linetoscr_asm16(pfield_linetoscr_normal_asm16, pix, lframe_end_1, diw_end_1, stoppos); - } - - /* The assembly functions work on aligned data, so we may have to do some - * additional work at the edges. */ - if (lframe_end != lframe_end_1) { - int i, c = colors_for_drawing.acolors[0]; - for (i = lframe_end_1; i < lframe_end; i++) - ((uae_u16 *)xlinebuffer)[i] = c; - } - if (diw_end != diw_end_1) { - int i, c = colors_for_drawing.acolors[0]; - for (i = diw_end; i < diw_end_1; i++) - ((uae_u16 *)xlinebuffer)[i] = c; - } -} - -#ifndef NO_DOUBLING_LINETOSCR -#define NO_DOUBLING_LINETOSCR -#endif - -#endif - -#ifdef NO_DOUBLING_LINETOSCR -#undef pfield_linetoscr_full8_double -#undef pfield_linetoscr_full16_double -static void pfield_linetoscr_full8_double(int start, int lframe_end, int diw_end, int stop) -{ - char *oldxlb = (char *)xlinebuffer; - pfield_linetoscr_full8(start, lframe_end, diw_end, stop); - xlinebuffer = oldxlb + linetoscr_double_offset; - pfield_linetoscr_full8(start, lframe_end, diw_end, stop); -} -static void pfield_linetoscr_full16_double(int start, int lframe_end, int diw_end, int stop) -{ - char *oldxlb = (char *)xlinebuffer; - pfield_linetoscr_full16(start, lframe_end, diw_end, stop); - xlinebuffer = oldxlb + linetoscr_double_offset; - pfield_linetoscr_full16(start, lframe_end, diw_end, stop); -} -#endif - -static int linetoscr_diw_end, linetoscr_diw_start; - -/* Initialize the variables necessary for drawing a line. - * This involves setting up start/stop positions and display window - * borders. Also, since the drawing code may not fully overwrite all - * releveant areas in the pixdata.apixels array for speed reasons, parts of - * it must possibly be cleared here. */ -static void pfield_init_linetoscr (void) -{ - int ddf_left, ddf_right; - int mindelay = bpldelay1, maxdelay = bpldelay2; - if (bpldelay1 > bpldelay2) - maxdelay = bpldelay1, mindelay = bpldelay2; - - linetoscr_diw_start = dp_for_drawing->diwfirstword; - linetoscr_diw_end = dp_for_drawing->diwlastword; - - /* We should really look at DDF also when calculating max_diwstop/min_diwstrt, - * so that centering works better, but I'm afraid that might cost too many - * cycles. Plus it's dangerous, see the code below that handles the case - * with sprites. */ - if (dip_for_drawing->nr_sprites == 0) { - int hiresadjust = bplhires ? 4 : 8; - ddf_left = ((dp_for_drawing->plfstrt + hiresadjust)*2 + mindelay - DISPLAY_LEFT_SHIFT) << lores_shift; - ddf_right = ((dp_for_drawing->plfstrt + dp_for_drawing->plflinelen + hiresadjust)*2 + maxdelay - DISPLAY_LEFT_SHIFT) << lores_shift; - - if (linetoscr_diw_start < ddf_left) - linetoscr_diw_start = ddf_left; - if (linetoscr_diw_end > ddf_right) - linetoscr_diw_end = ddf_right; - - if (mindelay != maxdelay) { - /* Raahh... - * We just clear the maximum amount of space that may need to be - * cleared. We could do this exactly, but it would come out slower - * because of the overhead. */ - int strt = ddf_left; - if (currprefs.gfx_lores == 2) { - fuzzy_memset_le32 (pixdata.apixels, 0, (ddf_left>>1), 15); - fuzzy_memset_le32 (pixdata.apixels, 0, (ddf_right>>1) - 15, 15); - } else if (currprefs.gfx_lores) { - fuzzy_memset_le32 (pixdata.apixels, 0, ddf_left, 15); - fuzzy_memset_le32 (pixdata.apixels, 0, ddf_right - 15, 15); - } else { - fuzzy_memset_le32 (pixdata.apixels, 0, ddf_left, 30); - fuzzy_memset_le32 (pixdata.apixels, 0, ddf_right - 30, 30); - } - } - } else { - int hiresadjust = bplhires ? 4 : 8; - /* We swap mindelay and maxdelay here to get rid of the mindelay != maxdelay check. - * Since we have to do a memset anyway (because there may be sprites), - * we might as well clear all at once. */ - ddf_left = ((dp_for_drawing->plfstrt + hiresadjust)*2 + maxdelay - DISPLAY_LEFT_SHIFT) << lores_shift; - ddf_right = ((dp_for_drawing->plfstrt + dp_for_drawing->plflinelen + hiresadjust)*2 + mindelay - DISPLAY_LEFT_SHIFT) << lores_shift; - if (linetoscr_diw_start < ddf_left) { - int strt = linetoscr_diw_start; - int stop = ddf_left; -#ifdef LORES_HACK - if (currprefs.gfx_lores == 2) - strt >>= 1, stop >>= 1; -#endif - if (strt < stop) - fuzzy_memset (pixdata.apixels, 0, strt, stop - strt); - } - - if (linetoscr_diw_end > ddf_right) { - int strt = ddf_right; - int stop = linetoscr_diw_end; -#ifdef LORES_HACK - if (currprefs.gfx_lores == 2) - strt >>= 1, stop >>= 1; -#endif - if (strt < stop) - fuzzy_memset (pixdata.apixels, 0, strt, stop - strt); - } - } - /* Perverse cases happen. */ - if (linetoscr_diw_end < linetoscr_diw_start) - linetoscr_diw_end = linetoscr_diw_start; -} - -static void pfield_do_linetoscr(int start, int stop) -{ - int lframe_end = linetoscr_diw_start, diw_end = linetoscr_diw_end; - - if (stop > linetoscr_right_x) - stop = linetoscr_right_x; - if (start < linetoscr_x_adjust) - start = linetoscr_x_adjust; +#define defstepx (1<<16) +#define defstepy (1<<16) +#define defxoffs 0 +#define defyoffs 0 - if (lframe_end < start) - lframe_end = start; - if (diw_end > stop) - diw_end = stop; +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; - if (start >= stop) - return; +int lastmx, lastmy; +int newmousecounters; +int ievent_alive = 0; -#if AGA_CHIPSET == 0 - if (start == linetoscr_x_adjust && stop == linetoscr_right_x) { - switch (gfxvidinfo.pixbytes) { - case 1: pfield_linetoscr_full8 (start, lframe_end, diw_end, stop); break; - case 2: pfield_linetoscr_full16 (start, lframe_end, diw_end, stop); break; - case 3: pfield_linetoscr_full24 (start, lframe_end, diw_end, stop); break; - case 4: pfield_linetoscr_full32 (start, lframe_end, diw_end, stop); break; - } - } else { - switch (gfxvidinfo.pixbytes) { - case 1: pfield_linetoscr_8 (start, lframe_end, diw_end, stop); break; - case 2: pfield_linetoscr_16 (start, lframe_end, diw_end, stop); break; - case 3: pfield_linetoscr_24 (start, lframe_end, diw_end, stop); break; - case 4: pfield_linetoscr_32 (start, lframe_end, diw_end, stop); break; - } - } -#else - pfield_linetoscr_aga(start, lframe_end, diw_end, stop); -#endif -} +static enum { unknown_mouse, normal_mouse, dont_care_mouse, follow_mouse } mousestate; -static void pfield_do_fill_line(int start, int stop) +static void mousehack_setdontcare (void) { - if (stop > linetoscr_right_x) - stop = linetoscr_right_x; - if (start < linetoscr_x_adjust) - start = linetoscr_x_adjust; - - if (start >= stop) + if (mousestate == dont_care_mouse) return; - switch (gfxvidinfo.pixbytes) { - case 1: fill_line_8 (xlinebuffer, start, stop); break; - case 2: fill_line_16 (xlinebuffer, start, stop); break; - case 3: fill_line_24 (xlinebuffer, start, stop); break; - case 4: fill_line_32 (xlinebuffer, start, stop); break; - } -} - -static void pfield_do_linetoscr_full(int double_line) -{ - int start = linetoscr_x_adjust, stop = start + gfxvidinfo.width; - int lframe_end = linetoscr_diw_start, diw_end = linetoscr_diw_end; - if (lframe_end < start) - lframe_end = start; - if (diw_end > stop) - diw_end = stop; - -#if AGA_CHIPSET == 0 - if (double_line) { - switch (gfxvidinfo.pixbytes) { - case 1: pfield_linetoscr_full8_double (start, lframe_end, diw_end, stop); break; - case 2: pfield_linetoscr_full16_double (start, lframe_end, diw_end, stop); break; - case 3: pfield_linetoscr_full24_double (start, lframe_end, diw_end, stop); break; - case 4: pfield_linetoscr_full32_double (start, lframe_end, diw_end, stop); break; - } - } else - switch (gfxvidinfo.pixbytes) { - case 1: pfield_linetoscr_full8 (start, lframe_end, diw_end, stop); break; - case 2: pfield_linetoscr_full16 (start, lframe_end, diw_end, stop); break; - case 3: pfield_linetoscr_full24 (start, lframe_end, diw_end, stop); break; - case 4: pfield_linetoscr_full32 (start, lframe_end, diw_end, stop); break; - } -#else - pfield_linetoscr_aga(start, lframe_end, diw_end, stop); -#endif -} - -/* Mouse stuff */ -static void setdontcare(void) -{ write_log ("Don't care mouse mode set\n"); mousestate = dont_care_mouse; lastspr0x = lastmx; lastspr0y = lastmy; mstepx = defstepx; mstepy = defstepy; } -static void setfollow(void) +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; + spr0ctl = spr0pos = 0; mstepx = defstepx; mstepy = defstepy; } -uae_u32 mousehack_helper (void) +static uae_u32 mousehack_helper (void) { int mousexpos, mouseypos; #ifdef PICASSO96 if (picasso_on) { - mousexpos = lastmx + picasso96_state.XOffset; - mouseypos = lastmy + picasso96_state.YOffset; + mousexpos = lastmx - picasso96_state.XOffset; + mouseypos = lastmy - picasso96_state.YOffset; } else #endif { - mousexpos = lastmx + linetoscr_x_adjust; if (lastmy >= gfxvidinfo.height) - lastmy = gfxvidinfo.height-1; - mouseypos = native2amiga_line_map[lastmy] + thisframe_y_adjust - minfirstline; - mouseypos <<= 1; - mousexpos <<= (1-lores_shift); - mousexpos += 2*DISPLAY_LEFT_SHIFT; + lastmy = gfxvidinfo.height - 1; + mouseypos = coord_native_to_amiga_y (lastmy) << 1; + mousexpos = coord_native_to_amiga_x (lastmx); } switch (m68k_dreg (regs, 0)) { @@ -2001,25 +1270,25 @@ uae_u32 mousehack_helper (void) return 0; } -void togglemouse(void) +void togglemouse (void) { - switch(mousestate) { - case dont_care_mouse: setfollow(); break; - case follow_mouse: setdontcare(); break; + switch (mousestate) { + case dont_care_mouse: mousehack_setfollow (); break; + case follow_mouse: mousehack_setdontcare (); break; default: break; /* Nnnnnghh! */ } } -static __inline__ int adjust(int val) +STATIC_INLINE int adjust (int val) { - if (val>127) + if (val > 127) return 127; - else if (val<-127) + else if (val < -127) return -127; return val; } -static void do_mouse_hack(void) +static void do_mouse_hack (void) { int spr0x = ((spr0pos & 0xff) << 2) | ((spr0ctl & 1) << 1); int spr0y = ((spr0pos >> 8) | ((spr0ctl & 4) << 6)) << 1; @@ -2030,7 +1299,7 @@ static void do_mouse_hack(void) return; } switch (mousestate) { - case normal_mouse: + case normal_mouse: diffx = lastmx - lastsampledmx; diffy = lastmy - lastsampledmy; if (!newmousecounters) { @@ -2044,72 +1313,108 @@ static void do_mouse_hack(void) 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; + 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) { + 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) + 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 (val >= 0x8000) + mstepx = (mstepx * (calweight - 1) + val) / calweight; } - if ((lastdiffy > docal || lastdiffy < -docal) && lastspr0y != spr0y - && spr0y>plffirstline+ycaloff && spr0y 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; + int val = (lastdiffy << 16) / (spr0y - lastspr0y); + if (val >= 0x8000) + mstepy = (mstepy * (calweight - 1) + val) / calweight; } - mousexpos = lastmx + linetoscr_x_adjust; if (lastmy >= gfxvidinfo.height) lastmy = gfxvidinfo.height-1; - mouseypos = native2amiga_line_map[lastmy] + thisframe_y_adjust - minfirstline; - mouseypos <<= 1; - mousexpos <<= (1-lores_shift); - mousexpos += 2*DISPLAY_LEFT_SHIFT; + 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; + 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 */ - -__inline__ uae_u16 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 __inline__ uae_u16 INTENAR(void) { return intena; } -uae_u16 INTREQR(void) +STATIC_INLINE uae_u16 INTENAR (void) { - return intreq | (currprefs.use_serial ? 0x0001 : 0); + return intena; } -static __inline__ uae_u16 ADKCONR(void) { return adkcon; } -static __inline__ uae_u16 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 void VPOSW(uae_u16 v) +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; @@ -2119,45 +1424,84 @@ static void VPOSW(uae_u16 v) * refresh rates with it ;) But I won't emulate this... */ } -static __inline__ uae_u16 VHPOSR(void) { return (vpos << 8) | current_hpos(); } -static __inline__ void COP1LCH(uae_u16 v) { cop1lc = (cop1lc & 0xffff) | ((uae_u32)v << 16); } -static __inline__ void COP1LCL(uae_u16 v) { cop1lc = (cop1lc & ~0xffff) | (v & 0xfffe); } -static __inline__ void COP2LCH(uae_u16 v) { cop2lc = (cop2lc & 0xffff) | ((uae_u32)v << 16); } -static __inline__ void COP2LCL(uae_u16 v) { cop2lc = (cop2lc & ~0xffff) | (v & 0xfffe); } - -static void COPJMP1(uae_u16 a) -{ - 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; - copper_waiting_for_blitter = 0; -} -static void COPJMP2(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; - copper_waiting_for_blitter = 0; +STATIC_INLINE uae_u16 VHPOSR (void) +{ + return (vpos << 8) | current_hpos(); +} + +STATIC_INLINE void COP1LCH (uae_u16 v) { cop1lc = (cop1lc & 0xffff) | ((uae_u32)v << 16); } +STATIC_INLINE void COP1LCL (uae_u16 v) { cop1lc = (cop1lc & ~0xffff) | (v & 0xfffe); } +STATIC_INLINE void COP2LCH (uae_u16 v) { cop2lc = (cop2lc & 0xffff) | ((uae_u32)v << 16); } +STATIC_INLINE void COP2LCL (uae_u16 v) { cop2lc = (cop2lc & ~0xffff) | (v & 0xfffe); } + +static void start_copper (void) +{ + 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 COPJMP1 (uae_u16 a) +{ + cop_state.ip = cop1lc; + start_copper (); +} + +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) + +STATIC_INLINE void COPCON (uae_u16 a) +{ + copcon = a; +} + +static void DMACON (uae_u16 v) { int i, need_resched = 0; uae_u16 oldcon = dmacon; - decide_line(); + decide_line (current_hpos ()); setclr(&dmacon,v); dmacon &= 0x1FFF; /* ??? 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)) { + if (eventtab[ev_copper].active) + need_resched = 1; + eventtab[ev_copper].active = 0; + } if ((dmacon & DMA_COPPER) > (oldcon & DMA_COPPER)) { - COPJMP1(0); + 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) { @@ -2166,7 +1510,11 @@ static void DMACON(uae_u16 v) } 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; @@ -2178,50 +1526,43 @@ static void DMACON(uae_u16 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 - calculate_copper_cycle_time (); - 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 int trace_intena = 0;*/ -static __inline__ void INTENA (uae_u16 v) +STATIC_INLINE void INTENA (uae_u16 v) { /* if (trace_intena) - fprintf(stderr, "INTENA: %04x\n", v);*/ + 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; + if (( v & 0x8800) == 0x0800) + serdat &= 0xbfff; } static void ADKCON (uae_u16 v) { unsigned long t; + + update_audio (); + setclr (&adkcon,v); t = adkcon | (adkcon >> 4); audio_channel[0].adk_mask = (((t >> 0) & 1) - 1); @@ -2230,133 +1571,181 @@ static void ADKCON (uae_u16 v) audio_channel[3].adk_mask = (((t >> 3) & 1) - 1); } -static void BPLPTH (uae_u16 v, int num) +static void BEAMCON0 (uae_u16 v) { - decide_line (); - decide_plane(); - do_modulos(); - bplpt[num] = (bplpt[num] & 0xffff) | ((uae_u32)v << 16); -} -static void BPLPTL (uae_u16 v, int num) -{ - decide_line (); - decide_plane(); - do_modulos(); - bplpt[num] = (bplpt[num] & ~0xffff) | (v & 0xfffe); -} - -static void BPLCON0 (uae_u16 v) -{ -#if AGA_CHIPSET == 0 - 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; -#endif + 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; - decide_line (); + decide_line (hpos); + /* if ((bplcon0 ^ v) & 0x8000)*/ + calcdiw (); bplcon0 = v; - nr_planes_from_bplcon0 = (bplcon0 >> 12) & 7; - corrected_nr_planes_from_bplcon0 = ((bplcon0 >> 12) & 7) << (bplcon0 & 0x8000 ? 1 : 0); - post_decide_line (); - calculate_copper_cycle_time (); -#if 0 - calcdiw(); /* This should go away. */ -#endif + 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 __inline__ void BPLCON1 (uae_u16 v) + +STATIC_INLINE void BPLCON1 (int hpos, uae_u16 v) { if (bplcon1 == v) return; - decide_diw (); + decide_diw (hpos); bplcon1 = v; - decide_delay (); + decide_delay (hpos); } -static __inline__ void BPLCON2 (uae_u16 v) +STATIC_INLINE void BPLCON2 (int hpos, uae_u16 v) { - if (bplcon2 != v) - decide_line (); + if (bplcon2 == v) + return; + decide_line (hpos); bplcon2 = v; } -static __inline__ void BPLCON3 (uae_u16 v) +STATIC_INLINE void BPLCON3 (int hpos, uae_u16 v) { - if (bplcon3 != v) - decide_line (); + if (bplcon3 == v) + return; + decide_line (hpos); bplcon3 = v; } -static __inline__ void BPLCON4 (uae_u16 v) +STATIC_INLINE void BPLCON4 (int hpos, uae_u16 v) { - if (bplcon4 != v) - decide_line (); + if (! (currprefs.chipset_mask & CSMASK_AGA)) + return; + if (bplcon4 == v) + return; + decide_line (hpos); bplcon4 = v; } -static void BPL1MOD (uae_u16 v) +static void BPL1MOD (int hpos, uae_u16 v) { v &= ~1; if ((uae_s16)bpl1mod == (uae_s16)v) return; bpl1mod = v; - decide_modulos (); + decide_modulos (hpos); } -static void BPL2MOD (uae_u16 v) +static void BPL2MOD (int hpos, uae_u16 v) { v &= ~1; if ((uae_s16)bpl2mod == (uae_s16)v) return; bpl2mod = v; - decide_modulos(); + decide_modulos (hpos); } +STATIC_INLINE void BPL1DAT (uae_u16 v) +{ + bpl1dat = v; + if (thisline_decision.plfleft == -1) + thisline_decision.plfleft = current_hpos (); +} /* We could do as well without those... */ -static __inline__ void BPL1DAT (uae_u16 v) { bpl1dat = v; } -static __inline__ void BPL2DAT (uae_u16 v) { bpl2dat = v; } -static __inline__ void BPL3DAT (uae_u16 v) { bpl3dat = v; } -static __inline__ void BPL4DAT (uae_u16 v) { bpl4dat = v; } -static __inline__ void BPL5DAT (uae_u16 v) { bpl5dat = v; } -static __inline__ void BPL6DAT (uae_u16 v) { bpl6dat = v; } +STATIC_INLINE void 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 (uae_u16 v) +static void DIWSTRT (int hpos, uae_u16 v) { - if (diwstrt == v) + if (diwstrt == v && ! diwhigh_written) return; - decide_line (); + decide_line (hpos); + diwhigh_written = 0; diwstrt = v; - calcdiw(); + calcdiw (); } -static void DIWSTOP (uae_u16 v) + +static void DIWSTOP (int hpos, uae_u16 v) { - if (diwstop == v) + if (diwstop == v && ! diwhigh_written) return; + decide_line (hpos); + diwhigh_written = 0; diwstop = v; - calcdiw(); + calcdiw (); +} + +static void DIWHIGH (int hpos, uae_u16 v) +{ + if (! (currprefs.chipset_mask & CSMASK_ECS_DENISE)) + return; + if (diwhigh_written && diwhigh == v) + return; + decide_line (hpos); + diwhigh_written = 1; + diwhigh = v; + calcdiw (); } -static void DDFSTRT (uae_u16 v) + +static void DDFSTRT (int hpos, uae_u16 v) { - v &= 0xFF; + v &= 0xFC; if (ddfstrt == v) return; - decide_line (); + decide_line (hpos); ddfstrt = v; - calcdiw(); + calcdiw (); } -static void DDFSTOP (uae_u16 v) +static void DDFSTOP (int hpos, uae_u16 v) { - v &= 0xFF; + v &= 0xFC; if (ddfstop == v) return; - decide_line (); + decide_line (hpos); ddfstop = v; - calcdiw(); + calcdiw (); } -static void BLTADAT(uae_u16 v) +static void FMODE (uae_u16 v) +{ + if (! (currprefs.chipset_mask & CSMASK_AGA)) + return; + fmode = v; + calcdiw (); +} + +static void BLTADAT (uae_u16 v) { maybe_blit(); @@ -2367,7 +1756,7 @@ static void BLTADAT(uae_u16 v) * 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) +static void BLTBDAT (uae_u16 v) { maybe_blit(); @@ -2377,35 +1766,41 @@ static void BLTBDAT(uae_u16 v) blt_info.bltbhold = v >> (bltcon1 >> 12); blt_info.bltbdat = v; } -static void BLTCDAT(uae_u16 v) { maybe_blit(); blt_info.bltcdat = v; } +static void BLTCDAT (uae_u16 v) { maybe_blit (); blt_info.bltcdat = v; } -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 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(uae_u16 v) { maybe_blit(); bltcon0 = v; blinea_shift = v >> 12; } +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(uae_u16 v) { maybe_blit(); bltcon0 = (bltcon0 & 0xFF00) | (v & 0xFF); } -static void BLTCON1(uae_u16 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 (uae_u16 v) { maybe_blit (); blt_info.bltafwm = v; } +static void BLTALWM (uae_u16 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 (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 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) +static void BLTSIZE (uae_u16 v) { bltsize = v; - maybe_blit(); + maybe_blit (); blt_info.vblitsize = bltsize >> 6; blt_info.hblitsize = bltsize & 0x3F; @@ -2413,115 +1808,122 @@ static void BLTSIZE(uae_u16 v) if (!blt_info.hblitsize) blt_info.hblitsize = 64; bltstate = BLT_init; - do_blitter(); + do_blitter (); } -static void BLTSIZV(uae_u16 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(uae_u16 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; - do_blitter(); + do_blitter (); } -static __inline__ void SPRxCTL_1(uae_u16 v, int num) + +STATIC_INLINE void SPRxCTL_1 (uae_u16 v, int num) { int sprxp; sprctl[num] = v; - nr_armed -= sprarmed[num]; - sprarmed[num] = 0; + nr_armed -= spr[num].armed; + spr[num].armed = 0; if (sprpos[num] == 0 && v == 0) { - sprst[num] = SPR_stop; - spron[num] = 0; + spr[num].state = SPR_stop; + spr[num].on = 0; } else - sprst[num] = SPR_waiting_start; + spr[num].state = SPR_waiting_start; - sprxp = ((sprpos[num] & 0xFF) * 2) + (v & 1) - DISPLAY_LEFT_SHIFT; - if (!currprefs.gfx_lores) - sprxp *= 2; - sprxpos[num] = sprxp; - sprvstart[num] = (sprpos[num] >> 8) | ((sprctl[num] << 6) & 0x100); - sprvstop[num] = (sprctl[num] >> 8) | ((sprctl[num] << 7) & 0x100); + sprxp = coord_hw_to_window_x ((sprpos[num] & 0xFF) * 2 + (v & 1)); + spr[num].xpos = sprxp; + spr[num].vstart = (sprpos[num] >> 8) | ((sprctl[num] << 6) & 0x100); + spr[num].vstop = (sprctl[num] >> 8) | ((sprctl[num] << 7) & 0x100); } -static __inline__ void SPRxPOS_1(uae_u16 v, int num) +STATIC_INLINE void SPRxPOS_1 (uae_u16 v, int num) { int sprxp; sprpos[num] = v; - sprxp = ((v & 0xFF) * 2) + (sprctl[num] & 1) - DISPLAY_LEFT_SHIFT; - if (!currprefs.gfx_lores) - sprxp *= 2; - sprxpos[num] = sprxp; - sprvstart[num] = (sprpos[num] >> 8) | ((sprctl[num] << 6) & 0x100); + sprxp = coord_hw_to_window_x ((v & 0xFF) * 2 + (sprctl[num] & 1)); + spr[num].xpos = sprxp; + spr[num].vstart = (sprpos[num] >> 8) | ((sprctl[num] << 6) & 0x100); } -static __inline__ void SPRxDATA_1(uae_u16 v, int num) +STATIC_INLINE void SPRxDATA_1 (uae_u16 v, int num) { sprdata[num] = v; - nr_armed += 1 - sprarmed[num]; - sprarmed[num] = 1; + nr_armed += 1 - spr[num].armed; + spr[num].armed = 1; } -static __inline__ void SPRxDATB_1(uae_u16 v, int num) +STATIC_INLINE void SPRxDATB_1 (uae_u16 v, int num) { sprdatb[num] = v; } -static void SPRxDATA(uae_u16 v, int num) { decide_sprites (); SPRxDATA_1 (v, num); } -static void SPRxDATB(uae_u16 v, int num) { decide_sprites (); SPRxDATB_1 (v, num); } -static void SPRxCTL(uae_u16 v, int num) { decide_sprites (); SPRxCTL_1 (v, num); } -static void SPRxPOS(uae_u16 v, int num) { decide_sprites (); SPRxPOS_1 (v, num); } -static void SPRxPTH(uae_u16 v, int num) -{ - decide_line (); - sprpt[num] &= 0xffff; - sprpt[num] |= (uae_u32)v << 16; - - if (sprst[num] == SPR_stop || vpos < vblank_endline) - sprst[num] = SPR_restart; - spron[num] = 1; -} -static void SPRxPTL(uae_u16 v, int num) -{ - decide_line (); - sprpt[num] &= ~0xffff; - sprpt[num] |= v; - - if (sprst[num] == SPR_stop || vpos < vblank_endline) - sprst[num] = SPR_restart; - spron[num] = 1; +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) +{ + 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 (int hpos, uae_u16 v, int num) +{ + 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) +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) +static uae_u16 CLXDAT (void) { uae_u16 v = clxdat; clxdat = 0; return v; } -static void COLOR(uae_u16 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 - { - /* XXX Broken */ + if (currprefs.chipset_mask & CSMASK_AGA) { + + int r,g,b; + int cr,cg,cb; + int colreg; uae_u32 cval; + + /* writing is disabled when RDRAM=1 */ + if (bplcon2 & 0x0100) return; + colreg = ((bplcon3 >> 13) & 7) * 32 + num; r = (v & 0xF00) >> 8; g = (v & 0xF0) >> 4; b = (v & 0xF) >> 0; - cr = color_regs[colreg] >> 16; - cg = (color_regs[colreg] >> 8) & 0xFF; - cb = color_regs[colreg] & 0xFF; + cr = current_colors.color_regs_aga[colreg] >> 16; + cg = (current_colors.color_regs_aga[colreg] >> 8) & 0xFF; + cb = current_colors.color_regs_aga[colreg] & 0xFF; if (bplcon3 & 0x200) { cr &= 0xF0; cr |= r; @@ -2533,117 +1935,61 @@ static void COLOR(uae_u16 v, int num) cb = b + (b << 4); } cval = (cr << 16) | (cg << 8) | cb; - if (cval == color_regs[colreg]) + if (cval == current_colors.color_regs_aga[colreg]) return; - color_regs[colreg] = cval; - pfield_may_need_update(1); - } -#else - { - if (current_colors.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; /* Call this with the old table still intact. */ - record_color_change (num, v); + record_color_change (hpos, num, v); remembered_color_entry = -1; - current_colors.color_regs[num] = v; + current_colors.color_regs_ecs[num] = v; current_colors.acolors[num] = xcolors[v]; } -#endif -} - -static void DSKSYNC(uae_u16 v) { dsksync = v; } -static void DSKDAT(uae_u16 v) { write_log ("DSKDAT written. Not good.\n"); } -static void DSKPTH(uae_u16 v) { dskpt = (dskpt & 0xffff) | ((uae_u32)v << 16); } -static void DSKPTL(uae_u16 v) { dskpt = (dskpt & ~0xffff) | (v); } - -static void DSKLEN(uae_u16 v) -{ - if (v & 0x8000) { - dskdmaen = dskdmaen == 1 ? 2 : 1; - } else { - dskdmaen = 0; - if (eventtab[ev_diskblk].active) - write_log ("warning: Disk DMA aborted!\n"); - eventtab[ev_diskblk].active = 0; - events_schedule(); - - } - dsklen = dsklength = v; dsklength &= 0x3fff; - if (dskdmaen == 2 && dsksync != 0x4489 && (adkcon & 0x400)) { - sprintf (warning_buffer, "Non-standard sync: %04x len: %x\n", dsksync, dsklength); - write_log (warning_buffer); - } - if (dskdmaen > 1) { - if (dsklen & 0x4000) { - eventtab[ev_diskblk].active = 1; - eventtab[ev_diskblk].oldcycles = cycles; - eventtab[ev_diskblk].evtime = 40 + cycles; /* ??? */ - events_schedule(); - } else { - int result = DISK_PrepareReadMFM(dsklength, dsksync, adkcon & 0x400); - if (result) { - eventtab[ev_diskblk].active = 1; - eventtab[ev_diskblk].oldcycles = cycles; - eventtab[ev_diskblk].evtime = result + cycles; - events_schedule(); - } - } - } -} - -static uae_u16 DSKBYTR(void) -{ - uae_u16 v = (dsklen >> 1) & 0x6000; - uae_u16 mfm, byte; - if (DISK_GetData(&mfm, &byte)) - v |= 0x8000; - v |= byte; - if (dsksync == mfm) v |= 0x1000; - return v; -} - -static uae_u16 DSKDATR(void) -{ - uae_u16 mfm, byte; - DISK_GetData(&mfm, &byte); - return mfm; } static uae_u16 potgo_value; -static void POTGO(uae_u16 v) +static void POTGO (uae_u16 v) { potgo_value = v; } -static uae_u16 POTGOR(void) +static uae_u16 POTGOR (void) { - uae_u16 v = (potgo_value | (potgo_value << 1)) & 0xAA00; - v |= v >> 1; + uae_u16 v = (potgo_value | (potgo_value >> 1)) & 0x5500; + + v |= (~potgo_value & 0xAA00) >> 1; - if (JSEM_ISMOUSE (0, currprefs.fake_joystick)) { + if (JSEM_ISMOUSE (0, &currprefs)) { if (buttonstate[2]) v &= 0xFBFF; if (buttonstate[1]) v &= 0xFEFF; - } - else if (JSEM_ISJOY0(0, currprefs.fake_joystick) || JSEM_ISJOY1(0, currprefs.fake_joystick)) { + } 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.fake_joystick) || JSEM_ISJOY1(1, currprefs.fake_joystick)) { + if (JSEM_ISJOY0 (1, &currprefs) || JSEM_ISJOY1 (1, &currprefs)) { if (joy1button & 2) v &= 0xbfff; if (joy1button & 4) v &= 0xefff; } return v; } -static uae_u16 POT0DAT(void) + +static uae_u16 POT0DAT (void) { static uae_u16 cnt = 0; - if (JSEM_ISMOUSE (0, currprefs.fake_joystick)) { + if (JSEM_ISMOUSE (0, &currprefs)) { if (buttonstate[2]) cnt = ((cnt + 1) & 0xFF) | (cnt & 0xFF00); if (buttonstate[1]) @@ -2652,561 +1998,337 @@ static uae_u16 POT0DAT(void) return cnt; } -static uae_u16 JOY0DAT(void) +static uae_u16 JOY0DAT (void) { - if (JSEM_ISMOUSE (0, currprefs.fake_joystick)) { - do_mouse_hack(); + if (JSEM_ISMOUSE (0, &currprefs)) { + do_mouse_hack (); return ((uae_u8)mouse_x) + ((uae_u16)mouse_y << 8); } return joy0dir; } -static uae_u16 JOY1DAT(void) +static uae_u16 JOY1DAT (void) { - if (JSEM_ISMOUSE (1, currprefs.fake_joystick)) { - do_mouse_hack(); + 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) +static void JOYTEST (uae_u16 v) { - if (JSEM_ISMOUSE (0, currprefs.fake_joystick)) { + if (JSEM_ISMOUSE (0, &currprefs)) { mouse_x = v & 0xFC; mouse_y = (v >> 8) & 0xFC; } } -/* - * Here starts the copper code. It should be rewritten. - */ - -#define COPPER_ALTERNATIVE 1 -/* - * 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) -{ - uae_u16 vp = currvpos & (((copi2 >> 8) & 0x7F) | 0x80); - uae_u16 hp = currhpos & (copi2 & 0xFE); - uae_u16 vcmp = ((copi1 & (copi2 | 0x8000)) >> 8); - uae_u16 hcmp = (copi1 & copi2 & 0xFE); - int copper_time_hpos; - int cycleadd = maxhpos - currhpos; - int coptime = 0; - int maxwait = 32767; - -#if COPPER_ALTERNATIVE == 0 - /* This is a kludge... the problem is that there are programs that wait for - * FFDDFFFE and then for a line in the second display half, and this doesn't - * work without this. I _think_ the reason why it works on the Amiga is that - * the last cycle in the line isn't available for the copper, but I'm not sure. - * OTOH, I'm pretty convinced that the copper timings are correct otherwise, so - * I added this rather than changing something else. */ - if (hcmp == 0xDC) - hcmp += 2; -#endif - decide_line(); - /* Copper DMA is turned off in Hires 4 bitplane mode */ - if (vp == vcmp - && decided_nr_planes == 4 /* -1 if before plfstrt */ - && decided_hires - && currhpos >= thisline_decision.plfstrt - && currhpos < thisline_decision.plfstrt + thisline_decision.plflinelen) - coptime += thisline_decision.plfstrt + thisline_decision.plflinelen - currhpos; - - if ((vp > vcmp || (vp == vcmp && hp >= hcmp)) && ((copi2 & 0x8000) || !(DMACONR() & 0x4000))) - return coptime; - - 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 ((bplcon0 & 0xF000) == 0xC000) { - if (coptime > 0) - return coptime; - maxwait = plfstrt - current_hpos(); - if (maxwait < 0) - maxwait = 32767; - } - copper_time_hpos = currhpos; - hp = copper_time_hpos & (copi2 & 0xFE); - if (!(vp > vcmp)) { - while ((int)hp < ((int)hcmp)) { - currhpos++; - /* Copper DMA is turned off in Hires 4 bitplane mode */ - if (decided_nr_planes != 4 /* -1 if before plfstrt */ - || !decided_hires - || current_hpos () >= (thisline_decision.plfstrt + thisline_decision.plflinelen)) - copper_time_hpos++; - - if (currhpos > maxhpos) { - /* 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++; - if (coptime >= maxwait) - return coptime; - hp = copper_time_hpos & (copi2 & 0xFE); - } - } - if (coptime == 0) /* waiting for the blitter */ - return 1; - - return coptime; -} - -/* - * Simple version of the above which only tries to get vpos correct. - */ -static int calc_copcomp_true_vpos(int currvpos, int currhpos) -{ - uae_u16 vp = currvpos & (((copi2 >> 8) & 0x7F) | 0x80); - uae_u16 hp = currhpos & (copi2 & 0xFE); - uae_u16 vcmp = ((copi1 & (copi2 | 0x8000)) >> 8); - uae_u16 hcmp = (copi1 & copi2 & 0xFE); - int copper_time_hpos; - int cycleadd = maxhpos - currhpos; - int coptime = 0; -#if COPPER_ALTERNATIVE == 0 - /* see above */ - if (hcmp == 0xDC) - hcmp += 2; -#endif - if ((vp > vcmp || (vp == vcmp && hp >= hcmp)) && ((copi2 & 0x8000) || !(DMACONR() & 0x4000))) - return 0; +/* 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 } +}; - while (vp < vcmp) { - currvpos++; - if (currvpos > maxvpos + 1) - return -1; - currhpos = 0; - coptime += cycleadd; - cycleadd = maxhpos; - vp = currvpos & (((copi2 >> 8) & 0x7F) | 0x80); - } - return coptime; -} - -static enum copper_states cop_cmds[4] = { COP_move, COP_wait, COP_move, COP_skip }; - -/* This function is not always correct, but it's the best we can do. */ -static int copper_memory_cycles (int n) -{ - int current_cycle = current_hpos (); - int n_needed = 0; - int planes = corrected_nr_planes_from_bplcon0; - - while (n) { - /* This sucks. The DIW may end vertically at exactly this point. Therefore, - * we must call decide_line(). If we're vertically outside the DIW, - * copper_cycle_time will be != -1 after this call [Sanity Interference] */ - decide_line (); -#if COPPER_ALTERNATIVE == 1 - if (current_cycle >= (maxhpos-3)) { - n_needed += maxhpos - current_cycle; - current_cycle = 0; - continue; - } -#endif - if (copper_cycle_time == -1 && current_cycle >= 0x14 - && current_cycle >= plfstrt && current_cycle < plfstrt + plflinelen - && (planes == 6 || (planes == 5 && (current_cycle % 8) < 4))) - { - n_needed += 4; - current_cycle += 4; - } else { - n_needed += 2; - current_cycle += 2; - } - if (current_cycle >= maxhpos) - current_cycle -= maxhpos; - n--; - } - return n_needed; -} +static unsigned int waitmasktab[256]; -static __inline__ int calc_copper_cycles (int n_cycles) +STATIC_INLINE int copper_in_playfield (enum diw_states diw, int hpos) { - return /*copper_cycle_time != -1 ? copper_cycle_time * n_cycles : */copper_memory_cycles (n_cycles); + return diw == DIW_waiting_stop && hpos >= plfstrt && hpos < plfstrt + plflinelen; } -static __inline__ int copper_init_read (int n_cycles) +STATIC_INLINE int copper_cant_read (enum diw_states diw, int hpos, int planes) { - if (dmaen(DMA_COPPER)){ - int t = calc_copper_cycles (n_cycles); + int t; - eventtab[ev_copper].evtime = t + cycles; + /* @@@ */ + if (hpos >= ((maxhpos - 2) & ~1)) return 1; - } else { - copstate = COP_read; - eventtab[ev_copper].active = 0; - return 0; - } -} -static __inline__ void copper_read (void) -{ - int cmd; + if (currprefs.chipset_mask & CSMASK_AGA) + /* FIXME */ + return 0; - copi1 = chipmem_bank.wget(coplc); - copi2 = chipmem_bank.wget(coplc+2); - coplc += 4; - eventtab[ev_copper].oldcycles = cycles; + if (! copper_in_playfield (diw, hpos)) + return 0; - cmd = (copi1 & 1) | ((copi2 & 1) << 1); - copstate = cop_cmds[cmd]; - eventtab[ev_copper].oldcycles = cycles; + t = cycles_for_plane[planes][hpos & 7]; +#if 0 + if (t == -1) + abort (); +#endif + return t; } -static __inline__ void handle_bltfinish_wait (void) +STATIC_INLINE int dangerous_reg (int reg) { - if (bltstate == BLT_done) { - copstate = COP_read; - /* Don't need to wait. Experimental: No copper wakeup time in this case. */ - } else { - eventtab[ev_copper].active = 0; - copstate = COP_morewait; - copper_waiting_for_blitter = 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; } -void blitter_done_notify (void) +static void update_copper (int until_hpos) { - if (copper_waiting_for_blitter) { - copper_waiting_for_blitter = 0; - eventtab[ev_copper].active = 1; - eventtab[ev_copper].oldcycles = cycles; - eventtab[ev_copper].evtime = 1 + cycles; - events_schedule (); - } -} + int vp = vpos & (((cop_state.i2 >> 8) & 0x7F) | 0x80); + int c_hpos = cop_state.hpos; -#if 0 -static void do_copper_cheat(void) -{ - int coptime, t; - int nmoves = 100; /*??*/ - int nextcycles = eventtab[ev_hsync].evtime + currprefs.copper_pos; + if (eventtab[ev_copper].active) + abort (); - eventtab[ev_copper].evtime = nextcycles; - eventtab[ev_copper].oldcycles = cycles; - nextcycles -= cycles; + if (cop_state.state == COP_wait && vp < cop_state.vcmp) + abort (); - if (!dmaen(DMA_COPPER)) { - eventtab[ev_copper].active = 0; - return; - } - for (; nmoves; nmoves--) - switch(copstate){ - case COP_read: - copper_read (); - break; + until_hpos &= ~1; - case COP_read_ignore: - copper_read (); - copstate = COP_read; - break; + if (until_hpos > (maxhpos & ~1)) + until_hpos = maxhpos & ~1; - case COP_move: - if (copi1 >= (copcon & 2 ? 0x40u : 0x80u)) { - custom_bank.wput(copi1,copi2); - copstate = COP_read; - } else { - copstate = COP_stop; - eventtab[ev_copper].active = 0; - copper_active = 0; - return; - } - break; + for (;;) { + int old_hpos = c_hpos; + int hp; - case COP_skip: - copstate = COP_read; - if (calc_copcomp_true(vpos, current_hpos()) == 0) - copstate = COP_read_ignore; + if (c_hpos > until_hpos) break; - case COP_wait: - coptime = calc_copcomp_true(vpos, current_hpos()); - if (coptime < 0) { - copstate = COP_stop; - eventtab[ev_copper].active = 0; - copper_active = 0; - return; - } - if (coptime == 0) { - copper_read(); - if (vpos != 255) - break; - eventtab[ev_copper].evtime = cycles + 6; - return; - } - if (coptime >= nextcycles) - return; - if (vpos == 255) - eventtab[ev_copper].evtime = cycles + coptime; - /*else - copstate = COP_read;*/ - return; - - case COP_stop: - eventtab[ev_copper].active = 0; - copper_active = 0; - return; - - case COP_morewait: - case COP_do_read: - case COP_do_read_ignore: - abort(); - } -} -#endif + /* So we know about the vertical DIW. */ + decide_line (c_hpos); -static void do_copper(void) -{ - int coptime, t; - for (;;) - switch(copstate){ - case COP_read: - eventtab[ev_copper].oldcycles = cycles; - if (!copper_init_read (2)) - return; - copstate = COP_do_read; - return; - - case COP_do_read: - copper_read (); - break; - - case COP_read_ignore: - eventtab[ev_copper].oldcycles = cycles; - if (!copper_init_read (2)) - return; - copstate = COP_do_read_ignore; - return; + c_hpos += 2; + if (copper_cant_read (diwstate, old_hpos, corrected_nr_planes_from_bplcon0)) + continue; - case COP_do_read_ignore: - copper_read (); - copstate = COP_read; + 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_move: - if (copi1 >= (copcon & 2 ? 0x40u : 0x80u)) { - custom_bank.wput(copi1,copi2); - copstate = COP_read; + 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; - } else { - copstate = COP_stop; - eventtab[ev_copper].active = 0; - copper_active = 0; } - return; - - case COP_skip: - copstate = COP_read; - if (calc_copcomp_true(vpos, current_hpos()) == 0) - copstate = COP_read_ignore; - break; - - case COP_wait: - /* Recognize blitter wait statements. This is a speed optimization - * only.*/ - if (copi1 == 1 && copi2 == 0) { - handle_bltfinish_wait (); - if (!eventtab[ev_copper].active) - return; + /* 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; } - coptime = calc_copcomp_true_vpos(vpos, current_hpos()); - if (coptime > 0) { - copstate = COP_morewait; - eventtab[ev_copper].oldcycles = cycles; - eventtab[ev_copper].evtime = coptime + cycles; - return; + + 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; } - coptime = calc_copcomp_true(vpos, current_hpos()); - if (coptime < 0) { - copstate = COP_stop; - eventtab[ev_copper].active = 0; - copper_active = 0; - return; + 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 (coptime) { - copstate = COP_morewait; - eventtab[ev_copper].evtime = coptime + cycles; - return; + 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; + } } - copstate = COP_read; - /* Experimental: no copper wakeup time in this case. The HRM says - * nothing about this. */ break; - case COP_morewait: - coptime = calc_copcomp_true(vpos, current_hpos()); - if (coptime < 0) { - copstate = COP_stop; - eventtab[ev_copper].active = 0; - copper_active = 0; - return; - } - if (coptime) { - eventtab[ev_copper].evtime = coptime + cycles; - return; + case COP_wait: + if (vp < cop_state.vcmp) + abort (); + + hp = c_hpos & (cop_state.i2 & 0xFE); + if (vp == cop_state.vcmp && hp < cop_state.hcmp) + break; + + /* Now we know that the comparisons were successful. We might still + have to wait for the blitter though. */ + if ((cop_state.i2 & 0x8000) == 0 && (DMACONR() & 0x4000)) { + /* We need to wait for the blitter. */ + cop_state.state = COP_bltwait; + copper_enabled_thisline = 0; + regs.spcflags &= ~SPCFLAG_COPPER; + goto out; } - /* Copper wakeup time: 1 memory cycle, plus 2 for the next read */ - eventtab[ev_copper].oldcycles = cycles; - if (!copper_init_read (3)) - return; - copstate = COP_do_read; - return; - case COP_stop: - eventtab[ev_copper].active = 0; - copper_active = 0; - return; + cop_state.state = COP_read1; + break; + + default: + abort (); } -} + } -static void diskblk_handler(void) -{ - regs.spcflags |= SPCFLAG_DISK; - eventtab[ev_diskblk].active = 0; + out: + cop_state.hpos = c_hpos; +#if 0 + /* The future, Conan? */ + if (cop_state.state == COP_read1 || cop_state.state == COP_read2) { + int ip = cop_state.ip; + int word = cop_state.i1; + + if (eventtab[ev_copper].active /* || ! (regs.spcflags & SPCFLAG_COPPER) */) + abort (); + + if (cop_state.state == COP_read2) { + ip += 2; + c_hpos += 2; + goto inner; + } + while (c_hpos < (maxhpos & ~1)) { + word = chipmem_bank.wget (ip); + ip += 4; + c_hpos += 4; + inner: + if ((word & 1) || dangerous_reg (word)) + break; + } + cop_min_waittime = c_hpos - cop_state.hpos; + if (cop_min_waittime >= 8) { + regs.spcflags &= ~SPCFLAG_COPPER; + eventtab[ev_copper].active = 1; + eventtab[ev_copper].oldcycles = cycles; + eventtab[ev_copper].evtime = cycles + cop_min_waittime; + events_schedule (); + } + } +#endif } -void do_disk(void) +static void compute_spcflag_copper (void) { - if (dskdmaen != 2 && (regs.spcflags & SPCFLAG_DISK)) { - static int warned = 0; - if (!warned) - warned++, write_log ("BUG!\n"); + copper_enabled_thisline = 0; + regs.spcflags &= ~SPCFLAG_COPPER; + if (! dmaen (DMA_COPPER) || cop_state.state == COP_stop || cop_state.state == COP_bltwait) return; - } - if (dmaen(0x10)){ - if (dsklen & 0x4000) { - if (!chipmem_bank.check (dskpt, 2*dsklength)) { - write_log ("warning: Bad disk write DMA pointer\n"); - } else { - uae_u8 *mfmp = get_real_address (dskpt); - int i; - DISK_InitWrite(); - - for (i = 0; i < dsklength; i++) { - uae_u16 d = (*mfmp << 8) + *(mfmp+1); - mfmwrite[i] = d; - mfmp += 2; - } - DISK_WriteData(dsklength); + + if (cop_state.state == COP_wait) { + int vp = vpos & (((cop_state.i2 >> 8) & 0x7F) | 0x80); + + if (vp < cop_state.vcmp) + return; + copper_enabled_thisline = 1; + + if (0 && vp == cop_state.vcmp) { + int hp = (cop_state.hpos + 2) & (cop_state.i2 & 0xFE); + cop_min_waittime = cop_state.hcmp - hp - 4; + + /* 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; } - } else { - int result = DISK_ReadMFM (dskpt); } - regs.spcflags &= ~SPCFLAG_DISK; - INTREQ(0x9002); - dskdmaen = -1; } + + copper_enabled_thisline = 1; + regs.spcflags |= SPCFLAG_COPPER; } -static void gen_pfield_tables(void) +static void copper_handler (void) { - int i; - union { - struct { - uae_u8 a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p; - } foo; - struct { - uae_u32 a, b, c, d; - } bar; - } baz; + /* This will take effect immediately, within the same cycle. */ + regs.spcflags |= SPCFLAG_COPPER; - 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; - 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; - clxtab[i] = ((((i & 3) && (i & 12)) << 9) - | (((i & 3) && (i & 48)) << 10) - | (((i & 3) && (i & 192)) << 11) - | (((i & 12) && (i & 48)) << 12) - | (((i & 12) && (i & 192)) << 13) - | (((i & 48) && (i & 192)) << 14)); - } + if (! copper_enabled_thisline) + abort (); - 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 (cop_state.state == COP_wait) { + cop_state.hpos += cop_min_waittime; + if (cop_state.hpos > current_hpos ()) + abort (); } + + eventtab[ev_copper].active = 0; +} + +void blitter_done_notify (void) +{ + if (cop_state.state != COP_bltwait) + return; + + copper_enabled_thisline = 1; + regs.spcflags |= SPCFLAG_COPPER; + cop_state.state = COP_wait; +} + +void do_copper (void) +{ + int hpos = current_hpos (); + update_copper (hpos); } -static void do_sprites(int currvp, int currhp) +static void do_sprites (int currvp, int currhp) { int i; - /* 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. */ - int maxspr = currhp/4 - 0x14/4; + int maxspr; + #if 0 if (currvp == 0) return; @@ -3224,9 +2346,17 @@ static void do_sprites(int currvp, int c * second time only _after_ the VBlank interval, and it showed the same behaviour * as it did unmodified under UAE with the above check. This indicates that the * solution below is correct. */ - if (currvp < vblank_endline) + /* Another update: seems like we have to use the NTSC value here (see Sanity Turmoil + * demo). */ + /* Maximum for Sanity Turmoil: 27. + Minimum for Sanity Arte: 22. */ + if (currvp < sprite_vblank_endline) return; #endif + + /* 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) @@ -3235,744 +2365,39 @@ static void do_sprites(int currvp, int c for (i = 0; i < maxspr; i++) { int fetch = 0; - if (spron[i] == 0) + if (spr[i].on == 0) continue; - if (sprst[i] == SPR_restart) { + if (spr[i].state == SPR_restart) { fetch = 2; - spron[i] = 1; - } else if ((sprst[i] == SPR_waiting_start && sprvstart[i] == vpos) || sprst[i] == SPR_waiting_stop) { + spr[i].on = 1; + } else if ((spr[i].state == SPR_waiting_start && spr[i].vstart == vpos) || spr[i].state == SPR_waiting_stop) { fetch = 1; - sprst[i] = SPR_waiting_stop; + spr[i].state = SPR_waiting_stop; } - if (sprst[i] == SPR_waiting_stop && sprvstop[i] == vpos) { + if ((spr[i].state == SPR_waiting_stop || spr[i].state == SPR_waiting_start) && spr[i].vstop == vpos) { fetch = 2; - sprst[i] = SPR_waiting_start; + spr[i].state = SPR_waiting_start; } - if (fetch && dmaen(DMA_SPRITE)) { - uae_u16 data1 = chipmem_bank.wget(sprpt[i]); - uae_u16 data2 = chipmem_bank.wget(sprpt[i]+2); - sprpt[i] += 4; + if (fetch && dmaen (DMA_SPRITE)) { + uae_u16 data1 = chipmem_bank.wget (spr[i].pt); + uae_u16 data2 = chipmem_bank.wget (spr[i].pt + 2); + spr[i].pt += 4; if (fetch == 1) { /* Hack for X mouse auto-calibration */ if (i == 0 && !sprvbfl && ((sprpos[0] & 0xff) << 2) > 2 * DISPLAY_LEFT_SHIFT) { - spr0ctl=sprctl[0]; - spr0pos=sprpos[0]; - sprvbfl=2; - } - SPRxDATB_1(data2, i); - SPRxDATA_1(data1, i); - } else { - SPRxPOS_1(data1, i); - SPRxCTL_1(data2, i); - } - } - } -} - -static uae_u32 attach_2nd; - -static uae_u32 do_sprite_collisions (struct sprite_draw *spd, int prev_overlap, int i, int nr_spr) -{ - int j; - int sprxp = spd[i].linepos; - uae_u32 datab = spd[i].datab; - uae_u32 mask2 = 0; - int sbit = 1 << spd[i].num; - int sprx_shift = 1; - int attach_compare = -1; - if (currprefs.gfx_lores != 1) - sprx_shift = 0; - - attach_2nd = 0; - if ((spd[i].num & 1) == 1 && (spd[i].ctl & 0x80) == 0x80) - attach_compare = spd[i].num - 1; - - for (j = prev_overlap; j < i; j++) { - uae_u32 mask1; - int off; - - if (spd[i].num < spd[j].num) - continue; - - off = sprxp - spd[j].linepos; - off <<= sprx_shift; - mask1 = spd[j].datab >> off; - - /* If j is an attachment for i, then j doesn't block i */ - if (spd[j].num == attach_compare) { - attach_2nd |= mask1; - } else { - mask1 |= (mask1 & 0xAAAAAAAA) >> 1; - mask1 |= (mask1 & 0x55555555) << 1; - if (datab & mask1) - clxdat |= clxtab[(sbit | (1 << spd[j].num)) & clx_sprmask]; - mask2 |= mask1; - } - } - for (j = i+1; j < nr_spr; j++) { - uae_u32 mask1; - int off = spd[j].linepos - sprxp; - - if (off >= sprite_width || spd[i].num < spd[j].num) - break; - - off <<= sprx_shift; - mask1 = spd[j].datab << off; - - /* If j is an attachment for i, then j doesn't block i */ - if (spd[j].num == attach_compare) { - attach_2nd |= mask1; - } else { - mask1 |= (mask1 & 0xAAAAAAAA) >> 1; - mask1 |= (mask1 & 0x55555555) << 1; - if (datab & mask1) - clxdat |= clxtab[(sbit | (1 << spd[j].num)) & clx_sprmask]; - mask2 |= mask1; - } - } - datab &= ~mask2; - return datab; -} - -static __inline__ void render_sprite (int spr, int sprxp, uae_u32 datab, int ham, int attch, int sprx_inc) -{ - uae_u32 datcd; - int basecol = 16; - if (!attch) - basecol += (spr & ~1)*2; - if (bpldualpf) - basecol |= 128; - if (attch) - datcd = attach_2nd; - - for(; attch ? datab | datcd : datab; sprxp += sprx_inc) { - int col; - - if (attch) { - col = ((datab & 3) << 2) | (datcd & 3); - datcd >>= 2; - } else - col = datab & 3; - datab >>= 2; - if (col) { - col |= basecol; - if (ham) { - col = colors_for_drawing.color_regs[col]; - ham_linebuf[sprxp] = col; - if (sprx_inc == 2) { - ham_linebuf[sprxp+1] = col; - } - } else { - pixdata.apixels[sprxp] = col; - if (sprx_inc == 2) { - pixdata.apixels[sprxp+1] = col; - } - } - } - } -} - -static void walk_sprites (struct sprite_draw *spd, int nr_spr) -{ - int i, prev_overlap; - int last_sprite_pos = -64; - uae_u32 plane1 = 0, plane2 = 0; - int sprx_inc = 1, sprx_shift = 1; - - if (currprefs.gfx_lores == 0) - sprx_inc = 2, sprx_shift = 0; - - prev_overlap = 0; - for (i = 0; i < nr_spr; i++) { - int sprxp = spd[i].linepos; - int m = 1 << spd[i].num; - uae_u32 datab; - while (prev_overlap < i && spd[prev_overlap].linepos + sprite_width <= sprxp) - prev_overlap++; - - datab = do_sprite_collisions (spd, prev_overlap, i, nr_spr); -#ifdef LORES_HACK - if (currprefs.gfx_lores == 2) - sprxp >>= 1; -#endif - if ((bpldualpf && plfpri[1] < 256) || (plfpri[2] < 256)) { - if (sprxp != last_sprite_pos) { - int ok = last_sprite_pos-sprxp+16; - int ok2; - if (ok <= 0) { - ok = ok2 = 0; - plane1 = 0; - plane2 = 0; - } else { - ok2 = ok << sprx_shift; - plane1 >>= 32 - ok2; - plane2 >>= 32 - ok2; - } - last_sprite_pos = sprxp; - - if (bpldualpf) { - uae_u32 mask = 3 << ok2; - int p = sprxp+ok; - - for (; mask; mask <<= 2, p += sprx_inc) { - int data = pixdata.apixels[p]; - if (dblpf_2nd2[data] == 2) - plane2 |= mask; - if (dblpf_2nd1[data] == 1) - plane1 |= mask; - } - } else { - uae_u32 mask = 3 << ok2; - int p = sprxp+ok; - - for (; mask; mask <<= 2, p += sprx_inc) { - if (pixdata.apixels[p]) - plane2 |= mask; - } - } - } - if (bpldualpf && m >= plfpri[1]) { - datab &= ~plane1; - attach_2nd &= ~plane1; - } - if (m >= plfpri[2]) { - datab &= ~plane2; - attach_2nd &= ~plane2; - } - } - if ((spd[i].num & 1) == 1 && (spd[i].ctl & 0x80) == 0x80) { - /* Attached sprite */ - if (bplham) { - if (sprx_inc == 1) { - render_sprite (spd[i].num, sprxp, datab, 1, 1, 1); - } else { - render_sprite (spd[i].num, sprxp, datab, 1, 1, 2); + spr0ctl = sprctl[0]; + spr0pos = sprpos[0]; + sprvbfl = 2; } + SPRxDATB_1 (data2, i); + SPRxDATA_1 (data1, i); } else { - if (sprx_inc == 1) { - render_sprite (spd[i].num, sprxp, datab, 0, 1, 1); - } else { - render_sprite (spd[i].num, sprxp, datab, 0, 1, 2); - } - } - /* This still leaves one attached sprite bug, but at the moment I'm too lazy */ - if (i + 1 < nr_spr && spd[i+1].num == spd[i].num - 1 && spd[i+1].linepos == spd[i].linepos) - i++; - } else { - if (bplham) { - if (sprx_inc == 1) { - render_sprite (spd[i].num, sprxp, datab, 1, 0, 1); - } else { - render_sprite (spd[i].num, sprxp, datab, 1, 0, 2); - } - } else { - if (sprx_inc == 1) { - render_sprite (spd[i].num, sprxp, datab, 0, 0, 1); - } else { - render_sprite (spd[i].num, sprxp, datab, 0, 0, 2); - } - } - } - } -} - -#ifndef SMART_UPDATE -#undef UNALIGNED_PROFITABLE -#endif - -#ifdef UNALIGNED_PROFITABLE - -static void pfield_doline_unaligned_h (int lineno) -{ - int xpos = dp_for_drawing->plfstrt * 4 - DISPLAY_LEFT_SHIFT * 2; - - if (bplhires) { - int xpos1 = xpos + 16 + bpldelay1*2; - int xpos2; - uae_u8 *dataptr = line_data[lineno]; - int len = dp_for_drawing->plflinelen >> 1; - - if (len <= 0) - return; - - if (bpldelay1 == bpldelay2) { - switch (bplplanecnt) { - case 1: set_hires_h_0_0 ((uae_u32 *)(pixdata.apixels + xpos1), dataptr, len); break; - case 2: set_hires_h_1_0 ((uae_u32 *)(pixdata.apixels + xpos1), dataptr, len); break; - case 3: set_hires_h_2_0 ((uae_u32 *)(pixdata.apixels + xpos1), dataptr, len); break; - case 4: set_hires_h_3_0 ((uae_u32 *)(pixdata.apixels + xpos1), dataptr, len); break; - case 5: set_hires_h_4_0 ((uae_u32 *)(pixdata.apixels + xpos1), dataptr, len); break; - case 6: set_hires_h_5_0 ((uae_u32 *)(pixdata.apixels + xpos1), dataptr, len); break; - case 7: set_hires_h_6_0 ((uae_u32 *)(pixdata.apixels + xpos1), dataptr, len); break; - case 8: set_hires_h_7_0 ((uae_u32 *)(pixdata.apixels + xpos1), dataptr, len); break; - } - } else { - switch (bplplanecnt) { - case 1: case 2: set_hires_h_0_1 ((uae_u32 *)(pixdata.apixels + xpos1), dataptr, len); break; - case 3: case 4: set_hires_h_1_1 ((uae_u32 *)(pixdata.apixels + xpos1), dataptr, len); break; - case 5: case 6: set_hires_h_2_1 ((uae_u32 *)(pixdata.apixels + xpos1), dataptr, len); break; - case 7: case 8: set_hires_h_3_1 ((uae_u32 *)(pixdata.apixels + xpos1), dataptr, len); break; - } - - xpos2 = xpos + 16 + bpldelay2*2; - switch (bplplanecnt) { - case 2: case 3: set_hires_h_0_2 ((uae_u32 *)(pixdata.apixels + xpos2), dataptr, len); break; - case 4: case 5: set_hires_h_1_2 ((uae_u32 *)(pixdata.apixels + xpos2), dataptr, len); break; - case 6: case 7: set_hires_h_2_2 ((uae_u32 *)(pixdata.apixels + xpos2), dataptr, len); break; - case 8: set_hires_h_3_2 ((uae_u32 *)(pixdata.apixels + xpos2), dataptr, len); break; - } - } - } else { - int xpos1 = xpos + 32 + bpldelay1*2; - int xpos2; - uae_u8 *dataptr = line_data[lineno]; - int len = dp_for_drawing->plflinelen >> 2; - - if (len <= 0) - return; - - if (bpldelay1 == bpldelay2) { - switch (bplplanecnt) { - case 1: set_lores_h_0_0 ((uae_u32 *)(pixdata.apixels + xpos1), dataptr, len); break; - case 2: set_lores_h_1_0 ((uae_u32 *)(pixdata.apixels + xpos1), dataptr, len); break; - case 3: set_lores_h_2_0 ((uae_u32 *)(pixdata.apixels + xpos1), dataptr, len); break; - case 4: set_lores_h_3_0 ((uae_u32 *)(pixdata.apixels + xpos1), dataptr, len); break; - case 5: set_lores_h_4_0 ((uae_u32 *)(pixdata.apixels + xpos1), dataptr, len); break; - case 6: set_lores_h_5_0 ((uae_u32 *)(pixdata.apixels + xpos1), dataptr, len); break; - case 7: set_lores_h_6_0 ((uae_u32 *)(pixdata.apixels + xpos1), dataptr, len); break; - case 8: set_lores_h_7_0 ((uae_u32 *)(pixdata.apixels + xpos1), dataptr, len); break; - } - } else { - switch (bplplanecnt) { - case 1: case 2: set_lores_h_0_1 ((uae_u32 *)(pixdata.apixels + xpos1), dataptr, len); break; - case 3: case 4: set_lores_h_1_1 ((uae_u32 *)(pixdata.apixels + xpos1), dataptr, len); break; - case 5: case 6: set_lores_h_2_1 ((uae_u32 *)(pixdata.apixels + xpos1), dataptr, len); break; - case 7: case 8: set_lores_h_3_1 ((uae_u32 *)(pixdata.apixels + xpos1), dataptr, len); break; - } - - xpos2 = xpos + 32 + bpldelay2*2; - switch (bplplanecnt) { - case 2: case 3: set_lores_h_0_2 ((uae_u32 *)(pixdata.apixels + xpos2), dataptr, len); break; - case 4: case 5: set_lores_h_1_2 ((uae_u32 *)(pixdata.apixels + xpos2), dataptr, len); break; - case 6: case 7: set_lores_h_2_2 ((uae_u32 *)(pixdata.apixels + xpos2), dataptr, len); break; - case 8: set_lores_h_3_2 ((uae_u32 *)(pixdata.apixels + xpos2), dataptr, len); break; - } - } - } -} - -static void pfield_doline_unaligned_l (int lineno) -{ - int xpos = dp_for_drawing->plfstrt * 2 - DISPLAY_LEFT_SHIFT; - - if (bplhires) { - int xpos1 = xpos + 8 + bpldelay1; - int xpos2; - uae_u8 *dataptr = line_data[lineno]; - int len = dp_for_drawing->plflinelen >> 1; - - if (len <= 0) - return; - - if (bpldelay1 == bpldelay2) { - switch (bplplanecnt) { - case 1: set_hires_l_0_0 ((uae_u32 *)(pixdata.apixels + xpos1), dataptr, len); break; - case 2: set_hires_l_1_0 ((uae_u32 *)(pixdata.apixels + xpos1), dataptr, len); break; - case 3: set_hires_l_2_0 ((uae_u32 *)(pixdata.apixels + xpos1), dataptr, len); break; - case 4: set_hires_l_3_0 ((uae_u32 *)(pixdata.apixels + xpos1), dataptr, len); break; - case 5: set_hires_l_4_0 ((uae_u32 *)(pixdata.apixels + xpos1), dataptr, len); break; - case 6: set_hires_l_5_0 ((uae_u32 *)(pixdata.apixels + xpos1), dataptr, len); break; - case 7: set_hires_l_6_0 ((uae_u32 *)(pixdata.apixels + xpos1), dataptr, len); break; - case 8: set_hires_l_7_0 ((uae_u32 *)(pixdata.apixels + xpos1), dataptr, len); break; - } - } else { - switch (bplplanecnt) { - case 1: case 2: set_hires_l_0_1 ((uae_u32 *)(pixdata.apixels + xpos1), dataptr, len); break; - case 3: case 4: set_hires_l_1_1 ((uae_u32 *)(pixdata.apixels + xpos1), dataptr, len); break; - case 5: case 6: set_hires_l_2_1 ((uae_u32 *)(pixdata.apixels + xpos1), dataptr, len); break; - case 7: case 8: set_hires_l_3_1 ((uae_u32 *)(pixdata.apixels + xpos1), dataptr, len); break; - } - - xpos2 = xpos + 8 + bpldelay2; - switch (bplplanecnt) { - case 2: case 3: set_hires_l_0_2 ((uae_u32 *)(pixdata.apixels + xpos2), dataptr, len); break; - case 4: case 5: set_hires_l_1_2 ((uae_u32 *)(pixdata.apixels + xpos2), dataptr, len); break; - case 6: case 7: set_hires_l_2_2 ((uae_u32 *)(pixdata.apixels + xpos2), dataptr, len); break; - case 8: set_hires_l_3_2 ((uae_u32 *)(pixdata.apixels + xpos2), dataptr, len); break; - } - } - } else { - int xpos1 = xpos + 16 + bpldelay1; - int xpos2; - uae_u8 *dataptr = line_data[lineno]; - int len = dp_for_drawing->plflinelen >> 2; - - if (len <= 0) - return; - - if (bpldelay1 == bpldelay2) { - switch (bplplanecnt) { - case 1: set_hires_h_0_0 ((uae_u32 *)(pixdata.apixels + xpos1), dataptr, len); break; - case 2: set_hires_h_1_0 ((uae_u32 *)(pixdata.apixels + xpos1), dataptr, len); break; - case 3: set_hires_h_2_0 ((uae_u32 *)(pixdata.apixels + xpos1), dataptr, len); break; - case 4: set_hires_h_3_0 ((uae_u32 *)(pixdata.apixels + xpos1), dataptr, len); break; - case 5: set_hires_h_4_0 ((uae_u32 *)(pixdata.apixels + xpos1), dataptr, len); break; - case 6: set_hires_h_5_0 ((uae_u32 *)(pixdata.apixels + xpos1), dataptr, len); break; - case 7: set_hires_h_6_0 ((uae_u32 *)(pixdata.apixels + xpos1), dataptr, len); break; - case 8: set_hires_h_7_0 ((uae_u32 *)(pixdata.apixels + xpos1), dataptr, len); break; - } - } else { - switch (bplplanecnt) { - case 1: case 2: set_hires_h_0_1 ((uae_u32 *)(pixdata.apixels + xpos1), dataptr, len); break; - case 3: case 4: set_hires_h_1_1 ((uae_u32 *)(pixdata.apixels + xpos1), dataptr, len); break; - case 5: case 6: set_hires_h_2_1 ((uae_u32 *)(pixdata.apixels + xpos1), dataptr, len); break; - case 7: case 8: set_hires_h_3_1 ((uae_u32 *)(pixdata.apixels + xpos1), dataptr, len); break; - } - - xpos2 = xpos + 16 + bpldelay2; - switch (bplplanecnt) { - case 2: case 3: set_hires_h_0_2 ((uae_u32 *)(pixdata.apixels + xpos2), dataptr, len); break; - case 4: case 5: set_hires_h_1_2 ((uae_u32 *)(pixdata.apixels + xpos2), dataptr, len); break; - case 6: case 7: set_hires_h_2_2 ((uae_u32 *)(pixdata.apixels + xpos2), dataptr, len); break; - case 8: set_hires_h_3_2 ((uae_u32 *)(pixdata.apixels + xpos2), dataptr, len); break; - } - } - } -} - -#define pfield_doline_h pfield_doline_unaligned_h -#define pfield_doline_l pfield_doline_unaligned_l - -#else /* not UNALIGNED_PROFITABLE */ - - -static __inline__ void pfield_orword_hires_h(int data, unsigned char *dp, int bit) -{ - uae_u32 *pixptr = (uae_u32 *)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; -} - -static __inline__ void pfield_orword_lores_h(int data, unsigned char *dp, int bit) -{ - uae_u32 *pixptr = (uae_u32 *)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; -} - -static __inline__ void pfield_setword_hires_h(int data, unsigned char *dp, int bit) -{ - uae_u32 *pixptr = (uae_u32 *)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; -} - -static __inline__ void pfield_setword_lores_h(int data, unsigned char *dp, int bit) -{ - uae_u32 *pixptr = (uae_u32 *)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; -} - -static __inline__ void pfield_orword_hires_l(int data, unsigned char *dp, int bit) -{ - uae_u32 *pixptr = (uae_u32 *)dp; - - *pixptr |= hirestab_l[data >> 8][0] << bit; - *(pixptr+1) |= hirestab_l[data & 255][0] << bit; -} - -static __inline__ void pfield_orword_lores_l(int data, unsigned char *dp, int bit) -{ - uae_u32 *pixptr = (uae_u32 *)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) -{ - uae_u32 *pixptr = (uae_u32 *)dp; - - *pixptr = hirestab_l[data >> 8][0] << bit; - *(pixptr+1) = hirestab_l[data & 255][0] << bit; -} - -static __inline__ void pfield_setword_lores_l(int data, unsigned char *dp, int bit) -{ - uae_u32 *pixptr = (uae_u32 *)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; \ - uae_u16 data; \ - unsigned int bpldat2 = 0; \ - uae_u8 *ptr = (POINTER); \ - for (i = dp_for_drawing->plflinelen; i > 0; i -= LL_SUB) { \ - bpldat1 = bpldat2; \ - bpldat2 = do_get_mem_word ((uae_u16 *)ptr); \ - ptr+=2; \ - data = (bpldat1 << (16 - DELAY)) | (bpldat2 >> DELAY); \ - FUNC(data, app, MULT); \ - app += P_ADD; \ - } \ - data = bpldat2 << (16 - DELAY); \ - FUNC(data, app, MULT); \ -} - -#ifdef SMART_UPDATE -#define DATA_POINTER(n) (dataptr + (n)*MAX_WORDS_PER_LINE*2) -#else -#define DATA_POINTER(n) (real_bplpt[n]) -#endif - -static void pfield_doline_aligned_h (int lineno) -{ - int xpos = dp_for_drawing->plfstrt * 4 - DISPLAY_LEFT_SHIFT * 2; - - 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; - uae_u8 *dataptr = line_data[lineno]; - - DO_ONE_PLANE(DATA_POINTER(0), 0, pfield_setword_hires_h, delay1, 4, 16); - if (bplplanecnt > 2) { - app = pixdata.apixels + xpos1; - DO_ONE_PLANE(DATA_POINTER(2), 2, pfield_orword_hires_h, delay1, 4, 16); - } -#if AGA_CHIPSET == 1 - if (bplplanecnt > 4) { - app = pixdata.apixels + xpos1; - DO_ONE_PLANE(DATA_POINTER(4), 4, pfield_orword_hires_h, delay1, 4, 16); - } - if (bplplanecnt > 6) { - app = pixdata.apixels + xpos1; - DO_ONE_PLANE(DATA_POINTER(6), 6, pfield_orword_hires_h, delay1, 4, 16); - } -#endif - if (bplplanecnt > 1) { - app = pixdata.apixels + xpos2; - DO_ONE_PLANE(DATA_POINTER(1), 1, pfield_orword_hires_h, delay2, 4, 16); - } - if (bplplanecnt > 3) { - app = pixdata.apixels + xpos2; - DO_ONE_PLANE(DATA_POINTER(3), 3, pfield_orword_hires_h, delay2, 4, 16); - } -#if AGA_CHIPSET == 1 - if (bplplanecnt > 5) { - app = pixdata.apixels + xpos2; - DO_ONE_PLANE(DATA_POINTER(5), 5, pfield_orword_hires_h, delay2, 4, 16); - } - if (bplplanecnt > 7) { - app = pixdata.apixels + xpos2; - DO_ONE_PLANE(DATA_POINTER(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; - uae_u8 *dataptr = line_data[lineno]; - - DO_ONE_PLANE(DATA_POINTER(0), 0, pfield_setword_lores_h, bpldelay1, 8, 32); - if (bplplanecnt > 2) { - app = pixdata.apixels + x; - DO_ONE_PLANE(DATA_POINTER(2), 2, pfield_orword_lores_h, bpldelay1, 8, 32); - } - if (bplplanecnt > 4) { - app = pixdata.apixels + x; - DO_ONE_PLANE(DATA_POINTER(4), 4, pfield_orword_lores_h, bpldelay1, 8, 32); - } -#if AGA_CHIPSET == 1 - if (bplplanecnt > 6) { - app = pixdata.apixels + x; - DO_ONE_PLANE(DATA_POINTER(6), 6, pfield_orword_lores_h, bpldelay1, 8, 32); - } -#endif - if (bplplanecnt > 1) { - app = pixdata.apixels + x; - DO_ONE_PLANE(DATA_POINTER(1), 1, pfield_orword_lores_h, bpldelay2, 8, 32); - } - if (bplplanecnt > 3) { - app = pixdata.apixels + x; - DO_ONE_PLANE(DATA_POINTER(3), 3, pfield_orword_lores_h, bpldelay2, 8, 32); - } - if (bplplanecnt > 5) { - app = pixdata.apixels + x; - DO_ONE_PLANE(DATA_POINTER(5), 5, pfield_orword_lores_h, bpldelay2, 8, 32); - } -#if AGA_CHIPSET == 1 - if (bplplanecnt > 7) { - app = pixdata.apixels + x; - DO_ONE_PLANE(DATA_POINTER(7), 7, pfield_orword_lores_h, bpldelay2, 8, 32); - } -#endif - } else { - memset(pixdata.apixels, 0, sizeof(pixdata.apixels)); - } - } -} - -static void pfield_doline_aligned_l (int lineno) -{ - int xpos = dp_for_drawing->plfstrt * 2 - DISPLAY_LEFT_SHIFT; - - 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; - uae_u8 *dataptr = line_data[lineno]; - - DO_ONE_PLANE(DATA_POINTER(0), 0, pfield_setword_hires_l, delay1, 4, 8); - if (bplplanecnt > 2) { - app = pixdata.apixels + xpos1; - DO_ONE_PLANE(DATA_POINTER(2), 2, pfield_orword_hires_l, delay1, 4, 8); - } -#if AGA_CHIPSET == 1 - if (bplplanecnt > 4) { - app = pixdata.apixels + xpos1; - DO_ONE_PLANE(DATA_POINTER(4), 4, pfield_orword_hires_l, delay1, 4, 8); - } - if (bplplanecnt > 6) { - app = pixdata.apixels + xpos1; - DO_ONE_PLANE(DATA_POINTER(6), 6, pfield_orword_hires_l, delay1, 4, 8); - } -#endif - if (bplplanecnt > 1) { - app = pixdata.apixels + xpos2; - DO_ONE_PLANE(DATA_POINTER(1), 1, pfield_orword_hires_l, delay2, 4, 8); - } - if (bplplanecnt > 3) { - app = pixdata.apixels + xpos2; - DO_ONE_PLANE(DATA_POINTER(3), 3, pfield_orword_hires_l, delay2, 4, 8); - } -#if AGA_CHIPSET == 1 - if (bplplanecnt > 5) { - app = pixdata.apixels + xpos2; - DO_ONE_PLANE(DATA_POINTER(5), 5, pfield_orword_hires_l, delay2, 4, 8); + SPRxPOS_1 (data1, i); + SPRxCTL_1 (data2, i); } - if (bplplanecnt > 7) { - app = pixdata.apixels + xpos2; - DO_ONE_PLANE(DATA_POINTER(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; - uae_u8 *dataptr = line_data[lineno]; - - DO_ONE_PLANE(DATA_POINTER(0), 0, pfield_setword_lores_l, delay1, 8, 16); - if (bplplanecnt > 2) { - app = pixdata.apixels + x; - DO_ONE_PLANE(DATA_POINTER(2), 2, pfield_orword_lores_l, delay1, 8, 16); - } - if (bplplanecnt > 4) { - app = pixdata.apixels + x; - DO_ONE_PLANE(DATA_POINTER(4), 4, pfield_orword_lores_l, delay1, 8, 16); - } -#if AGA_CHIPSET == 1 - if (bplplanecnt > 6) { - app = pixdata.apixels + x; - DO_ONE_PLANE(DATA_POINTER(6), 6, pfield_orword_lores_l, delay1, 8, 16); - } -#endif - if (bplplanecnt > 1) { - app = pixdata.apixels + x; - DO_ONE_PLANE(DATA_POINTER(1), 1, pfield_orword_lores_l, delay2, 8, 16); - } - if (bplplanecnt > 3) { - app = pixdata.apixels + x; - DO_ONE_PLANE(DATA_POINTER(3), 3, pfield_orword_lores_l, delay2, 8, 16); - } - if (bplplanecnt > 5) { - app = pixdata.apixels + x; - DO_ONE_PLANE(DATA_POINTER(5), 5, pfield_orword_lores_l, delay2, 8, 16); - } -#if AGA_CHIPSET == 1 - if (bplplanecnt > 7) { - app = pixdata.apixels + x; - DO_ONE_PLANE(DATA_POINTER(7), 7, pfield_orword_lores_l, delay2, 8, 16); - } -#endif - } else { - memset(pixdata.apixels, 0, sizeof(pixdata.apixels)); - } - } -} - -#define pfield_doline_h pfield_doline_aligned_h -#define pfield_doline_l pfield_doline_aligned_l - -#endif /* UNALIGNED_PROFITABLE */ - -static void pfield_adjust_delay (void) -{ - int ddf_left = dp_for_drawing->plfstrt; - int ddf_right = dp_for_drawing->plfstrt + dp_for_drawing->plflinelen; - int i; - - for (i = dip_for_drawing->last_delay_change-1; i >= dip_for_drawing->first_delay_change-1; i--) { - int delayreg = i < dip_for_drawing->first_delay_change ? dp_for_drawing->bplcon1 : delay_changes[i].value; - int delay1 = delayreg & 0xF; - int delay2 = (delayreg >> 4) & 0xF; - int startpos = i == dip_for_drawing->last_delay_change - 1 ? ddf_right + 8 : delay_changes[i+1].linepos; - int stoppos = i < dip_for_drawing->first_delay_change ? ddf_left : delay_changes[i].linepos; - int j; - startpos = PIXEL_XPOS (startpos + (bplhires ? 4 : 8)); - stoppos = PIXEL_XPOS (stoppos + (bplhires ? 4 : 8)); - if (currprefs.gfx_lores == 0) - delay1 <<= 1, delay2 <<= 1; - else if (currprefs.gfx_lores == 2) - startpos >>= 1, stoppos >>= 1; - for (j = startpos-1; j >= stoppos; j--) { - pixdata.apixels [j] = (pixdata.apixels[j-delay1] & 0x55) | (pixdata.apixels[j-delay2] & 0xAA); } } } @@ -3983,446 +2408,14 @@ static void init_sprites (void) for (i = 0; i < 8; i++) { /* ???? */ - sprst[i] = SPR_stop; - spron[i] = 0; + spr[i].state = SPR_stop; + spr[i].on = 0; } - memset(sprpos, 0, sizeof sprpos); - memset(sprctl, 0, sizeof sprctl); -} - -static void init_hardware_frame (void) -{ - next_lineno = 0; - nln_how = 0; - diwstate = DIW_waiting_start; - hdiwstate = DIW_waiting_start; -} - -void init_row_map(void) -{ - int i; - if (gfxvidinfo.height > 2048) { - write_log ("Resolution too high, aborting\n"); - } - for (i = 0; i < gfxvidinfo.height + 1; i++) - row_map[i] = gfxvidinfo.bufmem + gfxvidinfo.rowbytes * i; + memset (sprpos, 0, sizeof sprpos); + memset (sprctl, 0, sizeof sprctl); } -/* - * A raster line has been built in the graphics buffer. Tell the graphics code - * to do anything necessary to display it. - */ -static void do_flush_line_1 (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; - } - } -} - -static __inline__ void do_flush_line (int lineno) -{ - /* We don't want to call X libraries from the second thread right now. */ -#ifndef SUPPORT_PENGUINS - do_flush_line_1 (lineno); -#else - line_drawn[lineno] = 1; -#endif -} - -/* - * One drawing frame has been finished. Tell the graphics code about it. - * Note that the actual flush_screen() call is a no-op for all reasonable - * systems. - */ - -static __inline__ void do_flush_screen (int start, int stop) -{ - int i; -#ifdef SUPPORT_PENGUINS - for (i = 0; i < gfxvidinfo.height; i++) { - if (line_drawn[i]) - do_flush_line_1 (i); - } -#endif - if (gfxvidinfo.maxblocklines != 0 && first_block_line != -2) { - flush_block (first_block_line, last_block_line); - } - if (start <= stop) - flush_screen (start, stop); -} - -static void adjust_drawing_colors (int ctable, int bplham) -{ - if (drawing_color_matches != ctable) { - if (bplham) { - memcpy (&colors_for_drawing, curr_color_tables + ctable, - sizeof colors_for_drawing); - color_match_type = color_match_full; - } else { - memcpy (colors_for_drawing.acolors, curr_color_tables[ctable].acolors, - sizeof colors_for_drawing.acolors); - color_match_type = color_match_acolors; - } - drawing_color_matches = ctable; - } else if (bplham && color_match_type != color_match_full) { - memcpy (colors_for_drawing.color_regs, curr_color_tables[ctable].color_regs, - sizeof colors_for_drawing.color_regs); - color_match_type = color_match_full; - } -} - -static __inline__ void adjust_color0_for_color_change (void) -{ - drawing_color_matches = -1; - if (dp_for_drawing->color0 != 0xFFFFFFFFul) { - colors_for_drawing.color_regs[0] = dp_for_drawing->color0; - colors_for_drawing.acolors[0] = xcolors[dp_for_drawing->color0]; - } -} - -static __inline__ void do_color_changes (line_draw_func worker) -{ - int lastpos = 0, nextpos, i; - struct color_change *cc = curr_color_changes + dip_for_drawing->first_color_change; - - for (i = dip_for_drawing->first_color_change; i <= dip_for_drawing->last_color_change; i++, cc++) { - if (i == dip_for_drawing->last_color_change) - nextpos = max_diwlastword; - else - nextpos = PIXEL_XPOS (cc->linepos) + (COPPER_MAGIC_FUDGE << lores_shift); - worker (lastpos, nextpos); - if (i != dip_for_drawing->last_color_change) { - colors_for_drawing.color_regs[cc->regno] = cc->value; - colors_for_drawing.acolors[cc->regno] = xcolors[cc->value]; - } - if (nextpos > lastpos) { - lastpos = nextpos; - if (lastpos >= linetoscr_right_x) - break; - } - } -} - -/* We only save hardware registers during the hardware frame. Now, when - * drawing the frame, we expand the data into a slightly more useful - * form. */ -static void pfield_expand_dp_bplcon (void) -{ - bplhires = (dp_for_drawing->bplcon0 & 0x8000) == 0x8000; - bplplanecnt = (dp_for_drawing->bplcon0 & 0x7000) >> 12; - bplham = (dp_for_drawing->bplcon0 & 0x800) == 0x800; -#if AGA_CHIPSET == 1 /* The KILLEHB bit exists in ECS, but is apparently meant for Genlock - * stuff, and it's set by some demos (e.g. Andromeda Seven Seas) */ - bplehb = ((dp_for_drawing->bplcon0 & 0xFCC0) == 0x6000 && !(dp_for_drawing->bplcon2 & 0x200)); -#else - bplehb = (dp_for_drawing->bplcon0 & 0xFC00) == 0x6000; -#endif - bpldelay1 = dp_for_drawing->bplcon1 & 0xF; - bpldelay2 = (dp_for_drawing->bplcon1 >> 4) & 0xF; - plfpri[1] = 1 << 2*(dp_for_drawing->bplcon2 & 7); - plfpri[2] = 1 << 2*((dp_for_drawing->bplcon2 >> 3) & 7); - bpldualpf = (dp_for_drawing->bplcon0 & 0x400) == 0x400; - bpldualpfpri = (dp_for_drawing->bplcon2 & 0x40) == 0x40; -} - -static __inline__ void pfield_draw_line(int lineno, int gfx_ypos, int follow_ypos) -{ - int border = 0; - int to_screen = 0; - int do_double = 0; - - dp_for_drawing = 0; - dip_for_drawing = 0; - switch (linestate[lineno]) { - case LINE_AS_PREVIOUS: - case LINE_REMEMBERED_AS_PREVIOUS: - { - static int warned = 0; - if (!warned) - write_log ("Shouldn't get here... this is a bug.\n"), warned++; - } - line_decisions[lineno].which = -2; - return; - - case LINE_BORDER_PREV: - border = 1; - dp_for_drawing = line_decisions + lineno - 1; - dip_for_drawing = curr_drawinfo + lineno - 1; - break; - - case LINE_BORDER_NEXT: - border = 1; - dp_for_drawing = line_decisions + lineno + 1; - dip_for_drawing = curr_drawinfo + lineno + 1; - break; - - case LINE_DONE_AS_PREVIOUS: - line_decisions[lineno].which = -2; - /* fall through */ - case LINE_DONE: - return; - - case LINE_DECIDED_DOUBLE: - line_decisions[lineno+1].which = -2; - if (follow_ypos != -1) { - do_double = 1; - linetoscr_double_offset = gfxvidinfo.rowbytes * (follow_ypos - gfx_ypos); - } - - /* fall through */ - default: - dip_for_drawing = curr_drawinfo + lineno; - dp_for_drawing = line_decisions + lineno; - if (dp_for_drawing->which != 1) - border = 1; - break; - } - - if (!line_changed[lineno] && !frame_redraw_necessary) { - /* The case where we can skip redrawing this line. If this line - * is supposed to be doubled, and the next line is remembered as - * having been doubled, then the next line is done as well. */ - if (do_double) { - if (linestate[lineno+1] != LINE_REMEMBERED_AS_PREVIOUS) { - if (gfxvidinfo.linemem == NULL) - memcpy (row_map[follow_ypos], row_map[gfx_ypos], gfxvidinfo.rowbytes); - line_decisions[lineno + 1].which = -2; - do_flush_line (follow_ypos); - } - linestate[lineno + 1] = LINE_DONE_AS_PREVIOUS; - } - linestate[lineno] = LINE_DONE; - return; - } - - if (!border) { - xlinebuffer = gfxvidinfo.linemem; - if (xlinebuffer == NULL) - xlinebuffer = row_map[gfx_ypos]; - xlinebuffer -= linetoscr_x_adjust_bytes; - aga_lbufptr = aga_linebuf; - - pfield_expand_dp_bplcon (); - -#ifdef LORES_HACK - if (gfxvidinfo.can_double && !bplhires && !currprefs.gfx_lores - && dip_for_drawing->nr_color_changes == 0 && !bplham) - currprefs.gfx_lores = 2; -#endif - pfield_init_linetoscr (); - if (dip_for_drawing->first_delay_change != dip_for_drawing->last_delay_change) { - bpldelay1 = bpldelay2 = 0; - if (currprefs.gfx_lores) - pfield_doline_l (lineno); - else - pfield_doline_h (lineno); - pfield_adjust_delay (); - } else { - if (currprefs.gfx_lores) - pfield_doline_l (lineno); - else - pfield_doline_h (lineno); - } - - /* Check color0 adjust only if we have color changes - shouldn't happen - * otherwise. */ - adjust_drawing_colors (dp_for_drawing->ctable, bplham || bplehb); - - /* The problem is that we must call decode_ham6() BEFORE we do the - * sprites. */ - if (bplham) { - init_ham_decoding(linetoscr_x_adjust); - if (dip_for_drawing->nr_color_changes == 0) { - /* The easy case: need to do HAM decoding only once for the - * full line. */ - decode_ham6 (linetoscr_x_adjust, linetoscr_right_x); - } else /* Argh. */ { - adjust_color0_for_color_change (); - do_color_changes (decode_ham6); - adjust_drawing_colors (dp_for_drawing->ctable, bplham || bplehb); - } - } - - if (dip_for_drawing->nr_sprites != 0) { - int spr; - walk_sprites (curr_sprite_positions + dip_for_drawing->first_sprite_draw, dip_for_drawing->nr_sprites); - } - if (dip_for_drawing->nr_color_changes == 0) { - pfield_do_linetoscr_full (gfxvidinfo.linemem == NULL ? do_double : 0); - do_flush_line (gfx_ypos); - linestate[lineno] = LINE_DONE; - - if (do_double) { - linestate[lineno + 1] = LINE_DONE_AS_PREVIOUS; - do_flush_line (follow_ypos); - } - } else { - int lastpos = 0, nextpos, i; - - adjust_color0_for_color_change (); - do_color_changes (pfield_do_linetoscr); - - linestate[lineno] = LINE_DONE; - do_flush_line (gfx_ypos); - if (do_double) { - if (gfxvidinfo.linemem == NULL) - memcpy (row_map[follow_ypos], row_map[gfx_ypos], gfxvidinfo.rowbytes); - linestate[lineno + 1] = LINE_DONE_AS_PREVIOUS; - line_decisions[lineno + 1].which = -2; - do_flush_line (follow_ypos); - } - } -#ifdef LORES_HACK - if (currprefs.gfx_lores == 2) - currprefs.gfx_lores = 0; -#endif - } else { - /* Border. */ - int i, lastpos = 0, nextpos; - struct color_change *cc; - - xlinebuffer = gfxvidinfo.linemem; - if (xlinebuffer == NULL) - xlinebuffer = row_map[gfx_ypos]; - xlinebuffer -= linetoscr_x_adjust_bytes; - - adjust_drawing_colors (dp_for_drawing->ctable, 0); - /* Check color0 adjust only if we have color changes - shouldn't happen - * otherwise. */ - - if (dip_for_drawing->nr_color_changes == 0) { - fill_line (); - do_flush_line (gfx_ypos); - linestate[lineno] = LINE_DONE; - if (do_double) { - if (gfxvidinfo.linemem == NULL) { - xlinebuffer = row_map[follow_ypos] - linetoscr_x_adjust_bytes; - fill_line (); - } - do_flush_line (follow_ypos); - linestate[lineno+1] = LINE_DONE_AS_PREVIOUS; - } - return; - } - - adjust_color0_for_color_change (); - do_color_changes (pfield_do_fill_line); - - do_flush_line (gfx_ypos); - linestate[lineno] = LINE_DONE; - if (do_double) { - if (gfxvidinfo.linemem == NULL) - memcpy (row_map[follow_ypos], row_map[gfx_ypos], gfxvidinfo.rowbytes); - linestate[lineno + 1] = LINE_DONE_AS_PREVIOUS; - line_decisions[lineno + 1].which = -2; - do_flush_line (follow_ypos); - } - } -} - -#ifdef SUPPORT_PENGUINS -static smp_comm_pipe drawing_pipe; -static uae_sem_t drawing_lock; - -static void *drawing_penguin (void *cruxmedo) -{ - int l; - fprintf(stderr, "Hello, world!\n"); - - for (;;) { - /* Start of a frame. */ - int k; - new_frame: - k = read_comm_pipe_int_blocking (&drawing_pipe); - - switch (k) { - case -2: - /* Hoopy */ - break; - - default: - write_log ("Penguin got out of sync.\n"); - /* what can we do? Try to reduce the damage */ - for (;;) { - k = read_comm_pipe_int_blocking (&drawing_pipe); - if (k == -3) - break; - if (k == -1) { - uae_sem_post (&drawing_lock); - goto new_frame; - } - } - case -3: - UAE_PENGUIN_EXIT; - /* Can't happen */ - return 0; - } - - for (;;) { - int i, where; - int l = read_comm_pipe_int_blocking (&drawing_pipe); - switch (l) { - case -1: - /* End-of-frame synchronization. */ - uae_sem_post (&drawing_lock); - goto new_frame; - case -2: - /* customreset called a bit too often. That's harmless. */ - continue; - case -3: - write_log ("Penguin got out of sync.\n"); - UAE_PENGUIN_EXIT; - return 0; - } - - /* l is the line that has been finished for drawing. */ - i = l - thisframe_y_adjust_real; - if (i < 0 || i >= max_ypos_thisframe) - continue; - - if (linestate[l] == LINE_UNDECIDED) { - fprintf (stderr, "Line scheduled for drawing, but undecided %d!?\n", l); - continue; - } - if (inhibit_frame != 0) - continue; - where = amiga2aspect_line_map[i+min_ypos_for_screen]; - if (where >= gfxvidinfo.height || where == -1) - continue; - - pfield_draw_line (l, where, amiga2aspect_line_map[i+min_ypos_for_screen+1]); - } - } -} - -static penguin_id our_penguin; - -static void kill_drawing_penguin (void) -{ - /* ??? does libpthread do that for us? */ -} - -#endif - -static int penguins_enabled_thisframe; - static void adjust_array_sizes (void) { #ifdef OS_WITHOUT_MEMORY_MANAGEMENT @@ -4466,43 +2459,21 @@ static void adjust_array_sizes (void) #endif } -static void init_drawing_frame (void) +static void init_hardware_frame (void) { - int i, maxline; + next_lineno = 0; + nextline_how = nln_normal; + diwstate = DIW_waiting_start; + hdiwstate = DIW_waiting_start; +} +void init_hardware_for_drawing_frame (void) +{ adjust_array_sizes (); - check_prefs_changed_custom (); - check_prefs_changed_cpu (); - - if (max_diwstop == 0) - max_diwstop = diwlastword; - if (min_diwstart > max_diwstop) - min_diwstart = 0; - - if (thisframe_first_drawn_line == -1) - thisframe_first_drawn_line = minfirstline; - if (thisframe_first_drawn_line > thisframe_last_drawn_line) - thisframe_last_drawn_line = thisframe_first_drawn_line; - next_color_change = 0; next_delay_change = 0; next_sprite_draw = 0; - maxline = currprefs.gfx_linedbl ? (maxvpos+1) * 2 + 1 : (maxvpos+1) + 1; -#ifdef SMART_UPDATE - for (i = 0; i < maxline; i++) - linestate[i] = linestate[i] == LINE_DONE_AS_PREVIOUS ? LINE_REMEMBERED_AS_PREVIOUS : LINE_UNDECIDED; -#else - memset (linestate, LINE_UNDECIDED, maxline); -#endif - last_drawn_line = 0; - first_drawn_line = 32767; - - first_block_line = last_block_line = -2; - if (currprefs.test_drawing_speed) - frame_redraw_necessary = 1; - else if (frame_redraw_necessary) - frame_redraw_necessary--; next_color_entry = 0; remembered_color_entry = -1; @@ -4514,216 +2485,94 @@ static void init_drawing_frame (void) curr_color_tables = color_tables[current_change_set ^ 1]; prev_drawinfo = line_drawinfo[current_change_set]; - curr_drawinfo = line_drawinfo[current_change_set ^= 1]; - drawing_color_matches = -1; - color_src_match = color_dest_match = -1; - - prev_x_adjust = linetoscr_x_adjust; - prev_y_adjust = thisframe_y_adjust; - - if (currprefs.gfx_xcenter) { - if (max_diwstop - min_diwstart < gfxvidinfo.width && currprefs.gfx_xcenter == 2) - /* Try to center. */ - linetoscr_x_adjust = ((max_diwstop - min_diwstart - gfxvidinfo.width) / 2 + min_diwstart) & ~1; - else - linetoscr_x_adjust = max_diwstop - gfxvidinfo.width; + curr_drawinfo = line_drawinfo[current_change_set ^ 1]; + current_change_set ^= 1; - /* Would the old value be good enough? If so, leave it as it is if we want to - * be clever. */ - if (currprefs.gfx_xcenter == 2) { - if (linetoscr_x_adjust < prev_x_adjust && prev_x_adjust < min_diwstart) - linetoscr_x_adjust = prev_x_adjust; - } - } else - linetoscr_x_adjust = max_diwlastword - gfxvidinfo.width; - if (linetoscr_x_adjust < 0) - linetoscr_x_adjust = 0; - - linetoscr_x_adjust_bytes = linetoscr_x_adjust * gfxvidinfo.pixbytes; - - linetoscr_right_x = linetoscr_x_adjust + gfxvidinfo.width; - if (linetoscr_right_x > max_diwlastword) - linetoscr_right_x = max_diwlastword; - - thisframe_y_adjust = minfirstline; - if (currprefs.gfx_ycenter && thisframe_first_drawn_line != -1) { - if (thisframe_last_drawn_line - thisframe_first_drawn_line < max_drawn_amiga_line && currprefs.gfx_ycenter == 2) - thisframe_y_adjust = (thisframe_last_drawn_line - thisframe_first_drawn_line - max_drawn_amiga_line) / 2 + thisframe_first_drawn_line; - else - thisframe_y_adjust = thisframe_first_drawn_line; - /* Would the old value be good enough? If so, leave it as it is if we want to - * be clever. */ - if (currprefs.gfx_ycenter == 2) { - if (thisframe_y_adjust != prev_y_adjust - && prev_y_adjust <= thisframe_first_drawn_line - && prev_y_adjust + max_drawn_amiga_line > thisframe_last_drawn_line) - thisframe_y_adjust = prev_y_adjust; - } - /* Make sure the value makes sense */ - if (thisframe_y_adjust + max_drawn_amiga_line > maxvpos) - thisframe_y_adjust = maxvpos - max_drawn_amiga_line; - if (thisframe_y_adjust < minfirstline) - thisframe_y_adjust = minfirstline; - } - thisframe_y_adjust_real = thisframe_y_adjust << (currprefs.gfx_linedbl ? 1 : 0); - max_ypos_thisframe = (maxvpos - thisframe_y_adjust) << (currprefs.gfx_linedbl ? 1 : 0); - - if (prev_x_adjust != linetoscr_x_adjust || prev_y_adjust != thisframe_y_adjust) - frame_redraw_necessary |= (bplcon0 & 4) && currprefs.gfx_linedbl ? 2 : 1; - - max_diwstop = 0; - min_diwstart = 10000; - thisframe_first_drawn_line = -1; - thisframe_last_drawn_line = -1; -#ifdef SUPPORT_PENGUINS - penguins_enabled_thisframe = 1; - /* Tell the other thread that it can now expect data from us. */ - write_comm_pipe_int (&drawing_pipe, -2, 1); - memset (line_drawn, 0, sizeof line_drawn); -#endif -} - -static void finish_drawing_frame (void) -{ - int i; - -#ifdef SUPPORT_PENGUINS - /* Synchronize with other thread, then see whether there's something left for - * us to draw. @@@ This is probably a big waste of cycles if the two threads - * run at very different speeds - this one could draw stuff as well. */ - write_comm_pipe_int (&drawing_pipe, -1, 1); - uae_sem_wait (&drawing_lock); -#else - -#ifndef SMART_UPDATE - /* @@@ This isn't exactly right yet. FIXME */ - if (!interlace_seen) { - do_flush_screen (first_drawn_line, last_drawn_line); - return; - } -#endif - for (i = 0; i < max_ypos_thisframe; i++) { - int where; - int line = i + thisframe_y_adjust_real; - - if (linestate[line] == LINE_UNDECIDED) - break; - - where = amiga2aspect_line_map[i+min_ypos_for_screen]; - if (where >= gfxvidinfo.height) - break; - if (where == -1) - continue; - - pfield_draw_line (line, where, amiga2aspect_line_map[i+min_ypos_for_screen+1]); - } -#endif - do_flush_screen (first_drawn_line, last_drawn_line); -} - -static __inline__ void check_picasso (void) -{ -#ifdef PICASSO96 - if (picasso_requested_on == picasso_on) - return; - - picasso_on = picasso_requested_on; - - if (!picasso_on) - clear_inhibit_frame (2); - else - set_inhibit_frame (2); - - gfx_set_picasso_state (picasso_on); - picasso_enablescreen (picasso_requested_on); - - notice_screen_contents_lost (); -#endif + color_src_match = color_dest_match = -1; } static void vsync_handler (void) { -#ifdef FRAME_RATE_HACK /* put this here or at the end of the function? */ - { - frame_time_t curr_time = read_processor_time(); + n_frames++; + + 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 || did_reset) + if ((long int)(curr_time - vsyncmintime) > 0 || rpt_did_reset) vsyncmintime = curr_time + vsynctime; - did_reset = 0; + rpt_did_reset = 0; } -#endif + handle_events (); getjoystate (0, &joy0dir, &joy0button); getjoystate (1, &joy1dir, &joy1button); - INTREQ(0x8020); + INTREQ (0x8020); if (bplcon0 & 4) lof ^= 0x8000; - if (quit_program < 0) { - quit_program = -quit_program; - set_inhibit_frame (1); - regs.spcflags |= SPCFLAG_BRK; - if (framecnt == 0) - finish_drawing_frame (); - filesys_prepare_reset (); -#ifdef SUPPORT_PENGUINS - if (quit_program == 1) - /* Stop eating herring */ - write_comm_pipe_int (&drawing_pipe, -3, 1); -#endif + vsync_handle_redraw (lof, lof_changed); + if (quit_program > 0) return; - } - last_redraw_point++; - if (lof_changed || !interlace_seen || last_redraw_point >= 2 || lof) { + { static int cnt = 0; - - if (framecnt == 0) - finish_drawing_frame (); - count_frame (); - last_redraw_point = 0; - - check_picasso (); - - uae_sem_wait (&ihf_sem); - if (inhibit_frame != 0) - framecnt = 1; - if (frame_do_semup) - uae_sem_post (&frame_sem); - frame_do_semup = 0; - uae_sem_post (&ihf_sem); - if (cnt == 0) { /* resolution_check_change (); */ DISK_check_change (); cnt = 5; } cnt--; - if (framecnt == 0) - init_drawing_frame (); } + /* 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; - interlace_seen = 0; - COPJMP1(0); - init_hardware_frame(); + cop_state.ip = cop1lc; + cop_state.state = COP_read1; + cop_state.vpos = 0; + cop_state.hpos = 0; + cop_state.ignore_next = 0; + + init_hardware_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; + 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; @@ -4731,49 +2580,38 @@ static void vsync_handler (void) #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 = next_lineno; - int lineisdouble = 0; - int line_was_doubled = 0; + 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 (); + do_modulos (current_hpos ()); - if (framecnt == 0) { - switch (nln_how) { - case 0: - linestate[lineno] = LINE_DECIDED; - break; - case 1: - linestate[lineno] = LINE_DECIDED_DOUBLE; - if (linestate[lineno+1] != LINE_REMEMBERED_AS_PREVIOUS) - linestate[lineno+1] = LINE_AS_PREVIOUS; - break; - case 2: - if (linestate[lineno-1] == LINE_UNDECIDED) - linestate[lineno-1] = LINE_BORDER_NEXT; - linestate[lineno] = LINE_DECIDED; - break; - case 3: - linestate[lineno] = LINE_DECIDED; - if (linestate[lineno+1] == LINE_UNDECIDED - || linestate[lineno+1] == LINE_REMEMBERED_AS_PREVIOUS - || linestate[lineno+1] == LINE_AS_PREVIOUS) - linestate[lineno+1] = LINE_BORDER_PREV; - break; - } - } + 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(); + 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; @@ -4793,46 +2631,31 @@ static void hsync_handler(void) } } } -#ifdef SUPPORT_PENGUINS - if (framecnt == 0 && penguins_enabled_thisframe) { - write_comm_pipe_int (&drawing_pipe, next_lineno, 0); - } -#endif -#ifndef SMART_UPDATE - { - int i, where; - /* l is the line that has been finished for drawing. */ - i = next_lineno - thisframe_y_adjust_real; - if (i >= 0 && i < max_ypos_thisframe) { - where = amiga2aspect_line_map[i+min_ypos_for_screen]; - if (where < gfxvidinfo.height && where != -1) - pfield_draw_line (next_lineno, where, amiga2aspect_line_map[i+min_ypos_for_screen+1]); - } - } -#endif + + hardware_line_completed (next_lineno); + if (++vpos == (maxvpos + (lof != 0))) { vpos = 0; vsync_handler(); } - is_lastline = vpos + 1 == maxvpos + (lof != 0); + is_lastline = vpos + 1 == maxvpos + (lof != 0) && currprefs.m68k_speed == -1 && ! rpt_did_reset; - if ((bplcon0 & 4) && currprefs.gfx_linedbl) { - interlace_seen = 1, penguins_enabled_thisframe = 0; - } + if ((bplcon0 & 4) && currprefs.gfx_linedbl) + notice_interlace_seen (); if (framecnt == 0) { - lineno = vpos; - nln_how = 0; + int lineno = vpos; + nextline_how = nln_normal; if (currprefs.gfx_linedbl) { lineno *= 2; - nln_how = 1; + nextline_how = currprefs.gfx_linedbl == 1 ? nln_doubled : nln_nblack; if (bplcon0 & 4) { if (!lof) { lineno++; - nln_how = 2; + nextline_how = nln_lower; } else { - nln_how = 3; + nextline_how = nln_upper; } } } @@ -4843,6 +2666,9 @@ static void hsync_handler(void) 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) @@ -4853,195 +2679,101 @@ static void init_eventtab (void) eventtab[i].active = 0; eventtab[i].oldcycles = 0; } - copper_active = 0; + eventtab[ev_cia].handler = CIA_handler; - eventtab[ev_copper].handler = /* currprefs.copper_pos >= 0 ? do_copper_cheat : */ do_copper; eventtab[ev_hsync].handler = hsync_handler; eventtab[ev_hsync].evtime = maxhpos + cycles; eventtab[ev_hsync].active = 1; + eventtab[ev_copper].handler = copper_handler; + eventtab[ev_copper].active = 0; eventtab[ev_blitter].handler = blitter_handler; eventtab[ev_blitter].active = 0; - eventtab[ev_diskblk].handler = diskblk_handler; - eventtab[ev_diskblk].active = 0; - eventtab[ev_diskindex].handler = diskindex_handler; - eventtab[ev_diskindex].active = 0; -#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 && currprefs.produce_sound >= 2) { - eventtab[ev_sample].active = 1; - eventtab[ev_sample].evtime = sample_evtime; - } else { - eventtab[ev_sample].active = 0; - } -#endif + eventtab[ev_disk].handler = DISK_handler; + eventtab[ev_disk].active = 0; + events_schedule (); } void customreset (void) { - int i, maxl; - double native_lines_per_amiga_line; + int i; + int zero = 0; #ifdef HAVE_GETTIMEOFDAY struct timeval tv; #endif - for (i = 0; i < sizeof current_colors.color_regs / sizeof *current_colors.color_regs; i++) - current_colors.color_regs[i] = -1; + if ((currprefs.chipset_mask & CSMASK_AGA) == 0) { + for (i = 0; i < 32; i++) { + current_colors.color_regs_ecs[i] = 0; + current_colors.acolors[i] = xcolors[0]; + } + } else { + for (i = 0; i < 256; i++) { + current_colors.color_regs_aga[i] = 0; + current_colors.acolors[i] = CONVERT_RGB (zero); + } + } + + n_frames = 0; -#ifdef FRAME_RATE_HACK - did_reset = 1; - vsyncmintime = read_processor_time() + vsynctime; -#endif - inhibit_frame = 0; - frame_do_semup = 0; - uae_sem_init (&frame_sem, 0, 0); - uae_sem_init (&gui_sem, 0, 1); - uae_sem_init (&ihf_sem, 0, 1); expamem_reset (); - filesys_reset (); + + DISK_reset (); CIA_reset (); -#ifdef PICASSO96 - InitPicasso96 (); - picasso_on = 0; - picasso_requested_on = 0; - gfx_set_picasso_state (0); -#endif cycles = 0; - regs.spcflags &= SPCFLAG_BRK; - - lores_factor = currprefs.gfx_lores ? 1 : 2; - lores_shift = currprefs.gfx_lores ? 0 : 1; - sprite_width = currprefs.gfx_lores ? 16 : 32; + regs.spcflags &= SPCFLAG_BRK | SPCFLAG_MODE_CHANGE; vpos = 0; - is_lastline = 0; lof = 0; - max_diwstop = 0; - if (needmousehack()) { + if (needmousehack ()) { #if 0 - if (mousestate != follow_mouse) setfollow(); + mousehack_setfollow(); #else - if (mousestate != dont_care_mouse) setdontcare(); + mousehack_setdontcare(); #endif } else { mousestate = normal_mouse; } ievent_alive = 0; + timehack_alive = 0; clx_sprmask = 0xFF; clxdat = 0; - memset(sprarmed, 0, sizeof sprarmed); + /* Clear the armed flags of all sprites. */ + memset (spr, 0, sizeof spr); nr_armed = 0; - /*memset(blitcount, 0, sizeof(blitcount)); blitter debug */ - for (i = 0; i < (maxvpos+1)*2 + 1; i++) { - linestate[i] = LINE_UNDECIDED; - } - xlinebuffer = gfxvidinfo.bufmem; - 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; - audio_reset (); - bplcon4 = 0x11; /* Get AGA chipset into ECS compatibility mode */ bplcon3 = 0xC00; - init_eventtab (); - - if (native2amiga_line_map) - free (native2amiga_line_map); - if (amiga2aspect_line_map) - free (amiga2aspect_line_map); - - /* At least for this array the +1 is necessary. */ - amiga2aspect_line_map = (int *)malloc (sizeof (int) * (maxvpos+1)*2 + 1); - native2amiga_line_map = (int *)malloc (sizeof (int) * gfxvidinfo.height); - - if (currprefs.gfx_correct_aspect) - native_lines_per_amiga_line = ((double)gfxvidinfo.height - * (currprefs.gfx_lores ? 320 : 640) - / (currprefs.gfx_linedbl ? 512 : 256) - / gfxvidinfo.width); - else - native_lines_per_amiga_line = 1; - - maxl = (maxvpos+1) * (currprefs.gfx_linedbl ? 2 : 1); - min_ypos_for_screen = minfirstline << (currprefs.gfx_linedbl ? 1 : 0); - max_drawn_amiga_line = -1; - for (i = 0; i < maxl; i++) { - int v = (i - min_ypos_for_screen) * native_lines_per_amiga_line; - if (v >= gfxvidinfo.height && max_drawn_amiga_line == -1) - max_drawn_amiga_line = i-min_ypos_for_screen; - if (i < min_ypos_for_screen || v >= gfxvidinfo.height) - v = -1; - amiga2aspect_line_map[i] = v; - } - if (currprefs.gfx_linedbl) - max_drawn_amiga_line >>= 1; - - if (currprefs.gfx_ycenter && !(currprefs.gfx_correct_aspect)) { - extra_y_adjust = (gfxvidinfo.height - (maxvpos << (currprefs.gfx_linedbl ? 1 : 0))) >> 1; - if (extra_y_adjust < 0) - extra_y_adjust = 0; - } - - for (i = 0; i < gfxvidinfo.height; i++) - native2amiga_line_map[i] = -1; - - if (native_lines_per_amiga_line < 1) { - /* Must omit drawing some lines. */ - for (i = maxl-1; i > min_ypos_for_screen; i--) { - if (amiga2aspect_line_map[i] == amiga2aspect_line_map[i-1]) { - if (currprefs.gfx_linedbl && (i & 1) == 0 && amiga2aspect_line_map[i+1] != -1) { - /* If only the first line of a line pair would be omitted, - * omit the second one instead to avoid problems with line - * doubling. */ - amiga2aspect_line_map[i] = amiga2aspect_line_map[i+1]; - amiga2aspect_line_map[i+1] = -1; - } else - amiga2aspect_line_map[i] = -1; - } - } - } + new_beamcon0 = ntscmode ? 0x00 : 0x20; + init_hz (); - for (i = maxl-1; i >= min_ypos_for_screen; i--) { - int j; - if (amiga2aspect_line_map[i] == -1) - continue; - for (j = amiga2aspect_line_map[i]; j < gfxvidinfo.height && native2amiga_line_map[j] == -1; j++) - native2amiga_line_map[j] = i >> (currprefs.gfx_linedbl ? 1 : 0); - } + audio_reset (); - if (line_drawn == 0) - line_drawn = (char *)malloc (gfxvidinfo.height); - init_row_map(); + init_eventtab (); init_sprites (); init_hardware_frame (); - init_drawing_frame (); - last_redraw_point = 0; + reset_drawing (); + reset_decisions (); #ifdef HAVE_GETTIMEOFDAY - gettimeofday(&tv,NULL); + gettimeofday (&tv, NULL); seconds_base = tv.tv_sec; bogusframe = 1; #endif @@ -5049,15 +2781,17 @@ void customreset (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()); + 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) { - fprintf(stderr, "Average frame time: %d ms [frames: %d time: %d]\n", - frametime/timeframes, timeframes, frametime); + 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); } dump_audio_bench (); - /*for (i=0; i<256; i++) if (blitcount[i]) fprintf(stderr, "minterm %x = %d\n",i,blitcount[i]); blitter debug */ + /*for (i=0; i<256; i++) if (blitcount[i]) fprintf (stderr, "minterm %x = %d\n",i,blitcount[i]); blitter debug */ } int intlev (void) @@ -5074,62 +2808,73 @@ int intlev (void) return -1; } +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) { - int num; + uaecptr pos; #ifdef OS_WITHOUT_MEMORY_MANAGEMENT - 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)); + int 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)); } - delay_changes = xmalloc(max_delay_change * sizeof(struct delay_change)); + delay_changes = xmalloc (max_delay_change * sizeof (struct delay_change)); #endif - if (needmousehack()) - setfollow(); - init_regchanges (); + pos = here (); + + org (0xF0FF70); + calltrap (deftrap (mousehack_helper)); + dw (RTS); + + org (0xF0FFA0); + calltrap (deftrap (timehack_helper)); + dw (RTS); + + org (pos); + init_decisions (); - /* For now, the AGA stuff is broken in the dual playfield case. We encode - * sprites in dpf mode by ORing the pixel value with 0x80. To make dual - * playfield rendering easy, the lookup tables contain are made linear for - * values >= 128. That only works for OCS/ECS, though. */ - - 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; - if (plane2 > 0) plane2 += 8; - dblpf_ind1[num] = num >= 128 ? num & 0x7F : (plane1 == 0 ? plane2 : plane1); - dblpf_ind2[num] = num >= 128 ? num & 0x7F : (plane2 == 0 ? plane1 : plane2); - - lots_of_twos[num] = num == 0 ? 0 : 2; - linear_map_256[num] = num; - } - build_blitfilltable(); - gen_pfield_tables(); - native2amiga_line_map = 0; - amiga2aspect_line_map = 0; - line_drawn = 0; - -#ifdef SUPPORT_PENGUINS - init_comm_pipe (&drawing_pipe, 800, 5); - uae_sem_init (&drawing_lock, 0, 0); - start_penguin (drawing_penguin, 0, &our_penguin); - /*atexit(kill_drawing_penguin);*/ -#endif + gen_custom_tables (); + build_blitfilltable (); + + drawing_init (); + + mousestate = unknown_mouse; + + if (needmousehack ()) + mousehack_setfollow(); } /* Custom chip memory bank */ -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; +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 = { custom_lget, custom_wget, custom_bget, @@ -5139,12 +2884,12 @@ addrbank custom_bank = { 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(); @@ -5154,14 +2899,10 @@ uae_u32 REGPARAM2 custom_wget (uaecptr a case 0x012: return POT0DAT(); case 0x016: return POTGOR(); case 0x018: return SERDATR(); - case 0x01A: return DSKBYTR(); + case 0x01A: return DSKBYTR(current_hpos()); case 0x01C: return INTENAR(); case 0x01E: return INTREQR(); -#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; @@ -5178,14 +2919,13 @@ uae_u32 REGPARAM2 custom_lget (uaecptr a return ((uae_u32)custom_wget(addr & 0xfffe) << 16) | custom_wget((addr+2) & 0xfffe); } -void REGPARAM2 custom_wput (uaecptr addr, uae_u32 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 0x024: DSKLEN (value, current_hpos()); break; case 0x026: DSKDAT (value); break; case 0x02A: VPOSW (value); break; @@ -5229,10 +2969,10 @@ void REGPARAM2 custom_wput (uaecptr addr 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 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; @@ -5268,26 +3008,30 @@ void REGPARAM2 custom_wput (uaecptr addr 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 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 (value); break; - case 0x10A: BPL2MOD (value); break; + case 0x108: BPL1MOD (hpos, value); break; + case 0x10A: BPL2MOD (hpos, value); break; case 0x110: BPL1DAT (value); break; case 0x112: BPL2DAT (value); break; @@ -5295,6 +3039,8 @@ void REGPARAM2 custom_wput (uaecptr addr 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 0x180: case 0x182: case 0x184: case 0x186: case 0x188: case 0x18A: case 0x18C: case 0x18E: case 0x190: case 0x192: case 0x194: case 0x196: @@ -5302,58 +3048,65 @@ void REGPARAM2 custom_wput (uaecptr addr 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); + 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 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 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 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 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 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 0x1E4: DIWHIGH (hpos, value); break; + case 0x10C: BPLCON4 (hpos, value); break; + case 0x1FC: FMODE (value); break; } } -void REGPARAM2 custom_bput(uaecptr addr, uae_u32 value) +void REGPARAM2 custom_wput (uaecptr addr, uae_u32 value) +{ + 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 REGPARAM2 custom_bput (uaecptr addr, uae_u32 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); + custom_wput (addr, rval); if (!warned) write_log ("Byte put to custom register.\n"), warned++; } void REGPARAM2 custom_lput(uaecptr addr, uae_u32 value) { - custom_wput(addr & 0xfffe, value >> 16); - custom_wput((addr+2) & 0xfffe, (uae_u16)value); + custom_wput (addr & 0xfffe, value >> 16); + custom_wput ((addr + 2) & 0xfffe, (uae_u16)value); }