|
|
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.4 root 6: * Copyright 1995-1998 Bernd Schmidt
1.1.1.2 root 7: * Copyright 1995 Alessandro Bissacco
1.1 root 8: */
9:
10: #include "sysconfig.h"
11: #include "sysdeps.h"
12:
13: #include <ctype.h>
14: #include <assert.h>
15:
16: #include "config.h"
17: #include "options.h"
1.1.1.3 root 18: #include "threaddep/penguin.h"
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 "joystick.h"
31: #include "audio.h"
1.1 root 32: #include "keybuf.h"
33: #include "serial.h"
1.1.1.2 root 34: #include "osemu.h"
1.1.1.3 root 35: #include "autoconf.h"
36: #include "gui.h"
37: #include "picasso96.h"
1.1.1.4 root 38: #include "drawing.h"
1.1.1.2 root 39:
1.1.1.6 root 40: static unsigned int n_consecutive_skipped = 0;
41: static unsigned int total_skipped = 0;
42:
1.1.1.3 root 43: #define SPRITE_COLLISIONS
1.1.1.2 root 44:
1.1.1.3 root 45: /* Mouse and joystick emulation */
1.1.1.2 root 46:
1.1.1.3 root 47: int buttonstate[3];
48: static int mouse_x, mouse_y;
49: int joy0button, joy1button;
50: unsigned int joy0dir, joy1dir;
51:
52: /* Events */
1.1 root 53:
1.1.1.14! root 54: unsigned long int currcycle, nextevent, is_lastline;
1.1.1.4 root 55: static int rpt_did_reset;
1.1.1.2 root 56: struct ev eventtab[ev_max];
57:
1.1.1.3 root 58: frame_time_t vsynctime, vsyncmintime;
59:
1.1.1.4 root 60: static int vpos;
61: static uae_u16 lof;
62: static int next_lineno;
63: static enum nln_how nextline_how;
64: static int lof_changed = 0;
1.1 root 65:
1.1.1.3 root 66: static uae_u32 sprtaba[256],sprtabb[256];
1.1.1.13 root 67: static uae_u32 sprite_ab_merge[256];
68: /* Tables for collision detection. */
69: static uae_u32 sprclx[16], clxmask[16];
1.1.1.3 root 70:
1.1.1.2 root 71: /*
72: * Hardware registers of all sorts.
73: */
1.1 root 74:
1.1.1.4 root 75: static void custom_wput_1 (int, uaecptr, uae_u32) REGPARAM;
76:
1.1.1.3 root 77: static uae_u16 cregs[256];
1.1 root 78:
1.1.1.3 root 79: uae_u16 intena,intreq;
80: uae_u16 dmacon;
81: uae_u16 adkcon; /* used by audio code */
1.1 root 82:
1.1.1.3 root 83: static uae_u32 cop1lc,cop2lc,copcon;
1.1.1.7 root 84:
85: int maxhpos = MAXHPOS_PAL;
86: int maxvpos = MAXVPOS_PAL;
87: int minfirstline = MINFIRSTLINE_PAL;
88: int vblank_endline = VBLANK_ENDLINE_PAL;
89: int vblank_hz = VBLANK_HZ_PAL;
90: unsigned long syncbase;
91: static int fmode;
92: static unsigned int beamcon0, new_beamcon0;
93:
94: #define MAX_SPRITES 32
1.1 root 95:
1.1.1.2 root 96: /* This is but an educated guess. It seems to be correct, but this stuff
97: * isn't documented well. */
1.1.1.3 root 98: enum sprstate { SPR_stop, SPR_restart, SPR_waiting_start, SPR_waiting_stop };
1.1.1.10 root 99:
100: struct sprite {
101: uaecptr pt;
102: int on;
103: int xpos;
104: int vstart;
105: int vstop;
106: int armed;
107: enum sprstate state;
108: };
109:
110: static struct sprite spr[8];
111:
1.1.1.14! root 112: static int sprite_width;
! 113:
1.1.1.10 root 114: static int sprite_vblank_endline = VBLANK_ENDLINE_NTSC + 2;
1.1 root 115:
1.1.1.7 root 116: static unsigned int sprdata[MAX_SPRITES], sprdatb[MAX_SPRITES], sprctl[MAX_SPRITES], sprpos[MAX_SPRITES];
1.1.1.10 root 117: static int sprite_last_drawn_at[MAX_SPRITES];
1.1.1.7 root 118: static int last_sprite_point, nr_armed;
119:
1.1.1.6 root 120: static uae_u32 bpl1dat, bpl2dat, bpl3dat, bpl4dat, bpl5dat, bpl6dat, bpl7dat, bpl8dat;
121: static uae_s16 bpl1mod, bpl2mod;
1.1 root 122:
1.1.1.3 root 123: static uaecptr bplpt[8];
1.1.1.10 root 124: uae_u8 *real_bplpt[8];
1.1 root 125:
126: /*static int blitcount[256]; blitter debug */
127:
1.1.1.2 root 128: static struct color_entry current_colors;
1.1.1.6 root 129: static unsigned int bplcon0, bplcon1, bplcon2, bplcon3, bplcon4;
1.1.1.3 root 130: static int nr_planes_from_bplcon0, corrected_nr_planes_from_bplcon0;
1.1.1.4 root 131: static unsigned int diwstrt, diwstop, diwhigh;
132: static int diwhigh_written;
133: static unsigned int ddfstrt, ddfstop;
1.1.1.7 root 134:
1.1.1.4 root 135: /* The display and data fetch windows */
1.1 root 136:
1.1.1.4 root 137: enum diw_states
138: {
139: DIW_waiting_start, DIW_waiting_stop
140: };
1.1 root 141:
1.1.1.13 root 142: static int plffirstline, plflastline;
143: static int plfstrt, plfstop;
144: static int last_diw_pix_hpos, last_ddf_pix_hpos, last_decide_line_hpos;
145: static int last_fetch_hpos, last_sprite_hpos;
1.1.1.6 root 146: int diwfirstword, diwlastword;
1.1.1.4 root 147: static enum diw_states diwstate, hdiwstate;
1.1 root 148:
1.1.1.4 root 149: /* Sprite collisions */
1.1.1.14! root 150: static unsigned int clxdat, clxcon, clxcon2, clxcon_bpl_enable, clxcon_bpl_match;
! 151: static int clx_sprmask;
1.1.1.4 root 152:
153: enum copper_states {
154: COP_stop,
1.1.1.10 root 155: COP_read1, COP_read2,
1.1.1.4 root 156: COP_bltwait,
1.1.1.13 root 157: COP_wait,
158: COP_wait1
1.1.1.4 root 159: };
160:
161: struct copper {
162: /* The current instruction words. */
163: unsigned int i1, i2;
164: enum copper_states state;
165: /* Instruction pointer. */
166: uaecptr ip;
1.1.1.10 root 167: int hpos, vpos;
1.1.1.4 root 168: unsigned int ignore_next;
1.1.1.10 root 169: int vcmp, hcmp;
1.1.1.4 root 170: };
171:
172: static struct copper cop_state;
1.1.1.10 root 173: static int copper_enabled_thisline;
174: static int cop_min_waittime;
1.1 root 175:
176: /*
177: * Statistics
178: */
179:
1.1.1.2 root 180: /* Used also by bebox.cpp */
1.1.1.6 root 181: unsigned long int msecs = 0, frametime = 0, lastframetime = 0, timeframes = 0;
1.1 root 182: static unsigned long int seconds_base;
183: int bogusframe;
1.1.1.12 root 184: int n_frames;
1.1.1.4 root 185:
186: static int current_change_set;
187:
188: #ifdef OS_WITHOUT_MEMORY_MANAGEMENT
189: /* sam: Those arrays uses around 7Mb of BSS... That seems */
190: /* too much for AmigaDOS (uae crashes as soon as one loads */
191: /* it. So I use a different strategy here (realloc the */
192: /* arrays when needed. That strategy might be usefull for */
193: /* computer with low memory. */
1.1.1.13 root 194: struct sprite_entry *sprite_entries[2];
1.1.1.4 root 195: struct color_change *color_changes[2];
1.1.1.13 root 196: static int max_sprite_entry = 400;
197: static int delta_sprite_entry = 0;
1.1.1.4 root 198: static int max_color_change = 400;
199: static int delta_color_change = 0;
200: #else
1.1.1.13 root 201: struct sprite_entry sprite_entries[2][MAX_SPR_PIXELS / 16];
1.1.1.4 root 202: struct color_change color_changes[2][MAX_REG_CHANGE];
203: #endif
204:
1.1.1.7 root 205: struct decision line_decisions[2 * (MAXVPOS + 1) + 1];
206: struct draw_info line_drawinfo[2][2 * (MAXVPOS + 1) + 1];
207: struct color_entry color_tables[2][(MAXVPOS + 1) * 2];
1.1.1.4 root 208:
1.1.1.13 root 209: static int next_sprite_entry = 0;
210: static int prev_next_sprite_entry;
211: static int next_sprite_forced = 1;
212:
213: struct sprite_entry *curr_sprite_entries, *prev_sprite_entries;
1.1.1.4 root 214: struct color_change *curr_color_changes, *prev_color_changes;
215: struct draw_info *curr_drawinfo, *prev_drawinfo;
216: struct color_entry *curr_color_tables, *prev_color_tables;
217:
1.1.1.13 root 218: static int next_color_change;
1.1.1.4 root 219: static int next_color_entry, remembered_color_entry;
220: static int color_src_match, color_dest_match, color_compare_result;
221:
222: /* These few are only needed during/at the end of the scanline, and don't
223: * have to be remembered. */
1.1.1.13 root 224: static int decided_bpl1mod, decided_bpl2mod, decided_nr_planes;
1.1.1.5 root 225:
1.1.1.13 root 226: static uae_u32 thisline_changed;
1.1.1.4 root 227:
228: #ifdef SMART_UPDATE
1.1.1.5 root 229: #define MARK_LINE_CHANGED do { thisline_changed = 1; } while (0)
1.1.1.4 root 230: #else
1.1.1.5 root 231: #define MARK_LINE_CHANGED do { ; } while (0)
1.1.1.4 root 232: #endif
233:
234: static struct decision thisline_decision;
1.1.1.13 root 235: static int modulos_added, plane_decided, color_decided;
236: static int passed_plfstop, fetch_cycle;
237:
238: enum fetchstate {
239: fetch_not_started,
240: fetch_started,
241: fetch_was_plane0
242: } fetch_state;
1.1.1.4 root 243:
1.1 root 244: /*
245: * helper functions
246: */
247:
1.1.1.4 root 248: int rpt_available = 0;
1.1.1.3 root 249:
1.1.1.4 root 250: void reset_frame_rate_hack (void)
251: {
252: if (currprefs.m68k_speed != -1)
253: return;
254:
255: if (! rpt_available) {
256: currprefs.m68k_speed = 0;
257: return;
258: }
1.1.1.3 root 259:
1.1.1.4 root 260: rpt_did_reset = 1;
261: is_lastline = 0;
262: vsyncmintime = read_processor_time() + vsynctime;
263: write_log ("Resetting frame rate hack\n");
264: }
1.1 root 265:
1.1.1.3 root 266: void check_prefs_changed_custom (void)
267: {
1.1.1.7 root 268: currprefs.gfx_framerate = changed_prefs.gfx_framerate;
1.1.1.3 root 269: /* Not really the right place... */
1.1.1.6 root 270: if (currprefs.jport0 != changed_prefs.jport0
271: || currprefs.jport1 != changed_prefs.jport1) {
272: currprefs.jport0 = changed_prefs.jport0;
273: currprefs.jport1 = changed_prefs.jport1;
1.1.1.3 root 274: joystick_setting_changed ();
1.1 root 275: }
1.1.1.3 root 276: currprefs.immediate_blits = changed_prefs.immediate_blits;
277: currprefs.blits_32bit_enabled = changed_prefs.blits_32bit_enabled;
278:
1.1 root 279: }
280:
1.1.1.8 root 281: STATIC_INLINE void setclr (uae_u16 *p, uae_u16 val)
1.1 root 282: {
1.1.1.6 root 283: if (val & 0x8000)
1.1 root 284: *p |= val & 0x7FFF;
1.1.1.6 root 285: else
1.1 root 286: *p &= ~val;
287: }
288:
1.1.1.3 root 289: __inline__ int current_hpos (void)
1.1 root 290: {
1.1.1.14! root 291: return (get_cycles () - eventtab[ev_hsync].oldcycles) / CYCLE_UNIT;
1.1 root 292: }
293:
1.1.1.8 root 294: STATIC_INLINE uae_u8 *pfield_xlateptr (uaecptr plpt, int bytecount)
1.1.1.2 root 295: {
1.1.1.4 root 296: if (!chipmem_bank.check (plpt, bytecount)) {
1.1.1.2 root 297: static int count = 0;
1.1.1.3 root 298: if (!count)
299: count++, write_log ("Warning: Bad playfield pointer\n");
1.1.1.2 root 300: return NULL;
301: }
1.1.1.4 root 302: return chipmem_bank.xlateaddr (plpt);
1.1.1.2 root 303: }
304:
1.1.1.8 root 305: STATIC_INLINE void docols (struct color_entry *colentry)
1.1.1.3 root 306: {
307: int i;
1.1.1.11 root 308:
309: if (currprefs.chipset_mask & CSMASK_AGA) {
310: for (i = 0; i < 256; i++) {
311: int v = color_reg_get (colentry, i);
1.1.1.14! root 312: if (v < 0 || v > 16777215)
1.1.1.11 root 313: continue;
314: colentry->acolors[i] = CONVERT_RGB (v);
315: }
316: } else {
317: for (i = 0; i < 32; i++) {
318: int v = color_reg_get (colentry, i);
319: if (v < 0 || v > 4095)
320: continue;
321: colentry->acolors[i] = xcolors[v];
322: }
1.1.1.3 root 323: }
324: }
325:
326: void notice_new_xcolors (void)
327: {
328: int i;
329:
330: docols(¤t_colors);
1.1.1.4 root 331: /* docols(&colors_for_drawing);*/
1.1.1.7 root 332: for (i = 0; i < (MAXVPOS + 1)*2; i++) {
1.1.1.3 root 333: docols(color_tables[0]+i);
334: docols(color_tables[1]+i);
335: }
336: }
337:
1.1.1.4 root 338: static void do_sprites (int currvp, int currhp);
1.1.1.2 root 339:
340: static void remember_ctable (void)
341: {
342: if (remembered_color_entry == -1) {
343: /* The colors changed since we last recorded a color map. Record a
344: * new one. */
1.1.1.11 root 345: color_reg_cpy (curr_color_tables + next_color_entry, ¤t_colors);
1.1.1.2 root 346: remembered_color_entry = next_color_entry++;
347: }
348: thisline_decision.ctable = remembered_color_entry;
349: if (color_src_match == -1 || color_dest_match != remembered_color_entry
350: || line_decisions[next_lineno].ctable != color_src_match)
351: {
352: /* The remembered comparison didn't help us - need to compare again. */
353: int oldctable = line_decisions[next_lineno].ctable;
354: int changed = 0;
355:
1.1.1.3 root 356: if (oldctable == -1) {
1.1.1.2 root 357: changed = 1;
358: color_src_match = color_dest_match = -1;
359: } else {
1.1.1.11 root 360: color_compare_result = color_reg_cmp (&prev_color_tables[oldctable], ¤t_colors) != 0;
1.1.1.3 root 361: if (color_compare_result)
362: changed = 1;
363: color_src_match = oldctable;
1.1.1.2 root 364: color_dest_match = remembered_color_entry;
1.1.1.3 root 365: }
1.1.1.5 root 366: thisline_changed |= changed;
1.1.1.3 root 367: } else {
368: /* We know the result of the comparison */
369: if (color_compare_result)
1.1.1.5 root 370: thisline_changed = 1;
1.1.1.3 root 371: }
372: }
373:
374: static void remember_ctable_for_border (void)
375: {
376: remember_ctable ();
1.1.1.2 root 377: }
378:
1.1.1.3 root 379: /* Called to determine the state of the horizontal display window state
380: * machine at the current position. It might have changed since we last
381: * checked. */
1.1.1.4 root 382: static void decide_diw (int hpos)
1.1.1.2 root 383: {
1.1.1.13 root 384: int pix_hpos = coord_diw_to_window_x (hpos * 2);
1.1.1.3 root 385: if (hdiwstate == DIW_waiting_start && thisline_decision.diwfirstword == -1
1.1.1.9 root 386: && pix_hpos >= diwfirstword && last_diw_pix_hpos < diwfirstword)
1.1.1.3 root 387: {
1.1.1.13 root 388: thisline_decision.diwfirstword = diwfirstword < 0 ? 0 : diwfirstword;
1.1.1.3 root 389: hdiwstate = DIW_waiting_stop;
1.1.1.2 root 390: thisline_decision.diwlastword = -1;
391: }
1.1.1.3 root 392: if (hdiwstate == DIW_waiting_stop && thisline_decision.diwlastword == -1
1.1.1.9 root 393: && pix_hpos >= diwlastword && last_diw_pix_hpos < diwlastword)
1.1.1.3 root 394: {
1.1.1.13 root 395: thisline_decision.diwlastword = diwlastword < 0 ? 0 : diwlastword;
1.1.1.3 root 396: hdiwstate = DIW_waiting_start;
1.1.1.2 root 397: }
1.1.1.9 root 398: last_diw_pix_hpos = pix_hpos;
1.1.1.2 root 399: }
400:
1.1.1.13 root 401: /* The HRM says 0xD8, but that can't work... */
402: #define HARD_DDF_STOP (0xD4)
1.1.1.2 root 403:
1.1.1.13 root 404: static void finish_playfield_line (void)
405: {
1.1.1.2 root 406: /* The latter condition might be able to happen in interlaced frames. */
407: if (vpos >= minfirstline && (thisframe_first_drawn_line == -1 || vpos < thisframe_first_drawn_line))
408: thisframe_first_drawn_line = vpos;
409: thisframe_last_drawn_line = vpos;
410:
1.1.1.13 root 411: if (dmaen (DMA_BITPLANE))
412: switch (nr_planes_from_bplcon0) {
413: case 8: bplpt[7] += bpl2mod;
414: case 7: bplpt[6] += bpl1mod;
415: case 6: bplpt[5] += bpl2mod;
416: case 5: bplpt[4] += bpl1mod;
417: case 4: bplpt[3] += bpl2mod;
418: case 3: bplpt[2] += bpl1mod;
419: case 2: bplpt[1] += bpl2mod;
420: case 1: bplpt[0] += bpl1mod;
421: }
1.1.1.2 root 422:
423: /* These are for comparison. */
424: thisline_decision.bplcon0 = bplcon0;
425: thisline_decision.bplcon2 = bplcon2;
1.1.1.14! root 426: thisline_decision.bplcon3 = bplcon3;
1.1.1.2 root 427: thisline_decision.bplcon4 = bplcon4;
428:
429: #ifdef SMART_UPDATE
1.1.1.13 root 430: if (line_decisions[next_lineno].plflinelen != thisline_decision.plflinelen
431: || line_decisions[next_lineno].plfleft != thisline_decision.plfleft
1.1.1.2 root 432: || line_decisions[next_lineno].bplcon0 != thisline_decision.bplcon0
433: || line_decisions[next_lineno].bplcon2 != thisline_decision.bplcon2
1.1.1.14! root 434: || line_decisions[next_lineno].bplcon3 != thisline_decision.bplcon3
1.1.1.2 root 435: || line_decisions[next_lineno].bplcon4 != thisline_decision.bplcon4
436: )
437: #endif /* SMART_UPDATE */
1.1.1.5 root 438: thisline_changed = 1;
1.1.1.2 root 439: }
440:
1.1.1.14! root 441: static int fetchunits[] = { 8,8,8,0, 16,8,8,0, 32,16,8,0 };
! 442: static int fetchstarts[] = { 3,2,1,0, 4,3,2,0, 5,4,3,0 };
! 443: static int fm_maxplanes[] = { 3,2,1,0, 3,3,2,0, 3,3,3,0 };
! 444:
! 445: static int fetchmode, fetchunit, fetchunit_mask;
! 446: static int fetchstart, fetchstart_shift, fetchstart_mask;
! 447: static int fm_maxplane, fm_maxplane_shift;
! 448:
1.1.1.13 root 449: static int estimated_last_fetch_cycle;
1.1.1.4 root 450:
1.1.1.13 root 451: static void estimate_last_fetch_cycle (int hpos)
1.1.1.2 root 452: {
1.1.1.14! root 453: int fetchunit = fetchunits[fetchmode * 4 + GET_RES (bplcon0)];
! 454:
1.1.1.13 root 455: if (! passed_plfstop) {
456: int stop = plfstop < hpos || plfstop > HARD_DDF_STOP ? HARD_DDF_STOP : plfstop;
457: /* We know that fetching is up-to-date up until hpos, so we can use fetch_cycle. */
458: int fetch_cycle_at_stop = fetch_cycle + (stop - hpos);
1.1.1.14! root 459: int starting_last_block_at = (fetch_cycle_at_stop + fetchunit - 1) & ~(fetchunit - 1);
1.1.1.13 root 460:
1.1.1.14! root 461: estimated_last_fetch_cycle = hpos + (starting_last_block_at - fetch_cycle) + fetchunit;
1.1.1.13 root 462: } else {
1.1.1.14! root 463: int starting_last_block_at = (fetch_cycle + fetchunit - 1) & ~(fetchunit - 1);
1.1.1.13 root 464: if (passed_plfstop == 2)
1.1.1.14! root 465: starting_last_block_at -= fetchunit;
1.1.1.13 root 466:
1.1.1.14! root 467: estimated_last_fetch_cycle = hpos + (starting_last_block_at - fetch_cycle) + fetchunit;
1.1.1.13 root 468: }
1.1.1.4 root 469: }
470:
1.1.1.14! root 471: static uae_u32 outword[MAX_PLANES];
1.1.1.13 root 472: static int out_nbits, out_offs;
1.1.1.14! root 473: static uae_u32 todisplay[MAX_PLANES][4];
! 474: static uae_u32 fetched[MAX_PLANES];
! 475: static uae_u32 fetched_aga0[MAX_PLANES];
! 476: static uae_u32 fetched_aga1[MAX_PLANES];
1.1.1.13 root 477:
478: /* Expansions from bplcon0/bplcon1. */
1.1.1.14! root 479: static int toscr_res, toscr_delay1, toscr_delay2, toscr_nr_planes, fetchwidth;
1.1.1.13 root 480:
1.1.1.14! root 481: /* The number of bits left from the last fetched words.
! 482: This is an optimization - conceptually, we have to make sure the result is
! 483: the same as if toscr is called in each clock cycle. However, to speed this
! 484: up, we accumulate display data; this variable keeps track of how much.
! 485: Thus, once we do call toscr_nbits (which happens at least every 16 bits),
! 486: we can do more work at once. */
1.1.1.13 root 487: static int toscr_nbits;
488:
1.1.1.14! root 489: static int delayoffset;
! 490:
! 491: STATIC_INLINE void compute_delay_offset (int hpos)
1.1.1.4 root 492: {
1.1.1.14! root 493: /* this fixes most horizontal scrolling jerkyness but can't be correct */
! 494: delayoffset = ((hpos - 0x18) & fetchstart_mask) << 1;
! 495: delayoffset &= ~7;
! 496: delayoffset &= 31;
1.1.1.13 root 497: }
1.1.1.9 root 498:
1.1.1.14! root 499: STATIC_INLINE void maybe_first_bpl1dat (int hpos)
1.1.1.13 root 500: {
1.1.1.14! root 501: if (thisline_decision.plfleft == -1) {
! 502: thisline_decision.plfleft = hpos;
! 503: compute_delay_offset (hpos);
! 504: }
1.1.1.13 root 505: }
1.1.1.9 root 506:
1.1.1.14! root 507: STATIC_INLINE void fetch (int nr, int fm)
1.1.1.13 root 508: {
1.1.1.14! root 509: if (nr >= toscr_nr_planes)
! 510: return;
! 511: switch (fm) {
! 512: case 0:
1.1.1.13 root 513: fetched[nr] = chipmem_wget (bplpt[nr]);
514: bplpt[nr] += 2;
1.1.1.14! root 515: break;
! 516: case 1:
! 517: fetched_aga0[nr] = chipmem_lget (bplpt[nr]);
! 518: bplpt[nr] += 4;
! 519: break;
! 520: case 2:
! 521: fetched_aga1[nr] = chipmem_lget (bplpt[nr]);
! 522: fetched_aga0[nr] = chipmem_lget (bplpt[nr] + 4);
! 523: bplpt[nr] += 8;
! 524: break;
1.1.1.4 root 525: }
1.1.1.14! root 526: if (nr == 0)
! 527: fetch_state = fetch_was_plane0;
! 528: }
! 529:
! 530: static void expand_fmodes(void)
! 531: {
! 532: int res = GET_RES(bplcon0);
! 533: int fm = fetchmode;
! 534: fetchunit = fetchunits[fm * 4 + res];
! 535: fetchunit_mask = fetchunit - 1;
! 536: fetchstart_shift = fetchstarts[fm * 4 + res];
! 537: fetchstart = 1 << fetchstart_shift;
! 538: fetchstart_mask = fetchstart - 1;
! 539: fm_maxplane_shift = fm_maxplanes[fm * 4 + res];
! 540: fm_maxplane = 1 << fm_maxplane_shift;
1.1.1.13 root 541: }
542:
543: /* Expand bplcon0/bplcon1 into the toscr_xxx variables. */
1.1.1.14! root 544: static void compute_toscr_delay (int hpos)
1.1.1.13 root 545: {
546: int delay1 = (bplcon1 & 0x0f) | ((bplcon1 & 0x0c00) >> 6);
547: int delay2 = ((bplcon1 >> 4) & 0x0f) | (((bplcon1 >> 4) & 0x0c00) >> 6);
548: int delaymask;
1.1.1.14! root 549: int fetchwidth = 16 << fetchmode;
1.1.1.13 root 550:
551: toscr_res = GET_RES (bplcon0);
1.1.1.14! root 552: delay1 += delayoffset;
! 553: delay2 += delayoffset;
! 554: delaymask = (fetchwidth - 1) >> toscr_res;
1.1.1.13 root 555: toscr_delay1 = (delay1 & delaymask) << toscr_res;
556: toscr_delay2 = (delay2 & delaymask) << toscr_res;
557:
558: toscr_nr_planes = GET_PLANES (bplcon0);
559: }
560:
561: static void clear_fetchbuffer (uae_u32 *ptr, int nwords)
562: {
563: int i;
564:
565: if (! thisline_changed)
566: for (i = 0; i < nwords; i++)
567: if (ptr[i]) {
568: thisline_changed = 1;
569: break;
1.1.1.4 root 570: }
1.1.1.13 root 571:
572: memset (ptr, 0, nwords * 4);
573: }
574:
575: static void update_toscr_planes (void)
576: {
577: if (toscr_nr_planes > thisline_decision.nr_planes) {
578: int j;
579: for (j = thisline_decision.nr_planes; j < toscr_nr_planes; j++)
580: clear_fetchbuffer ((uae_u32 *)(line_data[next_lineno] + 2 * MAX_WORDS_PER_LINE * j), out_offs);
581: #if 0
582: if (thisline_decision.nr_planes > 0)
583: printf ("Planes from %d to %d\n", thisline_decision.nr_planes, toscr_nr_planes);
584: #endif
585: thisline_decision.nr_planes = toscr_nr_planes;
1.1.1.4 root 586: }
587: }
1.1.1.2 root 588:
1.1.1.14! root 589: STATIC_INLINE void toscr_3_ecs (int nbits)
1.1.1.7 root 590: {
1.1.1.13 root 591: int delay1 = toscr_delay1;
592: int delay2 = toscr_delay2;
593: int i;
594: uae_u32 mask = 0xFFFF >> (16 - nbits);
595:
596: for (i = 0; i < toscr_nr_planes; i += 2) {
597: outword[i] <<= nbits;
1.1.1.14! root 598: outword[i] |= (todisplay[i][0] >> (16 - nbits + delay1)) & mask;
! 599: todisplay[i][0] <<= nbits;
1.1.1.13 root 600: }
601: for (i = 1; i < toscr_nr_planes; i += 2) {
602: outword[i] <<= nbits;
1.1.1.14! root 603: outword[i] |= (todisplay[i][0] >> (16 - nbits + delay2)) & mask;
! 604: todisplay[i][0] <<= nbits;
! 605: }
! 606: }
! 607:
! 608: STATIC_INLINE void shift32plus (uae_u32 *p, int n)
! 609: {
! 610: uae_u32 t = p[1];
! 611: t <<= n;
! 612: t |= p[0] >> (32 - n);
! 613: p[1] = t;
! 614: }
! 615:
! 616: STATIC_INLINE void aga_shift (uae_u32 *p, int n, int fm)
! 617: {
! 618: if (fm == 2) {
! 619: shift32plus (p + 2, n);
! 620: shift32plus (p + 1, n);
1.1.1.13 root 621: }
1.1.1.14! root 622: shift32plus (p + 0, n);
! 623: p[0] <<= n;
! 624: }
! 625:
! 626: STATIC_INLINE void toscr_3_aga (int nbits, int fm)
! 627: {
! 628: int delay1 = toscr_delay1;
! 629: int delay2 = toscr_delay2;
! 630: int i;
! 631: uae_u32 mask = 0xFFFF >> (16 - nbits);
! 632:
! 633: {
! 634: int offs = (16 << fm) - nbits + delay1;
! 635: int off1 = offs >> 5;
! 636: if (off1 == 3)
! 637: off1 = 2;
! 638: offs -= off1 * 32;
! 639: for (i = 0; i < toscr_nr_planes; i += 2) {
! 640: uae_u32 t0 = todisplay[i][off1];
! 641: uae_u32 t1 = todisplay[i][off1 + 1];
! 642: uae_u64 t = (((uae_u64)t1) << 32) | t0;
! 643: outword[i] <<= nbits;
! 644: outword[i] |= (t >> offs) & mask;
! 645: aga_shift (todisplay[i], nbits, fm);
! 646: }
! 647: }
! 648: {
! 649: int offs = (16 << fm) - nbits + delay2;
! 650: int off1 = offs >> 5;
! 651: if (off1 == 3)
! 652: off1 = 2;
! 653: offs -= off1 * 32;
! 654: for (i = 1; i < toscr_nr_planes; i += 2) {
! 655: uae_u32 t0 = todisplay[i][off1];
! 656: uae_u32 t1 = todisplay[i][off1 + 1];
! 657: uae_u64 t = (((uae_u64)t1) << 32) | t0;
! 658: outword[i] <<= nbits;
! 659: outword[i] |= (t >> offs) & mask;
! 660: aga_shift (todisplay[i], nbits, fm);
! 661: }
! 662: }
! 663: }
! 664:
! 665: static void toscr_2_0 (int nbits) { toscr_3_ecs (nbits); }
! 666: static void toscr_2_1 (int nbits) { toscr_3_aga (nbits, 1); }
! 667: static void toscr_2_2 (int nbits) { toscr_3_aga (nbits, 2); }
! 668:
! 669: STATIC_INLINE void toscr_1 (int nbits, int fm)
! 670: {
! 671: switch (fm) {
! 672: case 0:
! 673: toscr_2_0 (nbits);
! 674: break;
! 675: case 1:
! 676: toscr_2_1 (nbits);
! 677: break;
! 678: case 2:
! 679: toscr_2_2 (nbits);
! 680: break;
! 681: }
! 682:
1.1.1.13 root 683: out_nbits += nbits;
684: if (out_nbits == 32) {
1.1.1.14! root 685: int i;
1.1.1.13 root 686: uae_u8 *dataptr = line_data[next_lineno] + out_offs * 4;
687: /* Don't use toscr_nr_planes here; if the plane count drops during the
688: line we still want the data to be correct for the full number of planes
689: over the full width of the line. */
690: for (i = 0; i < thisline_decision.nr_planes; i++) {
691: uae_u32 *dataptr32 = (uae_u32 *)dataptr;
692: if (*dataptr32 != outword[i])
693: thisline_changed = 1;
694: *dataptr32 = outword[i];
695: dataptr += MAX_WORDS_PER_LINE * 2;
696: }
697: out_offs++;
698: out_nbits = 0;
699: }
1.1.1.7 root 700: }
701:
1.1.1.14! root 702: static void toscr_fm0 (int);
! 703: static void toscr_fm1 (int);
! 704: static void toscr_fm2 (int);
! 705:
! 706: STATIC_INLINE void toscr (int nbits, int fm)
! 707: {
! 708: switch (fm) {
! 709: case 0: toscr_fm0 (nbits); break;
! 710: case 1: toscr_fm1 (nbits); break;
! 711: case 2: toscr_fm2 (nbits); break;
! 712: }
! 713: }
! 714:
! 715: STATIC_INLINE void toscr_0 (int nbits, int fm)
1.1.1.4 root 716: {
1.1.1.13 root 717: int t;
1.1.1.14! root 718:
1.1.1.13 root 719: if (nbits > 16) {
1.1.1.14! root 720: toscr (16, fm);
1.1.1.13 root 721: nbits -= 16;
1.1.1.2 root 722: }
1.1.1.3 root 723:
1.1.1.13 root 724: t = 32 - out_nbits;
725: if (t < nbits) {
1.1.1.14! root 726: toscr_1 (t, fm);
1.1.1.13 root 727: nbits -= t;
728: }
1.1.1.14! root 729: toscr_1 (nbits, fm);
1.1.1.13 root 730: }
1.1.1.14! root 731:
! 732: static void toscr_fm0 (int nbits) { toscr_0 (nbits, 0); }
! 733: static void toscr_fm1 (int nbits) { toscr_0 (nbits, 1); }
! 734: static void toscr_fm2 (int nbits) { toscr_0 (nbits, 2); }
! 735:
! 736: static int flush_plane_data (int fm)
1.1.1.13 root 737: {
738: int i = 0;
1.1.1.14! root 739: int fetchwidth = 16 << fm;
1.1.1.4 root 740:
1.1.1.13 root 741: if (out_nbits <= 16) {
742: i += 16;
1.1.1.14! root 743: toscr_1 (16, fm);
1.1.1.13 root 744: }
745: if (out_nbits != 0) {
746: i += 32 - out_nbits;
1.1.1.14! root 747: toscr_1 (32 - out_nbits, fm);
1.1.1.4 root 748: }
1.1.1.13 root 749: i += 32;
1.1.1.10 root 750:
1.1.1.14! root 751: toscr_1 (16, fm);
! 752: toscr_1 (16, fm);
1.1.1.13 root 753: return i >> (1 + toscr_res);
754: }
755:
1.1.1.14! root 756: STATIC_INLINE void flush_display (int fm)
! 757: {
! 758: if (toscr_nbits > 0 && thisline_decision.plfleft != -1)
! 759: toscr (toscr_nbits, fm);
! 760: toscr_nbits = 0;
! 761: }
! 762:
! 763: /* Called when all planes have been fetched, i.e. when a new block
! 764: of data is available to be displayed. The data in fetched[] is
! 765: moved into todisplay[]. */
! 766: STATIC_INLINE void beginning_of_plane_block (int pos, int dma, int fm)
! 767: {
! 768: int i;
! 769:
! 770: flush_display (fm);
! 771:
! 772: if (fm == 0)
! 773: for (i = 0; i < MAX_PLANES; i++)
! 774: todisplay[i][0] |= fetched[i];
! 775: else
! 776: for (i = 0; i < MAX_PLANES; i++) {
! 777: if (fm == 2)
! 778: todisplay[i][1] = fetched_aga1[i];
! 779: todisplay[i][0] = fetched_aga0[i];
! 780: }
! 781:
! 782: maybe_first_bpl1dat (pos);
! 783: }
! 784:
! 785: #define SPEEDUP
! 786:
! 787: #ifdef SPEEDUP
! 788:
1.1.1.13 root 789: /* The usual inlining tricks - don't touch unless you know what you are doing. */
1.1.1.14! root 790: STATIC_INLINE void long_fetch_ecs (int plane, int nwords, int weird_number_of_bits, int dma)
1.1.1.13 root 791: {
792: uae_u16 *real_pt = (uae_u16 *)pfield_xlateptr (bplpt[plane], nwords * 2);
1.1.1.14! root 793: int delay = ((plane & 1) ? toscr_delay2 : toscr_delay1);
1.1.1.13 root 794: int tmp_nbits = out_nbits;
1.1.1.14! root 795: uae_u32 shiftbuffer = todisplay[plane][0];
1.1.1.13 root 796: uae_u32 outval = outword[plane];
797: uae_u32 fetchval = fetched[plane];
798: uae_u32 *dataptr = (uae_u32 *)(line_data[next_lineno] + 2 * plane * MAX_WORDS_PER_LINE + 4 * out_offs);
799:
1.1.1.14! root 800: if (dma)
! 801: bplpt[plane] += nwords * 2;
1.1.1.13 root 802:
803: if (real_pt == 0)
804: /* @@@ Don't do this, fall back on chipmem_wget instead. */
1.1.1.4 root 805: return;
806:
1.1.1.13 root 807: while (nwords > 0) {
808: int bits_left = 32 - tmp_nbits;
1.1.1.14! root 809: uae_u32 t;
1.1.1.13 root 810:
811: shiftbuffer |= fetchval;
812:
1.1.1.14! root 813: t = (shiftbuffer >> delay) & 0xFFFF;
! 814:
1.1.1.13 root 815: if (weird_number_of_bits && bits_left < 16) {
816: outval <<= bits_left;
1.1.1.14! root 817: outval |= t >> (16 - bits_left);
1.1.1.13 root 818: thisline_changed |= *dataptr ^ outval;
819: *dataptr++ = outval;
820:
1.1.1.14! root 821: outval = t;
1.1.1.13 root 822: tmp_nbits = 16 - bits_left;
1.1.1.14! root 823: shiftbuffer <<= 16;
1.1.1.13 root 824: } else {
1.1.1.14! root 825: outval = (outval << 16) | t;
1.1.1.13 root 826: shiftbuffer <<= 16;
827: tmp_nbits += 16;
828: if (tmp_nbits == 32) {
829: thisline_changed |= *dataptr ^ outval;
830: *dataptr++ = outval;
831: tmp_nbits = 0;
832: }
833: }
834: nwords--;
1.1.1.14! root 835: if (dma) {
! 836: fetchval = do_get_mem_word (real_pt);
! 837: real_pt++;
! 838: }
1.1.1.13 root 839: }
840: fetched[plane] = fetchval;
1.1.1.14! root 841: todisplay[plane][0] = shiftbuffer;
1.1.1.13 root 842: outword[plane] = outval;
1.1.1.2 root 843: }
844:
1.1.1.14! root 845: STATIC_INLINE void long_fetch_aga (int plane, int nwords, int weird_number_of_bits, int fm, int dma)
! 846: {
! 847: uae_u32 *real_pt = (uae_u32 *)pfield_xlateptr (bplpt[plane], nwords * 2);
! 848: int delay = ((plane & 1) ? toscr_delay2 : toscr_delay1);
! 849: int tmp_nbits = out_nbits;
! 850: uae_u32 *shiftbuffer = todisplay[plane];
! 851: uae_u32 outval = outword[plane];
! 852: uae_u32 fetchval0 = fetched_aga0[plane];
! 853: uae_u32 fetchval1 = fetched_aga1[plane];
! 854: uae_u32 *dataptr = (uae_u32 *)(line_data[next_lineno] + 2 * plane * MAX_WORDS_PER_LINE + 4 * out_offs);
! 855: int offs = (16 << fm) - 16 + delay;
! 856: int off1 = offs >> 5;
! 857: if (off1 == 3)
! 858: off1 = 2;
! 859: offs -= off1 * 32;
! 860:
! 861: if (dma)
! 862: bplpt[plane] += nwords * 2;
! 863:
! 864: if (real_pt == 0)
! 865: /* @@@ Don't do this, fall back on chipmem_wget instead. */
! 866: return;
! 867:
! 868: while (nwords > 0) {
! 869: int i;
! 870:
! 871: shiftbuffer[0] = fetchval0;
! 872: if (fm == 2)
! 873: shiftbuffer[1] = fetchval1;
! 874:
! 875: for (i = 0; i < (1 << fm); i++) {
! 876: int bits_left = 32 - tmp_nbits;
1.1.1.13 root 877:
1.1.1.14! root 878: uae_u32 t0 = shiftbuffer[off1];
! 879: uae_u32 t1 = shiftbuffer[off1 + 1];
! 880: uae_u64 t = (((uae_u64)t1) << 32) | t0;
! 881:
! 882: t0 = (t >> offs) & 0xFFFF;
! 883:
! 884: if (weird_number_of_bits && bits_left < 16) {
! 885: outval <<= bits_left;
! 886: outval |= t0 >> (16 - bits_left);
! 887:
! 888: thisline_changed |= *dataptr ^ outval;
! 889: *dataptr++ = outval;
! 890:
! 891: outval = t0;
! 892: tmp_nbits = 16 - bits_left;
! 893: aga_shift (shiftbuffer, 16, fm);
! 894: } else {
! 895: outval = (outval << 16) | t0;
! 896: aga_shift (shiftbuffer, 16, fm);
! 897: tmp_nbits += 16;
! 898: if (tmp_nbits == 32) {
! 899: thisline_changed |= *dataptr ^ outval;
! 900: *dataptr++ = outval;
! 901: tmp_nbits = 0;
! 902: }
! 903: }
! 904: }
! 905:
! 906: nwords -= 1 << fm;
! 907:
! 908: if (dma) {
! 909: if (fm == 1)
! 910: fetchval0 = do_get_mem_long (real_pt);
! 911: else {
! 912: fetchval1 = do_get_mem_long (real_pt);
! 913: fetchval0 = do_get_mem_long (real_pt + 1);
! 914: }
! 915: real_pt += fm;
! 916: }
! 917: }
! 918: fetched_aga0[plane] = fetchval0;
! 919: fetched_aga1[plane] = fetchval1;
! 920: outword[plane] = outval;
! 921: }
! 922:
! 923: static void long_fetch_ecs_0 (int hpos, int nwords, int dma) { long_fetch_ecs (hpos, nwords, 0, dma); }
! 924: static void long_fetch_ecs_1 (int hpos, int nwords, int dma) { long_fetch_ecs (hpos, nwords, 1, dma); }
! 925: static void long_fetch_aga_1_0 (int hpos, int nwords, int dma) { long_fetch_aga (hpos, nwords, 0, 1, dma); }
! 926: static void long_fetch_aga_1_1 (int hpos, int nwords, int dma) { long_fetch_aga (hpos, nwords, 1, 1, dma); }
! 927: static void long_fetch_aga_2_0 (int hpos, int nwords, int dma) { long_fetch_aga (hpos, nwords, 0, 2, dma); }
! 928: static void long_fetch_aga_2_1 (int hpos, int nwords, int dma) { long_fetch_aga (hpos, nwords, 1, 2, dma); }
! 929:
! 930: static void do_long_fetch (int hpos, int nwords, int dma, int fm)
1.1.1.2 root 931: {
1.1.1.14! root 932: int added;
1.1.1.13 root 933: int i;
1.1.1.2 root 934:
1.1.1.14! root 935: flush_display (fm);
! 936: switch (fm) {
! 937: case 0:
! 938: if (out_nbits & 15) {
! 939: for (i = 0; i < toscr_nr_planes; i++)
! 940: long_fetch_ecs_1 (i, nwords, dma);
! 941: } else {
! 942: for (i = 0; i < toscr_nr_planes; i++)
! 943: long_fetch_ecs_0 (i, nwords, dma);
! 944: }
! 945: break;
! 946: case 1:
! 947: if (out_nbits & 15) {
! 948: for (i = 0; i < toscr_nr_planes; i++)
! 949: long_fetch_aga_1_1 (i, nwords, dma);
! 950: } else {
! 951: for (i = 0; i < toscr_nr_planes; i++)
! 952: long_fetch_aga_1_0 (i, nwords, dma);
! 953: }
! 954: break;
! 955: case 2:
! 956: if (out_nbits & 15) {
! 957: for (i = 0; i < toscr_nr_planes; i++)
! 958: long_fetch_aga_2_1 (i, nwords, dma);
! 959: } else {
! 960: for (i = 0; i < toscr_nr_planes; i++)
! 961: long_fetch_aga_2_0 (i, nwords, dma);
! 962: }
! 963: break;
1.1.1.2 root 964: }
1.1.1.13 root 965:
1.1.1.14! root 966: out_nbits += nwords * 16;
1.1.1.13 root 967: out_offs += out_nbits >> 5;
968: out_nbits &= 31;
1.1.1.14! root 969:
! 970: if (dma && toscr_nr_planes > 0)
! 971: fetch_state = fetch_was_plane0;
1.1.1.13 root 972: }
973:
1.1.1.14! root 974: #endif
1.1.1.13 root 975:
1.1.1.14! root 976: /* make sure fetch that goes beyond maxhpos is finished */
! 977: static void finish_final_fetch (int i, int fm)
! 978: {
! 979: passed_plfstop = 3;
! 980: i += flush_plane_data (fm);
! 981: thisline_decision.plfright = i;
! 982: thisline_decision.plflinelen = out_offs;
! 983: thisline_decision.bplres = toscr_res;
! 984: finish_playfield_line ();
! 985: }
! 986:
! 987: STATIC_INLINE int one_fetch_cycle_0 (int i, int ddfstop_to_test, int dma, int fm)
1.1.1.13 root 988: {
989: if (! passed_plfstop && i == ddfstop_to_test)
990: passed_plfstop = 1;
991:
1.1.1.14! root 992: if ((fetch_cycle & fetchunit_mask) == 0) {
1.1.1.13 root 993: if (passed_plfstop == 2) {
1.1.1.14! root 994: finish_final_fetch (i, fm);
1.1.1.13 root 995: return 1;
996: }
997: if (passed_plfstop)
998: passed_plfstop++;
1.1.1.2 root 999: }
1.1.1.13 root 1000: if (dma) {
1.1.1.14! root 1001: /* fetchstart_mask can be larger than fm_maxplane if FMODE > 0. This means
! 1002: that the remaining cycles are idle; we'll fall through the whole switch
! 1003: without doing anything. */
! 1004: int cycle_start = fetch_cycle & fetchstart_mask;
! 1005: switch (fm_maxplane) {
! 1006: case 8:
! 1007: switch (cycle_start) {
! 1008: case 0: fetch (7, fm); break;
! 1009: case 1: fetch (3, fm); break;
! 1010: case 2: fetch (5, fm); break;
! 1011: case 3: fetch (1, fm); break;
! 1012: case 4: fetch (6, fm); break;
! 1013: case 5: fetch (2, fm); break;
! 1014: case 6: fetch (4, fm); break;
! 1015: case 7: fetch (0, fm); break;
! 1016: }
! 1017: break;
! 1018: case 4:
! 1019: switch (cycle_start) {
! 1020: case 0: fetch (3, fm); break;
! 1021: case 1: fetch (1, fm); break;
! 1022: case 2: fetch (2, fm); break;
! 1023: case 3: fetch (0, fm); break;
! 1024: }
! 1025: break;
! 1026: case 2:
! 1027: switch (cycle_start) {
! 1028: case 0: fetch (1, fm); break;
! 1029: case 1: fetch (0, fm); break;
! 1030: }
! 1031: break;
1.1.1.13 root 1032: }
1.1.1.2 root 1033: }
1.1.1.13 root 1034: fetch_cycle++;
1035: toscr_nbits += 2 << toscr_res;
1036: return 0;
1037: }
1.1.1.3 root 1038:
1.1.1.14! root 1039: 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); }
! 1040: 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); }
! 1041: 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 1042:
1.1.1.14! root 1043: STATIC_INLINE int one_fetch_cycle (int i, int ddfstop_to_test, int dma, int fm)
! 1044: {
! 1045: switch (fm) {
! 1046: case 0: return one_fetch_cycle_fm0 (i, ddfstop_to_test, dma);
! 1047: case 1: return one_fetch_cycle_fm1 (i, ddfstop_to_test, dma);
! 1048: case 2: return one_fetch_cycle_fm2 (i, ddfstop_to_test, dma);
! 1049: default: abort ();
! 1050: }
1.1.1.13 root 1051: }
1052:
1.1.1.14! root 1053: STATIC_INLINE void update_fetch (int until, int fm)
1.1.1.13 root 1054: {
1055: int pos;
1056: int dma = dmaen (DMA_BITPLANE);
1057:
1058: int ddfstop_to_test;
1059:
1060: if (framecnt != 0 || passed_plfstop == 3)
1.1.1.2 root 1061: return;
1.1.1.13 root 1062:
1063: /* We need an explicit test against HARD_DDF_STOP here to guard against
1064: programs that move the DDFSTOP before our current position before we
1065: reach it. */
1066: ddfstop_to_test = HARD_DDF_STOP;
1067: if (ddfstop >= last_fetch_hpos && ddfstop < HARD_DDF_STOP)
1068: ddfstop_to_test = ddfstop;
1069:
1.1.1.14! root 1070: compute_toscr_delay (last_fetch_hpos);
1.1.1.13 root 1071: update_toscr_planes ();
1072:
1073: pos = last_fetch_hpos;
1074:
1.1.1.14! root 1075: /* First, a loop that prepares us for the speedup code. We want to enter
! 1076: the SPEEDUP case with fetch_state == fetch_was_plane0, and then unroll
! 1077: whole blocks, so that we end on the same fetch_state again. */
1.1.1.13 root 1078: for (; ; pos++) {
1.1.1.14! root 1079: if (pos == until) {
! 1080: if (until >= maxhpos && passed_plfstop == 2) {
! 1081: finish_final_fetch (pos, fm);
! 1082: return;
! 1083: }
! 1084: flush_display (fm);
! 1085: return;
! 1086: }
1.1.1.13 root 1087:
1.1.1.14! root 1088: if (fetch_state == fetch_was_plane0)
1.1.1.13 root 1089: break;
1090:
1091: fetch_state = fetch_started;
1.1.1.14! root 1092: if (one_fetch_cycle (pos, ddfstop_to_test, dma, fm))
1.1.1.13 root 1093: return;
1.1.1.2 root 1094:
1.1.1.14! root 1095: if (toscr_nbits == 16)
! 1096: flush_display (fm);
! 1097: if (toscr_nbits > 16)
! 1098: abort ();
! 1099: }
1.1.1.13 root 1100:
1101: #ifdef SPEEDUP
1102: /* Unrolled version of the for loop below. */
1.1.1.14! root 1103: if (! passed_plfstop
! 1104: && dma
! 1105: && (pos & fetchstart_mask) == (fm_maxplane & fetchstart_mask)
! 1106: # if 0
! 1107: /* @@@ We handle this case, but the code would be simpler if we
! 1108: * disallowed it - it may even be possible to guarantee that
! 1109: * this condition never is false. Later. */
! 1110: && (out_nbits & 15) == 0
! 1111: # endif
! 1112: && toscr_nr_planes == thisline_decision.nr_planes)
! 1113: {
! 1114: int offs = (pos - fetch_cycle) & 7;
! 1115: int ddf2 = ((ddfstop_to_test - offs + fetchunit - 1) & ~fetchunit_mask) + offs;
! 1116: int ddf3 = ddf2 + fetchunit;
! 1117: int stop = until < ddf2 ? until : until < ddf3 ? ddf2 : ddf3;
! 1118: int count;
! 1119:
! 1120: count = stop - pos;
! 1121:
! 1122: if (count >= fetchstart) {
! 1123: count &= ~fetchstart_mask;
! 1124:
! 1125: if (thisline_decision.plfleft == -1)
! 1126: compute_delay_offset (pos);
! 1127:
! 1128: do_long_fetch (pos, count >> (3 - toscr_res), dma, fm);
! 1129:
! 1130: /* This must come _after_ do_long_fetch so as not to confuse flush_display
! 1131: into thinking the first fetch has produced any output worth emitting to
! 1132: the screen. But the calculation of delay_offset must happen _before_. */
! 1133: maybe_first_bpl1dat (pos);
1.1.1.13 root 1134:
1135: if (pos <= ddfstop_to_test && pos + count > ddfstop_to_test)
1136: passed_plfstop = 1;
1.1.1.14! root 1137: if (pos <= ddfstop_to_test && pos + count > ddf2)
! 1138: passed_plfstop = 2;
1.1.1.13 root 1139: pos += count;
1140: fetch_cycle += count;
1141: }
1.1.1.2 root 1142: }
1143: #endif
1.1.1.13 root 1144: for (; pos < until; pos++) {
1145: if (fetch_state == fetch_was_plane0)
1.1.1.14! root 1146: beginning_of_plane_block (pos, dma, fm);
1.1.1.13 root 1147: fetch_state = fetch_started;
1148:
1.1.1.14! root 1149: if (one_fetch_cycle (pos, ddfstop_to_test, dma, fm))
1.1.1.13 root 1150: return;
1151:
1.1.1.14! root 1152: if (toscr_nbits == 16)
! 1153: flush_display (fm);
! 1154: if (toscr_nbits > 16)
! 1155: abort ();
1.1.1.13 root 1156: }
1.1.1.14! root 1157: if (until >= maxhpos && passed_plfstop == 2) {
! 1158: finish_final_fetch (pos, fm);
! 1159: return;
! 1160: }
! 1161: flush_display (fm);
1.1.1.2 root 1162: }
1163:
1.1.1.14! root 1164: static void update_fetch_0 (int hpos) { update_fetch (hpos, 0); }
! 1165: static void update_fetch_1 (int hpos) { update_fetch (hpos, 1); }
! 1166: static void update_fetch_2 (int hpos) { update_fetch (hpos, 2); }
! 1167:
1.1.1.13 root 1168: STATIC_INLINE void decide_fetch (int hpos)
1169: {
1.1.1.14! root 1170: if (fetch_state != fetch_not_started && hpos > last_fetch_hpos) {
! 1171: switch (fetchmode) {
! 1172: case 0: update_fetch_0 (hpos); break;
! 1173: case 1: update_fetch_1 (hpos); break;
! 1174: case 2: update_fetch_2 (hpos); break;
! 1175: default: abort ();
! 1176: }
! 1177: }
1.1.1.13 root 1178: last_fetch_hpos = hpos;
1179: }
1180:
1181: /* This function is responsible for turning on datafetch if necessary. */
1.1.1.8 root 1182: STATIC_INLINE void decide_line (int hpos)
1.1.1.2 root 1183: {
1.1.1.13 root 1184: if (fetch_state != fetch_not_started)
1185: return;
1186:
1187: /* Test if we passed the start of the DDF window. */
1188: if (last_decide_line_hpos < plfstrt && hpos >= plfstrt) {
1189: /* First, take care of the vertical DIW. Surprisingly enough, this seems to be
1190: correct here - putting this into decide_diw() results in garbage. */
1191: if (diwstate == DIW_waiting_start && vpos == plffirstline) {
1192: diwstate = DIW_waiting_stop;
1193: }
1194: if (diwstate == DIW_waiting_stop && vpos == plflastline) {
1195: diwstate = DIW_waiting_start;
1196: }
1197:
1198: if (diwstate == DIW_waiting_stop) {
1199: fetch_state = fetch_started;
1200: fetch_cycle = 0;
1201: last_fetch_hpos = plfstrt;
1202: out_nbits = 0;
1203: out_offs = 0;
1204: toscr_nbits = 0;
1205:
1.1.1.14! root 1206: compute_toscr_delay (last_fetch_hpos);
1.1.1.13 root 1207:
1208: /* If someone already wrote BPL1DAT, clear the area between that point and
1209: the real fetch start. */
1.1.1.14! root 1210: if (framecnt == 0) {
! 1211: if (thisline_decision.plfleft != -1) {
! 1212: out_nbits = (plfstrt - thisline_decision.plfleft) << (1 + toscr_res);
! 1213: out_offs = out_nbits >> 5;
! 1214: out_nbits &= 31;
! 1215: }
! 1216: update_toscr_planes ();
1.1.1.13 root 1217: }
1218: estimate_last_fetch_cycle (plfstrt);
1219: last_decide_line_hpos = hpos;
1220: do_sprites (vpos, plfstrt);
1221: return;
1222: }
1223: }
1224:
1225: if (last_decide_line_hpos < 0x34)
1226: do_sprites (vpos, hpos);
1227:
1228: last_decide_line_hpos = hpos;
1.1.1.2 root 1229: }
1230:
1.1.1.3 root 1231: /* Called when a color is about to be changed (write to a color register),
1232: * but the new color has not been entered into the table yet. */
1.1.1.4 root 1233: static void record_color_change (int hpos, int regno, unsigned long value)
1.1.1.3 root 1234: {
1235: /* Early positions don't appear on-screen. */
1.1.1.4 root 1236: if (framecnt != 0 || vpos < minfirstline || hpos < 0x18
1.1.1.3 root 1237: /*|| currprefs.emul_accuracy == 0*/)
1238: return;
1239:
1.1.1.4 root 1240: decide_diw (hpos);
1241: decide_line (hpos);
1.1.1.3 root 1242:
1.1.1.13 root 1243: if (thisline_decision.ctable == -1)
1244: remember_ctable ();
1.1.1.3 root 1245:
1246: #ifdef OS_WITHOUT_MEMORY_MANAGEMENT
1.1.1.4 root 1247: if (next_color_change >= max_color_change) {
1.1.1.3 root 1248: ++delta_color_change;
1249: return;
1250: }
1251: #endif
1.1.1.4 root 1252: curr_color_changes[next_color_change].linepos = hpos;
1.1.1.3 root 1253: curr_color_changes[next_color_change].regno = regno;
1254: curr_color_changes[next_color_change++].value = value;
1255: }
1256:
1.1.1.13 root 1257: /* Sprite-to-sprite collisions are taken care of in record_sprite. This one does
1258: playfield/sprite collisions.
1259: That's the theory. In practice this doesn't work yet. I also suspect this code
1260: is way too slow. */
1261: static void do_sprite_collisions (void)
1.1.1.2 root 1262: {
1.1.1.13 root 1263: int nr_sprites = curr_drawinfo[next_lineno].nr_sprites;
1264: int first = curr_drawinfo[next_lineno].first_sprite_entry;
1265: int i;
1266: unsigned int collision_mask = clxmask[clxcon >> 12];
1267: int plf_first_pixel = thisline_decision.plfleft * 2 + DIW_DDF_OFFSET;
1.1.1.2 root 1268:
1.1.1.13 root 1269: for (i = 0; i < nr_sprites; i++) {
1270: struct sprite_entry *e = curr_sprite_entries + first + i;
1271: int j;
1272: int minpos = e->pos;
1273: int maxpos = e->max;
1274:
1275: if (maxpos > thisline_decision.diwlastword)
1276: maxpos = thisline_decision.diwlastword;
1277: if (maxpos > thisline_decision.plfright * 2 + DIW_DDF_OFFSET)
1278: maxpos = thisline_decision.plfright * 2 + DIW_DDF_OFFSET;
1279: if (minpos < thisline_decision.diwfirstword)
1280: minpos = thisline_decision.diwfirstword;
1281: if (minpos < plf_first_pixel)
1282: minpos = plf_first_pixel;
1283:
1284: for (j = minpos; j < maxpos; j++) {
1285: int sprpix = spixels[e->first_pixel + j - e->pos] & collision_mask;
1286: int k;
1.1.1.2 root 1287:
1.1.1.13 root 1288: if (sprpix == 0)
1289: continue;
1.1.1.2 root 1290:
1.1.1.13 root 1291: sprpix = sprite_ab_merge[sprpix & 255] | (sprite_ab_merge[sprpix >> 8] << 2);
1292: sprpix <<= 1;
1.1.1.2 root 1293:
1.1.1.13 root 1294: /* Loop over number of playfields. */
1295: for (k = 0; k < 2; k++) {
1296: int l;
1297: int match = 1;
1.1.1.14! root 1298: int planes = ((currprefs.chipset_mask & CSMASK_AGA) ? 8 : 6);
1.1.1.13 root 1299:
1.1.1.14! root 1300: for (l = k; match && l < planes; l += 2)
! 1301: if (clxcon_bpl_enable & (1 << l)) {
1.1.1.13 root 1302: int t = 0;
1303: if (l < thisline_decision.nr_planes) {
1304: int offs = j - plf_first_pixel;
1305: uae_u32 *ldata = (uae_u32 *)(line_data[next_lineno] + 2 * l * MAX_WORDS_PER_LINE);
1306: uae_u32 word = ldata[offs >> 5];
1307: t = (word >> (31 - (offs & 31))) & 1;
1308: }
1.1.1.14! root 1309: if (t != ((clxcon_bpl_match >> l) & 1))
1.1.1.13 root 1310: match = 0;
1311: }
1312: if (match)
1313: clxdat |= sprpix;
1314: sprpix <<= 4;
1315: }
1.1.1.2 root 1316: }
1317: }
1318: }
1319:
1.1.1.13 root 1320: /* DATAB contains the sprite data; 16 pixels in two-bit packets. Bits 0/1
1321: determine the color of the leftmost pixel, bits 2/3 the color of the next
1322: etc.
1323: This function assumes that for all sprites in a given line, SPRXP either
1324: stays equal or increases between successive calls. */
1325: static void record_sprite (int line, int num, int sprxp, uae_u32 datab, unsigned int ctl)
1.1.1.2 root 1326: {
1.1.1.13 root 1327: struct sprite_entry *e = curr_sprite_entries + next_sprite_entry;
1328: int i;
1329: int word_offs;
1330: uae_u16 *buf;
1331: uae_u32 collision_mask;
1332: int collision_enabled;
1333:
1334: if (currprefs.gfx_lores == 0)
1335: sprxp >>= 1;
1336:
1337: /* Try to coalesce entries if they aren't too far apart. */
1338: if (! next_sprite_forced && e[-1].max + 16 >= sprxp)
1339: e--;
1340: else {
1341: next_sprite_entry++;
1342: e->pos = sprxp;
1343: e->has_attached = 0;
1344: }
1345: if (sprxp < e->pos)
1346: abort ();
1347: e->max = sprxp + 16;
1348: e[1].first_pixel = e->first_pixel + ((e->max - e->pos + 3) & ~3);
1349: next_sprite_forced = 0;
1350:
1351: collision_mask = clxmask[clxcon >> 12];
1352: word_offs = e->first_pixel + sprxp - e->pos;
1353: buf = spixels + word_offs;
1354: while (datab) {
1355: unsigned int tmp = *buf;
1356: unsigned int col = (datab & 3) << (2 * num);
1357: tmp |= col;
1358: *buf++ = tmp;
1359: datab >>= 2;
1360: tmp &= collision_mask;
1361: if (tmp) {
1362: unsigned int shrunk_tmp = sprite_ab_merge[tmp & 255] | (sprite_ab_merge[tmp >> 8] << 2);
1363: clxdat |= sprclx[shrunk_tmp];
1.1.1.2 root 1364: }
1365: }
1366:
1.1.1.13 root 1367: /* We have 8 bits per pixel in spixstate, two for every sprite pair. The
1368: low order bit records whether the attach bit was set for this pair. */
1369:
1370: if (ctl & (num << 7) & 0x80) {
1371: uae_u32 state = 0x01010101 << (num - 1);
1372: uae_u32 *stbuf = spixstate.words + (word_offs >> 2);
1373: uae_u8 *stb1 = spixstate.bytes + word_offs;
1374: stb1[0] |= state;
1375: stb1[1] |= state;
1376: stb1[2] |= state;
1377: stb1[3] |= state;
1378: stb1[4] |= state;
1379: stb1[5] |= state;
1380: stb1[6] |= state;
1381: stb1[7] |= state;
1382: stb1[8] |= state;
1383: stb1[9] |= state;
1384: stb1[10] |= state;
1385: stb1[11] |= state;
1386: stb1[12] |= state;
1387: stb1[13] |= state;
1388: stb1[14] |= state;
1389: stb1[15] |= state;
1390: e->has_attached = 1;
1.1.1.3 root 1391: }
1392: }
1.1.1.2 root 1393:
1.1.1.4 root 1394: static void decide_sprites (int hpos)
1.1.1.3 root 1395: {
1.1.1.7 root 1396: int nrs[MAX_SPRITES], posns[MAX_SPRITES];
1397: int count, i;
1.1.1.13 root 1398: int point = coord_hw_to_window_x (hpos * 2);
1.1.1.14! root 1399: int width = 16 << lores_shift;
1.1.1.2 root 1400:
1.1.1.4 root 1401: if (framecnt != 0 || hpos < 0x14 || nr_armed == 0 || point == last_sprite_point)
1.1.1.2 root 1402: return;
1403:
1.1.1.4 root 1404: decide_diw (hpos);
1405: decide_line (hpos);
1.1.1.3 root 1406:
1.1.1.13 root 1407: #if 0
1408: /* This tries to detect whether the line is border, but that doesn't work, it's too early. */
1409: if (thisline_decision.plfleft == -1)
1.1.1.2 root 1410: return;
1.1.1.13 root 1411: #endif
1.1.1.3 root 1412: count = 0;
1413: for (i = 0; i < 8; i++) {
1.1.1.10 root 1414: int sprxp = spr[i].xpos;
1.1.1.3 root 1415: int j, bestp;
1.1.1.2 root 1416:
1.1.1.13 root 1417: if (! spr[i].armed || sprxp < 0 || sprxp <= last_sprite_point || sprxp > point)
1.1.1.3 root 1418: continue;
1.1.1.14! root 1419: if ((thisline_decision.diwfirstword >= 0 && sprxp + width < thisline_decision.diwfirstword)
1.1.1.3 root 1420: || (thisline_decision.diwlastword >= 0 && sprxp > thisline_decision.diwlastword))
1421: continue;
1.1.1.2 root 1422:
1.1.1.13 root 1423: /* Sort the sprites in order of ascending X position before recording them. */
1.1.1.3 root 1424: for (bestp = 0; bestp < count; bestp++) {
1425: if (posns[bestp] > sprxp)
1426: break;
1427: if (posns[bestp] == sprxp && nrs[bestp] < i)
1428: break;
1429: }
1430: for (j = count; j > bestp; j--) {
1431: posns[j] = posns[j-1];
1432: nrs[j] = nrs[j-1];
1433: }
1434: posns[j] = sprxp;
1435: nrs[j] = i;
1436: count++;
1437: }
1.1.1.13 root 1438: for (i = 0; i < count; i++) {
1439: int nr = nrs[i];
1440: unsigned int data = sprdata[nr];
1441: unsigned int datb = sprdatb[nr];
1442: uae_u32 datab = ((sprtaba[data & 0xFF] << 16) | sprtaba[data >> 8]
1443: | (sprtabb[datb & 0xFF] << 16) | sprtabb[datb >> 8]);
1444: record_sprite (next_lineno, nr, spr[nr].xpos, datab, sprctl[nr]);
1445: }
1.1.1.3 root 1446: last_sprite_point = point;
1.1.1.2 root 1447: }
1448:
1.1.1.13 root 1449: STATIC_INLINE int sprites_differ (struct draw_info *dip, struct draw_info *dip_old)
1450: {
1451: struct sprite_entry *this_first = curr_sprite_entries + dip->first_sprite_entry;
1452: struct sprite_entry *this_last = curr_sprite_entries + dip->last_sprite_entry;
1453: struct sprite_entry *prev_first = prev_sprite_entries + dip_old->first_sprite_entry;
1454: int npixels;
1455: int i;
1456:
1457: if (dip->nr_sprites != dip_old->nr_sprites)
1458: return 1;
1459:
1460: if (dip->nr_sprites == 0)
1461: return 0;
1462:
1463: for (i = 0; i < dip->nr_sprites; i++)
1464: if (this_first[i].pos != prev_first[i].pos
1465: || this_first[i].max != prev_first[i].max
1466: || this_first[i].has_attached != prev_first[i].has_attached)
1467: return 1;
1468:
1469: npixels = this_last->first_pixel + (this_last->max - this_last->pos) - this_first->first_pixel;
1470: if (memcmp (spixels + this_first->first_pixel, spixels + prev_first->first_pixel,
1471: npixels * sizeof (uae_u16)) != 0)
1472: return 1;
1473: if (memcmp (spixstate.bytes + this_first->first_pixel, spixstate.bytes + prev_first->first_pixel, npixels) != 0)
1474: return 1;
1475: return 0;
1476: }
1477:
1478: STATIC_INLINE int color_changes_differ (struct draw_info *dip, struct draw_info *dip_old)
1479: {
1480: if (dip->nr_color_changes != dip_old->nr_color_changes)
1481: return 1;
1482:
1483: if (dip->nr_color_changes == 0)
1484: return 0;
1485: if (memcmp (curr_color_changes + dip->first_color_change,
1486: prev_color_changes + dip_old->first_color_change,
1487: dip->nr_color_changes * sizeof *curr_color_changes) != 0)
1488: return 1;
1489: return 0;
1490: }
1491:
1.1.1.3 root 1492: /* End of a horizontal scan line. Finish off all decisions that were not
1493: * made yet. */
1.1.1.2 root 1494: static void finish_decisions (void)
1495: {
1496: struct draw_info *dip;
1497: struct draw_info *dip_old;
1498: struct decision *dp;
1499: int changed;
1.1.1.4 root 1500: int hpos = current_hpos ();
1.1.1.2 root 1501:
1502: if (framecnt != 0)
1503: return;
1504:
1.1.1.4 root 1505: decide_diw (hpos);
1.1.1.13 root 1506: decide_line (hpos);
1507: decide_fetch (hpos);
1508:
1509: if (thisline_decision.plfleft != -1 && thisline_decision.plflinelen == -1) {
1510: if (fetch_state != fetch_not_started)
1511: abort ();
1512: thisline_decision.plfright = thisline_decision.plfleft;
1513: thisline_decision.plflinelen = 0;
1514: thisline_decision.bplres = RES_LORES;
1515: }
1.1.1.3 root 1516:
1517: /* Large DIWSTOP values can cause the stop position never to be
1518: * reached, so the state machine always stays in the same state and
1519: * there's a more-or-less full-screen DIW. */
1.1.1.13 root 1520: if (hdiwstate == DIW_waiting_stop || thisline_decision.diwlastword > max_diwlastword)
1.1.1.3 root 1521: thisline_decision.diwlastword = max_diwlastword;
1522:
1.1.1.13 root 1523: if (thisline_decision.diwfirstword != line_decisions[next_lineno].diwfirstword)
1524: MARK_LINE_CHANGED;
1525: if (thisline_decision.diwlastword != line_decisions[next_lineno].diwlastword)
1526: MARK_LINE_CHANGED;
1.1.1.2 root 1527:
1528: dip = curr_drawinfo + next_lineno;
1529: dip_old = prev_drawinfo + next_lineno;
1530: dp = line_decisions + next_lineno;
1.1.1.5 root 1531: changed = thisline_changed;
1.1.1.2 root 1532:
1.1.1.13 root 1533: if (thisline_decision.plfleft != -1) {
1534: record_diw_line (thisline_decision.diwfirstword, thisline_decision.diwlastword);
1.1.1.2 root 1535:
1.1.1.4 root 1536: decide_sprites (hpos);
1.1.1.2 root 1537: }
1538:
1.1.1.13 root 1539: dip->last_sprite_entry = next_sprite_entry;
1.1.1.2 root 1540: dip->last_color_change = next_color_change;
1.1.1.3 root 1541:
1542: if (thisline_decision.ctable == -1) {
1.1.1.13 root 1543: if (thisline_decision.plfleft == -1)
1.1.1.3 root 1544: remember_ctable_for_border ();
1.1.1.13 root 1545: else
1546: remember_ctable ();
1.1.1.3 root 1547: }
1.1.1.2 root 1548:
1549: dip->nr_color_changes = next_color_change - dip->first_color_change;
1.1.1.13 root 1550: dip->nr_sprites = next_sprite_entry - dip->first_sprite_entry;
1.1.1.2 root 1551:
1.1.1.13 root 1552: if (thisline_decision.plfleft != line_decisions[next_lineno].plfleft)
1.1.1.2 root 1553: changed = 1;
1.1.1.13 root 1554: if (! changed && color_changes_differ (dip, dip_old))
1.1.1.2 root 1555: changed = 1;
1.1.1.13 root 1556: if (!changed && thisline_decision.plfleft != -1 && sprites_differ (dip, dip_old))
1.1.1.10 root 1557: changed = 1;
1.1.1.2 root 1558:
1559: if (changed) {
1.1.1.5 root 1560: thisline_changed = 1;
1.1.1.2 root 1561: *dp = thisline_decision;
1562: } else
1563: /* The only one that may differ: */
1564: dp->ctable = thisline_decision.ctable;
1565: }
1566:
1.1.1.3 root 1567: /* Set the state of all decisions to "undecided" for a new scanline. */
1.1.1.2 root 1568: static void reset_decisions (void)
1569: {
1570: if (framecnt != 0)
1571: return;
1.1.1.13 root 1572:
1573: thisline_decision.nr_planes = 0;
1574:
1.1.1.2 root 1575: decided_bpl1mod = bpl1mod;
1576: decided_bpl2mod = bpl2mod;
1577:
1.1.1.10 root 1578: thisline_decision.plfleft = -1;
1.1.1.13 root 1579: thisline_decision.plflinelen = -1;
1.1.1.10 root 1580:
1.1.1.7 root 1581: /* decided_res shouldn't be touched before it's initialized by decide_line(). */
1.1.1.2 root 1582: thisline_decision.diwfirstword = -1;
1583: thisline_decision.diwlastword = -2;
1.1.1.3 root 1584: if (hdiwstate == DIW_waiting_stop) {
1.1.1.13 root 1585: thisline_decision.diwfirstword = 0;
1.1.1.3 root 1586: if (thisline_decision.diwfirstword != line_decisions[next_lineno].diwfirstword)
1.1.1.5 root 1587: MARK_LINE_CHANGED;
1.1.1.3 root 1588: }
1.1.1.2 root 1589: thisline_decision.ctable = -1;
1590:
1.1.1.5 root 1591: thisline_changed = 0;
1.1.1.2 root 1592: curr_drawinfo[next_lineno].first_color_change = next_color_change;
1.1.1.13 root 1593: curr_drawinfo[next_lineno].first_sprite_entry = next_sprite_entry;
1594: next_sprite_forced = 1;
1.1.1.2 root 1595:
1.1.1.3 root 1596: /* memset(sprite_last_drawn_at, 0, sizeof sprite_last_drawn_at); */
1597: last_sprite_point = 0;
1.1.1.2 root 1598: modulos_added = 0;
1599: plane_decided = 0;
1600: color_decided = 0;
1.1.1.13 root 1601: fetch_state = fetch_not_started;
1602: passed_plfstop = 0;
1603:
1604: memset (todisplay, 0, sizeof todisplay);
1605: memset (fetched, 0, sizeof fetched);
1.1.1.14! root 1606: memset (fetched_aga0, 0, sizeof fetched_aga0);
! 1607: memset (fetched_aga1, 0, sizeof fetched_aga1);
1.1.1.13 root 1608: memset (outword, 0, sizeof outword);
1.1.1.9 root 1609:
1.1.1.13 root 1610: last_decide_line_hpos = -1;
1.1.1.9 root 1611: last_diw_pix_hpos = -1;
1612: last_ddf_pix_hpos = -1;
1.1.1.13 root 1613: last_sprite_hpos = -1;
1614: last_fetch_hpos = -1;
1.1.1.2 root 1615: }
1616:
1.1.1.7 root 1617: /* set PAL or NTSC timing variables */
1618:
1619: static void init_hz (void)
1620: {
1621: int isntsc;
1622:
1623: beamcon0 = new_beamcon0;
1624:
1625: isntsc = beamcon0 & 0x20 ? 0 : 1;
1626: if (!isntsc) {
1627: maxvpos = MAXVPOS_PAL;
1628: maxhpos = MAXHPOS_PAL;
1629: minfirstline = MINFIRSTLINE_PAL;
1630: vblank_endline = VBLANK_ENDLINE_PAL;
1631: vblank_hz = VBLANK_HZ_PAL;
1632: } else {
1633: maxvpos = MAXVPOS_NTSC;
1634: maxhpos = MAXHPOS_NTSC;
1635: minfirstline = MINFIRSTLINE_NTSC;
1636: vblank_endline = VBLANK_ENDLINE_NTSC;
1637: vblank_hz = VBLANK_HZ_NTSC;
1638: }
1639: vsynctime = syncbase / vblank_hz;
1640:
1641: write_log ("Using %s timing\n", isntsc ? "NTSC" : "PAL");
1642: }
1643:
1.1.1.11 root 1644: static void calcdiw (void)
1645: {
1.1.1.4 root 1646: int hstrt = diwstrt & 0xFF;
1647: int hstop = diwstop & 0xFF;
1648: int vstrt = diwstrt >> 8;
1649: int vstop = diwstop >> 8;
1650:
1651: if (diwhigh_written) {
1652: hstrt |= ((diwhigh >> 5) & 1) << 8;
1653: hstop |= ((diwhigh >> 13) & 1) << 8;
1654: vstrt |= (diwhigh & 7) << 8;
1655: vstop |= ((diwhigh >> 8) & 7) << 8;
1656: } else {
1657: hstop += 0x100;
1658: if ((vstop & 0x80) == 0)
1659: vstop |= 0x100;
1660: }
1661:
1.1.1.13 root 1662: diwfirstword = coord_diw_to_window_x (hstrt);
1663: diwlastword = coord_diw_to_window_x (hstop);
1.1.1.2 root 1664: if (diwfirstword < 0)
1665: diwfirstword = 0;
1.1.1.3 root 1666:
1.1.1.4 root 1667: plffirstline = vstrt;
1668: plflastline = vstop;
1669:
1.1 root 1670: #if 0
1671: /* This happens far too often. */
1672: if (plffirstline < minfirstline) {
1673: fprintf(stderr, "Warning: Playfield begins before line %d!\n", minfirstline);
1674: plffirstline = minfirstline;
1675: }
1676: #endif
1.1.1.4 root 1677:
1.1 root 1678: #if 0 /* Turrican does this */
1679: if (plflastline > 313) {
1.1.1.4 root 1680: fprintf (stderr, "Warning: Playfield out of range!\n");
1.1 root 1681: plflastline = 313;
1682: }
1683: #endif
1.1.1.2 root 1684: plfstrt = ddfstrt;
1685: plfstop = ddfstop;
1.1.1.13 root 1686: if (plfstrt < 0x18)
1687: plfstrt = 0x18;
1.1 root 1688: }
1689:
1.1.1.4 root 1690: /* Mousehack stuff */
1.1.1.2 root 1691:
1.1.1.4 root 1692: #define defstepx (1<<16)
1693: #define defstepy (1<<16)
1694: #define defxoffs 0
1695: #define defyoffs 0
1.1.1.3 root 1696:
1.1.1.4 root 1697: static const int docal = 60, xcaloff = 40, ycaloff = 20;
1698: static const int calweight = 3;
1699: static int lastsampledmx, lastsampledmy;
1700: static int lastspr0x,lastspr0y,lastdiffx,lastdiffy,spr0pos,spr0ctl;
1701: static int mstepx,mstepy,xoffs=defxoffs,yoffs=defyoffs;
1702: static int sprvbfl;
1.1.1.2 root 1703:
1.1.1.4 root 1704: int lastmx, lastmy;
1705: int newmousecounters;
1706: int ievent_alive = 0;
1.1 root 1707:
1.1.1.4 root 1708: static enum { unknown_mouse, normal_mouse, dont_care_mouse, follow_mouse } mousestate;
1.1 root 1709:
1.1.1.4 root 1710: static void mousehack_setdontcare (void)
1.1 root 1711: {
1.1.1.4 root 1712: if (mousestate == dont_care_mouse)
1.1.1.2 root 1713: return;
1714:
1.1.1.3 root 1715: write_log ("Don't care mouse mode set\n");
1716: mousestate = dont_care_mouse;
1717: lastspr0x = lastmx; lastspr0y = lastmy;
1718: mstepx = defstepx; mstepy = defstepy;
1719: }
1720:
1.1.1.4 root 1721: static void mousehack_setfollow (void)
1.1.1.3 root 1722: {
1.1.1.4 root 1723: if (mousestate == follow_mouse)
1724: return;
1725:
1.1.1.3 root 1726: write_log ("Follow sprite mode set\n");
1727: mousestate = follow_mouse;
1728: lastdiffx = lastdiffy = 0;
1729: sprvbfl = 0;
1.1.1.4 root 1730: spr0ctl = spr0pos = 0;
1.1.1.3 root 1731: mstepx = defstepx; mstepy = defstepy;
1732: }
1733:
1.1.1.7 root 1734: static uae_u32 mousehack_helper (void)
1.1.1.3 root 1735: {
1736: int mousexpos, mouseypos;
1737:
1738: #ifdef PICASSO96
1739: if (picasso_on) {
1.1.1.4 root 1740: mousexpos = lastmx - picasso96_state.XOffset;
1741: mouseypos = lastmy - picasso96_state.YOffset;
1.1.1.3 root 1742: } else
1743: #endif
1744: {
1745: if (lastmy >= gfxvidinfo.height)
1.1.1.4 root 1746: lastmy = gfxvidinfo.height - 1;
1747: mouseypos = coord_native_to_amiga_y (lastmy) << 1;
1748: mousexpos = coord_native_to_amiga_x (lastmx);
1.1.1.3 root 1749: }
1750:
1751: switch (m68k_dreg (regs, 0)) {
1752: case 0:
1753: return ievent_alive ? -1 : needmousehack ();
1754: case 1:
1755: ievent_alive = 10;
1756: return mousexpos;
1757: case 2:
1758: return mouseypos;
1759: }
1760: return 0;
1761: }
1762:
1.1.1.4 root 1763: void togglemouse (void)
1.1.1.3 root 1764: {
1.1.1.4 root 1765: switch (mousestate) {
1766: case dont_care_mouse: mousehack_setfollow (); break;
1767: case follow_mouse: mousehack_setdontcare (); break;
1.1.1.3 root 1768: default: break; /* Nnnnnghh! */
1769: }
1770: }
1771:
1.1.1.8 root 1772: STATIC_INLINE int adjust (int val)
1.1.1.3 root 1773: {
1.1.1.4 root 1774: if (val > 127)
1.1.1.3 root 1775: return 127;
1.1.1.4 root 1776: else if (val < -127)
1.1.1.3 root 1777: return -127;
1778: return val;
1779: }
1780:
1.1.1.4 root 1781: static void do_mouse_hack (void)
1.1.1.3 root 1782: {
1783: int spr0x = ((spr0pos & 0xff) << 2) | ((spr0ctl & 1) << 1);
1784: int spr0y = ((spr0pos >> 8) | ((spr0ctl & 4) << 6)) << 1;
1785: int diffx, diffy;
1786:
1787: if (ievent_alive > 0) {
1788: mouse_x = mouse_y = 0;
1789: return;
1790: }
1791: switch (mousestate) {
1.1.1.11 root 1792: case normal_mouse:
1.1.1.3 root 1793: diffx = lastmx - lastsampledmx;
1794: diffy = lastmy - lastsampledmy;
1795: if (!newmousecounters) {
1796: if (diffx > 127) diffx = 127;
1797: if (diffx < -127) diffx = -127;
1798: mouse_x += diffx;
1799: if (diffy > 127) diffy = 127;
1800: if (diffy < -127) diffy = -127;
1801: mouse_y += diffy;
1802: }
1803: lastsampledmx += diffx; lastsampledmy += diffy;
1804: break;
1805:
1.1.1.11 root 1806: case dont_care_mouse:
1.1.1.4 root 1807: diffx = adjust (((lastmx - lastspr0x) * mstepx) >> 16);
1808: diffy = adjust (((lastmy - lastspr0y) * mstepy) >> 16);
1809: lastspr0x = lastmx; lastspr0y = lastmy;
1810: mouse_x += diffx; mouse_y += diffy;
1.1.1.3 root 1811: break;
1812:
1.1.1.11 root 1813: case follow_mouse:
1.1.1.4 root 1814: if (sprvbfl && sprvbfl-- > 1) {
1.1.1.3 root 1815: int mousexpos, mouseypos;
1816:
1.1.1.4 root 1817: if ((lastdiffx > docal || lastdiffx < -docal)
1818: && lastspr0x != spr0x
1819: && spr0x > plfstrt*4 + 34 + xcaloff
1820: && spr0x < plfstop*4 - xcaloff)
1.1.1.3 root 1821: {
1822: int val = (lastdiffx << 16) / (spr0x - lastspr0x);
1.1.1.4 root 1823: if (val >= 0x8000)
1824: mstepx = (mstepx * (calweight - 1) + val) / calweight;
1.1.1.3 root 1825: }
1.1.1.4 root 1826: if ((lastdiffy > docal || lastdiffy < -docal)
1827: && lastspr0y != spr0y
1828: && spr0y > plffirstline + ycaloff
1829: && spr0y < plflastline - ycaloff)
1.1.1.3 root 1830: {
1.1.1.4 root 1831: int val = (lastdiffy << 16) / (spr0y - lastspr0y);
1832: if (val >= 0x8000)
1833: mstepy = (mstepy * (calweight - 1) + val) / calweight;
1.1.1.3 root 1834: }
1835: if (lastmy >= gfxvidinfo.height)
1836: lastmy = gfxvidinfo.height-1;
1.1.1.4 root 1837: mouseypos = coord_native_to_amiga_y (lastmy) << 1;
1838: mousexpos = coord_native_to_amiga_x (lastmx);
1.1.1.3 root 1839: diffx = adjust ((((mousexpos + xoffs - spr0x) & ~1) * mstepx) >> 16);
1840: diffy = adjust ((((mouseypos + yoffs - spr0y) & ~1) * mstepy) >> 16);
1.1.1.4 root 1841: lastspr0x = spr0x; lastspr0y = spr0y;
1842: lastdiffx = diffx; lastdiffy = diffy;
1843: mouse_x += diffx; mouse_y += diffy;
1.1.1.3 root 1844: }
1845: break;
1.1.1.4 root 1846:
1.1.1.11 root 1847: default:
1.1.1.4 root 1848: abort ();
1.1.1.3 root 1849: }
1850: }
1851:
1.1.1.7 root 1852: static int timehack_alive = 0;
1853:
1854: static uae_u32 timehack_helper (void)
1855: {
1856: #ifdef HAVE_GETTIMEOFDAY
1857: struct timeval tv;
1858: if (m68k_dreg (regs, 0) == 0)
1859: return timehack_alive;
1860:
1861: timehack_alive = 10;
1862:
1863: gettimeofday (&tv, NULL);
1864: put_long (m68k_areg (regs, 0), tv.tv_sec - (((365 * 8 + 2) * 24 - 2) * 60 * 60));
1865: put_long (m68k_areg (regs, 0) + 4, tv.tv_usec);
1866: return 0;
1867: #else
1868: return 2;
1869: #endif
1870: }
1871:
1.1.1.3 root 1872: /*
1.1 root 1873: * register functions
1874: */
1.1.1.8 root 1875: STATIC_INLINE uae_u16 DENISEID (void)
1.1.1.7 root 1876: {
1877: if (currprefs.chipset_mask & CSMASK_AGA)
1878: return 0xF8;
1879: if (currprefs.chipset_mask & CSMASK_ECS_DENISE)
1880: return 0xFC;
1881: return 0xFFFF;
1882: }
1.1.1.8 root 1883: STATIC_INLINE uae_u16 DMACONR (void)
1.1 root 1884: {
1885: return (dmacon | (bltstate==BLT_done ? 0 : 0x4000)
1886: | (blt_info.blitzero ? 0x2000 : 0));
1887: }
1.1.1.8 root 1888: STATIC_INLINE uae_u16 INTENAR (void)
1.1.1.4 root 1889: {
1890: return intena;
1891: }
1892: uae_u16 INTREQR (void)
1.1 root 1893: {
1.1.1.9 root 1894: return intreq /* | (currprefs.use_serial ? 0x0001 : 0) */;
1.1 root 1895: }
1.1.1.8 root 1896: STATIC_INLINE uae_u16 ADKCONR (void)
1.1.1.4 root 1897: {
1898: return adkcon;
1899: }
1.1.1.8 root 1900: STATIC_INLINE uae_u16 VPOSR (void)
1.1 root 1901: {
1.1.1.14! root 1902: unsigned int csbit = currprefs.ntscmode ? 0x1000 : 0;
1.1.1.7 root 1903: csbit |= (currprefs.chipset_mask & CSMASK_AGA) ? 0x2300 : 0;
1904: csbit |= (currprefs.chipset_mask & CSMASK_ECS_AGNUS) ? 0x2000 : 0;
1905: return (vpos >> 8) | lof | csbit;
1.1 root 1906: }
1.1.1.4 root 1907: static void VPOSW (uae_u16 v)
1.1.1.2 root 1908: {
1909: if (lof != (v & 0x8000))
1910: lof_changed = 1;
1911: lof = v & 0x8000;
1.1.1.3 root 1912: /*
1913: * This register is much more fun on a real Amiga. You can program
1914: * refresh rates with it ;) But I won't emulate this...
1915: */
1.1.1.2 root 1916: }
1.1 root 1917:
1.1.1.8 root 1918: STATIC_INLINE uae_u16 VHPOSR (void)
1.1.1.4 root 1919: {
1.1.1.13 root 1920: return (vpos << 8) | current_hpos ();
1.1.1.4 root 1921: }
1922:
1.1.1.8 root 1923: STATIC_INLINE void COP1LCH (uae_u16 v) { cop1lc = (cop1lc & 0xffff) | ((uae_u32)v << 16); }
1924: STATIC_INLINE void COP1LCL (uae_u16 v) { cop1lc = (cop1lc & ~0xffff) | (v & 0xfffe); }
1925: STATIC_INLINE void COP2LCH (uae_u16 v) { cop2lc = (cop2lc & 0xffff) | ((uae_u32)v << 16); }
1926: STATIC_INLINE void COP2LCL (uae_u16 v) { cop2lc = (cop2lc & ~0xffff) | (v & 0xfffe); }
1.1.1.4 root 1927:
1.1.1.9 root 1928: static void start_copper (void)
1.1.1.4 root 1929: {
1.1.1.10 root 1930: int was_active = eventtab[ev_copper].active;
1931: eventtab[ev_copper].active = 0;
1932: if (was_active)
1933: events_schedule ();
1934:
1.1.1.4 root 1935: cop_state.ignore_next = 0;
1936: cop_state.state = COP_read1;
1937: cop_state.vpos = vpos;
1938: cop_state.hpos = current_hpos () & ~1;
1.1.1.9 root 1939:
1.1.1.10 root 1940: if (dmaen (DMA_COPPER)) {
1941: copper_enabled_thisline = 1;
1.1.1.13 root 1942: set_special (SPCFLAG_COPPER);
1.1.1.10 root 1943: }
1.1.1.9 root 1944: }
1945:
1946: static void COPJMP1 (uae_u16 a)
1947: {
1948: cop_state.ip = cop1lc;
1949: start_copper ();
1.1.1.4 root 1950: }
1951:
1952: static void COPJMP2 (uae_u16 a)
1953: {
1954: cop_state.ip = cop2lc;
1.1.1.9 root 1955: start_copper ();
1.1.1.4 root 1956: }
1957:
1.1.1.8 root 1958: STATIC_INLINE void COPCON (uae_u16 a)
1.1.1.4 root 1959: {
1960: copcon = a;
1.1 root 1961: }
1.1.1.4 root 1962:
1.1.1.13 root 1963: static void DMACON (int hpos, uae_u16 v)
1.1 root 1964: {
1.1.1.14! root 1965: int i;
1.1 root 1966:
1.1.1.3 root 1967: uae_u16 oldcon = dmacon;
1968:
1.1.1.13 root 1969: decide_line (hpos);
1970: decide_fetch (hpos);
1971:
1972: setclr (&dmacon, v);
1973: dmacon &= 0x1FFF;
1.1.1.3 root 1974:
1975: /* FIXME? Maybe we need to think a bit more about the master DMA enable
1.1 root 1976: * bit in these cases. */
1.1.1.10 root 1977: if ((dmacon & DMA_COPPER) != (oldcon & DMA_COPPER)) {
1978: eventtab[ev_copper].active = 0;
1979: }
1.1.1.3 root 1980: if ((dmacon & DMA_COPPER) > (oldcon & DMA_COPPER)) {
1.1.1.4 root 1981: cop_state.ip = cop1lc;
1982: cop_state.ignore_next = 0;
1983: cop_state.state = COP_read1;
1984: cop_state.vpos = vpos;
1.1.1.13 root 1985: cop_state.hpos = hpos & ~1;
1.1.1.10 root 1986: copper_enabled_thisline = 1;
1.1.1.13 root 1987: set_special (SPCFLAG_COPPER);
1.1 root 1988: }
1.1.1.9 root 1989: if (! (dmacon & DMA_COPPER)) {
1.1.1.10 root 1990: copper_enabled_thisline = 0;
1.1.1.13 root 1991: unset_special (SPCFLAG_COPPER);
1.1.1.9 root 1992: cop_state.state = COP_stop;
1993: }
1994:
1.1 root 1995: if ((dmacon & DMA_BLITPRI) > (oldcon & DMA_BLITPRI) && bltstate != BLT_done) {
1996: static int count = 0;
1997: if (!count) {
1998: count = 1;
1.1.1.3 root 1999: write_log ("warning: program is doing blitpri hacks.\n");
1.1 root 2000: }
1.1.1.13 root 2001: set_special (SPCFLAG_BLTNASTY);
1.1 root 2002: }
1.1.1.10 root 2003: if ((dmacon & (DMA_BLITPRI | DMA_BLITTER | DMA_MASTER)) != (DMA_BLITPRI | DMA_BLITTER | DMA_MASTER))
1.1.1.13 root 2004: unset_special (SPCFLAG_BLTNASTY);
1.1.1.4 root 2005:
1.1.1.14! root 2006: if (currprefs.produce_sound > 0) {
! 2007: update_audio ();
1.1.1.3 root 2008:
1.1.1.14! root 2009: for (i = 0; i < 4; i++) {
! 2010: struct audio_channel_data *cdp = audio_channel + i;
! 2011: int chan_ena = (dmacon & 0x200) && (dmacon & (1<<i));
! 2012: if (cdp->dmaen == chan_ena)
! 2013: continue;
! 2014: cdp->dmaen = chan_ena;
! 2015: if (cdp->dmaen) {
! 2016: if (cdp->state == 0) {
! 2017: cdp->state = 1;
! 2018: cdp->pt = cdp->lc;
! 2019: cdp->wper = cdp->per;
! 2020: cdp->wlen = cdp->len;
! 2021: cdp->data_written = 2;
! 2022: cdp->evtime = eventtab[ev_hsync].evtime - get_cycles ();
! 2023: }
! 2024: } else {
! 2025: if (cdp->state == 1 || cdp->state == 5) {
! 2026: cdp->state = 0;
! 2027: cdp->last_sample = 0;
! 2028: cdp->current_sample = 0;
! 2029: }
1.1 root 2030: }
2031: }
1.1.1.14! root 2032: schedule_audio ();
1.1 root 2033: }
1.1.1.14! root 2034: events_schedule();
1.1 root 2035: }
1.1.1.2 root 2036:
1.1.1.3 root 2037: /*static int trace_intena = 0;*/
1.1.1.2 root 2038:
1.1.1.8 root 2039: STATIC_INLINE void INTENA (uae_u16 v)
1.1.1.2 root 2040: {
1.1.1.3 root 2041: /* if (trace_intena)
1.1.1.4 root 2042: fprintf (stderr, "INTENA: %04x\n", v);*/
1.1.1.13 root 2043: setclr (&intena,v);
2044: set_special (SPCFLAG_INT);
1.1.1.2 root 2045: }
1.1.1.3 root 2046: void INTREQ (uae_u16 v)
1.1 root 2047: {
1.1.1.3 root 2048: setclr(&intreq,v);
1.1.1.13 root 2049: set_special (SPCFLAG_INT);
2050: if ((v & 0x8800) == 0x0800)
1.1.1.4 root 2051: serdat &= 0xbfff;
1.1.1.3 root 2052: }
1.1 root 2053:
1.1.1.3 root 2054: static void ADKCON (uae_u16 v)
2055: {
2056: unsigned long t;
1.1.1.4 root 2057:
1.1.1.14! root 2058: if (currprefs.produce_sound > 0)
! 2059: update_audio ();
1.1.1.4 root 2060:
1.1.1.3 root 2061: setclr (&adkcon,v);
2062: t = adkcon | (adkcon >> 4);
2063: audio_channel[0].adk_mask = (((t >> 0) & 1) - 1);
2064: audio_channel[1].adk_mask = (((t >> 1) & 1) - 1);
2065: audio_channel[2].adk_mask = (((t >> 2) & 1) - 1);
2066: audio_channel[3].adk_mask = (((t >> 3) & 1) - 1);
2067: }
1.1 root 2068:
1.1.1.7 root 2069: static void BEAMCON0 (uae_u16 v)
2070: {
2071: new_beamcon0 = v & 0x20;
2072: }
2073:
1.1.1.4 root 2074: static void BPLPTH (int hpos, uae_u16 v, int num)
1.1.1.3 root 2075: {
1.1.1.4 root 2076: decide_line (hpos);
1.1.1.13 root 2077: decide_fetch (hpos);
1.1.1.4 root 2078: bplpt[num] = (bplpt[num] & 0xffff) | ((uae_u32)v << 16);
1.1.1.3 root 2079: }
1.1.1.4 root 2080: static void BPLPTL (int hpos, uae_u16 v, int num)
1.1.1.3 root 2081: {
1.1.1.4 root 2082: decide_line (hpos);
1.1.1.13 root 2083: decide_fetch (hpos);
1.1.1.4 root 2084: bplpt[num] = (bplpt[num] & ~0xffff) | (v & 0xfffe);
1.1.1.3 root 2085: }
1.1 root 2086:
1.1.1.14! root 2087: static int maxplanes_ocs[]={ 6,4,0,0 };
! 2088: static int maxplanes_ecs[]={ 6,4,2,0 };
! 2089: static int maxplanes_aga[]={ 8,4,2,0, 8,8,4,0, 8,8,8,0 };
! 2090:
1.1.1.4 root 2091: static void BPLCON0 (int hpos, uae_u16 v)
1.1 root 2092: {
1.1.1.14! root 2093: int *planes;
! 2094:
! 2095: if (currprefs.chipset_mask & CSMASK_AGA) {
! 2096: planes = maxplanes_aga;
! 2097: } else if (! (currprefs.chipset_mask & CSMASK_ECS_DENISE)) {
! 2098: planes = maxplanes_ocs;
! 2099: v &= ~(0x0001|0x0010|0x0020|0x0040|0x0080);
! 2100: } else {
! 2101: planes = maxplanes_ecs;
! 2102: v &= ~(0x0001|0x0010|0x0020|0x0080);
1.1.1.7 root 2103: }
1.1.1.14! root 2104: /* Disable bitplane DMA if planes > maxplanes. This is needed e.g. by the
! 2105: Sanity WOC demo (at the "Party Effect"). */
! 2106: if (GET_PLANES(v) > planes[fetchmode*4 + GET_RES (v)])
! 2107: v &= ~0x7040;
! 2108:
1.1.1.2 root 2109: if (bplcon0 == v)
1.1 root 2110: return;
1.1.1.4 root 2111: decide_line (hpos);
1.1.1.13 root 2112: decide_fetch (hpos);
2113:
1.1.1.2 root 2114: bplcon0 = v;
1.1.1.6 root 2115: nr_planes_from_bplcon0 = GET_PLANES (v);
1.1.1.7 root 2116:
2117: if (currprefs.chipset_mask & CSMASK_AGA)
2118: /* It's not clear how the copper timings are affected by the number
2119: * of bitplanes on AGA machines */
2120: corrected_nr_planes_from_bplcon0 = 4;
2121: else
1.1.1.14! root 2122: corrected_nr_planes_from_bplcon0 = nr_planes_from_bplcon0 << GET_RES (bplcon0);
! 2123: expand_fmodes ();
1.1 root 2124: }
1.1.1.9 root 2125:
1.1.1.8 root 2126: STATIC_INLINE void BPLCON1 (int hpos, uae_u16 v)
1.1 root 2127: {
1.1.1.2 root 2128: if (bplcon1 == v)
1.1 root 2129: return;
1.1.1.13 root 2130: decide_line (hpos);
2131: decide_fetch (hpos);
1.1.1.2 root 2132: bplcon1 = v;
1.1 root 2133: }
1.1.1.8 root 2134: STATIC_INLINE void BPLCON2 (int hpos, uae_u16 v)
1.1 root 2135: {
1.1.1.7 root 2136: if (bplcon2 == v)
2137: return;
2138: decide_line (hpos);
1.1.1.2 root 2139: bplcon2 = v;
1.1 root 2140: }
1.1.1.8 root 2141: STATIC_INLINE void BPLCON3 (int hpos, uae_u16 v)
1.1 root 2142: {
1.1.1.14! root 2143: if (! (currprefs.chipset_mask & CSMASK_AGA))
! 2144: return;
1.1.1.7 root 2145: if (bplcon3 == v)
2146: return;
2147: decide_line (hpos);
1.1.1.3 root 2148: bplcon3 = v;
1.1 root 2149: }
1.1.1.8 root 2150: STATIC_INLINE void BPLCON4 (int hpos, uae_u16 v)
1.1 root 2151: {
1.1.1.7 root 2152: if (! (currprefs.chipset_mask & CSMASK_AGA))
2153: return;
2154: if (bplcon4 == v)
2155: return;
2156: decide_line (hpos);
1.1.1.3 root 2157: bplcon4 = v;
1.1 root 2158: }
2159:
1.1.1.4 root 2160: static void BPL1MOD (int hpos, uae_u16 v)
1.1 root 2161: {
2162: v &= ~1;
1.1.1.3 root 2163: if ((uae_s16)bpl1mod == (uae_s16)v)
1.1 root 2164: return;
1.1.1.13 root 2165: decide_line (hpos);
2166: decide_fetch (hpos);
1.1 root 2167: bpl1mod = v;
2168: }
1.1.1.2 root 2169:
1.1.1.4 root 2170: static void BPL2MOD (int hpos, uae_u16 v)
1.1.1.3 root 2171: {
1.1 root 2172: v &= ~1;
1.1.1.3 root 2173: if ((uae_s16)bpl2mod == (uae_s16)v)
1.1 root 2174: return;
1.1.1.13 root 2175: decide_line (hpos);
2176: decide_fetch (hpos);
1.1 root 2177: bpl2mod = v;
2178: }
2179:
1.1.1.13 root 2180: STATIC_INLINE void BPL1DAT (int hpos, uae_u16 v)
1.1.1.10 root 2181: {
1.1.1.13 root 2182: decide_line (hpos);
1.1.1.10 root 2183: bpl1dat = v;
1.1.1.13 root 2184:
2185: {
2186: static int count = 0;
2187: if (count++ > 1000) {
2188: count = 0;
1.1.1.14! root 2189: write_log ("BPL1DAT %d\n", hpos);
1.1.1.13 root 2190: }
2191: }
1.1.1.14! root 2192:
1.1.1.13 root 2193: maybe_first_bpl1dat (hpos);
1.1.1.10 root 2194: }
1.1.1.2 root 2195: /* We could do as well without those... */
1.1.1.8 root 2196: STATIC_INLINE void BPL2DAT (uae_u16 v) { bpl2dat = v; }
2197: STATIC_INLINE void BPL3DAT (uae_u16 v) { bpl3dat = v; }
2198: STATIC_INLINE void BPL4DAT (uae_u16 v) { bpl4dat = v; }
2199: STATIC_INLINE void BPL5DAT (uae_u16 v) { bpl5dat = v; }
2200: STATIC_INLINE void BPL6DAT (uae_u16 v) { bpl6dat = v; }
2201: STATIC_INLINE void BPL7DAT (uae_u16 v) { bpl7dat = v; }
2202: STATIC_INLINE void BPL8DAT (uae_u16 v) { bpl8dat = v; }
1.1 root 2203:
1.1.1.4 root 2204: static void DIWSTRT (int hpos, uae_u16 v)
1.1 root 2205: {
1.1.1.4 root 2206: if (diwstrt == v && ! diwhigh_written)
1.1 root 2207: return;
1.1.1.4 root 2208: decide_line (hpos);
2209: diwhigh_written = 0;
1.1.1.3 root 2210: diwstrt = v;
1.1.1.4 root 2211: calcdiw ();
1.1 root 2212: }
1.1.1.4 root 2213:
2214: static void DIWSTOP (int hpos, uae_u16 v)
1.1 root 2215: {
1.1.1.4 root 2216: if (diwstop == v && ! diwhigh_written)
1.1 root 2217: return;
1.1.1.4 root 2218: decide_line (hpos);
2219: diwhigh_written = 0;
1.1.1.3 root 2220: diwstop = v;
1.1.1.4 root 2221: calcdiw ();
2222: }
2223:
2224: static void DIWHIGH (int hpos, uae_u16 v)
2225: {
1.1.1.7 root 2226: if (! (currprefs.chipset_mask & CSMASK_ECS_DENISE))
2227: return;
1.1.1.4 root 2228: if (diwhigh_written && diwhigh == v)
2229: return;
2230: decide_line (hpos);
2231: diwhigh_written = 1;
2232: diwhigh = v;
2233: calcdiw ();
1.1 root 2234: }
1.1.1.4 root 2235:
2236: static void DDFSTRT (int hpos, uae_u16 v)
1.1.1.3 root 2237: {
1.1.1.11 root 2238: v &= 0xFC;
1.1.1.2 root 2239: if (ddfstrt == v)
1.1 root 2240: return;
1.1.1.4 root 2241: decide_line (hpos);
1.1.1.3 root 2242: ddfstrt = v;
1.1.1.4 root 2243: calcdiw ();
1.1.1.13 root 2244: if (ddfstop > 0xD4 && (ddfstrt & 4) == 4)
1.1.1.14! root 2245: write_log ("WARNING! Very strange DDF values.\n");
1.1 root 2246: }
1.1.1.4 root 2247: static void DDFSTOP (int hpos, uae_u16 v)
1.1.1.3 root 2248: {
1.1.1.11 root 2249: v &= 0xFC;
1.1.1.2 root 2250: if (ddfstop == v)
1.1 root 2251: return;
1.1.1.4 root 2252: decide_line (hpos);
1.1.1.13 root 2253: decide_fetch (hpos);
1.1.1.2 root 2254: ddfstop = v;
1.1.1.4 root 2255: calcdiw ();
1.1.1.13 root 2256: if (fetch_state != fetch_not_started)
2257: estimate_last_fetch_cycle (hpos);
2258: if (ddfstop > 0xD4 && (ddfstrt & 4) == 4)
1.1.1.14! root 2259: write_log ("WARNING! Very strange DDF values.\n");
1.1 root 2260: }
2261:
1.1.1.7 root 2262: static void FMODE (uae_u16 v)
2263: {
2264: if (! (currprefs.chipset_mask & CSMASK_AGA))
1.1.1.14! root 2265: v = 0;
1.1.1.13 root 2266:
1.1.1.7 root 2267: fmode = v;
1.1.1.14! root 2268: sprite_width = GET_SPRITEWIDTH (fmode);
! 2269: switch (fmode & 3) {
! 2270: case 0:
! 2271: fetchmode = 0;
! 2272: break;
! 2273: case 1:
! 2274: case 2:
! 2275: fetchmode = 1;
! 2276: break;
! 2277: case 3:
! 2278: fetchmode = 2;
! 2279: break;
! 2280: }
! 2281: expand_fmodes ();
1.1.1.7 root 2282: }
2283:
1.1.1.4 root 2284: static void BLTADAT (uae_u16 v)
1.1 root 2285: {
1.1.1.13 root 2286: maybe_blit ();
1.1.1.2 root 2287:
2288: blt_info.bltadat = v;
1.1 root 2289: }
1.1.1.2 root 2290: /*
2291: * "Loading data shifts it immediately" says the HRM. Well, that may
2292: * be true for BLTBDAT, but not for BLTADAT - it appears the A data must be
2293: * loaded for every word so that AFWM and ALWM can be applied.
2294: */
1.1.1.4 root 2295: static void BLTBDAT (uae_u16 v)
1.1 root 2296: {
1.1.1.13 root 2297: maybe_blit ();
1.1.1.2 root 2298:
2299: if (bltcon1 & 2)
2300: blt_info.bltbhold = v << (bltcon1 >> 12);
2301: else
2302: blt_info.bltbhold = v >> (bltcon1 >> 12);
2303: blt_info.bltbdat = v;
1.1 root 2304: }
1.1.1.4 root 2305: static void BLTCDAT (uae_u16 v) { maybe_blit (); blt_info.bltcdat = v; }
1.1 root 2306:
1.1.1.4 root 2307: static void BLTAMOD (uae_u16 v) { maybe_blit (); blt_info.bltamod = (uae_s16)(v & 0xFFFE); }
2308: static void BLTBMOD (uae_u16 v) { maybe_blit (); blt_info.bltbmod = (uae_s16)(v & 0xFFFE); }
2309: static void BLTCMOD (uae_u16 v) { maybe_blit (); blt_info.bltcmod = (uae_s16)(v & 0xFFFE); }
2310: static void BLTDMOD (uae_u16 v) { maybe_blit (); blt_info.bltdmod = (uae_s16)(v & 0xFFFE); }
1.1 root 2311:
1.1.1.4 root 2312: static void BLTCON0 (uae_u16 v) { maybe_blit (); bltcon0 = v; blinea_shift = v >> 12; }
1.1.1.3 root 2313: /* The next category is "Most useless hardware register".
1.1 root 2314: * And the winner is... */
1.1.1.7 root 2315: static void BLTCON0L (uae_u16 v)
2316: {
2317: if (! (currprefs.chipset_mask & CSMASK_ECS_AGNUS))
2318: return;
2319: maybe_blit (); bltcon0 = (bltcon0 & 0xFF00) | (v & 0xFF);
2320: }
1.1.1.4 root 2321: static void BLTCON1 (uae_u16 v) { maybe_blit (); bltcon1 = v; }
2322:
2323: static void BLTAFWM (uae_u16 v) { maybe_blit (); blt_info.bltafwm = v; }
2324: static void BLTALWM (uae_u16 v) { maybe_blit (); blt_info.bltalwm = v; }
1.1 root 2325:
1.1.1.4 root 2326: static void BLTAPTH (uae_u16 v) { maybe_blit (); bltapt = (bltapt & 0xffff) | ((uae_u32)v << 16); }
2327: static void BLTAPTL (uae_u16 v) { maybe_blit (); bltapt = (bltapt & ~0xffff) | (v & 0xFFFE); }
2328: static void BLTBPTH (uae_u16 v) { maybe_blit (); bltbpt = (bltbpt & 0xffff) | ((uae_u32)v << 16); }
2329: static void BLTBPTL (uae_u16 v) { maybe_blit (); bltbpt = (bltbpt & ~0xffff) | (v & 0xFFFE); }
2330: static void BLTCPTH (uae_u16 v) { maybe_blit (); bltcpt = (bltcpt & 0xffff) | ((uae_u32)v << 16); }
2331: static void BLTCPTL (uae_u16 v) { maybe_blit (); bltcpt = (bltcpt & ~0xffff) | (v & 0xFFFE); }
2332: static void BLTDPTH (uae_u16 v) { maybe_blit (); bltdpt = (bltdpt & 0xffff) | ((uae_u32)v << 16); }
2333: static void BLTDPTL (uae_u16 v) { maybe_blit (); bltdpt = (bltdpt & ~0xffff) | (v & 0xFFFE); }
1.1 root 2334:
1.1.1.4 root 2335: static void BLTSIZE (uae_u16 v)
1.1 root 2336: {
2337: bltsize = v;
1.1.1.3 root 2338:
1.1.1.4 root 2339: maybe_blit ();
1.1 root 2340:
2341: blt_info.vblitsize = bltsize >> 6;
2342: blt_info.hblitsize = bltsize & 0x3F;
2343: if (!blt_info.vblitsize) blt_info.vblitsize = 1024;
2344: if (!blt_info.hblitsize) blt_info.hblitsize = 64;
1.1.1.3 root 2345:
2346: bltstate = BLT_init;
1.1.1.4 root 2347: do_blitter ();
1.1 root 2348: }
1.1.1.4 root 2349:
2350: static void BLTSIZV (uae_u16 v)
1.1 root 2351: {
1.1.1.7 root 2352: if (! (currprefs.chipset_mask & CSMASK_ECS_AGNUS))
2353: return;
1.1.1.4 root 2354: maybe_blit ();
1.1 root 2355: oldvblts = v & 0x7FFF;
2356: }
1.1.1.4 root 2357:
2358: static void BLTSIZH (uae_u16 v)
1.1 root 2359: {
1.1.1.7 root 2360: if (! (currprefs.chipset_mask & CSMASK_ECS_AGNUS))
2361: return;
1.1.1.4 root 2362: maybe_blit ();
1.1 root 2363: blt_info.hblitsize = v & 0x7FF;
2364: blt_info.vblitsize = oldvblts;
2365: if (!blt_info.vblitsize) blt_info.vblitsize = 32768;
2366: if (!blt_info.hblitsize) blt_info.hblitsize = 0x800;
1.1.1.2 root 2367: bltstate = BLT_init;
1.1.1.5 root 2368: do_blitter ();
1.1 root 2369: }
1.1.1.4 root 2370:
1.1.1.8 root 2371: STATIC_INLINE void SPRxCTL_1 (uae_u16 v, int num)
1.1 root 2372: {
1.1.1.2 root 2373: int sprxp;
2374: sprctl[num] = v;
1.1.1.10 root 2375: nr_armed -= spr[num].armed;
2376: spr[num].armed = 0;
1.1.1.3 root 2377: if (sprpos[num] == 0 && v == 0) {
1.1.1.10 root 2378: spr[num].state = SPR_stop;
2379: spr[num].on = 0;
1.1.1.3 root 2380: } else
1.1.1.10 root 2381: spr[num].state = SPR_waiting_start;
1.1.1.2 root 2382:
1.1.1.13 root 2383: sprxp = coord_hw_to_window_x ((sprpos[num] & 0xFF) * 2 + (v & 1) + DIW_DDF_OFFSET);
1.1.1.10 root 2384: spr[num].xpos = sprxp;
2385: spr[num].vstart = (sprpos[num] >> 8) | ((sprctl[num] << 6) & 0x100);
2386: spr[num].vstop = (sprctl[num] >> 8) | ((sprctl[num] << 7) & 0x100);
1.1.1.2 root 2387: }
1.1.1.8 root 2388: STATIC_INLINE void SPRxPOS_1 (uae_u16 v, int num)
1.1.1.2 root 2389: {
2390: int sprxp;
2391: sprpos[num] = v;
1.1.1.13 root 2392: sprxp = coord_hw_to_window_x ((v & 0xFF) * 2 + (sprctl[num] & 1) + DIW_DDF_OFFSET);
1.1.1.10 root 2393: spr[num].xpos = sprxp;
2394: spr[num].vstart = (sprpos[num] >> 8) | ((sprctl[num] << 6) & 0x100);
1.1.1.2 root 2395: }
1.1.1.8 root 2396: STATIC_INLINE void SPRxDATA_1 (uae_u16 v, int num)
1.1.1.2 root 2397: {
2398: sprdata[num] = v;
1.1.1.10 root 2399: nr_armed += 1 - spr[num].armed;
2400: spr[num].armed = 1;
1.1.1.2 root 2401: }
1.1.1.8 root 2402: STATIC_INLINE void SPRxDATB_1 (uae_u16 v, int num)
1.1.1.2 root 2403: {
2404: sprdatb[num] = v;
2405: }
1.1.1.4 root 2406: static void SPRxDATA (int hpos, uae_u16 v, int num) { decide_sprites (hpos); SPRxDATA_1 (v, num); }
2407: static void SPRxDATB (int hpos, uae_u16 v, int num) { decide_sprites (hpos); SPRxDATB_1 (v, num); }
2408: static void SPRxCTL (int hpos, uae_u16 v, int num) { decide_sprites (hpos); SPRxCTL_1 (v, num); }
2409: static void SPRxPOS (int hpos, uae_u16 v, int num) { decide_sprites (hpos); SPRxPOS_1 (v, num); }
2410: static void SPRxPTH (int hpos, uae_u16 v, int num)
1.1 root 2411: {
1.1.1.4 root 2412: decide_sprites (hpos);
1.1.1.10 root 2413: spr[num].pt &= 0xffff;
2414: spr[num].pt |= (uae_u32)v << 16;
1.1.1.3 root 2415:
1.1.1.10 root 2416: if (spr[num].state == SPR_stop || vpos < sprite_vblank_endline)
2417: spr[num].state = SPR_restart;
2418: spr[num].on = 1;
1.1 root 2419: }
1.1.1.4 root 2420: static void SPRxPTL (int hpos, uae_u16 v, int num)
1.1 root 2421: {
1.1.1.4 root 2422: decide_sprites (hpos);
1.1.1.10 root 2423: spr[num].pt &= ~0xffff;
2424: spr[num].pt |= v;
1.1 root 2425:
1.1.1.10 root 2426: if (spr[num].state == SPR_stop || vpos < sprite_vblank_endline)
2427: spr[num].state = SPR_restart;
2428: spr[num].on = 1;
1.1.1.3 root 2429: }
1.1.1.4 root 2430: static void CLXCON (uae_u16 v)
1.1.1.3 root 2431: {
2432: clxcon = v;
1.1.1.14! root 2433: clxcon_bpl_enable = (v >> 6) & 63;
! 2434: clxcon_bpl_match = v & 63;
! 2435: clx_sprmask = ((((v >> 15) & 1) << 7) | (((v >> 14) & 1) << 5) | (((v >> 13) & 1) << 3) | (((v >> 12) & 1) << 1) | 0x55);
! 2436: }
! 2437: static void CLXCON2 (uae_u16 v)
! 2438: {
! 2439: if (!(currprefs.chipset_mask & CSMASK_AGA))
! 2440: return;
! 2441: clxcon2 = v;
! 2442: clxcon_bpl_enable |= v & (0x40|0x80);
! 2443: clxcon_bpl_match |= (v & (0x01|0x02)) << 6;
! 2444: }
1.1.1.4 root 2445: static uae_u16 CLXDAT (void)
1.1.1.3 root 2446: {
2447: uae_u16 v = clxdat;
2448: clxdat = 0;
2449: return v;
2450: }
1.1.1.11 root 2451:
1.1.1.13 root 2452: static uae_u16 COLOR_READ (int num)
1.1 root 2453: {
1.1.1.13 root 2454: int cr, cg, cb, colreg;
2455: uae_u16 cval;
2456:
2457: if (!(currprefs.chipset_mask & CSMASK_AGA) || !(bplcon2 & 0x0100))
2458: return 0xffff;
2459:
2460: colreg = ((bplcon3 >> 13) & 7) * 32 + num;
2461: cr = current_colors.color_regs_aga[colreg] >> 16;
2462: cg = (current_colors.color_regs_aga[colreg] >> 8) & 0xFF;
2463: cb = current_colors.color_regs_aga[colreg] & 0xFF;
2464: if (bplcon3 & 0x200)
2465: cval = ((cr & 15) << 12) | ((cg & 15) << 4) | ((cb & 15) << 0);
2466: else
2467: cval = ((cr >> 4) << 12) | ((cg >> 4) << 4) | ((cb >> 4) << 0);
2468: return cval;
2469: }
1.1.1.3 root 2470:
1.1.1.13 root 2471: static void COLOR_WRITE (int hpos, uae_u16 v, int num)
2472: {
1.1 root 2473: v &= 0xFFF;
1.1.1.11 root 2474: if (currprefs.chipset_mask & CSMASK_AGA) {
1.1.1.4 root 2475: int r,g,b;
2476: int cr,cg,cb;
2477: int colreg;
1.1.1.3 root 2478: uae_u32 cval;
1.1.1.4 root 2479:
1.1.1.11 root 2480: /* writing is disabled when RDRAM=1 */
1.1.1.13 root 2481: if (bplcon2 & 0x0100)
2482: return;
1.1.1.11 root 2483:
1.1.1.2 root 2484: colreg = ((bplcon3 >> 13) & 7) * 32 + num;
1.1 root 2485: r = (v & 0xF00) >> 8;
2486: g = (v & 0xF0) >> 4;
2487: b = (v & 0xF) >> 0;
1.1.1.11 root 2488: cr = current_colors.color_regs_aga[colreg] >> 16;
2489: cg = (current_colors.color_regs_aga[colreg] >> 8) & 0xFF;
2490: cb = current_colors.color_regs_aga[colreg] & 0xFF;
1.1 root 2491:
1.1.1.2 root 2492: if (bplcon3 & 0x200) {
1.1 root 2493: cr &= 0xF0; cr |= r;
2494: cg &= 0xF0; cg |= g;
2495: cb &= 0xF0; cb |= b;
2496: } else {
2497: cr = r + (r << 4);
2498: cg = g + (g << 4);
2499: cb = b + (b << 4);
2500: }
2501: cval = (cr << 16) | (cg << 8) | cb;
1.1.1.11 root 2502: if (cval == current_colors.color_regs_aga[colreg])
1.1 root 2503: return;
1.1.1.5 root 2504:
2505: /* Call this with the old table still intact. */
1.1.1.11 root 2506: record_color_change (hpos, colreg, cval);
1.1.1.5 root 2507: remembered_color_entry = -1;
1.1.1.11 root 2508: current_colors.color_regs_aga[colreg] = cval;
2509: current_colors.acolors[colreg] = CONVERT_RGB (cval);
2510: } else {
2511: if (current_colors.color_regs_ecs[num] == v)
1.1 root 2512: return;
1.1.1.2 root 2513: /* Call this with the old table still intact. */
1.1.1.4 root 2514: record_color_change (hpos, num, v);
1.1.1.2 root 2515: remembered_color_entry = -1;
1.1.1.11 root 2516: current_colors.color_regs_ecs[num] = v;
1.1.1.2 root 2517: current_colors.acolors[num] = xcolors[v];
1.1 root 2518: }
2519: }
1.1.1.3 root 2520:
2521: static uae_u16 potgo_value;
2522:
1.1.1.4 root 2523: static void POTGO (uae_u16 v)
1.1 root 2524: {
1.1.1.3 root 2525: potgo_value = v;
2526: }
2527:
1.1.1.4 root 2528: static uae_u16 POTGOR (void)
1.1.1.3 root 2529: {
1.1.1.11 root 2530: uae_u16 v = (potgo_value | (potgo_value >> 1)) & 0x5500;
2531:
2532: v |= (~potgo_value & 0xAA00) >> 1;
1.1.1.3 root 2533:
1.1.1.6 root 2534: if (JSEM_ISMOUSE (0, &currprefs)) {
1.1.1.3 root 2535: if (buttonstate[2])
2536: v &= 0xFBFF;
2537:
2538: if (buttonstate[1])
2539: v &= 0xFEFF;
1.1.1.6 root 2540: } else if (JSEM_ISJOY0 (0, &currprefs) || JSEM_ISJOY1 (0, &currprefs)) {
1.1.1.3 root 2541: if (joy0button & 2) v &= 0xfbff;
2542: if (joy0button & 4) v &= 0xfeff;
2543: }
2544:
1.1.1.6 root 2545: if (JSEM_ISJOY0 (1, &currprefs) || JSEM_ISJOY1 (1, &currprefs)) {
1.1.1.3 root 2546: if (joy1button & 2) v &= 0xbfff;
2547: if (joy1button & 4) v &= 0xefff;
2548: }
1.1 root 2549:
2550: return v;
2551: }
1.1.1.4 root 2552:
2553: static uae_u16 POT0DAT (void)
1.1 root 2554: {
1.1.1.3 root 2555: static uae_u16 cnt = 0;
1.1.1.6 root 2556: if (JSEM_ISMOUSE (0, &currprefs)) {
1.1.1.3 root 2557: if (buttonstate[2])
2558: cnt = ((cnt + 1) & 0xFF) | (cnt & 0xFF00);
2559: if (buttonstate[1])
2560: cnt += 0x100;
2561: }
2562:
1.1 root 2563: return cnt;
2564: }
1.1.1.4 root 2565: static uae_u16 JOY0DAT (void)
1.1 root 2566: {
1.1.1.6 root 2567: if (JSEM_ISMOUSE (0, &currprefs)) {
1.1.1.4 root 2568: do_mouse_hack ();
1.1.1.3 root 2569: return ((uae_u8)mouse_x) + ((uae_u16)mouse_y << 8);
2570: }
1.1 root 2571: return joy0dir;
2572: }
1.1.1.4 root 2573: static uae_u16 JOY1DAT (void)
1.1 root 2574: {
1.1.1.6 root 2575: if (JSEM_ISMOUSE (1, &currprefs)) {
1.1.1.4 root 2576: do_mouse_hack ();
1.1.1.3 root 2577: return ((uae_u8)mouse_x) + ((uae_u16)mouse_y << 8);
2578: }
2579: return joy1dir;
1.1 root 2580: }
1.1.1.4 root 2581: static void JOYTEST (uae_u16 v)
1.1 root 2582: {
1.1.1.6 root 2583: if (JSEM_ISMOUSE (0, &currprefs)) {
1.1.1.3 root 2584: mouse_x = v & 0xFC;
2585: mouse_y = (v >> 8) & 0xFC;
1.1 root 2586: }
2587: }
2588:
1.1.1.4 root 2589: /* Determine which cycles are available for the copper in a display
2590: * with a agiven number of planes. */
2591: static int cycles_for_plane[9][8] = {
2592: { 0, -1, 0, -1, 0, -1, 0, -1 },
2593: { 0, -1, 0, -1, 0, -1, 0, -1 },
2594: { 0, -1, 0, -1, 0, -1, 0, -1 },
2595: { 0, -1, 0, -1, 0, -1, 0, -1 },
2596: { 0, -1, 0, -1, 0, -1, 0, -1 },
1.1.1.13 root 2597: { 0, -1, 0, -1, 0, -1, 1, -1 }, /* */
1.1.1.4 root 2598: { 0, -1, 1, -1, 0, -1, 1, -1 },
2599: { 1, -1, 1, -1, 1, -1, 1, -1 },
2600: { 1, -1, 1, -1, 1, -1, 1, -1 }
2601: };
1.1.1.2 root 2602:
1.1.1.4 root 2603: static unsigned int waitmasktab[256];
1.1.1.2 root 2604:
1.1.1.13 root 2605: STATIC_INLINE int copper_cant_read (int hpos, int planes)
1.1 root 2606: {
1.1.1.4 root 2607: int t;
1.1.1.2 root 2608:
1.1.1.9 root 2609: /* @@@ */
1.1.1.13 root 2610: if (hpos >= (maxhpos & ~1))
1.1.1.2 root 2611: return 1;
1.1.1.3 root 2612:
1.1.1.7 root 2613: if (currprefs.chipset_mask & CSMASK_AGA)
2614: /* FIXME */
2615: return 0;
2616:
1.1.1.13 root 2617: if (fetch_state == fetch_not_started || passed_plfstop == 3
2618: || hpos > estimated_last_fetch_cycle)
1.1.1.4 root 2619: return 0;
1.1.1.3 root 2620:
1.1.1.13 root 2621: t = cycles_for_plane[planes][(hpos + fetch_cycle - last_fetch_hpos) & 7];
1.1.1.4 root 2622: #if 0
2623: if (t == -1)
2624: abort ();
2625: #endif
2626: return t;
1.1.1.2 root 2627: }
2628:
1.1.1.10 root 2629: STATIC_INLINE int dangerous_reg (int reg)
2630: {
2631: /* Safe:
2632: * Bitplane pointers, control registers, modulos and data.
2633: * Sprite pointers, control registers, and data.
2634: * Color registers. */
2635: if (reg >= 0xE0 && reg < 0x1C0)
2636: return 0;
2637: return 1;
2638: }
2639:
1.1.1.13 root 2640: #define FAST_COPPER 0
2641:
1.1.1.9 root 2642: static void update_copper (int until_hpos)
1.1.1.2 root 2643: {
1.1.1.10 root 2644: int vp = vpos & (((cop_state.i2 >> 8) & 0x7F) | 0x80);
1.1.1.4 root 2645: int c_hpos = cop_state.hpos;
1.1.1.2 root 2646:
1.1.1.10 root 2647: if (eventtab[ev_copper].active)
2648: abort ();
2649:
2650: if (cop_state.state == COP_wait && vp < cop_state.vcmp)
2651: abort ();
2652:
2653: until_hpos &= ~1;
2654:
2655: if (until_hpos > (maxhpos & ~1))
2656: until_hpos = maxhpos & ~1;
1.1.1.3 root 2657:
1.1.1.13 root 2658: until_hpos += 2;
1.1.1.4 root 2659: for (;;) {
1.1.1.10 root 2660: int old_hpos = c_hpos;
2661: int hp;
2662:
1.1.1.13 root 2663: if (c_hpos >= until_hpos)
1.1.1.3 root 2664: break;
2665:
1.1.1.13 root 2666: /* So we know about the fetch state. */
1.1.1.9 root 2667: decide_line (c_hpos);
1.1.1.3 root 2668:
1.1.1.10 root 2669: c_hpos += 2;
1.1.1.13 root 2670: if (copper_cant_read (old_hpos, corrected_nr_planes_from_bplcon0))
1.1.1.10 root 2671: continue;
1.1.1.3 root 2672:
1.1.1.10 root 2673: switch (cop_state.state) {
1.1.1.9 root 2674: case COP_read1:
2675: cop_state.i1 = chipmem_bank.wget (cop_state.ip);
2676: cop_state.ip += 2;
2677: cop_state.state = COP_read2;
2678: break;
2679:
2680: case COP_read2:
2681: cop_state.i2 = chipmem_bank.wget (cop_state.ip);
2682: cop_state.ip += 2;
1.1.1.10 root 2683: cop_state.state = COP_read1;
1.1.1.9 root 2684: if (cop_state.ignore_next) {
2685: cop_state.ignore_next = 0;
2686: break;
2687: }
2688: /* Perform moves immediately. */
2689: if ((cop_state.i1 & 1) == 0) {
1.1.1.11 root 2690: unsigned int address = cop_state.i1 & 0x1FE;
2691: if (address < (copcon & 2 ? ((currprefs.chipset_mask & CSMASK_AGA) ? 0 : 0x40u) : 0x80u)) {
1.1.1.10 root 2692: cop_state.state = COP_stop;
2693: copper_enabled_thisline = 0;
1.1.1.13 root 2694: unset_special (SPCFLAG_COPPER);
1.1.1.10 root 2695: goto out;
1.1.1.4 root 2696: }
1.1.1.13 root 2697: if (address == 0x88) {
1.1.1.4 root 2698: cop_state.ip = cop1lc;
1.1.1.13 root 2699: } else if (address == 0x8A) {
1.1.1.4 root 2700: cop_state.ip = cop2lc;
1.1.1.13 root 2701: } else
1.1.1.11 root 2702: custom_wput_1 (old_hpos, address, cop_state.i2);
1.1.1.10 root 2703: /* That could have turned off the copper... */
2704: if (! copper_enabled_thisline)
2705: goto out;
1.1.1.9 root 2706: break;
1.1.1.3 root 2707: }
1.1.1.2 root 2708:
1.1.1.10 root 2709: cop_state.vcmp = (cop_state.i1 & (cop_state.i2 | 0x8000)) >> 8;
1.1.1.9 root 2710: cop_state.hcmp = (cop_state.i1 & cop_state.i2 & 0xFE);
2711: if ((cop_state.i2 & 1) == 1) {
2712: /* Skip instruction. */
1.1.1.13 root 2713: vp = vpos & (((cop_state.i2 >> 8) & 0x7F) | 0x80);
2714: hp = old_hpos & (cop_state.i2 & 0xFE);
2715:
1.1.1.9 root 2716: if ((vp > cop_state.vcmp || (vp == cop_state.vcmp && hp >= cop_state.hcmp))
2717: && ((cop_state.i2 & 0x8000) != 0 || ! (DMACONR() & 0x4000)))
2718: cop_state.ignore_next = 1;
1.1.1.2 root 2719: break;
1.1.1.4 root 2720: }
1.1.1.9 root 2721: cop_state.state = COP_wait;
1.1.1.13 root 2722:
2723: vp = vpos & (((cop_state.i2 >> 8) & 0x7F) | 0x80);
2724: hp = old_hpos & (cop_state.i2 & 0xFE);
2725:
1.1.1.9 root 2726: if (cop_state.i1 == 0xFFFF && cop_state.i2 == 0xFFFE) {
2727: cop_state.state = COP_stop;
1.1.1.10 root 2728: copper_enabled_thisline = 0;
1.1.1.13 root 2729: unset_special (SPCFLAG_COPPER);
1.1.1.10 root 2730: goto out;
1.1.1.2 root 2731: }
1.1.1.9 root 2732: if (vp < cop_state.vcmp) {
1.1.1.10 root 2733: copper_enabled_thisline = 0;
1.1.1.13 root 2734: unset_special (SPCFLAG_COPPER);
1.1.1.10 root 2735: goto out;
1.1.1.2 root 2736: }
1.1.1.10 root 2737: if (vp > cop_state.vcmp)
1.1.1.9 root 2738: break;
2739:
1.1.1.10 root 2740: /* Only enable shortcuts if there's no masking going on. */
1.1.1.13 root 2741: if (FAST_COPPER && (cop_state.i2 & 0xFE) == 0xFE) {
2742: /* Compute cycles remaining until c_hpos is past until_hpos
2743: (i.e. until we'd normally break out of the loop). */
1.1.1.10 root 2744: int time_remaining = until_hpos - c_hpos;
2745:
1.1.1.13 root 2746: if (time_remaining < 0)
2747: abort ();
2748:
2749: /* Compute minimum number of cycles to wait once the copper is at c_hpos. */
2750: cop_min_waittime = cop_state.hcmp - hp - 2;
2751:
2752: if (cop_min_waittime <= 0)
1.1.1.10 root 2753: break;
1.1.1.13 root 2754:
2755: /* Does this still leave us before until_hpos? */
2756: if (cop_min_waittime <= time_remaining) {
1.1.1.10 root 2757: c_hpos += cop_min_waittime;
2758: break;
2759: }
1.1.1.13 root 2760:
2761: /* This wait will use up all the time up to until_hpos, and then some. */
1.1.1.10 root 2762: c_hpos += time_remaining;
2763: cop_min_waittime -= time_remaining;
1.1.1.13 root 2764:
1.1.1.10 root 2765: if (cop_min_waittime >= 8) {
1.1.1.13 root 2766: unset_special (SPCFLAG_COPPER);
1.1.1.10 root 2767: eventtab[ev_copper].active = 1;
1.1.1.14! root 2768: eventtab[ev_copper].oldcycles = get_cycles ();
! 2769: eventtab[ev_copper].evtime = get_cycles () + cop_min_waittime * CYCLE_UNIT;
1.1.1.13 root 2770: /* until_hpos is larger than hpos; add a correction for this adjustment. */
2771: cop_min_waittime -= 2;
1.1.1.10 root 2772: events_schedule ();
2773: goto out;
2774: }
2775: }
2776: break;
2777:
2778: case COP_wait:
2779: if (vp < cop_state.vcmp)
2780: abort ();
2781:
1.1.1.13 root 2782: hp = old_hpos & (cop_state.i2 & 0xFE);
1.1.1.9 root 2783: if (vp == cop_state.vcmp && hp < cop_state.hcmp)
1.1.1.4 root 2784: break;
1.1.1.10 root 2785:
2786: /* Now we know that the comparisons were successful. We might still
2787: have to wait for the blitter though. */
2788: if ((cop_state.i2 & 0x8000) == 0 && (DMACONR() & 0x4000)) {
1.1.1.9 root 2789: /* We need to wait for the blitter. */
1.1.1.4 root 2790: cop_state.state = COP_bltwait;
1.1.1.10 root 2791: copper_enabled_thisline = 0;
1.1.1.13 root 2792: unset_special (SPCFLAG_COPPER);
1.1.1.10 root 2793: goto out;
1.1.1.2 root 2794: }
1.1.1.10 root 2795:
1.1.1.13 root 2796: cop_state.state = COP_wait1;
2797: break;
2798:
2799: case COP_wait1:
1.1.1.10 root 2800: cop_state.state = COP_read1;
1.1.1.4 root 2801: break;
1.1.1.2 root 2802:
1.1.1.13 root 2803: default:
1.1.1.10 root 2804: abort ();
1.1 root 2805: }
1.1.1.4 root 2806: }
1.1.1.10 root 2807:
2808: out:
1.1.1.4 root 2809: cop_state.hpos = c_hpos;
1.1.1.13 root 2810: #if FAST_COPPER
1.1.1.10 root 2811: /* The future, Conan? */
2812: if (cop_state.state == COP_read1 || cop_state.state == COP_read2) {
2813: int ip = cop_state.ip;
2814: int word = cop_state.i1;
1.1.1.13 root 2815: int cycle_count;
1.1.1.10 root 2816:
2817: if (eventtab[ev_copper].active /* || ! (regs.spcflags & SPCFLAG_COPPER) */)
2818: abort ();
2819:
2820: if (cop_state.state == COP_read2) {
2821: ip += 2;
2822: c_hpos += 2;
2823: goto inner;
2824: }
2825: while (c_hpos < (maxhpos & ~1)) {
2826: word = chipmem_bank.wget (ip);
2827: ip += 4;
2828: c_hpos += 4;
2829: inner:
2830: if ((word & 1) || dangerous_reg (word))
2831: break;
2832: }
1.1.1.13 root 2833: cycle_count = c_hpos - cop_state.hpos;
2834: if (cycle_count >= 8) {
2835: unset_special (SPCFLAG_COPPER);
1.1.1.10 root 2836: eventtab[ev_copper].active = 1;
1.1.1.14! root 2837: eventtab[ev_copper].oldcycles = get_cycles ();
! 2838: eventtab[ev_copper].evtime = get_cycles () + cycle_count * CYCLE_UNIT;
1.1.1.10 root 2839: events_schedule ();
2840: }
2841: }
2842: #endif
1.1 root 2843: }
2844:
1.1.1.9 root 2845: static void compute_spcflag_copper (void)
1.1 root 2846: {
1.1.1.10 root 2847: copper_enabled_thisline = 0;
1.1.1.13 root 2848: unset_special (SPCFLAG_COPPER);
1.1.1.10 root 2849: if (! dmaen (DMA_COPPER) || cop_state.state == COP_stop || cop_state.state == COP_bltwait)
2850: return;
2851:
2852: if (cop_state.state == COP_wait) {
2853: int vp = vpos & (((cop_state.i2 >> 8) & 0x7F) | 0x80);
2854:
2855: if (vp < cop_state.vcmp)
2856: return;
2857: copper_enabled_thisline = 1;
2858:
1.1.1.13 root 2859: if (FAST_COPPER && vp == cop_state.vcmp) {
2860: int hp = cop_state.hpos & (cop_state.i2 & 0xFE);
2861: cop_min_waittime = cop_state.hcmp - hp - 2;
1.1.1.10 root 2862:
2863: /* If possible, compute a minimum waiting time, and set the event
2864: timer if it's sufficiently large to be worthwhile. */
2865: if ((cop_state.i2 & 0xFE) == 0xFE && cop_min_waittime >= 8) {
2866: eventtab[ev_copper].active = 1;
1.1.1.14! root 2867: eventtab[ev_copper].oldcycles = get_cycles ();
! 2868: eventtab[ev_copper].evtime = get_cycles () + cop_min_waittime * CYCLE_UNIT;
1.1.1.10 root 2869: events_schedule ();
2870: return;
2871: }
2872: }
2873: }
2874:
2875: copper_enabled_thisline = 1;
1.1.1.13 root 2876: set_special (SPCFLAG_COPPER);
1.1.1.10 root 2877: }
2878:
2879: static void copper_handler (void)
2880: {
2881: /* This will take effect immediately, within the same cycle. */
1.1.1.13 root 2882: set_special (SPCFLAG_COPPER);
1.1.1.10 root 2883:
2884: if (! copper_enabled_thisline)
2885: abort ();
2886:
2887: if (cop_state.state == COP_wait) {
2888: cop_state.hpos += cop_min_waittime;
2889: if (cop_state.hpos > current_hpos ())
2890: abort ();
2891: }
2892:
2893: eventtab[ev_copper].active = 0;
1.1.1.3 root 2894: }
1.1.1.2 root 2895:
1.1.1.4 root 2896: void blitter_done_notify (void)
1.1 root 2897: {
1.1.1.4 root 2898: if (cop_state.state != COP_bltwait)
2899: return;
1.1.1.10 root 2900:
2901: copper_enabled_thisline = 1;
1.1.1.13 root 2902: set_special (SPCFLAG_COPPER);
1.1.1.9 root 2903: cop_state.state = COP_wait;
1.1.1.2 root 2904: }
2905:
1.1.1.9 root 2906: void do_copper (void)
1.1.1.2 root 2907: {
1.1.1.4 root 2908: int hpos = current_hpos ();
2909: update_copper (hpos);
1.1.1.2 root 2910: }
2911:
1.1.1.13 root 2912: static void sync_copper_with_cpu (int hpos)
2913: {
2914: /* Need to let the copper advance to the current position, but only if it
2915: isn't in a waiting state. */
2916: if (eventtab[ev_copper].active) {
2917: if (cop_state.state != COP_wait) {
2918: eventtab[ev_copper].active = 0;
2919: events_schedule ();
2920: set_special (SPCFLAG_COPPER);
2921: }
2922: }
2923: if (copper_enabled_thisline && ! eventtab[ev_copper].active)
2924: update_copper (hpos);
2925: }
2926:
2927: static void do_sprites (int currvp, int hpos)
1.1.1.4 root 2928: {
2929: int i;
1.1.1.13 root 2930: int maxspr, minspr;
1.1.1.2 root 2931:
1.1.1.4 root 2932: /* I don't know whether this is right. Some programs write the sprite pointers
1.1.1.13 root 2933: * directly at the start of the copper list. With the test against currvp, the
1.1.1.4 root 2934: * first two words of data are read on the second line in the frame. The problem
2935: * occurs when the program jumps to another copperlist a few lines further down
2936: * which _also_ writes the sprite pointer registers. This means that a) writing
2937: * to the sprite pointers sets the state to SPR_restart; or b) that sprite DMA
2938: * is disabled until the end of the vertical blanking interval. The HRM
2939: * isn't clear - it says that the vertical sprite position can be set to any
2940: * value, but this wouldn't be the first mistake... */
2941: /* Update: I modified one of the programs to write the sprite pointers the
2942: * second time only _after_ the VBlank interval, and it showed the same behaviour
2943: * as it did unmodified under UAE with the above check. This indicates that the
2944: * solution below is correct. */
1.1.1.9 root 2945: /* Another update: seems like we have to use the NTSC value here (see Sanity Turmoil
2946: * demo). */
1.1.1.10 root 2947: /* Maximum for Sanity Turmoil: 27.
2948: Minimum for Sanity Arte: 22. */
2949: if (currvp < sprite_vblank_endline)
1.1.1.4 root 2950: return;
1.1.1.3 root 2951:
1.1.1.4 root 2952: /* The graph in the HRM, p. 195 seems to indicate that sprite 0 is
2953: * fetched at cycle 0x14 and thus can't be disabled by bitplane DMA. */
1.1.1.13 root 2954: maxspr = hpos / 4 - 0x14 / 4;
2955: minspr = last_sprite_hpos / 4 - 0x14 / 4;
2956:
2957: if (minspr > 8 || maxspr < 0)
1.1.1.4 root 2958: return;
1.1.1.13 root 2959:
1.1.1.4 root 2960: if (maxspr > 8)
2961: maxspr = 8;
1.1.1.13 root 2962: if (minspr < 0)
2963: minspr = 0;
1.1.1.2 root 2964:
1.1.1.13 root 2965: for (i = minspr; i < maxspr; i++) {
1.1.1.4 root 2966: int fetch = 0;
1.1.1.2 root 2967:
1.1.1.10 root 2968: if (spr[i].on == 0)
1.1.1.4 root 2969: continue;
1.1.1.2 root 2970:
1.1.1.10 root 2971: if (spr[i].state == SPR_restart) {
1.1.1.4 root 2972: fetch = 2;
1.1.1.10 root 2973: spr[i].on = 1;
2974: } else if ((spr[i].state == SPR_waiting_start && spr[i].vstart == vpos) || spr[i].state == SPR_waiting_stop) {
1.1.1.4 root 2975: fetch = 1;
1.1.1.10 root 2976: spr[i].state = SPR_waiting_stop;
1.1.1.2 root 2977: }
1.1.1.10 root 2978: if ((spr[i].state == SPR_waiting_stop || spr[i].state == SPR_waiting_start) && spr[i].vstop == vpos) {
1.1.1.4 root 2979: fetch = 2;
1.1.1.10 root 2980: spr[i].state = SPR_waiting_start;
1.1.1.2 root 2981: }
1.1.1.3 root 2982:
1.1.1.9 root 2983: if (fetch && dmaen (DMA_SPRITE)) {
1.1.1.10 root 2984: uae_u16 data1 = chipmem_bank.wget (spr[i].pt);
2985: uae_u16 data2 = chipmem_bank.wget (spr[i].pt + 2);
2986: spr[i].pt += 4;
1.1.1.3 root 2987:
1.1.1.4 root 2988: if (fetch == 1) {
2989: /* Hack for X mouse auto-calibration */
2990: if (i == 0 && !sprvbfl && ((sprpos[0] & 0xff) << 2) > 2 * DISPLAY_LEFT_SHIFT) {
1.1.1.9 root 2991: spr0ctl = sprctl[0];
2992: spr0pos = sprpos[0];
2993: sprvbfl = 2;
1.1.1.3 root 2994: }
1.1.1.9 root 2995: SPRxDATB_1 (data2, i);
2996: SPRxDATA_1 (data1, i);
1.1.1.4 root 2997: } else {
1.1.1.9 root 2998: SPRxPOS_1 (data1, i);
2999: SPRxCTL_1 (data2, i);
1.1.1.3 root 3000: }
1.1 root 3001: }
3002: }
1.1.1.13 root 3003: last_sprite_hpos = hpos;
1.1 root 3004: }
3005:
1.1.1.4 root 3006: static void init_sprites (void)
1.1 root 3007: {
1.1.1.4 root 3008: int i;
1.1.1.2 root 3009:
1.1.1.4 root 3010: for (i = 0; i < 8; i++) {
3011: /* ???? */
1.1.1.10 root 3012: spr[i].state = SPR_stop;
3013: spr[i].on = 0;
1.1.1.4 root 3014: }
1.1.1.2 root 3015:
1.1.1.4 root 3016: memset (sprpos, 0, sizeof sprpos);
3017: memset (sprctl, 0, sizeof sprctl);
3018: }
1.1.1.2 root 3019:
1.1.1.3 root 3020: static void adjust_array_sizes (void)
1.1.1.2 root 3021: {
3022: #ifdef OS_WITHOUT_MEMORY_MANAGEMENT
1.1.1.13 root 3023: if (delta_sprite_entry) {
1.1.1.3 root 3024: void *p1,*p2;
1.1.1.13 root 3025: int mcc = max_sprite_entry + 50 + delta_sprite_entry;
3026: delta_sprite_entry = 0;
3027: p1 = realloc (sprite_entries[0], mcc * sizeof (struct sprite_entry));
3028: p2 = realloc (sprite_entries[1], mcc * sizeof (struct sprite_entry));
3029: if (p1) sprite_entries[0] = p1;
3030: if (p2) sprite_entries[1] = p2;
1.1.1.3 root 3031: if (p1 && p2) {
1.1.1.13 root 3032: fprintf (stderr, "new max_sprite_entry=%d\n",mcc);
3033: max_sprite_entry = mcc;
1.1.1.2 root 3034: }
3035: }
1.1.1.3 root 3036: if (delta_color_change) {
3037: void *p1,*p2;
3038: int mcc = max_color_change + 200 + delta_color_change;
3039: delta_color_change = 0;
3040: p1 = realloc (color_changes[0], mcc * sizeof (struct color_change));
3041: p2 = realloc (color_changes[1], mcc * sizeof (struct color_change));
3042: if (p1) color_changes[0] = p1;
3043: if (p2) color_changes[1] = p2;
3044: if (p1 && p2) {
3045: fprintf (stderr, "new max_color_change=%d\n",mcc);
1.1.1.2 root 3046: max_color_change = mcc;
1.1.1.3 root 3047: }
3048: }
1.1.1.2 root 3049: #endif
1.1.1.3 root 3050: }
3051:
1.1.1.4 root 3052: static void init_hardware_frame (void)
1.1.1.3 root 3053: {
1.1.1.4 root 3054: next_lineno = 0;
3055: nextline_how = nln_normal;
3056: diwstate = DIW_waiting_start;
3057: hdiwstate = DIW_waiting_start;
3058: }
1.1.1.2 root 3059:
1.1.1.4 root 3060: void init_hardware_for_drawing_frame (void)
3061: {
1.1.1.3 root 3062: adjust_array_sizes ();
3063:
1.1.1.13 root 3064: /* Avoid this code in the first frame after a customreset. */
3065: if (prev_sprite_entries) {
3066: int first_pixel = prev_sprite_entries[0].first_pixel;
3067: int npixels = prev_sprite_entries[prev_next_sprite_entry].first_pixel - first_pixel;
3068: memset (spixels + first_pixel, 0, npixels * sizeof *spixels);
3069: memset (spixstate.bytes + first_pixel, 0, npixels * sizeof *spixstate.bytes);
3070: }
3071: prev_next_sprite_entry = next_sprite_entry;
1.1.1.3 root 3072:
1.1.1.13 root 3073: next_color_change = 0;
3074: next_sprite_entry = 0;
1.1.1.2 root 3075: next_color_entry = 0;
3076: remembered_color_entry = -1;
1.1.1.13 root 3077:
3078: prev_sprite_entries = sprite_entries[current_change_set];
3079: curr_sprite_entries = sprite_entries[current_change_set ^ 1];
1.1.1.2 root 3080: prev_color_changes = color_changes[current_change_set];
3081: curr_color_changes = color_changes[current_change_set ^ 1];
3082: prev_color_tables = color_tables[current_change_set];
3083: curr_color_tables = color_tables[current_change_set ^ 1];
1.1.1.3 root 3084:
1.1.1.2 root 3085: prev_drawinfo = line_drawinfo[current_change_set];
1.1.1.4 root 3086: curr_drawinfo = line_drawinfo[current_change_set ^ 1];
3087: current_change_set ^= 1;
1.1.1.3 root 3088:
1.1.1.4 root 3089: color_src_match = color_dest_match = -1;
1.1.1.13 root 3090:
3091: /* Use both halves of the array in alternating fashion. */
3092: curr_sprite_entries[0].first_pixel = current_change_set * MAX_SPR_PIXELS;
3093: next_sprite_forced = 1;
1.1.1.3 root 3094: }
3095:
1.1.1.2 root 3096: static void vsync_handler (void)
1.1 root 3097: {
1.1.1.12 root 3098: n_frames++;
3099:
1.1.1.4 root 3100: if (currprefs.m68k_speed == -1) {
3101: frame_time_t curr_time = read_processor_time ();
1.1.1.3 root 3102: vsyncmintime += vsynctime;
3103: /* @@@ Mathias? How do you think we should do this? */
3104: /* If we are too far behind, or we just did a reset, adjust the
3105: * needed time. */
1.1.1.4 root 3106: if ((long int)(curr_time - vsyncmintime) > 0 || rpt_did_reset)
1.1.1.3 root 3107: vsyncmintime = curr_time + vsynctime;
1.1.1.4 root 3108: rpt_did_reset = 0;
1.1.1.3 root 3109: }
1.1.1.4 root 3110:
1.1.1.3 root 3111: handle_events ();
1.1 root 3112:
1.1.1.3 root 3113: getjoystate (0, &joy0dir, &joy0button);
3114: getjoystate (1, &joy1dir, &joy1button);
1.1 root 3115:
1.1.1.4 root 3116: INTREQ (0x8020);
1.1.1.3 root 3117: if (bplcon0 & 4)
1.1.1.2 root 3118: lof ^= 0x8000;
1.1.1.3 root 3119:
1.1.1.4 root 3120: vsync_handle_redraw (lof, lof_changed);
3121: if (quit_program > 0)
1.1.1.3 root 3122: return;
3123:
1.1.1.4 root 3124: {
1.1.1.3 root 3125: static int cnt = 0;
3126: if (cnt == 0) {
3127: /* resolution_check_change (); */
3128: DISK_check_change ();
3129: cnt = 5;
3130: }
3131: cnt--;
1.1.1.2 root 3132: }
1.1.1.3 root 3133:
1.1.1.7 root 3134: /* For now, let's only allow this to change at vsync time. It gets too
3135: * hairy otherwise. */
3136: if (beamcon0 != new_beamcon0)
3137: init_hz ();
3138:
1.1.1.2 root 3139: lof_changed = 0;
1.1.1.3 root 3140:
1.1.1.4 root 3141: cop_state.ip = cop1lc;
3142: cop_state.state = COP_read1;
3143: cop_state.vpos = 0;
3144: cop_state.hpos = 0;
3145: cop_state.ignore_next = 0;
3146:
3147: init_hardware_frame ();
3148:
1.1 root 3149: #ifdef HAVE_GETTIMEOFDAY
3150: {
3151: struct timeval tv;
3152: unsigned long int newtime;
1.1.1.3 root 3153:
1.1.1.9 root 3154: gettimeofday (&tv,NULL);
1.1 root 3155: newtime = (tv.tv_sec-seconds_base) * 1000 + tv.tv_usec / 1000;
1.1.1.3 root 3156:
3157: if (!bogusframe) {
1.1.1.6 root 3158: lastframetime = newtime - msecs;
3159:
3160: #if 0 /* This doesn't appear to work too well yet... later. */
3161: if (n_consecutive_skipped > currprefs.sound_pri_cutoff
3162: || lastframetime < currprefs.sound_pri_time)
3163: {
3164: n_consecutive_skipped = 0;
3165: clear_inhibit_frame (IHF_SOUNDADJUST);
3166: } else {
3167: n_consecutive_skipped++;
3168: set_inhibit_frame (IHF_SOUNDADJUST);
3169: total_skipped++;
3170: }
3171: #endif
3172:
3173: frametime += lastframetime;
1.1 root 3174: timeframes++;
1.1.1.6 root 3175:
3176: if ((timeframes & 127) == 0)
3177: gui_fps (1000 * timeframes / frametime);
1.1 root 3178: }
3179: msecs = newtime;
3180: bogusframe = 0;
3181: }
3182: #endif
1.1.1.3 root 3183: if (ievent_alive > 0)
3184: ievent_alive--;
1.1.1.7 root 3185: if (timehack_alive > 0)
3186: timehack_alive--;
1.1 root 3187: CIA_vsync_handler();
3188: }
3189:
1.1.1.4 root 3190: static void hsync_handler (void)
1.1 root 3191: {
1.1.1.10 root 3192: int copper_was_active = eventtab[ev_copper].active;
3193: if (copper_was_active) {
3194: /* Could happen if horizontal wait position is too large. */
3195: eventtab[ev_copper].active = 0;
1.1.1.13 root 3196: /* If this was a sequence of moves, we have to call update_copper if
3197: we don't want to lose them. */
3198: if (cop_state.state != COP_wait) {
1.1.1.10 root 3199: copper_was_active = 0;
1.1.1.13 root 3200: set_special (SPCFLAG_COPPER);
3201: }
1.1.1.10 root 3202: }
3203: if (copper_enabled_thisline && ! copper_was_active)
3204: update_copper (maxhpos);
3205:
1.1.1.2 root 3206: finish_decisions ();
1.1.1.14! root 3207: if (currprefs.collision_level > 0)
1.1.1.13 root 3208: do_sprite_collisions ();
1.1.1.2 root 3209:
1.1.1.5 root 3210: hsync_record_line_state (next_lineno, nextline_how, thisline_changed);
1.1 root 3211:
1.1.1.14! root 3212: eventtab[ev_hsync].evtime += get_cycles () - eventtab[ev_hsync].oldcycles;
! 3213: eventtab[ev_hsync].oldcycles = get_cycles ();
1.1.1.8 root 3214: CIA_hsync_handler ();
1.1.1.11 root 3215: DISK_update ();
1.1.1.3 root 3216:
3217: if (currprefs.produce_sound > 0) {
1.1 root 3218: int nr;
1.1.1.4 root 3219:
3220: update_audio ();
3221:
1.1 root 3222: /* Sound data is fetched at the beginning of each line */
1.1.1.14! root 3223: for (nr = 0; nr < 6; nr++) {
1.1 root 3224: struct audio_channel_data *cdp = audio_channel + nr;
1.1.1.3 root 3225:
1.1 root 3226: if (cdp->data_written == 2) {
3227: cdp->data_written = 0;
3228: cdp->nextdat = chipmem_bank.wget(cdp->pt);
3229: cdp->pt += 2;
3230: if (cdp->state == 2 || cdp->state == 3) {
3231: if (cdp->wlen == 1) {
3232: cdp->pt = cdp->lc;
3233: cdp->wlen = cdp->len;
3234: cdp->intreq2 = 1;
3235: } else
3236: cdp->wlen--;
3237: }
3238: }
3239: }
3240: }
1.1.1.4 root 3241:
3242: hardware_line_completed (next_lineno);
3243:
1.1 root 3244: if (++vpos == (maxvpos + (lof != 0))) {
3245: vpos = 0;
3246: vsync_handler();
3247: }
1.1.1.2 root 3248:
1.1.1.4 root 3249: is_lastline = vpos + 1 == maxvpos + (lof != 0) && currprefs.m68k_speed == -1 && ! rpt_did_reset;
1.1.1.3 root 3250:
1.1.1.4 root 3251: if ((bplcon0 & 4) && currprefs.gfx_linedbl)
3252: notice_interlace_seen ();
1.1.1.2 root 3253:
3254: if (framecnt == 0) {
1.1.1.4 root 3255: int lineno = vpos;
3256: nextline_how = nln_normal;
1.1.1.3 root 3257: if (currprefs.gfx_linedbl) {
1.1 root 3258: lineno *= 2;
1.1.1.5 root 3259: nextline_how = currprefs.gfx_linedbl == 1 ? nln_doubled : nln_nblack;
1.1.1.2 root 3260: if (bplcon0 & 4) {
3261: if (!lof) {
3262: lineno++;
1.1.1.4 root 3263: nextline_how = nln_lower;
1.1.1.2 root 3264: } else {
1.1.1.4 root 3265: nextline_how = nln_upper;
1.1.1.2 root 3266: }
1.1 root 3267: }
3268: }
3269: next_lineno = lineno;
1.1.1.2 root 3270: reset_decisions ();
1.1 root 3271: }
1.1.1.3 root 3272: if (uae_int_requested) {
3273: set_uae_int_flag ();
3274: INTREQ (0xA000);
3275: }
1.1.1.9 root 3276: /* See if there's a chance of a copper wait ending this line. */
3277: cop_state.hpos = 0;
3278: compute_spcflag_copper ();
1.1.1.3 root 3279: }
3280:
3281: static void init_eventtab (void)
3282: {
3283: int i;
3284:
3285: for(i = 0; i < ev_max; i++) {
3286: eventtab[i].active = 0;
3287: eventtab[i].oldcycles = 0;
3288: }
1.1.1.4 root 3289:
1.1.1.3 root 3290: eventtab[ev_cia].handler = CIA_handler;
3291: eventtab[ev_hsync].handler = hsync_handler;
1.1.1.14! root 3292: eventtab[ev_hsync].evtime = maxhpos * CYCLE_UNIT + get_cycles ();
1.1.1.3 root 3293: eventtab[ev_hsync].active = 1;
3294:
1.1.1.10 root 3295: eventtab[ev_copper].handler = copper_handler;
3296: eventtab[ev_copper].active = 0;
1.1.1.3 root 3297: eventtab[ev_blitter].handler = blitter_handler;
3298: eventtab[ev_blitter].active = 0;
1.1.1.11 root 3299: eventtab[ev_disk].handler = DISK_handler;
3300: eventtab[ev_disk].active = 0;
1.1.1.14! root 3301: eventtab[ev_audio].handler = audio_evhandler;
! 3302: eventtab[ev_audio].active = 0;
1.1.1.3 root 3303: events_schedule ();
1.1 root 3304: }
3305:
1.1.1.3 root 3306: void customreset (void)
1.1 root 3307: {
1.1.1.4 root 3308: int i;
1.1.1.11 root 3309: int zero = 0;
1.1 root 3310: #ifdef HAVE_GETTIMEOFDAY
3311: struct timeval tv;
3312: #endif
1.1.1.2 root 3313:
1.1.1.12 root 3314: if ((currprefs.chipset_mask & CSMASK_AGA) == 0) {
1.1.1.11 root 3315: for (i = 0; i < 32; i++) {
3316: current_colors.color_regs_ecs[i] = 0;
3317: current_colors.acolors[i] = xcolors[0];
3318: }
3319: } else {
3320: for (i = 0; i < 256; i++) {
3321: current_colors.color_regs_aga[i] = 0;
3322: current_colors.acolors[i] = CONVERT_RGB (zero);
3323: }
1.1.1.9 root 3324: }
1.1.1.3 root 3325:
1.1.1.12 root 3326: n_frames = 0;
3327:
1.1.1.3 root 3328: expamem_reset ();
1.1.1.4 root 3329:
1.1.1.12 root 3330: DISK_reset ();
1.1.1.3 root 3331: CIA_reset ();
1.1.1.14! root 3332: currcycle = 0;
1.1.1.13 root 3333: unset_special (~(SPCFLAG_BRK | SPCFLAG_MODE_CHANGE));
1.1.1.3 root 3334:
1.1.1.2 root 3335: vpos = 0;
1.1 root 3336: lof = 0;
1.1.1.3 root 3337:
1.1.1.4 root 3338: if (needmousehack ()) {
1.1.1.3 root 3339: #if 0
1.1.1.4 root 3340: mousehack_setfollow();
1.1.1.3 root 3341: #else
1.1.1.4 root 3342: mousehack_setdontcare();
1.1.1.3 root 3343: #endif
1.1 root 3344: } else {
3345: mousestate = normal_mouse;
3346: }
1.1.1.3 root 3347: ievent_alive = 0;
1.1.1.7 root 3348: timehack_alive = 0;
1.1.1.3 root 3349:
3350: clx_sprmask = 0xFF;
3351: clxdat = 0;
3352:
1.1.1.13 root 3353: curr_sprite_entries = 0;
3354: prev_sprite_entries = 0;
3355: sprite_entries[0][0].first_pixel = 0;
3356: sprite_entries[1][0].first_pixel = MAX_SPR_PIXELS;
3357: sprite_entries[0][1].first_pixel = 0;
3358: sprite_entries[1][1].first_pixel = MAX_SPR_PIXELS;
3359: memset (spixels, 0, sizeof spixels);
3360: memset (&spixstate, 0, sizeof spixstate);
3361:
1.1.1.10 root 3362: /* Clear the armed flags of all sprites. */
3363: memset (spr, 0, sizeof spr);
1.1.1.3 root 3364: nr_armed = 0;
1.1 root 3365:
3366: dmacon = intena = 0;
3367: bltstate = BLT_done;
1.1.1.4 root 3368: cop_state.state = COP_stop;
1.1.1.2 root 3369: diwstate = DIW_waiting_start;
1.1.1.3 root 3370: hdiwstate = DIW_waiting_start;
1.1 root 3371: copcon = 0;
1.1.1.11 root 3372: DSKLEN (0, 0);
1.1.1.14! root 3373: currcycle = 0;
1.1.1.3 root 3374:
1.1.1.2 root 3375: bplcon4 = 0x11; /* Get AGA chipset into ECS compatibility mode */
3376: bplcon3 = 0xC00;
1.1.1.14! root 3377: fmode = 0;
! 3378: fetchmode = 0;
! 3379: sprite_width = 16;
1.1 root 3380:
1.1.1.14! root 3381: new_beamcon0 = currprefs.ntscmode ? 0x00 : 0x20;
1.1.1.7 root 3382: init_hz ();
3383:
3384: audio_reset ();
3385:
1.1.1.3 root 3386: init_eventtab ();
1.1.1.2 root 3387:
1.1.1.3 root 3388: init_sprites ();
3389:
1.1.1.2 root 3390: init_hardware_frame ();
1.1.1.4 root 3391: reset_drawing ();
3392:
1.1.1.2 root 3393: reset_decisions ();
1.1.1.3 root 3394:
1.1 root 3395: #ifdef HAVE_GETTIMEOFDAY
1.1.1.4 root 3396: gettimeofday (&tv, NULL);
1.1 root 3397: seconds_base = tv.tv_sec;
3398: bogusframe = 1;
3399: #endif
3400: }
3401:
1.1.1.3 root 3402: void dumpcustom (void)
1.1 root 3403: {
1.1.1.6 root 3404: write_log ("DMACON: %x INTENA: %x INTREQ: %x VPOS: %x HPOS: %x\n", DMACONR(),
3405: (unsigned int)intena, (unsigned int)intreq, (unsigned int)vpos, (unsigned int)current_hpos());
3406: write_log ("COP1LC: %08lx, COP2LC: %08lx\n", (unsigned long)cop1lc, (unsigned long)cop2lc);
1.1.1.13 root 3407: write_log ("DIWSTRT: %04x DIWSTOP: %04x DDFSTRT: %04x DDFSTOP: %04x\n",
3408: (unsigned int)diwstrt, (unsigned int)diwstop, (unsigned int)ddfstrt, (unsigned int)ddfstop);
1.1.1.3 root 3409: if (timeframes) {
1.1.1.6 root 3410: write_log ("Average frame time: %d ms [frames: %d time: %d]\n",
3411: frametime / timeframes, timeframes, frametime);
3412: if (total_skipped)
3413: write_log ("Skipped frames: %d\n", total_skipped);
1.1 root 3414: }
1.1.1.4 root 3415: /*for (i=0; i<256; i++) if (blitcount[i]) fprintf (stderr, "minterm %x = %d\n",i,blitcount[i]); blitter debug */
1.1 root 3416: }
3417:
1.1.1.3 root 3418: int intlev (void)
1.1 root 3419: {
1.1.1.3 root 3420: uae_u16 imask = intreq & intena;
1.1 root 3421: if (imask && (intena & 0x4000)){
3422: if (imask & 0x2000) return 6;
3423: if (imask & 0x1800) return 5;
3424: if (imask & 0x0780) return 4;
3425: if (imask & 0x0070) return 3;
3426: if (imask & 0x0008) return 2;
3427: if (imask & 0x0007) return 1;
3428: }
3429: return -1;
3430: }
3431:
1.1.1.4 root 3432: static void gen_custom_tables (void)
3433: {
3434: int i;
3435: for (i = 0; i < 256; i++) {
3436: unsigned int j;
3437: sprtaba[i] = ((((i >> 7) & 1) << 0)
3438: | (((i >> 6) & 1) << 2)
3439: | (((i >> 5) & 1) << 4)
3440: | (((i >> 4) & 1) << 6)
3441: | (((i >> 3) & 1) << 8)
3442: | (((i >> 2) & 1) << 10)
3443: | (((i >> 1) & 1) << 12)
3444: | (((i >> 0) & 1) << 14));
3445: sprtabb[i] = sprtaba[i] * 2;
1.1.1.13 root 3446: sprite_ab_merge[i] = (((i & 15) ? 1 : 0)
3447: | ((i & 240) ? 2 : 0));
3448:
1.1.1.4 root 3449: for (j = 0; j < 511; j = (j << 1) | 1)
3450: if ((i & ~j) == 0)
3451: waitmasktab[i] = ~j;
3452: }
1.1.1.13 root 3453: for (i = 0; i < 16; i++) {
3454: clxmask[i] = (((i & 1) ? 0xF : 0x3)
3455: | ((i & 2) ? 0xF0 : 0x30)
3456: | ((i & 4) ? 0xF00 : 0x300)
3457: | ((i & 8) ? 0xF000 : 0x3000));
3458: sprclx[i] = (((i & 0x3) == 0x3 ? 1 : 0)
3459: | ((i & 0x5) == 0x5 ? 2 : 0)
3460: | ((i & 0x9) == 0x9 ? 4 : 0)
3461: | ((i & 0x6) == 0x6 ? 8 : 0)
3462: | ((i & 0xA) == 0xA ? 16 : 0)
3463: | ((i & 0xC) == 0xC ? 32 : 0)) << 9;
3464: }
1.1.1.4 root 3465: }
3466:
1.1.1.3 root 3467: void custom_init (void)
1.1 root 3468: {
1.1.1.7 root 3469: uaecptr pos;
3470:
1.1.1.4 root 3471: #ifdef OS_WITHOUT_MEMORY_MANAGEMENT
1.1 root 3472: int num;
1.1.1.2 root 3473:
1.1.1.4 root 3474: for (num = 0; num < 2; num++) {
1.1.1.13 root 3475: sprite_entries[num] = xmalloc (max_sprite_entry * sizeof (struct sprite_entry));
1.1.1.4 root 3476: color_changes[num] = xmalloc (max_color_change * sizeof (struct color_change));
1.1.1.2 root 3477: }
3478: #endif
1.1.1.3 root 3479:
1.1.1.7 root 3480: pos = here ();
3481:
3482: org (0xF0FF70);
3483: calltrap (deftrap (mousehack_helper));
3484: dw (RTS);
3485:
3486: org (0xF0FFA0);
3487: calltrap (deftrap (timehack_helper));
3488: dw (RTS);
3489:
3490: org (pos);
3491:
1.1.1.4 root 3492: gen_custom_tables ();
3493: build_blitfilltable ();
3494:
3495: drawing_init ();
3496:
3497: mousestate = unknown_mouse;
3498:
3499: if (needmousehack ())
3500: mousehack_setfollow();
1.1 root 3501: }
3502:
3503: /* Custom chip memory bank */
3504:
1.1.1.4 root 3505: static uae_u32 custom_lget (uaecptr) REGPARAM;
3506: static uae_u32 custom_wget (uaecptr) REGPARAM;
3507: static uae_u32 custom_bget (uaecptr) REGPARAM;
3508: static void custom_lput (uaecptr, uae_u32) REGPARAM;
3509: static void custom_wput (uaecptr, uae_u32) REGPARAM;
3510: static void custom_bput (uaecptr, uae_u32) REGPARAM;
1.1 root 3511:
3512: addrbank custom_bank = {
3513: custom_lget, custom_wget, custom_bget,
3514: custom_lput, custom_wput, custom_bput,
3515: default_xlate, default_check
3516: };
3517:
1.1.1.13 root 3518: STATIC_INLINE uae_u32 REGPARAM2 custom_wget_1 (uaecptr addr)
1.1 root 3519: {
1.1.1.13 root 3520: special_mem |= S_READ;
1.1.1.4 root 3521: switch (addr & 0x1FE) {
1.1.1.13 root 3522: case 0x002: return DMACONR ();
3523: case 0x004: return VPOSR ();
3524: case 0x006: return VHPOSR ();
3525:
3526: case 0x008: return DSKDATR (current_hpos ());
3527:
3528: case 0x00A: return JOY0DAT ();
3529: case 0x00C: return JOY1DAT ();
3530: case 0x00E: return CLXDAT ();
3531: case 0x010: return ADKCONR ();
3532:
3533: case 0x012: return POT0DAT ();
3534: case 0x016: return POTGOR ();
3535: case 0x018: return SERDATR ();
3536: case 0x01A: return DSKBYTR (current_hpos ());
3537: case 0x01C: return INTENAR ();
3538: case 0x01E: return INTREQR ();
3539: case 0x07C: return DENISEID ();
3540:
3541: case 0x180: case 0x182: case 0x184: case 0x186: case 0x188: case 0x18A:
3542: case 0x18C: case 0x18E: case 0x190: case 0x192: case 0x194: case 0x196:
3543: case 0x198: case 0x19A: case 0x19C: case 0x19E: case 0x1A0: case 0x1A2:
3544: case 0x1A4: case 0x1A6: case 0x1A8: case 0x1AA: case 0x1AC: case 0x1AE:
3545: case 0x1B0: case 0x1B2: case 0x1B4: case 0x1B6: case 0x1B8: case 0x1BA:
3546: case 0x1BC: case 0x1BE:
3547: return COLOR_READ ((addr & 0x3E) / 2);
3548: break;
3549:
1.1 root 3550: default:
1.1.1.13 root 3551: custom_wput (addr, 0);
1.1 root 3552: return 0xffff;
3553: }
3554: }
3555:
1.1.1.13 root 3556: uae_u32 REGPARAM2 custom_wget (uaecptr addr)
3557: {
3558: sync_copper_with_cpu (current_hpos ());
3559: return custom_wget_1 (addr);
3560: }
3561:
1.1.1.3 root 3562: uae_u32 REGPARAM2 custom_bget (uaecptr addr)
1.1 root 3563: {
1.1.1.13 root 3564: special_mem |= S_READ;
3565: return custom_wget (addr & 0xfffe) >> (addr & 1 ? 0 : 8);
1.1 root 3566: }
3567:
1.1.1.3 root 3568: uae_u32 REGPARAM2 custom_lget (uaecptr addr)
1.1 root 3569: {
1.1.1.13 root 3570: special_mem |= S_READ;
3571: return ((uae_u32)custom_wget (addr & 0xfffe) << 16) | custom_wget ((addr + 2) & 0xfffe);
1.1 root 3572: }
3573:
1.1.1.4 root 3574: void REGPARAM2 custom_wput_1 (int hpos, uaecptr addr, uae_u32 value)
1.1 root 3575: {
3576: addr &= 0x1FE;
1.1.1.3 root 3577: switch (addr) {
3578: case 0x020: DSKPTH (value); break;
3579: case 0x022: DSKPTL (value); break;
1.1.1.13 root 3580: case 0x024: DSKLEN (value, hpos); break;
1.1.1.3 root 3581: case 0x026: DSKDAT (value); break;
3582:
3583: case 0x02A: VPOSW (value); break;
3584: case 0x2E: COPCON (value); break;
3585: case 0x030: SERDAT (value); break;
3586: case 0x032: SERPER (value); break;
3587: case 0x34: POTGO (value); break;
3588: case 0x040: BLTCON0 (value); break;
3589: case 0x042: BLTCON1 (value); break;
3590:
3591: case 0x044: BLTAFWM (value); break;
3592: case 0x046: BLTALWM (value); break;
3593:
3594: case 0x050: BLTAPTH (value); break;
3595: case 0x052: BLTAPTL (value); break;
3596: case 0x04C: BLTBPTH (value); break;
3597: case 0x04E: BLTBPTL (value); break;
3598: case 0x048: BLTCPTH (value); break;
3599: case 0x04A: BLTCPTL (value); break;
3600: case 0x054: BLTDPTH (value); break;
3601: case 0x056: BLTDPTL (value); break;
3602:
3603: case 0x058: BLTSIZE (value); break;
3604:
3605: case 0x064: BLTAMOD (value); break;
3606: case 0x062: BLTBMOD (value); break;
3607: case 0x060: BLTCMOD (value); break;
3608: case 0x066: BLTDMOD (value); break;
3609:
3610: case 0x070: BLTCDAT (value); break;
3611: case 0x072: BLTBDAT (value); break;
3612: case 0x074: BLTADAT (value); break;
3613:
3614: case 0x07E: DSKSYNC (value); break;
3615:
3616: case 0x080: COP1LCH (value); break;
3617: case 0x082: COP1LCL (value); break;
3618: case 0x084: COP2LCH (value); break;
3619: case 0x086: COP2LCL (value); break;
3620:
3621: case 0x088: COPJMP1 (value); break;
3622: case 0x08A: COPJMP2 (value); break;
3623:
1.1.1.4 root 3624: case 0x08E: DIWSTRT (hpos, value); break;
3625: case 0x090: DIWSTOP (hpos, value); break;
3626: case 0x092: DDFSTRT (hpos, value); break;
3627: case 0x094: DDFSTOP (hpos, value); break;
1.1.1.3 root 3628:
1.1.1.13 root 3629: case 0x096: DMACON (hpos, value); break;
1.1.1.3 root 3630: case 0x098: CLXCON (value); break;
3631: case 0x09A: INTENA (value); break;
3632: case 0x09C: INTREQ (value); break;
3633: case 0x09E: ADKCON (value); break;
3634:
3635: case 0x0A0: AUDxLCH (0, value); break;
3636: case 0x0A2: AUDxLCL (0, value); break;
3637: case 0x0A4: AUDxLEN (0, value); break;
3638: case 0x0A6: AUDxPER (0, value); break;
3639: case 0x0A8: AUDxVOL (0, value); break;
3640: case 0x0AA: AUDxDAT (0, value); break;
3641:
3642: case 0x0B0: AUDxLCH (1, value); break;
3643: case 0x0B2: AUDxLCL (1, value); break;
3644: case 0x0B4: AUDxLEN (1, value); break;
3645: case 0x0B6: AUDxPER (1, value); break;
3646: case 0x0B8: AUDxVOL (1, value); break;
3647: case 0x0BA: AUDxDAT (1, value); break;
3648:
3649: case 0x0C0: AUDxLCH (2, value); break;
3650: case 0x0C2: AUDxLCL (2, value); break;
3651: case 0x0C4: AUDxLEN (2, value); break;
3652: case 0x0C6: AUDxPER (2, value); break;
3653: case 0x0C8: AUDxVOL (2, value); break;
3654: case 0x0CA: AUDxDAT (2, value); break;
3655:
3656: case 0x0D0: AUDxLCH (3, value); break;
3657: case 0x0D2: AUDxLCL (3, value); break;
3658: case 0x0D4: AUDxLEN (3, value); break;
3659: case 0x0D6: AUDxPER (3, value); break;
3660: case 0x0D8: AUDxVOL (3, value); break;
3661: case 0x0DA: AUDxDAT (3, value); break;
3662:
1.1.1.4 root 3663: case 0x0E0: BPLPTH (hpos, value, 0); break;
3664: case 0x0E2: BPLPTL (hpos, value, 0); break;
3665: case 0x0E4: BPLPTH (hpos, value, 1); break;
3666: case 0x0E6: BPLPTL (hpos, value, 1); break;
3667: case 0x0E8: BPLPTH (hpos, value, 2); break;
3668: case 0x0EA: BPLPTL (hpos, value, 2); break;
3669: case 0x0EC: BPLPTH (hpos, value, 3); break;
3670: case 0x0EE: BPLPTL (hpos, value, 3); break;
3671: case 0x0F0: BPLPTH (hpos, value, 4); break;
3672: case 0x0F2: BPLPTL (hpos, value, 4); break;
3673: case 0x0F4: BPLPTH (hpos, value, 5); break;
3674: case 0x0F6: BPLPTL (hpos, value, 5); break;
1.1.1.6 root 3675: case 0x0F8: BPLPTH (hpos, value, 6); break;
3676: case 0x0FA: BPLPTL (hpos, value, 6); break;
3677: case 0x0FC: BPLPTH (hpos, value, 7); break;
3678: case 0x0FE: BPLPTL (hpos, value, 7); break;
1.1.1.4 root 3679:
3680: case 0x100: BPLCON0 (hpos, value); break;
3681: case 0x102: BPLCON1 (hpos, value); break;
3682: case 0x104: BPLCON2 (hpos, value); break;
3683: case 0x106: BPLCON3 (hpos, value); break;
1.1.1.3 root 3684:
1.1.1.4 root 3685: case 0x108: BPL1MOD (hpos, value); break;
3686: case 0x10A: BPL2MOD (hpos, value); break;
1.1.1.3 root 3687:
1.1.1.13 root 3688: case 0x110: BPL1DAT (hpos, value); break;
1.1.1.3 root 3689: case 0x112: BPL2DAT (value); break;
3690: case 0x114: BPL3DAT (value); break;
3691: case 0x116: BPL4DAT (value); break;
3692: case 0x118: BPL5DAT (value); break;
3693: case 0x11A: BPL6DAT (value); break;
1.1.1.6 root 3694: case 0x11C: BPL7DAT (value); break;
3695: case 0x11E: BPL8DAT (value); break;
1.1 root 3696:
3697: case 0x180: case 0x182: case 0x184: case 0x186: case 0x188: case 0x18A:
3698: case 0x18C: case 0x18E: case 0x190: case 0x192: case 0x194: case 0x196:
3699: case 0x198: case 0x19A: case 0x19C: case 0x19E: case 0x1A0: case 0x1A2:
3700: case 0x1A4: case 0x1A6: case 0x1A8: case 0x1AA: case 0x1AC: case 0x1AE:
3701: case 0x1B0: case 0x1B2: case 0x1B4: case 0x1B6: case 0x1B8: case 0x1BA:
1.1.1.2 root 3702: case 0x1BC: case 0x1BE:
1.1.1.13 root 3703: COLOR_WRITE (hpos, value & 0xFFF, (addr & 0x3E) / 2);
1.1.1.2 root 3704: break;
3705: case 0x120: case 0x124: case 0x128: case 0x12C:
1.1 root 3706: case 0x130: case 0x134: case 0x138: case 0x13C:
1.1.1.4 root 3707: SPRxPTH (hpos, value, (addr - 0x120) / 4);
1.1 root 3708: break;
1.1.1.2 root 3709: case 0x122: case 0x126: case 0x12A: case 0x12E:
1.1 root 3710: case 0x132: case 0x136: case 0x13A: case 0x13E:
1.1.1.4 root 3711: SPRxPTL (hpos, value, (addr - 0x122) / 4);
1.1 root 3712: break;
1.1.1.2 root 3713: case 0x140: case 0x148: case 0x150: case 0x158:
1.1 root 3714: case 0x160: case 0x168: case 0x170: case 0x178:
1.1.1.4 root 3715: SPRxPOS (hpos, value, (addr - 0x140) / 8);
1.1 root 3716: break;
1.1.1.2 root 3717: case 0x142: case 0x14A: case 0x152: case 0x15A:
1.1 root 3718: case 0x162: case 0x16A: case 0x172: case 0x17A:
1.1.1.4 root 3719: SPRxCTL (hpos, value, (addr - 0x142) / 8);
1.1 root 3720: break;
3721: case 0x144: case 0x14C: case 0x154: case 0x15C:
3722: case 0x164: case 0x16C: case 0x174: case 0x17C:
1.1.1.4 root 3723: SPRxDATA (hpos, value, (addr - 0x144) / 8);
1.1 root 3724: break;
1.1.1.2 root 3725: case 0x146: case 0x14E: case 0x156: case 0x15E:
1.1 root 3726: case 0x166: case 0x16E: case 0x176: case 0x17E:
1.1.1.4 root 3727: SPRxDATB (hpos, value, (addr - 0x146) / 8);
1.1 root 3728: break;
1.1.1.3 root 3729:
3730: case 0x36: JOYTEST (value); break;
1.1.1.7 root 3731: case 0x5A: BLTCON0L (value); break;
1.1.1.3 root 3732: case 0x5C: BLTSIZV (value); break;
3733: case 0x5E: BLTSIZH (value); break;
1.1.1.4 root 3734: case 0x1E4: DIWHIGH (hpos, value); break;
3735: case 0x10C: BPLCON4 (hpos, value); break;
1.1.1.7 root 3736: case 0x1FC: FMODE (value); break;
1.1 root 3737: }
3738: }
3739:
1.1.1.4 root 3740: void REGPARAM2 custom_wput (uaecptr addr, uae_u32 value)
3741: {
3742: int hpos = current_hpos ();
1.1.1.13 root 3743: special_mem |= S_WRITE;
3744:
3745: sync_copper_with_cpu (hpos);
1.1.1.4 root 3746: custom_wput_1 (hpos, addr, value);
3747: }
3748:
3749: void REGPARAM2 custom_bput (uaecptr addr, uae_u32 value)
1.1 root 3750: {
1.1.1.2 root 3751: static int warned = 0;
3752: /* Is this correct now? (There are people who bput things to the upper byte of AUDxVOL). */
1.1.1.3 root 3753: uae_u16 rval = (value << 8) | (value & 0xFF);
1.1.1.13 root 3754: special_mem |= S_WRITE;
1.1.1.9 root 3755: custom_wput (addr, rval);
1.1.1.2 root 3756: if (!warned)
1.1.1.3 root 3757: write_log ("Byte put to custom register.\n"), warned++;
1.1 root 3758: }
3759:
1.1.1.3 root 3760: void REGPARAM2 custom_lput(uaecptr addr, uae_u32 value)
1.1 root 3761: {
1.1.1.13 root 3762: special_mem |= S_WRITE;
1.1.1.9 root 3763: custom_wput (addr & 0xfffe, value >> 16);
3764: custom_wput ((addr + 2) & 0xfffe, (uae_u16)value);
1.1 root 3765: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.