|
|
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.20! root 6: * Copyright 1995-2002 Bernd Schmidt
1.1.1.2 root 7: * Copyright 1995 Alessandro Bissacco
1.1.1.20! root 8: * Copyright 2000-2002 Toni Wilen
1.1 root 9: */
10:
11: #include "sysconfig.h"
12: #include "sysdeps.h"
13:
14: #include <ctype.h>
15: #include <assert.h>
16:
17: #include "config.h"
18: #include "options.h"
1.1.1.16 root 19: #include "threaddep/thread.h"
1.1.1.3 root 20: #include "uae.h"
21: #include "gensound.h"
22: #include "sounddep/sound.h"
1.1 root 23: #include "events.h"
24: #include "memory.h"
25: #include "custom.h"
26: #include "newcpu.h"
27: #include "cia.h"
28: #include "disk.h"
29: #include "blitter.h"
30: #include "xwin.h"
1.1.1.3 root 31: #include "joystick.h"
32: #include "audio.h"
1.1 root 33: #include "keybuf.h"
34: #include "serial.h"
1.1.1.2 root 35: #include "osemu.h"
1.1.1.3 root 36: #include "autoconf.h"
37: #include "gui.h"
38: #include "picasso96.h"
1.1.1.4 root 39: #include "drawing.h"
1.1.1.15 root 40: #include "savestate.h"
1.1.1.2 root 41:
1.1.1.20! root 42: #define SPRITE_COLLISIONS
! 43:
! 44: static uae_u16 last_custom_value;
! 45:
1.1.1.6 root 46: static unsigned int n_consecutive_skipped = 0;
47: static unsigned int total_skipped = 0;
48:
1.1.1.3 root 49: /* Mouse and joystick emulation */
1.1.1.2 root 50:
1.1.1.3 root 51: int buttonstate[3];
52: static int mouse_x, mouse_y;
53: int joy0button, joy1button;
54: unsigned int joy0dir, joy1dir;
55:
56: /* Events */
1.1 root 57:
1.1.1.14 root 58: unsigned long int currcycle, nextevent, is_lastline;
1.1.1.4 root 59: static int rpt_did_reset;
1.1.1.2 root 60: struct ev eventtab[ev_max];
61:
1.1.1.3 root 62: frame_time_t vsynctime, vsyncmintime;
63:
1.1.1.4 root 64: static int vpos;
65: static uae_u16 lof;
66: static int next_lineno;
67: static enum nln_how nextline_how;
68: static int lof_changed = 0;
1.1 root 69:
1.1.1.3 root 70: static uae_u32 sprtaba[256],sprtabb[256];
1.1.1.13 root 71: static uae_u32 sprite_ab_merge[256];
72: /* Tables for collision detection. */
73: static uae_u32 sprclx[16], clxmask[16];
1.1.1.3 root 74:
1.1.1.2 root 75: /*
76: * Hardware registers of all sorts.
77: */
1.1 root 78:
1.1.1.4 root 79: static void custom_wput_1 (int, uaecptr, uae_u32) REGPARAM;
80:
1.1.1.3 root 81: static uae_u16 cregs[256];
1.1 root 82:
1.1.1.3 root 83: uae_u16 intena,intreq;
84: uae_u16 dmacon;
85: uae_u16 adkcon; /* used by audio code */
1.1 root 86:
1.1.1.3 root 87: static uae_u32 cop1lc,cop2lc,copcon;
1.1.1.7 root 88:
89: int maxhpos = MAXHPOS_PAL;
90: int maxvpos = MAXVPOS_PAL;
91: int minfirstline = MINFIRSTLINE_PAL;
92: int vblank_endline = VBLANK_ENDLINE_PAL;
93: int vblank_hz = VBLANK_HZ_PAL;
94: unsigned long syncbase;
95: static int fmode;
96: static unsigned int beamcon0, new_beamcon0;
97:
1.1.1.15 root 98: #define MAX_SPRITES 8
1.1 root 99:
1.1.1.2 root 100: /* This is but an educated guess. It seems to be correct, but this stuff
101: * isn't documented well. */
1.1.1.20! root 102: enum sprstate { SPR_restart, SPR_waiting_start, SPR_waiting_stop };
1.1.1.10 root 103:
104: struct sprite {
105: uaecptr pt;
106: int xpos;
107: int vstart;
108: int vstop;
109: int armed;
110: enum sprstate state;
111: };
112:
113: static struct sprite spr[8];
114:
1.1.1.20! root 115: static int sprite_vblank_endline = 25;
1.1 root 116:
1.1.1.15 root 117: static unsigned int sprctl[MAX_SPRITES], sprpos[MAX_SPRITES];
118: static uae_u16 sprdata[MAX_SPRITES][4], sprdatb[MAX_SPRITES][4];
1.1.1.10 root 119: static int sprite_last_drawn_at[MAX_SPRITES];
1.1.1.7 root 120: static int last_sprite_point, nr_armed;
1.1.1.15 root 121: static int sprite_width, sprres, sprite_buffer_res;
1.1.1.7 root 122:
1.1.1.6 root 123: static uae_u32 bpl1dat, bpl2dat, bpl3dat, bpl4dat, bpl5dat, bpl6dat, bpl7dat, bpl8dat;
124: static uae_s16 bpl1mod, bpl2mod;
1.1 root 125:
1.1.1.3 root 126: static uaecptr bplpt[8];
1.1.1.10 root 127: uae_u8 *real_bplpt[8];
1.1.1.15 root 128: /* Used as a debugging aid, to offset any bitplane temporarily. */
1.1.1.16 root 129: int bpl_off[8];
1.1 root 130:
131: /*static int blitcount[256]; blitter debug */
132:
1.1.1.2 root 133: static struct color_entry current_colors;
1.1.1.6 root 134: static unsigned int bplcon0, bplcon1, bplcon2, bplcon3, bplcon4;
1.1.1.4 root 135: static unsigned int diwstrt, diwstop, diwhigh;
136: static int diwhigh_written;
137: static unsigned int ddfstrt, ddfstop;
1.1.1.7 root 138:
1.1.1.4 root 139: /* The display and data fetch windows */
1.1 root 140:
1.1.1.4 root 141: enum diw_states
142: {
143: DIW_waiting_start, DIW_waiting_stop
144: };
1.1 root 145:
1.1.1.13 root 146: static int plffirstline, plflastline;
147: static int plfstrt, plfstop;
148: static int last_diw_pix_hpos, last_ddf_pix_hpos, last_decide_line_hpos;
149: static int last_fetch_hpos, last_sprite_hpos;
1.1.1.6 root 150: int diwfirstword, diwlastword;
1.1.1.4 root 151: static enum diw_states diwstate, hdiwstate;
1.1 root 152:
1.1.1.4 root 153: /* Sprite collisions */
1.1.1.14 root 154: static unsigned int clxdat, clxcon, clxcon2, clxcon_bpl_enable, clxcon_bpl_match;
155: static int clx_sprmask;
1.1.1.4 root 156:
157: enum copper_states {
158: COP_stop,
1.1.1.15 root 159: COP_read1_in2,
160: COP_read1_wr_in4,
161: COP_read1_wr_in2,
162: COP_read1,
163: COP_read2_wr_in2,
164: COP_read2,
1.1.1.4 root 165: COP_bltwait,
1.1.1.15 root 166: COP_wait_in4,
167: COP_wait_in2,
168: COP_skip_in4,
169: COP_skip_in2,
170: COP_wait1,
171: COP_wait
1.1.1.4 root 172: };
173:
174: struct copper {
175: /* The current instruction words. */
176: unsigned int i1, i2;
1.1.1.15 root 177: unsigned int saved_i1, saved_i2;
1.1.1.4 root 178: enum copper_states state;
179: /* Instruction pointer. */
1.1.1.15 root 180: uaecptr ip, saved_ip;
1.1.1.10 root 181: int hpos, vpos;
1.1.1.4 root 182: unsigned int ignore_next;
1.1.1.10 root 183: int vcmp, hcmp;
1.1.1.15 root 184:
185: /* When we schedule a copper event, knowing a few things about the future
186: of the copper list can reduce the number of sync_with_cpu calls
187: dramatically. */
188: unsigned int first_sync;
189: unsigned int regtypes_modified;
1.1.1.4 root 190: };
191:
1.1.1.15 root 192: #define REGTYPE_NONE 0
193: #define REGTYPE_COLOR 1
194: #define REGTYPE_SPRITE 2
195: #define REGTYPE_PLANE 4
196: #define REGTYPE_BLITTER 8
197: #define REGTYPE_JOYPORT 16
198: #define REGTYPE_DISK 32
199: #define REGTYPE_POS 64
200: #define REGTYPE_AUDIO 128
201:
202: #define REGTYPE_ALL 255
203: /* Always set in regtypes_modified, to enable a forced update when things like
204: DMACON, BPLCON0, COPJMPx get written. */
205: #define REGTYPE_FORCE 256
206:
207:
208: static unsigned int regtypes[512];
209:
1.1.1.4 root 210: static struct copper cop_state;
1.1.1.10 root 211: static int copper_enabled_thisline;
212: static int cop_min_waittime;
1.1 root 213:
214: /*
215: * Statistics
216: */
217:
1.1.1.2 root 218: /* Used also by bebox.cpp */
1.1.1.6 root 219: unsigned long int msecs = 0, frametime = 0, lastframetime = 0, timeframes = 0;
1.1 root 220: static unsigned long int seconds_base;
221: int bogusframe;
1.1.1.12 root 222: int n_frames;
1.1.1.4 root 223:
1.1.1.15 root 224: #define DEBUG_COPPER 0
225: #if DEBUG_COPPER
226: /* 10000 isn't enough! */
227: #define NR_COPPER_RECORDS 40000
228: #else
229: #define NR_COPPER_RECORDS 1
230: #endif
231:
232: /* Record copper activity for the debugger. */
233: struct cop_record
234: {
235: int hpos, vpos;
236: uaecptr addr;
237: };
238: static struct cop_record cop_record[2][NR_COPPER_RECORDS];
239: static int nr_cop_records[2];
240: static int curr_cop_set;
241:
242: /* Recording of custom chip register changes. */
1.1.1.4 root 243: static int current_change_set;
244:
245: #ifdef OS_WITHOUT_MEMORY_MANAGEMENT
246: /* sam: Those arrays uses around 7Mb of BSS... That seems */
247: /* too much for AmigaDOS (uae crashes as soon as one loads */
248: /* it. So I use a different strategy here (realloc the */
249: /* arrays when needed. That strategy might be usefull for */
250: /* computer with low memory. */
1.1.1.13 root 251: struct sprite_entry *sprite_entries[2];
1.1.1.4 root 252: struct color_change *color_changes[2];
1.1.1.13 root 253: static int max_sprite_entry = 400;
254: static int delta_sprite_entry = 0;
1.1.1.4 root 255: static int max_color_change = 400;
256: static int delta_color_change = 0;
257: #else
1.1.1.13 root 258: struct sprite_entry sprite_entries[2][MAX_SPR_PIXELS / 16];
1.1.1.4 root 259: struct color_change color_changes[2][MAX_REG_CHANGE];
260: #endif
261:
1.1.1.7 root 262: struct decision line_decisions[2 * (MAXVPOS + 1) + 1];
263: struct draw_info line_drawinfo[2][2 * (MAXVPOS + 1) + 1];
264: struct color_entry color_tables[2][(MAXVPOS + 1) * 2];
1.1.1.4 root 265:
1.1.1.13 root 266: static int next_sprite_entry = 0;
267: static int prev_next_sprite_entry;
268: static int next_sprite_forced = 1;
269:
270: struct sprite_entry *curr_sprite_entries, *prev_sprite_entries;
1.1.1.4 root 271: struct color_change *curr_color_changes, *prev_color_changes;
272: struct draw_info *curr_drawinfo, *prev_drawinfo;
273: struct color_entry *curr_color_tables, *prev_color_tables;
274:
1.1.1.13 root 275: static int next_color_change;
1.1.1.4 root 276: static int next_color_entry, remembered_color_entry;
277: static int color_src_match, color_dest_match, color_compare_result;
278:
1.1.1.13 root 279: static uae_u32 thisline_changed;
1.1.1.4 root 280:
281: #ifdef SMART_UPDATE
1.1.1.5 root 282: #define MARK_LINE_CHANGED do { thisline_changed = 1; } while (0)
1.1.1.4 root 283: #else
1.1.1.5 root 284: #define MARK_LINE_CHANGED do { ; } while (0)
1.1.1.4 root 285: #endif
286:
287: static struct decision thisline_decision;
1.1.1.13 root 288: static int passed_plfstop, fetch_cycle;
289:
290: enum fetchstate {
291: fetch_not_started,
292: fetch_started,
293: fetch_was_plane0
294: } fetch_state;
1.1.1.4 root 295:
1.1 root 296: /*
297: * helper functions
298: */
299:
1.1.1.15 root 300: uae_u32 get_copper_address (int copno)
301: {
302: switch (copno) {
303: case 1: return cop1lc;
304: case 2: return cop2lc;
305: default: return 0;
306: }
307: }
308:
309: STATIC_INLINE void record_copper (uaecptr addr, int hpos, int vpos)
310: {
311: #if DEBUG_COPPER
312: int t = nr_cop_records[curr_cop_set];
313: if (t < NR_COPPER_RECORDS) {
314: cop_record[curr_cop_set][t].addr = addr;
315: cop_record[curr_cop_set][t].hpos = hpos;
316: cop_record[curr_cop_set][t].vpos = vpos;
317: nr_cop_records[curr_cop_set] = t + 1;
318: }
319: #endif
320: }
321:
322: int find_copper_record (uaecptr addr, int *phpos, int *pvpos)
323: {
324: int s = curr_cop_set ^ 1;
325: int t = nr_cop_records[s];
326: int i;
327: for (i = 0; i < t; i++) {
328: if (cop_record[s][i].addr == addr) {
329: *phpos = cop_record[s][i].hpos;
330: *pvpos = cop_record[s][i].vpos;
331: return 1;
332: }
333: }
334: return 0;
335: }
336:
1.1.1.4 root 337: int rpt_available = 0;
1.1.1.3 root 338:
1.1.1.4 root 339: void reset_frame_rate_hack (void)
340: {
341: if (currprefs.m68k_speed != -1)
342: return;
343:
344: if (! rpt_available) {
345: currprefs.m68k_speed = 0;
346: return;
347: }
1.1.1.3 root 348:
1.1.1.4 root 349: rpt_did_reset = 1;
350: is_lastline = 0;
351: vsyncmintime = read_processor_time() + vsynctime;
352: write_log ("Resetting frame rate hack\n");
353: }
1.1 root 354:
1.1.1.3 root 355: void check_prefs_changed_custom (void)
356: {
1.1.1.7 root 357: currprefs.gfx_framerate = changed_prefs.gfx_framerate;
1.1.1.3 root 358: /* Not really the right place... */
1.1.1.6 root 359: if (currprefs.jport0 != changed_prefs.jport0
360: || currprefs.jport1 != changed_prefs.jport1) {
361: currprefs.jport0 = changed_prefs.jport0;
362: currprefs.jport1 = changed_prefs.jport1;
1.1.1.3 root 363: joystick_setting_changed ();
1.1 root 364: }
1.1.1.3 root 365: currprefs.immediate_blits = changed_prefs.immediate_blits;
366: currprefs.blits_32bit_enabled = changed_prefs.blits_32bit_enabled;
1.1.1.15 root 367: currprefs.collision_level = changed_prefs.collision_level;
368: currprefs.fast_copper = changed_prefs.fast_copper;
1.1 root 369: }
370:
1.1.1.8 root 371: STATIC_INLINE void setclr (uae_u16 *p, uae_u16 val)
1.1 root 372: {
1.1.1.6 root 373: if (val & 0x8000)
1.1 root 374: *p |= val & 0x7FFF;
1.1.1.6 root 375: else
1.1 root 376: *p &= ~val;
377: }
378:
1.1.1.3 root 379: __inline__ int current_hpos (void)
1.1 root 380: {
1.1.1.14 root 381: return (get_cycles () - eventtab[ev_hsync].oldcycles) / CYCLE_UNIT;
1.1 root 382: }
383:
1.1.1.8 root 384: STATIC_INLINE uae_u8 *pfield_xlateptr (uaecptr plpt, int bytecount)
1.1.1.2 root 385: {
1.1.1.4 root 386: if (!chipmem_bank.check (plpt, bytecount)) {
1.1.1.2 root 387: static int count = 0;
1.1.1.3 root 388: if (!count)
389: count++, write_log ("Warning: Bad playfield pointer\n");
1.1.1.2 root 390: return NULL;
391: }
1.1.1.4 root 392: return chipmem_bank.xlateaddr (plpt);
1.1.1.2 root 393: }
394:
1.1.1.8 root 395: STATIC_INLINE void docols (struct color_entry *colentry)
1.1.1.3 root 396: {
397: int i;
1.1.1.11 root 398:
399: if (currprefs.chipset_mask & CSMASK_AGA) {
1.1.1.20! root 400: for (i = 0; i < 256; i++) {
1.1.1.11 root 401: int v = color_reg_get (colentry, i);
1.1.1.14 root 402: if (v < 0 || v > 16777215)
1.1.1.11 root 403: continue;
404: colentry->acolors[i] = CONVERT_RGB (v);
405: }
406: } else {
1.1.1.20! root 407: for (i = 0; i < 32; i++) {
1.1.1.11 root 408: int v = color_reg_get (colentry, i);
409: if (v < 0 || v > 4095)
410: continue;
411: colentry->acolors[i] = xcolors[v];
412: }
1.1.1.3 root 413: }
414: }
415:
416: void notice_new_xcolors (void)
417: {
418: int i;
419:
420: docols(¤t_colors);
1.1.1.4 root 421: /* docols(&colors_for_drawing);*/
1.1.1.7 root 422: for (i = 0; i < (MAXVPOS + 1)*2; i++) {
1.1.1.3 root 423: docols(color_tables[0]+i);
424: docols(color_tables[1]+i);
425: }
426: }
427:
1.1.1.20! root 428: static void do_sprites (int currhp);
1.1.1.2 root 429:
430: static void remember_ctable (void)
431: {
432: if (remembered_color_entry == -1) {
433: /* The colors changed since we last recorded a color map. Record a
434: * new one. */
1.1.1.11 root 435: color_reg_cpy (curr_color_tables + next_color_entry, ¤t_colors);
1.1.1.2 root 436: remembered_color_entry = next_color_entry++;
437: }
438: thisline_decision.ctable = remembered_color_entry;
439: if (color_src_match == -1 || color_dest_match != remembered_color_entry
440: || line_decisions[next_lineno].ctable != color_src_match)
441: {
442: /* The remembered comparison didn't help us - need to compare again. */
443: int oldctable = line_decisions[next_lineno].ctable;
444: int changed = 0;
445:
1.1.1.3 root 446: if (oldctable == -1) {
1.1.1.2 root 447: changed = 1;
448: color_src_match = color_dest_match = -1;
449: } else {
1.1.1.11 root 450: color_compare_result = color_reg_cmp (&prev_color_tables[oldctable], ¤t_colors) != 0;
1.1.1.3 root 451: if (color_compare_result)
452: changed = 1;
453: color_src_match = oldctable;
1.1.1.2 root 454: color_dest_match = remembered_color_entry;
1.1.1.3 root 455: }
1.1.1.5 root 456: thisline_changed |= changed;
1.1.1.3 root 457: } else {
458: /* We know the result of the comparison */
459: if (color_compare_result)
1.1.1.5 root 460: thisline_changed = 1;
1.1.1.3 root 461: }
462: }
463:
464: static void remember_ctable_for_border (void)
465: {
466: remember_ctable ();
1.1.1.2 root 467: }
468:
1.1.1.3 root 469: /* Called to determine the state of the horizontal display window state
470: * machine at the current position. It might have changed since we last
471: * checked. */
1.1.1.4 root 472: static void decide_diw (int hpos)
1.1.1.2 root 473: {
1.1.1.13 root 474: int pix_hpos = coord_diw_to_window_x (hpos * 2);
1.1.1.3 root 475: if (hdiwstate == DIW_waiting_start && thisline_decision.diwfirstword == -1
1.1.1.9 root 476: && pix_hpos >= diwfirstword && last_diw_pix_hpos < diwfirstword)
1.1.1.3 root 477: {
1.1.1.13 root 478: thisline_decision.diwfirstword = diwfirstword < 0 ? 0 : diwfirstword;
1.1.1.3 root 479: hdiwstate = DIW_waiting_stop;
1.1.1.2 root 480: thisline_decision.diwlastword = -1;
481: }
1.1.1.3 root 482: if (hdiwstate == DIW_waiting_stop && thisline_decision.diwlastword == -1
1.1.1.9 root 483: && pix_hpos >= diwlastword && last_diw_pix_hpos < diwlastword)
1.1.1.3 root 484: {
1.1.1.13 root 485: thisline_decision.diwlastword = diwlastword < 0 ? 0 : diwlastword;
1.1.1.3 root 486: hdiwstate = DIW_waiting_start;
1.1.1.2 root 487: }
1.1.1.9 root 488: last_diw_pix_hpos = pix_hpos;
1.1.1.2 root 489: }
490:
1.1.1.13 root 491: /* The HRM says 0xD8, but that can't work... */
492: #define HARD_DDF_STOP (0xD4)
1.1.1.2 root 493:
1.1.1.13 root 494: static void finish_playfield_line (void)
495: {
1.1.1.15 root 496: int m1, m2;
497:
1.1.1.2 root 498: /* The latter condition might be able to happen in interlaced frames. */
499: if (vpos >= minfirstline && (thisframe_first_drawn_line == -1 || vpos < thisframe_first_drawn_line))
500: thisframe_first_drawn_line = vpos;
501: thisframe_last_drawn_line = vpos;
502:
1.1.1.15 root 503: if ((currprefs.chipset_mask & CSMASK_AGA) && (fmode & 0x4000)) {
504: if (((diwstrt >> 8) ^ vpos) & 1)
505: m1 = m2 = bpl2mod;
506: else
507: m1 = m2 = bpl1mod;
508: } else {
509: m1 = bpl1mod;
510: m2 = bpl2mod;
511: }
512:
1.1.1.13 root 513: if (dmaen (DMA_BITPLANE))
1.1.1.16 root 514: switch (GET_PLANES (bplcon0)) {
1.1.1.15 root 515: case 8: bplpt[7] += m2;
516: case 7: bplpt[6] += m1;
517: case 6: bplpt[5] += m2;
518: case 5: bplpt[4] += m1;
519: case 4: bplpt[3] += m2;
520: case 3: bplpt[2] += m1;
521: case 2: bplpt[1] += m2;
522: case 1: bplpt[0] += m1;
1.1.1.13 root 523: }
1.1.1.2 root 524:
525: /* These are for comparison. */
526: thisline_decision.bplcon0 = bplcon0;
527: thisline_decision.bplcon2 = bplcon2;
1.1.1.14 root 528: thisline_decision.bplcon3 = bplcon3;
1.1.1.2 root 529: thisline_decision.bplcon4 = bplcon4;
530:
531: #ifdef SMART_UPDATE
1.1.1.13 root 532: if (line_decisions[next_lineno].plflinelen != thisline_decision.plflinelen
533: || line_decisions[next_lineno].plfleft != thisline_decision.plfleft
1.1.1.2 root 534: || line_decisions[next_lineno].bplcon0 != thisline_decision.bplcon0
535: || line_decisions[next_lineno].bplcon2 != thisline_decision.bplcon2
1.1.1.14 root 536: || line_decisions[next_lineno].bplcon3 != thisline_decision.bplcon3
1.1.1.2 root 537: || line_decisions[next_lineno].bplcon4 != thisline_decision.bplcon4
538: )
539: #endif /* SMART_UPDATE */
1.1.1.5 root 540: thisline_changed = 1;
1.1.1.2 root 541: }
542:
1.1.1.15 root 543: static int fetchmode;
1.1.1.14 root 544:
1.1.1.15 root 545: /* The fetch unit mainly controls ddf stop. It's the number of cycles that
546: are contained in an indivisible block during which ddf is active. E.g.
547: if DDF starts at 0x30, and fetchunit is 8, then possible DDF stops are
548: 0x30 + n * 8. */
549: static int fetchunit, fetchunit_mask;
550: /* The delay before fetching the same bitplane again. Can be larger than
551: the number of bitplanes; in that case there are additional empty cycles
552: with no data fetch (this happens for high fetchmodes and low
553: resolutions). */
1.1.1.14 root 554: static int fetchstart, fetchstart_shift, fetchstart_mask;
1.1.1.15 root 555: /* fm_maxplane holds the maximum number of planes possible with the current
556: fetch mode. This selects the cycle diagram:
557: 8 planes: 73516240
558: 4 planes: 3120
559: 2 planes: 10. */
1.1.1.14 root 560: static int fm_maxplane, fm_maxplane_shift;
561:
1.1.1.15 root 562: /* The corresponding values, by fetchmode and display resolution. */
563: static int fetchunits[] = { 8,8,8,0, 16,8,8,0, 32,16,8,0 };
564: static int fetchstarts[] = { 3,2,1,0, 4,3,2,0, 5,4,3,0 };
565: static int fm_maxplanes[] = { 3,2,1,0, 3,3,2,0, 3,3,3,0 };
566:
1.1.1.16 root 567: static int cycle_diagram_table[3][3][9][32];
568: static int *curr_diagram;
569: static int cycle_sequences[3*8] = { 2,1,2,1,2,1,2,1, 4,2,3,1,4,2,3,1, 8,4,6,2,7,3,5,1 };
570:
571: static void debug_cycle_diagram(void)
572: {
573: int fm, res, planes, cycle, v;
574: char aa;
575:
576: for (fm = 0; fm < 3; fm++) {
577: write_log ("FMODE %d\n=======\n", fm);
578: for (res = 0; res <= 2; res++) {
579: for (planes = 0; planes <= 8; planes++) {
580: write_log("%d: ",planes);
581: for (cycle = 0; cycle < 32; cycle++) {
582: v=cycle_diagram_table[fm][res][planes][cycle];
583: if (v==0) aa='-'; else if(v>0) aa='1'; else aa='X';
584: write_log("%c",aa);
585: }
586: write_log("\n");
587: }
588: write_log("\n");
589: }
590: }
591: fm=0;
592: }
593:
594: static void create_cycle_diagram_table(void)
595: {
596: int fm, res, cycle, planes, v;
597: int fetch_start, max_planes;
598: int *cycle_sequence;
599:
600: for (fm = 0; fm <= 2; fm++) {
601: for (res = 0; res <= 2; res++) {
602: max_planes = fm_maxplanes[fm * 4 + res];
603: fetch_start = 1 << fetchstarts[fm * 4 + res];
604: cycle_sequence = &cycle_sequences[(max_planes - 1) * 8];
605: max_planes = 1 << max_planes;
606: for (planes = 0; planes <= 8; planes++) {
607: for (cycle = 0; cycle < 32; cycle++)
608: cycle_diagram_table[fm][res][planes][cycle] = -1;
609: if (planes <= max_planes) {
610: for (cycle = 0; cycle < fetch_start; cycle++) {
611: if (cycle < max_planes && planes >= cycle_sequence[cycle & 7]) {
612: v = 1;
613: } else {
614: v = 0;
615: }
616: cycle_diagram_table[fm][res][planes][cycle] = v;
617: }
618: }
619: }
620: }
621: }
622: #if 0
623: debug_cycle_diagram ();
624: #endif
625: }
626:
627:
1.1.1.15 root 628: /* Used by the copper. */
1.1.1.13 root 629: static int estimated_last_fetch_cycle;
1.1.1.15 root 630: static int cycle_diagram_shift;
1.1.1.4 root 631:
1.1.1.13 root 632: static void estimate_last_fetch_cycle (int hpos)
1.1.1.2 root 633: {
1.1.1.14 root 634: int fetchunit = fetchunits[fetchmode * 4 + GET_RES (bplcon0)];
635:
1.1.1.13 root 636: if (! passed_plfstop) {
637: int stop = plfstop < hpos || plfstop > HARD_DDF_STOP ? HARD_DDF_STOP : plfstop;
638: /* We know that fetching is up-to-date up until hpos, so we can use fetch_cycle. */
639: int fetch_cycle_at_stop = fetch_cycle + (stop - hpos);
1.1.1.14 root 640: int starting_last_block_at = (fetch_cycle_at_stop + fetchunit - 1) & ~(fetchunit - 1);
1.1.1.13 root 641:
1.1.1.14 root 642: estimated_last_fetch_cycle = hpos + (starting_last_block_at - fetch_cycle) + fetchunit;
1.1.1.13 root 643: } else {
1.1.1.14 root 644: int starting_last_block_at = (fetch_cycle + fetchunit - 1) & ~(fetchunit - 1);
1.1.1.13 root 645: if (passed_plfstop == 2)
1.1.1.14 root 646: starting_last_block_at -= fetchunit;
1.1.1.13 root 647:
1.1.1.14 root 648: estimated_last_fetch_cycle = hpos + (starting_last_block_at - fetch_cycle) + fetchunit;
1.1.1.13 root 649: }
1.1.1.4 root 650: }
651:
1.1.1.14 root 652: static uae_u32 outword[MAX_PLANES];
1.1.1.13 root 653: static int out_nbits, out_offs;
1.1.1.14 root 654: static uae_u32 todisplay[MAX_PLANES][4];
655: static uae_u32 fetched[MAX_PLANES];
656: static uae_u32 fetched_aga0[MAX_PLANES];
657: static uae_u32 fetched_aga1[MAX_PLANES];
1.1.1.13 root 658:
659: /* Expansions from bplcon0/bplcon1. */
1.1.1.14 root 660: static int toscr_res, toscr_delay1, toscr_delay2, toscr_nr_planes, fetchwidth;
1.1.1.13 root 661:
1.1.1.14 root 662: /* The number of bits left from the last fetched words.
663: This is an optimization - conceptually, we have to make sure the result is
664: the same as if toscr is called in each clock cycle. However, to speed this
665: up, we accumulate display data; this variable keeps track of how much.
666: Thus, once we do call toscr_nbits (which happens at least every 16 bits),
667: we can do more work at once. */
1.1.1.13 root 668: static int toscr_nbits;
669:
1.1.1.14 root 670: static int delayoffset;
671:
672: STATIC_INLINE void compute_delay_offset (int hpos)
1.1.1.4 root 673: {
1.1.1.14 root 674: /* this fixes most horizontal scrolling jerkyness but can't be correct */
1.1.1.15 root 675: delayoffset = ((hpos - fm_maxplane - 0x18) & fetchstart_mask) << 1;
1.1.1.14 root 676: delayoffset &= ~7;
1.1.1.16 root 677: if (delayoffset & 8)
678: delayoffset = 8;
679: else if (delayoffset & 16)
680: delayoffset = 16;
681: else if (delayoffset & 32)
682: delayoffset = 32;
683: else
684: delayoffset = 0;
1.1.1.13 root 685: }
1.1.1.9 root 686:
1.1.1.15 root 687: static void expand_fmodes (void)
1.1.1.14 root 688: {
689: int res = GET_RES(bplcon0);
690: int fm = fetchmode;
691: fetchunit = fetchunits[fm * 4 + res];
692: fetchunit_mask = fetchunit - 1;
693: fetchstart_shift = fetchstarts[fm * 4 + res];
694: fetchstart = 1 << fetchstart_shift;
695: fetchstart_mask = fetchstart - 1;
696: fm_maxplane_shift = fm_maxplanes[fm * 4 + res];
697: fm_maxplane = 1 << fm_maxplane_shift;
1.1.1.13 root 698: }
699:
1.1.1.15 root 700: static int maxplanes_ocs[]={ 6,4,0,0 };
701: static int maxplanes_ecs[]={ 6,4,2,0 };
702: static int maxplanes_aga[]={ 8,4,2,0, 8,8,4,0, 8,8,8,0 };
703:
1.1.1.13 root 704: /* Expand bplcon0/bplcon1 into the toscr_xxx variables. */
1.1.1.15 root 705: static void compute_toscr_delay_1 (void)
1.1.1.13 root 706: {
707: int delay1 = (bplcon1 & 0x0f) | ((bplcon1 & 0x0c00) >> 6);
708: int delay2 = ((bplcon1 >> 4) & 0x0f) | (((bplcon1 >> 4) & 0x0c00) >> 6);
709: int delaymask;
1.1.1.14 root 710: int fetchwidth = 16 << fetchmode;
1.1.1.13 root 711:
1.1.1.14 root 712: delay1 += delayoffset;
713: delay2 += delayoffset;
714: delaymask = (fetchwidth - 1) >> toscr_res;
1.1.1.13 root 715: toscr_delay1 = (delay1 & delaymask) << toscr_res;
716: toscr_delay2 = (delay2 & delaymask) << toscr_res;
1.1.1.15 root 717: }
718:
719: static void compute_toscr_delay (int hpos)
720: {
721: int v = bplcon0;
722: int *planes;
723:
724: if (currprefs.chipset_mask & CSMASK_AGA)
725: planes = maxplanes_aga;
726: else if (! (currprefs.chipset_mask & CSMASK_ECS_DENISE))
727: planes = maxplanes_ocs;
728: else
729: planes = maxplanes_ecs;
730: /* Disable bitplane DMA if planes > maxplanes. This is needed e.g. by the
731: Sanity WOC demo (at the "Party Effect"). */
732: if (GET_PLANES(v) > planes[fetchmode*4 + GET_RES (v)])
733: v &= ~0x7010;
734: toscr_res = GET_RES (v);
735:
736: toscr_nr_planes = GET_PLANES (v);
737:
738: compute_toscr_delay_1 ();
739: }
740:
741: STATIC_INLINE void maybe_first_bpl1dat (int hpos)
742: {
743: if (thisline_decision.plfleft == -1) {
744: thisline_decision.plfleft = hpos;
745: compute_delay_offset (hpos);
746: compute_toscr_delay_1 ();
747: }
748: }
1.1.1.13 root 749:
1.1.1.15 root 750: STATIC_INLINE void fetch (int nr, int fm)
751: {
752: uaecptr p;
753: if (nr >= toscr_nr_planes)
754: return;
1.1.1.16 root 755: p = bplpt[nr] + bpl_off[nr];
1.1.1.15 root 756: switch (fm) {
757: case 0:
758: fetched[nr] = chipmem_wget (p);
759: bplpt[nr] += 2;
760: break;
761: case 1:
762: fetched_aga0[nr] = chipmem_lget (p);
763: bplpt[nr] += 4;
764: break;
765: case 2:
766: fetched_aga1[nr] = chipmem_lget (p);
767: fetched_aga0[nr] = chipmem_lget (p + 4);
768: bplpt[nr] += 8;
769: break;
770: }
771: if (nr == 0)
772: fetch_state = fetch_was_plane0;
1.1.1.13 root 773: }
774:
775: static void clear_fetchbuffer (uae_u32 *ptr, int nwords)
776: {
777: int i;
778:
779: if (! thisline_changed)
780: for (i = 0; i < nwords; i++)
781: if (ptr[i]) {
782: thisline_changed = 1;
783: break;
1.1.1.4 root 784: }
1.1.1.13 root 785:
786: memset (ptr, 0, nwords * 4);
787: }
788:
789: static void update_toscr_planes (void)
790: {
791: if (toscr_nr_planes > thisline_decision.nr_planes) {
792: int j;
793: for (j = thisline_decision.nr_planes; j < toscr_nr_planes; j++)
794: clear_fetchbuffer ((uae_u32 *)(line_data[next_lineno] + 2 * MAX_WORDS_PER_LINE * j), out_offs);
795: #if 0
796: if (thisline_decision.nr_planes > 0)
797: printf ("Planes from %d to %d\n", thisline_decision.nr_planes, toscr_nr_planes);
798: #endif
799: thisline_decision.nr_planes = toscr_nr_planes;
1.1.1.4 root 800: }
801: }
1.1.1.2 root 802:
1.1.1.14 root 803: STATIC_INLINE void toscr_3_ecs (int nbits)
1.1.1.7 root 804: {
1.1.1.13 root 805: int delay1 = toscr_delay1;
806: int delay2 = toscr_delay2;
807: int i;
808: uae_u32 mask = 0xFFFF >> (16 - nbits);
809:
810: for (i = 0; i < toscr_nr_planes; i += 2) {
811: outword[i] <<= nbits;
1.1.1.14 root 812: outword[i] |= (todisplay[i][0] >> (16 - nbits + delay1)) & mask;
813: todisplay[i][0] <<= nbits;
1.1.1.13 root 814: }
815: for (i = 1; i < toscr_nr_planes; i += 2) {
816: outword[i] <<= nbits;
1.1.1.14 root 817: outword[i] |= (todisplay[i][0] >> (16 - nbits + delay2)) & mask;
818: todisplay[i][0] <<= nbits;
819: }
820: }
821:
822: STATIC_INLINE void shift32plus (uae_u32 *p, int n)
823: {
824: uae_u32 t = p[1];
825: t <<= n;
826: t |= p[0] >> (32 - n);
827: p[1] = t;
828: }
829:
830: STATIC_INLINE void aga_shift (uae_u32 *p, int n, int fm)
831: {
832: if (fm == 2) {
833: shift32plus (p + 2, n);
834: shift32plus (p + 1, n);
1.1.1.13 root 835: }
1.1.1.14 root 836: shift32plus (p + 0, n);
837: p[0] <<= n;
838: }
839:
840: STATIC_INLINE void toscr_3_aga (int nbits, int fm)
841: {
842: int delay1 = toscr_delay1;
843: int delay2 = toscr_delay2;
844: int i;
845: uae_u32 mask = 0xFFFF >> (16 - nbits);
846:
847: {
848: int offs = (16 << fm) - nbits + delay1;
849: int off1 = offs >> 5;
850: if (off1 == 3)
851: off1 = 2;
852: offs -= off1 * 32;
853: for (i = 0; i < toscr_nr_planes; i += 2) {
854: uae_u32 t0 = todisplay[i][off1];
855: uae_u32 t1 = todisplay[i][off1 + 1];
856: uae_u64 t = (((uae_u64)t1) << 32) | t0;
857: outword[i] <<= nbits;
858: outword[i] |= (t >> offs) & mask;
859: aga_shift (todisplay[i], nbits, fm);
860: }
861: }
862: {
863: int offs = (16 << fm) - nbits + delay2;
864: int off1 = offs >> 5;
865: if (off1 == 3)
866: off1 = 2;
867: offs -= off1 * 32;
868: for (i = 1; i < toscr_nr_planes; i += 2) {
869: uae_u32 t0 = todisplay[i][off1];
870: uae_u32 t1 = todisplay[i][off1 + 1];
871: uae_u64 t = (((uae_u64)t1) << 32) | t0;
872: outword[i] <<= nbits;
873: outword[i] |= (t >> offs) & mask;
874: aga_shift (todisplay[i], nbits, fm);
875: }
876: }
877: }
878:
879: static void toscr_2_0 (int nbits) { toscr_3_ecs (nbits); }
880: static void toscr_2_1 (int nbits) { toscr_3_aga (nbits, 1); }
881: static void toscr_2_2 (int nbits) { toscr_3_aga (nbits, 2); }
882:
883: STATIC_INLINE void toscr_1 (int nbits, int fm)
884: {
885: switch (fm) {
886: case 0:
887: toscr_2_0 (nbits);
888: break;
889: case 1:
890: toscr_2_1 (nbits);
891: break;
892: case 2:
893: toscr_2_2 (nbits);
894: break;
895: }
896:
1.1.1.13 root 897: out_nbits += nbits;
898: if (out_nbits == 32) {
1.1.1.14 root 899: int i;
1.1.1.13 root 900: uae_u8 *dataptr = line_data[next_lineno] + out_offs * 4;
901: /* Don't use toscr_nr_planes here; if the plane count drops during the
902: line we still want the data to be correct for the full number of planes
903: over the full width of the line. */
904: for (i = 0; i < thisline_decision.nr_planes; i++) {
905: uae_u32 *dataptr32 = (uae_u32 *)dataptr;
906: if (*dataptr32 != outword[i])
907: thisline_changed = 1;
908: *dataptr32 = outword[i];
909: dataptr += MAX_WORDS_PER_LINE * 2;
910: }
911: out_offs++;
912: out_nbits = 0;
913: }
1.1.1.7 root 914: }
915:
1.1.1.14 root 916: static void toscr_fm0 (int);
917: static void toscr_fm1 (int);
918: static void toscr_fm2 (int);
919:
920: STATIC_INLINE void toscr (int nbits, int fm)
921: {
922: switch (fm) {
923: case 0: toscr_fm0 (nbits); break;
924: case 1: toscr_fm1 (nbits); break;
925: case 2: toscr_fm2 (nbits); break;
926: }
927: }
928:
929: STATIC_INLINE void toscr_0 (int nbits, int fm)
1.1.1.4 root 930: {
1.1.1.13 root 931: int t;
1.1.1.14 root 932:
1.1.1.13 root 933: if (nbits > 16) {
1.1.1.14 root 934: toscr (16, fm);
1.1.1.13 root 935: nbits -= 16;
1.1.1.2 root 936: }
1.1.1.3 root 937:
1.1.1.13 root 938: t = 32 - out_nbits;
939: if (t < nbits) {
1.1.1.14 root 940: toscr_1 (t, fm);
1.1.1.13 root 941: nbits -= t;
942: }
1.1.1.14 root 943: toscr_1 (nbits, fm);
1.1.1.13 root 944: }
1.1.1.14 root 945:
946: static void toscr_fm0 (int nbits) { toscr_0 (nbits, 0); }
947: static void toscr_fm1 (int nbits) { toscr_0 (nbits, 1); }
948: static void toscr_fm2 (int nbits) { toscr_0 (nbits, 2); }
949:
950: static int flush_plane_data (int fm)
1.1.1.13 root 951: {
952: int i = 0;
1.1.1.14 root 953: int fetchwidth = 16 << fm;
1.1.1.4 root 954:
1.1.1.13 root 955: if (out_nbits <= 16) {
956: i += 16;
1.1.1.14 root 957: toscr_1 (16, fm);
1.1.1.13 root 958: }
959: if (out_nbits != 0) {
960: i += 32 - out_nbits;
1.1.1.14 root 961: toscr_1 (32 - out_nbits, fm);
1.1.1.4 root 962: }
1.1.1.13 root 963: i += 32;
1.1.1.10 root 964:
1.1.1.14 root 965: toscr_1 (16, fm);
966: toscr_1 (16, fm);
1.1.1.13 root 967: return i >> (1 + toscr_res);
968: }
969:
1.1.1.14 root 970: STATIC_INLINE void flush_display (int fm)
971: {
972: if (toscr_nbits > 0 && thisline_decision.plfleft != -1)
973: toscr (toscr_nbits, fm);
974: toscr_nbits = 0;
975: }
976:
977: /* Called when all planes have been fetched, i.e. when a new block
978: of data is available to be displayed. The data in fetched[] is
979: moved into todisplay[]. */
980: STATIC_INLINE void beginning_of_plane_block (int pos, int dma, int fm)
981: {
982: int i;
983:
984: flush_display (fm);
985:
986: if (fm == 0)
987: for (i = 0; i < MAX_PLANES; i++)
988: todisplay[i][0] |= fetched[i];
989: else
990: for (i = 0; i < MAX_PLANES; i++) {
991: if (fm == 2)
992: todisplay[i][1] = fetched_aga1[i];
993: todisplay[i][0] = fetched_aga0[i];
994: }
995:
996: maybe_first_bpl1dat (pos);
997: }
998:
999: #define SPEEDUP
1000:
1001: #ifdef SPEEDUP
1002:
1.1.1.13 root 1003: /* The usual inlining tricks - don't touch unless you know what you are doing. */
1.1.1.14 root 1004: STATIC_INLINE void long_fetch_ecs (int plane, int nwords, int weird_number_of_bits, int dma)
1.1.1.13 root 1005: {
1.1.1.16 root 1006: uae_u16 *real_pt = (uae_u16 *)pfield_xlateptr (bplpt[plane] + bpl_off[plane], nwords * 2);
1.1.1.14 root 1007: int delay = ((plane & 1) ? toscr_delay2 : toscr_delay1);
1.1.1.13 root 1008: int tmp_nbits = out_nbits;
1.1.1.14 root 1009: uae_u32 shiftbuffer = todisplay[plane][0];
1.1.1.13 root 1010: uae_u32 outval = outword[plane];
1011: uae_u32 fetchval = fetched[plane];
1012: uae_u32 *dataptr = (uae_u32 *)(line_data[next_lineno] + 2 * plane * MAX_WORDS_PER_LINE + 4 * out_offs);
1013:
1.1.1.14 root 1014: if (dma)
1015: bplpt[plane] += nwords * 2;
1.1.1.13 root 1016:
1017: if (real_pt == 0)
1018: /* @@@ Don't do this, fall back on chipmem_wget instead. */
1.1.1.4 root 1019: return;
1020:
1.1.1.13 root 1021: while (nwords > 0) {
1022: int bits_left = 32 - tmp_nbits;
1.1.1.14 root 1023: uae_u32 t;
1.1.1.13 root 1024:
1025: shiftbuffer |= fetchval;
1026:
1.1.1.14 root 1027: t = (shiftbuffer >> delay) & 0xFFFF;
1028:
1.1.1.13 root 1029: if (weird_number_of_bits && bits_left < 16) {
1030: outval <<= bits_left;
1.1.1.14 root 1031: outval |= t >> (16 - bits_left);
1.1.1.13 root 1032: thisline_changed |= *dataptr ^ outval;
1033: *dataptr++ = outval;
1034:
1.1.1.14 root 1035: outval = t;
1.1.1.13 root 1036: tmp_nbits = 16 - bits_left;
1.1.1.14 root 1037: shiftbuffer <<= 16;
1.1.1.13 root 1038: } else {
1.1.1.14 root 1039: outval = (outval << 16) | t;
1.1.1.13 root 1040: shiftbuffer <<= 16;
1041: tmp_nbits += 16;
1042: if (tmp_nbits == 32) {
1043: thisline_changed |= *dataptr ^ outval;
1044: *dataptr++ = outval;
1045: tmp_nbits = 0;
1046: }
1047: }
1048: nwords--;
1.1.1.14 root 1049: if (dma) {
1050: fetchval = do_get_mem_word (real_pt);
1051: real_pt++;
1052: }
1.1.1.13 root 1053: }
1054: fetched[plane] = fetchval;
1.1.1.14 root 1055: todisplay[plane][0] = shiftbuffer;
1.1.1.13 root 1056: outword[plane] = outval;
1.1.1.2 root 1057: }
1058:
1.1.1.14 root 1059: STATIC_INLINE void long_fetch_aga (int plane, int nwords, int weird_number_of_bits, int fm, int dma)
1060: {
1.1.1.16 root 1061: uae_u32 *real_pt = (uae_u32 *)pfield_xlateptr (bplpt[plane] + bpl_off[plane], nwords * 2);
1.1.1.14 root 1062: int delay = ((plane & 1) ? toscr_delay2 : toscr_delay1);
1063: int tmp_nbits = out_nbits;
1064: uae_u32 *shiftbuffer = todisplay[plane];
1065: uae_u32 outval = outword[plane];
1066: uae_u32 fetchval0 = fetched_aga0[plane];
1067: uae_u32 fetchval1 = fetched_aga1[plane];
1068: uae_u32 *dataptr = (uae_u32 *)(line_data[next_lineno] + 2 * plane * MAX_WORDS_PER_LINE + 4 * out_offs);
1069: int offs = (16 << fm) - 16 + delay;
1070: int off1 = offs >> 5;
1071: if (off1 == 3)
1072: off1 = 2;
1073: offs -= off1 * 32;
1074:
1075: if (dma)
1076: bplpt[plane] += nwords * 2;
1077:
1078: if (real_pt == 0)
1079: /* @@@ Don't do this, fall back on chipmem_wget instead. */
1080: return;
1081:
1082: while (nwords > 0) {
1083: int i;
1084:
1085: shiftbuffer[0] = fetchval0;
1086: if (fm == 2)
1087: shiftbuffer[1] = fetchval1;
1088:
1089: for (i = 0; i < (1 << fm); i++) {
1090: int bits_left = 32 - tmp_nbits;
1.1.1.13 root 1091:
1.1.1.14 root 1092: uae_u32 t0 = shiftbuffer[off1];
1093: uae_u32 t1 = shiftbuffer[off1 + 1];
1094: uae_u64 t = (((uae_u64)t1) << 32) | t0;
1095:
1096: t0 = (t >> offs) & 0xFFFF;
1097:
1098: if (weird_number_of_bits && bits_left < 16) {
1099: outval <<= bits_left;
1100: outval |= t0 >> (16 - bits_left);
1101:
1102: thisline_changed |= *dataptr ^ outval;
1103: *dataptr++ = outval;
1104:
1105: outval = t0;
1106: tmp_nbits = 16 - bits_left;
1107: aga_shift (shiftbuffer, 16, fm);
1108: } else {
1109: outval = (outval << 16) | t0;
1110: aga_shift (shiftbuffer, 16, fm);
1111: tmp_nbits += 16;
1112: if (tmp_nbits == 32) {
1113: thisline_changed |= *dataptr ^ outval;
1114: *dataptr++ = outval;
1115: tmp_nbits = 0;
1116: }
1117: }
1118: }
1119:
1120: nwords -= 1 << fm;
1121:
1122: if (dma) {
1123: if (fm == 1)
1124: fetchval0 = do_get_mem_long (real_pt);
1125: else {
1126: fetchval1 = do_get_mem_long (real_pt);
1127: fetchval0 = do_get_mem_long (real_pt + 1);
1128: }
1129: real_pt += fm;
1130: }
1131: }
1132: fetched_aga0[plane] = fetchval0;
1133: fetched_aga1[plane] = fetchval1;
1134: outword[plane] = outval;
1135: }
1136:
1137: static void long_fetch_ecs_0 (int hpos, int nwords, int dma) { long_fetch_ecs (hpos, nwords, 0, dma); }
1138: static void long_fetch_ecs_1 (int hpos, int nwords, int dma) { long_fetch_ecs (hpos, nwords, 1, dma); }
1139: static void long_fetch_aga_1_0 (int hpos, int nwords, int dma) { long_fetch_aga (hpos, nwords, 0, 1, dma); }
1140: static void long_fetch_aga_1_1 (int hpos, int nwords, int dma) { long_fetch_aga (hpos, nwords, 1, 1, dma); }
1141: static void long_fetch_aga_2_0 (int hpos, int nwords, int dma) { long_fetch_aga (hpos, nwords, 0, 2, dma); }
1142: static void long_fetch_aga_2_1 (int hpos, int nwords, int dma) { long_fetch_aga (hpos, nwords, 1, 2, dma); }
1143:
1144: static void do_long_fetch (int hpos, int nwords, int dma, int fm)
1.1.1.2 root 1145: {
1.1.1.14 root 1146: int added;
1.1.1.13 root 1147: int i;
1.1.1.2 root 1148:
1.1.1.14 root 1149: flush_display (fm);
1150: switch (fm) {
1151: case 0:
1152: if (out_nbits & 15) {
1153: for (i = 0; i < toscr_nr_planes; i++)
1154: long_fetch_ecs_1 (i, nwords, dma);
1155: } else {
1156: for (i = 0; i < toscr_nr_planes; i++)
1157: long_fetch_ecs_0 (i, nwords, dma);
1158: }
1159: break;
1160: case 1:
1161: if (out_nbits & 15) {
1162: for (i = 0; i < toscr_nr_planes; i++)
1163: long_fetch_aga_1_1 (i, nwords, dma);
1164: } else {
1165: for (i = 0; i < toscr_nr_planes; i++)
1166: long_fetch_aga_1_0 (i, nwords, dma);
1167: }
1168: break;
1169: case 2:
1170: if (out_nbits & 15) {
1171: for (i = 0; i < toscr_nr_planes; i++)
1172: long_fetch_aga_2_1 (i, nwords, dma);
1173: } else {
1174: for (i = 0; i < toscr_nr_planes; i++)
1175: long_fetch_aga_2_0 (i, nwords, dma);
1176: }
1177: break;
1.1.1.2 root 1178: }
1.1.1.13 root 1179:
1.1.1.14 root 1180: out_nbits += nwords * 16;
1.1.1.13 root 1181: out_offs += out_nbits >> 5;
1182: out_nbits &= 31;
1.1.1.14 root 1183:
1184: if (dma && toscr_nr_planes > 0)
1185: fetch_state = fetch_was_plane0;
1.1.1.13 root 1186: }
1187:
1.1.1.14 root 1188: #endif
1.1.1.13 root 1189:
1.1.1.14 root 1190: /* make sure fetch that goes beyond maxhpos is finished */
1191: static void finish_final_fetch (int i, int fm)
1192: {
1193: passed_plfstop = 3;
1.1.1.15 root 1194:
1195: if (thisline_decision.plfleft != -1) {
1196: i += flush_plane_data (fm);
1197: thisline_decision.plfright = i;
1198: thisline_decision.plflinelen = out_offs;
1199: thisline_decision.bplres = toscr_res;
1200: finish_playfield_line ();
1201: }
1.1.1.14 root 1202: }
1203:
1204: STATIC_INLINE int one_fetch_cycle_0 (int i, int ddfstop_to_test, int dma, int fm)
1.1.1.13 root 1205: {
1206: if (! passed_plfstop && i == ddfstop_to_test)
1207: passed_plfstop = 1;
1208:
1.1.1.14 root 1209: if ((fetch_cycle & fetchunit_mask) == 0) {
1.1.1.13 root 1210: if (passed_plfstop == 2) {
1.1.1.14 root 1211: finish_final_fetch (i, fm);
1.1.1.13 root 1212: return 1;
1213: }
1214: if (passed_plfstop)
1215: passed_plfstop++;
1.1.1.2 root 1216: }
1.1.1.13 root 1217: if (dma) {
1.1.1.14 root 1218: /* fetchstart_mask can be larger than fm_maxplane if FMODE > 0. This means
1219: that the remaining cycles are idle; we'll fall through the whole switch
1220: without doing anything. */
1221: int cycle_start = fetch_cycle & fetchstart_mask;
1222: switch (fm_maxplane) {
1223: case 8:
1224: switch (cycle_start) {
1225: case 0: fetch (7, fm); break;
1226: case 1: fetch (3, fm); break;
1227: case 2: fetch (5, fm); break;
1228: case 3: fetch (1, fm); break;
1229: case 4: fetch (6, fm); break;
1230: case 5: fetch (2, fm); break;
1231: case 6: fetch (4, fm); break;
1232: case 7: fetch (0, fm); break;
1233: }
1234: break;
1235: case 4:
1236: switch (cycle_start) {
1237: case 0: fetch (3, fm); break;
1238: case 1: fetch (1, fm); break;
1239: case 2: fetch (2, fm); break;
1240: case 3: fetch (0, fm); break;
1241: }
1242: break;
1243: case 2:
1244: switch (cycle_start) {
1245: case 0: fetch (1, fm); break;
1246: case 1: fetch (0, fm); break;
1247: }
1248: break;
1.1.1.13 root 1249: }
1.1.1.2 root 1250: }
1.1.1.13 root 1251: fetch_cycle++;
1252: toscr_nbits += 2 << toscr_res;
1.1.1.15 root 1253:
1254: if (toscr_nbits == 16)
1255: flush_display (fm);
1256: if (toscr_nbits > 16)
1257: abort ();
1258:
1.1.1.13 root 1259: return 0;
1260: }
1.1.1.3 root 1261:
1.1.1.14 root 1262: static int one_fetch_cycle_fm0 (int i, int ddfstop_to_test, int dma) { return one_fetch_cycle_0 (i, ddfstop_to_test, dma, 0); }
1263: static int one_fetch_cycle_fm1 (int i, int ddfstop_to_test, int dma) { return one_fetch_cycle_0 (i, ddfstop_to_test, dma, 1); }
1264: static int one_fetch_cycle_fm2 (int i, int ddfstop_to_test, int dma) { return one_fetch_cycle_0 (i, ddfstop_to_test, dma, 2); }
1.1.1.13 root 1265:
1.1.1.14 root 1266: STATIC_INLINE int one_fetch_cycle (int i, int ddfstop_to_test, int dma, int fm)
1267: {
1268: switch (fm) {
1269: case 0: return one_fetch_cycle_fm0 (i, ddfstop_to_test, dma);
1270: case 1: return one_fetch_cycle_fm1 (i, ddfstop_to_test, dma);
1271: case 2: return one_fetch_cycle_fm2 (i, ddfstop_to_test, dma);
1272: default: abort ();
1273: }
1.1.1.13 root 1274: }
1275:
1.1.1.14 root 1276: STATIC_INLINE void update_fetch (int until, int fm)
1.1.1.13 root 1277: {
1278: int pos;
1279: int dma = dmaen (DMA_BITPLANE);
1280:
1281: int ddfstop_to_test;
1282:
1283: if (framecnt != 0 || passed_plfstop == 3)
1.1.1.2 root 1284: return;
1.1.1.13 root 1285:
1286: /* We need an explicit test against HARD_DDF_STOP here to guard against
1287: programs that move the DDFSTOP before our current position before we
1288: reach it. */
1289: ddfstop_to_test = HARD_DDF_STOP;
1290: if (ddfstop >= last_fetch_hpos && ddfstop < HARD_DDF_STOP)
1291: ddfstop_to_test = ddfstop;
1292:
1.1.1.14 root 1293: compute_toscr_delay (last_fetch_hpos);
1.1.1.13 root 1294: update_toscr_planes ();
1295:
1296: pos = last_fetch_hpos;
1.1.1.16 root 1297: cycle_diagram_shift = (last_fetch_hpos - fetch_cycle) & fetchstart_mask;
1.1.1.13 root 1298:
1.1.1.14 root 1299: /* First, a loop that prepares us for the speedup code. We want to enter
1300: the SPEEDUP case with fetch_state == fetch_was_plane0, and then unroll
1301: whole blocks, so that we end on the same fetch_state again. */
1.1.1.13 root 1302: for (; ; pos++) {
1.1.1.14 root 1303: if (pos == until) {
1304: if (until >= maxhpos && passed_plfstop == 2) {
1305: finish_final_fetch (pos, fm);
1306: return;
1307: }
1308: flush_display (fm);
1309: return;
1310: }
1.1.1.13 root 1311:
1.1.1.14 root 1312: if (fetch_state == fetch_was_plane0)
1.1.1.13 root 1313: break;
1314:
1315: fetch_state = fetch_started;
1.1.1.14 root 1316: if (one_fetch_cycle (pos, ddfstop_to_test, dma, fm))
1.1.1.13 root 1317: return;
1.1.1.14 root 1318: }
1.1.1.13 root 1319:
1320: #ifdef SPEEDUP
1321: /* Unrolled version of the for loop below. */
1.1.1.14 root 1322: if (! passed_plfstop
1323: && dma
1.1.1.15 root 1324: && (fetch_cycle & fetchstart_mask) == (fm_maxplane & fetchstart_mask)
1.1.1.14 root 1325: # if 0
1326: /* @@@ We handle this case, but the code would be simpler if we
1327: * disallowed it - it may even be possible to guarantee that
1328: * this condition never is false. Later. */
1329: && (out_nbits & 15) == 0
1330: # endif
1331: && toscr_nr_planes == thisline_decision.nr_planes)
1332: {
1.1.1.15 root 1333: int offs = (pos - fetch_cycle) & fetchunit_mask;
1.1.1.14 root 1334: int ddf2 = ((ddfstop_to_test - offs + fetchunit - 1) & ~fetchunit_mask) + offs;
1335: int ddf3 = ddf2 + fetchunit;
1336: int stop = until < ddf2 ? until : until < ddf3 ? ddf2 : ddf3;
1337: int count;
1338:
1339: count = stop - pos;
1340:
1341: if (count >= fetchstart) {
1342: count &= ~fetchstart_mask;
1343:
1.1.1.15 root 1344: if (thisline_decision.plfleft == -1) {
1.1.1.14 root 1345: compute_delay_offset (pos);
1.1.1.15 root 1346: compute_toscr_delay_1 ();
1347: }
1.1.1.14 root 1348: do_long_fetch (pos, count >> (3 - toscr_res), dma, fm);
1349:
1350: /* This must come _after_ do_long_fetch so as not to confuse flush_display
1351: into thinking the first fetch has produced any output worth emitting to
1352: the screen. But the calculation of delay_offset must happen _before_. */
1353: maybe_first_bpl1dat (pos);
1.1.1.13 root 1354:
1355: if (pos <= ddfstop_to_test && pos + count > ddfstop_to_test)
1356: passed_plfstop = 1;
1.1.1.14 root 1357: if (pos <= ddfstop_to_test && pos + count > ddf2)
1358: passed_plfstop = 2;
1.1.1.13 root 1359: pos += count;
1360: fetch_cycle += count;
1361: }
1.1.1.2 root 1362: }
1363: #endif
1.1.1.13 root 1364: for (; pos < until; pos++) {
1365: if (fetch_state == fetch_was_plane0)
1.1.1.14 root 1366: beginning_of_plane_block (pos, dma, fm);
1.1.1.13 root 1367: fetch_state = fetch_started;
1368:
1.1.1.14 root 1369: if (one_fetch_cycle (pos, ddfstop_to_test, dma, fm))
1.1.1.13 root 1370: return;
1371: }
1.1.1.14 root 1372: if (until >= maxhpos && passed_plfstop == 2) {
1373: finish_final_fetch (pos, fm);
1374: return;
1375: }
1376: flush_display (fm);
1.1.1.2 root 1377: }
1378:
1.1.1.14 root 1379: static void update_fetch_0 (int hpos) { update_fetch (hpos, 0); }
1380: static void update_fetch_1 (int hpos) { update_fetch (hpos, 1); }
1381: static void update_fetch_2 (int hpos) { update_fetch (hpos, 2); }
1382:
1.1.1.13 root 1383: STATIC_INLINE void decide_fetch (int hpos)
1384: {
1.1.1.14 root 1385: if (fetch_state != fetch_not_started && hpos > last_fetch_hpos) {
1386: switch (fetchmode) {
1387: case 0: update_fetch_0 (hpos); break;
1388: case 1: update_fetch_1 (hpos); break;
1389: case 2: update_fetch_2 (hpos); break;
1390: default: abort ();
1391: }
1392: }
1.1.1.13 root 1393: last_fetch_hpos = hpos;
1394: }
1395:
1396: /* This function is responsible for turning on datafetch if necessary. */
1.1.1.8 root 1397: STATIC_INLINE void decide_line (int hpos)
1.1.1.2 root 1398: {
1.1.1.15 root 1399: if (hpos <= last_decide_line_hpos)
1400: return;
1.1.1.13 root 1401: if (fetch_state != fetch_not_started)
1402: return;
1403:
1404: /* Test if we passed the start of the DDF window. */
1405: if (last_decide_line_hpos < plfstrt && hpos >= plfstrt) {
1406: /* First, take care of the vertical DIW. Surprisingly enough, this seems to be
1407: correct here - putting this into decide_diw() results in garbage. */
1408: if (diwstate == DIW_waiting_start && vpos == plffirstline) {
1409: diwstate = DIW_waiting_stop;
1410: }
1411: if (diwstate == DIW_waiting_stop && vpos == plflastline) {
1412: diwstate = DIW_waiting_start;
1413: }
1414:
1.1.1.15 root 1415: /* If DMA isn't on by the time we reach plfstrt, then there's no
1416: bitplane DMA at all for the whole line. */
1417: if (dmaen (DMA_BITPLANE)
1418: && diwstate == DIW_waiting_stop)
1419: {
1.1.1.13 root 1420: fetch_state = fetch_started;
1421: fetch_cycle = 0;
1422: last_fetch_hpos = plfstrt;
1423: out_nbits = 0;
1424: out_offs = 0;
1425: toscr_nbits = 0;
1426:
1.1.1.14 root 1427: compute_toscr_delay (last_fetch_hpos);
1.1.1.13 root 1428:
1429: /* If someone already wrote BPL1DAT, clear the area between that point and
1430: the real fetch start. */
1.1.1.14 root 1431: if (framecnt == 0) {
1432: if (thisline_decision.plfleft != -1) {
1433: out_nbits = (plfstrt - thisline_decision.plfleft) << (1 + toscr_res);
1434: out_offs = out_nbits >> 5;
1435: out_nbits &= 31;
1436: }
1437: update_toscr_planes ();
1.1.1.13 root 1438: }
1439: estimate_last_fetch_cycle (plfstrt);
1440: last_decide_line_hpos = hpos;
1.1.1.20! root 1441: do_sprites (plfstrt);
1.1.1.13 root 1442: return;
1443: }
1444: }
1445:
1446: if (last_decide_line_hpos < 0x34)
1.1.1.20! root 1447: do_sprites (hpos);
1.1.1.13 root 1448:
1449: last_decide_line_hpos = hpos;
1.1.1.2 root 1450: }
1451:
1.1.1.3 root 1452: /* Called when a color is about to be changed (write to a color register),
1453: * but the new color has not been entered into the table yet. */
1.1.1.4 root 1454: static void record_color_change (int hpos, int regno, unsigned long value)
1.1.1.3 root 1455: {
1.1.1.18 root 1456: if (regno == -1 && value) {
1457: thisline_decision.ham_seen = 1;
1458: if (hpos < 0x18)
1459: thisline_decision.ham_at_start = 1;
1460: }
1461:
1.1.1.3 root 1462: /* Early positions don't appear on-screen. */
1.1.1.4 root 1463: if (framecnt != 0 || vpos < minfirstline || hpos < 0x18
1.1.1.3 root 1464: /*|| currprefs.emul_accuracy == 0*/)
1465: return;
1466:
1.1.1.4 root 1467: decide_diw (hpos);
1468: decide_line (hpos);
1.1.1.3 root 1469:
1.1.1.13 root 1470: if (thisline_decision.ctable == -1)
1471: remember_ctable ();
1.1.1.3 root 1472:
1473: #ifdef OS_WITHOUT_MEMORY_MANAGEMENT
1.1.1.4 root 1474: if (next_color_change >= max_color_change) {
1.1.1.3 root 1475: ++delta_color_change;
1476: return;
1477: }
1478: #endif
1.1.1.4 root 1479: curr_color_changes[next_color_change].linepos = hpos;
1.1.1.3 root 1480: curr_color_changes[next_color_change].regno = regno;
1481: curr_color_changes[next_color_change++].value = value;
1482: }
1483:
1.1.1.15 root 1484: typedef int sprbuf_res_t, cclockres_t, hwres_t, bplres_t;
1485:
1486: static void do_playfield_collisions (void)
1487: {
1488: uae_u8 *ld = line_data[next_lineno];
1489: int i;
1490:
1491: if (clxcon_bpl_enable == 0) {
1492: clxdat |= 1;
1493: return;
1494: }
1495:
1496: for (i = thisline_decision.plfleft; i < thisline_decision.plfright; i += 2) {
1497: int j;
1498: uae_u32 total = 0xFFFFFFFF;
1499: for (j = 0; j < 8; j++) {
1500: uae_u32 t = 0;
1501: if ((clxcon_bpl_enable & (1 << j)) == 0)
1502: t = 0xFFFFFFFF;
1503: else if (j < thisline_decision.nr_planes) {
1504: t = *(uae_u32 *)(line_data[next_lineno] + 2 * i + 2 * j * MAX_WORDS_PER_LINE);
1505: t ^= ~(((clxcon_bpl_match >> j) & 1) - 1);
1506: }
1507: total &= t;
1508: }
1509: if (total)
1510: clxdat |= 1;
1511: }
1512: }
1513:
1.1.1.13 root 1514: /* Sprite-to-sprite collisions are taken care of in record_sprite. This one does
1515: playfield/sprite collisions.
1516: That's the theory. In practice this doesn't work yet. I also suspect this code
1517: is way too slow. */
1518: static void do_sprite_collisions (void)
1.1.1.2 root 1519: {
1.1.1.13 root 1520: int nr_sprites = curr_drawinfo[next_lineno].nr_sprites;
1521: int first = curr_drawinfo[next_lineno].first_sprite_entry;
1522: int i;
1523: unsigned int collision_mask = clxmask[clxcon >> 12];
1.1.1.15 root 1524: int bplres = GET_RES (bplcon0);
1525: hwres_t ddf_left = thisline_decision.plfleft * 2 << bplres;
1526: hwres_t hw_diwlast = coord_window_to_diw_x (thisline_decision.diwlastword);
1527: hwres_t hw_diwfirst = coord_window_to_diw_x (thisline_decision.diwfirstword);
1528:
1529: if (clxcon_bpl_enable == 0) {
1530: clxdat |= 0x1FE;
1531: return;
1532: }
1.1.1.2 root 1533:
1.1.1.13 root 1534: for (i = 0; i < nr_sprites; i++) {
1535: struct sprite_entry *e = curr_sprite_entries + first + i;
1.1.1.15 root 1536: sprbuf_res_t j;
1537: sprbuf_res_t minpos = e->pos;
1538: sprbuf_res_t maxpos = e->max;
1539: hwres_t minp1 = minpos >> sprite_buffer_res;
1540: hwres_t maxp1 = maxpos >> sprite_buffer_res;
1541:
1542: if (maxp1 > hw_diwlast)
1543: maxpos = hw_diwlast << sprite_buffer_res;
1544: if (maxp1 > thisline_decision.plfright * 2)
1545: maxpos = thisline_decision.plfright * 2 << sprite_buffer_res;
1546: if (minp1 < hw_diwfirst)
1547: minpos = hw_diwfirst << sprite_buffer_res;
1548: if (minp1 < thisline_decision.plfleft * 2)
1549: minpos = thisline_decision.plfleft * 2 << sprite_buffer_res;
1.1.1.13 root 1550:
1551: for (j = minpos; j < maxpos; j++) {
1552: int sprpix = spixels[e->first_pixel + j - e->pos] & collision_mask;
1553: int k;
1.1.1.15 root 1554: int offs;
1.1.1.2 root 1555:
1.1.1.13 root 1556: if (sprpix == 0)
1557: continue;
1.1.1.2 root 1558:
1.1.1.15 root 1559: offs = ((j << bplres) >> sprite_buffer_res) - ddf_left;
1.1.1.13 root 1560: sprpix = sprite_ab_merge[sprpix & 255] | (sprite_ab_merge[sprpix >> 8] << 2);
1561: sprpix <<= 1;
1.1.1.2 root 1562:
1.1.1.13 root 1563: /* Loop over number of playfields. */
1564: for (k = 0; k < 2; k++) {
1565: int l;
1566: int match = 1;
1.1.1.14 root 1567: int planes = ((currprefs.chipset_mask & CSMASK_AGA) ? 8 : 6);
1.1.1.13 root 1568:
1.1.1.15 root 1569: for (l = k; match && l < planes; l += 2) {
1.1.1.14 root 1570: if (clxcon_bpl_enable & (1 << l)) {
1.1.1.13 root 1571: int t = 0;
1572: if (l < thisline_decision.nr_planes) {
1573: uae_u32 *ldata = (uae_u32 *)(line_data[next_lineno] + 2 * l * MAX_WORDS_PER_LINE);
1574: uae_u32 word = ldata[offs >> 5];
1575: t = (word >> (31 - (offs & 31))) & 1;
1576: }
1.1.1.14 root 1577: if (t != ((clxcon_bpl_match >> l) & 1))
1.1.1.13 root 1578: match = 0;
1579: }
1.1.1.15 root 1580: }
1.1.1.13 root 1581: if (match)
1582: clxdat |= sprpix;
1583: sprpix <<= 4;
1584: }
1.1.1.2 root 1585: }
1586: }
1587: }
1588:
1.1.1.15 root 1589: static void expand_sprres (void)
1590: {
1591: switch ((bplcon3 >> 6) & 3) {
1592: case 0: /* ECS defaults (LORES,HIRES=140ns,SHRES=70ns) */
1593: if ((currprefs.chipset_mask & CSMASK_ECS_DENISE) && GET_RES (bplcon0) == RES_SUPERHIRES)
1594: sprres = RES_HIRES;
1595: else
1596: sprres = RES_LORES;
1597: break;
1598: case 1:
1599: sprres = RES_LORES;
1600: break;
1601: case 2:
1602: sprres = RES_HIRES;
1603: break;
1604: case 3:
1605: sprres = RES_SUPERHIRES;
1606: break;
1607: }
1608: }
1609:
1610: STATIC_INLINE void record_sprite_1 (uae_u16 *buf, uae_u32 datab, int num, int dbl,
1611: unsigned int mask, int do_collisions, uae_u32 collision_mask)
1612: {
1613: int j = 0;
1614: while (datab) {
1615: unsigned int tmp = *buf;
1616: unsigned int col = (datab & 3) << (2 * num);
1617: tmp |= col;
1618: if ((j & mask) == 0)
1619: *buf++ = tmp;
1620: if (dbl)
1621: *buf++ = tmp;
1622: j++;
1623: datab >>= 2;
1624: if (do_collisions) {
1625: tmp &= collision_mask;
1626: if (tmp) {
1627: unsigned int shrunk_tmp = sprite_ab_merge[tmp & 255] | (sprite_ab_merge[tmp >> 8] << 2);
1628: clxdat |= sprclx[shrunk_tmp];
1629: }
1630: }
1631: }
1632: }
1633:
1.1.1.13 root 1634: /* DATAB contains the sprite data; 16 pixels in two-bit packets. Bits 0/1
1635: determine the color of the leftmost pixel, bits 2/3 the color of the next
1636: etc.
1637: This function assumes that for all sprites in a given line, SPRXP either
1.1.1.15 root 1638: stays equal or increases between successive calls.
1639:
1640: The data is recorded either in lores pixels (if ECS), or in hires pixels
1641: (if AGA). No support for SHRES sprites. */
1642:
1643: static void record_sprite (int line, int num, int sprxp, uae_u16 *data, uae_u16 *datb, unsigned int ctl)
1.1.1.2 root 1644: {
1.1.1.13 root 1645: struct sprite_entry *e = curr_sprite_entries + next_sprite_entry;
1646: int i;
1647: int word_offs;
1648: uae_u16 *buf;
1649: uae_u32 collision_mask;
1.1.1.15 root 1650: int width = sprite_width;
1651: int dbl = 0;
1652: unsigned int mask = 0;
1.1.1.13 root 1653:
1.1.1.15 root 1654: if (sprres != RES_LORES)
1655: thisline_decision.any_hires_sprites = 1;
1656:
1657: if (currprefs.chipset_mask & CSMASK_AGA) {
1658: width = (width << 1) >> sprres;
1659: dbl = sprite_buffer_res - sprres;
1660: mask = sprres == RES_SUPERHIRES ? 1 : 0;
1661: }
1.1.1.13 root 1662:
1663: /* Try to coalesce entries if they aren't too far apart. */
1.1.1.15 root 1664: if (! next_sprite_forced && e[-1].max + 16 >= sprxp) {
1.1.1.13 root 1665: e--;
1.1.1.15 root 1666: } else {
1.1.1.13 root 1667: next_sprite_entry++;
1668: e->pos = sprxp;
1669: e->has_attached = 0;
1670: }
1.1.1.15 root 1671:
1.1.1.13 root 1672: if (sprxp < e->pos)
1673: abort ();
1.1.1.15 root 1674:
1675: e->max = sprxp + width;
1.1.1.13 root 1676: e[1].first_pixel = e->first_pixel + ((e->max - e->pos + 3) & ~3);
1677: next_sprite_forced = 0;
1678:
1679: collision_mask = clxmask[clxcon >> 12];
1680: word_offs = e->first_pixel + sprxp - e->pos;
1.1.1.15 root 1681:
1682: for (i = 0; i < sprite_width; i += 16) {
1683: unsigned int da = *data;
1684: unsigned int db = *datb;
1685: uae_u32 datab = ((sprtaba[da & 0xFF] << 16) | sprtaba[da >> 8]
1686: | (sprtabb[db & 0xFF] << 16) | sprtabb[db >> 8]);
1687:
1688: buf = spixels + word_offs + (i << dbl);
1689: if (currprefs.collision_level > 0 && collision_mask)
1690: record_sprite_1 (buf, datab, num, dbl, mask, 1, collision_mask);
1691: else
1692: record_sprite_1 (buf, datab, num, dbl, mask, 0, collision_mask);
1693: data++;
1694: datb++;
1.1.1.2 root 1695: }
1696:
1.1.1.13 root 1697: /* We have 8 bits per pixel in spixstate, two for every sprite pair. The
1698: low order bit records whether the attach bit was set for this pair. */
1699:
1700: if (ctl & (num << 7) & 0x80) {
1701: uae_u32 state = 0x01010101 << (num - 1);
1702: uae_u32 *stbuf = spixstate.words + (word_offs >> 2);
1703: uae_u8 *stb1 = spixstate.bytes + word_offs;
1.1.1.15 root 1704: for (i = 0; i < width; i += 8) {
1705: stb1[0] |= state;
1706: stb1[1] |= state;
1707: stb1[2] |= state;
1708: stb1[3] |= state;
1709: stb1[4] |= state;
1710: stb1[5] |= state;
1711: stb1[6] |= state;
1712: stb1[7] |= state;
1713: stb1 += 8;
1714: }
1.1.1.13 root 1715: e->has_attached = 1;
1.1.1.3 root 1716: }
1717: }
1.1.1.2 root 1718:
1.1.1.4 root 1719: static void decide_sprites (int hpos)
1.1.1.3 root 1720: {
1.1.1.7 root 1721: int nrs[MAX_SPRITES], posns[MAX_SPRITES];
1722: int count, i;
1.1.1.15 root 1723: int point = hpos * 2;
1724: int width = sprite_width;
1725: int window_width = (width << lores_shift) >> sprres;
1.1.1.2 root 1726:
1.1.1.4 root 1727: if (framecnt != 0 || hpos < 0x14 || nr_armed == 0 || point == last_sprite_point)
1.1.1.2 root 1728: return;
1729:
1.1.1.4 root 1730: decide_diw (hpos);
1731: decide_line (hpos);
1.1.1.3 root 1732:
1.1.1.13 root 1733: #if 0
1734: /* This tries to detect whether the line is border, but that doesn't work, it's too early. */
1735: if (thisline_decision.plfleft == -1)
1.1.1.2 root 1736: return;
1.1.1.13 root 1737: #endif
1.1.1.3 root 1738: count = 0;
1.1.1.15 root 1739: for (i = 0; i < MAX_SPRITES; i++) {
1.1.1.10 root 1740: int sprxp = spr[i].xpos;
1.1.1.15 root 1741: int hw_xp = (sprxp >> sprite_buffer_res);
1742: int window_xp = coord_hw_to_window_x (hw_xp) + (DIW_DDF_OFFSET << lores_shift);
1.1.1.3 root 1743: int j, bestp;
1.1.1.2 root 1744:
1.1.1.15 root 1745: if (! spr[i].armed || sprxp < 0 || hw_xp <= last_sprite_point || hw_xp > point)
1.1.1.3 root 1746: continue;
1.1.1.15 root 1747: if ((thisline_decision.diwfirstword >= 0 && window_xp + window_width < thisline_decision.diwfirstword)
1748: || (thisline_decision.diwlastword >= 0 && window_xp > thisline_decision.diwlastword))
1.1.1.3 root 1749: continue;
1.1.1.2 root 1750:
1.1.1.13 root 1751: /* Sort the sprites in order of ascending X position before recording them. */
1.1.1.3 root 1752: for (bestp = 0; bestp < count; bestp++) {
1753: if (posns[bestp] > sprxp)
1754: break;
1755: if (posns[bestp] == sprxp && nrs[bestp] < i)
1756: break;
1757: }
1758: for (j = count; j > bestp; j--) {
1759: posns[j] = posns[j-1];
1760: nrs[j] = nrs[j-1];
1761: }
1762: posns[j] = sprxp;
1763: nrs[j] = i;
1764: count++;
1765: }
1.1.1.13 root 1766: for (i = 0; i < count; i++) {
1767: int nr = nrs[i];
1.1.1.15 root 1768: record_sprite (next_lineno, nr, spr[nr].xpos, sprdata[nr], sprdatb[nr], sprctl[nr]);
1.1.1.13 root 1769: }
1.1.1.3 root 1770: last_sprite_point = point;
1.1.1.2 root 1771: }
1772:
1.1.1.13 root 1773: STATIC_INLINE int sprites_differ (struct draw_info *dip, struct draw_info *dip_old)
1774: {
1775: struct sprite_entry *this_first = curr_sprite_entries + dip->first_sprite_entry;
1776: struct sprite_entry *this_last = curr_sprite_entries + dip->last_sprite_entry;
1777: struct sprite_entry *prev_first = prev_sprite_entries + dip_old->first_sprite_entry;
1778: int npixels;
1779: int i;
1780:
1781: if (dip->nr_sprites != dip_old->nr_sprites)
1782: return 1;
1783:
1784: if (dip->nr_sprites == 0)
1785: return 0;
1786:
1787: for (i = 0; i < dip->nr_sprites; i++)
1788: if (this_first[i].pos != prev_first[i].pos
1789: || this_first[i].max != prev_first[i].max
1790: || this_first[i].has_attached != prev_first[i].has_attached)
1791: return 1;
1792:
1793: npixels = this_last->first_pixel + (this_last->max - this_last->pos) - this_first->first_pixel;
1794: if (memcmp (spixels + this_first->first_pixel, spixels + prev_first->first_pixel,
1795: npixels * sizeof (uae_u16)) != 0)
1796: return 1;
1797: if (memcmp (spixstate.bytes + this_first->first_pixel, spixstate.bytes + prev_first->first_pixel, npixels) != 0)
1798: return 1;
1799: return 0;
1800: }
1801:
1802: STATIC_INLINE int color_changes_differ (struct draw_info *dip, struct draw_info *dip_old)
1803: {
1804: if (dip->nr_color_changes != dip_old->nr_color_changes)
1805: return 1;
1806:
1807: if (dip->nr_color_changes == 0)
1808: return 0;
1809: if (memcmp (curr_color_changes + dip->first_color_change,
1810: prev_color_changes + dip_old->first_color_change,
1811: dip->nr_color_changes * sizeof *curr_color_changes) != 0)
1812: return 1;
1813: return 0;
1814: }
1815:
1.1.1.3 root 1816: /* End of a horizontal scan line. Finish off all decisions that were not
1817: * made yet. */
1.1.1.2 root 1818: static void finish_decisions (void)
1819: {
1820: struct draw_info *dip;
1821: struct draw_info *dip_old;
1822: struct decision *dp;
1823: int changed;
1.1.1.4 root 1824: int hpos = current_hpos ();
1.1.1.2 root 1825:
1826: if (framecnt != 0)
1827: return;
1828:
1.1.1.4 root 1829: decide_diw (hpos);
1.1.1.13 root 1830: decide_line (hpos);
1831: decide_fetch (hpos);
1832:
1833: if (thisline_decision.plfleft != -1 && thisline_decision.plflinelen == -1) {
1834: if (fetch_state != fetch_not_started)
1835: abort ();
1836: thisline_decision.plfright = thisline_decision.plfleft;
1837: thisline_decision.plflinelen = 0;
1838: thisline_decision.bplres = RES_LORES;
1839: }
1.1.1.3 root 1840:
1841: /* Large DIWSTOP values can cause the stop position never to be
1842: * reached, so the state machine always stays in the same state and
1843: * there's a more-or-less full-screen DIW. */
1.1.1.13 root 1844: if (hdiwstate == DIW_waiting_stop || thisline_decision.diwlastword > max_diwlastword)
1.1.1.3 root 1845: thisline_decision.diwlastword = max_diwlastword;
1846:
1.1.1.13 root 1847: if (thisline_decision.diwfirstword != line_decisions[next_lineno].diwfirstword)
1848: MARK_LINE_CHANGED;
1849: if (thisline_decision.diwlastword != line_decisions[next_lineno].diwlastword)
1850: MARK_LINE_CHANGED;
1.1.1.2 root 1851:
1852: dip = curr_drawinfo + next_lineno;
1853: dip_old = prev_drawinfo + next_lineno;
1854: dp = line_decisions + next_lineno;
1.1.1.5 root 1855: changed = thisline_changed;
1.1.1.2 root 1856:
1.1.1.13 root 1857: if (thisline_decision.plfleft != -1) {
1858: record_diw_line (thisline_decision.diwfirstword, thisline_decision.diwlastword);
1.1.1.2 root 1859:
1.1.1.4 root 1860: decide_sprites (hpos);
1.1.1.2 root 1861: }
1862:
1.1.1.13 root 1863: dip->last_sprite_entry = next_sprite_entry;
1.1.1.2 root 1864: dip->last_color_change = next_color_change;
1.1.1.3 root 1865:
1866: if (thisline_decision.ctable == -1) {
1.1.1.13 root 1867: if (thisline_decision.plfleft == -1)
1.1.1.3 root 1868: remember_ctable_for_border ();
1.1.1.13 root 1869: else
1870: remember_ctable ();
1.1.1.3 root 1871: }
1.1.1.2 root 1872:
1873: dip->nr_color_changes = next_color_change - dip->first_color_change;
1.1.1.13 root 1874: dip->nr_sprites = next_sprite_entry - dip->first_sprite_entry;
1.1.1.2 root 1875:
1.1.1.13 root 1876: if (thisline_decision.plfleft != line_decisions[next_lineno].plfleft)
1.1.1.2 root 1877: changed = 1;
1.1.1.13 root 1878: if (! changed && color_changes_differ (dip, dip_old))
1.1.1.2 root 1879: changed = 1;
1.1.1.13 root 1880: if (!changed && thisline_decision.plfleft != -1 && sprites_differ (dip, dip_old))
1.1.1.10 root 1881: changed = 1;
1.1.1.2 root 1882:
1883: if (changed) {
1.1.1.5 root 1884: thisline_changed = 1;
1.1.1.2 root 1885: *dp = thisline_decision;
1886: } else
1887: /* The only one that may differ: */
1888: dp->ctable = thisline_decision.ctable;
1889: }
1890:
1.1.1.3 root 1891: /* Set the state of all decisions to "undecided" for a new scanline. */
1.1.1.2 root 1892: static void reset_decisions (void)
1893: {
1894: if (framecnt != 0)
1895: return;
1.1.1.13 root 1896:
1.1.1.15 root 1897: thisline_decision.any_hires_sprites = 0;
1.1.1.13 root 1898: thisline_decision.nr_planes = 0;
1899:
1.1.1.10 root 1900: thisline_decision.plfleft = -1;
1.1.1.13 root 1901: thisline_decision.plflinelen = -1;
1.1.1.18 root 1902: thisline_decision.ham_seen = !! (bplcon0 & 0x800);
1903: thisline_decision.ham_at_start = !! (bplcon0 & 0x800);
1.1.1.10 root 1904:
1.1.1.7 root 1905: /* decided_res shouldn't be touched before it's initialized by decide_line(). */
1.1.1.2 root 1906: thisline_decision.diwfirstword = -1;
1907: thisline_decision.diwlastword = -2;
1.1.1.3 root 1908: if (hdiwstate == DIW_waiting_stop) {
1.1.1.13 root 1909: thisline_decision.diwfirstword = 0;
1.1.1.3 root 1910: if (thisline_decision.diwfirstword != line_decisions[next_lineno].diwfirstword)
1.1.1.5 root 1911: MARK_LINE_CHANGED;
1.1.1.3 root 1912: }
1.1.1.2 root 1913: thisline_decision.ctable = -1;
1914:
1.1.1.5 root 1915: thisline_changed = 0;
1.1.1.2 root 1916: curr_drawinfo[next_lineno].first_color_change = next_color_change;
1.1.1.13 root 1917: curr_drawinfo[next_lineno].first_sprite_entry = next_sprite_entry;
1918: next_sprite_forced = 1;
1.1.1.2 root 1919:
1.1.1.3 root 1920: /* memset(sprite_last_drawn_at, 0, sizeof sprite_last_drawn_at); */
1921: last_sprite_point = 0;
1.1.1.13 root 1922: fetch_state = fetch_not_started;
1923: passed_plfstop = 0;
1924:
1925: memset (todisplay, 0, sizeof todisplay);
1926: memset (fetched, 0, sizeof fetched);
1.1.1.14 root 1927: memset (fetched_aga0, 0, sizeof fetched_aga0);
1928: memset (fetched_aga1, 0, sizeof fetched_aga1);
1.1.1.13 root 1929: memset (outword, 0, sizeof outword);
1.1.1.9 root 1930:
1.1.1.13 root 1931: last_decide_line_hpos = -1;
1.1.1.9 root 1932: last_diw_pix_hpos = -1;
1933: last_ddf_pix_hpos = -1;
1.1.1.13 root 1934: last_sprite_hpos = -1;
1935: last_fetch_hpos = -1;
1.1.1.2 root 1936: }
1937:
1.1.1.20! root 1938: void compute_vsynctime (void)
! 1939: {
! 1940: vsynctime = syncbase / vblank_hz;
! 1941: if (currprefs.produce_sound > 1) {
! 1942: vsynctime = vsynctime * 9 / 10;
! 1943: }
! 1944: }
! 1945:
1.1.1.7 root 1946: /* set PAL or NTSC timing variables */
1947:
1948: static void init_hz (void)
1949: {
1950: int isntsc;
1951:
1952: beamcon0 = new_beamcon0;
1953:
1954: isntsc = beamcon0 & 0x20 ? 0 : 1;
1955: if (!isntsc) {
1956: maxvpos = MAXVPOS_PAL;
1957: maxhpos = MAXHPOS_PAL;
1958: minfirstline = MINFIRSTLINE_PAL;
1959: vblank_endline = VBLANK_ENDLINE_PAL;
1960: vblank_hz = VBLANK_HZ_PAL;
1961: } else {
1962: maxvpos = MAXVPOS_NTSC;
1963: maxhpos = MAXHPOS_NTSC;
1964: minfirstline = MINFIRSTLINE_NTSC;
1965: vblank_endline = VBLANK_ENDLINE_NTSC;
1966: vblank_hz = VBLANK_HZ_NTSC;
1967: }
1.1.1.20! root 1968: compute_vsynctime ();
1.1.1.7 root 1969:
1970: write_log ("Using %s timing\n", isntsc ? "NTSC" : "PAL");
1971: }
1972:
1.1.1.11 root 1973: static void calcdiw (void)
1974: {
1.1.1.4 root 1975: int hstrt = diwstrt & 0xFF;
1976: int hstop = diwstop & 0xFF;
1977: int vstrt = diwstrt >> 8;
1978: int vstop = diwstop >> 8;
1979:
1980: if (diwhigh_written) {
1981: hstrt |= ((diwhigh >> 5) & 1) << 8;
1982: hstop |= ((diwhigh >> 13) & 1) << 8;
1983: vstrt |= (diwhigh & 7) << 8;
1984: vstop |= ((diwhigh >> 8) & 7) << 8;
1985: } else {
1986: hstop += 0x100;
1987: if ((vstop & 0x80) == 0)
1988: vstop |= 0x100;
1989: }
1990:
1.1.1.13 root 1991: diwfirstword = coord_diw_to_window_x (hstrt);
1992: diwlastword = coord_diw_to_window_x (hstop);
1.1.1.2 root 1993: if (diwfirstword < 0)
1994: diwfirstword = 0;
1.1.1.3 root 1995:
1.1.1.4 root 1996: plffirstline = vstrt;
1997: plflastline = vstop;
1998:
1.1 root 1999: #if 0
2000: /* This happens far too often. */
2001: if (plffirstline < minfirstline) {
1.1.1.18 root 2002: write_log ("Warning: Playfield begins before line %d!\n", minfirstline);
1.1 root 2003: plffirstline = minfirstline;
2004: }
2005: #endif
1.1.1.4 root 2006:
1.1 root 2007: #if 0 /* Turrican does this */
2008: if (plflastline > 313) {
1.1.1.18 root 2009: write_log ("Warning: Playfield out of range!\n");
1.1 root 2010: plflastline = 313;
2011: }
2012: #endif
1.1.1.2 root 2013: plfstrt = ddfstrt;
2014: plfstop = ddfstop;
1.1.1.13 root 2015: if (plfstrt < 0x18)
2016: plfstrt = 0x18;
1.1 root 2017: }
2018:
1.1.1.4 root 2019: /* Mousehack stuff */
1.1.1.2 root 2020:
1.1.1.4 root 2021: #define defstepx (1<<16)
2022: #define defstepy (1<<16)
2023: #define defxoffs 0
2024: #define defyoffs 0
1.1.1.3 root 2025:
1.1.1.4 root 2026: static const int docal = 60, xcaloff = 40, ycaloff = 20;
2027: static const int calweight = 3;
2028: static int lastsampledmx, lastsampledmy;
2029: static int lastspr0x,lastspr0y,lastdiffx,lastdiffy,spr0pos,spr0ctl;
2030: static int mstepx,mstepy,xoffs=defxoffs,yoffs=defyoffs;
2031: static int sprvbfl;
1.1.1.2 root 2032:
1.1.1.4 root 2033: int lastmx, lastmy;
2034: int newmousecounters;
2035: int ievent_alive = 0;
1.1 root 2036:
1.1.1.4 root 2037: static enum { unknown_mouse, normal_mouse, dont_care_mouse, follow_mouse } mousestate;
1.1 root 2038:
1.1.1.4 root 2039: static void mousehack_setdontcare (void)
1.1 root 2040: {
1.1.1.4 root 2041: if (mousestate == dont_care_mouse)
1.1.1.2 root 2042: return;
2043:
1.1.1.3 root 2044: write_log ("Don't care mouse mode set\n");
2045: mousestate = dont_care_mouse;
2046: lastspr0x = lastmx; lastspr0y = lastmy;
2047: mstepx = defstepx; mstepy = defstepy;
2048: }
2049:
1.1.1.4 root 2050: static void mousehack_setfollow (void)
1.1.1.3 root 2051: {
1.1.1.4 root 2052: if (mousestate == follow_mouse)
2053: return;
2054:
1.1.1.3 root 2055: write_log ("Follow sprite mode set\n");
2056: mousestate = follow_mouse;
2057: lastdiffx = lastdiffy = 0;
2058: sprvbfl = 0;
1.1.1.4 root 2059: spr0ctl = spr0pos = 0;
1.1.1.3 root 2060: mstepx = defstepx; mstepy = defstepy;
2061: }
2062:
1.1.1.7 root 2063: static uae_u32 mousehack_helper (void)
1.1.1.3 root 2064: {
2065: int mousexpos, mouseypos;
2066:
2067: #ifdef PICASSO96
2068: if (picasso_on) {
1.1.1.17 root 2069: picasso_clip_mouse (&lastmx, &lastmy);
2070: mousexpos = lastmx;
2071: mouseypos = lastmy;
1.1.1.3 root 2072: } else
2073: #endif
2074: {
1.1.1.17 root 2075: /* @@@ This isn't completely right, it doesn't deal with virtual
2076: screen sizes larger than physical very well. */
1.1.1.3 root 2077: if (lastmy >= gfxvidinfo.height)
1.1.1.4 root 2078: lastmy = gfxvidinfo.height - 1;
1.1.1.17 root 2079: if (lastmy < 0)
2080: lastmy = 0;
2081: if (lastmx < 0)
2082: lastmx = 0;
2083: if (lastmx >= gfxvidinfo.width)
2084: lastmx = gfxvidinfo.width - 1;
1.1.1.4 root 2085: mouseypos = coord_native_to_amiga_y (lastmy) << 1;
2086: mousexpos = coord_native_to_amiga_x (lastmx);
1.1.1.3 root 2087: }
2088:
2089: switch (m68k_dreg (regs, 0)) {
1.1.1.15 root 2090: case 0:
1.1.1.3 root 2091: return ievent_alive ? -1 : needmousehack ();
1.1.1.15 root 2092: case 1:
1.1.1.3 root 2093: ievent_alive = 10;
2094: return mousexpos;
1.1.1.15 root 2095: case 2:
1.1.1.3 root 2096: return mouseypos;
2097: }
2098: return 0;
2099: }
2100:
1.1.1.4 root 2101: void togglemouse (void)
1.1.1.3 root 2102: {
1.1.1.4 root 2103: switch (mousestate) {
2104: case dont_care_mouse: mousehack_setfollow (); break;
2105: case follow_mouse: mousehack_setdontcare (); break;
1.1.1.3 root 2106: default: break; /* Nnnnnghh! */
2107: }
2108: }
2109:
1.1.1.8 root 2110: STATIC_INLINE int adjust (int val)
1.1.1.3 root 2111: {
1.1.1.4 root 2112: if (val > 127)
1.1.1.3 root 2113: return 127;
1.1.1.4 root 2114: else if (val < -127)
1.1.1.3 root 2115: return -127;
2116: return val;
2117: }
2118:
1.1.1.4 root 2119: static void do_mouse_hack (void)
1.1.1.3 root 2120: {
2121: int spr0x = ((spr0pos & 0xff) << 2) | ((spr0ctl & 1) << 1);
2122: int spr0y = ((spr0pos >> 8) | ((spr0ctl & 4) << 6)) << 1;
2123: int diffx, diffy;
2124:
2125: if (ievent_alive > 0) {
2126: mouse_x = mouse_y = 0;
2127: return;
2128: }
2129: switch (mousestate) {
1.1.1.11 root 2130: case normal_mouse:
1.1.1.3 root 2131: diffx = lastmx - lastsampledmx;
2132: diffy = lastmy - lastsampledmy;
2133: if (!newmousecounters) {
2134: if (diffx > 127) diffx = 127;
2135: if (diffx < -127) diffx = -127;
2136: mouse_x += diffx;
2137: if (diffy > 127) diffy = 127;
2138: if (diffy < -127) diffy = -127;
2139: mouse_y += diffy;
2140: }
2141: lastsampledmx += diffx; lastsampledmy += diffy;
2142: break;
2143:
1.1.1.11 root 2144: case dont_care_mouse:
1.1.1.4 root 2145: diffx = adjust (((lastmx - lastspr0x) * mstepx) >> 16);
2146: diffy = adjust (((lastmy - lastspr0y) * mstepy) >> 16);
2147: lastspr0x = lastmx; lastspr0y = lastmy;
2148: mouse_x += diffx; mouse_y += diffy;
1.1.1.3 root 2149: break;
2150:
1.1.1.11 root 2151: case follow_mouse:
1.1.1.4 root 2152: if (sprvbfl && sprvbfl-- > 1) {
1.1.1.3 root 2153: int mousexpos, mouseypos;
2154:
1.1.1.4 root 2155: if ((lastdiffx > docal || lastdiffx < -docal)
2156: && lastspr0x != spr0x
2157: && spr0x > plfstrt*4 + 34 + xcaloff
2158: && spr0x < plfstop*4 - xcaloff)
1.1.1.3 root 2159: {
2160: int val = (lastdiffx << 16) / (spr0x - lastspr0x);
1.1.1.4 root 2161: if (val >= 0x8000)
2162: mstepx = (mstepx * (calweight - 1) + val) / calweight;
1.1.1.3 root 2163: }
1.1.1.4 root 2164: if ((lastdiffy > docal || lastdiffy < -docal)
2165: && lastspr0y != spr0y
2166: && spr0y > plffirstline + ycaloff
2167: && spr0y < plflastline - ycaloff)
1.1.1.3 root 2168: {
1.1.1.4 root 2169: int val = (lastdiffy << 16) / (spr0y - lastspr0y);
2170: if (val >= 0x8000)
2171: mstepy = (mstepy * (calweight - 1) + val) / calweight;
1.1.1.3 root 2172: }
2173: if (lastmy >= gfxvidinfo.height)
2174: lastmy = gfxvidinfo.height-1;
1.1.1.4 root 2175: mouseypos = coord_native_to_amiga_y (lastmy) << 1;
2176: mousexpos = coord_native_to_amiga_x (lastmx);
1.1.1.3 root 2177: diffx = adjust ((((mousexpos + xoffs - spr0x) & ~1) * mstepx) >> 16);
2178: diffy = adjust ((((mouseypos + yoffs - spr0y) & ~1) * mstepy) >> 16);
1.1.1.4 root 2179: lastspr0x = spr0x; lastspr0y = spr0y;
2180: lastdiffx = diffx; lastdiffy = diffy;
2181: mouse_x += diffx; mouse_y += diffy;
1.1.1.3 root 2182: }
2183: break;
1.1.1.4 root 2184:
1.1.1.11 root 2185: default:
1.1.1.4 root 2186: abort ();
1.1.1.3 root 2187: }
2188: }
2189:
1.1.1.20! root 2190: static void mousehack_handle (unsigned int ctl, unsigned int pos)
! 2191: {
! 2192: if (!sprvbfl && ((pos & 0xff) << 2) > 2 * DISPLAY_LEFT_SHIFT) {
! 2193: spr0ctl = ctl;
! 2194: spr0pos = pos;
! 2195: sprvbfl = 2;
! 2196: }
! 2197: }
! 2198:
1.1.1.7 root 2199: static int timehack_alive = 0;
2200:
2201: static uae_u32 timehack_helper (void)
2202: {
2203: #ifdef HAVE_GETTIMEOFDAY
2204: struct timeval tv;
2205: if (m68k_dreg (regs, 0) == 0)
2206: return timehack_alive;
2207:
2208: timehack_alive = 10;
2209:
2210: gettimeofday (&tv, NULL);
2211: put_long (m68k_areg (regs, 0), tv.tv_sec - (((365 * 8 + 2) * 24 - 2) * 60 * 60));
2212: put_long (m68k_areg (regs, 0) + 4, tv.tv_usec);
2213: return 0;
2214: #else
2215: return 2;
2216: #endif
2217: }
2218:
1.1.1.3 root 2219: /*
1.1 root 2220: * register functions
2221: */
1.1.1.8 root 2222: STATIC_INLINE uae_u16 DENISEID (void)
1.1.1.7 root 2223: {
2224: if (currprefs.chipset_mask & CSMASK_AGA)
2225: return 0xF8;
2226: if (currprefs.chipset_mask & CSMASK_ECS_DENISE)
2227: return 0xFC;
2228: return 0xFFFF;
2229: }
1.1.1.8 root 2230: STATIC_INLINE uae_u16 DMACONR (void)
1.1 root 2231: {
2232: return (dmacon | (bltstate==BLT_done ? 0 : 0x4000)
2233: | (blt_info.blitzero ? 0x2000 : 0));
2234: }
1.1.1.8 root 2235: STATIC_INLINE uae_u16 INTENAR (void)
1.1.1.4 root 2236: {
2237: return intena;
2238: }
2239: uae_u16 INTREQR (void)
1.1 root 2240: {
1.1.1.9 root 2241: return intreq /* | (currprefs.use_serial ? 0x0001 : 0) */;
1.1 root 2242: }
1.1.1.8 root 2243: STATIC_INLINE uae_u16 ADKCONR (void)
1.1.1.4 root 2244: {
2245: return adkcon;
2246: }
1.1.1.8 root 2247: STATIC_INLINE uae_u16 VPOSR (void)
1.1 root 2248: {
1.1.1.14 root 2249: unsigned int csbit = currprefs.ntscmode ? 0x1000 : 0;
1.1.1.7 root 2250: csbit |= (currprefs.chipset_mask & CSMASK_AGA) ? 0x2300 : 0;
2251: csbit |= (currprefs.chipset_mask & CSMASK_ECS_AGNUS) ? 0x2000 : 0;
2252: return (vpos >> 8) | lof | csbit;
1.1 root 2253: }
1.1.1.4 root 2254: static void VPOSW (uae_u16 v)
1.1.1.2 root 2255: {
2256: if (lof != (v & 0x8000))
2257: lof_changed = 1;
2258: lof = v & 0x8000;
1.1.1.3 root 2259: /*
2260: * This register is much more fun on a real Amiga. You can program
2261: * refresh rates with it ;) But I won't emulate this...
2262: */
1.1.1.2 root 2263: }
1.1 root 2264:
1.1.1.8 root 2265: STATIC_INLINE uae_u16 VHPOSR (void)
1.1.1.4 root 2266: {
1.1.1.13 root 2267: return (vpos << 8) | current_hpos ();
1.1.1.4 root 2268: }
2269:
1.1.1.8 root 2270: STATIC_INLINE void COP1LCH (uae_u16 v) { cop1lc = (cop1lc & 0xffff) | ((uae_u32)v << 16); }
2271: STATIC_INLINE void COP1LCL (uae_u16 v) { cop1lc = (cop1lc & ~0xffff) | (v & 0xfffe); }
2272: STATIC_INLINE void COP2LCH (uae_u16 v) { cop2lc = (cop2lc & 0xffff) | ((uae_u32)v << 16); }
2273: STATIC_INLINE void COP2LCL (uae_u16 v) { cop2lc = (cop2lc & ~0xffff) | (v & 0xfffe); }
1.1.1.4 root 2274:
1.1.1.9 root 2275: static void start_copper (void)
1.1.1.4 root 2276: {
1.1.1.10 root 2277: int was_active = eventtab[ev_copper].active;
2278: eventtab[ev_copper].active = 0;
2279: if (was_active)
2280: events_schedule ();
2281:
1.1.1.4 root 2282: cop_state.ignore_next = 0;
2283: cop_state.state = COP_read1;
2284: cop_state.vpos = vpos;
2285: cop_state.hpos = current_hpos () & ~1;
1.1.1.9 root 2286:
1.1.1.10 root 2287: if (dmaen (DMA_COPPER)) {
2288: copper_enabled_thisline = 1;
1.1.1.13 root 2289: set_special (SPCFLAG_COPPER);
1.1.1.10 root 2290: }
1.1.1.9 root 2291: }
2292:
2293: static void COPJMP1 (uae_u16 a)
2294: {
2295: cop_state.ip = cop1lc;
2296: start_copper ();
1.1.1.4 root 2297: }
2298:
2299: static void COPJMP2 (uae_u16 a)
2300: {
2301: cop_state.ip = cop2lc;
1.1.1.9 root 2302: start_copper ();
1.1.1.4 root 2303: }
2304:
1.1.1.8 root 2305: STATIC_INLINE void COPCON (uae_u16 a)
1.1.1.4 root 2306: {
2307: copcon = a;
1.1 root 2308: }
1.1.1.4 root 2309:
1.1.1.13 root 2310: static void DMACON (int hpos, uae_u16 v)
1.1 root 2311: {
1.1.1.14 root 2312: int i;
1.1 root 2313:
1.1.1.3 root 2314: uae_u16 oldcon = dmacon;
2315:
1.1.1.13 root 2316: decide_line (hpos);
2317: decide_fetch (hpos);
2318:
2319: setclr (&dmacon, v);
2320: dmacon &= 0x1FFF;
1.1.1.3 root 2321:
2322: /* FIXME? Maybe we need to think a bit more about the master DMA enable
1.1 root 2323: * bit in these cases. */
1.1.1.10 root 2324: if ((dmacon & DMA_COPPER) != (oldcon & DMA_COPPER)) {
2325: eventtab[ev_copper].active = 0;
2326: }
1.1.1.3 root 2327: if ((dmacon & DMA_COPPER) > (oldcon & DMA_COPPER)) {
1.1.1.4 root 2328: cop_state.ip = cop1lc;
2329: cop_state.ignore_next = 0;
2330: cop_state.state = COP_read1;
2331: cop_state.vpos = vpos;
1.1.1.13 root 2332: cop_state.hpos = hpos & ~1;
1.1.1.10 root 2333: copper_enabled_thisline = 1;
1.1.1.13 root 2334: set_special (SPCFLAG_COPPER);
1.1 root 2335: }
1.1.1.9 root 2336: if (! (dmacon & DMA_COPPER)) {
1.1.1.10 root 2337: copper_enabled_thisline = 0;
1.1.1.13 root 2338: unset_special (SPCFLAG_COPPER);
1.1.1.9 root 2339: cop_state.state = COP_stop;
2340: }
2341:
1.1 root 2342: if ((dmacon & DMA_BLITPRI) > (oldcon & DMA_BLITPRI) && bltstate != BLT_done) {
2343: static int count = 0;
2344: if (!count) {
2345: count = 1;
1.1.1.3 root 2346: write_log ("warning: program is doing blitpri hacks.\n");
1.1 root 2347: }
1.1.1.13 root 2348: set_special (SPCFLAG_BLTNASTY);
1.1 root 2349: }
1.1.1.10 root 2350: if ((dmacon & (DMA_BLITPRI | DMA_BLITTER | DMA_MASTER)) != (DMA_BLITPRI | DMA_BLITTER | DMA_MASTER))
1.1.1.13 root 2351: unset_special (SPCFLAG_BLTNASTY);
1.1.1.4 root 2352:
1.1.1.14 root 2353: if (currprefs.produce_sound > 0) {
2354: update_audio ();
1.1.1.3 root 2355:
1.1.1.14 root 2356: for (i = 0; i < 4; i++) {
2357: struct audio_channel_data *cdp = audio_channel + i;
2358: int chan_ena = (dmacon & 0x200) && (dmacon & (1<<i));
2359: if (cdp->dmaen == chan_ena)
2360: continue;
2361: cdp->dmaen = chan_ena;
1.1.1.17 root 2362: if (cdp->dmaen)
2363: audio_channel_enable_dma (cdp);
2364: else
2365: audio_channel_disable_dma (cdp);
1.1 root 2366: }
1.1.1.14 root 2367: schedule_audio ();
1.1 root 2368: }
1.1.1.14 root 2369: events_schedule();
1.1 root 2370: }
1.1.1.2 root 2371:
1.1.1.3 root 2372: /*static int trace_intena = 0;*/
1.1.1.2 root 2373:
1.1.1.8 root 2374: STATIC_INLINE void INTENA (uae_u16 v)
1.1.1.2 root 2375: {
1.1.1.3 root 2376: /* if (trace_intena)
1.1.1.18 root 2377: write_log ("INTENA: %04x\n", v);*/
1.1.1.13 root 2378: setclr (&intena,v);
1.1.1.15 root 2379: /* There's stupid code out there that does
1.1.1.20! root 2380: [some INTREQ bits at level 3 are set]
1.1.1.15 root 2381: clear all INTREQ bits
2382: Enable one INTREQ level 3 bit
2383: Set level 3 handler
2384:
2385: If we set SPCFLAG_INT for the clear, then by the time the enable happens,
2386: we'll have SPCFLAG_DOINT set, and the interrupt happens immediately, but
2387: it needs to happen one insn later, when the new L3 handler has been
2388: installed. */
2389: if (v & 0x8000)
2390: set_special (SPCFLAG_INT);
2391: }
2392:
2393: void INTREQ_0 (uae_u16 v)
2394: {
2395: setclr (&intreq,v);
1.1.1.13 root 2396: set_special (SPCFLAG_INT);
1.1.1.2 root 2397: }
1.1.1.15 root 2398:
1.1.1.3 root 2399: void INTREQ (uae_u16 v)
1.1 root 2400: {
1.1.1.15 root 2401: INTREQ_0 (v);
1.1.1.13 root 2402: if ((v & 0x8800) == 0x0800)
1.1.1.4 root 2403: serdat &= 0xbfff;
1.1.1.15 root 2404: rethink_cias ();
1.1.1.3 root 2405: }
1.1 root 2406:
1.1.1.15 root 2407: static void update_adkmasks (void)
1.1.1.3 root 2408: {
2409: unsigned long t;
1.1.1.4 root 2410:
1.1.1.3 root 2411: t = adkcon | (adkcon >> 4);
2412: audio_channel[0].adk_mask = (((t >> 0) & 1) - 1);
2413: audio_channel[1].adk_mask = (((t >> 1) & 1) - 1);
2414: audio_channel[2].adk_mask = (((t >> 2) & 1) - 1);
2415: audio_channel[3].adk_mask = (((t >> 3) & 1) - 1);
2416: }
1.1 root 2417:
1.1.1.15 root 2418: static void ADKCON (uae_u16 v)
2419: {
2420: if (currprefs.produce_sound > 0)
2421: update_audio ();
2422:
2423: setclr (&adkcon,v);
2424: update_adkmasks ();
2425: }
2426:
1.1.1.7 root 2427: static void BEAMCON0 (uae_u16 v)
2428: {
1.1.1.18 root 2429: if (currprefs.chipset_mask & CSMASK_ECS_AGNUS)
2430: new_beamcon0 = v & 0x20;
1.1.1.7 root 2431: }
2432:
1.1.1.4 root 2433: static void BPLPTH (int hpos, uae_u16 v, int num)
1.1.1.3 root 2434: {
1.1.1.4 root 2435: decide_line (hpos);
1.1.1.13 root 2436: decide_fetch (hpos);
1.1.1.4 root 2437: bplpt[num] = (bplpt[num] & 0xffff) | ((uae_u32)v << 16);
1.1.1.3 root 2438: }
1.1.1.4 root 2439: static void BPLPTL (int hpos, uae_u16 v, int num)
1.1.1.3 root 2440: {
1.1.1.4 root 2441: decide_line (hpos);
1.1.1.13 root 2442: decide_fetch (hpos);
1.1.1.4 root 2443: bplpt[num] = (bplpt[num] & ~0xffff) | (v & 0xfffe);
1.1.1.3 root 2444: }
1.1 root 2445:
1.1.1.4 root 2446: static void BPLCON0 (int hpos, uae_u16 v)
1.1 root 2447: {
1.1.1.15 root 2448: if (! (currprefs.chipset_mask & CSMASK_ECS_DENISE))
2449: v &= ~0x00F1;
2450: else if (! (currprefs.chipset_mask & CSMASK_AGA))
2451: v &= ~0x00B1;
1.1.1.14 root 2452:
1.1.1.2 root 2453: if (bplcon0 == v)
1.1 root 2454: return;
1.1.1.4 root 2455: decide_line (hpos);
1.1.1.13 root 2456: decide_fetch (hpos);
2457:
1.1.1.18 root 2458: /* HAM change? */
2459: if ((bplcon0 ^ v) & 0x800) {
2460: record_color_change (hpos, -1, !! (v & 0x800));
2461: }
2462:
1.1.1.2 root 2463: bplcon0 = v;
1.1.1.16 root 2464: curr_diagram = cycle_diagram_table[fetchmode][GET_RES(bplcon0)][GET_PLANES (v)];
1.1.1.15 root 2465:
2466: if (currprefs.chipset_mask & CSMASK_AGA) {
2467: decide_sprites (hpos);
2468: expand_sprres ();
2469: }
2470:
1.1.1.14 root 2471: expand_fmodes ();
1.1 root 2472: }
1.1.1.9 root 2473:
1.1.1.8 root 2474: STATIC_INLINE void BPLCON1 (int hpos, uae_u16 v)
1.1 root 2475: {
1.1.1.2 root 2476: if (bplcon1 == v)
1.1 root 2477: return;
1.1.1.13 root 2478: decide_line (hpos);
2479: decide_fetch (hpos);
1.1.1.2 root 2480: bplcon1 = v;
1.1 root 2481: }
1.1.1.15 root 2482:
1.1.1.8 root 2483: STATIC_INLINE void BPLCON2 (int hpos, uae_u16 v)
1.1 root 2484: {
1.1.1.7 root 2485: if (bplcon2 == v)
2486: return;
2487: decide_line (hpos);
1.1.1.2 root 2488: bplcon2 = v;
1.1 root 2489: }
1.1.1.15 root 2490:
1.1.1.8 root 2491: STATIC_INLINE void BPLCON3 (int hpos, uae_u16 v)
1.1 root 2492: {
1.1.1.14 root 2493: if (! (currprefs.chipset_mask & CSMASK_AGA))
2494: return;
1.1.1.7 root 2495: if (bplcon3 == v)
2496: return;
2497: decide_line (hpos);
1.1.1.15 root 2498: decide_sprites (hpos);
1.1.1.3 root 2499: bplcon3 = v;
1.1.1.15 root 2500: expand_sprres ();
1.1 root 2501: }
1.1.1.15 root 2502:
1.1.1.8 root 2503: STATIC_INLINE void BPLCON4 (int hpos, uae_u16 v)
1.1 root 2504: {
1.1.1.7 root 2505: if (! (currprefs.chipset_mask & CSMASK_AGA))
2506: return;
2507: if (bplcon4 == v)
2508: return;
2509: decide_line (hpos);
1.1.1.3 root 2510: bplcon4 = v;
1.1 root 2511: }
2512:
1.1.1.4 root 2513: static void BPL1MOD (int hpos, uae_u16 v)
1.1 root 2514: {
2515: v &= ~1;
1.1.1.3 root 2516: if ((uae_s16)bpl1mod == (uae_s16)v)
1.1 root 2517: return;
1.1.1.13 root 2518: decide_line (hpos);
2519: decide_fetch (hpos);
1.1 root 2520: bpl1mod = v;
2521: }
1.1.1.2 root 2522:
1.1.1.4 root 2523: static void BPL2MOD (int hpos, uae_u16 v)
1.1.1.3 root 2524: {
1.1 root 2525: v &= ~1;
1.1.1.3 root 2526: if ((uae_s16)bpl2mod == (uae_s16)v)
1.1 root 2527: return;
1.1.1.13 root 2528: decide_line (hpos);
2529: decide_fetch (hpos);
1.1 root 2530: bpl2mod = v;
2531: }
2532:
1.1.1.13 root 2533: STATIC_INLINE void BPL1DAT (int hpos, uae_u16 v)
1.1.1.10 root 2534: {
1.1.1.13 root 2535: decide_line (hpos);
1.1.1.10 root 2536: bpl1dat = v;
1.1.1.13 root 2537:
2538: maybe_first_bpl1dat (hpos);
1.1.1.10 root 2539: }
1.1.1.2 root 2540: /* We could do as well without those... */
1.1.1.8 root 2541: STATIC_INLINE void BPL2DAT (uae_u16 v) { bpl2dat = v; }
2542: STATIC_INLINE void BPL3DAT (uae_u16 v) { bpl3dat = v; }
2543: STATIC_INLINE void BPL4DAT (uae_u16 v) { bpl4dat = v; }
2544: STATIC_INLINE void BPL5DAT (uae_u16 v) { bpl5dat = v; }
2545: STATIC_INLINE void BPL6DAT (uae_u16 v) { bpl6dat = v; }
2546: STATIC_INLINE void BPL7DAT (uae_u16 v) { bpl7dat = v; }
2547: STATIC_INLINE void BPL8DAT (uae_u16 v) { bpl8dat = v; }
1.1 root 2548:
1.1.1.4 root 2549: static void DIWSTRT (int hpos, uae_u16 v)
1.1 root 2550: {
1.1.1.4 root 2551: if (diwstrt == v && ! diwhigh_written)
1.1 root 2552: return;
1.1.1.4 root 2553: decide_line (hpos);
2554: diwhigh_written = 0;
1.1.1.3 root 2555: diwstrt = v;
1.1.1.4 root 2556: calcdiw ();
1.1 root 2557: }
1.1.1.4 root 2558:
2559: static void DIWSTOP (int hpos, uae_u16 v)
1.1 root 2560: {
1.1.1.4 root 2561: if (diwstop == v && ! diwhigh_written)
1.1 root 2562: return;
1.1.1.4 root 2563: decide_line (hpos);
2564: diwhigh_written = 0;
1.1.1.3 root 2565: diwstop = v;
1.1.1.4 root 2566: calcdiw ();
2567: }
2568:
2569: static void DIWHIGH (int hpos, uae_u16 v)
2570: {
1.1.1.7 root 2571: if (! (currprefs.chipset_mask & CSMASK_ECS_DENISE))
2572: return;
1.1.1.4 root 2573: if (diwhigh_written && diwhigh == v)
2574: return;
2575: decide_line (hpos);
2576: diwhigh_written = 1;
2577: diwhigh = v;
2578: calcdiw ();
1.1 root 2579: }
1.1.1.4 root 2580:
2581: static void DDFSTRT (int hpos, uae_u16 v)
1.1.1.3 root 2582: {
1.1.1.11 root 2583: v &= 0xFC;
1.1.1.2 root 2584: if (ddfstrt == v)
1.1 root 2585: return;
1.1.1.4 root 2586: decide_line (hpos);
1.1.1.3 root 2587: ddfstrt = v;
1.1.1.4 root 2588: calcdiw ();
1.1.1.15 root 2589: if (ddfstop > 0xD4 && (ddfstrt & 4) == 4) {
2590: static int last_warned;
2591: last_warned = (last_warned + 1) & 4095;
2592: if (last_warned == 0)
2593: write_log ("WARNING! Very strange DDF values.\n");
2594: }
1.1 root 2595: }
1.1.1.15 root 2596:
1.1.1.4 root 2597: static void DDFSTOP (int hpos, uae_u16 v)
1.1.1.3 root 2598: {
1.1.1.15 root 2599: /* ??? "Virtual Meltdown" sets this to 0xD2 and expects it to behave
2600: differently from 0xD0. RSI Megademo sets it to 0xd1 and expects it
1.1.1.16 root 2601: to behave like 0xd0. Some people also write the high 8 bits and
2602: expect them to be ignored. So mask it with 0xFE. */
2603: v &= 0xFE;
1.1.1.2 root 2604: if (ddfstop == v)
1.1 root 2605: return;
1.1.1.4 root 2606: decide_line (hpos);
1.1.1.13 root 2607: decide_fetch (hpos);
1.1.1.2 root 2608: ddfstop = v;
1.1.1.4 root 2609: calcdiw ();
1.1.1.13 root 2610: if (fetch_state != fetch_not_started)
2611: estimate_last_fetch_cycle (hpos);
1.1.1.15 root 2612: if (ddfstop > 0xD4 && (ddfstrt & 4) == 4) {
2613: static int last_warned;
2614: last_warned = (last_warned + 1) & 4095;
2615: if (last_warned == 0)
2616: write_log ("WARNING! Very strange DDF values.\n");
1.1.1.14 root 2617: write_log ("WARNING! Very strange DDF values.\n");
1.1.1.15 root 2618: }
1.1 root 2619: }
2620:
1.1.1.7 root 2621: static void FMODE (uae_u16 v)
2622: {
2623: if (! (currprefs.chipset_mask & CSMASK_AGA))
1.1.1.14 root 2624: v = 0;
1.1.1.13 root 2625:
1.1.1.7 root 2626: fmode = v;
1.1.1.14 root 2627: sprite_width = GET_SPRITEWIDTH (fmode);
2628: switch (fmode & 3) {
2629: case 0:
2630: fetchmode = 0;
2631: break;
2632: case 1:
2633: case 2:
2634: fetchmode = 1;
2635: break;
2636: case 3:
2637: fetchmode = 2;
2638: break;
2639: }
1.1.1.16 root 2640: curr_diagram = cycle_diagram_table[fetchmode][GET_RES (v)][GET_PLANES (bplcon0)];
1.1.1.14 root 2641: expand_fmodes ();
1.1.1.7 root 2642: }
2643:
1.1.1.4 root 2644: static void BLTADAT (uae_u16 v)
1.1 root 2645: {
1.1.1.19 root 2646: maybe_blit (0);
1.1.1.2 root 2647:
2648: blt_info.bltadat = v;
1.1 root 2649: }
1.1.1.2 root 2650: /*
2651: * "Loading data shifts it immediately" says the HRM. Well, that may
2652: * be true for BLTBDAT, but not for BLTADAT - it appears the A data must be
2653: * loaded for every word so that AFWM and ALWM can be applied.
2654: */
1.1.1.4 root 2655: static void BLTBDAT (uae_u16 v)
1.1 root 2656: {
1.1.1.19 root 2657: maybe_blit (0);
1.1.1.2 root 2658:
2659: if (bltcon1 & 2)
2660: blt_info.bltbhold = v << (bltcon1 >> 12);
2661: else
2662: blt_info.bltbhold = v >> (bltcon1 >> 12);
2663: blt_info.bltbdat = v;
1.1 root 2664: }
1.1.1.19 root 2665: static void BLTCDAT (uae_u16 v) { maybe_blit (0); blt_info.bltcdat = v; }
1.1 root 2666:
1.1.1.19 root 2667: static void BLTAMOD (uae_u16 v) { maybe_blit (1); blt_info.bltamod = (uae_s16)(v & 0xFFFE); }
2668: static void BLTBMOD (uae_u16 v) { maybe_blit (1); blt_info.bltbmod = (uae_s16)(v & 0xFFFE); }
2669: static void BLTCMOD (uae_u16 v) { maybe_blit (1); blt_info.bltcmod = (uae_s16)(v & 0xFFFE); }
2670: static void BLTDMOD (uae_u16 v) { maybe_blit (1); blt_info.bltdmod = (uae_s16)(v & 0xFFFE); }
1.1 root 2671:
1.1.1.19 root 2672: static void BLTCON0 (uae_u16 v) { maybe_blit (0); bltcon0 = v; blinea_shift = v >> 12; }
1.1.1.3 root 2673: /* The next category is "Most useless hardware register".
1.1 root 2674: * And the winner is... */
1.1.1.7 root 2675: static void BLTCON0L (uae_u16 v)
2676: {
2677: if (! (currprefs.chipset_mask & CSMASK_ECS_AGNUS))
2678: return;
1.1.1.19 root 2679: maybe_blit (0); bltcon0 = (bltcon0 & 0xFF00) | (v & 0xFF);
1.1.1.7 root 2680: }
1.1.1.19 root 2681: static void BLTCON1 (uae_u16 v) { maybe_blit (0); bltcon1 = v; }
1.1.1.4 root 2682:
1.1.1.19 root 2683: static void BLTAFWM (uae_u16 v) { maybe_blit (0); blt_info.bltafwm = v; }
2684: static void BLTALWM (uae_u16 v) { maybe_blit (0); blt_info.bltalwm = v; }
1.1 root 2685:
1.1.1.19 root 2686: static void BLTAPTH (uae_u16 v) { maybe_blit (0); bltapt = (bltapt & 0xffff) | ((uae_u32)v << 16); }
2687: static void BLTAPTL (uae_u16 v) { maybe_blit (0); bltapt = (bltapt & ~0xffff) | (v & 0xFFFE); }
2688: static void BLTBPTH (uae_u16 v) { maybe_blit (0); bltbpt = (bltbpt & 0xffff) | ((uae_u32)v << 16); }
2689: static void BLTBPTL (uae_u16 v) { maybe_blit (0); bltbpt = (bltbpt & ~0xffff) | (v & 0xFFFE); }
2690: static void BLTCPTH (uae_u16 v) { maybe_blit (0); bltcpt = (bltcpt & 0xffff) | ((uae_u32)v << 16); }
2691: static void BLTCPTL (uae_u16 v) { maybe_blit (0); bltcpt = (bltcpt & ~0xffff) | (v & 0xFFFE); }
2692: static void BLTDPTH (uae_u16 v) { maybe_blit (0); bltdpt = (bltdpt & 0xffff) | ((uae_u32)v << 16); }
2693: static void BLTDPTL (uae_u16 v) { maybe_blit (0); bltdpt = (bltdpt & ~0xffff) | (v & 0xFFFE); }
1.1 root 2694:
1.1.1.4 root 2695: static void BLTSIZE (uae_u16 v)
1.1 root 2696: {
1.1.1.19 root 2697: maybe_blit (0);
1.1 root 2698:
1.1.1.15 root 2699: blt_info.vblitsize = v >> 6;
2700: blt_info.hblitsize = v & 0x3F;
1.1 root 2701: if (!blt_info.vblitsize) blt_info.vblitsize = 1024;
2702: if (!blt_info.hblitsize) blt_info.hblitsize = 64;
1.1.1.3 root 2703:
2704: bltstate = BLT_init;
1.1.1.4 root 2705: do_blitter ();
1.1 root 2706: }
1.1.1.4 root 2707:
2708: static void BLTSIZV (uae_u16 v)
1.1 root 2709: {
1.1.1.7 root 2710: if (! (currprefs.chipset_mask & CSMASK_ECS_AGNUS))
2711: return;
1.1.1.19 root 2712: maybe_blit (0);
1.1 root 2713: oldvblts = v & 0x7FFF;
2714: }
1.1.1.4 root 2715:
2716: static void BLTSIZH (uae_u16 v)
1.1 root 2717: {
1.1.1.7 root 2718: if (! (currprefs.chipset_mask & CSMASK_ECS_AGNUS))
2719: return;
1.1.1.19 root 2720: maybe_blit (0);
1.1 root 2721: blt_info.hblitsize = v & 0x7FF;
2722: blt_info.vblitsize = oldvblts;
2723: if (!blt_info.vblitsize) blt_info.vblitsize = 32768;
2724: if (!blt_info.hblitsize) blt_info.hblitsize = 0x800;
1.1.1.2 root 2725: bltstate = BLT_init;
1.1.1.5 root 2726: do_blitter ();
1.1 root 2727: }
1.1.1.4 root 2728:
1.1.1.20! root 2729: STATIC_INLINE void SPRxCTL_1 (uae_u16 v, int num, int hpos)
1.1 root 2730: {
1.1.1.2 root 2731: int sprxp;
1.1.1.20! root 2732: struct sprite *s = &spr[num];
1.1.1.2 root 2733: sprctl[num] = v;
1.1.1.20! root 2734: nr_armed -= s->armed;
! 2735: s->armed = 0;
1.1.1.15 root 2736: sprxp = (sprpos[num] & 0xFF) * 2 + (v & 1);
2737:
2738: /* Quite a bit salad in this register... */
2739: if (currprefs.chipset_mask & CSMASK_AGA) {
2740: /* We ignore the SHRES 35ns increment for now; SHRES support doesn't
2741: work anyway, so we may as well restrict AGA sprites to a 70ns
2742: resolution. */
2743: sprxp <<= 1;
2744: sprxp |= (v >> 4) & 1;
2745: }
1.1.1.20! root 2746: s->xpos = sprxp;
! 2747: s->vstart = (sprpos[num] >> 8) | ((sprctl[num] << 6) & 0x100);
! 2748: s->vstop = (sprctl[num] >> 8) | ((sprctl[num] << 7) & 0x100);
! 2749: if (vpos == s->vstart)
! 2750: s->state = SPR_waiting_stop;
! 2751: #ifdef SPRITE_DEBUG
! 2752: write_log ("%d:%d:SPR%dCTL V=%04.4X STATE=%d ARMED=%d\n", vpos, hpos, num, v, s->state, s->armed);
! 2753: #endif
1.1.1.2 root 2754: }
1.1.1.20! root 2755: STATIC_INLINE void SPRxPOS_1 (uae_u16 v, int num, int hpos)
1.1.1.2 root 2756: {
2757: int sprxp;
1.1.1.20! root 2758: struct sprite *s = &spr[num];
1.1.1.2 root 2759: sprpos[num] = v;
1.1.1.15 root 2760: sprxp = (v & 0xFF) * 2 + (sprctl[num] & 1);
2761:
2762: if (currprefs.chipset_mask & CSMASK_AGA) {
2763: sprxp <<= 1;
2764: sprxp |= (sprctl[num] >> 4) & 1;
2765: }
1.1.1.20! root 2766: s->xpos = sprxp;
! 2767: s->vstart = (sprpos[num] >> 8) | ((sprctl[num] << 6) & 0x100);
! 2768: #ifdef SPRITE_DEBUG
! 2769: write_log ("%d:%d:SPR%dPOS %04.4X STATE=%d ARMED=%d\n", vpos, hpos, num, v, s->state, s->armed);
! 2770: #endif
1.1.1.2 root 2771: }
1.1.1.8 root 2772: STATIC_INLINE void SPRxDATA_1 (uae_u16 v, int num)
1.1.1.2 root 2773: {
1.1.1.15 root 2774: sprdata[num][0] = v;
1.1.1.10 root 2775: nr_armed += 1 - spr[num].armed;
2776: spr[num].armed = 1;
1.1.1.2 root 2777: }
1.1.1.8 root 2778: STATIC_INLINE void SPRxDATB_1 (uae_u16 v, int num)
1.1.1.2 root 2779: {
1.1.1.15 root 2780: sprdatb[num][0] = v;
1.1.1.2 root 2781: }
1.1.1.4 root 2782: static void SPRxDATA (int hpos, uae_u16 v, int num) { decide_sprites (hpos); SPRxDATA_1 (v, num); }
2783: static void SPRxDATB (int hpos, uae_u16 v, int num) { decide_sprites (hpos); SPRxDATB_1 (v, num); }
1.1.1.20! root 2784: static void SPRxCTL (int hpos, uae_u16 v, int num) { decide_sprites (hpos); SPRxCTL_1 (v, num, hpos); }
! 2785: static void SPRxPOS (int hpos, uae_u16 v, int num) { decide_sprites (hpos); SPRxPOS_1 (v, num, hpos); }
1.1.1.4 root 2786: static void SPRxPTH (int hpos, uae_u16 v, int num)
1.1 root 2787: {
1.1.1.4 root 2788: decide_sprites (hpos);
1.1.1.10 root 2789: spr[num].pt &= 0xffff;
2790: spr[num].pt |= (uae_u32)v << 16;
1.1.1.20! root 2791: #ifdef SPRITE_DEBUG
! 2792: write_log ("%d:%d:SPR%dPTH %08.8X\n", vpos, hpos, num, spr[num].pt);
! 2793: #endif
1.1 root 2794: }
1.1.1.4 root 2795: static void SPRxPTL (int hpos, uae_u16 v, int num)
1.1 root 2796: {
1.1.1.4 root 2797: decide_sprites (hpos);
1.1.1.10 root 2798: spr[num].pt &= ~0xffff;
2799: spr[num].pt |= v;
1.1.1.20! root 2800: #ifdef SPRITE_DEBUG
! 2801: write_log ("%d:%d:SPR%dPTL %08.8X\n", vpos, hpos, num, spr[num].pt);
! 2802: #endif
1.1.1.3 root 2803: }
1.1.1.20! root 2804:
1.1.1.4 root 2805: static void CLXCON (uae_u16 v)
1.1.1.3 root 2806: {
2807: clxcon = v;
1.1.1.14 root 2808: clxcon_bpl_enable = (v >> 6) & 63;
2809: clxcon_bpl_match = v & 63;
2810: clx_sprmask = ((((v >> 15) & 1) << 7) | (((v >> 14) & 1) << 5) | (((v >> 13) & 1) << 3) | (((v >> 12) & 1) << 1) | 0x55);
2811: }
2812: static void CLXCON2 (uae_u16 v)
2813: {
2814: if (!(currprefs.chipset_mask & CSMASK_AGA))
2815: return;
2816: clxcon2 = v;
2817: clxcon_bpl_enable |= v & (0x40|0x80);
2818: clxcon_bpl_match |= (v & (0x01|0x02)) << 6;
2819: }
1.1.1.4 root 2820: static uae_u16 CLXDAT (void)
1.1.1.3 root 2821: {
2822: uae_u16 v = clxdat;
2823: clxdat = 0;
2824: return v;
2825: }
1.1.1.11 root 2826:
1.1.1.13 root 2827: static uae_u16 COLOR_READ (int num)
1.1 root 2828: {
1.1.1.13 root 2829: int cr, cg, cb, colreg;
2830: uae_u16 cval;
2831:
2832: if (!(currprefs.chipset_mask & CSMASK_AGA) || !(bplcon2 & 0x0100))
2833: return 0xffff;
2834:
2835: colreg = ((bplcon3 >> 13) & 7) * 32 + num;
2836: cr = current_colors.color_regs_aga[colreg] >> 16;
2837: cg = (current_colors.color_regs_aga[colreg] >> 8) & 0xFF;
2838: cb = current_colors.color_regs_aga[colreg] & 0xFF;
2839: if (bplcon3 & 0x200)
1.1.1.16 root 2840: cval = ((cr & 15) << 8) | ((cg & 15) << 4) | ((cb & 15) << 0);
1.1.1.13 root 2841: else
1.1.1.16 root 2842: cval = ((cr >> 4) << 8) | ((cg >> 4) << 4) | ((cb >> 4) << 0);
1.1.1.13 root 2843: return cval;
2844: }
1.1.1.3 root 2845:
1.1.1.13 root 2846: static void COLOR_WRITE (int hpos, uae_u16 v, int num)
2847: {
1.1 root 2848: v &= 0xFFF;
1.1.1.11 root 2849: if (currprefs.chipset_mask & CSMASK_AGA) {
1.1.1.4 root 2850: int r,g,b;
2851: int cr,cg,cb;
2852: int colreg;
1.1.1.3 root 2853: uae_u32 cval;
1.1.1.4 root 2854:
1.1.1.11 root 2855: /* writing is disabled when RDRAM=1 */
1.1.1.13 root 2856: if (bplcon2 & 0x0100)
2857: return;
1.1.1.11 root 2858:
1.1.1.2 root 2859: colreg = ((bplcon3 >> 13) & 7) * 32 + num;
1.1 root 2860: r = (v & 0xF00) >> 8;
2861: g = (v & 0xF0) >> 4;
2862: b = (v & 0xF) >> 0;
1.1.1.11 root 2863: cr = current_colors.color_regs_aga[colreg] >> 16;
2864: cg = (current_colors.color_regs_aga[colreg] >> 8) & 0xFF;
2865: cb = current_colors.color_regs_aga[colreg] & 0xFF;
1.1 root 2866:
1.1.1.2 root 2867: if (bplcon3 & 0x200) {
1.1 root 2868: cr &= 0xF0; cr |= r;
2869: cg &= 0xF0; cg |= g;
2870: cb &= 0xF0; cb |= b;
2871: } else {
2872: cr = r + (r << 4);
2873: cg = g + (g << 4);
2874: cb = b + (b << 4);
2875: }
2876: cval = (cr << 16) | (cg << 8) | cb;
1.1.1.11 root 2877: if (cval == current_colors.color_regs_aga[colreg])
1.1 root 2878: return;
1.1.1.5 root 2879:
2880: /* Call this with the old table still intact. */
1.1.1.11 root 2881: record_color_change (hpos, colreg, cval);
1.1.1.5 root 2882: remembered_color_entry = -1;
1.1.1.11 root 2883: current_colors.color_regs_aga[colreg] = cval;
2884: current_colors.acolors[colreg] = CONVERT_RGB (cval);
2885: } else {
2886: if (current_colors.color_regs_ecs[num] == v)
1.1 root 2887: return;
1.1.1.2 root 2888: /* Call this with the old table still intact. */
1.1.1.4 root 2889: record_color_change (hpos, num, v);
1.1.1.2 root 2890: remembered_color_entry = -1;
1.1.1.11 root 2891: current_colors.color_regs_ecs[num] = v;
1.1.1.2 root 2892: current_colors.acolors[num] = xcolors[v];
1.1 root 2893: }
2894: }
1.1.1.3 root 2895:
2896: static uae_u16 potgo_value;
2897:
1.1.1.4 root 2898: static void POTGO (uae_u16 v)
1.1 root 2899: {
1.1.1.3 root 2900: potgo_value = v;
2901: }
2902:
1.1.1.4 root 2903: static uae_u16 POTGOR (void)
1.1.1.3 root 2904: {
1.1.1.11 root 2905: uae_u16 v = (potgo_value | (potgo_value >> 1)) & 0x5500;
2906:
2907: v |= (~potgo_value & 0xAA00) >> 1;
1.1.1.3 root 2908:
1.1.1.6 root 2909: if (JSEM_ISMOUSE (0, &currprefs)) {
1.1.1.3 root 2910: if (buttonstate[2])
2911: v &= 0xFBFF;
2912:
2913: if (buttonstate[1])
2914: v &= 0xFEFF;
1.1.1.6 root 2915: } else if (JSEM_ISJOY0 (0, &currprefs) || JSEM_ISJOY1 (0, &currprefs)) {
1.1.1.3 root 2916: if (joy0button & 2) v &= 0xfbff;
2917: if (joy0button & 4) v &= 0xfeff;
2918: }
2919:
1.1.1.6 root 2920: if (JSEM_ISJOY0 (1, &currprefs) || JSEM_ISJOY1 (1, &currprefs)) {
1.1.1.3 root 2921: if (joy1button & 2) v &= 0xbfff;
2922: if (joy1button & 4) v &= 0xefff;
2923: }
1.1 root 2924:
2925: return v;
2926: }
1.1.1.4 root 2927:
2928: static uae_u16 POT0DAT (void)
1.1 root 2929: {
1.1.1.3 root 2930: static uae_u16 cnt = 0;
1.1.1.6 root 2931: if (JSEM_ISMOUSE (0, &currprefs)) {
1.1.1.3 root 2932: if (buttonstate[2])
2933: cnt = ((cnt + 1) & 0xFF) | (cnt & 0xFF00);
2934: if (buttonstate[1])
2935: cnt += 0x100;
2936: }
2937:
1.1 root 2938: return cnt;
2939: }
1.1.1.4 root 2940: static uae_u16 JOY0DAT (void)
1.1 root 2941: {
1.1.1.6 root 2942: if (JSEM_ISMOUSE (0, &currprefs)) {
1.1.1.4 root 2943: do_mouse_hack ();
1.1.1.3 root 2944: return ((uae_u8)mouse_x) + ((uae_u16)mouse_y << 8);
2945: }
1.1 root 2946: return joy0dir;
2947: }
1.1.1.4 root 2948: static uae_u16 JOY1DAT (void)
1.1 root 2949: {
1.1.1.6 root 2950: if (JSEM_ISMOUSE (1, &currprefs)) {
1.1.1.4 root 2951: do_mouse_hack ();
1.1.1.3 root 2952: return ((uae_u8)mouse_x) + ((uae_u16)mouse_y << 8);
2953: }
2954: return joy1dir;
1.1 root 2955: }
1.1.1.4 root 2956: static void JOYTEST (uae_u16 v)
1.1 root 2957: {
1.1.1.6 root 2958: if (JSEM_ISMOUSE (0, &currprefs)) {
1.1.1.3 root 2959: mouse_x = v & 0xFC;
2960: mouse_y = (v >> 8) & 0xFC;
1.1 root 2961: }
2962: }
2963:
1.1.1.15 root 2964: /* The copper code. The biggest nightmare in the whole emulator.
2965:
2966: Alright. The current theory:
1.1.1.20! root 2967: 1. Copper moves happen 2 cycles after state READ2 is reached.
1.1.1.15 root 2968: It can't happen immediately when we reach READ2, because the
1.1.1.20! root 2969: data needs time to get back from the bus. An additional 2
! 2970: cycles are needed for non-Agnus registers, to take into account
! 2971: the delay for moving data from chip to chip.
1.1.1.15 root 2972: 2. As stated in the HRM, a WAIT really does need an extra cycle
2973: to wake up. This is implemented by _not_ falling through from
2974: a successful wait to READ1, but by starting the next cycle.
2975: (Note: the extra cycle for the WAIT apparently really needs a
2976: free cycle; i.e. contention with the bitplane fetch can slow
2977: it down).
2978: 3. Apparently, to compensate for the extra wake up cycle, a WAIT
2979: will use the _incremented_ horizontal position, so the WAIT
2980: cycle normally finishes two clocks earlier than the position
2981: it was waiting for. The extra cycle then takes us to the
2982: position that was waited for.
2983: If the earlier cycle is busy with a bitplane, things change a bit.
2984: E.g., waiting for position 0x50 in a 6 plane display: In cycle
2985: 0x4e, we fetch BPL5, so the wait wakes up in 0x50, the extra cycle
2986: takes us to 0x54 (since 0x52 is busy), then we have READ1/READ2,
2987: and the next register write is at 0x5c.
2988: 4. The last cycle in a line is not usable for the copper.
2989: 5. A 4 cycle delay also applies to the WAIT instruction. This means
2990: that the second of two back-to-back WAITs (or a WAIT whose
2991: condition is immediately true) takes 8 cycles.
2992: 6. This also applies to a SKIP instruction. The copper does not
2993: fetch the next instruction while waiting for the second word of
2994: a WAIT or a SKIP to arrive.
2995: 7. A SKIP also seems to need an unexplained additional two cycles
2996: after its second word arrives; this is _not_ a memory cycle (I
2997: think, the documentation is pretty clear on this).
2998: 8. Two additional cycles are inserted when writing to COPJMP1/2. */
2999:
1.1.1.4 root 3000: /* Determine which cycles are available for the copper in a display
3001: * with a agiven number of planes. */
1.1.1.2 root 3002:
1.1.1.16 root 3003: STATIC_INLINE int copper_cant_read (int hpos)
1.1 root 3004: {
1.1.1.4 root 3005: int t;
1.1.1.2 root 3006:
1.1.1.15 root 3007: if (hpos + 1 >= maxhpos)
1.1.1.2 root 3008: return 1;
1.1.1.3 root 3009:
1.1.1.15 root 3010: if (fetch_state == fetch_not_started || hpos < thisline_decision.plfleft)
3011: return 0;
3012:
3013: if ((passed_plfstop == 3 && hpos >= thisline_decision.plfright)
3014: || hpos >= estimated_last_fetch_cycle)
1.1.1.4 root 3015: return 0;
1.1.1.3 root 3016:
1.1.1.16 root 3017: t = curr_diagram[(hpos + cycle_diagram_shift) & fetchstart_mask];
1.1.1.4 root 3018: #if 0
3019: if (t == -1)
3020: abort ();
3021: #endif
3022: return t;
1.1.1.2 root 3023: }
3024:
1.1.1.10 root 3025: STATIC_INLINE int dangerous_reg (int reg)
3026: {
3027: /* Safe:
3028: * Bitplane pointers, control registers, modulos and data.
3029: * Sprite pointers, control registers, and data.
3030: * Color registers. */
3031: if (reg >= 0xE0 && reg < 0x1C0)
3032: return 0;
3033: return 1;
3034: }
3035:
1.1.1.15 root 3036: #define FAST_COPPER 1
3037:
3038: /* The future, Conan?
3039: We try to look ahead in the copper list to avoid doing continuous calls
3040: to updat_copper (which is what happens when SPCFLAG_COPPER is set). If
3041: we find that the same effect can be achieved by setting a delayed event
3042: and then doing multiple copper insns in one batch, we can get a massive
3043: speedup.
3044:
3045: We don't try to be precise here. All copper reads take exactly 2 cycles,
3046: the effect of bitplane contention is ignored. Trying to get it exactly
3047: right would be much more complex and as such carry a huge risk of getting
3048: it subtly wrong; and it would also be more expensive - we want this code
3049: to be fast. */
3050: static void predict_copper (void)
3051: {
3052: uaecptr ip = cop_state.ip;
3053: unsigned int c_hpos = cop_state.hpos;
3054: enum copper_states state = cop_state.state;
3055: unsigned int w1, w2, cycle_count;
3056:
3057: switch (state) {
3058: case COP_read1_wr_in2:
3059: case COP_read2_wr_in2:
3060: case COP_read1_wr_in4:
3061: if (dangerous_reg (cop_state.saved_i1))
3062: return;
3063: state = state == COP_read2_wr_in2 ? COP_read2 : COP_read1;
3064: break;
3065:
3066: case COP_read1_in2:
3067: c_hpos += 2;
3068: state = COP_read1;
3069: break;
3070:
3071: case COP_stop:
3072: case COP_bltwait:
3073: case COP_wait1:
3074: case COP_skip_in4:
3075: case COP_skip_in2:
3076: return;
3077:
3078: case COP_wait_in4:
3079: c_hpos += 2;
3080: /* fallthrough */
3081: case COP_wait_in2:
3082: c_hpos += 2;
3083: /* fallthrough */
3084: case COP_wait:
3085: state = COP_wait;
3086: break;
3087:
3088: default:
3089: break;
3090: }
3091: /* Only needed for COP_wait, but let's shut up the compiler. */
3092: w1 = cop_state.saved_i1;
3093: w2 = cop_state.saved_i2;
3094: cop_state.first_sync = c_hpos;
3095: cop_state.regtypes_modified = REGTYPE_FORCE;
3096:
3097: /* Get this case out of the way, so that the loop below only has to deal
3098: with read1 and wait. */
3099: if (state == COP_read2) {
3100: w1 = cop_state.i1;
3101: if (w1 & 1) {
3102: w2 = chipmem_wget (ip);
3103: if (w2 & 1)
3104: goto done;
3105: state = COP_wait;
3106: c_hpos += 4;
3107: } else if (dangerous_reg (w1)) {
3108: c_hpos += 4;
3109: goto done;
3110: } else {
3111: cop_state.regtypes_modified |= regtypes[w1 & 0x1FE];
3112: state = COP_read1;
3113: c_hpos += 2;
3114: }
3115: ip += 2;
3116: }
3117:
3118: while (c_hpos + 1 < maxhpos) {
3119: if (state == COP_read1) {
3120: w1 = chipmem_wget (ip);
3121: if (w1 & 1) {
3122: w2 = chipmem_wget (ip + 2);
3123: if (w2 & 1)
3124: break;
3125: state = COP_wait;
3126: c_hpos += 6;
3127: } else if (dangerous_reg (w1)) {
3128: c_hpos += 6;
3129: goto done;
3130: } else {
3131: cop_state.regtypes_modified |= regtypes[w1 & 0x1FE];
3132: c_hpos += 4;
3133: }
3134: ip += 4;
3135: } else if (state == COP_wait) {
3136: if ((w2 & 0xFE) != 0xFE)
3137: break;
3138: else {
3139: unsigned int vcmp = (w1 & (w2 | 0x8000)) >> 8;
3140: unsigned int hcmp = (w1 & 0xFE);
3141:
3142: unsigned int vp = vpos & (((w2 >> 8) & 0x7F) | 0x80);
3143: if (vp < vcmp) {
3144: /* Whee. We can wait until the end of the line! */
3145: c_hpos = maxhpos;
3146: } else if (vp > vcmp || hcmp <= c_hpos) {
3147: state = COP_read1;
3148: /* minimum wakeup time */
3149: c_hpos += 2;
3150: } else {
3151: state = COP_read1;
3152: c_hpos = hcmp;
3153: }
3154: /* If this is the current instruction, remember that we don't
3155: need to sync CPU and copper anytime soon. */
3156: if (cop_state.ip == ip) {
3157: cop_state.first_sync = c_hpos;
3158: }
3159: }
3160: } else
3161: abort ();
3162: }
3163:
3164: done:
3165: cycle_count = c_hpos - cop_state.hpos;
3166: if (cycle_count >= 8) {
3167: unset_special (SPCFLAG_COPPER);
3168: eventtab[ev_copper].active = 1;
3169: eventtab[ev_copper].oldcycles = get_cycles ();
3170: eventtab[ev_copper].evtime = get_cycles () + cycle_count * CYCLE_UNIT;
3171: events_schedule ();
3172: }
3173: }
3174:
3175: static void perform_copper_write (int old_hpos)
3176: {
3177: int vp = vpos & (((cop_state.saved_i2 >> 8) & 0x7F) | 0x80);
3178: unsigned int address = cop_state.saved_i1 & 0x1FE;
3179:
3180: record_copper (cop_state.saved_ip - 4, old_hpos, vpos);
3181:
3182: if (address < (copcon & 2 ? ((currprefs.chipset_mask & CSMASK_AGA) ? 0 : 0x40u) : 0x80u)) {
3183: cop_state.state = COP_stop;
3184: copper_enabled_thisline = 0;
3185: unset_special (SPCFLAG_COPPER);
3186: return;
3187: }
3188:
3189: if (address == 0x88) {
3190: cop_state.ip = cop1lc;
3191: cop_state.state = COP_read1_in2;
3192: } else if (address == 0x8A) {
3193: cop_state.ip = cop2lc;
3194: cop_state.state = COP_read1_in2;
3195: } else
3196: custom_wput_1 (old_hpos, address, cop_state.saved_i2);
3197: }
1.1.1.13 root 3198:
1.1.1.20! root 3199: static int isagnus[]= {
! 3200: 1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0,
! 3201: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
! 3202: 0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,
! 3203: 1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,
! 3204: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* BPLxPT */
! 3205: 0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,
! 3206: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* SPRxPT */
! 3207: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
! 3208: 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* colors */
! 3209: 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
! 3210: };
! 3211:
1.1.1.9 root 3212: static void update_copper (int until_hpos)
1.1.1.2 root 3213: {
1.1.1.15 root 3214: int vp = vpos & (((cop_state.saved_i2 >> 8) & 0x7F) | 0x80);
1.1.1.4 root 3215: int c_hpos = cop_state.hpos;
1.1.1.2 root 3216:
1.1.1.10 root 3217: if (eventtab[ev_copper].active)
3218: abort ();
3219:
3220: if (cop_state.state == COP_wait && vp < cop_state.vcmp)
3221: abort ();
3222:
3223: until_hpos &= ~1;
3224:
3225: if (until_hpos > (maxhpos & ~1))
3226: until_hpos = maxhpos & ~1;
1.1.1.3 root 3227:
1.1.1.13 root 3228: until_hpos += 2;
1.1.1.4 root 3229: for (;;) {
1.1.1.10 root 3230: int old_hpos = c_hpos;
3231: int hp;
3232:
1.1.1.13 root 3233: if (c_hpos >= until_hpos)
1.1.1.3 root 3234: break;
3235:
1.1.1.13 root 3236: /* So we know about the fetch state. */
1.1.1.9 root 3237: decide_line (c_hpos);
1.1.1.3 root 3238:
1.1.1.15 root 3239: switch (cop_state.state) {
3240: case COP_read1_in2:
3241: cop_state.state = COP_read1;
3242: break;
3243: case COP_read1_wr_in2:
3244: cop_state.state = COP_read1;
3245: perform_copper_write (old_hpos);
3246: /* That could have turned off the copper. */
3247: if (! copper_enabled_thisline)
3248: goto out;
3249:
3250: break;
3251: case COP_read1_wr_in4:
3252: cop_state.state = COP_read1_wr_in2;
3253: break;
3254: case COP_read2_wr_in2:
3255: cop_state.state = COP_read2;
3256: perform_copper_write (old_hpos);
3257: /* That could have turned off the copper. */
3258: if (! copper_enabled_thisline)
3259: goto out;
3260:
3261: break;
3262: case COP_wait_in2:
3263: cop_state.state = COP_wait1;
3264: break;
3265: case COP_wait_in4:
3266: cop_state.state = COP_wait_in2;
3267: break;
3268: case COP_skip_in2:
3269: {
3270: static int skipped_before;
3271: unsigned int vcmp, hcmp, vp1, hp1;
3272: cop_state.state = COP_read1_in2;
3273:
3274: vcmp = (cop_state.saved_i1 & (cop_state.saved_i2 | 0x8000)) >> 8;
3275: hcmp = (cop_state.saved_i1 & cop_state.saved_i2 & 0xFE);
3276:
3277: if (! skipped_before) {
3278: skipped_before = 1;
3279: write_log ("Program uses Copper SKIP instruction.\n");
3280: }
3281:
3282: vp1 = vpos & (((cop_state.saved_i2 >> 8) & 0x7F) | 0x80);
3283: hp1 = old_hpos & (cop_state.saved_i2 & 0xFE);
3284:
3285: if ((vp1 > vcmp || (vp1 == vcmp && hp1 >= hcmp))
3286: && ((cop_state.saved_i2 & 0x8000) != 0 || ! (DMACONR() & 0x4000)))
3287: cop_state.ignore_next = 1;
3288: break;
3289: }
3290: case COP_skip_in4:
3291: cop_state.state = COP_skip_in2;
3292: break;
3293: default:
3294: break;
3295: }
3296:
1.1.1.10 root 3297: c_hpos += 2;
1.1.1.16 root 3298: if (copper_cant_read (old_hpos))
1.1.1.10 root 3299: continue;
1.1.1.3 root 3300:
1.1.1.10 root 3301: switch (cop_state.state) {
1.1.1.15 root 3302: case COP_read1_wr_in4:
3303: abort ();
3304:
3305: case COP_read1_wr_in2:
1.1.1.9 root 3306: case COP_read1:
1.1.1.15 root 3307: cop_state.i1 = chipmem_wget (cop_state.ip);
1.1.1.9 root 3308: cop_state.ip += 2;
1.1.1.15 root 3309: cop_state.state = cop_state.state == COP_read1 ? COP_read2 : COP_read2_wr_in2;
1.1.1.9 root 3310: break;
3311:
1.1.1.15 root 3312: case COP_read2_wr_in2:
3313: abort ();
3314:
1.1.1.9 root 3315: case COP_read2:
1.1.1.15 root 3316: cop_state.i2 = chipmem_wget (cop_state.ip);
1.1.1.9 root 3317: cop_state.ip += 2;
3318: if (cop_state.ignore_next) {
3319: cop_state.ignore_next = 0;
1.1.1.15 root 3320: cop_state.state = COP_read1;
1.1.1.9 root 3321: break;
1.1.1.3 root 3322: }
1.1.1.2 root 3323:
1.1.1.15 root 3324: cop_state.saved_i1 = cop_state.i1;
3325: cop_state.saved_i2 = cop_state.i2;
3326: cop_state.saved_ip = cop_state.ip;
3327:
3328: if (cop_state.i1 & 1) {
3329: if (cop_state.i2 & 1)
3330: cop_state.state = COP_skip_in4;
3331: else
3332: cop_state.state = COP_wait_in4;
1.1.1.20! root 3333: } else {
! 3334: unsigned int reg = cop_state.i1 & 0x1FE;
! 3335: cop_state.state = isagnus[reg >> 1] ? COP_read1_wr_in2 : COP_read1_wr_in4;
! 3336: }
1.1.1.15 root 3337: break;
3338:
3339: case COP_wait1:
1.1.1.20! root 3340: /* There's a nasty case here. As stated in the "Theory" comment above, we
! 3341: test against the incremented copper position. I believe this means that
! 3342: we have to increment the _vertical_ position at the last cycle in the line,
! 3343: and set the horizontal position to 0.
! 3344: Normally, this isn't going to make a difference, since we consider these
! 3345: last cycles unavailable for the copper, so waking up in the last cycle has
! 3346: the same effect as waking up at the start of the line. However, there is
! 3347: one possible problem: If we're at 0xFFE0, any wait for an earlier position
! 3348: must _not_ complete (since, in effect, the current position will be back
! 3349: at 0/0). This can be seen in the Superfrog copper list.
! 3350: Things get monstrously complicated if we try to handle this "properly" by
! 3351: incrementing vpos and setting c_hpos to 0. Especially the various speedup
! 3352: hacks really assume that vpos remains constant during one line. Hence,
! 3353: this hack: defer the entire decision until the next line if necessary. */
! 3354: if (c_hpos >= (maxhpos & ~1))
! 3355: break;
1.1.1.9 root 3356: cop_state.state = COP_wait;
1.1.1.13 root 3357:
1.1.1.15 root 3358: cop_state.vcmp = (cop_state.saved_i1 & (cop_state.saved_i2 | 0x8000)) >> 8;
3359: cop_state.hcmp = (cop_state.saved_i1 & cop_state.saved_i2 & 0xFE);
3360:
3361: vp = vpos & (((cop_state.saved_i2 >> 8) & 0x7F) | 0x80);
1.1.1.13 root 3362:
1.1.1.15 root 3363: if (cop_state.saved_i1 == 0xFFFF && cop_state.saved_i2 == 0xFFFE) {
1.1.1.9 root 3364: cop_state.state = COP_stop;
1.1.1.10 root 3365: copper_enabled_thisline = 0;
1.1.1.13 root 3366: unset_special (SPCFLAG_COPPER);
1.1.1.10 root 3367: goto out;
1.1.1.2 root 3368: }
1.1.1.9 root 3369: if (vp < cop_state.vcmp) {
1.1.1.10 root 3370: copper_enabled_thisline = 0;
1.1.1.13 root 3371: unset_special (SPCFLAG_COPPER);
1.1.1.10 root 3372: goto out;
1.1.1.2 root 3373: }
1.1.1.10 root 3374:
1.1.1.15 root 3375: /* fall through */
3376: do_wait:
1.1.1.10 root 3377: case COP_wait:
3378: if (vp < cop_state.vcmp)
3379: abort ();
3380:
1.1.1.15 root 3381: hp = c_hpos & (cop_state.saved_i2 & 0xFE);
3382: if (vp == cop_state.vcmp && hp < cop_state.hcmp) {
3383: /* Position not reached yet. */
3384: if (currprefs.fast_copper && (cop_state.saved_i2 & 0xFE) == 0xFE) {
3385: int wait_finish = cop_state.hcmp - 2;
3386: /* This will leave c_hpos untouched if it's equal to wait_finish. */
3387: if (wait_finish < c_hpos)
3388: abort ();
3389: else if (wait_finish <= until_hpos) {
3390: c_hpos = wait_finish;
3391: } else
3392: c_hpos = until_hpos;
3393: }
1.1.1.4 root 3394: break;
1.1.1.15 root 3395: }
1.1.1.10 root 3396:
3397: /* Now we know that the comparisons were successful. We might still
3398: have to wait for the blitter though. */
1.1.1.15 root 3399: if ((cop_state.saved_i2 & 0x8000) == 0 && (DMACONR() & 0x4000)) {
1.1.1.9 root 3400: /* We need to wait for the blitter. */
1.1.1.4 root 3401: cop_state.state = COP_bltwait;
1.1.1.10 root 3402: copper_enabled_thisline = 0;
1.1.1.13 root 3403: unset_special (SPCFLAG_COPPER);
1.1.1.10 root 3404: goto out;
1.1.1.2 root 3405: }
1.1.1.10 root 3406:
1.1.1.15 root 3407: record_copper (cop_state.ip - 4, old_hpos, vpos);
1.1.1.13 root 3408:
1.1.1.10 root 3409: cop_state.state = COP_read1;
1.1.1.4 root 3410: break;
1.1.1.2 root 3411:
1.1.1.13 root 3412: default:
1.1.1.15 root 3413: break;
1.1 root 3414: }
1.1.1.4 root 3415: }
1.1.1.10 root 3416:
3417: out:
1.1.1.4 root 3418: cop_state.hpos = c_hpos;
1.1.1.10 root 3419:
1.1.1.15 root 3420: /* The test against maxhpos also prevents us from calling predict_copper
3421: when we are being called from hsync_handler, which would not only be
3422: stupid, but actively harmful. */
3423: if (currprefs.fast_copper && (regs.spcflags & SPCFLAG_COPPER) && c_hpos + 8 < maxhpos)
3424: predict_copper ();
1.1 root 3425: }
3426:
1.1.1.9 root 3427: static void compute_spcflag_copper (void)
1.1 root 3428: {
1.1.1.10 root 3429: copper_enabled_thisline = 0;
1.1.1.13 root 3430: unset_special (SPCFLAG_COPPER);
1.1.1.10 root 3431: if (! dmaen (DMA_COPPER) || cop_state.state == COP_stop || cop_state.state == COP_bltwait)
3432: return;
3433:
3434: if (cop_state.state == COP_wait) {
1.1.1.15 root 3435: int vp = vpos & (((cop_state.saved_i2 >> 8) & 0x7F) | 0x80);
1.1.1.10 root 3436:
3437: if (vp < cop_state.vcmp)
3438: return;
3439: }
3440: copper_enabled_thisline = 1;
1.1.1.15 root 3441:
3442: if (currprefs.fast_copper)
3443: predict_copper ();
3444:
3445: if (! eventtab[ev_copper].active)
3446: set_special (SPCFLAG_COPPER);
1.1.1.10 root 3447: }
3448:
3449: static void copper_handler (void)
3450: {
3451: /* This will take effect immediately, within the same cycle. */
1.1.1.13 root 3452: set_special (SPCFLAG_COPPER);
1.1.1.10 root 3453:
3454: if (! copper_enabled_thisline)
3455: abort ();
3456:
3457: eventtab[ev_copper].active = 0;
1.1.1.3 root 3458: }
1.1.1.2 root 3459:
1.1.1.4 root 3460: void blitter_done_notify (void)
1.1 root 3461: {
1.1.1.4 root 3462: if (cop_state.state != COP_bltwait)
3463: return;
1.1.1.10 root 3464:
1.1.1.20! root 3465: cop_state.hpos = current_hpos () & ~1;
! 3466: cop_state.vpos = vpos;
1.1.1.9 root 3467: cop_state.state = COP_wait;
1.1.1.20! root 3468: compute_spcflag_copper ();
1.1.1.2 root 3469: }
3470:
1.1.1.9 root 3471: void do_copper (void)
1.1.1.2 root 3472: {
1.1.1.4 root 3473: int hpos = current_hpos ();
3474: update_copper (hpos);
1.1.1.2 root 3475: }
3476:
1.1.1.15 root 3477: /* ADDR is the address that is going to be read/written; this access is
3478: the reason why we want to update the copper. This function is also
3479: used from hsync_handler to finish up the line; for this case, we check
3480: hpos against maxhpos. */
3481: STATIC_INLINE void sync_copper_with_cpu (int hpos, int do_schedule, unsigned int addr)
1.1.1.13 root 3482: {
1.1.1.15 root 3483: /* Need to let the copper advance to the current position. */
1.1.1.13 root 3484: if (eventtab[ev_copper].active) {
1.1.1.15 root 3485: if (hpos != maxhpos) {
3486: /* There might be reasons why we don't actually need to bother
3487: updating the copper. */
3488: if (hpos < cop_state.first_sync)
3489: return;
3490:
3491: if ((cop_state.regtypes_modified & regtypes[addr & 0x1FE]) == 0)
3492: return;
1.1.1.13 root 3493: }
1.1.1.15 root 3494:
3495: eventtab[ev_copper].active = 0;
3496: if (do_schedule)
3497: events_schedule ();
3498: set_special (SPCFLAG_COPPER);
1.1.1.13 root 3499: }
1.1.1.15 root 3500: if (copper_enabled_thisline)
1.1.1.13 root 3501: update_copper (hpos);
3502: }
3503:
1.1.1.20! root 3504: STATIC_INLINE uae_u16 sprite_fetch (struct sprite *s, int dma)
! 3505: {
! 3506: uae_u16 data = last_custom_value;
! 3507: if (dma)
! 3508: data = last_custom_value = chipmem_wget (s->pt);
! 3509: s->pt += 2;
! 3510: return data;
! 3511: }
! 3512:
! 3513: STATIC_INLINE void do_sprites_1 (int num, int cycle, int hpos)
! 3514: {
! 3515: struct sprite *s = &spr[num];
! 3516: int dma;
! 3517:
! 3518: if (cycle == 0) {
! 3519: if (vpos == s->vstart)
! 3520: s->state = SPR_waiting_stop;
! 3521: if (vpos == s->vstop)
! 3522: s->state = SPR_restart;
! 3523: }
! 3524: if (!dmaen (DMA_SPRITE))
! 3525: return;
! 3526: dma = hpos < ddfstrt || diwstate != DIW_waiting_stop || !dmaen (DMA_BITPLANE);
! 3527: if (s->state == SPR_restart || vpos == sprite_vblank_endline) {
! 3528: uae_u16 data = sprite_fetch (s, dma);
! 3529: s->pt += (sprite_width >> 3) - 2;
! 3530: #ifdef SPRITE_DEBUG
! 3531: write_log ("dma:");
! 3532: #endif
! 3533: if (cycle == 0) {
! 3534: SPRxPOS_1 (dma ? data : sprpos[num], num, hpos);
! 3535: } else {
! 3536: s->state = SPR_waiting_start;
! 3537: SPRxCTL_1 (dma ? data : sprctl[num], num, hpos);
! 3538: }
! 3539: } else if (s->state == SPR_waiting_stop) {
! 3540: uae_u16 data = sprite_fetch (s, dma);
! 3541: /* Hack for X mouse auto-calibration */
! 3542: if (num == 0 && cycle == 0)
! 3543: mousehack_handle (sprctl[0], sprpos[0]);
! 3544:
! 3545: if (cycle == 0)
! 3546: SPRxDATA_1 (dma ? data : sprdata[num][0], num);
! 3547: else
! 3548: SPRxDATB_1 (dma ? data : sprdatb[num][0], num);
! 3549: switch (sprite_width)
! 3550: {
! 3551: case 64:
! 3552: {
! 3553: uae_u32 data32 = sprite_fetch (s, dma);
! 3554: uae_u32 data641 = sprite_fetch (s, dma);
! 3555: uae_u32 data642 = sprite_fetch (s, dma);
! 3556: if (dma) {
! 3557: if (cycle == 0) {
! 3558: sprdata[num][3] = data642;
! 3559: sprdata[num][2] = data641;
! 3560: sprdata[num][1] = data32;
! 3561: } else {
! 3562: sprdatb[num][3] = data642;
! 3563: sprdatb[num][2] = data641;
! 3564: sprdatb[num][1] = data32;
! 3565: }
! 3566: }
! 3567: }
! 3568: break;
! 3569: case 32:
! 3570: {
! 3571: uae_u32 data32 = sprite_fetch (s, dma);
! 3572: if (dma) {
! 3573: if (cycle == 0)
! 3574: sprdata[num][1] = data32;
! 3575: else
! 3576: sprdatb[num][1] = data32;
! 3577: }
! 3578: }
! 3579: break;
! 3580: }
! 3581: }
! 3582: }
! 3583:
! 3584: #define SPR0_HPOS 0x15
! 3585: static void do_sprites (int hpos)
1.1.1.4 root 3586: {
1.1.1.13 root 3587: int maxspr, minspr;
1.1.1.20! root 3588: int i;
1.1.1.2 root 3589:
1.1.1.4 root 3590: /* I don't know whether this is right. Some programs write the sprite pointers
1.1.1.13 root 3591: * directly at the start of the copper list. With the test against currvp, the
1.1.1.4 root 3592: * first two words of data are read on the second line in the frame. The problem
3593: * occurs when the program jumps to another copperlist a few lines further down
3594: * which _also_ writes the sprite pointer registers. This means that a) writing
3595: * to the sprite pointers sets the state to SPR_restart; or b) that sprite DMA
3596: * is disabled until the end of the vertical blanking interval. The HRM
3597: * isn't clear - it says that the vertical sprite position can be set to any
3598: * value, but this wouldn't be the first mistake... */
3599: /* Update: I modified one of the programs to write the sprite pointers the
3600: * second time only _after_ the VBlank interval, and it showed the same behaviour
3601: * as it did unmodified under UAE with the above check. This indicates that the
3602: * solution below is correct. */
1.1.1.9 root 3603: /* Another update: seems like we have to use the NTSC value here (see Sanity Turmoil
3604: * demo). */
1.1.1.10 root 3605: /* Maximum for Sanity Turmoil: 27.
3606: Minimum for Sanity Arte: 22. */
1.1.1.20! root 3607: if (vpos < sprite_vblank_endline)
1.1.1.4 root 3608: return;
1.1.1.3 root 3609:
1.1.1.20! root 3610: maxspr = hpos;
! 3611: minspr = last_sprite_hpos;
1.1.1.13 root 3612:
1.1.1.20! root 3613: if (minspr >= SPR0_HPOS + MAX_SPRITES * 4 || maxspr < SPR0_HPOS)
1.1.1.4 root 3614: return;
1.1.1.13 root 3615:
1.1.1.20! root 3616: if (maxspr > SPR0_HPOS + MAX_SPRITES * 4)
! 3617: maxspr = SPR0_HPOS + MAX_SPRITES * 4;
! 3618: if (minspr < SPR0_HPOS)
! 3619: minspr = SPR0_HPOS;
1.1.1.2 root 3620:
1.1.1.13 root 3621: for (i = minspr; i < maxspr; i++) {
1.1.1.20! root 3622: int cycle = -1;
! 3623: switch ((i - SPR0_HPOS) & 3)
! 3624: {
! 3625: case 0:
! 3626: cycle = 0;
! 3627: break;
! 3628: case 2:
! 3629: cycle = 1;
! 3630: break;
1.1 root 3631: }
1.1.1.20! root 3632: if (cycle >= 0)
! 3633: do_sprites_1 ((i - SPR0_HPOS) / 4, cycle, i);
1.1 root 3634: }
1.1.1.13 root 3635: last_sprite_hpos = hpos;
1.1 root 3636: }
3637:
1.1.1.4 root 3638: static void init_sprites (void)
1.1 root 3639: {
1.1.1.4 root 3640: int i;
1.1.1.2 root 3641:
1.1.1.20! root 3642: for (i = 0; i < MAX_SPRITES; i++)
! 3643: spr[i].state = SPR_restart;
1.1.1.4 root 3644: memset (sprpos, 0, sizeof sprpos);
3645: memset (sprctl, 0, sizeof sprctl);
3646: }
1.1.1.2 root 3647:
1.1.1.3 root 3648: static void adjust_array_sizes (void)
1.1.1.2 root 3649: {
3650: #ifdef OS_WITHOUT_MEMORY_MANAGEMENT
1.1.1.13 root 3651: if (delta_sprite_entry) {
1.1.1.3 root 3652: void *p1,*p2;
1.1.1.13 root 3653: int mcc = max_sprite_entry + 50 + delta_sprite_entry;
3654: delta_sprite_entry = 0;
3655: p1 = realloc (sprite_entries[0], mcc * sizeof (struct sprite_entry));
3656: p2 = realloc (sprite_entries[1], mcc * sizeof (struct sprite_entry));
3657: if (p1) sprite_entries[0] = p1;
3658: if (p2) sprite_entries[1] = p2;
1.1.1.3 root 3659: if (p1 && p2) {
1.1.1.18 root 3660: write_log ("new max_sprite_entry=%d\n",mcc);
1.1.1.13 root 3661: max_sprite_entry = mcc;
1.1.1.2 root 3662: }
3663: }
1.1.1.3 root 3664: if (delta_color_change) {
3665: void *p1,*p2;
3666: int mcc = max_color_change + 200 + delta_color_change;
3667: delta_color_change = 0;
3668: p1 = realloc (color_changes[0], mcc * sizeof (struct color_change));
3669: p2 = realloc (color_changes[1], mcc * sizeof (struct color_change));
3670: if (p1) color_changes[0] = p1;
3671: if (p2) color_changes[1] = p2;
3672: if (p1 && p2) {
1.1.1.18 root 3673: write_log ("new max_color_change=%d\n",mcc);
1.1.1.2 root 3674: max_color_change = mcc;
1.1.1.3 root 3675: }
3676: }
1.1.1.2 root 3677: #endif
1.1.1.3 root 3678: }
3679:
1.1.1.4 root 3680: static void init_hardware_frame (void)
1.1.1.3 root 3681: {
1.1.1.4 root 3682: next_lineno = 0;
3683: nextline_how = nln_normal;
3684: diwstate = DIW_waiting_start;
3685: hdiwstate = DIW_waiting_start;
3686: }
1.1.1.2 root 3687:
1.1.1.4 root 3688: void init_hardware_for_drawing_frame (void)
3689: {
1.1.1.3 root 3690: adjust_array_sizes ();
3691:
1.1.1.13 root 3692: /* Avoid this code in the first frame after a customreset. */
3693: if (prev_sprite_entries) {
3694: int first_pixel = prev_sprite_entries[0].first_pixel;
3695: int npixels = prev_sprite_entries[prev_next_sprite_entry].first_pixel - first_pixel;
3696: memset (spixels + first_pixel, 0, npixels * sizeof *spixels);
3697: memset (spixstate.bytes + first_pixel, 0, npixels * sizeof *spixstate.bytes);
3698: }
3699: prev_next_sprite_entry = next_sprite_entry;
1.1.1.3 root 3700:
1.1.1.13 root 3701: next_color_change = 0;
3702: next_sprite_entry = 0;
1.1.1.2 root 3703: next_color_entry = 0;
3704: remembered_color_entry = -1;
1.1.1.13 root 3705:
3706: prev_sprite_entries = sprite_entries[current_change_set];
3707: curr_sprite_entries = sprite_entries[current_change_set ^ 1];
1.1.1.2 root 3708: prev_color_changes = color_changes[current_change_set];
3709: curr_color_changes = color_changes[current_change_set ^ 1];
3710: prev_color_tables = color_tables[current_change_set];
3711: curr_color_tables = color_tables[current_change_set ^ 1];
1.1.1.3 root 3712:
1.1.1.2 root 3713: prev_drawinfo = line_drawinfo[current_change_set];
1.1.1.4 root 3714: curr_drawinfo = line_drawinfo[current_change_set ^ 1];
3715: current_change_set ^= 1;
1.1.1.3 root 3716:
1.1.1.4 root 3717: color_src_match = color_dest_match = -1;
1.1.1.13 root 3718:
3719: /* Use both halves of the array in alternating fashion. */
3720: curr_sprite_entries[0].first_pixel = current_change_set * MAX_SPR_PIXELS;
3721: next_sprite_forced = 1;
1.1.1.3 root 3722: }
3723:
1.1.1.15 root 3724: static void do_savestate(void);
3725:
1.1.1.2 root 3726: static void vsync_handler (void)
1.1 root 3727: {
1.1.1.20! root 3728: int i;
! 3729: for (i = 0; i < MAX_SPRITES; i++)
! 3730: spr[i].state = SPR_waiting_start;
! 3731:
1.1.1.12 root 3732: n_frames++;
3733:
1.1.1.4 root 3734: if (currprefs.m68k_speed == -1) {
3735: frame_time_t curr_time = read_processor_time ();
1.1.1.3 root 3736: vsyncmintime += vsynctime;
3737: /* @@@ Mathias? How do you think we should do this? */
3738: /* If we are too far behind, or we just did a reset, adjust the
3739: * needed time. */
1.1.1.4 root 3740: if ((long int)(curr_time - vsyncmintime) > 0 || rpt_did_reset)
1.1.1.3 root 3741: vsyncmintime = curr_time + vsynctime;
1.1.1.4 root 3742: rpt_did_reset = 0;
1.1.1.20! root 3743: } else {
! 3744: #ifdef RPT_WORKS_OK
! 3745: if (RPT_WORKS_OK) {
! 3746: frame_time_t curr_time;
! 3747: do
! 3748: curr_time = read_processor_time ();
! 3749: while ((long int)(read_processor_time () - vsyncmintime) < 0);
! 3750: vsyncmintime = curr_time + vsynctime;
! 3751: }
! 3752: #endif
1.1.1.3 root 3753: }
1.1.1.4 root 3754:
1.1.1.3 root 3755: handle_events ();
1.1 root 3756:
1.1.1.3 root 3757: getjoystate (0, &joy0dir, &joy0button);
3758: getjoystate (1, &joy1dir, &joy1button);
1.1 root 3759:
1.1.1.4 root 3760: INTREQ (0x8020);
1.1.1.3 root 3761: if (bplcon0 & 4)
1.1.1.2 root 3762: lof ^= 0x8000;
1.1.1.3 root 3763:
1.1.1.18 root 3764: #ifdef PICASSO96
1.1.1.16 root 3765: if (picasso_on)
3766: picasso_handle_vsync ();
1.1.1.18 root 3767: #endif
1.1.1.4 root 3768: vsync_handle_redraw (lof, lof_changed);
1.1.1.16 root 3769:
1.1.1.4 root 3770: if (quit_program > 0)
1.1.1.3 root 3771: return;
3772:
1.1.1.4 root 3773: {
1.1.1.3 root 3774: static int cnt = 0;
3775: if (cnt == 0) {
3776: /* resolution_check_change (); */
3777: DISK_check_change ();
3778: cnt = 5;
3779: }
3780: cnt--;
1.1.1.2 root 3781: }
1.1.1.3 root 3782:
1.1.1.15 root 3783: /* Start a new set of copper records. */
3784: curr_cop_set ^= 1;
3785: nr_cop_records[curr_cop_set] = 0;
3786:
1.1.1.7 root 3787: /* For now, let's only allow this to change at vsync time. It gets too
3788: * hairy otherwise. */
3789: if (beamcon0 != new_beamcon0)
3790: init_hz ();
3791:
1.1.1.2 root 3792: lof_changed = 0;
1.1.1.3 root 3793:
1.1.1.4 root 3794: cop_state.ip = cop1lc;
3795: cop_state.state = COP_read1;
3796: cop_state.vpos = 0;
3797: cop_state.hpos = 0;
3798: cop_state.ignore_next = 0;
3799:
3800: init_hardware_frame ();
3801:
1.1 root 3802: #ifdef HAVE_GETTIMEOFDAY
3803: {
3804: struct timeval tv;
3805: unsigned long int newtime;
1.1.1.3 root 3806:
1.1.1.9 root 3807: gettimeofday (&tv,NULL);
1.1 root 3808: newtime = (tv.tv_sec-seconds_base) * 1000 + tv.tv_usec / 1000;
1.1.1.3 root 3809:
3810: if (!bogusframe) {
1.1.1.6 root 3811: lastframetime = newtime - msecs;
3812:
3813: #if 0 /* This doesn't appear to work too well yet... later. */
3814: if (n_consecutive_skipped > currprefs.sound_pri_cutoff
3815: || lastframetime < currprefs.sound_pri_time)
3816: {
3817: n_consecutive_skipped = 0;
3818: clear_inhibit_frame (IHF_SOUNDADJUST);
3819: } else {
3820: n_consecutive_skipped++;
3821: set_inhibit_frame (IHF_SOUNDADJUST);
3822: total_skipped++;
3823: }
3824: #endif
3825:
3826: frametime += lastframetime;
1.1 root 3827: timeframes++;
1.1.1.6 root 3828:
3829: if ((timeframes & 127) == 0)
3830: gui_fps (1000 * timeframes / frametime);
1.1 root 3831: }
3832: msecs = newtime;
3833: bogusframe = 0;
3834: }
3835: #endif
1.1.1.3 root 3836: if (ievent_alive > 0)
3837: ievent_alive--;
1.1.1.7 root 3838: if (timehack_alive > 0)
3839: timehack_alive--;
1.1.1.15 root 3840: CIA_vsync_handler ();
1.1 root 3841: }
3842:
1.1.1.4 root 3843: static void hsync_handler (void)
1.1 root 3844: {
1.1.1.15 root 3845: /* Using 0x8A makes sure that we don't accidentally trip over the
3846: modified_regtypes check. */
3847: sync_copper_with_cpu (maxhpos, 0, 0x8A);
1.1.1.10 root 3848:
1.1.1.2 root 3849: finish_decisions ();
1.1.1.15 root 3850: if (thisline_decision.plfleft != -1) {
3851: if (currprefs.collision_level > 1)
3852: do_sprite_collisions ();
3853: if (currprefs.collision_level > 2)
3854: do_playfield_collisions ();
3855: }
1.1.1.5 root 3856: hsync_record_line_state (next_lineno, nextline_how, thisline_changed);
1.1 root 3857:
1.1.1.14 root 3858: eventtab[ev_hsync].evtime += get_cycles () - eventtab[ev_hsync].oldcycles;
3859: eventtab[ev_hsync].oldcycles = get_cycles ();
1.1.1.8 root 3860: CIA_hsync_handler ();
1.1.1.3 root 3861:
3862: if (currprefs.produce_sound > 0) {
1.1 root 3863: int nr;
1.1.1.4 root 3864:
3865: update_audio ();
3866:
1.1 root 3867: /* Sound data is fetched at the beginning of each line */
1.1.1.17 root 3868: for (nr = 0; nr < 4; nr++) {
1.1 root 3869: struct audio_channel_data *cdp = audio_channel + nr;
1.1.1.3 root 3870:
1.1 root 3871: if (cdp->data_written == 2) {
3872: cdp->data_written = 0;
1.1.1.17 root 3873: cdp->nextdat = chipmem_wget (cdp->pt);
1.1 root 3874: cdp->pt += 2;
3875: if (cdp->state == 2 || cdp->state == 3) {
3876: if (cdp->wlen == 1) {
3877: cdp->pt = cdp->lc;
3878: cdp->wlen = cdp->len;
3879: cdp->intreq2 = 1;
3880: } else
1.1.1.16 root 3881: cdp->wlen = (cdp->wlen - 1) & 0xFFFF;
1.1 root 3882: }
3883: }
3884: }
3885: }
1.1.1.4 root 3886:
3887: hardware_line_completed (next_lineno);
3888:
1.1.1.16 root 3889: /* In theory only an equality test is needed here - but if a program
3890: goes haywire with the VPOSW register, it can cause us to miss this,
3891: with vpos going into the thousands (and all the nasty consequences
3892: this has). */
3893:
3894: if (++vpos >= (maxvpos + (lof != 0))) {
1.1 root 3895: vpos = 0;
1.1.1.15 root 3896: vsync_handler ();
1.1 root 3897: }
1.1.1.2 root 3898:
1.1.1.15 root 3899: DISK_update ();
3900:
1.1.1.4 root 3901: is_lastline = vpos + 1 == maxvpos + (lof != 0) && currprefs.m68k_speed == -1 && ! rpt_did_reset;
1.1.1.3 root 3902:
1.1.1.4 root 3903: if ((bplcon0 & 4) && currprefs.gfx_linedbl)
3904: notice_interlace_seen ();
1.1.1.2 root 3905:
3906: if (framecnt == 0) {
1.1.1.4 root 3907: int lineno = vpos;
3908: nextline_how = nln_normal;
1.1.1.3 root 3909: if (currprefs.gfx_linedbl) {
1.1 root 3910: lineno *= 2;
1.1.1.5 root 3911: nextline_how = currprefs.gfx_linedbl == 1 ? nln_doubled : nln_nblack;
1.1.1.2 root 3912: if (bplcon0 & 4) {
3913: if (!lof) {
3914: lineno++;
1.1.1.4 root 3915: nextline_how = nln_lower;
1.1.1.2 root 3916: } else {
1.1.1.4 root 3917: nextline_how = nln_upper;
1.1.1.2 root 3918: }
1.1 root 3919: }
3920: }
3921: next_lineno = lineno;
1.1.1.2 root 3922: reset_decisions ();
1.1 root 3923: }
1.1.1.3 root 3924: if (uae_int_requested) {
3925: set_uae_int_flag ();
3926: INTREQ (0xA000);
3927: }
1.1.1.9 root 3928: /* See if there's a chance of a copper wait ending this line. */
3929: cop_state.hpos = 0;
3930: compute_spcflag_copper ();
1.1.1.3 root 3931: }
3932:
1.1.1.15 root 3933: static void init_regtypes (void)
3934: {
3935: int i;
3936: for (i = 0; i < 512; i += 2) {
3937: regtypes[i] = REGTYPE_ALL;
3938: if ((i >= 0x20 && i < 0x28) || i == 0x08 || i == 0x7E)
3939: regtypes[i] = REGTYPE_DISK;
3940: else if (i >= 0x68 && i < 0x70)
3941: regtypes[i] = REGTYPE_NONE;
3942: else if (i >= 0x40 && i < 0x78)
3943: regtypes[i] = REGTYPE_BLITTER;
3944: else if (i >= 0xA0 && i < 0xE0 && (i & 0xF) < 0xE)
3945: regtypes[i] = REGTYPE_AUDIO;
3946: else if (i >= 0xA0 && i < 0xE0)
3947: regtypes[i] = REGTYPE_NONE;
3948: else if (i >= 0xE0 && i < 0x100)
3949: regtypes[i] = REGTYPE_PLANE;
3950: else if (i >= 0x120 && i < 0x180)
3951: regtypes[i] = REGTYPE_SPRITE;
3952: else if (i >= 0x180 && i < 0x1C0)
3953: regtypes[i] = REGTYPE_COLOR;
3954: else switch (i) {
3955: case 0x02:
3956: /* DMACONR - setting this to REGTYPE_BLITTER will cause it to
3957: conflict with DMACON (since that is REGTYPE_ALL), and the
3958: blitter registers (for the BBUSY bit), but nothing else,
3959: which is (I think) what we want. */
3960: regtypes[i] = REGTYPE_BLITTER;
3961: break;
3962: case 0x04: case 0x06: case 0x2A: case 0x2C:
3963: regtypes[i] = REGTYPE_POS;
3964: break;
3965: case 0x0A: case 0x0C:
3966: case 0x12: case 0x14: case 0x16:
3967: case 0x36:
3968: regtypes[i] = REGTYPE_JOYPORT;
3969: break;
3970: case 0x104:
3971: case 0x102:
3972: regtypes[i] = REGTYPE_PLANE;
3973: break;
3974: case 0x88: case 0x8A:
3975: case 0x8E: case 0x90: case 0x92: case 0x94:
3976: case 0x96:
3977: case 0x100:
3978: regtypes[i] |= REGTYPE_FORCE;
3979: break;
3980: }
3981: }
3982: }
3983:
3984: void init_eventtab (void)
1.1.1.3 root 3985: {
3986: int i;
3987:
1.1.1.15 root 3988: currcycle = 0;
3989: for (i = 0; i < ev_max; i++) {
1.1.1.3 root 3990: eventtab[i].active = 0;
3991: eventtab[i].oldcycles = 0;
3992: }
1.1.1.4 root 3993:
1.1.1.3 root 3994: eventtab[ev_cia].handler = CIA_handler;
3995: eventtab[ev_hsync].handler = hsync_handler;
1.1.1.14 root 3996: eventtab[ev_hsync].evtime = maxhpos * CYCLE_UNIT + get_cycles ();
1.1.1.3 root 3997: eventtab[ev_hsync].active = 1;
3998:
1.1.1.10 root 3999: eventtab[ev_copper].handler = copper_handler;
4000: eventtab[ev_copper].active = 0;
1.1.1.3 root 4001: eventtab[ev_blitter].handler = blitter_handler;
4002: eventtab[ev_blitter].active = 0;
1.1.1.11 root 4003: eventtab[ev_disk].handler = DISK_handler;
4004: eventtab[ev_disk].active = 0;
1.1.1.14 root 4005: eventtab[ev_audio].handler = audio_evhandler;
4006: eventtab[ev_audio].active = 0;
1.1.1.3 root 4007: events_schedule ();
1.1 root 4008: }
4009:
1.1.1.3 root 4010: void customreset (void)
1.1 root 4011: {
1.1.1.4 root 4012: int i;
1.1.1.11 root 4013: int zero = 0;
1.1 root 4014: #ifdef HAVE_GETTIMEOFDAY
4015: struct timeval tv;
4016: #endif
1.1.1.2 root 4017:
1.1.1.15 root 4018: if (! savestate_state) {
4019: currprefs.chipset_mask = changed_prefs.chipset_mask;
4020: if ((currprefs.chipset_mask & CSMASK_AGA) == 0) {
4021: for (i = 0; i < 32; i++) {
4022: current_colors.color_regs_ecs[i] = 0;
4023: current_colors.acolors[i] = xcolors[0];
4024: }
4025: } else {
1.1.1.20! root 4026: for (i = 0; i < 256; i++) {
1.1.1.15 root 4027: current_colors.color_regs_aga[i] = 0;
4028: current_colors.acolors[i] = CONVERT_RGB (zero);
4029: }
1.1.1.11 root 4030: }
1.1.1.15 root 4031:
4032: clx_sprmask = 0xFF;
4033: clxdat = 0;
4034:
4035: /* Clear the armed flags of all sprites. */
4036: memset (spr, 0, sizeof spr);
4037: nr_armed = 0;
4038:
4039: dmacon = intena = 0;
4040:
4041: copcon = 0;
4042: DSKLEN (0, 0);
4043:
1.1.1.16 root 4044: bplcon0 = 0;
1.1.1.15 root 4045: bplcon4 = 0x11; /* Get AGA chipset into ECS compatibility mode */
4046: bplcon3 = 0xC00;
4047:
4048: FMODE (0);
4049: CLXCON (0);
1.1.1.20! root 4050: lof = 0;
1.1.1.9 root 4051: }
1.1.1.3 root 4052:
1.1.1.12 root 4053: n_frames = 0;
4054:
1.1.1.3 root 4055: expamem_reset ();
1.1.1.4 root 4056:
1.1.1.12 root 4057: DISK_reset ();
1.1.1.3 root 4058: CIA_reset ();
1.1.1.13 root 4059: unset_special (~(SPCFLAG_BRK | SPCFLAG_MODE_CHANGE));
1.1.1.3 root 4060:
1.1.1.2 root 4061: vpos = 0;
1.1.1.3 root 4062:
1.1.1.4 root 4063: if (needmousehack ()) {
1.1.1.3 root 4064: #if 0
1.1.1.4 root 4065: mousehack_setfollow();
1.1.1.3 root 4066: #else
1.1.1.4 root 4067: mousehack_setdontcare();
1.1.1.3 root 4068: #endif
1.1 root 4069: } else {
4070: mousestate = normal_mouse;
4071: }
1.1.1.3 root 4072: ievent_alive = 0;
1.1.1.7 root 4073: timehack_alive = 0;
1.1.1.3 root 4074:
1.1.1.13 root 4075: curr_sprite_entries = 0;
4076: prev_sprite_entries = 0;
4077: sprite_entries[0][0].first_pixel = 0;
4078: sprite_entries[1][0].first_pixel = MAX_SPR_PIXELS;
4079: sprite_entries[0][1].first_pixel = 0;
4080: sprite_entries[1][1].first_pixel = MAX_SPR_PIXELS;
4081: memset (spixels, 0, sizeof spixels);
4082: memset (&spixstate, 0, sizeof spixstate);
1.1 root 4083:
4084: bltstate = BLT_done;
1.1.1.4 root 4085: cop_state.state = COP_stop;
1.1.1.2 root 4086: diwstate = DIW_waiting_start;
1.1.1.3 root 4087: hdiwstate = DIW_waiting_start;
1.1.1.14 root 4088: currcycle = 0;
1.1.1.3 root 4089:
1.1.1.14 root 4090: new_beamcon0 = currprefs.ntscmode ? 0x00 : 0x20;
1.1.1.7 root 4091: init_hz ();
4092:
4093: audio_reset ();
4094:
1.1.1.3 root 4095: init_sprites ();
4096:
1.1.1.2 root 4097: init_hardware_frame ();
1.1.1.4 root 4098: reset_drawing ();
4099:
1.1.1.2 root 4100: reset_decisions ();
1.1.1.3 root 4101:
1.1 root 4102: #ifdef HAVE_GETTIMEOFDAY
1.1.1.4 root 4103: gettimeofday (&tv, NULL);
1.1 root 4104: seconds_base = tv.tv_sec;
4105: bogusframe = 1;
4106: #endif
1.1.1.15 root 4107:
4108: init_regtypes ();
4109:
4110: sprite_buffer_res = currprefs.chipset_mask & CSMASK_AGA ? RES_HIRES : RES_LORES;
4111: if (savestate_state == STATE_RESTORE) {
4112: uae_u16 v;
4113: uae_u32 vv;
4114:
4115: update_adkmasks ();
4116: INTENA (0);
4117: INTREQ (0);
4118: #if 0
4119: DMACON (0, 0);
4120: #endif
4121: COPJMP1 (0);
4122: if (diwhigh)
4123: diwhigh_written = 1;
4124: v = bplcon0;
4125: BPLCON0 (0, 0);
4126: BPLCON0 (0, v);
1.1.1.17 root 4127: FMODE (fmode);
1.1.1.15 root 4128: if (!(currprefs.chipset_mask & CSMASK_AGA)) {
4129: for(i = 0 ; i < 32 ; i++) {
4130: vv = current_colors.color_regs_ecs[i];
4131: current_colors.color_regs_ecs[i] = -1;
4132: record_color_change (0, i, vv);
4133: remembered_color_entry = -1;
4134: current_colors.color_regs_ecs[i] = vv;
4135: current_colors.acolors[i] = xcolors[vv];
4136: }
4137: } else {
4138: for(i = 0 ; i < 256 ; i++) {
1.1.1.20! root 4139: vv = current_colors.color_regs_aga[i];
1.1.1.15 root 4140: current_colors.color_regs_aga[i] = -1;
4141: record_color_change (0, i, vv);
4142: remembered_color_entry = -1;
4143: current_colors.color_regs_aga[i] = vv;
4144: current_colors.acolors[i] = CONVERT_RGB(vv);
4145: }
4146: }
1.1.1.17 root 4147: CLXCON (clxcon);
4148: CLXCON2 (clxcon2);
1.1.1.15 root 4149: calcdiw ();
4150: write_log ("State restored\n");
4151: dumpcustom ();
4152: for (i = 0; i < 8; i++)
4153: nr_armed += spr[i].armed != 0;
4154: }
4155: expand_sprres ();
1.1 root 4156: }
4157:
1.1.1.3 root 4158: void dumpcustom (void)
1.1 root 4159: {
1.1.1.6 root 4160: write_log ("DMACON: %x INTENA: %x INTREQ: %x VPOS: %x HPOS: %x\n", DMACONR(),
4161: (unsigned int)intena, (unsigned int)intreq, (unsigned int)vpos, (unsigned int)current_hpos());
4162: write_log ("COP1LC: %08lx, COP2LC: %08lx\n", (unsigned long)cop1lc, (unsigned long)cop2lc);
1.1.1.13 root 4163: write_log ("DIWSTRT: %04x DIWSTOP: %04x DDFSTRT: %04x DDFSTOP: %04x\n",
4164: (unsigned int)diwstrt, (unsigned int)diwstop, (unsigned int)ddfstrt, (unsigned int)ddfstop);
1.1.1.3 root 4165: if (timeframes) {
1.1.1.6 root 4166: write_log ("Average frame time: %d ms [frames: %d time: %d]\n",
4167: frametime / timeframes, timeframes, frametime);
4168: if (total_skipped)
4169: write_log ("Skipped frames: %d\n", total_skipped);
1.1 root 4170: }
1.1.1.18 root 4171: /*for (i=0; i<256; i++) if (blitcount[i]) write_log ("minterm %x = %d\n",i,blitcount[i]); blitter debug */
1.1 root 4172: }
4173:
1.1.1.3 root 4174: int intlev (void)
1.1 root 4175: {
1.1.1.3 root 4176: uae_u16 imask = intreq & intena;
1.1 root 4177: if (imask && (intena & 0x4000)){
4178: if (imask & 0x2000) return 6;
4179: if (imask & 0x1800) return 5;
4180: if (imask & 0x0780) return 4;
4181: if (imask & 0x0070) return 3;
4182: if (imask & 0x0008) return 2;
4183: if (imask & 0x0007) return 1;
4184: }
4185: return -1;
4186: }
4187:
1.1.1.4 root 4188: static void gen_custom_tables (void)
4189: {
4190: int i;
4191: for (i = 0; i < 256; i++) {
4192: unsigned int j;
4193: sprtaba[i] = ((((i >> 7) & 1) << 0)
4194: | (((i >> 6) & 1) << 2)
4195: | (((i >> 5) & 1) << 4)
4196: | (((i >> 4) & 1) << 6)
4197: | (((i >> 3) & 1) << 8)
4198: | (((i >> 2) & 1) << 10)
4199: | (((i >> 1) & 1) << 12)
4200: | (((i >> 0) & 1) << 14));
4201: sprtabb[i] = sprtaba[i] * 2;
1.1.1.13 root 4202: sprite_ab_merge[i] = (((i & 15) ? 1 : 0)
4203: | ((i & 240) ? 2 : 0));
1.1.1.4 root 4204: }
1.1.1.13 root 4205: for (i = 0; i < 16; i++) {
4206: clxmask[i] = (((i & 1) ? 0xF : 0x3)
4207: | ((i & 2) ? 0xF0 : 0x30)
4208: | ((i & 4) ? 0xF00 : 0x300)
4209: | ((i & 8) ? 0xF000 : 0x3000));
4210: sprclx[i] = (((i & 0x3) == 0x3 ? 1 : 0)
4211: | ((i & 0x5) == 0x5 ? 2 : 0)
4212: | ((i & 0x9) == 0x9 ? 4 : 0)
4213: | ((i & 0x6) == 0x6 ? 8 : 0)
4214: | ((i & 0xA) == 0xA ? 16 : 0)
4215: | ((i & 0xC) == 0xC ? 32 : 0)) << 9;
4216: }
1.1.1.4 root 4217: }
4218:
1.1.1.3 root 4219: void custom_init (void)
1.1 root 4220: {
1.1.1.7 root 4221: uaecptr pos;
4222:
1.1.1.4 root 4223: #ifdef OS_WITHOUT_MEMORY_MANAGEMENT
1.1 root 4224: int num;
1.1.1.2 root 4225:
1.1.1.4 root 4226: for (num = 0; num < 2; num++) {
1.1.1.13 root 4227: sprite_entries[num] = xmalloc (max_sprite_entry * sizeof (struct sprite_entry));
1.1.1.4 root 4228: color_changes[num] = xmalloc (max_color_change * sizeof (struct color_change));
1.1.1.2 root 4229: }
4230: #endif
1.1.1.3 root 4231:
1.1.1.7 root 4232: pos = here ();
4233:
1.1.1.18 root 4234: org (RTAREA_BASE+0xFF70);
1.1.1.7 root 4235: calltrap (deftrap (mousehack_helper));
4236: dw (RTS);
4237:
1.1.1.18 root 4238: org (RTAREA_BASE+0xFFA0);
1.1.1.7 root 4239: calltrap (deftrap (timehack_helper));
4240: dw (RTS);
4241:
4242: org (pos);
4243:
1.1.1.4 root 4244: gen_custom_tables ();
4245: build_blitfilltable ();
4246:
4247: drawing_init ();
4248:
4249: mousestate = unknown_mouse;
4250:
4251: if (needmousehack ())
1.1.1.16 root 4252: mousehack_setfollow ();
4253:
4254: create_cycle_diagram_table ();
1.1 root 4255: }
4256:
4257: /* Custom chip memory bank */
4258:
1.1.1.4 root 4259: static uae_u32 custom_lget (uaecptr) REGPARAM;
4260: static uae_u32 custom_wget (uaecptr) REGPARAM;
4261: static uae_u32 custom_bget (uaecptr) REGPARAM;
4262: static void custom_lput (uaecptr, uae_u32) REGPARAM;
4263: static void custom_wput (uaecptr, uae_u32) REGPARAM;
4264: static void custom_bput (uaecptr, uae_u32) REGPARAM;
1.1 root 4265:
4266: addrbank custom_bank = {
4267: custom_lget, custom_wget, custom_bget,
4268: custom_lput, custom_wput, custom_bput,
1.1.1.15 root 4269: default_xlate, default_check, NULL
1.1 root 4270: };
4271:
1.1.1.13 root 4272: STATIC_INLINE uae_u32 REGPARAM2 custom_wget_1 (uaecptr addr)
1.1 root 4273: {
1.1.1.20! root 4274: uae_u16 v;
1.1.1.13 root 4275: special_mem |= S_READ;
1.1.1.4 root 4276: switch (addr & 0x1FE) {
1.1.1.20! root 4277: case 0x002: v = DMACONR (); break;
! 4278: case 0x004: v = VPOSR (); break;
! 4279: case 0x006: v = VHPOSR (); break;
! 4280:
! 4281: case 0x008: v = DSKDATR (current_hpos ()); break;
! 4282:
! 4283: case 0x00A: v = JOY0DAT (); break;
! 4284: case 0x00C: v = JOY1DAT (); break;
! 4285: case 0x00E: v = CLXDAT (); break;
! 4286: case 0x010: v = ADKCONR (); break;
! 4287:
! 4288: case 0x012: v = POT0DAT (); break;
! 4289: case 0x016: v = POTGOR (); break;
! 4290: case 0x018: v = SERDATR (); break;
! 4291: case 0x01A: v = DSKBYTR (current_hpos ()); break;
! 4292: case 0x01C: v = INTENAR (); break;
! 4293: case 0x01E: v = INTREQR (); break;
! 4294: case 0x07C: v = DENISEID (); break;
1.1.1.13 root 4295:
4296: case 0x180: case 0x182: case 0x184: case 0x186: case 0x188: case 0x18A:
4297: case 0x18C: case 0x18E: case 0x190: case 0x192: case 0x194: case 0x196:
4298: case 0x198: case 0x19A: case 0x19C: case 0x19E: case 0x1A0: case 0x1A2:
4299: case 0x1A4: case 0x1A6: case 0x1A8: case 0x1AA: case 0x1AC: case 0x1AE:
4300: case 0x1B0: case 0x1B2: case 0x1B4: case 0x1B6: case 0x1B8: case 0x1BA:
4301: case 0x1BC: case 0x1BE:
1.1.1.20! root 4302: v = COLOR_READ ((addr & 0x3E) / 2);
1.1.1.13 root 4303: break;
4304:
1.1 root 4305: default:
1.1.1.20! root 4306: v = last_custom_value;
! 4307: custom_wput (addr, v);
! 4308: last_custom_value = 0xffff;
! 4309: return v;
1.1 root 4310: }
1.1.1.20! root 4311: last_custom_value = v;
! 4312: return v;
1.1 root 4313: }
4314:
1.1.1.13 root 4315: uae_u32 REGPARAM2 custom_wget (uaecptr addr)
4316: {
1.1.1.15 root 4317: sync_copper_with_cpu (current_hpos (), 1, addr);
1.1.1.13 root 4318: return custom_wget_1 (addr);
4319: }
4320:
1.1.1.3 root 4321: uae_u32 REGPARAM2 custom_bget (uaecptr addr)
1.1 root 4322: {
1.1.1.13 root 4323: special_mem |= S_READ;
4324: return custom_wget (addr & 0xfffe) >> (addr & 1 ? 0 : 8);
1.1 root 4325: }
4326:
1.1.1.3 root 4327: uae_u32 REGPARAM2 custom_lget (uaecptr addr)
1.1 root 4328: {
1.1.1.13 root 4329: special_mem |= S_READ;
4330: return ((uae_u32)custom_wget (addr & 0xfffe) << 16) | custom_wget ((addr + 2) & 0xfffe);
1.1 root 4331: }
4332:
1.1.1.4 root 4333: void REGPARAM2 custom_wput_1 (int hpos, uaecptr addr, uae_u32 value)
1.1 root 4334: {
4335: addr &= 0x1FE;
1.1.1.20! root 4336: last_custom_value = value;
1.1.1.3 root 4337: switch (addr) {
4338: case 0x020: DSKPTH (value); break;
4339: case 0x022: DSKPTL (value); break;
1.1.1.13 root 4340: case 0x024: DSKLEN (value, hpos); break;
1.1.1.3 root 4341: case 0x026: DSKDAT (value); break;
4342:
4343: case 0x02A: VPOSW (value); break;
1.1.1.15 root 4344: case 0x02E: COPCON (value); break;
1.1.1.3 root 4345: case 0x030: SERDAT (value); break;
4346: case 0x032: SERPER (value); break;
1.1.1.15 root 4347: case 0x034: POTGO (value); break;
1.1.1.3 root 4348: case 0x040: BLTCON0 (value); break;
4349: case 0x042: BLTCON1 (value); break;
4350:
4351: case 0x044: BLTAFWM (value); break;
4352: case 0x046: BLTALWM (value); break;
4353:
4354: case 0x050: BLTAPTH (value); break;
4355: case 0x052: BLTAPTL (value); break;
4356: case 0x04C: BLTBPTH (value); break;
4357: case 0x04E: BLTBPTL (value); break;
4358: case 0x048: BLTCPTH (value); break;
4359: case 0x04A: BLTCPTL (value); break;
4360: case 0x054: BLTDPTH (value); break;
4361: case 0x056: BLTDPTL (value); break;
4362:
4363: case 0x058: BLTSIZE (value); break;
4364:
4365: case 0x064: BLTAMOD (value); break;
4366: case 0x062: BLTBMOD (value); break;
4367: case 0x060: BLTCMOD (value); break;
4368: case 0x066: BLTDMOD (value); break;
4369:
4370: case 0x070: BLTCDAT (value); break;
4371: case 0x072: BLTBDAT (value); break;
4372: case 0x074: BLTADAT (value); break;
4373:
4374: case 0x07E: DSKSYNC (value); break;
4375:
4376: case 0x080: COP1LCH (value); break;
4377: case 0x082: COP1LCL (value); break;
4378: case 0x084: COP2LCH (value); break;
4379: case 0x086: COP2LCL (value); break;
4380:
4381: case 0x088: COPJMP1 (value); break;
4382: case 0x08A: COPJMP2 (value); break;
4383:
1.1.1.4 root 4384: case 0x08E: DIWSTRT (hpos, value); break;
4385: case 0x090: DIWSTOP (hpos, value); break;
4386: case 0x092: DDFSTRT (hpos, value); break;
4387: case 0x094: DDFSTOP (hpos, value); break;
1.1.1.3 root 4388:
1.1.1.13 root 4389: case 0x096: DMACON (hpos, value); break;
1.1.1.3 root 4390: case 0x098: CLXCON (value); break;
4391: case 0x09A: INTENA (value); break;
4392: case 0x09C: INTREQ (value); break;
4393: case 0x09E: ADKCON (value); break;
4394:
4395: case 0x0A0: AUDxLCH (0, value); break;
4396: case 0x0A2: AUDxLCL (0, value); break;
4397: case 0x0A4: AUDxLEN (0, value); break;
4398: case 0x0A6: AUDxPER (0, value); break;
4399: case 0x0A8: AUDxVOL (0, value); break;
4400: case 0x0AA: AUDxDAT (0, value); break;
4401:
4402: case 0x0B0: AUDxLCH (1, value); break;
4403: case 0x0B2: AUDxLCL (1, value); break;
4404: case 0x0B4: AUDxLEN (1, value); break;
4405: case 0x0B6: AUDxPER (1, value); break;
4406: case 0x0B8: AUDxVOL (1, value); break;
4407: case 0x0BA: AUDxDAT (1, value); break;
4408:
4409: case 0x0C0: AUDxLCH (2, value); break;
4410: case 0x0C2: AUDxLCL (2, value); break;
4411: case 0x0C4: AUDxLEN (2, value); break;
4412: case 0x0C6: AUDxPER (2, value); break;
4413: case 0x0C8: AUDxVOL (2, value); break;
4414: case 0x0CA: AUDxDAT (2, value); break;
4415:
4416: case 0x0D0: AUDxLCH (3, value); break;
4417: case 0x0D2: AUDxLCL (3, value); break;
4418: case 0x0D4: AUDxLEN (3, value); break;
4419: case 0x0D6: AUDxPER (3, value); break;
4420: case 0x0D8: AUDxVOL (3, value); break;
4421: case 0x0DA: AUDxDAT (3, value); break;
4422:
1.1.1.4 root 4423: case 0x0E0: BPLPTH (hpos, value, 0); break;
4424: case 0x0E2: BPLPTL (hpos, value, 0); break;
4425: case 0x0E4: BPLPTH (hpos, value, 1); break;
4426: case 0x0E6: BPLPTL (hpos, value, 1); break;
4427: case 0x0E8: BPLPTH (hpos, value, 2); break;
4428: case 0x0EA: BPLPTL (hpos, value, 2); break;
4429: case 0x0EC: BPLPTH (hpos, value, 3); break;
4430: case 0x0EE: BPLPTL (hpos, value, 3); break;
4431: case 0x0F0: BPLPTH (hpos, value, 4); break;
4432: case 0x0F2: BPLPTL (hpos, value, 4); break;
4433: case 0x0F4: BPLPTH (hpos, value, 5); break;
4434: case 0x0F6: BPLPTL (hpos, value, 5); break;
1.1.1.6 root 4435: case 0x0F8: BPLPTH (hpos, value, 6); break;
4436: case 0x0FA: BPLPTL (hpos, value, 6); break;
4437: case 0x0FC: BPLPTH (hpos, value, 7); break;
4438: case 0x0FE: BPLPTL (hpos, value, 7); break;
1.1.1.4 root 4439:
4440: case 0x100: BPLCON0 (hpos, value); break;
4441: case 0x102: BPLCON1 (hpos, value); break;
4442: case 0x104: BPLCON2 (hpos, value); break;
4443: case 0x106: BPLCON3 (hpos, value); break;
1.1.1.3 root 4444:
1.1.1.4 root 4445: case 0x108: BPL1MOD (hpos, value); break;
4446: case 0x10A: BPL2MOD (hpos, value); break;
1.1.1.17 root 4447: case 0x10E: CLXCON2 (value); break;
1.1.1.3 root 4448:
1.1.1.13 root 4449: case 0x110: BPL1DAT (hpos, value); break;
1.1.1.3 root 4450: case 0x112: BPL2DAT (value); break;
4451: case 0x114: BPL3DAT (value); break;
4452: case 0x116: BPL4DAT (value); break;
4453: case 0x118: BPL5DAT (value); break;
4454: case 0x11A: BPL6DAT (value); break;
1.1.1.6 root 4455: case 0x11C: BPL7DAT (value); break;
4456: case 0x11E: BPL8DAT (value); break;
1.1 root 4457:
4458: case 0x180: case 0x182: case 0x184: case 0x186: case 0x188: case 0x18A:
4459: case 0x18C: case 0x18E: case 0x190: case 0x192: case 0x194: case 0x196:
4460: case 0x198: case 0x19A: case 0x19C: case 0x19E: case 0x1A0: case 0x1A2:
4461: case 0x1A4: case 0x1A6: case 0x1A8: case 0x1AA: case 0x1AC: case 0x1AE:
4462: case 0x1B0: case 0x1B2: case 0x1B4: case 0x1B6: case 0x1B8: case 0x1BA:
1.1.1.2 root 4463: case 0x1BC: case 0x1BE:
1.1.1.13 root 4464: COLOR_WRITE (hpos, value & 0xFFF, (addr & 0x3E) / 2);
1.1.1.2 root 4465: break;
4466: case 0x120: case 0x124: case 0x128: case 0x12C:
1.1 root 4467: case 0x130: case 0x134: case 0x138: case 0x13C:
1.1.1.4 root 4468: SPRxPTH (hpos, value, (addr - 0x120) / 4);
1.1 root 4469: break;
1.1.1.2 root 4470: case 0x122: case 0x126: case 0x12A: case 0x12E:
1.1 root 4471: case 0x132: case 0x136: case 0x13A: case 0x13E:
1.1.1.4 root 4472: SPRxPTL (hpos, value, (addr - 0x122) / 4);
1.1 root 4473: break;
1.1.1.2 root 4474: case 0x140: case 0x148: case 0x150: case 0x158:
1.1 root 4475: case 0x160: case 0x168: case 0x170: case 0x178:
1.1.1.4 root 4476: SPRxPOS (hpos, value, (addr - 0x140) / 8);
1.1 root 4477: break;
1.1.1.2 root 4478: case 0x142: case 0x14A: case 0x152: case 0x15A:
1.1 root 4479: case 0x162: case 0x16A: case 0x172: case 0x17A:
1.1.1.4 root 4480: SPRxCTL (hpos, value, (addr - 0x142) / 8);
1.1 root 4481: break;
4482: case 0x144: case 0x14C: case 0x154: case 0x15C:
4483: case 0x164: case 0x16C: case 0x174: case 0x17C:
1.1.1.4 root 4484: SPRxDATA (hpos, value, (addr - 0x144) / 8);
1.1 root 4485: break;
1.1.1.2 root 4486: case 0x146: case 0x14E: case 0x156: case 0x15E:
1.1 root 4487: case 0x166: case 0x16E: case 0x176: case 0x17E:
1.1.1.4 root 4488: SPRxDATB (hpos, value, (addr - 0x146) / 8);
1.1 root 4489: break;
1.1.1.3 root 4490:
4491: case 0x36: JOYTEST (value); break;
1.1.1.7 root 4492: case 0x5A: BLTCON0L (value); break;
1.1.1.3 root 4493: case 0x5C: BLTSIZV (value); break;
4494: case 0x5E: BLTSIZH (value); break;
1.1.1.4 root 4495: case 0x1E4: DIWHIGH (hpos, value); break;
4496: case 0x10C: BPLCON4 (hpos, value); break;
1.1.1.7 root 4497: case 0x1FC: FMODE (value); break;
1.1 root 4498: }
4499: }
4500:
1.1.1.4 root 4501: void REGPARAM2 custom_wput (uaecptr addr, uae_u32 value)
4502: {
4503: int hpos = current_hpos ();
1.1.1.13 root 4504: special_mem |= S_WRITE;
4505:
1.1.1.15 root 4506: sync_copper_with_cpu (hpos, 1, addr);
1.1.1.4 root 4507: custom_wput_1 (hpos, addr, value);
4508: }
4509:
4510: void REGPARAM2 custom_bput (uaecptr addr, uae_u32 value)
1.1 root 4511: {
1.1.1.2 root 4512: static int warned = 0;
4513: /* Is this correct now? (There are people who bput things to the upper byte of AUDxVOL). */
1.1.1.3 root 4514: uae_u16 rval = (value << 8) | (value & 0xFF);
1.1.1.13 root 4515: special_mem |= S_WRITE;
1.1.1.9 root 4516: custom_wput (addr, rval);
1.1.1.2 root 4517: if (!warned)
1.1.1.3 root 4518: write_log ("Byte put to custom register.\n"), warned++;
1.1 root 4519: }
4520:
1.1.1.3 root 4521: void REGPARAM2 custom_lput(uaecptr addr, uae_u32 value)
1.1 root 4522: {
1.1.1.13 root 4523: special_mem |= S_WRITE;
1.1.1.9 root 4524: custom_wput (addr & 0xfffe, value >> 16);
4525: custom_wput ((addr + 2) & 0xfffe, (uae_u16)value);
1.1 root 4526: }
1.1.1.15 root 4527:
4528: void custom_prepare_savestate (void)
4529: {
4530: /* force blitter to finish, no support for saving full blitter state yet */
4531: if (eventtab[ev_blitter].active) {
4532: unsigned int olddmacon = dmacon;
4533: dmacon |= DMA_BLITTER; /* ugh.. */
4534: blitter_handler ();
4535: dmacon = olddmacon;
4536: }
4537: }
4538:
4539: #define RB restore_u8 ()
4540: #define RW restore_u16 ()
4541: #define RL restore_u32 ()
4542:
4543: uae_u8 *restore_custom (uae_u8 *src)
4544: {
4545: uae_u16 dsklen, dskbytr, dskdatr;
4546: int dskpt;
4547: int i;
4548:
4549: audio_reset ();
4550:
4551: currprefs.chipset_mask = RL;
4552: RW; /* 000 ? */
4553: RW; /* 002 DMACONR */
4554: RW; /* 004 VPOSR */
4555: RW; /* 006 VHPOSR */
4556: dskdatr = RW; /* 008 DSKDATR */
4557: RW; /* 00A JOY0DAT */
4558: RW; /* 00C JOY1DAT */
4559: clxdat = RW; /* 00E CLXDAT */
4560: RW; /* 010 ADKCONR */
4561: RW; /* 012 POT0DAT* */
4562: RW; /* 014 POT1DAT* */
4563: RW; /* 016 POTINP* */
4564: RW; /* 018 SERDATR* */
4565: dskbytr = RW; /* 01A DSKBYTR */
4566: RW; /* 01C INTENAR */
4567: RW; /* 01E INTREQR */
4568: dskpt = RL; /* 020-022 DSKPT */
4569: dsklen = RW; /* 024 DSKLEN */
4570: RW; /* 026 DSKDAT */
4571: RW; /* 028 REFPTR */
4572: lof = RW; /* 02A VPOSW */
4573: RW; /* 02C VHPOSW */
4574: COPCON(RW); /* 02E COPCON */
4575: RW; /* 030 SERDAT* */
4576: RW; /* 032 SERPER* */
4577: POTGO(RW); /* 034 POTGO */
4578: RW; /* 036 JOYTEST* */
4579: RW; /* 038 STREQU */
4580: RW; /* 03A STRVHBL */
4581: RW; /* 03C STRHOR */
4582: RW; /* 03E STRLONG */
4583: BLTCON0(RW); /* 040 BLTCON0 */
4584: BLTCON1(RW); /* 042 BLTCON1 */
4585: BLTAFWM(RW); /* 044 BLTAFWM */
4586: BLTALWM(RW); /* 046 BLTALWM */
4587: BLTCPTH(RL); /* 048-04B BLTCPT */
4588: BLTBPTH(RL); /* 04C-04F BLTBPT */
4589: BLTAPTH(RL); /* 050-053 BLTAPT */
4590: BLTDPTH(RL); /* 054-057 BLTDPT */
4591: RW; /* 058 BLTSIZE */
4592: RW; /* 05A BLTCON0L */
4593: oldvblts = RW; /* 05C BLTSIZV */
4594: RW; /* 05E BLTSIZH */
4595: BLTCMOD(RW); /* 060 BLTCMOD */
4596: BLTBMOD(RW); /* 062 BLTBMOD */
4597: BLTAMOD(RW); /* 064 BLTAMOD */
4598: BLTDMOD(RW); /* 066 BLTDMOD */
4599: RW; /* 068 ? */
4600: RW; /* 06A ? */
4601: RW; /* 06C ? */
4602: RW; /* 06E ? */
4603: BLTCDAT(RW); /* 070 BLTCDAT */
4604: BLTBDAT(RW); /* 072 BLTBDAT */
4605: BLTADAT(RW); /* 074 BLTADAT */
4606: RW; /* 076 ? */
4607: RW; /* 078 ? */
4608: RW; /* 07A ? */
4609: RW; /* 07C LISAID */
4610: DSKSYNC(RW); /* 07E DSKSYNC */
4611: cop1lc = RL; /* 080/082 COP1LC */
4612: cop2lc = RL; /* 084/086 COP2LC */
4613: RW; /* 088 ? */
4614: RW; /* 08A ? */
4615: RW; /* 08C ? */
4616: diwstrt = RW; /* 08E DIWSTRT */
4617: diwstop = RW; /* 090 DIWSTOP */
4618: ddfstrt = RW; /* 092 DDFSTRT */
4619: ddfstop = RW; /* 094 DDFSTOP */
4620: dmacon = RW & ~(0x2000|0x4000); /* 096 DMACON */
4621: CLXCON(RW); /* 098 CLXCON */
4622: intena = RW; /* 09A INTENA */
4623: intreq = RW; /* 09C INTREQ */
4624: adkcon = RW; /* 09E ADKCON */
4625: for (i = 0; i < 8; i++)
4626: bplpt[i] = RL;
4627: bplcon0 = RW; /* 100 BPLCON0 */
4628: bplcon1 = RW; /* 102 BPLCON1 */
4629: bplcon2 = RW; /* 104 BPLCON2 */
4630: bplcon3 = RW; /* 106 BPLCON3 */
4631: bpl1mod = RW; /* 108 BPL1MOD */
4632: bpl2mod = RW; /* 10A BPL2MOD */
4633: bplcon4 = RW; /* 10C BPLCON4 */
1.1.1.17 root 4634: clxcon2 = RW; /* 10E CLXCON2* */
1.1.1.15 root 4635: for(i = 0; i < 8; i++)
4636: RW; /* BPLXDAT */
4637: for(i = 0; i < 32; i++)
4638: current_colors.color_regs_ecs[i] = RW; /* 180 COLORxx */
4639: RW; /* 1C0 ? */
4640: RW; /* 1C2 ? */
4641: RW; /* 1C4 ? */
4642: RW; /* 1C6 ? */
4643: RW; /* 1C8 ? */
4644: RW; /* 1CA ? */
4645: RW; /* 1CC ? */
4646: RW; /* 1CE ? */
4647: RW; /* 1D0 ? */
4648: RW; /* 1D2 ? */
4649: RW; /* 1D4 ? */
4650: RW; /* 1D6 ? */
4651: RW; /* 1D8 ? */
4652: RW; /* 1DA ? */
4653: new_beamcon0 = RW; /* 1DC BEAMCON0 */
4654: RW; /* 1DE ? */
4655: RW; /* 1E0 ? */
4656: RW; /* 1E2 ? */
4657: RW; /* 1E4 ? */
4658: RW; /* 1E6 ? */
4659: RW; /* 1E8 ? */
4660: RW; /* 1EA ? */
4661: RW; /* 1EC ? */
4662: RW; /* 1EE ? */
4663: RW; /* 1F0 ? */
4664: RW; /* 1F2 ? */
4665: RW; /* 1F4 ? */
4666: RW; /* 1F6 ? */
4667: RW; /* 1F8 ? */
4668: RW; /* 1FA ? */
4669: fmode = RW; /* 1FC FMODE */
4670: RW; /* 1FE ? */
4671:
4672: DISK_restore_custom (dskpt, dsklen, dskdatr, dskbytr);
4673:
4674: return src;
4675: }
4676:
4677:
4678: #define SB save_u8
4679: #define SW save_u16
4680: #define SL save_u32
4681:
4682: extern uae_u16 serper;
4683:
4684: uae_u8 *save_custom (int *len)
4685: {
4686: uae_u8 *dstbak, *dst;
4687: int i;
4688: uae_u32 dskpt;
4689: uae_u16 dsklen, dsksync, dskdatr, dskbytr;
4690:
4691: DISK_save_custom (&dskpt, &dsklen, &dsksync, &dskdatr, &dskbytr);
4692: dstbak = dst = malloc (8+256*2);
4693: SL (currprefs.chipset_mask);
4694: SW (0); /* 000 ? */
4695: SW (dmacon); /* 002 DMACONR */
4696: SW (VPOSR()); /* 004 VPOSR */
4697: SW (VHPOSR()); /* 006 VHPOSR */
4698: SW (dskdatr); /* 008 DSKDATR */
4699: SW (JOY0DAT()); /* 00A JOY0DAT */
4700: SW (JOY1DAT()); /* 00C JOY1DAT */
4701: SW (clxdat); /* 00E CLXDAT */
4702: SW (ADKCONR()); /* 010 ADKCONR */
4703: SW (POT0DAT()); /* 012 POT0DAT */
4704: SW (POT0DAT()); /* 014 POT1DAT */
4705: SW (0) ; /* 016 POTINP * */
4706: SW (0); /* 018 SERDATR * */
4707: SW (dskbytr); /* 01A DSKBYTR */
4708: SW (INTENAR()); /* 01C INTENAR */
4709: SW (INTREQR()); /* 01E INTREQR */
4710: SL (dskpt); /* 020-023 DSKPT */
4711: SW (dsklen); /* 024 DSKLEN */
4712: SW (0); /* 026 DSKDAT */
4713: SW (0); /* 028 REFPTR */
4714: SW (lof); /* 02A VPOSW */
4715: SW (0); /* 02C VHPOSW */
4716: SW (copcon); /* 02E COPCON */
4717: SW (serper); /* 030 SERDAT * */
4718: SW (serdat); /* 032 SERPER * */
4719: SW (potgo_value); /* 034 POTGO */
4720: SW (0); /* 036 JOYTEST * */
4721: SW (0); /* 038 STREQU */
4722: SW (0); /* 03A STRVBL */
4723: SW (0); /* 03C STRHOR */
4724: SW (0); /* 03E STRLONG */
4725: SW (bltcon0); /* 040 BLTCON0 */
4726: SW (bltcon1); /* 042 BLTCON1 */
4727: SW (blt_info.bltafwm); /* 044 BLTAFWM */
4728: SW (blt_info.bltalwm); /* 046 BLTALWM */
4729: SL (bltcpt); /* 048-04B BLTCPT */
4730: SL (bltbpt); /* 04C-04F BLTCPT */
4731: SL (bltapt); /* 050-043 BLTCPT */
4732: SL (bltdpt); /* 054-057 BLTCPT */
4733: SW (0); /* 058 BLTSIZE */
4734: SW (0); /* 05A BLTCON0L (use BLTCON0 instead) */
4735: SW (oldvblts); /* 05C BLTSIZV */
4736: SW (blt_info.hblitsize); /* 05E BLTSIZH */
4737: SW (blt_info.bltcmod); /* 060 BLTCMOD */
4738: SW (blt_info.bltbmod); /* 062 BLTBMOD */
4739: SW (blt_info.bltamod); /* 064 BLTAMOD */
4740: SW (blt_info.bltdmod); /* 066 BLTDMOD */
4741: SW (0); /* 068 ? */
4742: SW (0); /* 06A ? */
4743: SW (0); /* 06C ? */
4744: SW (0); /* 06E ? */
4745: SW (blt_info.bltcdat); /* 070 BLTCDAT */
4746: SW (blt_info.bltbdat); /* 072 BLTBDAT */
4747: SW (blt_info.bltadat); /* 074 BLTADAT */
4748: SW (0); /* 076 ? */
4749: SW (0); /* 078 ? */
4750: SW (0); /* 07A ? */
4751: SW (DENISEID()); /* 07C DENISEID/LISAID */
4752: SW (dsksync); /* 07E DSKSYNC */
4753: SL (cop1lc); /* 080-083 COP1LC */
4754: SL (cop2lc); /* 084-087 COP2LC */
4755: SW (0); /* 088 ? */
4756: SW (0); /* 08A ? */
4757: SW (0); /* 08C ? */
4758: SW (diwstrt); /* 08E DIWSTRT */
4759: SW (diwstop); /* 090 DIWSTOP */
4760: SW (ddfstrt); /* 092 DDFSTRT */
4761: SW (ddfstop); /* 094 DDFSTOP */
4762: SW (dmacon); /* 096 DMACON */
4763: SW (clxcon); /* 098 CLXCON */
4764: SW (intena); /* 09A INTENA */
4765: SW (intreq); /* 09C INTREQ */
4766: SW (adkcon); /* 09E ADKCON */
4767: for (i = 0; i < 8; i++)
4768: SL (bplpt[i]); /* 0E0-0FE BPLxPT */
4769: SW (bplcon0); /* 100 BPLCON0 */
4770: SW (bplcon1); /* 102 BPLCON1 */
4771: SW (bplcon2); /* 104 BPLCON2 */
4772: SW (bplcon3); /* 106 BPLCON3 */
4773: SW (bpl1mod); /* 108 BPL1MOD */
4774: SW (bpl2mod); /* 10A BPL2MOD */
4775: SW (bplcon4); /* 10C BPLCON4 */
1.1.1.17 root 4776: SW (clxcon2); /* 10E CLXCON2 */
1.1.1.15 root 4777: for (i = 0;i < 8; i++)
4778: SW (0); /* 110 BPLxDAT */
4779: for ( i = 0; i < 32; i++)
4780: SW (current_colors.color_regs_ecs[i]); /* 180-1BE COLORxx */
4781: SW (0); /* 1C0 */
4782: SW (0); /* 1C2 */
4783: SW (0); /* 1C4 */
4784: SW (0); /* 1C6 */
4785: SW (0); /* 1C8 */
4786: SW (0); /* 1CA */
4787: SW (0); /* 1CC */
4788: SW (0); /* 1CE */
4789: SW (0); /* 1D0 */
4790: SW (0); /* 1D2 */
4791: SW (0); /* 1D4 */
4792: SW (0); /* 1D6 */
4793: SW (0); /* 1D8 */
4794: SW (0); /* 1DA */
4795: SW (beamcon0); /* 1DC BEAMCON0 */
4796: SW (0); /* 1DE */
4797: SW (0); /* 1E0 */
4798: SW (0); /* 1E2 */
4799: SW (0); /* 1E4 */
4800: SW (0); /* 1E6 */
4801: SW (0); /* 1E8 */
4802: SW (0); /* 1EA */
4803: SW (0); /* 1EC */
4804: SW (0); /* 1EE */
4805: SW (0); /* 1F0 */
4806: SW (0); /* 1F2 */
4807: SW (0); /* 1F4 */
4808: SW (0); /* 1F6 */
4809: SW (0); /* 1F8 */
4810: SW (0); /* 1FA */
4811: SW (fmode); /* 1FC FMODE */
4812: SW (0xffff); /* 1FE */
4813:
4814: *len = dst - dstbak;
4815: return dstbak;
4816: }
4817:
4818: uae_u8 *restore_custom_agacolors (uae_u8 *src)
4819: {
4820: int i;
4821:
4822: for (i = 0; i < 256; i++)
4823: current_colors.color_regs_aga[i] = RL;
4824: return src;
4825: }
4826:
4827: uae_u8 *save_custom_agacolors (int *len)
4828: {
4829: uae_u8 *dstbak, *dst;
4830: int i;
4831:
4832: dstbak = dst = malloc (256*4);
4833: for (i = 0; i < 256; i++)
4834: SL (current_colors.color_regs_aga[i]);
4835: *len = dst - dstbak;
4836: return dstbak;
4837: }
4838:
4839: uae_u8 *restore_custom_sprite (uae_u8 *src, int num)
4840: {
4841: spr[num].pt = RL; /* 120-13E SPRxPT */
4842: sprpos[num] = RW; /* 1x0 SPRxPOS */
4843: sprctl[num] = RW; /* 1x2 SPRxPOS */
4844: sprdata[num][0] = RW; /* 1x4 SPRxDATA */
4845: sprdatb[num][0] = RW; /* 1x6 SPRxDATB */
4846: sprdata[num][1] = RW;
4847: sprdatb[num][1] = RW;
4848: sprdata[num][2] = RW;
4849: sprdatb[num][2] = RW;
4850: sprdata[num][3] = RW;
4851: sprdatb[num][3] = RW;
4852: spr[num].armed = RB;
4853: return src;
4854: }
4855:
4856: uae_u8 *save_custom_sprite(int *len, int num)
4857: {
4858: uae_u8 *dstbak, *dst;
4859:
1.1.1.16 root 4860: dstbak = dst = malloc (25);
1.1.1.15 root 4861: SL (spr[num].pt); /* 120-13E SPRxPT */
4862: SW (sprpos[num]); /* 1x0 SPRxPOS */
4863: SW (sprctl[num]); /* 1x2 SPRxPOS */
4864: SW (sprdata[num][0]); /* 1x4 SPRxDATA */
4865: SW (sprdatb[num][0]); /* 1x6 SPRxDATB */
4866: SW (sprdata[num][1]);
4867: SW (sprdatb[num][1]);
4868: SW (sprdata[num][2]);
4869: SW (sprdatb[num][2]);
4870: SW (sprdata[num][3]);
4871: SW (sprdatb[num][3]);
4872: SB (spr[num].armed ? 1 : 0);
4873: *len = dst - dstbak;
4874: return dstbak;
4875: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.