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