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