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