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