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