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