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