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