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