|
|
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: {
1.1.1.18 root 1455: if (regno == -1 && value) {
1456: thisline_decision.ham_seen = 1;
1457: if (hpos < 0x18)
1458: thisline_decision.ham_at_start = 1;
1459: }
1460:
1.1.1.3 root 1461: /* Early positions don't appear on-screen. */
1.1.1.4 root 1462: if (framecnt != 0 || vpos < minfirstline || hpos < 0x18
1.1.1.3 root 1463: /*|| currprefs.emul_accuracy == 0*/)
1464: return;
1465:
1.1.1.4 root 1466: decide_diw (hpos);
1467: decide_line (hpos);
1.1.1.3 root 1468:
1.1.1.13 root 1469: if (thisline_decision.ctable == -1)
1470: remember_ctable ();
1.1.1.3 root 1471:
1472: #ifdef OS_WITHOUT_MEMORY_MANAGEMENT
1.1.1.4 root 1473: if (next_color_change >= max_color_change) {
1.1.1.3 root 1474: ++delta_color_change;
1475: return;
1476: }
1477: #endif
1.1.1.4 root 1478: curr_color_changes[next_color_change].linepos = hpos;
1.1.1.3 root 1479: curr_color_changes[next_color_change].regno = regno;
1480: curr_color_changes[next_color_change++].value = value;
1481: }
1482:
1.1.1.15 root 1483: typedef int sprbuf_res_t, cclockres_t, hwres_t, bplres_t;
1484:
1485: static void do_playfield_collisions (void)
1486: {
1487: uae_u8 *ld = line_data[next_lineno];
1488: int i;
1489:
1490: if (clxcon_bpl_enable == 0) {
1491: clxdat |= 1;
1492: return;
1493: }
1494:
1495: for (i = thisline_decision.plfleft; i < thisline_decision.plfright; i += 2) {
1496: int j;
1497: uae_u32 total = 0xFFFFFFFF;
1498: for (j = 0; j < 8; j++) {
1499: uae_u32 t = 0;
1500: if ((clxcon_bpl_enable & (1 << j)) == 0)
1501: t = 0xFFFFFFFF;
1502: else if (j < thisline_decision.nr_planes) {
1503: t = *(uae_u32 *)(line_data[next_lineno] + 2 * i + 2 * j * MAX_WORDS_PER_LINE);
1504: t ^= ~(((clxcon_bpl_match >> j) & 1) - 1);
1505: }
1506: total &= t;
1507: }
1508: if (total)
1509: clxdat |= 1;
1510: }
1511: }
1512:
1.1.1.13 root 1513: /* Sprite-to-sprite collisions are taken care of in record_sprite. This one does
1514: playfield/sprite collisions.
1515: That's the theory. In practice this doesn't work yet. I also suspect this code
1516: is way too slow. */
1517: static void do_sprite_collisions (void)
1.1.1.2 root 1518: {
1.1.1.13 root 1519: int nr_sprites = curr_drawinfo[next_lineno].nr_sprites;
1520: int first = curr_drawinfo[next_lineno].first_sprite_entry;
1521: int i;
1522: unsigned int collision_mask = clxmask[clxcon >> 12];
1.1.1.15 root 1523: int bplres = GET_RES (bplcon0);
1524: hwres_t ddf_left = thisline_decision.plfleft * 2 << bplres;
1525: hwres_t hw_diwlast = coord_window_to_diw_x (thisline_decision.diwlastword);
1526: hwres_t hw_diwfirst = coord_window_to_diw_x (thisline_decision.diwfirstword);
1527:
1528: if (clxcon_bpl_enable == 0) {
1529: clxdat |= 0x1FE;
1530: return;
1531: }
1.1.1.2 root 1532:
1.1.1.13 root 1533: for (i = 0; i < nr_sprites; i++) {
1534: struct sprite_entry *e = curr_sprite_entries + first + i;
1.1.1.15 root 1535: sprbuf_res_t j;
1536: sprbuf_res_t minpos = e->pos;
1537: sprbuf_res_t maxpos = e->max;
1538: hwres_t minp1 = minpos >> sprite_buffer_res;
1539: hwres_t maxp1 = maxpos >> sprite_buffer_res;
1540:
1541: if (maxp1 > hw_diwlast)
1542: maxpos = hw_diwlast << sprite_buffer_res;
1543: if (maxp1 > thisline_decision.plfright * 2)
1544: maxpos = thisline_decision.plfright * 2 << sprite_buffer_res;
1545: if (minp1 < hw_diwfirst)
1546: minpos = hw_diwfirst << sprite_buffer_res;
1547: if (minp1 < thisline_decision.plfleft * 2)
1548: minpos = thisline_decision.plfleft * 2 << sprite_buffer_res;
1.1.1.13 root 1549:
1550: for (j = minpos; j < maxpos; j++) {
1551: int sprpix = spixels[e->first_pixel + j - e->pos] & collision_mask;
1552: int k;
1.1.1.15 root 1553: int offs;
1.1.1.2 root 1554:
1.1.1.13 root 1555: if (sprpix == 0)
1556: continue;
1.1.1.2 root 1557:
1.1.1.15 root 1558: offs = ((j << bplres) >> sprite_buffer_res) - ddf_left;
1.1.1.13 root 1559: sprpix = sprite_ab_merge[sprpix & 255] | (sprite_ab_merge[sprpix >> 8] << 2);
1560: sprpix <<= 1;
1.1.1.2 root 1561:
1.1.1.13 root 1562: /* Loop over number of playfields. */
1563: for (k = 0; k < 2; k++) {
1564: int l;
1565: int match = 1;
1.1.1.14 root 1566: int planes = ((currprefs.chipset_mask & CSMASK_AGA) ? 8 : 6);
1.1.1.13 root 1567:
1.1.1.15 root 1568: for (l = k; match && l < planes; l += 2) {
1.1.1.14 root 1569: if (clxcon_bpl_enable & (1 << l)) {
1.1.1.13 root 1570: int t = 0;
1571: if (l < thisline_decision.nr_planes) {
1572: uae_u32 *ldata = (uae_u32 *)(line_data[next_lineno] + 2 * l * MAX_WORDS_PER_LINE);
1573: uae_u32 word = ldata[offs >> 5];
1574: t = (word >> (31 - (offs & 31))) & 1;
1575: }
1.1.1.14 root 1576: if (t != ((clxcon_bpl_match >> l) & 1))
1.1.1.13 root 1577: match = 0;
1578: }
1.1.1.15 root 1579: }
1.1.1.13 root 1580: if (match)
1581: clxdat |= sprpix;
1582: sprpix <<= 4;
1583: }
1.1.1.2 root 1584: }
1585: }
1586: }
1587:
1.1.1.15 root 1588: static void expand_sprres (void)
1589: {
1590: switch ((bplcon3 >> 6) & 3) {
1591: case 0: /* ECS defaults (LORES,HIRES=140ns,SHRES=70ns) */
1592: if ((currprefs.chipset_mask & CSMASK_ECS_DENISE) && GET_RES (bplcon0) == RES_SUPERHIRES)
1593: sprres = RES_HIRES;
1594: else
1595: sprres = RES_LORES;
1596: break;
1597: case 1:
1598: sprres = RES_LORES;
1599: break;
1600: case 2:
1601: sprres = RES_HIRES;
1602: break;
1603: case 3:
1604: sprres = RES_SUPERHIRES;
1605: break;
1606: }
1607: }
1608:
1609: STATIC_INLINE void record_sprite_1 (uae_u16 *buf, uae_u32 datab, int num, int dbl,
1610: unsigned int mask, int do_collisions, uae_u32 collision_mask)
1611: {
1612: int j = 0;
1613: while (datab) {
1614: unsigned int tmp = *buf;
1615: unsigned int col = (datab & 3) << (2 * num);
1616: tmp |= col;
1617: if ((j & mask) == 0)
1618: *buf++ = tmp;
1619: if (dbl)
1620: *buf++ = tmp;
1621: j++;
1622: datab >>= 2;
1623: if (do_collisions) {
1624: tmp &= collision_mask;
1625: if (tmp) {
1626: unsigned int shrunk_tmp = sprite_ab_merge[tmp & 255] | (sprite_ab_merge[tmp >> 8] << 2);
1627: clxdat |= sprclx[shrunk_tmp];
1628: }
1629: }
1630: }
1631: }
1632:
1.1.1.13 root 1633: /* DATAB contains the sprite data; 16 pixels in two-bit packets. Bits 0/1
1634: determine the color of the leftmost pixel, bits 2/3 the color of the next
1635: etc.
1636: This function assumes that for all sprites in a given line, SPRXP either
1.1.1.15 root 1637: stays equal or increases between successive calls.
1638:
1639: The data is recorded either in lores pixels (if ECS), or in hires pixels
1640: (if AGA). No support for SHRES sprites. */
1641:
1642: static void record_sprite (int line, int num, int sprxp, uae_u16 *data, uae_u16 *datb, unsigned int ctl)
1.1.1.2 root 1643: {
1.1.1.13 root 1644: struct sprite_entry *e = curr_sprite_entries + next_sprite_entry;
1645: int i;
1646: int word_offs;
1647: uae_u16 *buf;
1648: uae_u32 collision_mask;
1.1.1.15 root 1649: int width = sprite_width;
1650: int dbl = 0;
1651: unsigned int mask = 0;
1.1.1.13 root 1652:
1.1.1.15 root 1653: if (sprres != RES_LORES)
1654: thisline_decision.any_hires_sprites = 1;
1655:
1656: if (currprefs.chipset_mask & CSMASK_AGA) {
1657: width = (width << 1) >> sprres;
1658: dbl = sprite_buffer_res - sprres;
1659: mask = sprres == RES_SUPERHIRES ? 1 : 0;
1660: }
1.1.1.13 root 1661:
1662: /* Try to coalesce entries if they aren't too far apart. */
1.1.1.15 root 1663: if (! next_sprite_forced && e[-1].max + 16 >= sprxp) {
1.1.1.13 root 1664: e--;
1.1.1.15 root 1665: } else {
1.1.1.13 root 1666: next_sprite_entry++;
1667: e->pos = sprxp;
1668: e->has_attached = 0;
1669: }
1.1.1.15 root 1670:
1.1.1.13 root 1671: if (sprxp < e->pos)
1672: abort ();
1.1.1.15 root 1673:
1674: e->max = sprxp + width;
1.1.1.13 root 1675: e[1].first_pixel = e->first_pixel + ((e->max - e->pos + 3) & ~3);
1676: next_sprite_forced = 0;
1677:
1678: collision_mask = clxmask[clxcon >> 12];
1679: word_offs = e->first_pixel + sprxp - e->pos;
1.1.1.15 root 1680:
1681: for (i = 0; i < sprite_width; i += 16) {
1682: unsigned int da = *data;
1683: unsigned int db = *datb;
1684: uae_u32 datab = ((sprtaba[da & 0xFF] << 16) | sprtaba[da >> 8]
1685: | (sprtabb[db & 0xFF] << 16) | sprtabb[db >> 8]);
1686:
1687: buf = spixels + word_offs + (i << dbl);
1688: if (currprefs.collision_level > 0 && collision_mask)
1689: record_sprite_1 (buf, datab, num, dbl, mask, 1, collision_mask);
1690: else
1691: record_sprite_1 (buf, datab, num, dbl, mask, 0, collision_mask);
1692: data++;
1693: datb++;
1.1.1.2 root 1694: }
1695:
1.1.1.13 root 1696: /* We have 8 bits per pixel in spixstate, two for every sprite pair. The
1697: low order bit records whether the attach bit was set for this pair. */
1698:
1699: if (ctl & (num << 7) & 0x80) {
1700: uae_u32 state = 0x01010101 << (num - 1);
1701: uae_u32 *stbuf = spixstate.words + (word_offs >> 2);
1702: uae_u8 *stb1 = spixstate.bytes + word_offs;
1.1.1.15 root 1703: for (i = 0; i < width; i += 8) {
1704: stb1[0] |= state;
1705: stb1[1] |= state;
1706: stb1[2] |= state;
1707: stb1[3] |= state;
1708: stb1[4] |= state;
1709: stb1[5] |= state;
1710: stb1[6] |= state;
1711: stb1[7] |= state;
1712: stb1 += 8;
1713: }
1.1.1.13 root 1714: e->has_attached = 1;
1.1.1.3 root 1715: }
1716: }
1.1.1.2 root 1717:
1.1.1.4 root 1718: static void decide_sprites (int hpos)
1.1.1.3 root 1719: {
1.1.1.7 root 1720: int nrs[MAX_SPRITES], posns[MAX_SPRITES];
1721: int count, i;
1.1.1.15 root 1722: int point = hpos * 2;
1723: int width = sprite_width;
1724: int window_width = (width << lores_shift) >> sprres;
1.1.1.2 root 1725:
1.1.1.4 root 1726: if (framecnt != 0 || hpos < 0x14 || nr_armed == 0 || point == last_sprite_point)
1.1.1.2 root 1727: return;
1728:
1.1.1.4 root 1729: decide_diw (hpos);
1730: decide_line (hpos);
1.1.1.3 root 1731:
1.1.1.13 root 1732: #if 0
1733: /* This tries to detect whether the line is border, but that doesn't work, it's too early. */
1734: if (thisline_decision.plfleft == -1)
1.1.1.2 root 1735: return;
1.1.1.13 root 1736: #endif
1.1.1.3 root 1737: count = 0;
1.1.1.15 root 1738: for (i = 0; i < MAX_SPRITES; i++) {
1.1.1.10 root 1739: int sprxp = spr[i].xpos;
1.1.1.15 root 1740: int hw_xp = (sprxp >> sprite_buffer_res);
1741: int window_xp = coord_hw_to_window_x (hw_xp) + (DIW_DDF_OFFSET << lores_shift);
1.1.1.3 root 1742: int j, bestp;
1.1.1.2 root 1743:
1.1.1.15 root 1744: /* ??? It is uncertain where exactly sprite data is needed. It appears
1745: to be used some time after the actual position given in SPRxPOS.
1746: How soon after is an open question. For Battle Squadron, using a
1747: value of 5 seems to be enough to meet all timing constraints.
1748: This gives it 2 more color clock cycles until the data appears on
1749: the screen. */
1750: hw_xp += 5;
1751: if (! spr[i].armed || sprxp < 0 || hw_xp <= last_sprite_point || hw_xp > point)
1.1.1.3 root 1752: continue;
1.1.1.15 root 1753: if ((thisline_decision.diwfirstword >= 0 && window_xp + window_width < thisline_decision.diwfirstword)
1754: || (thisline_decision.diwlastword >= 0 && window_xp > thisline_decision.diwlastword))
1.1.1.3 root 1755: continue;
1.1.1.2 root 1756:
1.1.1.13 root 1757: /* Sort the sprites in order of ascending X position before recording them. */
1.1.1.3 root 1758: for (bestp = 0; bestp < count; bestp++) {
1759: if (posns[bestp] > sprxp)
1760: break;
1761: if (posns[bestp] == sprxp && nrs[bestp] < i)
1762: break;
1763: }
1764: for (j = count; j > bestp; j--) {
1765: posns[j] = posns[j-1];
1766: nrs[j] = nrs[j-1];
1767: }
1768: posns[j] = sprxp;
1769: nrs[j] = i;
1770: count++;
1771: }
1.1.1.13 root 1772: for (i = 0; i < count; i++) {
1773: int nr = nrs[i];
1.1.1.15 root 1774: record_sprite (next_lineno, nr, spr[nr].xpos, sprdata[nr], sprdatb[nr], sprctl[nr]);
1.1.1.13 root 1775: }
1.1.1.3 root 1776: last_sprite_point = point;
1.1.1.2 root 1777: }
1778:
1.1.1.13 root 1779: STATIC_INLINE int sprites_differ (struct draw_info *dip, struct draw_info *dip_old)
1780: {
1781: struct sprite_entry *this_first = curr_sprite_entries + dip->first_sprite_entry;
1782: struct sprite_entry *this_last = curr_sprite_entries + dip->last_sprite_entry;
1783: struct sprite_entry *prev_first = prev_sprite_entries + dip_old->first_sprite_entry;
1784: int npixels;
1785: int i;
1786:
1787: if (dip->nr_sprites != dip_old->nr_sprites)
1788: return 1;
1789:
1790: if (dip->nr_sprites == 0)
1791: return 0;
1792:
1793: for (i = 0; i < dip->nr_sprites; i++)
1794: if (this_first[i].pos != prev_first[i].pos
1795: || this_first[i].max != prev_first[i].max
1796: || this_first[i].has_attached != prev_first[i].has_attached)
1797: return 1;
1798:
1799: npixels = this_last->first_pixel + (this_last->max - this_last->pos) - this_first->first_pixel;
1800: if (memcmp (spixels + this_first->first_pixel, spixels + prev_first->first_pixel,
1801: npixels * sizeof (uae_u16)) != 0)
1802: return 1;
1803: if (memcmp (spixstate.bytes + this_first->first_pixel, spixstate.bytes + prev_first->first_pixel, npixels) != 0)
1804: return 1;
1805: return 0;
1806: }
1807:
1808: STATIC_INLINE int color_changes_differ (struct draw_info *dip, struct draw_info *dip_old)
1809: {
1810: if (dip->nr_color_changes != dip_old->nr_color_changes)
1811: return 1;
1812:
1813: if (dip->nr_color_changes == 0)
1814: return 0;
1815: if (memcmp (curr_color_changes + dip->first_color_change,
1816: prev_color_changes + dip_old->first_color_change,
1817: dip->nr_color_changes * sizeof *curr_color_changes) != 0)
1818: return 1;
1819: return 0;
1820: }
1821:
1.1.1.3 root 1822: /* End of a horizontal scan line. Finish off all decisions that were not
1823: * made yet. */
1.1.1.2 root 1824: static void finish_decisions (void)
1825: {
1826: struct draw_info *dip;
1827: struct draw_info *dip_old;
1828: struct decision *dp;
1829: int changed;
1.1.1.4 root 1830: int hpos = current_hpos ();
1.1.1.2 root 1831:
1832: if (framecnt != 0)
1833: return;
1834:
1.1.1.4 root 1835: decide_diw (hpos);
1.1.1.13 root 1836: decide_line (hpos);
1837: decide_fetch (hpos);
1838:
1839: if (thisline_decision.plfleft != -1 && thisline_decision.plflinelen == -1) {
1840: if (fetch_state != fetch_not_started)
1841: abort ();
1842: thisline_decision.plfright = thisline_decision.plfleft;
1843: thisline_decision.plflinelen = 0;
1844: thisline_decision.bplres = RES_LORES;
1845: }
1.1.1.3 root 1846:
1847: /* Large DIWSTOP values can cause the stop position never to be
1848: * reached, so the state machine always stays in the same state and
1849: * there's a more-or-less full-screen DIW. */
1.1.1.13 root 1850: if (hdiwstate == DIW_waiting_stop || thisline_decision.diwlastword > max_diwlastword)
1.1.1.3 root 1851: thisline_decision.diwlastword = max_diwlastword;
1852:
1.1.1.13 root 1853: if (thisline_decision.diwfirstword != line_decisions[next_lineno].diwfirstword)
1854: MARK_LINE_CHANGED;
1855: if (thisline_decision.diwlastword != line_decisions[next_lineno].diwlastword)
1856: MARK_LINE_CHANGED;
1.1.1.2 root 1857:
1858: dip = curr_drawinfo + next_lineno;
1859: dip_old = prev_drawinfo + next_lineno;
1860: dp = line_decisions + next_lineno;
1.1.1.5 root 1861: changed = thisline_changed;
1.1.1.2 root 1862:
1.1.1.13 root 1863: if (thisline_decision.plfleft != -1) {
1864: record_diw_line (thisline_decision.diwfirstword, thisline_decision.diwlastword);
1.1.1.2 root 1865:
1.1.1.4 root 1866: decide_sprites (hpos);
1.1.1.2 root 1867: }
1868:
1.1.1.13 root 1869: dip->last_sprite_entry = next_sprite_entry;
1.1.1.2 root 1870: dip->last_color_change = next_color_change;
1.1.1.3 root 1871:
1872: if (thisline_decision.ctable == -1) {
1.1.1.13 root 1873: if (thisline_decision.plfleft == -1)
1.1.1.3 root 1874: remember_ctable_for_border ();
1.1.1.13 root 1875: else
1876: remember_ctable ();
1.1.1.3 root 1877: }
1.1.1.2 root 1878:
1879: dip->nr_color_changes = next_color_change - dip->first_color_change;
1.1.1.13 root 1880: dip->nr_sprites = next_sprite_entry - dip->first_sprite_entry;
1.1.1.2 root 1881:
1.1.1.13 root 1882: if (thisline_decision.plfleft != line_decisions[next_lineno].plfleft)
1.1.1.2 root 1883: changed = 1;
1.1.1.13 root 1884: if (! changed && color_changes_differ (dip, dip_old))
1.1.1.2 root 1885: changed = 1;
1.1.1.13 root 1886: if (!changed && thisline_decision.plfleft != -1 && sprites_differ (dip, dip_old))
1.1.1.10 root 1887: changed = 1;
1.1.1.2 root 1888:
1889: if (changed) {
1.1.1.5 root 1890: thisline_changed = 1;
1.1.1.2 root 1891: *dp = thisline_decision;
1892: } else
1893: /* The only one that may differ: */
1894: dp->ctable = thisline_decision.ctable;
1895: }
1896:
1.1.1.3 root 1897: /* Set the state of all decisions to "undecided" for a new scanline. */
1.1.1.2 root 1898: static void reset_decisions (void)
1899: {
1900: if (framecnt != 0)
1901: return;
1.1.1.13 root 1902:
1.1.1.15 root 1903: thisline_decision.any_hires_sprites = 0;
1.1.1.13 root 1904: thisline_decision.nr_planes = 0;
1905:
1.1.1.10 root 1906: thisline_decision.plfleft = -1;
1.1.1.13 root 1907: thisline_decision.plflinelen = -1;
1.1.1.18 root 1908: thisline_decision.ham_seen = !! (bplcon0 & 0x800);
1909: thisline_decision.ham_at_start = !! (bplcon0 & 0x800);
1.1.1.10 root 1910:
1.1.1.7 root 1911: /* decided_res shouldn't be touched before it's initialized by decide_line(). */
1.1.1.2 root 1912: thisline_decision.diwfirstword = -1;
1913: thisline_decision.diwlastword = -2;
1.1.1.3 root 1914: if (hdiwstate == DIW_waiting_stop) {
1.1.1.13 root 1915: thisline_decision.diwfirstword = 0;
1.1.1.3 root 1916: if (thisline_decision.diwfirstword != line_decisions[next_lineno].diwfirstword)
1.1.1.5 root 1917: MARK_LINE_CHANGED;
1.1.1.3 root 1918: }
1.1.1.2 root 1919: thisline_decision.ctable = -1;
1920:
1.1.1.5 root 1921: thisline_changed = 0;
1.1.1.2 root 1922: curr_drawinfo[next_lineno].first_color_change = next_color_change;
1.1.1.13 root 1923: curr_drawinfo[next_lineno].first_sprite_entry = next_sprite_entry;
1924: next_sprite_forced = 1;
1.1.1.2 root 1925:
1.1.1.3 root 1926: /* memset(sprite_last_drawn_at, 0, sizeof sprite_last_drawn_at); */
1927: last_sprite_point = 0;
1.1.1.13 root 1928: fetch_state = fetch_not_started;
1929: passed_plfstop = 0;
1930:
1931: memset (todisplay, 0, sizeof todisplay);
1932: memset (fetched, 0, sizeof fetched);
1.1.1.14 root 1933: memset (fetched_aga0, 0, sizeof fetched_aga0);
1934: memset (fetched_aga1, 0, sizeof fetched_aga1);
1.1.1.13 root 1935: memset (outword, 0, sizeof outword);
1.1.1.9 root 1936:
1.1.1.13 root 1937: last_decide_line_hpos = -1;
1.1.1.9 root 1938: last_diw_pix_hpos = -1;
1939: last_ddf_pix_hpos = -1;
1.1.1.13 root 1940: last_sprite_hpos = -1;
1941: last_fetch_hpos = -1;
1.1.1.2 root 1942: }
1943:
1.1.1.7 root 1944: /* set PAL or NTSC timing variables */
1945:
1946: static void init_hz (void)
1947: {
1948: int isntsc;
1949:
1950: beamcon0 = new_beamcon0;
1951:
1952: isntsc = beamcon0 & 0x20 ? 0 : 1;
1953: if (!isntsc) {
1954: maxvpos = MAXVPOS_PAL;
1955: maxhpos = MAXHPOS_PAL;
1956: minfirstline = MINFIRSTLINE_PAL;
1957: vblank_endline = VBLANK_ENDLINE_PAL;
1958: vblank_hz = VBLANK_HZ_PAL;
1959: } else {
1960: maxvpos = MAXVPOS_NTSC;
1961: maxhpos = MAXHPOS_NTSC;
1962: minfirstline = MINFIRSTLINE_NTSC;
1963: vblank_endline = VBLANK_ENDLINE_NTSC;
1964: vblank_hz = VBLANK_HZ_NTSC;
1965: }
1966: vsynctime = syncbase / vblank_hz;
1967:
1968: write_log ("Using %s timing\n", isntsc ? "NTSC" : "PAL");
1969: }
1970:
1.1.1.11 root 1971: static void calcdiw (void)
1972: {
1.1.1.4 root 1973: int hstrt = diwstrt & 0xFF;
1974: int hstop = diwstop & 0xFF;
1975: int vstrt = diwstrt >> 8;
1976: int vstop = diwstop >> 8;
1977:
1978: if (diwhigh_written) {
1979: hstrt |= ((diwhigh >> 5) & 1) << 8;
1980: hstop |= ((diwhigh >> 13) & 1) << 8;
1981: vstrt |= (diwhigh & 7) << 8;
1982: vstop |= ((diwhigh >> 8) & 7) << 8;
1983: } else {
1984: hstop += 0x100;
1985: if ((vstop & 0x80) == 0)
1986: vstop |= 0x100;
1987: }
1988:
1.1.1.13 root 1989: diwfirstword = coord_diw_to_window_x (hstrt);
1990: diwlastword = coord_diw_to_window_x (hstop);
1.1.1.2 root 1991: if (diwfirstword < 0)
1992: diwfirstword = 0;
1.1.1.3 root 1993:
1.1.1.4 root 1994: plffirstline = vstrt;
1995: plflastline = vstop;
1996:
1.1 root 1997: #if 0
1998: /* This happens far too often. */
1999: if (plffirstline < minfirstline) {
1.1.1.18 root 2000: write_log ("Warning: Playfield begins before line %d!\n", minfirstline);
1.1 root 2001: plffirstline = minfirstline;
2002: }
2003: #endif
1.1.1.4 root 2004:
1.1 root 2005: #if 0 /* Turrican does this */
2006: if (plflastline > 313) {
1.1.1.18 root 2007: write_log ("Warning: Playfield out of range!\n");
1.1 root 2008: plflastline = 313;
2009: }
2010: #endif
1.1.1.2 root 2011: plfstrt = ddfstrt;
2012: plfstop = ddfstop;
1.1.1.13 root 2013: if (plfstrt < 0x18)
2014: plfstrt = 0x18;
1.1 root 2015: }
2016:
1.1.1.4 root 2017: /* Mousehack stuff */
1.1.1.2 root 2018:
1.1.1.4 root 2019: #define defstepx (1<<16)
2020: #define defstepy (1<<16)
2021: #define defxoffs 0
2022: #define defyoffs 0
1.1.1.3 root 2023:
1.1.1.4 root 2024: static const int docal = 60, xcaloff = 40, ycaloff = 20;
2025: static const int calweight = 3;
2026: static int lastsampledmx, lastsampledmy;
2027: static int lastspr0x,lastspr0y,lastdiffx,lastdiffy,spr0pos,spr0ctl;
2028: static int mstepx,mstepy,xoffs=defxoffs,yoffs=defyoffs;
2029: static int sprvbfl;
1.1.1.2 root 2030:
1.1.1.4 root 2031: int lastmx, lastmy;
2032: int newmousecounters;
2033: int ievent_alive = 0;
1.1 root 2034:
1.1.1.4 root 2035: static enum { unknown_mouse, normal_mouse, dont_care_mouse, follow_mouse } mousestate;
1.1 root 2036:
1.1.1.4 root 2037: static void mousehack_setdontcare (void)
1.1 root 2038: {
1.1.1.4 root 2039: if (mousestate == dont_care_mouse)
1.1.1.2 root 2040: return;
2041:
1.1.1.3 root 2042: write_log ("Don't care mouse mode set\n");
2043: mousestate = dont_care_mouse;
2044: lastspr0x = lastmx; lastspr0y = lastmy;
2045: mstepx = defstepx; mstepy = defstepy;
2046: }
2047:
1.1.1.4 root 2048: static void mousehack_setfollow (void)
1.1.1.3 root 2049: {
1.1.1.4 root 2050: if (mousestate == follow_mouse)
2051: return;
2052:
1.1.1.3 root 2053: write_log ("Follow sprite mode set\n");
2054: mousestate = follow_mouse;
2055: lastdiffx = lastdiffy = 0;
2056: sprvbfl = 0;
1.1.1.4 root 2057: spr0ctl = spr0pos = 0;
1.1.1.3 root 2058: mstepx = defstepx; mstepy = defstepy;
2059: }
2060:
1.1.1.7 root 2061: static uae_u32 mousehack_helper (void)
1.1.1.3 root 2062: {
2063: int mousexpos, mouseypos;
2064:
2065: #ifdef PICASSO96
2066: if (picasso_on) {
1.1.1.17 root 2067: picasso_clip_mouse (&lastmx, &lastmy);
2068: mousexpos = lastmx;
2069: mouseypos = lastmy;
1.1.1.3 root 2070: } else
2071: #endif
2072: {
1.1.1.17 root 2073: /* @@@ This isn't completely right, it doesn't deal with virtual
2074: screen sizes larger than physical very well. */
1.1.1.3 root 2075: if (lastmy >= gfxvidinfo.height)
1.1.1.4 root 2076: lastmy = gfxvidinfo.height - 1;
1.1.1.17 root 2077: if (lastmy < 0)
2078: lastmy = 0;
2079: if (lastmx < 0)
2080: lastmx = 0;
2081: if (lastmx >= gfxvidinfo.width)
2082: lastmx = gfxvidinfo.width - 1;
1.1.1.4 root 2083: mouseypos = coord_native_to_amiga_y (lastmy) << 1;
2084: mousexpos = coord_native_to_amiga_x (lastmx);
1.1.1.3 root 2085: }
2086:
2087: switch (m68k_dreg (regs, 0)) {
1.1.1.15 root 2088: case 0:
1.1.1.3 root 2089: return ievent_alive ? -1 : needmousehack ();
1.1.1.15 root 2090: case 1:
1.1.1.3 root 2091: ievent_alive = 10;
2092: return mousexpos;
1.1.1.15 root 2093: case 2:
1.1.1.3 root 2094: return mouseypos;
2095: }
2096: return 0;
2097: }
2098:
1.1.1.4 root 2099: void togglemouse (void)
1.1.1.3 root 2100: {
1.1.1.4 root 2101: switch (mousestate) {
2102: case dont_care_mouse: mousehack_setfollow (); break;
2103: case follow_mouse: mousehack_setdontcare (); break;
1.1.1.3 root 2104: default: break; /* Nnnnnghh! */
2105: }
2106: }
2107:
1.1.1.8 root 2108: STATIC_INLINE int adjust (int val)
1.1.1.3 root 2109: {
1.1.1.4 root 2110: if (val > 127)
1.1.1.3 root 2111: return 127;
1.1.1.4 root 2112: else if (val < -127)
1.1.1.3 root 2113: return -127;
2114: return val;
2115: }
2116:
1.1.1.4 root 2117: static void do_mouse_hack (void)
1.1.1.3 root 2118: {
2119: int spr0x = ((spr0pos & 0xff) << 2) | ((spr0ctl & 1) << 1);
2120: int spr0y = ((spr0pos >> 8) | ((spr0ctl & 4) << 6)) << 1;
2121: int diffx, diffy;
2122:
2123: if (ievent_alive > 0) {
2124: mouse_x = mouse_y = 0;
2125: return;
2126: }
2127: switch (mousestate) {
1.1.1.11 root 2128: case normal_mouse:
1.1.1.3 root 2129: diffx = lastmx - lastsampledmx;
2130: diffy = lastmy - lastsampledmy;
2131: if (!newmousecounters) {
2132: if (diffx > 127) diffx = 127;
2133: if (diffx < -127) diffx = -127;
2134: mouse_x += diffx;
2135: if (diffy > 127) diffy = 127;
2136: if (diffy < -127) diffy = -127;
2137: mouse_y += diffy;
2138: }
2139: lastsampledmx += diffx; lastsampledmy += diffy;
2140: break;
2141:
1.1.1.11 root 2142: case dont_care_mouse:
1.1.1.4 root 2143: diffx = adjust (((lastmx - lastspr0x) * mstepx) >> 16);
2144: diffy = adjust (((lastmy - lastspr0y) * mstepy) >> 16);
2145: lastspr0x = lastmx; lastspr0y = lastmy;
2146: mouse_x += diffx; mouse_y += diffy;
1.1.1.3 root 2147: break;
2148:
1.1.1.11 root 2149: case follow_mouse:
1.1.1.4 root 2150: if (sprvbfl && sprvbfl-- > 1) {
1.1.1.3 root 2151: int mousexpos, mouseypos;
2152:
1.1.1.4 root 2153: if ((lastdiffx > docal || lastdiffx < -docal)
2154: && lastspr0x != spr0x
2155: && spr0x > plfstrt*4 + 34 + xcaloff
2156: && spr0x < plfstop*4 - xcaloff)
1.1.1.3 root 2157: {
2158: int val = (lastdiffx << 16) / (spr0x - lastspr0x);
1.1.1.4 root 2159: if (val >= 0x8000)
2160: mstepx = (mstepx * (calweight - 1) + val) / calweight;
1.1.1.3 root 2161: }
1.1.1.4 root 2162: if ((lastdiffy > docal || lastdiffy < -docal)
2163: && lastspr0y != spr0y
2164: && spr0y > plffirstline + ycaloff
2165: && spr0y < plflastline - ycaloff)
1.1.1.3 root 2166: {
1.1.1.4 root 2167: int val = (lastdiffy << 16) / (spr0y - lastspr0y);
2168: if (val >= 0x8000)
2169: mstepy = (mstepy * (calweight - 1) + val) / calweight;
1.1.1.3 root 2170: }
2171: if (lastmy >= gfxvidinfo.height)
2172: lastmy = gfxvidinfo.height-1;
1.1.1.4 root 2173: mouseypos = coord_native_to_amiga_y (lastmy) << 1;
2174: mousexpos = coord_native_to_amiga_x (lastmx);
1.1.1.3 root 2175: diffx = adjust ((((mousexpos + xoffs - spr0x) & ~1) * mstepx) >> 16);
2176: diffy = adjust ((((mouseypos + yoffs - spr0y) & ~1) * mstepy) >> 16);
1.1.1.4 root 2177: lastspr0x = spr0x; lastspr0y = spr0y;
2178: lastdiffx = diffx; lastdiffy = diffy;
2179: mouse_x += diffx; mouse_y += diffy;
1.1.1.3 root 2180: }
2181: break;
1.1.1.4 root 2182:
1.1.1.11 root 2183: default:
1.1.1.4 root 2184: abort ();
1.1.1.3 root 2185: }
2186: }
2187:
1.1.1.7 root 2188: static int timehack_alive = 0;
2189:
2190: static uae_u32 timehack_helper (void)
2191: {
2192: #ifdef HAVE_GETTIMEOFDAY
2193: struct timeval tv;
2194: if (m68k_dreg (regs, 0) == 0)
2195: return timehack_alive;
2196:
2197: timehack_alive = 10;
2198:
2199: gettimeofday (&tv, NULL);
2200: put_long (m68k_areg (regs, 0), tv.tv_sec - (((365 * 8 + 2) * 24 - 2) * 60 * 60));
2201: put_long (m68k_areg (regs, 0) + 4, tv.tv_usec);
2202: return 0;
2203: #else
2204: return 2;
2205: #endif
2206: }
2207:
1.1.1.3 root 2208: /*
1.1 root 2209: * register functions
2210: */
1.1.1.8 root 2211: STATIC_INLINE uae_u16 DENISEID (void)
1.1.1.7 root 2212: {
2213: if (currprefs.chipset_mask & CSMASK_AGA)
2214: return 0xF8;
2215: if (currprefs.chipset_mask & CSMASK_ECS_DENISE)
2216: return 0xFC;
2217: return 0xFFFF;
2218: }
1.1.1.8 root 2219: STATIC_INLINE uae_u16 DMACONR (void)
1.1 root 2220: {
2221: return (dmacon | (bltstate==BLT_done ? 0 : 0x4000)
2222: | (blt_info.blitzero ? 0x2000 : 0));
2223: }
1.1.1.8 root 2224: STATIC_INLINE uae_u16 INTENAR (void)
1.1.1.4 root 2225: {
2226: return intena;
2227: }
2228: uae_u16 INTREQR (void)
1.1 root 2229: {
1.1.1.9 root 2230: return intreq /* | (currprefs.use_serial ? 0x0001 : 0) */;
1.1 root 2231: }
1.1.1.8 root 2232: STATIC_INLINE uae_u16 ADKCONR (void)
1.1.1.4 root 2233: {
2234: return adkcon;
2235: }
1.1.1.8 root 2236: STATIC_INLINE uae_u16 VPOSR (void)
1.1 root 2237: {
1.1.1.14 root 2238: unsigned int csbit = currprefs.ntscmode ? 0x1000 : 0;
1.1.1.7 root 2239: csbit |= (currprefs.chipset_mask & CSMASK_AGA) ? 0x2300 : 0;
2240: csbit |= (currprefs.chipset_mask & CSMASK_ECS_AGNUS) ? 0x2000 : 0;
2241: return (vpos >> 8) | lof | csbit;
1.1 root 2242: }
1.1.1.4 root 2243: static void VPOSW (uae_u16 v)
1.1.1.2 root 2244: {
2245: if (lof != (v & 0x8000))
2246: lof_changed = 1;
2247: lof = v & 0x8000;
1.1.1.3 root 2248: /*
2249: * This register is much more fun on a real Amiga. You can program
2250: * refresh rates with it ;) But I won't emulate this...
2251: */
1.1.1.2 root 2252: }
1.1 root 2253:
1.1.1.8 root 2254: STATIC_INLINE uae_u16 VHPOSR (void)
1.1.1.4 root 2255: {
1.1.1.13 root 2256: return (vpos << 8) | current_hpos ();
1.1.1.4 root 2257: }
2258:
1.1.1.8 root 2259: STATIC_INLINE void COP1LCH (uae_u16 v) { cop1lc = (cop1lc & 0xffff) | ((uae_u32)v << 16); }
2260: STATIC_INLINE void COP1LCL (uae_u16 v) { cop1lc = (cop1lc & ~0xffff) | (v & 0xfffe); }
2261: STATIC_INLINE void COP2LCH (uae_u16 v) { cop2lc = (cop2lc & 0xffff) | ((uae_u32)v << 16); }
2262: STATIC_INLINE void COP2LCL (uae_u16 v) { cop2lc = (cop2lc & ~0xffff) | (v & 0xfffe); }
1.1.1.4 root 2263:
1.1.1.9 root 2264: static void start_copper (void)
1.1.1.4 root 2265: {
1.1.1.10 root 2266: int was_active = eventtab[ev_copper].active;
2267: eventtab[ev_copper].active = 0;
2268: if (was_active)
2269: events_schedule ();
2270:
1.1.1.4 root 2271: cop_state.ignore_next = 0;
2272: cop_state.state = COP_read1;
2273: cop_state.vpos = vpos;
2274: cop_state.hpos = current_hpos () & ~1;
1.1.1.9 root 2275:
1.1.1.10 root 2276: if (dmaen (DMA_COPPER)) {
2277: copper_enabled_thisline = 1;
1.1.1.13 root 2278: set_special (SPCFLAG_COPPER);
1.1.1.10 root 2279: }
1.1.1.9 root 2280: }
2281:
2282: static void COPJMP1 (uae_u16 a)
2283: {
2284: cop_state.ip = cop1lc;
2285: start_copper ();
1.1.1.4 root 2286: }
2287:
2288: static void COPJMP2 (uae_u16 a)
2289: {
2290: cop_state.ip = cop2lc;
1.1.1.9 root 2291: start_copper ();
1.1.1.4 root 2292: }
2293:
1.1.1.8 root 2294: STATIC_INLINE void COPCON (uae_u16 a)
1.1.1.4 root 2295: {
2296: copcon = a;
1.1 root 2297: }
1.1.1.4 root 2298:
1.1.1.13 root 2299: static void DMACON (int hpos, uae_u16 v)
1.1 root 2300: {
1.1.1.14 root 2301: int i;
1.1 root 2302:
1.1.1.3 root 2303: uae_u16 oldcon = dmacon;
2304:
1.1.1.13 root 2305: decide_line (hpos);
2306: decide_fetch (hpos);
2307:
2308: setclr (&dmacon, v);
2309: dmacon &= 0x1FFF;
1.1.1.3 root 2310:
2311: /* FIXME? Maybe we need to think a bit more about the master DMA enable
1.1 root 2312: * bit in these cases. */
1.1.1.10 root 2313: if ((dmacon & DMA_COPPER) != (oldcon & DMA_COPPER)) {
2314: eventtab[ev_copper].active = 0;
2315: }
1.1.1.3 root 2316: if ((dmacon & DMA_COPPER) > (oldcon & DMA_COPPER)) {
1.1.1.4 root 2317: cop_state.ip = cop1lc;
2318: cop_state.ignore_next = 0;
2319: cop_state.state = COP_read1;
2320: cop_state.vpos = vpos;
1.1.1.13 root 2321: cop_state.hpos = hpos & ~1;
1.1.1.10 root 2322: copper_enabled_thisline = 1;
1.1.1.13 root 2323: set_special (SPCFLAG_COPPER);
1.1 root 2324: }
1.1.1.9 root 2325: if (! (dmacon & DMA_COPPER)) {
1.1.1.10 root 2326: copper_enabled_thisline = 0;
1.1.1.13 root 2327: unset_special (SPCFLAG_COPPER);
1.1.1.9 root 2328: cop_state.state = COP_stop;
2329: }
2330:
1.1 root 2331: if ((dmacon & DMA_BLITPRI) > (oldcon & DMA_BLITPRI) && bltstate != BLT_done) {
2332: static int count = 0;
2333: if (!count) {
2334: count = 1;
1.1.1.3 root 2335: write_log ("warning: program is doing blitpri hacks.\n");
1.1 root 2336: }
1.1.1.13 root 2337: set_special (SPCFLAG_BLTNASTY);
1.1 root 2338: }
1.1.1.10 root 2339: if ((dmacon & (DMA_BLITPRI | DMA_BLITTER | DMA_MASTER)) != (DMA_BLITPRI | DMA_BLITTER | DMA_MASTER))
1.1.1.13 root 2340: unset_special (SPCFLAG_BLTNASTY);
1.1.1.4 root 2341:
1.1.1.14 root 2342: if (currprefs.produce_sound > 0) {
2343: update_audio ();
1.1.1.3 root 2344:
1.1.1.14 root 2345: for (i = 0; i < 4; i++) {
2346: struct audio_channel_data *cdp = audio_channel + i;
2347: int chan_ena = (dmacon & 0x200) && (dmacon & (1<<i));
2348: if (cdp->dmaen == chan_ena)
2349: continue;
2350: cdp->dmaen = chan_ena;
1.1.1.17 root 2351: if (cdp->dmaen)
2352: audio_channel_enable_dma (cdp);
2353: else
2354: audio_channel_disable_dma (cdp);
1.1 root 2355: }
1.1.1.14 root 2356: schedule_audio ();
1.1 root 2357: }
1.1.1.14 root 2358: events_schedule();
1.1 root 2359: }
1.1.1.2 root 2360:
1.1.1.3 root 2361: /*static int trace_intena = 0;*/
1.1.1.2 root 2362:
1.1.1.8 root 2363: STATIC_INLINE void INTENA (uae_u16 v)
1.1.1.2 root 2364: {
1.1.1.3 root 2365: /* if (trace_intena)
1.1.1.18 root 2366: write_log ("INTENA: %04x\n", v);*/
1.1.1.13 root 2367: setclr (&intena,v);
1.1.1.15 root 2368: /* There's stupid code out there that does
2369: [some INTREQ bits at level 3 are set]
2370: clear all INTREQ bits
2371: Enable one INTREQ level 3 bit
2372: Set level 3 handler
2373:
2374: If we set SPCFLAG_INT for the clear, then by the time the enable happens,
2375: we'll have SPCFLAG_DOINT set, and the interrupt happens immediately, but
2376: it needs to happen one insn later, when the new L3 handler has been
2377: installed. */
2378: if (v & 0x8000)
2379: set_special (SPCFLAG_INT);
2380: }
2381:
2382: void INTREQ_0 (uae_u16 v)
2383: {
2384: setclr (&intreq,v);
1.1.1.13 root 2385: set_special (SPCFLAG_INT);
1.1.1.2 root 2386: }
1.1.1.15 root 2387:
1.1.1.3 root 2388: void INTREQ (uae_u16 v)
1.1 root 2389: {
1.1.1.15 root 2390: INTREQ_0 (v);
1.1.1.13 root 2391: if ((v & 0x8800) == 0x0800)
1.1.1.4 root 2392: serdat &= 0xbfff;
1.1.1.15 root 2393: rethink_cias ();
1.1.1.3 root 2394: }
1.1 root 2395:
1.1.1.15 root 2396: static void update_adkmasks (void)
1.1.1.3 root 2397: {
2398: unsigned long t;
1.1.1.4 root 2399:
1.1.1.3 root 2400: t = adkcon | (adkcon >> 4);
2401: audio_channel[0].adk_mask = (((t >> 0) & 1) - 1);
2402: audio_channel[1].adk_mask = (((t >> 1) & 1) - 1);
2403: audio_channel[2].adk_mask = (((t >> 2) & 1) - 1);
2404: audio_channel[3].adk_mask = (((t >> 3) & 1) - 1);
2405: }
1.1 root 2406:
1.1.1.15 root 2407: static void ADKCON (uae_u16 v)
2408: {
2409: if (currprefs.produce_sound > 0)
2410: update_audio ();
2411:
2412: setclr (&adkcon,v);
2413: update_adkmasks ();
2414: }
2415:
1.1.1.7 root 2416: static void BEAMCON0 (uae_u16 v)
2417: {
1.1.1.18 root 2418: if (currprefs.chipset_mask & CSMASK_ECS_AGNUS)
2419: new_beamcon0 = v & 0x20;
1.1.1.7 root 2420: }
2421:
1.1.1.4 root 2422: static void BPLPTH (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) | ((uae_u32)v << 16);
1.1.1.3 root 2427: }
1.1.1.4 root 2428: static void BPLPTL (int hpos, uae_u16 v, int num)
1.1.1.3 root 2429: {
1.1.1.4 root 2430: decide_line (hpos);
1.1.1.13 root 2431: decide_fetch (hpos);
1.1.1.4 root 2432: bplpt[num] = (bplpt[num] & ~0xffff) | (v & 0xfffe);
1.1.1.3 root 2433: }
1.1 root 2434:
1.1.1.4 root 2435: static void BPLCON0 (int hpos, uae_u16 v)
1.1 root 2436: {
1.1.1.15 root 2437: if (! (currprefs.chipset_mask & CSMASK_ECS_DENISE))
2438: v &= ~0x00F1;
2439: else if (! (currprefs.chipset_mask & CSMASK_AGA))
2440: v &= ~0x00B1;
1.1.1.14 root 2441:
1.1.1.2 root 2442: if (bplcon0 == v)
1.1 root 2443: return;
1.1.1.4 root 2444: decide_line (hpos);
1.1.1.13 root 2445: decide_fetch (hpos);
2446:
1.1.1.18 root 2447: /* HAM change? */
2448: if ((bplcon0 ^ v) & 0x800) {
2449: record_color_change (hpos, -1, !! (v & 0x800));
2450: }
2451:
1.1.1.2 root 2452: bplcon0 = v;
1.1.1.16 root 2453: curr_diagram = cycle_diagram_table[fetchmode][GET_RES(bplcon0)][GET_PLANES (v)];
1.1.1.15 root 2454:
2455: if (currprefs.chipset_mask & CSMASK_AGA) {
2456: decide_sprites (hpos);
2457: expand_sprres ();
2458: }
2459:
1.1.1.14 root 2460: expand_fmodes ();
1.1 root 2461: }
1.1.1.9 root 2462:
1.1.1.8 root 2463: STATIC_INLINE void BPLCON1 (int hpos, uae_u16 v)
1.1 root 2464: {
1.1.1.2 root 2465: if (bplcon1 == v)
1.1 root 2466: return;
1.1.1.13 root 2467: decide_line (hpos);
2468: decide_fetch (hpos);
1.1.1.2 root 2469: bplcon1 = v;
1.1 root 2470: }
1.1.1.15 root 2471:
1.1.1.8 root 2472: STATIC_INLINE void BPLCON2 (int hpos, uae_u16 v)
1.1 root 2473: {
1.1.1.7 root 2474: if (bplcon2 == v)
2475: return;
2476: decide_line (hpos);
1.1.1.2 root 2477: bplcon2 = v;
1.1 root 2478: }
1.1.1.15 root 2479:
1.1.1.8 root 2480: STATIC_INLINE void BPLCON3 (int hpos, uae_u16 v)
1.1 root 2481: {
1.1.1.14 root 2482: if (! (currprefs.chipset_mask & CSMASK_AGA))
2483: return;
1.1.1.7 root 2484: if (bplcon3 == v)
2485: return;
2486: decide_line (hpos);
1.1.1.15 root 2487: decide_sprites (hpos);
1.1.1.3 root 2488: bplcon3 = v;
1.1.1.15 root 2489: expand_sprres ();
1.1 root 2490: }
1.1.1.15 root 2491:
1.1.1.8 root 2492: STATIC_INLINE void BPLCON4 (int hpos, uae_u16 v)
1.1 root 2493: {
1.1.1.7 root 2494: if (! (currprefs.chipset_mask & CSMASK_AGA))
2495: return;
2496: if (bplcon4 == v)
2497: return;
2498: decide_line (hpos);
1.1.1.3 root 2499: bplcon4 = v;
1.1 root 2500: }
2501:
1.1.1.4 root 2502: static void BPL1MOD (int hpos, uae_u16 v)
1.1 root 2503: {
2504: v &= ~1;
1.1.1.3 root 2505: if ((uae_s16)bpl1mod == (uae_s16)v)
1.1 root 2506: return;
1.1.1.13 root 2507: decide_line (hpos);
2508: decide_fetch (hpos);
1.1 root 2509: bpl1mod = v;
2510: }
1.1.1.2 root 2511:
1.1.1.4 root 2512: static void BPL2MOD (int hpos, uae_u16 v)
1.1.1.3 root 2513: {
1.1 root 2514: v &= ~1;
1.1.1.3 root 2515: if ((uae_s16)bpl2mod == (uae_s16)v)
1.1 root 2516: return;
1.1.1.13 root 2517: decide_line (hpos);
2518: decide_fetch (hpos);
1.1 root 2519: bpl2mod = v;
2520: }
2521:
1.1.1.13 root 2522: STATIC_INLINE void BPL1DAT (int hpos, uae_u16 v)
1.1.1.10 root 2523: {
1.1.1.13 root 2524: decide_line (hpos);
1.1.1.10 root 2525: bpl1dat = v;
1.1.1.13 root 2526:
2527: maybe_first_bpl1dat (hpos);
1.1.1.10 root 2528: }
1.1.1.2 root 2529: /* We could do as well without those... */
1.1.1.8 root 2530: STATIC_INLINE void BPL2DAT (uae_u16 v) { bpl2dat = v; }
2531: STATIC_INLINE void BPL3DAT (uae_u16 v) { bpl3dat = v; }
2532: STATIC_INLINE void BPL4DAT (uae_u16 v) { bpl4dat = v; }
2533: STATIC_INLINE void BPL5DAT (uae_u16 v) { bpl5dat = v; }
2534: STATIC_INLINE void BPL6DAT (uae_u16 v) { bpl6dat = v; }
2535: STATIC_INLINE void BPL7DAT (uae_u16 v) { bpl7dat = v; }
2536: STATIC_INLINE void BPL8DAT (uae_u16 v) { bpl8dat = v; }
1.1 root 2537:
1.1.1.4 root 2538: static void DIWSTRT (int hpos, uae_u16 v)
1.1 root 2539: {
1.1.1.4 root 2540: if (diwstrt == v && ! diwhigh_written)
1.1 root 2541: return;
1.1.1.4 root 2542: decide_line (hpos);
2543: diwhigh_written = 0;
1.1.1.3 root 2544: diwstrt = v;
1.1.1.4 root 2545: calcdiw ();
1.1 root 2546: }
1.1.1.4 root 2547:
2548: static void DIWSTOP (int hpos, uae_u16 v)
1.1 root 2549: {
1.1.1.4 root 2550: if (diwstop == v && ! diwhigh_written)
1.1 root 2551: return;
1.1.1.4 root 2552: decide_line (hpos);
2553: diwhigh_written = 0;
1.1.1.3 root 2554: diwstop = v;
1.1.1.4 root 2555: calcdiw ();
2556: }
2557:
2558: static void DIWHIGH (int hpos, uae_u16 v)
2559: {
1.1.1.7 root 2560: if (! (currprefs.chipset_mask & CSMASK_ECS_DENISE))
2561: return;
1.1.1.4 root 2562: if (diwhigh_written && diwhigh == v)
2563: return;
2564: decide_line (hpos);
2565: diwhigh_written = 1;
2566: diwhigh = v;
2567: calcdiw ();
1.1 root 2568: }
1.1.1.4 root 2569:
2570: static void DDFSTRT (int hpos, uae_u16 v)
1.1.1.3 root 2571: {
1.1.1.11 root 2572: v &= 0xFC;
1.1.1.2 root 2573: if (ddfstrt == v)
1.1 root 2574: return;
1.1.1.4 root 2575: decide_line (hpos);
1.1.1.3 root 2576: ddfstrt = v;
1.1.1.4 root 2577: calcdiw ();
1.1.1.15 root 2578: if (ddfstop > 0xD4 && (ddfstrt & 4) == 4) {
2579: static int last_warned;
2580: last_warned = (last_warned + 1) & 4095;
2581: if (last_warned == 0)
2582: write_log ("WARNING! Very strange DDF values.\n");
2583: }
1.1 root 2584: }
1.1.1.15 root 2585:
1.1.1.4 root 2586: static void DDFSTOP (int hpos, uae_u16 v)
1.1.1.3 root 2587: {
1.1.1.15 root 2588: /* ??? "Virtual Meltdown" sets this to 0xD2 and expects it to behave
2589: differently from 0xD0. RSI Megademo sets it to 0xd1 and expects it
1.1.1.16 root 2590: to behave like 0xd0. Some people also write the high 8 bits and
2591: expect them to be ignored. So mask it with 0xFE. */
2592: v &= 0xFE;
1.1.1.2 root 2593: if (ddfstop == v)
1.1 root 2594: return;
1.1.1.4 root 2595: decide_line (hpos);
1.1.1.13 root 2596: decide_fetch (hpos);
1.1.1.2 root 2597: ddfstop = v;
1.1.1.4 root 2598: calcdiw ();
1.1.1.13 root 2599: if (fetch_state != fetch_not_started)
2600: estimate_last_fetch_cycle (hpos);
1.1.1.15 root 2601: if (ddfstop > 0xD4 && (ddfstrt & 4) == 4) {
2602: static int last_warned;
2603: last_warned = (last_warned + 1) & 4095;
2604: if (last_warned == 0)
2605: write_log ("WARNING! Very strange DDF values.\n");
1.1.1.14 root 2606: write_log ("WARNING! Very strange DDF values.\n");
1.1.1.15 root 2607: }
1.1 root 2608: }
2609:
1.1.1.7 root 2610: static void FMODE (uae_u16 v)
2611: {
2612: if (! (currprefs.chipset_mask & CSMASK_AGA))
1.1.1.14 root 2613: v = 0;
1.1.1.13 root 2614:
1.1.1.7 root 2615: fmode = v;
1.1.1.14 root 2616: sprite_width = GET_SPRITEWIDTH (fmode);
2617: switch (fmode & 3) {
2618: case 0:
2619: fetchmode = 0;
2620: break;
2621: case 1:
2622: case 2:
2623: fetchmode = 1;
2624: break;
2625: case 3:
2626: fetchmode = 2;
2627: break;
2628: }
1.1.1.16 root 2629: curr_diagram = cycle_diagram_table[fetchmode][GET_RES (v)][GET_PLANES (bplcon0)];
1.1.1.14 root 2630: expand_fmodes ();
1.1.1.7 root 2631: }
2632:
1.1.1.4 root 2633: static void BLTADAT (uae_u16 v)
1.1 root 2634: {
1.1.1.19! root 2635: maybe_blit (0);
1.1.1.2 root 2636:
2637: blt_info.bltadat = v;
1.1 root 2638: }
1.1.1.2 root 2639: /*
2640: * "Loading data shifts it immediately" says the HRM. Well, that may
2641: * be true for BLTBDAT, but not for BLTADAT - it appears the A data must be
2642: * loaded for every word so that AFWM and ALWM can be applied.
2643: */
1.1.1.4 root 2644: static void BLTBDAT (uae_u16 v)
1.1 root 2645: {
1.1.1.19! root 2646: maybe_blit (0);
1.1.1.2 root 2647:
2648: if (bltcon1 & 2)
2649: blt_info.bltbhold = v << (bltcon1 >> 12);
2650: else
2651: blt_info.bltbhold = v >> (bltcon1 >> 12);
2652: blt_info.bltbdat = v;
1.1 root 2653: }
1.1.1.19! root 2654: static void BLTCDAT (uae_u16 v) { maybe_blit (0); blt_info.bltcdat = v; }
1.1 root 2655:
1.1.1.19! root 2656: static void BLTAMOD (uae_u16 v) { maybe_blit (1); blt_info.bltamod = (uae_s16)(v & 0xFFFE); }
! 2657: static void BLTBMOD (uae_u16 v) { maybe_blit (1); blt_info.bltbmod = (uae_s16)(v & 0xFFFE); }
! 2658: static void BLTCMOD (uae_u16 v) { maybe_blit (1); blt_info.bltcmod = (uae_s16)(v & 0xFFFE); }
! 2659: static void BLTDMOD (uae_u16 v) { maybe_blit (1); blt_info.bltdmod = (uae_s16)(v & 0xFFFE); }
1.1 root 2660:
1.1.1.19! root 2661: static void BLTCON0 (uae_u16 v) { maybe_blit (0); bltcon0 = v; blinea_shift = v >> 12; }
1.1.1.3 root 2662: /* The next category is "Most useless hardware register".
1.1 root 2663: * And the winner is... */
1.1.1.7 root 2664: static void BLTCON0L (uae_u16 v)
2665: {
2666: if (! (currprefs.chipset_mask & CSMASK_ECS_AGNUS))
2667: return;
1.1.1.19! root 2668: maybe_blit (0); bltcon0 = (bltcon0 & 0xFF00) | (v & 0xFF);
1.1.1.7 root 2669: }
1.1.1.19! root 2670: static void BLTCON1 (uae_u16 v) { maybe_blit (0); bltcon1 = v; }
1.1.1.4 root 2671:
1.1.1.19! root 2672: static void BLTAFWM (uae_u16 v) { maybe_blit (0); blt_info.bltafwm = v; }
! 2673: static void BLTALWM (uae_u16 v) { maybe_blit (0); blt_info.bltalwm = v; }
1.1 root 2674:
1.1.1.19! root 2675: static void BLTAPTH (uae_u16 v) { maybe_blit (0); bltapt = (bltapt & 0xffff) | ((uae_u32)v << 16); }
! 2676: static void BLTAPTL (uae_u16 v) { maybe_blit (0); bltapt = (bltapt & ~0xffff) | (v & 0xFFFE); }
! 2677: static void BLTBPTH (uae_u16 v) { maybe_blit (0); bltbpt = (bltbpt & 0xffff) | ((uae_u32)v << 16); }
! 2678: static void BLTBPTL (uae_u16 v) { maybe_blit (0); bltbpt = (bltbpt & ~0xffff) | (v & 0xFFFE); }
! 2679: static void BLTCPTH (uae_u16 v) { maybe_blit (0); bltcpt = (bltcpt & 0xffff) | ((uae_u32)v << 16); }
! 2680: static void BLTCPTL (uae_u16 v) { maybe_blit (0); bltcpt = (bltcpt & ~0xffff) | (v & 0xFFFE); }
! 2681: static void BLTDPTH (uae_u16 v) { maybe_blit (0); bltdpt = (bltdpt & 0xffff) | ((uae_u32)v << 16); }
! 2682: static void BLTDPTL (uae_u16 v) { maybe_blit (0); bltdpt = (bltdpt & ~0xffff) | (v & 0xFFFE); }
1.1 root 2683:
1.1.1.4 root 2684: static void BLTSIZE (uae_u16 v)
1.1 root 2685: {
1.1.1.19! root 2686: maybe_blit (0);
1.1 root 2687:
1.1.1.15 root 2688: blt_info.vblitsize = v >> 6;
2689: blt_info.hblitsize = v & 0x3F;
1.1 root 2690: if (!blt_info.vblitsize) blt_info.vblitsize = 1024;
2691: if (!blt_info.hblitsize) blt_info.hblitsize = 64;
1.1.1.3 root 2692:
2693: bltstate = BLT_init;
1.1.1.4 root 2694: do_blitter ();
1.1 root 2695: }
1.1.1.4 root 2696:
2697: static void BLTSIZV (uae_u16 v)
1.1 root 2698: {
1.1.1.7 root 2699: if (! (currprefs.chipset_mask & CSMASK_ECS_AGNUS))
2700: return;
1.1.1.19! root 2701: maybe_blit (0);
1.1 root 2702: oldvblts = v & 0x7FFF;
2703: }
1.1.1.4 root 2704:
2705: static void BLTSIZH (uae_u16 v)
1.1 root 2706: {
1.1.1.7 root 2707: if (! (currprefs.chipset_mask & CSMASK_ECS_AGNUS))
2708: return;
1.1.1.19! root 2709: maybe_blit (0);
1.1 root 2710: blt_info.hblitsize = v & 0x7FF;
2711: blt_info.vblitsize = oldvblts;
2712: if (!blt_info.vblitsize) blt_info.vblitsize = 32768;
2713: if (!blt_info.hblitsize) blt_info.hblitsize = 0x800;
1.1.1.2 root 2714: bltstate = BLT_init;
1.1.1.5 root 2715: do_blitter ();
1.1 root 2716: }
1.1.1.4 root 2717:
1.1.1.8 root 2718: STATIC_INLINE void SPRxCTL_1 (uae_u16 v, int num)
1.1 root 2719: {
1.1.1.2 root 2720: int sprxp;
2721: sprctl[num] = v;
1.1.1.10 root 2722: nr_armed -= spr[num].armed;
2723: spr[num].armed = 0;
1.1.1.3 root 2724: if (sprpos[num] == 0 && v == 0) {
1.1.1.10 root 2725: spr[num].state = SPR_stop;
2726: spr[num].on = 0;
1.1.1.15 root 2727: } else if (spr[num].state != SPR_waiting_stop) {
1.1.1.10 root 2728: spr[num].state = SPR_waiting_start;
1.1.1.15 root 2729: spr[num].on = 1;
2730: }
1.1.1.2 root 2731:
1.1.1.15 root 2732: sprxp = (sprpos[num] & 0xFF) * 2 + (v & 1);
2733:
2734: /* Quite a bit salad in this register... */
2735: if (currprefs.chipset_mask & CSMASK_AGA) {
2736: /* We ignore the SHRES 35ns increment for now; SHRES support doesn't
2737: work anyway, so we may as well restrict AGA sprites to a 70ns
2738: resolution. */
2739: sprxp <<= 1;
2740: sprxp |= (v >> 4) & 1;
2741: }
1.1.1.10 root 2742: spr[num].xpos = sprxp;
2743: spr[num].vstart = (sprpos[num] >> 8) | ((sprctl[num] << 6) & 0x100);
2744: spr[num].vstop = (sprctl[num] >> 8) | ((sprctl[num] << 7) & 0x100);
1.1.1.15 root 2745:
1.1.1.2 root 2746: }
1.1.1.8 root 2747: STATIC_INLINE void SPRxPOS_1 (uae_u16 v, int num)
1.1.1.2 root 2748: {
2749: int sprxp;
2750: sprpos[num] = v;
1.1.1.15 root 2751: sprxp = (v & 0xFF) * 2 + (sprctl[num] & 1);
2752:
2753: if (currprefs.chipset_mask & CSMASK_AGA) {
2754: sprxp <<= 1;
2755: sprxp |= (sprctl[num] >> 4) & 1;
2756: }
1.1.1.10 root 2757: spr[num].xpos = sprxp;
2758: spr[num].vstart = (sprpos[num] >> 8) | ((sprctl[num] << 6) & 0x100);
1.1.1.2 root 2759: }
1.1.1.8 root 2760: STATIC_INLINE void SPRxDATA_1 (uae_u16 v, int num)
1.1.1.2 root 2761: {
1.1.1.15 root 2762: sprdata[num][0] = v;
1.1.1.10 root 2763: nr_armed += 1 - spr[num].armed;
2764: spr[num].armed = 1;
1.1.1.2 root 2765: }
1.1.1.8 root 2766: STATIC_INLINE void SPRxDATB_1 (uae_u16 v, int num)
1.1.1.2 root 2767: {
1.1.1.15 root 2768: sprdatb[num][0] = v;
1.1.1.2 root 2769: }
1.1.1.4 root 2770: static void SPRxDATA (int hpos, uae_u16 v, int num) { decide_sprites (hpos); SPRxDATA_1 (v, num); }
2771: static void SPRxDATB (int hpos, uae_u16 v, int num) { decide_sprites (hpos); SPRxDATB_1 (v, num); }
2772: static void SPRxCTL (int hpos, uae_u16 v, int num) { decide_sprites (hpos); SPRxCTL_1 (v, num); }
2773: static void SPRxPOS (int hpos, uae_u16 v, int num) { decide_sprites (hpos); SPRxPOS_1 (v, num); }
2774: static void SPRxPTH (int hpos, uae_u16 v, int num)
1.1 root 2775: {
1.1.1.4 root 2776: decide_sprites (hpos);
1.1.1.10 root 2777: spr[num].pt &= 0xffff;
2778: spr[num].pt |= (uae_u32)v << 16;
1.1.1.3 root 2779:
1.1.1.10 root 2780: if (spr[num].state == SPR_stop || vpos < sprite_vblank_endline)
2781: spr[num].state = SPR_restart;
2782: spr[num].on = 1;
1.1 root 2783: }
1.1.1.4 root 2784: static void SPRxPTL (int hpos, uae_u16 v, int num)
1.1 root 2785: {
1.1.1.4 root 2786: decide_sprites (hpos);
1.1.1.10 root 2787: spr[num].pt &= ~0xffff;
2788: spr[num].pt |= v;
1.1 root 2789:
1.1.1.10 root 2790: if (spr[num].state == SPR_stop || vpos < sprite_vblank_endline)
2791: spr[num].state = SPR_restart;
2792: spr[num].on = 1;
1.1.1.3 root 2793: }
1.1.1.4 root 2794: static void CLXCON (uae_u16 v)
1.1.1.3 root 2795: {
2796: clxcon = v;
1.1.1.14 root 2797: clxcon_bpl_enable = (v >> 6) & 63;
2798: clxcon_bpl_match = v & 63;
2799: clx_sprmask = ((((v >> 15) & 1) << 7) | (((v >> 14) & 1) << 5) | (((v >> 13) & 1) << 3) | (((v >> 12) & 1) << 1) | 0x55);
2800: }
2801: static void CLXCON2 (uae_u16 v)
2802: {
2803: if (!(currprefs.chipset_mask & CSMASK_AGA))
2804: return;
2805: clxcon2 = v;
2806: clxcon_bpl_enable |= v & (0x40|0x80);
2807: clxcon_bpl_match |= (v & (0x01|0x02)) << 6;
2808: }
1.1.1.4 root 2809: static uae_u16 CLXDAT (void)
1.1.1.3 root 2810: {
2811: uae_u16 v = clxdat;
2812: clxdat = 0;
2813: return v;
2814: }
1.1.1.11 root 2815:
1.1.1.13 root 2816: static uae_u16 COLOR_READ (int num)
1.1 root 2817: {
1.1.1.13 root 2818: int cr, cg, cb, colreg;
2819: uae_u16 cval;
2820:
2821: if (!(currprefs.chipset_mask & CSMASK_AGA) || !(bplcon2 & 0x0100))
2822: return 0xffff;
2823:
2824: colreg = ((bplcon3 >> 13) & 7) * 32 + num;
2825: cr = current_colors.color_regs_aga[colreg] >> 16;
2826: cg = (current_colors.color_regs_aga[colreg] >> 8) & 0xFF;
2827: cb = current_colors.color_regs_aga[colreg] & 0xFF;
2828: if (bplcon3 & 0x200)
1.1.1.16 root 2829: cval = ((cr & 15) << 8) | ((cg & 15) << 4) | ((cb & 15) << 0);
1.1.1.13 root 2830: else
1.1.1.16 root 2831: cval = ((cr >> 4) << 8) | ((cg >> 4) << 4) | ((cb >> 4) << 0);
1.1.1.13 root 2832: return cval;
2833: }
1.1.1.3 root 2834:
1.1.1.13 root 2835: static void COLOR_WRITE (int hpos, uae_u16 v, int num)
2836: {
1.1 root 2837: v &= 0xFFF;
1.1.1.11 root 2838: if (currprefs.chipset_mask & CSMASK_AGA) {
1.1.1.4 root 2839: int r,g,b;
2840: int cr,cg,cb;
2841: int colreg;
1.1.1.3 root 2842: uae_u32 cval;
1.1.1.4 root 2843:
1.1.1.11 root 2844: /* writing is disabled when RDRAM=1 */
1.1.1.13 root 2845: if (bplcon2 & 0x0100)
2846: return;
1.1.1.11 root 2847:
1.1.1.2 root 2848: colreg = ((bplcon3 >> 13) & 7) * 32 + num;
1.1 root 2849: r = (v & 0xF00) >> 8;
2850: g = (v & 0xF0) >> 4;
2851: b = (v & 0xF) >> 0;
1.1.1.11 root 2852: cr = current_colors.color_regs_aga[colreg] >> 16;
2853: cg = (current_colors.color_regs_aga[colreg] >> 8) & 0xFF;
2854: cb = current_colors.color_regs_aga[colreg] & 0xFF;
1.1 root 2855:
1.1.1.2 root 2856: if (bplcon3 & 0x200) {
1.1 root 2857: cr &= 0xF0; cr |= r;
2858: cg &= 0xF0; cg |= g;
2859: cb &= 0xF0; cb |= b;
2860: } else {
2861: cr = r + (r << 4);
2862: cg = g + (g << 4);
2863: cb = b + (b << 4);
2864: }
2865: cval = (cr << 16) | (cg << 8) | cb;
1.1.1.11 root 2866: if (cval == current_colors.color_regs_aga[colreg])
1.1 root 2867: return;
1.1.1.5 root 2868:
2869: /* Call this with the old table still intact. */
1.1.1.11 root 2870: record_color_change (hpos, colreg, cval);
1.1.1.5 root 2871: remembered_color_entry = -1;
1.1.1.11 root 2872: current_colors.color_regs_aga[colreg] = cval;
2873: current_colors.acolors[colreg] = CONVERT_RGB (cval);
2874: } else {
2875: if (current_colors.color_regs_ecs[num] == v)
1.1 root 2876: return;
1.1.1.2 root 2877: /* Call this with the old table still intact. */
1.1.1.4 root 2878: record_color_change (hpos, num, v);
1.1.1.2 root 2879: remembered_color_entry = -1;
1.1.1.11 root 2880: current_colors.color_regs_ecs[num] = v;
1.1.1.2 root 2881: current_colors.acolors[num] = xcolors[v];
1.1 root 2882: }
2883: }
1.1.1.3 root 2884:
2885: static uae_u16 potgo_value;
2886:
1.1.1.4 root 2887: static void POTGO (uae_u16 v)
1.1 root 2888: {
1.1.1.3 root 2889: potgo_value = v;
2890: }
2891:
1.1.1.4 root 2892: static uae_u16 POTGOR (void)
1.1.1.3 root 2893: {
1.1.1.11 root 2894: uae_u16 v = (potgo_value | (potgo_value >> 1)) & 0x5500;
2895:
2896: v |= (~potgo_value & 0xAA00) >> 1;
1.1.1.3 root 2897:
1.1.1.6 root 2898: if (JSEM_ISMOUSE (0, &currprefs)) {
1.1.1.3 root 2899: if (buttonstate[2])
2900: v &= 0xFBFF;
2901:
2902: if (buttonstate[1])
2903: v &= 0xFEFF;
1.1.1.6 root 2904: } else if (JSEM_ISJOY0 (0, &currprefs) || JSEM_ISJOY1 (0, &currprefs)) {
1.1.1.3 root 2905: if (joy0button & 2) v &= 0xfbff;
2906: if (joy0button & 4) v &= 0xfeff;
2907: }
2908:
1.1.1.6 root 2909: if (JSEM_ISJOY0 (1, &currprefs) || JSEM_ISJOY1 (1, &currprefs)) {
1.1.1.3 root 2910: if (joy1button & 2) v &= 0xbfff;
2911: if (joy1button & 4) v &= 0xefff;
2912: }
1.1 root 2913:
2914: return v;
2915: }
1.1.1.4 root 2916:
2917: static uae_u16 POT0DAT (void)
1.1 root 2918: {
1.1.1.3 root 2919: static uae_u16 cnt = 0;
1.1.1.6 root 2920: if (JSEM_ISMOUSE (0, &currprefs)) {
1.1.1.3 root 2921: if (buttonstate[2])
2922: cnt = ((cnt + 1) & 0xFF) | (cnt & 0xFF00);
2923: if (buttonstate[1])
2924: cnt += 0x100;
2925: }
2926:
1.1 root 2927: return cnt;
2928: }
1.1.1.4 root 2929: static uae_u16 JOY0DAT (void)
1.1 root 2930: {
1.1.1.6 root 2931: if (JSEM_ISMOUSE (0, &currprefs)) {
1.1.1.4 root 2932: do_mouse_hack ();
1.1.1.3 root 2933: return ((uae_u8)mouse_x) + ((uae_u16)mouse_y << 8);
2934: }
1.1 root 2935: return joy0dir;
2936: }
1.1.1.4 root 2937: static uae_u16 JOY1DAT (void)
1.1 root 2938: {
1.1.1.6 root 2939: if (JSEM_ISMOUSE (1, &currprefs)) {
1.1.1.4 root 2940: do_mouse_hack ();
1.1.1.3 root 2941: return ((uae_u8)mouse_x) + ((uae_u16)mouse_y << 8);
2942: }
2943: return joy1dir;
1.1 root 2944: }
1.1.1.4 root 2945: static void JOYTEST (uae_u16 v)
1.1 root 2946: {
1.1.1.6 root 2947: if (JSEM_ISMOUSE (0, &currprefs)) {
1.1.1.3 root 2948: mouse_x = v & 0xFC;
2949: mouse_y = (v >> 8) & 0xFC;
1.1 root 2950: }
2951: }
2952:
1.1.1.15 root 2953: /* The copper code. The biggest nightmare in the whole emulator.
2954:
2955: Alright. The current theory:
2956: 1. Copper moves happen 4 cycles after state READ2 is reached.
2957: It can't happen immediately when we reach READ2, because the
2958: data needs time to get back from the bus. 4 cycles appears
2959: to be the time a chip memory access takes on the Amiga.
2960: 2. As stated in the HRM, a WAIT really does need an extra cycle
2961: to wake up. This is implemented by _not_ falling through from
2962: a successful wait to READ1, but by starting the next cycle.
2963: (Note: the extra cycle for the WAIT apparently really needs a
2964: free cycle; i.e. contention with the bitplane fetch can slow
2965: it down).
2966: 3. Apparently, to compensate for the extra wake up cycle, a WAIT
2967: will use the _incremented_ horizontal position, so the WAIT
2968: cycle normally finishes two clocks earlier than the position
2969: it was waiting for. The extra cycle then takes us to the
2970: position that was waited for.
2971: If the earlier cycle is busy with a bitplane, things change a bit.
2972: E.g., waiting for position 0x50 in a 6 plane display: In cycle
2973: 0x4e, we fetch BPL5, so the wait wakes up in 0x50, the extra cycle
2974: takes us to 0x54 (since 0x52 is busy), then we have READ1/READ2,
2975: and the next register write is at 0x5c.
2976: 4. The last cycle in a line is not usable for the copper.
2977: 5. A 4 cycle delay also applies to the WAIT instruction. This means
2978: that the second of two back-to-back WAITs (or a WAIT whose
2979: condition is immediately true) takes 8 cycles.
2980: 6. This also applies to a SKIP instruction. The copper does not
2981: fetch the next instruction while waiting for the second word of
2982: a WAIT or a SKIP to arrive.
2983: 7. A SKIP also seems to need an unexplained additional two cycles
2984: after its second word arrives; this is _not_ a memory cycle (I
2985: think, the documentation is pretty clear on this).
2986: 8. Two additional cycles are inserted when writing to COPJMP1/2. */
2987:
1.1.1.4 root 2988: /* Determine which cycles are available for the copper in a display
2989: * with a agiven number of planes. */
1.1.1.2 root 2990:
1.1.1.16 root 2991: STATIC_INLINE int copper_cant_read (int hpos)
1.1 root 2992: {
1.1.1.4 root 2993: int t;
1.1.1.2 root 2994:
1.1.1.15 root 2995: if (hpos + 1 >= maxhpos)
1.1.1.2 root 2996: return 1;
1.1.1.3 root 2997:
1.1.1.15 root 2998: if (fetch_state == fetch_not_started || hpos < thisline_decision.plfleft)
2999: return 0;
3000:
3001: if ((passed_plfstop == 3 && hpos >= thisline_decision.plfright)
3002: || hpos >= estimated_last_fetch_cycle)
1.1.1.4 root 3003: return 0;
1.1.1.3 root 3004:
1.1.1.16 root 3005: t = curr_diagram[(hpos + cycle_diagram_shift) & fetchstart_mask];
1.1.1.4 root 3006: #if 0
3007: if (t == -1)
3008: abort ();
3009: #endif
3010: return t;
1.1.1.2 root 3011: }
3012:
1.1.1.10 root 3013: STATIC_INLINE int dangerous_reg (int reg)
3014: {
3015: /* Safe:
3016: * Bitplane pointers, control registers, modulos and data.
3017: * Sprite pointers, control registers, and data.
3018: * Color registers. */
3019: if (reg >= 0xE0 && reg < 0x1C0)
3020: return 0;
3021: return 1;
3022: }
3023:
1.1.1.15 root 3024: #define FAST_COPPER 1
3025:
3026: /* The future, Conan?
3027: We try to look ahead in the copper list to avoid doing continuous calls
3028: to updat_copper (which is what happens when SPCFLAG_COPPER is set). If
3029: we find that the same effect can be achieved by setting a delayed event
3030: and then doing multiple copper insns in one batch, we can get a massive
3031: speedup.
3032:
3033: We don't try to be precise here. All copper reads take exactly 2 cycles,
3034: the effect of bitplane contention is ignored. Trying to get it exactly
3035: right would be much more complex and as such carry a huge risk of getting
3036: it subtly wrong; and it would also be more expensive - we want this code
3037: to be fast. */
3038: static void predict_copper (void)
3039: {
3040: uaecptr ip = cop_state.ip;
3041: unsigned int c_hpos = cop_state.hpos;
3042: enum copper_states state = cop_state.state;
3043: unsigned int w1, w2, cycle_count;
3044:
3045: switch (state) {
3046: case COP_read1_wr_in2:
3047: case COP_read2_wr_in2:
3048: case COP_read1_wr_in4:
3049: if (dangerous_reg (cop_state.saved_i1))
3050: return;
3051: state = state == COP_read2_wr_in2 ? COP_read2 : COP_read1;
3052: break;
3053:
3054: case COP_read1_in2:
3055: c_hpos += 2;
3056: state = COP_read1;
3057: break;
3058:
3059: case COP_stop:
3060: case COP_bltwait:
3061: case COP_wait1:
3062: case COP_skip_in4:
3063: case COP_skip_in2:
3064: return;
3065:
3066: case COP_wait_in4:
3067: c_hpos += 2;
3068: /* fallthrough */
3069: case COP_wait_in2:
3070: c_hpos += 2;
3071: /* fallthrough */
3072: case COP_wait:
3073: state = COP_wait;
3074: break;
3075:
3076: default:
3077: break;
3078: }
3079: /* Only needed for COP_wait, but let's shut up the compiler. */
3080: w1 = cop_state.saved_i1;
3081: w2 = cop_state.saved_i2;
3082: cop_state.first_sync = c_hpos;
3083: cop_state.regtypes_modified = REGTYPE_FORCE;
3084:
3085: /* Get this case out of the way, so that the loop below only has to deal
3086: with read1 and wait. */
3087: if (state == COP_read2) {
3088: w1 = cop_state.i1;
3089: if (w1 & 1) {
3090: w2 = chipmem_wget (ip);
3091: if (w2 & 1)
3092: goto done;
3093: state = COP_wait;
3094: c_hpos += 4;
3095: } else if (dangerous_reg (w1)) {
3096: c_hpos += 4;
3097: goto done;
3098: } else {
3099: cop_state.regtypes_modified |= regtypes[w1 & 0x1FE];
3100: state = COP_read1;
3101: c_hpos += 2;
3102: }
3103: ip += 2;
3104: }
3105:
3106: while (c_hpos + 1 < maxhpos) {
3107: if (state == COP_read1) {
3108: w1 = chipmem_wget (ip);
3109: if (w1 & 1) {
3110: w2 = chipmem_wget (ip + 2);
3111: if (w2 & 1)
3112: break;
3113: state = COP_wait;
3114: c_hpos += 6;
3115: } else if (dangerous_reg (w1)) {
3116: c_hpos += 6;
3117: goto done;
3118: } else {
3119: cop_state.regtypes_modified |= regtypes[w1 & 0x1FE];
3120: c_hpos += 4;
3121: }
3122: ip += 4;
3123: } else if (state == COP_wait) {
3124: if ((w2 & 0xFE) != 0xFE)
3125: break;
3126: else {
3127: unsigned int vcmp = (w1 & (w2 | 0x8000)) >> 8;
3128: unsigned int hcmp = (w1 & 0xFE);
3129:
3130: unsigned int vp = vpos & (((w2 >> 8) & 0x7F) | 0x80);
3131: if (vp < vcmp) {
3132: /* Whee. We can wait until the end of the line! */
3133: c_hpos = maxhpos;
3134: } else if (vp > vcmp || hcmp <= c_hpos) {
3135: state = COP_read1;
3136: /* minimum wakeup time */
3137: c_hpos += 2;
3138: } else {
3139: state = COP_read1;
3140: c_hpos = hcmp;
3141: }
3142: /* If this is the current instruction, remember that we don't
3143: need to sync CPU and copper anytime soon. */
3144: if (cop_state.ip == ip) {
3145: cop_state.first_sync = c_hpos;
3146: }
3147: }
3148: } else
3149: abort ();
3150: }
3151:
3152: done:
3153: cycle_count = c_hpos - cop_state.hpos;
3154: if (cycle_count >= 8) {
3155: unset_special (SPCFLAG_COPPER);
3156: eventtab[ev_copper].active = 1;
3157: eventtab[ev_copper].oldcycles = get_cycles ();
3158: eventtab[ev_copper].evtime = get_cycles () + cycle_count * CYCLE_UNIT;
3159: events_schedule ();
3160: }
3161: }
3162:
3163: static void perform_copper_write (int old_hpos)
3164: {
3165: int vp = vpos & (((cop_state.saved_i2 >> 8) & 0x7F) | 0x80);
3166: int hp;
3167: unsigned int address = cop_state.saved_i1 & 0x1FE;
3168:
3169: record_copper (cop_state.saved_ip - 4, old_hpos, vpos);
3170:
3171: if (address < (copcon & 2 ? ((currprefs.chipset_mask & CSMASK_AGA) ? 0 : 0x40u) : 0x80u)) {
3172: cop_state.state = COP_stop;
3173: copper_enabled_thisline = 0;
3174: unset_special (SPCFLAG_COPPER);
3175: return;
3176: }
3177:
3178: if (address == 0x88) {
3179: cop_state.ip = cop1lc;
3180: cop_state.state = COP_read1_in2;
3181: } else if (address == 0x8A) {
3182: cop_state.ip = cop2lc;
3183: cop_state.state = COP_read1_in2;
3184: } else
3185: custom_wput_1 (old_hpos, address, cop_state.saved_i2);
3186: }
1.1.1.13 root 3187:
1.1.1.9 root 3188: static void update_copper (int until_hpos)
1.1.1.2 root 3189: {
1.1.1.15 root 3190: int vp = vpos & (((cop_state.saved_i2 >> 8) & 0x7F) | 0x80);
1.1.1.4 root 3191: int c_hpos = cop_state.hpos;
1.1.1.2 root 3192:
1.1.1.10 root 3193: if (eventtab[ev_copper].active)
3194: abort ();
3195:
3196: if (cop_state.state == COP_wait && vp < cop_state.vcmp)
3197: abort ();
3198:
3199: until_hpos &= ~1;
3200:
3201: if (until_hpos > (maxhpos & ~1))
3202: until_hpos = maxhpos & ~1;
1.1.1.3 root 3203:
1.1.1.13 root 3204: until_hpos += 2;
1.1.1.4 root 3205: for (;;) {
1.1.1.10 root 3206: int old_hpos = c_hpos;
3207: int hp;
3208:
1.1.1.13 root 3209: if (c_hpos >= until_hpos)
1.1.1.3 root 3210: break;
3211:
1.1.1.13 root 3212: /* So we know about the fetch state. */
1.1.1.9 root 3213: decide_line (c_hpos);
1.1.1.3 root 3214:
1.1.1.15 root 3215: switch (cop_state.state) {
3216: case COP_read1_in2:
3217: cop_state.state = COP_read1;
3218: break;
3219: case COP_read1_wr_in2:
3220: cop_state.state = COP_read1;
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_read1_wr_in4:
3228: cop_state.state = COP_read1_wr_in2;
3229: break;
3230: case COP_read2_wr_in2:
3231: cop_state.state = COP_read2;
3232: perform_copper_write (old_hpos);
3233: /* That could have turned off the copper. */
3234: if (! copper_enabled_thisline)
3235: goto out;
3236:
3237: break;
3238: case COP_wait_in2:
3239: cop_state.state = COP_wait1;
3240: break;
3241: case COP_wait_in4:
3242: cop_state.state = COP_wait_in2;
3243: break;
3244: case COP_skip_in2:
3245: {
3246: static int skipped_before;
3247: unsigned int vcmp, hcmp, vp1, hp1;
3248: cop_state.state = COP_read1_in2;
3249:
3250: vcmp = (cop_state.saved_i1 & (cop_state.saved_i2 | 0x8000)) >> 8;
3251: hcmp = (cop_state.saved_i1 & cop_state.saved_i2 & 0xFE);
3252:
3253: if (! skipped_before) {
3254: skipped_before = 1;
3255: write_log ("Program uses Copper SKIP instruction.\n");
3256: }
3257:
3258: vp1 = vpos & (((cop_state.saved_i2 >> 8) & 0x7F) | 0x80);
3259: hp1 = old_hpos & (cop_state.saved_i2 & 0xFE);
3260:
3261: if ((vp1 > vcmp || (vp1 == vcmp && hp1 >= hcmp))
3262: && ((cop_state.saved_i2 & 0x8000) != 0 || ! (DMACONR() & 0x4000)))
3263: cop_state.ignore_next = 1;
3264: break;
3265: }
3266: case COP_skip_in4:
3267: cop_state.state = COP_skip_in2;
3268: break;
3269: default:
3270: break;
3271: }
3272:
1.1.1.10 root 3273: c_hpos += 2;
1.1.1.16 root 3274: if (copper_cant_read (old_hpos))
1.1.1.10 root 3275: continue;
1.1.1.3 root 3276:
1.1.1.10 root 3277: switch (cop_state.state) {
1.1.1.15 root 3278: case COP_read1_wr_in4:
3279: abort ();
3280:
3281: case COP_read1_wr_in2:
1.1.1.9 root 3282: case COP_read1:
1.1.1.15 root 3283: cop_state.i1 = chipmem_wget (cop_state.ip);
1.1.1.9 root 3284: cop_state.ip += 2;
1.1.1.15 root 3285: cop_state.state = cop_state.state == COP_read1 ? COP_read2 : COP_read2_wr_in2;
1.1.1.9 root 3286: break;
3287:
1.1.1.15 root 3288: case COP_read2_wr_in2:
3289: abort ();
3290:
1.1.1.9 root 3291: case COP_read2:
1.1.1.15 root 3292: cop_state.i2 = chipmem_wget (cop_state.ip);
1.1.1.9 root 3293: cop_state.ip += 2;
3294: if (cop_state.ignore_next) {
3295: cop_state.ignore_next = 0;
1.1.1.15 root 3296: cop_state.state = COP_read1;
1.1.1.9 root 3297: break;
1.1.1.3 root 3298: }
1.1.1.2 root 3299:
1.1.1.15 root 3300: cop_state.saved_i1 = cop_state.i1;
3301: cop_state.saved_i2 = cop_state.i2;
3302: cop_state.saved_ip = cop_state.ip;
3303:
3304: if (cop_state.i1 & 1) {
3305: if (cop_state.i2 & 1)
3306: cop_state.state = COP_skip_in4;
3307: else
3308: cop_state.state = COP_wait_in4;
3309: } else
3310: cop_state.state = COP_read1_wr_in4;
3311: break;
3312:
3313: case COP_wait1:
1.1.1.9 root 3314: cop_state.state = COP_wait;
1.1.1.13 root 3315:
1.1.1.15 root 3316: cop_state.vcmp = (cop_state.saved_i1 & (cop_state.saved_i2 | 0x8000)) >> 8;
3317: cop_state.hcmp = (cop_state.saved_i1 & cop_state.saved_i2 & 0xFE);
3318:
3319: vp = vpos & (((cop_state.saved_i2 >> 8) & 0x7F) | 0x80);
1.1.1.13 root 3320:
1.1.1.15 root 3321: if (cop_state.saved_i1 == 0xFFFF && cop_state.saved_i2 == 0xFFFE) {
1.1.1.9 root 3322: cop_state.state = COP_stop;
1.1.1.10 root 3323: copper_enabled_thisline = 0;
1.1.1.13 root 3324: unset_special (SPCFLAG_COPPER);
1.1.1.10 root 3325: goto out;
1.1.1.2 root 3326: }
1.1.1.9 root 3327: if (vp < cop_state.vcmp) {
1.1.1.10 root 3328: copper_enabled_thisline = 0;
1.1.1.13 root 3329: unset_special (SPCFLAG_COPPER);
1.1.1.10 root 3330: goto out;
1.1.1.2 root 3331: }
1.1.1.10 root 3332:
1.1.1.15 root 3333: /* fall through */
3334: do_wait:
1.1.1.10 root 3335: case COP_wait:
3336: if (vp < cop_state.vcmp)
3337: abort ();
3338:
1.1.1.15 root 3339: hp = c_hpos & (cop_state.saved_i2 & 0xFE);
3340: if (vp == cop_state.vcmp && hp < cop_state.hcmp) {
3341: /* Position not reached yet. */
3342: if (currprefs.fast_copper && (cop_state.saved_i2 & 0xFE) == 0xFE) {
3343: int wait_finish = cop_state.hcmp - 2;
3344: /* This will leave c_hpos untouched if it's equal to wait_finish. */
3345: if (wait_finish < c_hpos)
3346: abort ();
3347: else if (wait_finish <= until_hpos) {
3348: c_hpos = wait_finish;
3349: } else
3350: c_hpos = until_hpos;
3351: }
1.1.1.4 root 3352: break;
1.1.1.15 root 3353: }
1.1.1.10 root 3354:
3355: /* Now we know that the comparisons were successful. We might still
3356: have to wait for the blitter though. */
1.1.1.15 root 3357: if ((cop_state.saved_i2 & 0x8000) == 0 && (DMACONR() & 0x4000)) {
1.1.1.9 root 3358: /* We need to wait for the blitter. */
1.1.1.4 root 3359: cop_state.state = COP_bltwait;
1.1.1.10 root 3360: copper_enabled_thisline = 0;
1.1.1.13 root 3361: unset_special (SPCFLAG_COPPER);
1.1.1.10 root 3362: goto out;
1.1.1.2 root 3363: }
1.1.1.10 root 3364:
1.1.1.15 root 3365: record_copper (cop_state.ip - 4, old_hpos, vpos);
1.1.1.13 root 3366:
1.1.1.10 root 3367: cop_state.state = COP_read1;
1.1.1.4 root 3368: break;
1.1.1.2 root 3369:
1.1.1.13 root 3370: default:
1.1.1.15 root 3371: break;
1.1 root 3372: }
1.1.1.4 root 3373: }
1.1.1.10 root 3374:
3375: out:
1.1.1.4 root 3376: cop_state.hpos = c_hpos;
1.1.1.10 root 3377:
1.1.1.15 root 3378: /* The test against maxhpos also prevents us from calling predict_copper
3379: when we are being called from hsync_handler, which would not only be
3380: stupid, but actively harmful. */
3381: if (currprefs.fast_copper && (regs.spcflags & SPCFLAG_COPPER) && c_hpos + 8 < maxhpos)
3382: predict_copper ();
1.1 root 3383: }
3384:
1.1.1.9 root 3385: static void compute_spcflag_copper (void)
1.1 root 3386: {
1.1.1.10 root 3387: copper_enabled_thisline = 0;
1.1.1.13 root 3388: unset_special (SPCFLAG_COPPER);
1.1.1.10 root 3389: if (! dmaen (DMA_COPPER) || cop_state.state == COP_stop || cop_state.state == COP_bltwait)
3390: return;
3391:
3392: if (cop_state.state == COP_wait) {
1.1.1.15 root 3393: int vp = vpos & (((cop_state.saved_i2 >> 8) & 0x7F) | 0x80);
1.1.1.10 root 3394:
3395: if (vp < cop_state.vcmp)
3396: return;
3397: }
3398: copper_enabled_thisline = 1;
1.1.1.15 root 3399:
3400: if (currprefs.fast_copper)
3401: predict_copper ();
3402:
3403: if (! eventtab[ev_copper].active)
3404: set_special (SPCFLAG_COPPER);
1.1.1.10 root 3405: }
3406:
3407: static void copper_handler (void)
3408: {
3409: /* This will take effect immediately, within the same cycle. */
1.1.1.13 root 3410: set_special (SPCFLAG_COPPER);
1.1.1.10 root 3411:
3412: if (! copper_enabled_thisline)
3413: abort ();
3414:
3415: eventtab[ev_copper].active = 0;
1.1.1.3 root 3416: }
1.1.1.2 root 3417:
1.1.1.4 root 3418: void blitter_done_notify (void)
1.1 root 3419: {
1.1.1.4 root 3420: if (cop_state.state != COP_bltwait)
3421: return;
1.1.1.10 root 3422:
3423: copper_enabled_thisline = 1;
1.1.1.13 root 3424: set_special (SPCFLAG_COPPER);
1.1.1.9 root 3425: cop_state.state = COP_wait;
1.1.1.2 root 3426: }
3427:
1.1.1.9 root 3428: void do_copper (void)
1.1.1.2 root 3429: {
1.1.1.4 root 3430: int hpos = current_hpos ();
3431: update_copper (hpos);
1.1.1.2 root 3432: }
3433:
1.1.1.15 root 3434: /* ADDR is the address that is going to be read/written; this access is
3435: the reason why we want to update the copper. This function is also
3436: used from hsync_handler to finish up the line; for this case, we check
3437: hpos against maxhpos. */
3438: STATIC_INLINE void sync_copper_with_cpu (int hpos, int do_schedule, unsigned int addr)
1.1.1.13 root 3439: {
1.1.1.15 root 3440: /* Need to let the copper advance to the current position. */
1.1.1.13 root 3441: if (eventtab[ev_copper].active) {
1.1.1.15 root 3442: if (hpos != maxhpos) {
3443: /* There might be reasons why we don't actually need to bother
3444: updating the copper. */
3445: if (hpos < cop_state.first_sync)
3446: return;
3447:
3448: if ((cop_state.regtypes_modified & regtypes[addr & 0x1FE]) == 0)
3449: return;
1.1.1.13 root 3450: }
1.1.1.15 root 3451:
3452: eventtab[ev_copper].active = 0;
3453: if (do_schedule)
3454: events_schedule ();
3455: set_special (SPCFLAG_COPPER);
1.1.1.13 root 3456: }
1.1.1.15 root 3457: if (copper_enabled_thisline)
1.1.1.13 root 3458: update_copper (hpos);
3459: }
3460:
3461: static void do_sprites (int currvp, int hpos)
1.1.1.4 root 3462: {
3463: int i;
1.1.1.13 root 3464: int maxspr, minspr;
1.1.1.15 root 3465: int sw = sprite_width >> 3;
1.1.1.2 root 3466:
1.1.1.4 root 3467: /* I don't know whether this is right. Some programs write the sprite pointers
1.1.1.13 root 3468: * directly at the start of the copper list. With the test against currvp, the
1.1.1.4 root 3469: * first two words of data are read on the second line in the frame. The problem
3470: * occurs when the program jumps to another copperlist a few lines further down
3471: * which _also_ writes the sprite pointer registers. This means that a) writing
3472: * to the sprite pointers sets the state to SPR_restart; or b) that sprite DMA
3473: * is disabled until the end of the vertical blanking interval. The HRM
3474: * isn't clear - it says that the vertical sprite position can be set to any
3475: * value, but this wouldn't be the first mistake... */
3476: /* Update: I modified one of the programs to write the sprite pointers the
3477: * second time only _after_ the VBlank interval, and it showed the same behaviour
3478: * as it did unmodified under UAE with the above check. This indicates that the
3479: * solution below is correct. */
1.1.1.9 root 3480: /* Another update: seems like we have to use the NTSC value here (see Sanity Turmoil
3481: * demo). */
1.1.1.10 root 3482: /* Maximum for Sanity Turmoil: 27.
3483: Minimum for Sanity Arte: 22. */
3484: if (currvp < sprite_vblank_endline)
1.1.1.4 root 3485: return;
1.1.1.3 root 3486:
1.1.1.4 root 3487: /* The graph in the HRM, p. 195 seems to indicate that sprite 0 is
3488: * fetched at cycle 0x14 and thus can't be disabled by bitplane DMA. */
1.1.1.13 root 3489: maxspr = hpos / 4 - 0x14 / 4;
3490: minspr = last_sprite_hpos / 4 - 0x14 / 4;
3491:
1.1.1.15 root 3492: if (minspr > MAX_SPRITES || maxspr < 0)
1.1.1.4 root 3493: return;
1.1.1.13 root 3494:
1.1.1.15 root 3495: if (maxspr > MAX_SPRITES)
3496: maxspr = MAX_SPRITES;
1.1.1.13 root 3497: if (minspr < 0)
3498: minspr = 0;
1.1.1.2 root 3499:
1.1.1.13 root 3500: for (i = minspr; i < maxspr; i++) {
1.1.1.4 root 3501: int fetch = 0;
1.1.1.2 root 3502:
1.1.1.10 root 3503: if (spr[i].on == 0)
1.1.1.4 root 3504: continue;
1.1.1.2 root 3505:
1.1.1.10 root 3506: if (spr[i].state == SPR_restart) {
1.1.1.4 root 3507: fetch = 2;
1.1.1.10 root 3508: spr[i].on = 1;
3509: } else if ((spr[i].state == SPR_waiting_start && spr[i].vstart == vpos) || spr[i].state == SPR_waiting_stop) {
1.1.1.4 root 3510: fetch = 1;
1.1.1.10 root 3511: spr[i].state = SPR_waiting_stop;
1.1.1.2 root 3512: }
1.1.1.10 root 3513: if ((spr[i].state == SPR_waiting_stop || spr[i].state == SPR_waiting_start) && spr[i].vstop == vpos) {
1.1.1.4 root 3514: fetch = 2;
1.1.1.10 root 3515: spr[i].state = SPR_waiting_start;
1.1.1.2 root 3516: }
1.1.1.3 root 3517:
1.1.1.9 root 3518: if (fetch && dmaen (DMA_SPRITE)) {
1.1.1.15 root 3519: uae_u16 data1 = chipmem_wget (spr[i].pt);
3520: uae_u16 data2 = chipmem_wget (spr[i].pt + sw);
1.1.1.3 root 3521:
1.1.1.4 root 3522: if (fetch == 1) {
3523: /* Hack for X mouse auto-calibration */
3524: if (i == 0 && !sprvbfl && ((sprpos[0] & 0xff) << 2) > 2 * DISPLAY_LEFT_SHIFT) {
1.1.1.9 root 3525: spr0ctl = sprctl[0];
3526: spr0pos = sprpos[0];
3527: sprvbfl = 2;
1.1.1.3 root 3528: }
1.1.1.9 root 3529: SPRxDATB_1 (data2, i);
3530: SPRxDATA_1 (data1, i);
1.1.1.15 root 3531: switch (sw)
3532: {
3533: case 64 >> 3:
3534: sprdata[i][3] = chipmem_wget (spr[i].pt + 6);
3535: sprdatb[i][3] = chipmem_wget (spr[i].pt + 6 + sw);
3536: sprdata[i][2] = chipmem_wget (spr[i].pt + 4);
3537: sprdatb[i][2] = chipmem_wget (spr[i].pt + 4 + sw);
3538: /* fall through */
3539: case 32 >> 3:
3540: sprdata[i][1] = chipmem_wget (spr[i].pt + 2);
3541: sprdatb[i][1] = chipmem_wget (spr[i].pt + 2 + sw);
3542: break;
3543: }
1.1.1.4 root 3544: } else {
1.1.1.9 root 3545: SPRxPOS_1 (data1, i);
3546: SPRxCTL_1 (data2, i);
1.1.1.3 root 3547: }
1.1.1.15 root 3548: spr[i].pt += sw * 2;
1.1 root 3549: }
3550: }
1.1.1.13 root 3551: last_sprite_hpos = hpos;
1.1 root 3552: }
3553:
1.1.1.4 root 3554: static void init_sprites (void)
1.1 root 3555: {
1.1.1.4 root 3556: int i;
1.1.1.2 root 3557:
1.1.1.15 root 3558: for (i = 0; i < MAX_SPRITES; i++) {
1.1.1.4 root 3559: /* ???? */
1.1.1.10 root 3560: spr[i].state = SPR_stop;
3561: spr[i].on = 0;
1.1.1.4 root 3562: }
1.1.1.2 root 3563:
1.1.1.4 root 3564: memset (sprpos, 0, sizeof sprpos);
3565: memset (sprctl, 0, sizeof sprctl);
3566: }
1.1.1.2 root 3567:
1.1.1.3 root 3568: static void adjust_array_sizes (void)
1.1.1.2 root 3569: {
3570: #ifdef OS_WITHOUT_MEMORY_MANAGEMENT
1.1.1.13 root 3571: if (delta_sprite_entry) {
1.1.1.3 root 3572: void *p1,*p2;
1.1.1.13 root 3573: int mcc = max_sprite_entry + 50 + delta_sprite_entry;
3574: delta_sprite_entry = 0;
3575: p1 = realloc (sprite_entries[0], mcc * sizeof (struct sprite_entry));
3576: p2 = realloc (sprite_entries[1], mcc * sizeof (struct sprite_entry));
3577: if (p1) sprite_entries[0] = p1;
3578: if (p2) sprite_entries[1] = p2;
1.1.1.3 root 3579: if (p1 && p2) {
1.1.1.18 root 3580: write_log ("new max_sprite_entry=%d\n",mcc);
1.1.1.13 root 3581: max_sprite_entry = mcc;
1.1.1.2 root 3582: }
3583: }
1.1.1.3 root 3584: if (delta_color_change) {
3585: void *p1,*p2;
3586: int mcc = max_color_change + 200 + delta_color_change;
3587: delta_color_change = 0;
3588: p1 = realloc (color_changes[0], mcc * sizeof (struct color_change));
3589: p2 = realloc (color_changes[1], mcc * sizeof (struct color_change));
3590: if (p1) color_changes[0] = p1;
3591: if (p2) color_changes[1] = p2;
3592: if (p1 && p2) {
1.1.1.18 root 3593: write_log ("new max_color_change=%d\n",mcc);
1.1.1.2 root 3594: max_color_change = mcc;
1.1.1.3 root 3595: }
3596: }
1.1.1.2 root 3597: #endif
1.1.1.3 root 3598: }
3599:
1.1.1.4 root 3600: static void init_hardware_frame (void)
1.1.1.3 root 3601: {
1.1.1.4 root 3602: next_lineno = 0;
3603: nextline_how = nln_normal;
3604: diwstate = DIW_waiting_start;
3605: hdiwstate = DIW_waiting_start;
3606: }
1.1.1.2 root 3607:
1.1.1.4 root 3608: void init_hardware_for_drawing_frame (void)
3609: {
1.1.1.3 root 3610: adjust_array_sizes ();
3611:
1.1.1.13 root 3612: /* Avoid this code in the first frame after a customreset. */
3613: if (prev_sprite_entries) {
3614: int first_pixel = prev_sprite_entries[0].first_pixel;
3615: int npixels = prev_sprite_entries[prev_next_sprite_entry].first_pixel - first_pixel;
3616: memset (spixels + first_pixel, 0, npixels * sizeof *spixels);
3617: memset (spixstate.bytes + first_pixel, 0, npixels * sizeof *spixstate.bytes);
3618: }
3619: prev_next_sprite_entry = next_sprite_entry;
1.1.1.3 root 3620:
1.1.1.13 root 3621: next_color_change = 0;
3622: next_sprite_entry = 0;
1.1.1.2 root 3623: next_color_entry = 0;
3624: remembered_color_entry = -1;
1.1.1.13 root 3625:
3626: prev_sprite_entries = sprite_entries[current_change_set];
3627: curr_sprite_entries = sprite_entries[current_change_set ^ 1];
1.1.1.2 root 3628: prev_color_changes = color_changes[current_change_set];
3629: curr_color_changes = color_changes[current_change_set ^ 1];
3630: prev_color_tables = color_tables[current_change_set];
3631: curr_color_tables = color_tables[current_change_set ^ 1];
1.1.1.3 root 3632:
1.1.1.2 root 3633: prev_drawinfo = line_drawinfo[current_change_set];
1.1.1.4 root 3634: curr_drawinfo = line_drawinfo[current_change_set ^ 1];
3635: current_change_set ^= 1;
1.1.1.3 root 3636:
1.1.1.4 root 3637: color_src_match = color_dest_match = -1;
1.1.1.13 root 3638:
3639: /* Use both halves of the array in alternating fashion. */
3640: curr_sprite_entries[0].first_pixel = current_change_set * MAX_SPR_PIXELS;
3641: next_sprite_forced = 1;
1.1.1.3 root 3642: }
3643:
1.1.1.15 root 3644: static void do_savestate(void);
3645:
1.1.1.2 root 3646: static void vsync_handler (void)
1.1 root 3647: {
1.1.1.15 root 3648: #if 0
3649: static int old_clxdat;
3650: if (clxdat != old_clxdat) {
3651: printf ("CLXDAT %04x\n", clxdat);
3652: old_clxdat = clxdat;
3653: }
3654: #endif
1.1.1.12 root 3655: n_frames++;
3656:
1.1.1.4 root 3657: if (currprefs.m68k_speed == -1) {
3658: frame_time_t curr_time = read_processor_time ();
1.1.1.3 root 3659: vsyncmintime += vsynctime;
3660: /* @@@ Mathias? How do you think we should do this? */
3661: /* If we are too far behind, or we just did a reset, adjust the
3662: * needed time. */
1.1.1.4 root 3663: if ((long int)(curr_time - vsyncmintime) > 0 || rpt_did_reset)
1.1.1.3 root 3664: vsyncmintime = curr_time + vsynctime;
1.1.1.4 root 3665: rpt_did_reset = 0;
1.1.1.3 root 3666: }
1.1.1.4 root 3667:
1.1.1.3 root 3668: handle_events ();
1.1 root 3669:
1.1.1.3 root 3670: getjoystate (0, &joy0dir, &joy0button);
3671: getjoystate (1, &joy1dir, &joy1button);
1.1 root 3672:
1.1.1.4 root 3673: INTREQ (0x8020);
1.1.1.3 root 3674: if (bplcon0 & 4)
1.1.1.2 root 3675: lof ^= 0x8000;
1.1.1.3 root 3676:
1.1.1.18 root 3677: #ifdef PICASSO96
1.1.1.16 root 3678: if (picasso_on)
3679: picasso_handle_vsync ();
1.1.1.18 root 3680: #endif
1.1.1.4 root 3681: vsync_handle_redraw (lof, lof_changed);
1.1.1.16 root 3682:
1.1.1.4 root 3683: if (quit_program > 0)
1.1.1.3 root 3684: return;
3685:
1.1.1.4 root 3686: {
1.1.1.3 root 3687: static int cnt = 0;
3688: if (cnt == 0) {
3689: /* resolution_check_change (); */
3690: DISK_check_change ();
3691: cnt = 5;
3692: }
3693: cnt--;
1.1.1.2 root 3694: }
1.1.1.3 root 3695:
1.1.1.15 root 3696: /* Start a new set of copper records. */
3697: curr_cop_set ^= 1;
3698: nr_cop_records[curr_cop_set] = 0;
3699:
1.1.1.7 root 3700: /* For now, let's only allow this to change at vsync time. It gets too
3701: * hairy otherwise. */
3702: if (beamcon0 != new_beamcon0)
3703: init_hz ();
3704:
1.1.1.2 root 3705: lof_changed = 0;
1.1.1.3 root 3706:
1.1.1.4 root 3707: cop_state.ip = cop1lc;
3708: cop_state.state = COP_read1;
3709: cop_state.vpos = 0;
3710: cop_state.hpos = 0;
3711: cop_state.ignore_next = 0;
3712:
3713: init_hardware_frame ();
3714:
1.1 root 3715: #ifdef HAVE_GETTIMEOFDAY
3716: {
3717: struct timeval tv;
3718: unsigned long int newtime;
1.1.1.3 root 3719:
1.1.1.9 root 3720: gettimeofday (&tv,NULL);
1.1 root 3721: newtime = (tv.tv_sec-seconds_base) * 1000 + tv.tv_usec / 1000;
1.1.1.3 root 3722:
3723: if (!bogusframe) {
1.1.1.6 root 3724: lastframetime = newtime - msecs;
3725:
3726: #if 0 /* This doesn't appear to work too well yet... later. */
3727: if (n_consecutive_skipped > currprefs.sound_pri_cutoff
3728: || lastframetime < currprefs.sound_pri_time)
3729: {
3730: n_consecutive_skipped = 0;
3731: clear_inhibit_frame (IHF_SOUNDADJUST);
3732: } else {
3733: n_consecutive_skipped++;
3734: set_inhibit_frame (IHF_SOUNDADJUST);
3735: total_skipped++;
3736: }
3737: #endif
3738:
3739: frametime += lastframetime;
1.1 root 3740: timeframes++;
1.1.1.6 root 3741:
3742: if ((timeframes & 127) == 0)
3743: gui_fps (1000 * timeframes / frametime);
1.1 root 3744: }
3745: msecs = newtime;
3746: bogusframe = 0;
3747: }
3748: #endif
1.1.1.3 root 3749: if (ievent_alive > 0)
3750: ievent_alive--;
1.1.1.7 root 3751: if (timehack_alive > 0)
3752: timehack_alive--;
1.1.1.15 root 3753: CIA_vsync_handler ();
1.1 root 3754: }
3755:
1.1.1.4 root 3756: static void hsync_handler (void)
1.1 root 3757: {
1.1.1.15 root 3758: /* Using 0x8A makes sure that we don't accidentally trip over the
3759: modified_regtypes check. */
3760: sync_copper_with_cpu (maxhpos, 0, 0x8A);
1.1.1.10 root 3761:
1.1.1.2 root 3762: finish_decisions ();
1.1.1.15 root 3763: if (thisline_decision.plfleft != -1) {
3764: if (currprefs.collision_level > 1)
3765: do_sprite_collisions ();
3766: if (currprefs.collision_level > 2)
3767: do_playfield_collisions ();
3768: }
1.1.1.5 root 3769: hsync_record_line_state (next_lineno, nextline_how, thisline_changed);
1.1 root 3770:
1.1.1.14 root 3771: eventtab[ev_hsync].evtime += get_cycles () - eventtab[ev_hsync].oldcycles;
3772: eventtab[ev_hsync].oldcycles = get_cycles ();
1.1.1.8 root 3773: CIA_hsync_handler ();
1.1.1.3 root 3774:
3775: if (currprefs.produce_sound > 0) {
1.1 root 3776: int nr;
1.1.1.4 root 3777:
3778: update_audio ();
3779:
1.1 root 3780: /* Sound data is fetched at the beginning of each line */
1.1.1.17 root 3781: for (nr = 0; nr < 4; nr++) {
1.1 root 3782: struct audio_channel_data *cdp = audio_channel + nr;
1.1.1.3 root 3783:
1.1 root 3784: if (cdp->data_written == 2) {
3785: cdp->data_written = 0;
1.1.1.17 root 3786: cdp->nextdat = chipmem_wget (cdp->pt);
1.1 root 3787: cdp->pt += 2;
3788: if (cdp->state == 2 || cdp->state == 3) {
3789: if (cdp->wlen == 1) {
3790: cdp->pt = cdp->lc;
3791: cdp->wlen = cdp->len;
3792: cdp->intreq2 = 1;
3793: } else
1.1.1.16 root 3794: cdp->wlen = (cdp->wlen - 1) & 0xFFFF;
1.1 root 3795: }
3796: }
3797: }
3798: }
1.1.1.4 root 3799:
3800: hardware_line_completed (next_lineno);
3801:
1.1.1.16 root 3802: /* In theory only an equality test is needed here - but if a program
3803: goes haywire with the VPOSW register, it can cause us to miss this,
3804: with vpos going into the thousands (and all the nasty consequences
3805: this has). */
3806:
3807: if (++vpos >= (maxvpos + (lof != 0))) {
1.1 root 3808: vpos = 0;
1.1.1.15 root 3809: vsync_handler ();
1.1 root 3810: }
1.1.1.2 root 3811:
1.1.1.15 root 3812: DISK_update ();
3813:
1.1.1.4 root 3814: is_lastline = vpos + 1 == maxvpos + (lof != 0) && currprefs.m68k_speed == -1 && ! rpt_did_reset;
1.1.1.3 root 3815:
1.1.1.4 root 3816: if ((bplcon0 & 4) && currprefs.gfx_linedbl)
3817: notice_interlace_seen ();
1.1.1.2 root 3818:
3819: if (framecnt == 0) {
1.1.1.4 root 3820: int lineno = vpos;
3821: nextline_how = nln_normal;
1.1.1.3 root 3822: if (currprefs.gfx_linedbl) {
1.1 root 3823: lineno *= 2;
1.1.1.5 root 3824: nextline_how = currprefs.gfx_linedbl == 1 ? nln_doubled : nln_nblack;
1.1.1.2 root 3825: if (bplcon0 & 4) {
3826: if (!lof) {
3827: lineno++;
1.1.1.4 root 3828: nextline_how = nln_lower;
1.1.1.2 root 3829: } else {
1.1.1.4 root 3830: nextline_how = nln_upper;
1.1.1.2 root 3831: }
1.1 root 3832: }
3833: }
3834: next_lineno = lineno;
1.1.1.2 root 3835: reset_decisions ();
1.1 root 3836: }
1.1.1.3 root 3837: if (uae_int_requested) {
3838: set_uae_int_flag ();
3839: INTREQ (0xA000);
3840: }
1.1.1.9 root 3841: /* See if there's a chance of a copper wait ending this line. */
3842: cop_state.hpos = 0;
3843: compute_spcflag_copper ();
1.1.1.3 root 3844: }
3845:
1.1.1.15 root 3846: static void init_regtypes (void)
3847: {
3848: int i;
3849: for (i = 0; i < 512; i += 2) {
3850: regtypes[i] = REGTYPE_ALL;
3851: if ((i >= 0x20 && i < 0x28) || i == 0x08 || i == 0x7E)
3852: regtypes[i] = REGTYPE_DISK;
3853: else if (i >= 0x68 && i < 0x70)
3854: regtypes[i] = REGTYPE_NONE;
3855: else if (i >= 0x40 && i < 0x78)
3856: regtypes[i] = REGTYPE_BLITTER;
3857: else if (i >= 0xA0 && i < 0xE0 && (i & 0xF) < 0xE)
3858: regtypes[i] = REGTYPE_AUDIO;
3859: else if (i >= 0xA0 && i < 0xE0)
3860: regtypes[i] = REGTYPE_NONE;
3861: else if (i >= 0xE0 && i < 0x100)
3862: regtypes[i] = REGTYPE_PLANE;
3863: else if (i >= 0x120 && i < 0x180)
3864: regtypes[i] = REGTYPE_SPRITE;
3865: else if (i >= 0x180 && i < 0x1C0)
3866: regtypes[i] = REGTYPE_COLOR;
3867: else switch (i) {
3868: case 0x02:
3869: /* DMACONR - setting this to REGTYPE_BLITTER will cause it to
3870: conflict with DMACON (since that is REGTYPE_ALL), and the
3871: blitter registers (for the BBUSY bit), but nothing else,
3872: which is (I think) what we want. */
3873: regtypes[i] = REGTYPE_BLITTER;
3874: break;
3875: case 0x04: case 0x06: case 0x2A: case 0x2C:
3876: regtypes[i] = REGTYPE_POS;
3877: break;
3878: case 0x0A: case 0x0C:
3879: case 0x12: case 0x14: case 0x16:
3880: case 0x36:
3881: regtypes[i] = REGTYPE_JOYPORT;
3882: break;
3883: case 0x104:
3884: case 0x102:
3885: regtypes[i] = REGTYPE_PLANE;
3886: break;
3887: case 0x88: case 0x8A:
3888: case 0x8E: case 0x90: case 0x92: case 0x94:
3889: case 0x96:
3890: case 0x100:
3891: regtypes[i] |= REGTYPE_FORCE;
3892: break;
3893: }
3894: }
3895: }
3896:
3897: void init_eventtab (void)
1.1.1.3 root 3898: {
3899: int i;
3900:
1.1.1.15 root 3901: currcycle = 0;
3902: for (i = 0; i < ev_max; i++) {
1.1.1.3 root 3903: eventtab[i].active = 0;
3904: eventtab[i].oldcycles = 0;
3905: }
1.1.1.4 root 3906:
1.1.1.3 root 3907: eventtab[ev_cia].handler = CIA_handler;
3908: eventtab[ev_hsync].handler = hsync_handler;
1.1.1.14 root 3909: eventtab[ev_hsync].evtime = maxhpos * CYCLE_UNIT + get_cycles ();
1.1.1.3 root 3910: eventtab[ev_hsync].active = 1;
3911:
1.1.1.10 root 3912: eventtab[ev_copper].handler = copper_handler;
3913: eventtab[ev_copper].active = 0;
1.1.1.3 root 3914: eventtab[ev_blitter].handler = blitter_handler;
3915: eventtab[ev_blitter].active = 0;
1.1.1.11 root 3916: eventtab[ev_disk].handler = DISK_handler;
3917: eventtab[ev_disk].active = 0;
1.1.1.14 root 3918: eventtab[ev_audio].handler = audio_evhandler;
3919: eventtab[ev_audio].active = 0;
1.1.1.3 root 3920: events_schedule ();
1.1 root 3921: }
3922:
1.1.1.3 root 3923: void customreset (void)
1.1 root 3924: {
1.1.1.4 root 3925: int i;
1.1.1.11 root 3926: int zero = 0;
1.1 root 3927: #ifdef HAVE_GETTIMEOFDAY
3928: struct timeval tv;
3929: #endif
1.1.1.2 root 3930:
1.1.1.15 root 3931: if (! savestate_state) {
3932: currprefs.chipset_mask = changed_prefs.chipset_mask;
3933: if ((currprefs.chipset_mask & CSMASK_AGA) == 0) {
3934: for (i = 0; i < 32; i++) {
3935: current_colors.color_regs_ecs[i] = 0;
3936: current_colors.acolors[i] = xcolors[0];
3937: }
3938: } else {
3939: for (i = 0; i < 256; i++) {
3940: current_colors.color_regs_aga[i] = 0;
3941: current_colors.acolors[i] = CONVERT_RGB (zero);
3942: }
1.1.1.11 root 3943: }
1.1.1.15 root 3944:
3945: clx_sprmask = 0xFF;
3946: clxdat = 0;
3947:
3948: /* Clear the armed flags of all sprites. */
3949: memset (spr, 0, sizeof spr);
3950: nr_armed = 0;
3951:
3952: dmacon = intena = 0;
3953:
3954: copcon = 0;
3955: DSKLEN (0, 0);
3956:
1.1.1.16 root 3957: bplcon0 = 0;
1.1.1.15 root 3958: bplcon4 = 0x11; /* Get AGA chipset into ECS compatibility mode */
3959: bplcon3 = 0xC00;
3960:
3961: FMODE (0);
3962: CLXCON (0);
1.1.1.9 root 3963: }
1.1.1.3 root 3964:
1.1.1.12 root 3965: n_frames = 0;
3966:
1.1.1.3 root 3967: expamem_reset ();
1.1.1.4 root 3968:
1.1.1.12 root 3969: DISK_reset ();
1.1.1.3 root 3970: CIA_reset ();
1.1.1.13 root 3971: unset_special (~(SPCFLAG_BRK | SPCFLAG_MODE_CHANGE));
1.1.1.3 root 3972:
1.1.1.2 root 3973: vpos = 0;
1.1 root 3974: lof = 0;
1.1.1.3 root 3975:
1.1.1.4 root 3976: if (needmousehack ()) {
1.1.1.3 root 3977: #if 0
1.1.1.4 root 3978: mousehack_setfollow();
1.1.1.3 root 3979: #else
1.1.1.4 root 3980: mousehack_setdontcare();
1.1.1.3 root 3981: #endif
1.1 root 3982: } else {
3983: mousestate = normal_mouse;
3984: }
1.1.1.3 root 3985: ievent_alive = 0;
1.1.1.7 root 3986: timehack_alive = 0;
1.1.1.3 root 3987:
1.1.1.13 root 3988: curr_sprite_entries = 0;
3989: prev_sprite_entries = 0;
3990: sprite_entries[0][0].first_pixel = 0;
3991: sprite_entries[1][0].first_pixel = MAX_SPR_PIXELS;
3992: sprite_entries[0][1].first_pixel = 0;
3993: sprite_entries[1][1].first_pixel = MAX_SPR_PIXELS;
3994: memset (spixels, 0, sizeof spixels);
3995: memset (&spixstate, 0, sizeof spixstate);
1.1 root 3996:
3997: bltstate = BLT_done;
1.1.1.4 root 3998: cop_state.state = COP_stop;
1.1.1.2 root 3999: diwstate = DIW_waiting_start;
1.1.1.3 root 4000: hdiwstate = DIW_waiting_start;
1.1.1.14 root 4001: currcycle = 0;
1.1.1.3 root 4002:
1.1.1.14 root 4003: new_beamcon0 = currprefs.ntscmode ? 0x00 : 0x20;
1.1.1.7 root 4004: init_hz ();
4005:
4006: audio_reset ();
4007:
1.1.1.3 root 4008: init_sprites ();
4009:
1.1.1.2 root 4010: init_hardware_frame ();
1.1.1.4 root 4011: reset_drawing ();
4012:
1.1.1.2 root 4013: reset_decisions ();
1.1.1.3 root 4014:
1.1 root 4015: #ifdef HAVE_GETTIMEOFDAY
1.1.1.4 root 4016: gettimeofday (&tv, NULL);
1.1 root 4017: seconds_base = tv.tv_sec;
4018: bogusframe = 1;
4019: #endif
1.1.1.15 root 4020:
4021: init_regtypes ();
4022:
4023: sprite_buffer_res = currprefs.chipset_mask & CSMASK_AGA ? RES_HIRES : RES_LORES;
4024: if (savestate_state == STATE_RESTORE) {
4025: uae_u16 v;
4026: uae_u32 vv;
4027:
4028: update_adkmasks ();
4029: INTENA (0);
4030: INTREQ (0);
4031: #if 0
4032: DMACON (0, 0);
4033: #endif
4034: COPJMP1 (0);
4035: if (diwhigh)
4036: diwhigh_written = 1;
4037: v = bplcon0;
4038: BPLCON0 (0, 0);
4039: BPLCON0 (0, v);
1.1.1.17 root 4040: FMODE (fmode);
1.1.1.15 root 4041: if (!(currprefs.chipset_mask & CSMASK_AGA)) {
4042: for(i = 0 ; i < 32 ; i++) {
4043: vv = current_colors.color_regs_ecs[i];
4044: current_colors.color_regs_ecs[i] = -1;
4045: record_color_change (0, i, vv);
4046: remembered_color_entry = -1;
4047: current_colors.color_regs_ecs[i] = vv;
4048: current_colors.acolors[i] = xcolors[vv];
4049: }
4050: } else {
4051: for(i = 0 ; i < 256 ; i++) {
4052: vv = current_colors.color_regs_aga[i];
4053: current_colors.color_regs_aga[i] = -1;
4054: record_color_change (0, i, vv);
4055: remembered_color_entry = -1;
4056: current_colors.color_regs_aga[i] = vv;
4057: current_colors.acolors[i] = CONVERT_RGB(vv);
4058: }
4059: }
1.1.1.17 root 4060: CLXCON (clxcon);
4061: CLXCON2 (clxcon2);
1.1.1.15 root 4062: calcdiw ();
4063: write_log ("State restored\n");
4064: dumpcustom ();
4065: for (i = 0; i < 8; i++)
4066: nr_armed += spr[i].armed != 0;
4067: }
4068: expand_sprres ();
1.1 root 4069: }
4070:
1.1.1.3 root 4071: void dumpcustom (void)
1.1 root 4072: {
1.1.1.6 root 4073: write_log ("DMACON: %x INTENA: %x INTREQ: %x VPOS: %x HPOS: %x\n", DMACONR(),
4074: (unsigned int)intena, (unsigned int)intreq, (unsigned int)vpos, (unsigned int)current_hpos());
4075: write_log ("COP1LC: %08lx, COP2LC: %08lx\n", (unsigned long)cop1lc, (unsigned long)cop2lc);
1.1.1.13 root 4076: write_log ("DIWSTRT: %04x DIWSTOP: %04x DDFSTRT: %04x DDFSTOP: %04x\n",
4077: (unsigned int)diwstrt, (unsigned int)diwstop, (unsigned int)ddfstrt, (unsigned int)ddfstop);
1.1.1.3 root 4078: if (timeframes) {
1.1.1.6 root 4079: write_log ("Average frame time: %d ms [frames: %d time: %d]\n",
4080: frametime / timeframes, timeframes, frametime);
4081: if (total_skipped)
4082: write_log ("Skipped frames: %d\n", total_skipped);
1.1 root 4083: }
1.1.1.18 root 4084: /*for (i=0; i<256; i++) if (blitcount[i]) write_log ("minterm %x = %d\n",i,blitcount[i]); blitter debug */
1.1 root 4085: }
4086:
1.1.1.3 root 4087: int intlev (void)
1.1 root 4088: {
1.1.1.3 root 4089: uae_u16 imask = intreq & intena;
1.1 root 4090: if (imask && (intena & 0x4000)){
4091: if (imask & 0x2000) return 6;
4092: if (imask & 0x1800) return 5;
4093: if (imask & 0x0780) return 4;
4094: if (imask & 0x0070) return 3;
4095: if (imask & 0x0008) return 2;
4096: if (imask & 0x0007) return 1;
4097: }
4098: return -1;
4099: }
4100:
1.1.1.4 root 4101: static void gen_custom_tables (void)
4102: {
4103: int i;
4104: for (i = 0; i < 256; i++) {
4105: unsigned int j;
4106: sprtaba[i] = ((((i >> 7) & 1) << 0)
4107: | (((i >> 6) & 1) << 2)
4108: | (((i >> 5) & 1) << 4)
4109: | (((i >> 4) & 1) << 6)
4110: | (((i >> 3) & 1) << 8)
4111: | (((i >> 2) & 1) << 10)
4112: | (((i >> 1) & 1) << 12)
4113: | (((i >> 0) & 1) << 14));
4114: sprtabb[i] = sprtaba[i] * 2;
1.1.1.13 root 4115: sprite_ab_merge[i] = (((i & 15) ? 1 : 0)
4116: | ((i & 240) ? 2 : 0));
1.1.1.4 root 4117: }
1.1.1.13 root 4118: for (i = 0; i < 16; i++) {
4119: clxmask[i] = (((i & 1) ? 0xF : 0x3)
4120: | ((i & 2) ? 0xF0 : 0x30)
4121: | ((i & 4) ? 0xF00 : 0x300)
4122: | ((i & 8) ? 0xF000 : 0x3000));
4123: sprclx[i] = (((i & 0x3) == 0x3 ? 1 : 0)
4124: | ((i & 0x5) == 0x5 ? 2 : 0)
4125: | ((i & 0x9) == 0x9 ? 4 : 0)
4126: | ((i & 0x6) == 0x6 ? 8 : 0)
4127: | ((i & 0xA) == 0xA ? 16 : 0)
4128: | ((i & 0xC) == 0xC ? 32 : 0)) << 9;
4129: }
1.1.1.4 root 4130: }
4131:
1.1.1.3 root 4132: void custom_init (void)
1.1 root 4133: {
1.1.1.7 root 4134: uaecptr pos;
4135:
1.1.1.4 root 4136: #ifdef OS_WITHOUT_MEMORY_MANAGEMENT
1.1 root 4137: int num;
1.1.1.2 root 4138:
1.1.1.4 root 4139: for (num = 0; num < 2; num++) {
1.1.1.13 root 4140: sprite_entries[num] = xmalloc (max_sprite_entry * sizeof (struct sprite_entry));
1.1.1.4 root 4141: color_changes[num] = xmalloc (max_color_change * sizeof (struct color_change));
1.1.1.2 root 4142: }
4143: #endif
1.1.1.3 root 4144:
1.1.1.7 root 4145: pos = here ();
4146:
1.1.1.18 root 4147: org (RTAREA_BASE+0xFF70);
1.1.1.7 root 4148: calltrap (deftrap (mousehack_helper));
4149: dw (RTS);
4150:
1.1.1.18 root 4151: org (RTAREA_BASE+0xFFA0);
1.1.1.7 root 4152: calltrap (deftrap (timehack_helper));
4153: dw (RTS);
4154:
4155: org (pos);
4156:
1.1.1.4 root 4157: gen_custom_tables ();
4158: build_blitfilltable ();
4159:
4160: drawing_init ();
4161:
4162: mousestate = unknown_mouse;
4163:
4164: if (needmousehack ())
1.1.1.16 root 4165: mousehack_setfollow ();
4166:
4167: create_cycle_diagram_table ();
1.1 root 4168: }
4169:
4170: /* Custom chip memory bank */
4171:
1.1.1.4 root 4172: static uae_u32 custom_lget (uaecptr) REGPARAM;
4173: static uae_u32 custom_wget (uaecptr) REGPARAM;
4174: static uae_u32 custom_bget (uaecptr) REGPARAM;
4175: static void custom_lput (uaecptr, uae_u32) REGPARAM;
4176: static void custom_wput (uaecptr, uae_u32) REGPARAM;
4177: static void custom_bput (uaecptr, uae_u32) REGPARAM;
1.1 root 4178:
4179: addrbank custom_bank = {
4180: custom_lget, custom_wget, custom_bget,
4181: custom_lput, custom_wput, custom_bput,
1.1.1.15 root 4182: default_xlate, default_check, NULL
1.1 root 4183: };
4184:
1.1.1.13 root 4185: STATIC_INLINE uae_u32 REGPARAM2 custom_wget_1 (uaecptr addr)
1.1 root 4186: {
1.1.1.13 root 4187: special_mem |= S_READ;
1.1.1.4 root 4188: switch (addr & 0x1FE) {
1.1.1.13 root 4189: case 0x002: return DMACONR ();
4190: case 0x004: return VPOSR ();
4191: case 0x006: return VHPOSR ();
4192:
4193: case 0x008: return DSKDATR (current_hpos ());
4194:
4195: case 0x00A: return JOY0DAT ();
4196: case 0x00C: return JOY1DAT ();
4197: case 0x00E: return CLXDAT ();
4198: case 0x010: return ADKCONR ();
4199:
4200: case 0x012: return POT0DAT ();
4201: case 0x016: return POTGOR ();
4202: case 0x018: return SERDATR ();
4203: case 0x01A: return DSKBYTR (current_hpos ());
4204: case 0x01C: return INTENAR ();
4205: case 0x01E: return INTREQR ();
4206: case 0x07C: return DENISEID ();
4207:
4208: case 0x180: case 0x182: case 0x184: case 0x186: case 0x188: case 0x18A:
4209: case 0x18C: case 0x18E: case 0x190: case 0x192: case 0x194: case 0x196:
4210: case 0x198: case 0x19A: case 0x19C: case 0x19E: case 0x1A0: case 0x1A2:
4211: case 0x1A4: case 0x1A6: case 0x1A8: case 0x1AA: case 0x1AC: case 0x1AE:
4212: case 0x1B0: case 0x1B2: case 0x1B4: case 0x1B6: case 0x1B8: case 0x1BA:
4213: case 0x1BC: case 0x1BE:
4214: return COLOR_READ ((addr & 0x3E) / 2);
4215: break;
4216:
1.1 root 4217: default:
1.1.1.13 root 4218: custom_wput (addr, 0);
1.1 root 4219: return 0xffff;
4220: }
4221: }
4222:
1.1.1.13 root 4223: uae_u32 REGPARAM2 custom_wget (uaecptr addr)
4224: {
1.1.1.15 root 4225: sync_copper_with_cpu (current_hpos (), 1, addr);
1.1.1.13 root 4226: return custom_wget_1 (addr);
4227: }
4228:
1.1.1.3 root 4229: uae_u32 REGPARAM2 custom_bget (uaecptr addr)
1.1 root 4230: {
1.1.1.13 root 4231: special_mem |= S_READ;
4232: return custom_wget (addr & 0xfffe) >> (addr & 1 ? 0 : 8);
1.1 root 4233: }
4234:
1.1.1.3 root 4235: uae_u32 REGPARAM2 custom_lget (uaecptr addr)
1.1 root 4236: {
1.1.1.13 root 4237: special_mem |= S_READ;
4238: return ((uae_u32)custom_wget (addr & 0xfffe) << 16) | custom_wget ((addr + 2) & 0xfffe);
1.1 root 4239: }
4240:
1.1.1.4 root 4241: void REGPARAM2 custom_wput_1 (int hpos, uaecptr addr, uae_u32 value)
1.1 root 4242: {
4243: addr &= 0x1FE;
1.1.1.3 root 4244: switch (addr) {
4245: case 0x020: DSKPTH (value); break;
4246: case 0x022: DSKPTL (value); break;
1.1.1.13 root 4247: case 0x024: DSKLEN (value, hpos); break;
1.1.1.3 root 4248: case 0x026: DSKDAT (value); break;
4249:
4250: case 0x02A: VPOSW (value); break;
1.1.1.15 root 4251: case 0x02E: COPCON (value); break;
1.1.1.3 root 4252: case 0x030: SERDAT (value); break;
4253: case 0x032: SERPER (value); break;
1.1.1.15 root 4254: case 0x034: POTGO (value); break;
1.1.1.3 root 4255: case 0x040: BLTCON0 (value); break;
4256: case 0x042: BLTCON1 (value); break;
4257:
4258: case 0x044: BLTAFWM (value); break;
4259: case 0x046: BLTALWM (value); break;
4260:
4261: case 0x050: BLTAPTH (value); break;
4262: case 0x052: BLTAPTL (value); break;
4263: case 0x04C: BLTBPTH (value); break;
4264: case 0x04E: BLTBPTL (value); break;
4265: case 0x048: BLTCPTH (value); break;
4266: case 0x04A: BLTCPTL (value); break;
4267: case 0x054: BLTDPTH (value); break;
4268: case 0x056: BLTDPTL (value); break;
4269:
4270: case 0x058: BLTSIZE (value); break;
4271:
4272: case 0x064: BLTAMOD (value); break;
4273: case 0x062: BLTBMOD (value); break;
4274: case 0x060: BLTCMOD (value); break;
4275: case 0x066: BLTDMOD (value); break;
4276:
4277: case 0x070: BLTCDAT (value); break;
4278: case 0x072: BLTBDAT (value); break;
4279: case 0x074: BLTADAT (value); break;
4280:
4281: case 0x07E: DSKSYNC (value); break;
4282:
4283: case 0x080: COP1LCH (value); break;
4284: case 0x082: COP1LCL (value); break;
4285: case 0x084: COP2LCH (value); break;
4286: case 0x086: COP2LCL (value); break;
4287:
4288: case 0x088: COPJMP1 (value); break;
4289: case 0x08A: COPJMP2 (value); break;
4290:
1.1.1.4 root 4291: case 0x08E: DIWSTRT (hpos, value); break;
4292: case 0x090: DIWSTOP (hpos, value); break;
4293: case 0x092: DDFSTRT (hpos, value); break;
4294: case 0x094: DDFSTOP (hpos, value); break;
1.1.1.3 root 4295:
1.1.1.13 root 4296: case 0x096: DMACON (hpos, value); break;
1.1.1.3 root 4297: case 0x098: CLXCON (value); break;
4298: case 0x09A: INTENA (value); break;
4299: case 0x09C: INTREQ (value); break;
4300: case 0x09E: ADKCON (value); break;
4301:
4302: case 0x0A0: AUDxLCH (0, value); break;
4303: case 0x0A2: AUDxLCL (0, value); break;
4304: case 0x0A4: AUDxLEN (0, value); break;
4305: case 0x0A6: AUDxPER (0, value); break;
4306: case 0x0A8: AUDxVOL (0, value); break;
4307: case 0x0AA: AUDxDAT (0, value); break;
4308:
4309: case 0x0B0: AUDxLCH (1, value); break;
4310: case 0x0B2: AUDxLCL (1, value); break;
4311: case 0x0B4: AUDxLEN (1, value); break;
4312: case 0x0B6: AUDxPER (1, value); break;
4313: case 0x0B8: AUDxVOL (1, value); break;
4314: case 0x0BA: AUDxDAT (1, value); break;
4315:
4316: case 0x0C0: AUDxLCH (2, value); break;
4317: case 0x0C2: AUDxLCL (2, value); break;
4318: case 0x0C4: AUDxLEN (2, value); break;
4319: case 0x0C6: AUDxPER (2, value); break;
4320: case 0x0C8: AUDxVOL (2, value); break;
4321: case 0x0CA: AUDxDAT (2, value); break;
4322:
4323: case 0x0D0: AUDxLCH (3, value); break;
4324: case 0x0D2: AUDxLCL (3, value); break;
4325: case 0x0D4: AUDxLEN (3, value); break;
4326: case 0x0D6: AUDxPER (3, value); break;
4327: case 0x0D8: AUDxVOL (3, value); break;
4328: case 0x0DA: AUDxDAT (3, value); break;
4329:
1.1.1.4 root 4330: case 0x0E0: BPLPTH (hpos, value, 0); break;
4331: case 0x0E2: BPLPTL (hpos, value, 0); break;
4332: case 0x0E4: BPLPTH (hpos, value, 1); break;
4333: case 0x0E6: BPLPTL (hpos, value, 1); break;
4334: case 0x0E8: BPLPTH (hpos, value, 2); break;
4335: case 0x0EA: BPLPTL (hpos, value, 2); break;
4336: case 0x0EC: BPLPTH (hpos, value, 3); break;
4337: case 0x0EE: BPLPTL (hpos, value, 3); break;
4338: case 0x0F0: BPLPTH (hpos, value, 4); break;
4339: case 0x0F2: BPLPTL (hpos, value, 4); break;
4340: case 0x0F4: BPLPTH (hpos, value, 5); break;
4341: case 0x0F6: BPLPTL (hpos, value, 5); break;
1.1.1.6 root 4342: case 0x0F8: BPLPTH (hpos, value, 6); break;
4343: case 0x0FA: BPLPTL (hpos, value, 6); break;
4344: case 0x0FC: BPLPTH (hpos, value, 7); break;
4345: case 0x0FE: BPLPTL (hpos, value, 7); break;
1.1.1.4 root 4346:
4347: case 0x100: BPLCON0 (hpos, value); break;
4348: case 0x102: BPLCON1 (hpos, value); break;
4349: case 0x104: BPLCON2 (hpos, value); break;
4350: case 0x106: BPLCON3 (hpos, value); break;
1.1.1.3 root 4351:
1.1.1.4 root 4352: case 0x108: BPL1MOD (hpos, value); break;
4353: case 0x10A: BPL2MOD (hpos, value); break;
1.1.1.17 root 4354: case 0x10E: CLXCON2 (value); break;
1.1.1.3 root 4355:
1.1.1.13 root 4356: case 0x110: BPL1DAT (hpos, value); break;
1.1.1.3 root 4357: case 0x112: BPL2DAT (value); break;
4358: case 0x114: BPL3DAT (value); break;
4359: case 0x116: BPL4DAT (value); break;
4360: case 0x118: BPL5DAT (value); break;
4361: case 0x11A: BPL6DAT (value); break;
1.1.1.6 root 4362: case 0x11C: BPL7DAT (value); break;
4363: case 0x11E: BPL8DAT (value); break;
1.1 root 4364:
4365: case 0x180: case 0x182: case 0x184: case 0x186: case 0x188: case 0x18A:
4366: case 0x18C: case 0x18E: case 0x190: case 0x192: case 0x194: case 0x196:
4367: case 0x198: case 0x19A: case 0x19C: case 0x19E: case 0x1A0: case 0x1A2:
4368: case 0x1A4: case 0x1A6: case 0x1A8: case 0x1AA: case 0x1AC: case 0x1AE:
4369: case 0x1B0: case 0x1B2: case 0x1B4: case 0x1B6: case 0x1B8: case 0x1BA:
1.1.1.2 root 4370: case 0x1BC: case 0x1BE:
1.1.1.13 root 4371: COLOR_WRITE (hpos, value & 0xFFF, (addr & 0x3E) / 2);
1.1.1.2 root 4372: break;
4373: case 0x120: case 0x124: case 0x128: case 0x12C:
1.1 root 4374: case 0x130: case 0x134: case 0x138: case 0x13C:
1.1.1.4 root 4375: SPRxPTH (hpos, value, (addr - 0x120) / 4);
1.1 root 4376: break;
1.1.1.2 root 4377: case 0x122: case 0x126: case 0x12A: case 0x12E:
1.1 root 4378: case 0x132: case 0x136: case 0x13A: case 0x13E:
1.1.1.4 root 4379: SPRxPTL (hpos, value, (addr - 0x122) / 4);
1.1 root 4380: break;
1.1.1.2 root 4381: case 0x140: case 0x148: case 0x150: case 0x158:
1.1 root 4382: case 0x160: case 0x168: case 0x170: case 0x178:
1.1.1.4 root 4383: SPRxPOS (hpos, value, (addr - 0x140) / 8);
1.1 root 4384: break;
1.1.1.2 root 4385: case 0x142: case 0x14A: case 0x152: case 0x15A:
1.1 root 4386: case 0x162: case 0x16A: case 0x172: case 0x17A:
1.1.1.4 root 4387: SPRxCTL (hpos, value, (addr - 0x142) / 8);
1.1 root 4388: break;
4389: case 0x144: case 0x14C: case 0x154: case 0x15C:
4390: case 0x164: case 0x16C: case 0x174: case 0x17C:
1.1.1.4 root 4391: SPRxDATA (hpos, value, (addr - 0x144) / 8);
1.1 root 4392: break;
1.1.1.2 root 4393: case 0x146: case 0x14E: case 0x156: case 0x15E:
1.1 root 4394: case 0x166: case 0x16E: case 0x176: case 0x17E:
1.1.1.4 root 4395: SPRxDATB (hpos, value, (addr - 0x146) / 8);
1.1 root 4396: break;
1.1.1.3 root 4397:
4398: case 0x36: JOYTEST (value); break;
1.1.1.7 root 4399: case 0x5A: BLTCON0L (value); break;
1.1.1.3 root 4400: case 0x5C: BLTSIZV (value); break;
4401: case 0x5E: BLTSIZH (value); break;
1.1.1.4 root 4402: case 0x1E4: DIWHIGH (hpos, value); break;
4403: case 0x10C: BPLCON4 (hpos, value); break;
1.1.1.7 root 4404: case 0x1FC: FMODE (value); break;
1.1 root 4405: }
4406: }
4407:
1.1.1.4 root 4408: void REGPARAM2 custom_wput (uaecptr addr, uae_u32 value)
4409: {
4410: int hpos = current_hpos ();
1.1.1.13 root 4411: special_mem |= S_WRITE;
4412:
1.1.1.15 root 4413: sync_copper_with_cpu (hpos, 1, addr);
1.1.1.4 root 4414: custom_wput_1 (hpos, addr, value);
4415: }
4416:
4417: void REGPARAM2 custom_bput (uaecptr addr, uae_u32 value)
1.1 root 4418: {
1.1.1.2 root 4419: static int warned = 0;
4420: /* Is this correct now? (There are people who bput things to the upper byte of AUDxVOL). */
1.1.1.3 root 4421: uae_u16 rval = (value << 8) | (value & 0xFF);
1.1.1.13 root 4422: special_mem |= S_WRITE;
1.1.1.9 root 4423: custom_wput (addr, rval);
1.1.1.2 root 4424: if (!warned)
1.1.1.3 root 4425: write_log ("Byte put to custom register.\n"), warned++;
1.1 root 4426: }
4427:
1.1.1.3 root 4428: void REGPARAM2 custom_lput(uaecptr addr, uae_u32 value)
1.1 root 4429: {
1.1.1.13 root 4430: special_mem |= S_WRITE;
1.1.1.9 root 4431: custom_wput (addr & 0xfffe, value >> 16);
4432: custom_wput ((addr + 2) & 0xfffe, (uae_u16)value);
1.1 root 4433: }
1.1.1.15 root 4434:
4435: void custom_prepare_savestate (void)
4436: {
4437: /* force blitter to finish, no support for saving full blitter state yet */
4438: if (eventtab[ev_blitter].active) {
4439: unsigned int olddmacon = dmacon;
4440: dmacon |= DMA_BLITTER; /* ugh.. */
4441: blitter_handler ();
4442: dmacon = olddmacon;
4443: }
4444: }
4445:
4446: #define RB restore_u8 ()
4447: #define RW restore_u16 ()
4448: #define RL restore_u32 ()
4449:
4450: uae_u8 *restore_custom (uae_u8 *src)
4451: {
4452: uae_u16 dsklen, dskbytr, dskdatr;
4453: int dskpt;
4454: int i;
4455:
4456: audio_reset ();
4457:
4458: currprefs.chipset_mask = RL;
4459: RW; /* 000 ? */
4460: RW; /* 002 DMACONR */
4461: RW; /* 004 VPOSR */
4462: RW; /* 006 VHPOSR */
4463: dskdatr = RW; /* 008 DSKDATR */
4464: RW; /* 00A JOY0DAT */
4465: RW; /* 00C JOY1DAT */
4466: clxdat = RW; /* 00E CLXDAT */
4467: RW; /* 010 ADKCONR */
4468: RW; /* 012 POT0DAT* */
4469: RW; /* 014 POT1DAT* */
4470: RW; /* 016 POTINP* */
4471: RW; /* 018 SERDATR* */
4472: dskbytr = RW; /* 01A DSKBYTR */
4473: RW; /* 01C INTENAR */
4474: RW; /* 01E INTREQR */
4475: dskpt = RL; /* 020-022 DSKPT */
4476: dsklen = RW; /* 024 DSKLEN */
4477: RW; /* 026 DSKDAT */
4478: RW; /* 028 REFPTR */
4479: lof = RW; /* 02A VPOSW */
4480: RW; /* 02C VHPOSW */
4481: COPCON(RW); /* 02E COPCON */
4482: RW; /* 030 SERDAT* */
4483: RW; /* 032 SERPER* */
4484: POTGO(RW); /* 034 POTGO */
4485: RW; /* 036 JOYTEST* */
4486: RW; /* 038 STREQU */
4487: RW; /* 03A STRVHBL */
4488: RW; /* 03C STRHOR */
4489: RW; /* 03E STRLONG */
4490: BLTCON0(RW); /* 040 BLTCON0 */
4491: BLTCON1(RW); /* 042 BLTCON1 */
4492: BLTAFWM(RW); /* 044 BLTAFWM */
4493: BLTALWM(RW); /* 046 BLTALWM */
4494: BLTCPTH(RL); /* 048-04B BLTCPT */
4495: BLTBPTH(RL); /* 04C-04F BLTBPT */
4496: BLTAPTH(RL); /* 050-053 BLTAPT */
4497: BLTDPTH(RL); /* 054-057 BLTDPT */
4498: RW; /* 058 BLTSIZE */
4499: RW; /* 05A BLTCON0L */
4500: oldvblts = RW; /* 05C BLTSIZV */
4501: RW; /* 05E BLTSIZH */
4502: BLTCMOD(RW); /* 060 BLTCMOD */
4503: BLTBMOD(RW); /* 062 BLTBMOD */
4504: BLTAMOD(RW); /* 064 BLTAMOD */
4505: BLTDMOD(RW); /* 066 BLTDMOD */
4506: RW; /* 068 ? */
4507: RW; /* 06A ? */
4508: RW; /* 06C ? */
4509: RW; /* 06E ? */
4510: BLTCDAT(RW); /* 070 BLTCDAT */
4511: BLTBDAT(RW); /* 072 BLTBDAT */
4512: BLTADAT(RW); /* 074 BLTADAT */
4513: RW; /* 076 ? */
4514: RW; /* 078 ? */
4515: RW; /* 07A ? */
4516: RW; /* 07C LISAID */
4517: DSKSYNC(RW); /* 07E DSKSYNC */
4518: cop1lc = RL; /* 080/082 COP1LC */
4519: cop2lc = RL; /* 084/086 COP2LC */
4520: RW; /* 088 ? */
4521: RW; /* 08A ? */
4522: RW; /* 08C ? */
4523: diwstrt = RW; /* 08E DIWSTRT */
4524: diwstop = RW; /* 090 DIWSTOP */
4525: ddfstrt = RW; /* 092 DDFSTRT */
4526: ddfstop = RW; /* 094 DDFSTOP */
4527: dmacon = RW & ~(0x2000|0x4000); /* 096 DMACON */
4528: CLXCON(RW); /* 098 CLXCON */
4529: intena = RW; /* 09A INTENA */
4530: intreq = RW; /* 09C INTREQ */
4531: adkcon = RW; /* 09E ADKCON */
4532: for (i = 0; i < 8; i++)
4533: bplpt[i] = RL;
4534: bplcon0 = RW; /* 100 BPLCON0 */
4535: bplcon1 = RW; /* 102 BPLCON1 */
4536: bplcon2 = RW; /* 104 BPLCON2 */
4537: bplcon3 = RW; /* 106 BPLCON3 */
4538: bpl1mod = RW; /* 108 BPL1MOD */
4539: bpl2mod = RW; /* 10A BPL2MOD */
4540: bplcon4 = RW; /* 10C BPLCON4 */
1.1.1.17 root 4541: clxcon2 = RW; /* 10E CLXCON2* */
1.1.1.15 root 4542: for(i = 0; i < 8; i++)
4543: RW; /* BPLXDAT */
4544: for(i = 0; i < 32; i++)
4545: current_colors.color_regs_ecs[i] = RW; /* 180 COLORxx */
4546: RW; /* 1C0 ? */
4547: RW; /* 1C2 ? */
4548: RW; /* 1C4 ? */
4549: RW; /* 1C6 ? */
4550: RW; /* 1C8 ? */
4551: RW; /* 1CA ? */
4552: RW; /* 1CC ? */
4553: RW; /* 1CE ? */
4554: RW; /* 1D0 ? */
4555: RW; /* 1D2 ? */
4556: RW; /* 1D4 ? */
4557: RW; /* 1D6 ? */
4558: RW; /* 1D8 ? */
4559: RW; /* 1DA ? */
4560: new_beamcon0 = RW; /* 1DC BEAMCON0 */
4561: RW; /* 1DE ? */
4562: RW; /* 1E0 ? */
4563: RW; /* 1E2 ? */
4564: RW; /* 1E4 ? */
4565: RW; /* 1E6 ? */
4566: RW; /* 1E8 ? */
4567: RW; /* 1EA ? */
4568: RW; /* 1EC ? */
4569: RW; /* 1EE ? */
4570: RW; /* 1F0 ? */
4571: RW; /* 1F2 ? */
4572: RW; /* 1F4 ? */
4573: RW; /* 1F6 ? */
4574: RW; /* 1F8 ? */
4575: RW; /* 1FA ? */
4576: fmode = RW; /* 1FC FMODE */
4577: RW; /* 1FE ? */
4578:
4579: DISK_restore_custom (dskpt, dsklen, dskdatr, dskbytr);
4580:
4581: return src;
4582: }
4583:
4584:
4585: #define SB save_u8
4586: #define SW save_u16
4587: #define SL save_u32
4588:
4589: extern uae_u16 serper;
4590:
4591: uae_u8 *save_custom (int *len)
4592: {
4593: uae_u8 *dstbak, *dst;
4594: int i;
4595: uae_u32 dskpt;
4596: uae_u16 dsklen, dsksync, dskdatr, dskbytr;
4597:
4598: DISK_save_custom (&dskpt, &dsklen, &dsksync, &dskdatr, &dskbytr);
4599: dstbak = dst = malloc (8+256*2);
4600: SL (currprefs.chipset_mask);
4601: SW (0); /* 000 ? */
4602: SW (dmacon); /* 002 DMACONR */
4603: SW (VPOSR()); /* 004 VPOSR */
4604: SW (VHPOSR()); /* 006 VHPOSR */
4605: SW (dskdatr); /* 008 DSKDATR */
4606: SW (JOY0DAT()); /* 00A JOY0DAT */
4607: SW (JOY1DAT()); /* 00C JOY1DAT */
4608: SW (clxdat); /* 00E CLXDAT */
4609: SW (ADKCONR()); /* 010 ADKCONR */
4610: SW (POT0DAT()); /* 012 POT0DAT */
4611: SW (POT0DAT()); /* 014 POT1DAT */
4612: SW (0) ; /* 016 POTINP * */
4613: SW (0); /* 018 SERDATR * */
4614: SW (dskbytr); /* 01A DSKBYTR */
4615: SW (INTENAR()); /* 01C INTENAR */
4616: SW (INTREQR()); /* 01E INTREQR */
4617: SL (dskpt); /* 020-023 DSKPT */
4618: SW (dsklen); /* 024 DSKLEN */
4619: SW (0); /* 026 DSKDAT */
4620: SW (0); /* 028 REFPTR */
4621: SW (lof); /* 02A VPOSW */
4622: SW (0); /* 02C VHPOSW */
4623: SW (copcon); /* 02E COPCON */
4624: SW (serper); /* 030 SERDAT * */
4625: SW (serdat); /* 032 SERPER * */
4626: SW (potgo_value); /* 034 POTGO */
4627: SW (0); /* 036 JOYTEST * */
4628: SW (0); /* 038 STREQU */
4629: SW (0); /* 03A STRVBL */
4630: SW (0); /* 03C STRHOR */
4631: SW (0); /* 03E STRLONG */
4632: SW (bltcon0); /* 040 BLTCON0 */
4633: SW (bltcon1); /* 042 BLTCON1 */
4634: SW (blt_info.bltafwm); /* 044 BLTAFWM */
4635: SW (blt_info.bltalwm); /* 046 BLTALWM */
4636: SL (bltcpt); /* 048-04B BLTCPT */
4637: SL (bltbpt); /* 04C-04F BLTCPT */
4638: SL (bltapt); /* 050-043 BLTCPT */
4639: SL (bltdpt); /* 054-057 BLTCPT */
4640: SW (0); /* 058 BLTSIZE */
4641: SW (0); /* 05A BLTCON0L (use BLTCON0 instead) */
4642: SW (oldvblts); /* 05C BLTSIZV */
4643: SW (blt_info.hblitsize); /* 05E BLTSIZH */
4644: SW (blt_info.bltcmod); /* 060 BLTCMOD */
4645: SW (blt_info.bltbmod); /* 062 BLTBMOD */
4646: SW (blt_info.bltamod); /* 064 BLTAMOD */
4647: SW (blt_info.bltdmod); /* 066 BLTDMOD */
4648: SW (0); /* 068 ? */
4649: SW (0); /* 06A ? */
4650: SW (0); /* 06C ? */
4651: SW (0); /* 06E ? */
4652: SW (blt_info.bltcdat); /* 070 BLTCDAT */
4653: SW (blt_info.bltbdat); /* 072 BLTBDAT */
4654: SW (blt_info.bltadat); /* 074 BLTADAT */
4655: SW (0); /* 076 ? */
4656: SW (0); /* 078 ? */
4657: SW (0); /* 07A ? */
4658: SW (DENISEID()); /* 07C DENISEID/LISAID */
4659: SW (dsksync); /* 07E DSKSYNC */
4660: SL (cop1lc); /* 080-083 COP1LC */
4661: SL (cop2lc); /* 084-087 COP2LC */
4662: SW (0); /* 088 ? */
4663: SW (0); /* 08A ? */
4664: SW (0); /* 08C ? */
4665: SW (diwstrt); /* 08E DIWSTRT */
4666: SW (diwstop); /* 090 DIWSTOP */
4667: SW (ddfstrt); /* 092 DDFSTRT */
4668: SW (ddfstop); /* 094 DDFSTOP */
4669: SW (dmacon); /* 096 DMACON */
4670: SW (clxcon); /* 098 CLXCON */
4671: SW (intena); /* 09A INTENA */
4672: SW (intreq); /* 09C INTREQ */
4673: SW (adkcon); /* 09E ADKCON */
4674: for (i = 0; i < 8; i++)
4675: SL (bplpt[i]); /* 0E0-0FE BPLxPT */
4676: SW (bplcon0); /* 100 BPLCON0 */
4677: SW (bplcon1); /* 102 BPLCON1 */
4678: SW (bplcon2); /* 104 BPLCON2 */
4679: SW (bplcon3); /* 106 BPLCON3 */
4680: SW (bpl1mod); /* 108 BPL1MOD */
4681: SW (bpl2mod); /* 10A BPL2MOD */
4682: SW (bplcon4); /* 10C BPLCON4 */
1.1.1.17 root 4683: SW (clxcon2); /* 10E CLXCON2 */
1.1.1.15 root 4684: for (i = 0;i < 8; i++)
4685: SW (0); /* 110 BPLxDAT */
4686: for ( i = 0; i < 32; i++)
4687: SW (current_colors.color_regs_ecs[i]); /* 180-1BE COLORxx */
4688: SW (0); /* 1C0 */
4689: SW (0); /* 1C2 */
4690: SW (0); /* 1C4 */
4691: SW (0); /* 1C6 */
4692: SW (0); /* 1C8 */
4693: SW (0); /* 1CA */
4694: SW (0); /* 1CC */
4695: SW (0); /* 1CE */
4696: SW (0); /* 1D0 */
4697: SW (0); /* 1D2 */
4698: SW (0); /* 1D4 */
4699: SW (0); /* 1D6 */
4700: SW (0); /* 1D8 */
4701: SW (0); /* 1DA */
4702: SW (beamcon0); /* 1DC BEAMCON0 */
4703: SW (0); /* 1DE */
4704: SW (0); /* 1E0 */
4705: SW (0); /* 1E2 */
4706: SW (0); /* 1E4 */
4707: SW (0); /* 1E6 */
4708: SW (0); /* 1E8 */
4709: SW (0); /* 1EA */
4710: SW (0); /* 1EC */
4711: SW (0); /* 1EE */
4712: SW (0); /* 1F0 */
4713: SW (0); /* 1F2 */
4714: SW (0); /* 1F4 */
4715: SW (0); /* 1F6 */
4716: SW (0); /* 1F8 */
4717: SW (0); /* 1FA */
4718: SW (fmode); /* 1FC FMODE */
4719: SW (0xffff); /* 1FE */
4720:
4721: *len = dst - dstbak;
4722: return dstbak;
4723: }
4724:
4725: uae_u8 *restore_custom_agacolors (uae_u8 *src)
4726: {
4727: int i;
4728:
4729: for (i = 0; i < 256; i++)
4730: current_colors.color_regs_aga[i] = RL;
4731: return src;
4732: }
4733:
4734: uae_u8 *save_custom_agacolors (int *len)
4735: {
4736: uae_u8 *dstbak, *dst;
4737: int i;
4738:
4739: dstbak = dst = malloc (256*4);
4740: for (i = 0; i < 256; i++)
4741: SL (current_colors.color_regs_aga[i]);
4742: *len = dst - dstbak;
4743: return dstbak;
4744: }
4745:
4746: uae_u8 *restore_custom_sprite (uae_u8 *src, int num)
4747: {
4748: spr[num].pt = RL; /* 120-13E SPRxPT */
4749: sprpos[num] = RW; /* 1x0 SPRxPOS */
4750: sprctl[num] = RW; /* 1x2 SPRxPOS */
4751: sprdata[num][0] = RW; /* 1x4 SPRxDATA */
4752: sprdatb[num][0] = RW; /* 1x6 SPRxDATB */
4753: sprdata[num][1] = RW;
4754: sprdatb[num][1] = RW;
4755: sprdata[num][2] = RW;
4756: sprdatb[num][2] = RW;
4757: sprdata[num][3] = RW;
4758: sprdatb[num][3] = RW;
4759: spr[num].armed = RB;
4760: return src;
4761: }
4762:
4763: uae_u8 *save_custom_sprite(int *len, int num)
4764: {
4765: uae_u8 *dstbak, *dst;
4766:
1.1.1.16 root 4767: dstbak = dst = malloc (25);
1.1.1.15 root 4768: SL (spr[num].pt); /* 120-13E SPRxPT */
4769: SW (sprpos[num]); /* 1x0 SPRxPOS */
4770: SW (sprctl[num]); /* 1x2 SPRxPOS */
4771: SW (sprdata[num][0]); /* 1x4 SPRxDATA */
4772: SW (sprdatb[num][0]); /* 1x6 SPRxDATB */
4773: SW (sprdata[num][1]);
4774: SW (sprdatb[num][1]);
4775: SW (sprdata[num][2]);
4776: SW (sprdatb[num][2]);
4777: SW (sprdata[num][3]);
4778: SW (sprdatb[num][3]);
4779: SB (spr[num].armed ? 1 : 0);
4780: *len = dst - dstbak;
4781: return dstbak;
4782: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.