|
|
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"
1.1.1.2 root 25: #include "readcpu.h"
1.1 root 26: #include "newcpu.h"
27: #include "cia.h"
28: #include "disk.h"
29: #include "blitter.h"
30: #include "xwin.h"
1.1.1.3 root 31: #include "joystick.h"
32: #include "audio.h"
1.1 root 33: #include "keybuf.h"
34: #include "serial.h"
1.1.1.2 root 35: #include "osemu.h"
1.1.1.3 root 36: #include "autoconf.h"
37: #include "gui.h"
38: #include "picasso96.h"
1.1.1.4 ! root 39: #include "drawing.h"
1.1.1.2 root 40:
1.1.1.3 root 41: #define SPRITE_COLLISIONS
1.1.1.2 root 42:
1.1.1.3 root 43: /* Mouse and joystick emulation */
1.1.1.2 root 44:
1.1.1.3 root 45: int buttonstate[3];
46: static int mouse_x, mouse_y;
47: int joy0button, joy1button;
48: unsigned int joy0dir, joy1dir;
49:
50: /* Events */
1.1 root 51:
1.1.1.4 ! root 52: unsigned long int cycles, nextevent, is_lastline;
! 53: static int rpt_did_reset;
1.1.1.2 root 54: struct ev eventtab[ev_max];
55:
1.1.1.3 root 56: frame_time_t vsynctime, vsyncmintime;
57:
1.1.1.4 ! root 58: static int vpos;
! 59: static uae_u16 lof;
! 60: static int next_lineno;
! 61: static enum nln_how nextline_how;
! 62: static int lof_changed = 0;
1.1 root 63:
1.1.1.2 root 64: static const int dskdelay = 2; /* FIXME: ??? */
1.1 root 65:
1.1.1.3 root 66: static uae_u32 sprtaba[256],sprtabb[256];
67:
1.1.1.2 root 68: /*
69: * Hardware registers of all sorts.
70: */
1.1 root 71:
1.1.1.4 ! root 72: static void custom_wput_1 (int, uaecptr, uae_u32) REGPARAM;
! 73:
1.1 root 74: static int fmode;
75:
1.1.1.3 root 76: static uae_u16 cregs[256];
1.1 root 77:
1.1.1.3 root 78: uae_u16 intena,intreq;
79: uae_u16 dmacon;
80: uae_u16 adkcon; /* used by audio code */
1.1 root 81:
1.1.1.3 root 82: static uae_u32 cop1lc,cop2lc,copcon;
1.1 root 83:
1.1.1.2 root 84: /* This is but an educated guess. It seems to be correct, but this stuff
85: * isn't documented well. */
1.1.1.3 root 86: enum sprstate { SPR_stop, SPR_restart, SPR_waiting_start, SPR_waiting_stop };
87: static enum sprstate sprst[8];
88: static int spron[8];
89: static uaecptr sprpt[8];
1.1.1.2 root 90: static int sprxpos[8], sprvstart[8], sprvstop[8];
1.1 root 91:
1.1.1.3 root 92: static uae_u32 bpl1dat,bpl2dat,bpl3dat,bpl4dat,bpl5dat,bpl6dat,bpl7dat,bpl8dat;
93: static uae_s16 bpl1mod,bpl2mod;
1.1 root 94:
1.1.1.3 root 95: static uaecptr bplpt[8];
1.1.1.2 root 96: #ifndef SMART_UPDATE
97: static char *real_bplpt[8];
98: #endif
1.1 root 99:
100: /*static int blitcount[256]; blitter debug */
101:
1.1.1.2 root 102: static struct color_entry current_colors;
103: static unsigned int bplcon0,bplcon1,bplcon2,bplcon3,bplcon4;
1.1.1.3 root 104: static int nr_planes_from_bplcon0, corrected_nr_planes_from_bplcon0;
1.1.1.4 ! root 105: static unsigned int diwstrt, diwstop, diwhigh;
! 106: static int diwhigh_written;
! 107: static unsigned int ddfstrt, ddfstop;
1.1.1.2 root 108: static unsigned int sprdata[8], sprdatb[8], sprctl[8], sprpos[8];
109: static int sprarmed[8], sprite_last_drawn_at[8];
1.1.1.3 root 110: static int last_sprite_point, nr_armed;
111: static uae_u32 dskpt;
112: static uae_u16 dsklen,dsksync;
1.1.1.4 ! root 113: static int dsklength;
1.1 root 114:
1.1.1.4 ! root 115: /* The display and data fetch windows */
1.1 root 116:
1.1.1.4 ! root 117: enum diw_states
! 118: {
! 119: DIW_waiting_start, DIW_waiting_stop
! 120: };
1.1 root 121:
1.1.1.2 root 122: static int plffirstline,plflastline,plfstrt,plfstop,plflinelen;
1.1.1.4 ! root 123: int diwfirstword,diwlastword;
! 124: static enum diw_states diwstate, hdiwstate;
1.1 root 125:
1.1.1.4 ! root 126: /* Sprite collisions */
! 127: uae_u16 clxdat, clxcon;
! 128: int clx_sprmask;
! 129:
! 130: enum copper_states {
! 131: COP_stop,
! 132: COP_rdelay1, COP_read1, COP_read2,
! 133: COP_bltwait,
! 134: COP_wait1, COP_wait1b, COP_wait2,
! 135: };
! 136:
! 137: struct copper {
! 138: /* The current instruction words. */
! 139: unsigned int i1, i2;
! 140: enum copper_states state;
! 141: /* Instruction pointer. */
! 142: uaecptr ip;
! 143: int hpos, vpos, count;
! 144: unsigned int ignore_next;
! 145: unsigned int do_move;
! 146: enum diw_states vdiw;
! 147: };
! 148:
! 149: static struct copper cop_state;
1.1 root 150:
1.1.1.4 ! root 151: static void prepare_copper_1 (void);
! 152:
! 153: int dskdmaen; /* used in cia.c */
1.1 root 154:
155: /*
156: * Statistics
157: */
158:
1.1.1.2 root 159: /* Used also by bebox.cpp */
160: unsigned long int msecs = 0, frametime = 0, timeframes = 0;
1.1 root 161: static unsigned long int seconds_base;
162: int bogusframe;
163:
1.1.1.4 ! root 164:
! 165: static int current_change_set;
! 166:
! 167: #ifdef OS_WITHOUT_MEMORY_MANAGEMENT
! 168: /* sam: Those arrays uses around 7Mb of BSS... That seems */
! 169: /* too much for AmigaDOS (uae crashes as soon as one loads */
! 170: /* it. So I use a different strategy here (realloc the */
! 171: /* arrays when needed. That strategy might be usefull for */
! 172: /* computer with low memory. */
! 173: struct sprite_draw *sprite_positions[2];
! 174: struct color_change *color_changes[2];
! 175: struct delay_change *delay_changes;
! 176: static int max_sprite_draw = 400;
! 177: static int delta_sprite_draw = 0;
! 178: static int max_color_change = 400;
! 179: static int delta_color_change = 0;
! 180: static int max_delay_change = 100;
! 181: static int delta_delay_change = 0;
! 182: #else
! 183: struct sprite_draw sprite_positions[2][MAX_REG_CHANGE];
! 184: struct color_change color_changes[2][MAX_REG_CHANGE];
! 185: /* We don't remember those across frames, that would be too much effort.
! 186: * We simply redraw the line whenever we see one of these. */
! 187: struct delay_change delay_changes[MAX_REG_CHANGE];
! 188: #endif
! 189:
! 190: struct decision line_decisions[2 * (maxvpos+1) + 1];
! 191: struct draw_info line_drawinfo[2][2 * (maxvpos+1) + 1];
! 192: struct color_entry color_tables[2][(maxvpos+1) * 2];
! 193:
! 194: struct sprite_draw *curr_sprite_positions, *prev_sprite_positions;
! 195: struct color_change *curr_color_changes, *prev_color_changes;
! 196: struct draw_info *curr_drawinfo, *prev_drawinfo;
! 197: struct color_entry *curr_color_tables, *prev_color_tables;
! 198:
! 199: static int next_color_change, next_sprite_draw, next_delay_change;
! 200: static int next_color_entry, remembered_color_entry;
! 201: static int color_src_match, color_dest_match, color_compare_result;
! 202:
! 203: /* These few are only needed during/at the end of the scanline, and don't
! 204: * have to be remembered. */
! 205: static int decided_bpl1mod, decided_bpl2mod, decided_nr_planes, decided_hires;
! 206:
! 207: char line_changed[2 * (maxvpos+1)];
! 208:
! 209: #ifdef SMART_UPDATE
! 210: #define MARK_LINE_CHANGED(l) do { line_changed[l] = 1; } while (0)
! 211: #else
! 212: #define MARK_LINE_CHANGED(l) do { } while (0)
! 213: #endif
! 214:
! 215: static struct decision thisline_decision;
! 216: static int modulos_added, plane_decided, color_decided, very_broken_program;
! 217:
1.1 root 218: /*
219: * helper functions
220: */
221:
1.1.1.4 ! root 222: int rpt_available = 0;
1.1.1.3 root 223:
1.1.1.4 ! root 224: void reset_frame_rate_hack (void)
! 225: {
! 226: if (currprefs.m68k_speed != -1)
! 227: return;
! 228:
! 229: if (! rpt_available) {
! 230: currprefs.m68k_speed = 0;
! 231: return;
! 232: }
1.1.1.3 root 233:
1.1.1.4 ! root 234: rpt_did_reset = 1;
! 235: is_lastline = 0;
! 236: vsyncmintime = read_processor_time() + vsynctime;
! 237: write_log ("Resetting frame rate hack\n");
! 238: }
1.1 root 239:
1.1.1.4 ! root 240: static __inline__ void prepare_copper (void)
1.1 root 241: {
1.1.1.4 ! root 242: if (cop_state.vpos > vpos
! 243: || cop_state.state == COP_stop)
! 244: {
! 245: eventtab[ev_copper].active = 0;
! 246: return;
! 247: }
! 248: prepare_copper_1 ();
1.1.1.3 root 249: }
250:
251: void check_prefs_changed_custom (void)
252: {
253: currprefs.framerate = changed_prefs.framerate;
254: /* Not really the right place... */
255: if (currprefs.fake_joystick != changed_prefs.fake_joystick) {
256: currprefs.fake_joystick = changed_prefs.fake_joystick;
257: joystick_setting_changed ();
1.1 root 258: }
1.1.1.3 root 259: currprefs.immediate_blits = changed_prefs.immediate_blits;
260: currprefs.blits_32bit_enabled = changed_prefs.blits_32bit_enabled;
261:
1.1 root 262: }
263:
1.1.1.3 root 264: static __inline__ void setclr (uae_u16 *p, uae_u16 val)
1.1 root 265: {
266: if (val & 0x8000) {
267: *p |= val & 0x7FFF;
268: } else {
269: *p &= ~val;
270: }
271: }
272:
1.1.1.3 root 273: __inline__ int current_hpos (void)
1.1 root 274: {
275: return cycles - eventtab[ev_hsync].oldcycles;
276: }
277:
1.1.1.3 root 278: static __inline__ uae_u8 *pfield_xlateptr (uaecptr plpt, int bytecount)
1.1.1.2 root 279: {
1.1.1.4 ! root 280: if (!chipmem_bank.check (plpt, bytecount)) {
1.1.1.2 root 281: static int count = 0;
1.1.1.3 root 282: if (!count)
283: count++, write_log ("Warning: Bad playfield pointer\n");
1.1.1.2 root 284: return NULL;
285: }
1.1.1.4 ! root 286: return chipmem_bank.xlateaddr (plpt);
1.1.1.2 root 287: }
288:
1.1.1.3 root 289: static __inline__ void docols(struct color_entry *colentry)
290: {
291: #if AGA_CHIPSET == 0
292: int i;
293: for (i = 0; i < 32; i++) {
294: int v = colentry->color_regs[i];
295: if (v < 0 || v > 4095)
296: continue;
297: colentry->acolors[i] = xcolors[v];
298: }
299: #endif
300: }
301:
302: void notice_new_xcolors (void)
303: {
304: int i;
305:
306: docols(¤t_colors);
1.1.1.4 ! root 307: /* docols(&colors_for_drawing);*/
1.1.1.3 root 308: for (i = 0; i < (maxvpos+1)*2; i++) {
309: docols(color_tables[0]+i);
310: docols(color_tables[1]+i);
311: }
312: }
313:
1.1.1.4 ! root 314: static void do_sprites (int currvp, int currhp);
1.1.1.2 root 315:
316: static void remember_ctable (void)
317: {
318: if (remembered_color_entry == -1) {
319: /* The colors changed since we last recorded a color map. Record a
320: * new one. */
321: memcpy (curr_color_tables + next_color_entry, ¤t_colors, sizeof current_colors);
322: remembered_color_entry = next_color_entry++;
323: }
324: thisline_decision.ctable = remembered_color_entry;
325: if (color_src_match == -1 || color_dest_match != remembered_color_entry
326: || line_decisions[next_lineno].ctable != color_src_match)
327: {
328: /* The remembered comparison didn't help us - need to compare again. */
329: int oldctable = line_decisions[next_lineno].ctable;
330: int changed = 0;
331:
1.1.1.3 root 332: if (oldctable == -1) {
1.1.1.2 root 333: changed = 1;
334: color_src_match = color_dest_match = -1;
335: } else {
1.1.1.3 root 336: color_compare_result = memcmp (&prev_color_tables[oldctable].color_regs,
337: ¤t_colors.color_regs,
338: sizeof current_colors.color_regs) != 0;
339: if (color_compare_result)
340: changed = 1;
341: color_src_match = oldctable;
1.1.1.2 root 342: color_dest_match = remembered_color_entry;
1.1.1.3 root 343: }
344: if (changed) {
345: line_changed[next_lineno] = 1;
346: }
347: } else {
348: /* We know the result of the comparison */
349: if (color_compare_result)
350: line_changed[next_lineno] = 1;
351: }
352: }
353:
354: static void remember_ctable_for_border (void)
355: {
356: remember_ctable ();
1.1.1.2 root 357: }
358:
1.1.1.3 root 359: /* Called to determine the state of the horizontal display window state
360: * machine at the current position. It might have changed since we last
361: * checked. */
1.1.1.4 ! root 362: static void decide_diw (int hpos)
1.1.1.2 root 363: {
1.1.1.3 root 364: if (hdiwstate == DIW_waiting_start && thisline_decision.diwfirstword == -1
1.1.1.4 ! root 365: && PIXEL_XPOS (hpos) >= diwfirstword)
1.1.1.3 root 366: {
1.1.1.2 root 367: thisline_decision.diwfirstword = diwfirstword;
1.1.1.3 root 368: hdiwstate = DIW_waiting_stop;
1.1.1.2 root 369: /* Decide playfield delays only at DIW start, because they don't matter before and
370: * some programs change them after DDF start but before DIW start. */
371: thisline_decision.bplcon1 = bplcon1;
372: if (thisline_decision.diwfirstword != line_decisions[next_lineno].diwfirstword)
373: MARK_LINE_CHANGED (next_lineno);
374: thisline_decision.diwlastword = -1;
375: }
1.1.1.3 root 376: if (hdiwstate == DIW_waiting_stop && thisline_decision.diwlastword == -1
1.1.1.4 ! root 377: && PIXEL_XPOS (hpos) >= diwlastword)
1.1.1.3 root 378: {
1.1.1.2 root 379: thisline_decision.diwlastword = diwlastword;
1.1.1.3 root 380: hdiwstate = DIW_waiting_start;
1.1.1.2 root 381: if (thisline_decision.diwlastword != line_decisions[next_lineno].diwlastword)
382: MARK_LINE_CHANGED (next_lineno);
383: }
384: }
385:
1.1.1.4 ! root 386: /* Called when we know that the line is not in the border and we want to draw
! 387: * it. The data fetch starting position and length are passed as parameters. */
1.1.1.2 root 388: static __inline__ void decide_as_playfield (int startpos, int len)
389: {
390: thisline_decision.which = 1;
391:
392: /* The latter condition might be able to happen in interlaced frames. */
393: if (vpos >= minfirstline && (thisframe_first_drawn_line == -1 || vpos < thisframe_first_drawn_line))
394: thisframe_first_drawn_line = vpos;
395: thisframe_last_drawn_line = vpos;
396:
397: thisline_decision.plfstrt = startpos;
398: thisline_decision.plflinelen = len;
399:
400: /* These are for comparison. */
401: thisline_decision.bplcon0 = bplcon0;
402: thisline_decision.bplcon2 = bplcon2;
403: #if AGA_CHIPSET == 1
404: thisline_decision.bplcon4 = bplcon4;
405: #endif
406:
407: #ifdef SMART_UPDATE
408: if (line_decisions[next_lineno].plfstrt != thisline_decision.plfstrt
409: || line_decisions[next_lineno].plflinelen != thisline_decision.plflinelen
410: || line_decisions[next_lineno].bplcon0 != thisline_decision.bplcon0
411: || line_decisions[next_lineno].bplcon2 != thisline_decision.bplcon2
412: #if AGA_CHIPSET == 1
413: || line_decisions[next_lineno].bplcon4 != thisline_decision.bplcon4
414: #endif
415: )
416: #endif /* SMART_UPDATE */
417: line_changed[next_lineno] = 1;
418: }
419:
1.1.1.3 root 420: /* Called when we already decided whether the line is playfield or border,
421: * but are no longer sure that this was such a good idea. This can make a
1.1.1.4 ! root 422: * difference only for very badly written software.
! 423: *
! 424: * We try to handle two cases:
! 425: * a) bitplane DMA gets turned off during a line which was decided as plane
! 426: * b) bitplane DMA turns on for all or some planes, either after the line was
! 427: * decided as border, or after we made an incorrect nr_planes decision.
! 428: *
! 429: * Examples of programs which need this: Majic 12 "Ray of Hope 2" demo
! 430: * (final large scrolltext) and Masterblazer (menu screen).
! 431: *
! 432: * There's no hope of catching all cases; we'd need a cycle based emulation
! 433: * for that. I'm getting increasingly convinced that that would be a good
! 434: * idea.
! 435: */
! 436: static int broken_plane_sub[8];
! 437:
! 438: static void init_broken_program (void)
1.1.1.2 root 439: {
1.1.1.4 ! root 440: int i;
! 441: if (very_broken_program)
! 442: return;
! 443: very_broken_program = 1;
! 444: for (i = 0; i < 8; i++)
! 445: broken_plane_sub[i] = i >= decided_nr_planes || thisline_decision.which != 1 ? -1 : 0;
! 446: }
! 447:
! 448: static void adjust_broken_program (int hpos)
! 449: {
! 450: int tmp1, tmp2;
! 451: int i;
! 452: if (decided_hires) {
! 453: tmp1 = hpos & 3;
! 454: tmp2 = hpos & ~3;
! 455: } else {
! 456: tmp1 = hpos & 7;
! 457: tmp2 = hpos & ~7;
! 458: }
! 459: for (i = 0; i < decided_nr_planes; i++) {
! 460: if (broken_plane_sub[i] != -1)
! 461: continue;
! 462: if (decided_hires) {
! 463: broken_plane_sub[i] = (tmp2 - thisline_decision.plfstrt) / 4 * 2;
! 464: switch (i) {
! 465: case 3: broken_plane_sub[i] += 2; break; /* @@@ break was missing */
! 466: case 2: broken_plane_sub[i] += (tmp1 >= 3 ? 2 : 0); break;
! 467: case 1: broken_plane_sub[i] += (tmp1 >= 2 ? 2 : 0); break;
! 468: case 0: break;
! 469: }
! 470: } else {
! 471: broken_plane_sub[i] = (tmp2 - thisline_decision.plfstrt) / 8 * 2;
! 472: switch (i) {
! 473: case 5: broken_plane_sub[i] += (tmp1 >= 3 ? 2 : 0); break;
! 474: case 4: broken_plane_sub[i] += (tmp1 >= 7 ? 2 : 0); break;
! 475: case 3: broken_plane_sub[i] += (tmp1 >= 2 ? 2 : 0); break;
! 476: case 2: broken_plane_sub[i] += (tmp1 >= 6 ? 2 : 0); break;
! 477: case 1: broken_plane_sub[i] += (tmp1 >= 4 ? 2 : 0); break;
! 478: case 0: break;
! 479: }
! 480: }
! 481: }
! 482: }
1.1.1.2 root 483:
1.1.1.4 ! root 484: static __inline__ void post_decide_line (int hpos)
! 485: {
! 486: if (thisline_decision.which == 1
! 487: && hpos < thisline_decision.plfstrt + thisline_decision.plflinelen
1.1.1.2 root 488: && ((bplcon0 & 0x7000) == 0 || !dmaen (DMA_BITPLANE)))
489: {
490: /* This is getting gross... */
1.1.1.4 ! root 491: thisline_decision.plflinelen = hpos - thisline_decision.plfstrt;
1.1.1.2 root 492: thisline_decision.plflinelen &= 7;
493: if (thisline_decision.plflinelen == 0)
494: thisline_decision.which = -1;
495: /* ... especially THIS! */
496: modulos_added = 1;
497: return;
498: }
1.1.1.3 root 499:
1.1.1.4 ! root 500: if (diwstate == DIW_waiting_start
! 501: || (bplcon0 & 0x7000) == 0
! 502: || !dmaen (DMA_BITPLANE)
! 503: || hpos >= thisline_decision.plfstrt + thisline_decision.plflinelen)
1.1.1.2 root 504: return;
1.1.1.4 ! root 505:
! 506: if (thisline_decision.which == 1
! 507: && hpos > thisline_decision.plfstrt
! 508: && decided_nr_planes < nr_planes_from_bplcon0)
! 509: {
! 510: decided_hires = (bplcon0 & 0x8000) == 0x8000;
! 511: init_broken_program ();
! 512: decided_nr_planes = nr_planes_from_bplcon0;
! 513: thisline_decision.bplcon0 &= 0xFFF;
! 514: thisline_decision.bplcon0 |= bplcon0 & 0xF000;
! 515: adjust_broken_program (hpos);
! 516: MARK_LINE_CHANGED (next_lineno); /* Play safe. */
! 517: return;
! 518: }
! 519:
! 520: if (thisline_decision.which != -1)
! 521: return;
! 522:
1.1.1.2 root 523: #if 0 /* Can't warn because Kickstart 1.3 does it at reset time ;-) */
1.1.1.4 ! root 524: {
! 525: static int warned = 0;
! 526: if (!warned) {
! 527: write_log ("That program you are running is _really_ broken.\n");
! 528: warned = 1;
! 529: }
1.1.1.2 root 530: }
531: #endif
1.1.1.4 ! root 532: init_broken_program ();
1.1.1.2 root 533:
1.1.1.3 root 534: decided_nr_planes = nr_planes_from_bplcon0;
1.1.1.4 ! root 535: thisline_decision.bplcon0 &= 0xFFF;
! 536: thisline_decision.bplcon0 |= bplcon0 & 0xF000;
1.1.1.2 root 537:
538: MARK_LINE_CHANGED (next_lineno); /* Play safe. */
1.1.1.4 ! root 539: decide_as_playfield (plfstrt, plflinelen);
! 540: adjust_broken_program (hpos);
1.1.1.2 root 541: }
542:
1.1.1.4 ! root 543: static void decide_line_1 (int hpos)
1.1.1.2 root 544: {
1.1.1.4 ! root 545: do_sprites (vpos, hpos);
1.1.1.2 root 546:
547: /* Surprisingly enough, this seems to be correct here - putting this into
548: * decide_diw() results in garbage. */
549: if (diwstate == DIW_waiting_start && vpos == plffirstline) {
550: diwstate = DIW_waiting_stop;
551: }
552: if (diwstate == DIW_waiting_stop && vpos == plflastline) {
553: diwstate = DIW_waiting_start;
554: }
555:
556: if (framecnt != 0) {
557: /* thisline_decision.which = -2; This doesn't do anything but hurt, I think. */
558: return;
559: }
1.1.1.3 root 560:
561: if (!dmaen(DMA_BITPLANE) || diwstate == DIW_waiting_start || nr_planes_from_bplcon0 == 0) {
1.1.1.2 root 562: /* We don't want to draw this one. */
563: thisline_decision.which = -1;
1.1.1.3 root 564: thisline_decision.plfstrt = plfstrt;
565: thisline_decision.plflinelen = plflinelen;
1.1.1.2 root 566: return;
567: }
568:
569: decided_hires = (bplcon0 & 0x8000) == 0x8000;
1.1.1.3 root 570: decided_nr_planes = nr_planes_from_bplcon0;
1.1.1.2 root 571: #if 0
1.1.1.3 root 572: /* The blitter gets slower if there's high bitplane activity.
1.1.1.2 root 573: * @@@ but the values must be different. FIXME */
574: if (bltstate != BLT_done
575: && ((decided_hires && decided_nr_planes > 2)
576: || (!decided_hires && decided_nr_planes > 4)))
577: {
578: int pl = decided_nr_planes;
579: unsigned int n = (eventtab[ev_blitter].evtime-cycles);
580: if (n > plflinelen)
581: n = plflinelen;
582: n >>= 1;
583: if (decided_hires)
584: pl <<= 1;
585: if (pl == 8)
586: eventtab[ev_blitter].evtime += plflinelen;
587: else if (pl == 6)
588: eventtab[ev_blitter].evtime += n*2;
589: else if (pl == 5)
590: eventtab[ev_blitter].evtime += n*3/2;
591: events_schedule();
592: }
593: #endif
594: decide_as_playfield (plfstrt, plflinelen);
595: }
596:
1.1.1.3 root 597: /* Main entry point for deciding how to draw a line. May either do
598: * nothing, decide the line as border, or decide the line as playfield. */
1.1.1.4 ! root 599: static __inline__ void decide_line (int hpos)
1.1.1.2 root 600: {
1.1.1.4 ! root 601: if (thisline_decision.which == 0 && hpos >= plfstrt)
! 602: decide_line_1 (hpos);
1.1.1.2 root 603: }
604:
1.1.1.3 root 605: /* Called when a color is about to be changed (write to a color register),
606: * but the new color has not been entered into the table yet. */
1.1.1.4 ! root 607: static void record_color_change (int hpos, int regno, unsigned long value)
1.1.1.3 root 608: {
609: /* Early positions don't appear on-screen. */
1.1.1.4 ! root 610: if (framecnt != 0 || vpos < minfirstline || hpos < 0x18
1.1.1.3 root 611: /*|| currprefs.emul_accuracy == 0*/)
612: return;
613:
1.1.1.4 ! root 614: decide_diw (hpos);
! 615: decide_line (hpos);
1.1.1.3 root 616:
617: /* See if we can record the color table, but have not done so yet.
618: * @@@ There might be a minimal performance loss in case someone changes
619: * a color exactly at the start of the DIW. I don't think it can actually
620: * fail to work even in this case, but I'm not 100% sure.
621: * @@@ There might be a slightly larger performance loss if we're drawing
622: * this line as border... especially if there are changes in colors != 0
623: * we might end up setting line_changed for no reason. FIXME */
624: if (thisline_decision.diwfirstword >= 0
625: && thisline_decision.which != 0)
626: {
627: if (thisline_decision.ctable == -1)
628: remember_ctable ();
629: }
630:
631: /* Changes outside the DIW can be ignored if the modified color is not the
632: * background color, or if the accuracy is < 2. */
633: if ((regno != 0 || currprefs.emul_accuracy < 2)
634: && (diwstate == DIW_waiting_start || thisline_decision.diwfirstword < 0
635: || thisline_decision.diwlastword >= 0
636: || thisline_decision.which == 0
1.1.1.4 ! root 637: || (thisline_decision.which == 1 && hpos >= thisline_decision.plfstrt + thisline_decision.plflinelen)))
1.1.1.3 root 638: return;
639:
640: /* If the border is changed the first time before the DIW, record the
641: * original starting border value. */
642: if (regno == 0 && thisline_decision.color0 == 0xFFFFFFFFul && thisline_decision.diwfirstword < 0) {
643: thisline_decision.color0 = current_colors.color_regs[0];
644: if (line_decisions[next_lineno].color0 != value)
645: line_changed[next_lineno] = 1;
646: }
647: /* Anything else gets recorded in the color_changes table. */
648: #ifdef OS_WITHOUT_MEMORY_MANAGEMENT
1.1.1.4 ! root 649: if (next_color_change >= max_color_change) {
1.1.1.3 root 650: ++delta_color_change;
651: return;
652: }
653: #endif
1.1.1.4 ! root 654: curr_color_changes[next_color_change].linepos = hpos;
1.1.1.3 root 655: curr_color_changes[next_color_change].regno = regno;
656: curr_color_changes[next_color_change++].value = value;
657: }
658:
659: /* Stupid hack to get some Sanity demos working. */
1.1.1.4 ! root 660: static void decide_delay (int hpos)
1.1.1.2 root 661: {
662: static int warned;
663:
664: /* Don't do anything if we're outside the DIW. */
665: if (thisline_decision.diwfirstword == -1 || thisline_decision.diwlastword > 0)
666: return;
1.1.1.4 ! root 667: decide_line (hpos);
1.1.1.2 root 668: /* Half-hearted attempt to get things right even when post_decide_line() changes
669: * the decision afterwards. */
670: if (thisline_decision.which != 1) {
671: thisline_decision.bplcon1 = bplcon1;
672: return;
673: }
674: /* @@@ Could check here for DDF stopping earlier than DIW */
1.1.1.3 root 675:
676: #ifdef OS_WITHOUT_MEMORY_MANAGEMENT
1.1.1.4 ! root 677: if (next_delay_change >= max_delay_change) {
1.1.1.3 root 678: ++delta_delay_change;
679: return;
680: }
681: #endif
1.1.1.4 ! root 682: delay_changes[next_delay_change].linepos = hpos;
1.1.1.2 root 683: delay_changes[next_delay_change++].value = bplcon1;
684: if (!warned) {
685: warned = 1;
1.1.1.3 root 686: write_log ("Program is torturing BPLCON1.\n");
1.1.1.2 root 687: }
688: }
689:
690: /*
1.1.1.4 ! root 691: * The decision which bitplane pointers to use is not made at plfstrt, since
1.1.1.2 root 692: * data fetch does not start for all planes at this point. Therefore, we wait
693: * for the end of the ddf area or the first write to any of the bitplane
694: * pointer registers, whichever comes last, before we decide which plane pointers
695: * to use.
696: * Call decide_line() before this function.
697: */
1.1.1.4 ! root 698: static void decide_plane (int hpos)
1.1.1.2 root 699: {
700: int i, bytecount;
701:
702: if (framecnt != 0 || plane_decided)
703: return;
704:
705: if (decided_nr_planes == -1 /* Still undecided */
1.1.1.4 ! root 706: || hpos < thisline_decision.plfstrt + thisline_decision.plflinelen)
1.1.1.2 root 707: return;
708:
709: plane_decided = 1;
710:
711: bytecount = plflinelen / (decided_hires ? 4 : 8) * 2;
712:
713: if (bytecount > MAX_WORDS_PER_LINE * 2) {
714: /* Can't happen. */
715: static int warned = 0;
716: if (!warned)
1.1.1.3 root 717: write_log ("Mysterious bug in decide_plane(). Please report.\n");
1.1.1.2 root 718: bytecount = 0;
719: }
720: if (!very_broken_program) {
1.1.1.3 root 721: uae_u8 *dataptr = line_data[next_lineno];
1.1.1.2 root 722: for (i = 0; i < decided_nr_planes; i++, dataptr += MAX_WORDS_PER_LINE*2) {
1.1.1.3 root 723: uaecptr pt = bplpt[i];
724: uae_u8 *real_ptr = pfield_xlateptr(pt, bytecount);
1.1.1.2 root 725: if (real_ptr == NULL)
726: real_ptr = pfield_xlateptr(0, 0);
727: #ifdef SMART_UPDATE
1.1.1.3 root 728: #if 1
729: if (line_changed[next_lineno])
1.1.1.2 root 730: memcpy (dataptr, real_ptr, bytecount);
1.1.1.3 root 731: else
732: #endif
733: line_changed[next_lineno] |= memcmpy (dataptr, real_ptr, bytecount);
1.1.1.2 root 734: #else
735: real_bplpt[i] = real_ptr;
736: #endif
737: }
1.1 root 738: } else {
1.1.1.3 root 739: uae_u8 *dataptr = line_data[next_lineno];
1.1.1.2 root 740: for (i = 0; i < decided_nr_planes; i++, dataptr += MAX_WORDS_PER_LINE*2) {
1.1.1.3 root 741: uaecptr pt = bplpt[i];
742: uae_u8 *real_ptr;
743:
1.1.1.4 ! root 744: pt -= broken_plane_sub[i];
! 745: real_ptr = pfield_xlateptr (pt, bytecount);
1.1.1.2 root 746: if (real_ptr == NULL)
747: real_ptr = pfield_xlateptr(0, 0);
748: #ifdef SMART_UPDATE
749: if (!line_changed[next_lineno])
750: line_changed[next_lineno] |= memcmpy (dataptr, real_ptr, bytecount);
751: else
752: memcpy (dataptr, real_ptr, bytecount);
753: #else
754: real_bplpt[i] = real_ptr;
755: #endif
756: }
757: }
758: }
759:
760: /*
761: * Called from the BPLxMOD routines, after a new value has been written.
762: * This routine decides whether the new value is already relevant for the
763: * current line.
764: */
1.1.1.4 ! root 765: static void decide_modulos (int hpos)
1.1.1.2 root 766: {
767: /* All this effort just for the Sanity WOC demo... */
1.1.1.4 ! root 768: decide_line (hpos);
! 769: if (decided_nr_planes != -1 && hpos >= thisline_decision.plfstrt + thisline_decision.plflinelen)
1.1.1.2 root 770: return;
771: decided_bpl1mod = bpl1mod;
772: decided_bpl2mod = bpl2mod;
773: }
774:
775: /*
1.1.1.3 root 776: * Add the modulos to the bitplane pointers if data fetch is already
777: * finished for the current line.
778: * Call decide_plane() before calling this, so that we won't use the
779: * new values of the plane pointers for the current line.
1.1.1.2 root 780: */
1.1.1.4 ! root 781: static void do_modulos (int hpos)
1.1.1.2 root 782: {
783: /* decided_nr_planes is != -1 if this line should be drawn by the
1.1.1.3 root 784: * display hardware, regardless of whether it fits on the emulated screen.
1.1.1.2 root 785: */
786: if (decided_nr_planes != -1 && plane_decided && !modulos_added
1.1.1.4 ! root 787: && hpos >= thisline_decision.plfstrt + thisline_decision.plflinelen)
1.1.1.2 root 788: {
789: int bytecount = thisline_decision.plflinelen / (decided_hires ? 4 : 8) * 2;
790: int add1 = bytecount + decided_bpl1mod;
791: int add2 = bytecount + decided_bpl2mod;
792:
793: if (!very_broken_program) {
794: switch (decided_nr_planes) {
795: case 8: bplpt[7] += add2;
796: case 7: bplpt[6] += add1;
797: case 6: bplpt[5] += add2;
798: case 5: bplpt[4] += add1;
799: case 4: bplpt[3] += add2;
800: case 3: bplpt[2] += add1;
801: case 2: bplpt[1] += add2;
802: case 1: bplpt[0] += add1;
803: }
1.1.1.4 ! root 804: } else switch (decided_nr_planes) {
! 805: case 8: bplpt[7] += add2 - broken_plane_sub[7];
! 806: case 7: bplpt[6] += add1 - broken_plane_sub[6];
! 807: case 6: bplpt[5] += add2 - broken_plane_sub[5];
! 808: case 5: bplpt[4] += add1 - broken_plane_sub[4];
! 809: case 4: bplpt[3] += add2 - broken_plane_sub[3];
! 810: case 3: bplpt[2] += add1 - broken_plane_sub[2];
! 811: case 2: bplpt[1] += add2 - broken_plane_sub[1];
! 812: case 1: bplpt[0] += add1 - broken_plane_sub[0];
1.1.1.2 root 813: }
814:
815: modulos_added = 1;
816: }
817: }
818:
1.1.1.3 root 819: static __inline__ void record_sprite (int spr, int sprxp)
1.1.1.2 root 820: {
1.1.1.3 root 821: int pos = next_sprite_draw;
822: unsigned int data, datb;
1.1.1.2 root 823:
1.1.1.3 root 824: #ifdef OS_WITHOUT_MEMORY_MANAGEMENT
825: if(pos >= max_sprite_draw) {
826: ++delta_sprite_draw;
1.1.1.2 root 827: return;
1.1.1.3 root 828: }
829: #endif
830: data = sprdata[spr];
831: datb = sprdatb[spr];
1.1.1.2 root 832:
1.1.1.3 root 833: /* XXX FIXME, this isn't very clever, but it might do */
834: for (;;) {
835: if (pos == curr_drawinfo[next_lineno].first_sprite_draw)
836: break;
837: if (curr_sprite_positions[pos-1].linepos < sprxp)
838: break;
839: if (curr_sprite_positions[pos-1].linepos == sprxp
840: && curr_sprite_positions[pos-1].num > spr)
841: break;
842: printf("Foo\n");
843: pos--;
844: }
845: if (pos != next_sprite_draw) {
846: int pos2 = next_sprite_draw;
847: while (pos2 != pos) {
848: curr_sprite_positions[pos2] = curr_sprite_positions[pos2-1];
849: pos2--;
850: }
851: }
852: curr_sprite_positions[pos].linepos = sprxp;
853: curr_sprite_positions[pos].num = spr;
854: curr_sprite_positions[pos].ctl = sprctl[spr];
855: curr_sprite_positions[pos].datab = ((sprtaba[data & 0xFF] << 16) | sprtaba[data >> 8]
856: | (sprtabb[datb & 0xFF] << 16) | sprtabb[datb >> 8]);
857: next_sprite_draw++;
858: }
1.1.1.2 root 859:
1.1.1.4 ! root 860: static void decide_sprites (int hpos)
1.1.1.3 root 861: {
862: int nrs[8], posns[8], count, i;
1.1.1.4 ! root 863: int point = PIXEL_XPOS (hpos);
1.1.1.2 root 864:
1.1.1.4 ! root 865: if (framecnt != 0 || hpos < 0x14 || nr_armed == 0 || point == last_sprite_point)
1.1.1.2 root 866: return;
867:
1.1.1.4 ! root 868: decide_diw (hpos);
! 869: decide_line (hpos);
1.1.1.3 root 870:
871: if (thisline_decision.which != 1)
1.1.1.2 root 872: return;
873:
1.1.1.3 root 874: count = 0;
875: for (i = 0; i < 8; i++) {
876: int sprxp = sprxpos[i];
877: int j, bestp;
1.1.1.2 root 878:
1.1.1.3 root 879: if (!sprarmed[i] || sprxp < 0 || sprxp > point || last_sprite_point >= sprxp)
880: continue;
881: if ((thisline_decision.diwfirstword >= 0 && sprxp + sprite_width < thisline_decision.diwfirstword)
882: || (thisline_decision.diwlastword >= 0 && sprxp > thisline_decision.diwlastword))
883: continue;
1.1.1.2 root 884:
1.1.1.3 root 885: for (bestp = 0; bestp < count; bestp++) {
886: if (posns[bestp] > sprxp)
887: break;
888: if (posns[bestp] == sprxp && nrs[bestp] < i)
889: break;
890: }
891: for (j = count; j > bestp; j--) {
892: posns[j] = posns[j-1];
893: nrs[j] = nrs[j-1];
894: }
895: posns[j] = sprxp;
896: nrs[j] = i;
897: count++;
898: }
899: for (i = 0; i < count; i++)
1.1.1.4 ! root 900: record_sprite (nrs[i], posns[i]);
1.1.1.3 root 901: last_sprite_point = point;
1.1.1.2 root 902: }
903:
1.1.1.3 root 904: /* End of a horizontal scan line. Finish off all decisions that were not
905: * made yet. */
1.1.1.2 root 906: static void finish_decisions (void)
907: {
908: struct draw_info *dip;
909: struct draw_info *dip_old;
910: struct decision *dp;
911: int changed;
1.1.1.4 ! root 912: int hpos = current_hpos ();
1.1.1.2 root 913:
914: if (framecnt != 0)
915: return;
916:
1.1.1.4 ! root 917: decide_diw (hpos);
1.1.1.2 root 918: if (thisline_decision.which == 0)
1.1.1.4 ! root 919: decide_line_1 (hpos);
1.1.1.3 root 920:
921: /* Large DIWSTOP values can cause the stop position never to be
922: * reached, so the state machine always stays in the same state and
923: * there's a more-or-less full-screen DIW. */
924: if (hdiwstate == DIW_waiting_stop) {
925: thisline_decision.diwlastword = max_diwlastword;
926: if (thisline_decision.diwlastword != line_decisions[next_lineno].diwlastword)
927: MARK_LINE_CHANGED (next_lineno);
928: }
929:
1.1.1.2 root 930: if (line_decisions[next_lineno].which != thisline_decision.which)
931: line_changed[next_lineno] = 1;
1.1.1.4 ! root 932: decide_plane (hpos);
1.1.1.2 root 933:
934: dip = curr_drawinfo + next_lineno;
935: dip_old = prev_drawinfo + next_lineno;
936: dp = line_decisions + next_lineno;
937: changed = line_changed[next_lineno];
938:
939: if (thisline_decision.which == 1) {
1.1.1.4 ! root 940: record_diw_line (diwfirstword, diwlastword);
1.1.1.2 root 941:
1.1.1.4 ! root 942: decide_sprites (hpos);
1.1.1.3 root 943:
1.1.1.2 root 944: if (thisline_decision.bplcon1 != line_decisions[next_lineno].bplcon1)
945: changed = 1;
946: }
947:
948: dip->last_color_change = next_color_change;
949: dip->last_delay_change = next_delay_change;
950: dip->last_sprite_draw = next_sprite_draw;
1.1.1.3 root 951:
952: if (thisline_decision.ctable == -1) {
953: if (thisline_decision.which == 1)
954: remember_ctable ();
955: else
956: remember_ctable_for_border ();
957: }
1.1.1.2 root 958: if (thisline_decision.which == -1 && thisline_decision.color0 == 0xFFFFFFFFul)
959: thisline_decision.color0 = current_colors.color_regs[0];
960:
961: dip->nr_color_changes = next_color_change - dip->first_color_change;
962: dip->nr_sprites = next_sprite_draw - dip->first_sprite_draw;
963:
964: if (dip->first_delay_change != dip->last_delay_change)
965: changed = 1;
966: if (!changed
967: && (dip->nr_color_changes != dip_old->nr_color_changes
1.1.1.3 root 968: || (dip->nr_color_changes > 0
969: && memcmp (curr_color_changes + dip->first_color_change,
970: prev_color_changes + dip_old->first_color_change,
971: dip->nr_color_changes * sizeof *curr_color_changes) != 0)))
1.1.1.2 root 972: changed = 1;
973: if (!changed && thisline_decision.which == 1
974: && (dip->nr_sprites != dip_old->nr_sprites
975: || (dip->nr_sprites > 0
1.1.1.3 root 976: && memcmp (curr_sprite_positions + dip->first_sprite_draw,
977: prev_sprite_positions + dip_old->first_sprite_draw,
978: dip->nr_sprites * sizeof *curr_sprite_positions) != 0)))
1.1.1.2 root 979: changed = 1;
980:
981: if (changed) {
982: line_changed[next_lineno] = 1;
983: *dp = thisline_decision;
984: } else
985: /* The only one that may differ: */
986: dp->ctable = thisline_decision.ctable;
987: }
988:
1.1.1.3 root 989: /* Set the state of all decisions to "undecided" for a new scanline. */
1.1.1.2 root 990: static void reset_decisions (void)
991: {
992: if (framecnt != 0)
993: return;
994: thisline_decision.which = 0;
995: decided_bpl1mod = bpl1mod;
996: decided_bpl2mod = bpl2mod;
997: decided_nr_planes = -1;
998:
999: /* decided_hires shouldn't be touched before it's initialized by decide_line(). */
1000: thisline_decision.diwfirstword = -1;
1001: thisline_decision.diwlastword = -2;
1.1.1.3 root 1002: if (hdiwstate == DIW_waiting_stop) {
1003: thisline_decision.diwfirstword = PIXEL_XPOS (DISPLAY_LEFT_SHIFT/2);
1004: if (thisline_decision.diwfirstword != line_decisions[next_lineno].diwfirstword)
1005: MARK_LINE_CHANGED (next_lineno);
1006: }
1.1.1.2 root 1007: thisline_decision.ctable = -1;
1008: thisline_decision.color0 = 0xFFFFFFFFul;
1009:
1010: line_changed[next_lineno] = 0;
1011: curr_drawinfo[next_lineno].first_color_change = next_color_change;
1012: curr_drawinfo[next_lineno].first_delay_change = next_delay_change;
1013: curr_drawinfo[next_lineno].first_sprite_draw = next_sprite_draw;
1014:
1.1.1.3 root 1015: /* memset(sprite_last_drawn_at, 0, sizeof sprite_last_drawn_at); */
1016: last_sprite_point = 0;
1.1.1.2 root 1017: modulos_added = 0;
1018: plane_decided = 0;
1019: color_decided = 0;
1020: very_broken_program = 0;
1021: }
1022:
1.1.1.3 root 1023: /* Initialize the decision array, once before the emulator really starts. */
1.1.1.2 root 1024: static void init_decisions (void)
1025: {
1026: size_t i;
1027: for (i = 0; i < sizeof line_decisions / sizeof *line_decisions; i++) {
1028: line_decisions[i].which = -2;
1.1 root 1029: }
1.1.1.2 root 1030: }
1031:
1.1.1.3 root 1032: /* Calculate display window and data fetch values from the corresponding
1033: * hardware registers. */
1.1.1.2 root 1034: static void calcdiw (void)
1035: {
1.1.1.4 ! root 1036: int hstrt = diwstrt & 0xFF;
! 1037: int hstop = diwstop & 0xFF;
! 1038: int vstrt = diwstrt >> 8;
! 1039: int vstop = diwstop >> 8;
! 1040:
! 1041: if (diwhigh_written) {
! 1042: hstrt |= ((diwhigh >> 5) & 1) << 8;
! 1043: hstop |= ((diwhigh >> 13) & 1) << 8;
! 1044: vstrt |= (diwhigh & 7) << 8;
! 1045: vstop |= ((diwhigh >> 8) & 7) << 8;
! 1046: } else {
! 1047: hstop += 0x100;
! 1048: if ((vstop & 0x80) == 0)
! 1049: vstop |= 0x100;
! 1050: }
! 1051:
! 1052: diwfirstword = coord_hw_to_native_x (hstrt - 1);
! 1053: diwlastword = coord_hw_to_native_x (hstop - 1);
1.1.1.2 root 1054:
1055: if (diwlastword > max_diwlastword)
1056: diwlastword = max_diwlastword;
1057: if (diwfirstword < 0)
1058: diwfirstword = 0;
1059: if (diwlastword < 0)
1060: diwlastword = 0;
1.1.1.3 root 1061:
1.1.1.4 ! root 1062: plffirstline = vstrt;
! 1063: plflastline = vstop;
! 1064:
1.1 root 1065: #if 0
1066: /* This happens far too often. */
1067: if (plffirstline < minfirstline) {
1068: fprintf(stderr, "Warning: Playfield begins before line %d!\n", minfirstline);
1069: plffirstline = minfirstline;
1070: }
1071: #endif
1.1.1.4 ! root 1072:
1.1 root 1073: #if 0 /* Turrican does this */
1074: if (plflastline > 313) {
1.1.1.4 ! root 1075: fprintf (stderr, "Warning: Playfield out of range!\n");
1.1 root 1076: plflastline = 313;
1077: }
1078: #endif
1.1.1.2 root 1079: plfstrt = ddfstrt;
1080: plfstop = ddfstop;
1.1 root 1081: if (plfstrt < 0x18) plfstrt = 0x18;
1.1.1.3 root 1082: if (plfstop < 0x18) plfstop = 0x18;
1.1 root 1083: if (plfstop > 0xD8) plfstop = 0xD8;
1084: if (plfstrt > plfstop) plfstrt = plfstop;
1085:
1086: /* ! If the masking operation is changed, the pfield_doline code could break
1087: * on some systems (alignment) */
1088: /* This actually seems to be correct now, at least the non-AGA stuff... */
1089: plfstrt &= ~3;
1090: plfstop &= ~3;
1.1.1.2 root 1091: /* @@@ Start looking for AGA bugs here... (or maybe even in the above masking ops) */
1.1 root 1092: if ((fmode & 3) == 0)
1093: plflinelen = (plfstop-plfstrt+15) & ~7;
1094: else if ((fmode & 3) == 3)
1095: plflinelen = (plfstop-plfstrt+63) & ~31;
1096: else
1097: plflinelen = (plfstop-plfstrt+31) & ~15;
1098: }
1099:
1.1.1.4 ! root 1100: /* Mousehack stuff */
1.1.1.2 root 1101:
1.1.1.4 ! root 1102: #define defstepx (1<<16)
! 1103: #define defstepy (1<<16)
! 1104: #define defxoffs 0
! 1105: #define defyoffs 0
1.1.1.3 root 1106:
1.1.1.4 ! root 1107: static const int docal = 60, xcaloff = 40, ycaloff = 20;
! 1108: static const int calweight = 3;
! 1109: static int lastsampledmx, lastsampledmy;
! 1110: static int lastspr0x,lastspr0y,lastdiffx,lastdiffy,spr0pos,spr0ctl;
! 1111: static int mstepx,mstepy,xoffs=defxoffs,yoffs=defyoffs;
! 1112: static int sprvbfl;
1.1.1.2 root 1113:
1.1.1.4 ! root 1114: int lastmx, lastmy;
! 1115: int newmousecounters;
! 1116: int ievent_alive = 0;
1.1 root 1117:
1.1.1.4 ! root 1118: static enum { unknown_mouse, normal_mouse, dont_care_mouse, follow_mouse } mousestate;
1.1 root 1119:
1.1.1.4 ! root 1120: static void mousehack_setdontcare (void)
1.1 root 1121: {
1.1.1.4 ! root 1122: if (mousestate == dont_care_mouse)
1.1.1.2 root 1123: return;
1124:
1.1.1.3 root 1125: write_log ("Don't care mouse mode set\n");
1126: mousestate = dont_care_mouse;
1127: lastspr0x = lastmx; lastspr0y = lastmy;
1128: mstepx = defstepx; mstepy = defstepy;
1129: }
1130:
1.1.1.4 ! root 1131: static void mousehack_setfollow (void)
1.1.1.3 root 1132: {
1.1.1.4 ! root 1133: if (mousestate == follow_mouse)
! 1134: return;
! 1135:
1.1.1.3 root 1136: write_log ("Follow sprite mode set\n");
1137: mousestate = follow_mouse;
1138: lastdiffx = lastdiffy = 0;
1139: sprvbfl = 0;
1.1.1.4 ! root 1140: spr0ctl = spr0pos = 0;
1.1.1.3 root 1141: mstepx = defstepx; mstepy = defstepy;
1142: }
1143:
1144: uae_u32 mousehack_helper (void)
1145: {
1146: int mousexpos, mouseypos;
1147:
1148: #ifdef PICASSO96
1149: if (picasso_on) {
1.1.1.4 ! root 1150: mousexpos = lastmx - picasso96_state.XOffset;
! 1151: mouseypos = lastmy - picasso96_state.YOffset;
1.1.1.3 root 1152: } else
1153: #endif
1154: {
1155: if (lastmy >= gfxvidinfo.height)
1.1.1.4 ! root 1156: lastmy = gfxvidinfo.height - 1;
! 1157: mouseypos = coord_native_to_amiga_y (lastmy) << 1;
! 1158: mousexpos = coord_native_to_amiga_x (lastmx);
1.1.1.3 root 1159: }
1160:
1161: switch (m68k_dreg (regs, 0)) {
1162: case 0:
1163: return ievent_alive ? -1 : needmousehack ();
1164: case 1:
1165: ievent_alive = 10;
1166: return mousexpos;
1167: case 2:
1168: return mouseypos;
1169: }
1170: return 0;
1171: }
1172:
1.1.1.4 ! root 1173: void togglemouse (void)
1.1.1.3 root 1174: {
1.1.1.4 ! root 1175: switch (mousestate) {
! 1176: case dont_care_mouse: mousehack_setfollow (); break;
! 1177: case follow_mouse: mousehack_setdontcare (); break;
1.1.1.3 root 1178: default: break; /* Nnnnnghh! */
1179: }
1180: }
1181:
1.1.1.4 ! root 1182: static __inline__ int adjust (int val)
1.1.1.3 root 1183: {
1.1.1.4 ! root 1184: if (val > 127)
1.1.1.3 root 1185: return 127;
1.1.1.4 ! root 1186: else if (val < -127)
1.1.1.3 root 1187: return -127;
1188: return val;
1189: }
1190:
1.1.1.4 ! root 1191: static void do_mouse_hack (void)
1.1.1.3 root 1192: {
1193: int spr0x = ((spr0pos & 0xff) << 2) | ((spr0ctl & 1) << 1);
1194: int spr0y = ((spr0pos >> 8) | ((spr0ctl & 4) << 6)) << 1;
1195: int diffx, diffy;
1196:
1197: if (ievent_alive > 0) {
1198: mouse_x = mouse_y = 0;
1199: return;
1200: }
1201: switch (mousestate) {
1202: case normal_mouse:
1203: diffx = lastmx - lastsampledmx;
1204: diffy = lastmy - lastsampledmy;
1205: if (!newmousecounters) {
1206: if (diffx > 127) diffx = 127;
1207: if (diffx < -127) diffx = -127;
1208: mouse_x += diffx;
1209: if (diffy > 127) diffy = 127;
1210: if (diffy < -127) diffy = -127;
1211: mouse_y += diffy;
1212: }
1213: lastsampledmx += diffx; lastsampledmy += diffy;
1214: break;
1215:
1216: case dont_care_mouse:
1.1.1.4 ! root 1217: diffx = adjust (((lastmx - lastspr0x) * mstepx) >> 16);
! 1218: diffy = adjust (((lastmy - lastspr0y) * mstepy) >> 16);
! 1219: lastspr0x = lastmx; lastspr0y = lastmy;
! 1220: mouse_x += diffx; mouse_y += diffy;
1.1.1.3 root 1221: break;
1222:
1223: case follow_mouse:
1.1.1.4 ! root 1224: if (sprvbfl && sprvbfl-- > 1) {
1.1.1.3 root 1225: int mousexpos, mouseypos;
1226:
1.1.1.4 ! root 1227: if ((lastdiffx > docal || lastdiffx < -docal)
! 1228: && lastspr0x != spr0x
! 1229: && spr0x > plfstrt*4 + 34 + xcaloff
! 1230: && spr0x < plfstop*4 - xcaloff)
1.1.1.3 root 1231: {
1232: int val = (lastdiffx << 16) / (spr0x - lastspr0x);
1.1.1.4 ! root 1233: if (val >= 0x8000)
! 1234: mstepx = (mstepx * (calweight - 1) + val) / calweight;
1.1.1.3 root 1235: }
1.1.1.4 ! root 1236: if ((lastdiffy > docal || lastdiffy < -docal)
! 1237: && lastspr0y != spr0y
! 1238: && spr0y > plffirstline + ycaloff
! 1239: && spr0y < plflastline - ycaloff)
1.1.1.3 root 1240: {
1.1.1.4 ! root 1241: int val = (lastdiffy << 16) / (spr0y - lastspr0y);
! 1242: if (val >= 0x8000)
! 1243: mstepy = (mstepy * (calweight - 1) + val) / calweight;
1.1.1.3 root 1244: }
1245: if (lastmy >= gfxvidinfo.height)
1246: lastmy = gfxvidinfo.height-1;
1.1.1.4 ! root 1247: mouseypos = coord_native_to_amiga_y (lastmy) << 1;
! 1248: mousexpos = coord_native_to_amiga_x (lastmx);
1.1.1.3 root 1249: diffx = adjust ((((mousexpos + xoffs - spr0x) & ~1) * mstepx) >> 16);
1250: diffy = adjust ((((mouseypos + yoffs - spr0y) & ~1) * mstepy) >> 16);
1.1.1.4 ! root 1251: lastspr0x = spr0x; lastspr0y = spr0y;
! 1252: lastdiffx = diffx; lastdiffy = diffy;
! 1253: mouse_x += diffx; mouse_y += diffy;
1.1.1.3 root 1254: }
1255: break;
1.1.1.4 ! root 1256:
! 1257: default:
! 1258: abort ();
1.1.1.3 root 1259: }
1260: }
1261:
1262: /*
1.1 root 1263: * register functions
1264: */
1265:
1.1.1.4 ! root 1266: static __inline__ uae_u16 DMACONR (void)
1.1 root 1267: {
1268: return (dmacon | (bltstate==BLT_done ? 0 : 0x4000)
1269: | (blt_info.blitzero ? 0x2000 : 0));
1270: }
1.1.1.4 ! root 1271: static __inline__ uae_u16 INTENAR (void)
! 1272: {
! 1273: return intena;
! 1274: }
! 1275: uae_u16 INTREQR (void)
1.1 root 1276: {
1.1.1.3 root 1277: return intreq | (currprefs.use_serial ? 0x0001 : 0);
1.1 root 1278: }
1.1.1.4 ! root 1279: static __inline__ uae_u16 ADKCONR (void)
! 1280: {
! 1281: return adkcon;
! 1282: }
! 1283: static __inline__ uae_u16 VPOSR (void)
1.1 root 1284: {
1285: #if AGA_CHIPSET == 1
1286: return (vpos >> 8) | lof | 0x2300;
1287: #elif defined (ECS_AGNUS)
1288: return (vpos >> 8) | lof | 0x2000;
1289: #else
1290: return (vpos >> 8) | lof;
1291: #endif
1292: }
1.1.1.4 ! root 1293: static void VPOSW (uae_u16 v)
1.1.1.2 root 1294: {
1295: if (lof != (v & 0x8000))
1296: lof_changed = 1;
1297: lof = v & 0x8000;
1.1.1.3 root 1298: /*
1299: * This register is much more fun on a real Amiga. You can program
1300: * refresh rates with it ;) But I won't emulate this...
1301: */
1.1.1.2 root 1302: }
1.1 root 1303:
1.1.1.4 ! root 1304: static __inline__ uae_u16 VHPOSR (void)
! 1305: {
! 1306: return (vpos << 8) | current_hpos();
! 1307: }
! 1308:
! 1309: static __inline__ void COP1LCH (uae_u16 v) { cop1lc = (cop1lc & 0xffff) | ((uae_u32)v << 16); }
! 1310: static __inline__ void COP1LCL (uae_u16 v) { cop1lc = (cop1lc & ~0xffff) | (v & 0xfffe); }
! 1311: static __inline__ void COP2LCH (uae_u16 v) { cop2lc = (cop2lc & 0xffff) | ((uae_u32)v << 16); }
! 1312: static __inline__ void COP2LCL (uae_u16 v) { cop2lc = (cop2lc & ~0xffff) | (v & 0xfffe); }
! 1313:
! 1314: static void COPJMP1 (uae_u16 a)
! 1315: {
! 1316: cop_state.ip = cop1lc;
! 1317: cop_state.do_move = 0;
! 1318: cop_state.ignore_next = 0;
! 1319: cop_state.state = COP_read1;
! 1320: cop_state.vpos = vpos;
! 1321: cop_state.hpos = current_hpos () & ~1;
! 1322: cop_state.count = current_hpos () & ~1;
! 1323: prepare_copper ();
! 1324: if (eventtab[ev_copper].evtime == cycles && eventtab[ev_copper].active)
! 1325: abort ();
! 1326: events_schedule ();
! 1327: }
! 1328:
! 1329: static void COPJMP2 (uae_u16 a)
! 1330: {
! 1331: cop_state.ip = cop2lc;
! 1332: cop_state.do_move = 0;
! 1333: cop_state.ignore_next = 0;
! 1334: cop_state.state = COP_read1;
! 1335: cop_state.vpos = vpos;
! 1336: cop_state.hpos = current_hpos () & ~1;
! 1337: cop_state.count = current_hpos () & ~1;
! 1338: prepare_copper ();
! 1339: if (eventtab[ev_copper].evtime == cycles && eventtab[ev_copper].active)
! 1340: abort ();
! 1341: events_schedule ();
! 1342: }
! 1343:
! 1344: static __inline__ void COPCON (uae_u16 a)
! 1345: {
! 1346: copcon = a;
1.1 root 1347: }
1.1.1.4 ! root 1348:
! 1349: static void DMACON (uae_u16 v)
1.1 root 1350: {
1351: int i, need_resched = 0;
1352:
1.1.1.3 root 1353: uae_u16 oldcon = dmacon;
1354:
1.1.1.4 ! root 1355: decide_line (current_hpos ());
1.1 root 1356: setclr(&dmacon,v); dmacon &= 0x1FFF;
1.1.1.3 root 1357: /* ??? post_decide_line (); */
1358:
1359: /* FIXME? Maybe we need to think a bit more about the master DMA enable
1.1 root 1360: * bit in these cases. */
1.1.1.3 root 1361: if ((dmacon & DMA_COPPER) > (oldcon & DMA_COPPER)) {
1.1.1.4 ! root 1362: cop_state.ip = cop1lc;
! 1363: cop_state.do_move = 0;
! 1364: cop_state.ignore_next = 0;
! 1365: cop_state.state = COP_read1;
! 1366: cop_state.vpos = vpos;
! 1367: cop_state.hpos = current_hpos () & ~1;
! 1368: cop_state.count = current_hpos () & ~1;
! 1369: prepare_copper ();
! 1370: if (eventtab[ev_copper].evtime == cycles && eventtab[ev_copper].active)
! 1371: abort ();
! 1372: need_resched = 1;
1.1 root 1373: }
1374: if ((dmacon & DMA_BLITPRI) > (oldcon & DMA_BLITPRI) && bltstate != BLT_done) {
1375: static int count = 0;
1376: if (!count) {
1377: count = 1;
1.1.1.3 root 1378: write_log ("warning: program is doing blitpri hacks.\n");
1.1 root 1379: }
1380: regs.spcflags |= SPCFLAG_BLTNASTY;
1381: }
1.1.1.4 ! root 1382:
! 1383: update_audio ();
! 1384:
1.1 root 1385: for (i = 0; i < 4; i++) {
1386: struct audio_channel_data *cdp = audio_channel + i;
1.1.1.3 root 1387:
1.1 root 1388: cdp->dmaen = (dmacon & 0x200) && (dmacon & (1<<i));
1389: if (cdp->dmaen) {
1390: if (cdp->state == 0) {
1391: cdp->state = 1;
1392: cdp->pt = cdp->lc;
1393: cdp->wper = cdp->per;
1394: cdp->wlen = cdp->len;
1395: cdp->data_written = 2;
1.1.1.4 ! root 1396: cdp->evtime = eventtab[ev_hsync].evtime - cycles;
1.1 root 1397: }
1398: } else {
1399: if (cdp->state == 1 || cdp->state == 5) {
1400: cdp->state = 0;
1401: cdp->current_sample = 0;
1402: }
1403: }
1404: }
1.1.1.4 ! root 1405:
1.1 root 1406: if (need_resched)
1407: events_schedule();
1408: }
1.1.1.2 root 1409:
1.1.1.3 root 1410: /*static int trace_intena = 0;*/
1.1.1.2 root 1411:
1.1.1.3 root 1412: static __inline__ void INTENA (uae_u16 v)
1.1.1.2 root 1413: {
1.1.1.3 root 1414: /* if (trace_intena)
1.1.1.4 ! root 1415: fprintf (stderr, "INTENA: %04x\n", v);*/
1.1.1.3 root 1416: setclr(&intena,v); regs.spcflags |= SPCFLAG_INT;
1.1.1.2 root 1417: }
1.1.1.3 root 1418: void INTREQ (uae_u16 v)
1.1 root 1419: {
1.1.1.3 root 1420: setclr(&intreq,v);
1421: regs.spcflags |= SPCFLAG_INT;
1.1.1.4 ! root 1422: if (( v & 0x8800) == 0x0800)
! 1423: serdat &= 0xbfff;
1.1.1.3 root 1424: }
1.1 root 1425:
1.1.1.3 root 1426: static void ADKCON (uae_u16 v)
1427: {
1428: unsigned long t;
1.1.1.4 ! root 1429:
! 1430: update_audio ();
! 1431:
1.1.1.3 root 1432: setclr (&adkcon,v);
1433: t = adkcon | (adkcon >> 4);
1434: audio_channel[0].adk_mask = (((t >> 0) & 1) - 1);
1435: audio_channel[1].adk_mask = (((t >> 1) & 1) - 1);
1436: audio_channel[2].adk_mask = (((t >> 2) & 1) - 1);
1437: audio_channel[3].adk_mask = (((t >> 3) & 1) - 1);
1438: }
1.1 root 1439:
1.1.1.4 ! root 1440: static void BPLPTH (int hpos, uae_u16 v, int num)
1.1.1.3 root 1441: {
1.1.1.4 ! root 1442: decide_line (hpos);
! 1443: decide_plane (hpos);
! 1444: do_modulos (hpos);
! 1445: bplpt[num] = (bplpt[num] & 0xffff) | ((uae_u32)v << 16);
1.1.1.3 root 1446: }
1.1.1.4 ! root 1447: static void BPLPTL (int hpos, uae_u16 v, int num)
1.1.1.3 root 1448: {
1.1.1.4 ! root 1449: decide_line (hpos);
! 1450: decide_plane (hpos);
! 1451: do_modulos (hpos);
! 1452: bplpt[num] = (bplpt[num] & ~0xffff) | (v & 0xfffe);
1.1.1.3 root 1453: }
1.1 root 1454:
1.1.1.4 ! root 1455: static void BPLCON0 (int hpos, uae_u16 v)
1.1 root 1456: {
1.1.1.2 root 1457: #if AGA_CHIPSET == 0
1458: v &= 0xFF0E;
1459: /* The Sanity WOC demo needs this at one place (at the end of the "Party Effect")
1460: * Disable bitplane DMA if someone tries to do more than 4 Hires bitplanes. */
1461: if ((v & 0xF000) > 0xC000)
1462: v &= 0xFFF;
1463: /* Don't want 7 lores planes either. */
1464: if ((v & 0x8000) == 0 && (v & 0x7000) == 0x7000)
1465: v &= 0xEFFF;
1466: #endif
1467: if (bplcon0 == v)
1.1 root 1468: return;
1.1.1.4 ! root 1469: decide_line (hpos);
1.1.1.2 root 1470: bplcon0 = v;
1.1.1.3 root 1471: nr_planes_from_bplcon0 = (bplcon0 >> 12) & 7;
1472: corrected_nr_planes_from_bplcon0 = ((bplcon0 >> 12) & 7) << (bplcon0 & 0x8000 ? 1 : 0);
1.1.1.4 ! root 1473: post_decide_line (hpos);
1.1 root 1474: }
1.1.1.4 ! root 1475: static __inline__ void BPLCON1 (int hpos, uae_u16 v)
1.1 root 1476: {
1.1.1.2 root 1477: if (bplcon1 == v)
1.1 root 1478: return;
1.1.1.4 ! root 1479: decide_diw (hpos);
1.1.1.2 root 1480: bplcon1 = v;
1.1.1.4 ! root 1481: decide_delay (hpos);
1.1 root 1482: }
1.1.1.4 ! root 1483: static __inline__ void BPLCON2 (int hpos, uae_u16 v)
1.1 root 1484: {
1.1.1.2 root 1485: if (bplcon2 != v)
1.1.1.4 ! root 1486: decide_line (hpos);
1.1.1.2 root 1487: bplcon2 = v;
1.1 root 1488: }
1.1.1.4 ! root 1489: static __inline__ void BPLCON3 (int hpos, uae_u16 v)
1.1 root 1490: {
1.1.1.2 root 1491: if (bplcon3 != v)
1.1.1.4 ! root 1492: decide_line (hpos);
1.1.1.3 root 1493: bplcon3 = v;
1.1 root 1494: }
1.1.1.4 ! root 1495: static __inline__ void BPLCON4 (int hpos, uae_u16 v)
1.1 root 1496: {
1.1.1.2 root 1497: if (bplcon4 != v)
1.1.1.4 ! root 1498: decide_line (hpos);
1.1.1.3 root 1499: bplcon4 = v;
1.1 root 1500: }
1501:
1.1.1.4 ! root 1502: static void BPL1MOD (int hpos, uae_u16 v)
1.1 root 1503: {
1504: v &= ~1;
1.1.1.3 root 1505: if ((uae_s16)bpl1mod == (uae_s16)v)
1.1 root 1506: return;
1507: bpl1mod = v;
1.1.1.4 ! root 1508: decide_modulos (hpos);
1.1 root 1509: }
1.1.1.2 root 1510:
1.1.1.4 ! root 1511: static void BPL2MOD (int hpos, uae_u16 v)
1.1.1.3 root 1512: {
1.1 root 1513: v &= ~1;
1.1.1.3 root 1514: if ((uae_s16)bpl2mod == (uae_s16)v)
1.1 root 1515: return;
1516: bpl2mod = v;
1.1.1.4 ! root 1517: decide_modulos (hpos);
1.1 root 1518: }
1519:
1.1.1.2 root 1520: /* We could do as well without those... */
1.1.1.3 root 1521: static __inline__ void BPL1DAT (uae_u16 v) { bpl1dat = v; }
1522: static __inline__ void BPL2DAT (uae_u16 v) { bpl2dat = v; }
1523: static __inline__ void BPL3DAT (uae_u16 v) { bpl3dat = v; }
1524: static __inline__ void BPL4DAT (uae_u16 v) { bpl4dat = v; }
1525: static __inline__ void BPL5DAT (uae_u16 v) { bpl5dat = v; }
1526: static __inline__ void BPL6DAT (uae_u16 v) { bpl6dat = v; }
1.1 root 1527:
1.1.1.4 ! root 1528: static void DIWSTRT (int hpos, uae_u16 v)
1.1 root 1529: {
1.1.1.4 ! root 1530: if (diwstrt == v && ! diwhigh_written)
1.1 root 1531: return;
1.1.1.4 ! root 1532: decide_line (hpos);
! 1533: diwhigh_written = 0;
1.1.1.3 root 1534: diwstrt = v;
1.1.1.4 ! root 1535: calcdiw ();
1.1 root 1536: }
1.1.1.4 ! root 1537:
! 1538: static void DIWSTOP (int hpos, uae_u16 v)
1.1 root 1539: {
1.1.1.4 ! root 1540: if (diwstop == v && ! diwhigh_written)
1.1 root 1541: return;
1.1.1.4 ! root 1542: decide_line (hpos);
! 1543: diwhigh_written = 0;
1.1.1.3 root 1544: diwstop = v;
1.1.1.4 ! root 1545: calcdiw ();
! 1546: }
! 1547:
! 1548: static void DIWHIGH (int hpos, uae_u16 v)
! 1549: {
! 1550: if (diwhigh_written && diwhigh == v)
! 1551: return;
! 1552: decide_line (hpos);
! 1553: diwhigh_written = 1;
! 1554: diwhigh = v;
! 1555: calcdiw ();
1.1 root 1556: }
1.1.1.4 ! root 1557:
! 1558: static void DDFSTRT (int hpos, uae_u16 v)
1.1.1.3 root 1559: {
1.1.1.2 root 1560: v &= 0xFF;
1561: if (ddfstrt == v)
1.1 root 1562: return;
1.1.1.4 ! root 1563: decide_line (hpos);
1.1.1.3 root 1564: ddfstrt = v;
1.1.1.4 ! root 1565: calcdiw ();
1.1 root 1566: }
1.1.1.4 ! root 1567: static void DDFSTOP (int hpos, uae_u16 v)
1.1.1.3 root 1568: {
1.1.1.2 root 1569: v &= 0xFF;
1570: if (ddfstop == v)
1.1 root 1571: return;
1.1.1.4 ! root 1572: decide_line (hpos);
1.1.1.2 root 1573: ddfstop = v;
1.1.1.4 ! root 1574: calcdiw ();
1.1 root 1575: }
1576:
1.1.1.4 ! root 1577: static void BLTADAT (uae_u16 v)
1.1 root 1578: {
1.1.1.2 root 1579: maybe_blit();
1580:
1581: blt_info.bltadat = v;
1.1 root 1582: }
1.1.1.2 root 1583: /*
1584: * "Loading data shifts it immediately" says the HRM. Well, that may
1585: * be true for BLTBDAT, but not for BLTADAT - it appears the A data must be
1586: * loaded for every word so that AFWM and ALWM can be applied.
1587: */
1.1.1.4 ! root 1588: static void BLTBDAT (uae_u16 v)
1.1 root 1589: {
1.1.1.3 root 1590: maybe_blit();
1.1.1.2 root 1591:
1592: if (bltcon1 & 2)
1593: blt_info.bltbhold = v << (bltcon1 >> 12);
1594: else
1595: blt_info.bltbhold = v >> (bltcon1 >> 12);
1596: blt_info.bltbdat = v;
1.1 root 1597: }
1.1.1.4 ! root 1598: static void BLTCDAT (uae_u16 v) { maybe_blit (); blt_info.bltcdat = v; }
1.1 root 1599:
1.1.1.4 ! root 1600: static void BLTAMOD (uae_u16 v) { maybe_blit (); blt_info.bltamod = (uae_s16)(v & 0xFFFE); }
! 1601: static void BLTBMOD (uae_u16 v) { maybe_blit (); blt_info.bltbmod = (uae_s16)(v & 0xFFFE); }
! 1602: static void BLTCMOD (uae_u16 v) { maybe_blit (); blt_info.bltcmod = (uae_s16)(v & 0xFFFE); }
! 1603: static void BLTDMOD (uae_u16 v) { maybe_blit (); blt_info.bltdmod = (uae_s16)(v & 0xFFFE); }
1.1 root 1604:
1.1.1.4 ! root 1605: static void BLTCON0 (uae_u16 v) { maybe_blit (); bltcon0 = v; blinea_shift = v >> 12; }
1.1.1.3 root 1606: /* The next category is "Most useless hardware register".
1.1 root 1607: * And the winner is... */
1.1.1.4 ! root 1608: static void BLTCON0L (uae_u16 v) { maybe_blit (); bltcon0 = (bltcon0 & 0xFF00) | (v & 0xFF); }
! 1609: static void BLTCON1 (uae_u16 v) { maybe_blit (); bltcon1 = v; }
! 1610:
! 1611: static void BLTAFWM (uae_u16 v) { maybe_blit (); blt_info.bltafwm = v; }
! 1612: static void BLTALWM (uae_u16 v) { maybe_blit (); blt_info.bltalwm = v; }
1.1 root 1613:
1.1.1.4 ! root 1614: static void BLTAPTH (uae_u16 v) { maybe_blit (); bltapt = (bltapt & 0xffff) | ((uae_u32)v << 16); }
! 1615: static void BLTAPTL (uae_u16 v) { maybe_blit (); bltapt = (bltapt & ~0xffff) | (v & 0xFFFE); }
! 1616: static void BLTBPTH (uae_u16 v) { maybe_blit (); bltbpt = (bltbpt & 0xffff) | ((uae_u32)v << 16); }
! 1617: static void BLTBPTL (uae_u16 v) { maybe_blit (); bltbpt = (bltbpt & ~0xffff) | (v & 0xFFFE); }
! 1618: static void BLTCPTH (uae_u16 v) { maybe_blit (); bltcpt = (bltcpt & 0xffff) | ((uae_u32)v << 16); }
! 1619: static void BLTCPTL (uae_u16 v) { maybe_blit (); bltcpt = (bltcpt & ~0xffff) | (v & 0xFFFE); }
! 1620: static void BLTDPTH (uae_u16 v) { maybe_blit (); bltdpt = (bltdpt & 0xffff) | ((uae_u32)v << 16); }
! 1621: static void BLTDPTL (uae_u16 v) { maybe_blit (); bltdpt = (bltdpt & ~0xffff) | (v & 0xFFFE); }
1.1 root 1622:
1.1.1.4 ! root 1623: static void BLTSIZE (uae_u16 v)
1.1 root 1624: {
1625: bltsize = v;
1.1.1.3 root 1626:
1.1.1.4 ! root 1627: maybe_blit ();
1.1 root 1628:
1629: blt_info.vblitsize = bltsize >> 6;
1630: blt_info.hblitsize = bltsize & 0x3F;
1631: if (!blt_info.vblitsize) blt_info.vblitsize = 1024;
1632: if (!blt_info.hblitsize) blt_info.hblitsize = 64;
1.1.1.3 root 1633:
1634: bltstate = BLT_init;
1.1.1.4 ! root 1635: do_blitter ();
1.1 root 1636: }
1.1.1.4 ! root 1637:
! 1638: static void BLTSIZV (uae_u16 v)
1.1 root 1639: {
1.1.1.4 ! root 1640: maybe_blit ();
1.1 root 1641: oldvblts = v & 0x7FFF;
1642: }
1.1.1.4 ! root 1643:
! 1644: static void BLTSIZH (uae_u16 v)
1.1 root 1645: {
1.1.1.4 ! root 1646: maybe_blit ();
1.1 root 1647: blt_info.hblitsize = v & 0x7FF;
1648: blt_info.vblitsize = oldvblts;
1649: if (!blt_info.vblitsize) blt_info.vblitsize = 32768;
1650: if (!blt_info.hblitsize) blt_info.hblitsize = 0x800;
1.1.1.2 root 1651: bltstate = BLT_init;
1652: do_blitter();
1.1 root 1653: }
1.1.1.4 ! root 1654:
! 1655: static __inline__ void SPRxCTL_1 (uae_u16 v, int num)
1.1 root 1656: {
1.1.1.2 root 1657: int sprxp;
1658: sprctl[num] = v;
1.1.1.3 root 1659: nr_armed -= sprarmed[num];
1.1.1.2 root 1660: sprarmed[num] = 0;
1.1.1.3 root 1661: if (sprpos[num] == 0 && v == 0) {
1662: sprst[num] = SPR_stop;
1663: spron[num] = 0;
1664: } else
1665: sprst[num] = SPR_waiting_start;
1.1.1.2 root 1666:
1.1.1.4 ! root 1667: sprxp = coord_hw_to_native_x ((sprpos[num] & 0xFF) * 2 + (v & 1));
1.1.1.2 root 1668: sprxpos[num] = sprxp;
1669: sprvstart[num] = (sprpos[num] >> 8) | ((sprctl[num] << 6) & 0x100);
1670: sprvstop[num] = (sprctl[num] >> 8) | ((sprctl[num] << 7) & 0x100);
1671: }
1.1.1.4 ! root 1672: static __inline__ void SPRxPOS_1 (uae_u16 v, int num)
1.1.1.2 root 1673: {
1674: int sprxp;
1675: sprpos[num] = v;
1.1.1.4 ! root 1676: sprxp = coord_hw_to_native_x ((v & 0xFF) * 2 + (sprctl[num] & 1));
1.1.1.2 root 1677: sprxpos[num] = sprxp;
1678: sprvstart[num] = (sprpos[num] >> 8) | ((sprctl[num] << 6) & 0x100);
1679: }
1.1.1.4 ! root 1680: static __inline__ void SPRxDATA_1 (uae_u16 v, int num)
1.1.1.2 root 1681: {
1682: sprdata[num] = v;
1.1.1.3 root 1683: nr_armed += 1 - sprarmed[num];
1.1.1.2 root 1684: sprarmed[num] = 1;
1685: }
1.1.1.4 ! root 1686: static __inline__ void SPRxDATB_1 (uae_u16 v, int num)
1.1.1.2 root 1687: {
1688: sprdatb[num] = v;
1689: }
1.1.1.4 ! root 1690: static void SPRxDATA (int hpos, uae_u16 v, int num) { decide_sprites (hpos); SPRxDATA_1 (v, num); }
! 1691: static void SPRxDATB (int hpos, uae_u16 v, int num) { decide_sprites (hpos); SPRxDATB_1 (v, num); }
! 1692: static void SPRxCTL (int hpos, uae_u16 v, int num) { decide_sprites (hpos); SPRxCTL_1 (v, num); }
! 1693: static void SPRxPOS (int hpos, uae_u16 v, int num) { decide_sprites (hpos); SPRxPOS_1 (v, num); }
! 1694: static void SPRxPTH (int hpos, uae_u16 v, int num)
1.1 root 1695: {
1.1.1.4 ! root 1696: decide_sprites (hpos);
1.1.1.3 root 1697: sprpt[num] &= 0xffff;
1698: sprpt[num] |= (uae_u32)v << 16;
1699:
1700: if (sprst[num] == SPR_stop || vpos < vblank_endline)
1701: sprst[num] = SPR_restart;
1702: spron[num] = 1;
1.1 root 1703: }
1.1.1.4 ! root 1704: static void SPRxPTL (int hpos, uae_u16 v, int num)
1.1 root 1705: {
1.1.1.4 ! root 1706: decide_sprites (hpos);
1.1.1.3 root 1707: sprpt[num] &= ~0xffff;
1.1.1.2 root 1708: sprpt[num] |= v;
1.1 root 1709:
1.1.1.3 root 1710: if (sprst[num] == SPR_stop || vpos < vblank_endline)
1711: sprst[num] = SPR_restart;
1712: spron[num] = 1;
1713: }
1.1.1.4 ! root 1714: static void CLXCON (uae_u16 v)
1.1.1.3 root 1715: {
1716: clxcon = v;
1717: clx_sprmask = (((v >> 15) << 7) | ((v >> 14) << 5) | ((v >> 13) << 3) | ((v >> 12) << 1) | 0x55);
1718: }
1.1.1.4 ! root 1719: static uae_u16 CLXDAT (void)
1.1.1.3 root 1720: {
1721: uae_u16 v = clxdat;
1722: clxdat = 0;
1723: return v;
1724: }
1.1.1.4 ! root 1725: static void COLOR (int hpos, uae_u16 v, int num)
1.1 root 1726: {
1.1.1.3 root 1727:
1.1 root 1728: v &= 0xFFF;
1729: #if AGA_CHIPSET == 1
1730: {
1.1.1.2 root 1731: /* XXX Broken */
1.1.1.4 ! root 1732: int r,g,b;
! 1733: int cr,cg,cb;
! 1734: int colreg;
1.1.1.3 root 1735: uae_u32 cval;
1.1.1.4 ! root 1736:
1.1.1.2 root 1737: colreg = ((bplcon3 >> 13) & 7) * 32 + num;
1.1 root 1738: r = (v & 0xF00) >> 8;
1739: g = (v & 0xF0) >> 4;
1740: b = (v & 0xF) >> 0;
1.1.1.2 root 1741: cr = color_regs[colreg] >> 16;
1742: cg = (color_regs[colreg] >> 8) & 0xFF;
1743: cb = color_regs[colreg] & 0xFF;
1.1 root 1744:
1.1.1.2 root 1745: if (bplcon3 & 0x200) {
1.1 root 1746: cr &= 0xF0; cr |= r;
1747: cg &= 0xF0; cg |= g;
1748: cb &= 0xF0; cb |= b;
1749: } else {
1750: cr = r + (r << 4);
1751: cg = g + (g << 4);
1752: cb = b + (b << 4);
1753: }
1754: cval = (cr << 16) | (cg << 8) | cb;
1.1.1.2 root 1755: if (cval == color_regs[colreg])
1.1 root 1756: return;
1.1.1.2 root 1757: color_regs[colreg] = cval;
1.1 root 1758: pfield_may_need_update(1);
1759: }
1.1.1.3 root 1760: #else
1.1 root 1761: {
1.1.1.2 root 1762: if (current_colors.color_regs[num] == v)
1.1 root 1763: return;
1.1.1.2 root 1764: /* Call this with the old table still intact. */
1.1.1.4 ! root 1765: record_color_change (hpos, num, v);
1.1.1.2 root 1766: remembered_color_entry = -1;
1767: current_colors.color_regs[num] = v;
1768: current_colors.acolors[num] = xcolors[v];
1.1 root 1769: }
1770: #endif
1771: }
1772:
1.1.1.4 ! root 1773: static void DSKSYNC (uae_u16 v) { dsksync = v; }
! 1774: static void DSKDAT (uae_u16 v) { write_log ("DSKDAT written. Not good.\n"); }
! 1775: static void DSKPTH (uae_u16 v) { dskpt = (dskpt & 0xffff) | ((uae_u32)v << 16); }
! 1776: static void DSKPTL (uae_u16 v) { dskpt = (dskpt & ~0xffff) | (v); }
1.1 root 1777:
1.1.1.4 ! root 1778: static void DSKLEN (uae_u16 v)
1.1 root 1779: {
1780: if (v & 0x8000) {
1781: dskdmaen = dskdmaen == 1 ? 2 : 1;
1.1.1.3 root 1782: } else {
1.1 root 1783: dskdmaen = 0;
1784: if (eventtab[ev_diskblk].active)
1.1.1.3 root 1785: write_log ("warning: Disk DMA aborted!\n");
1.1 root 1786: eventtab[ev_diskblk].active = 0;
1787: events_schedule();
1.1.1.3 root 1788:
1.1 root 1789: }
1790: dsklen = dsklength = v; dsklength &= 0x3fff;
1791: if (dskdmaen == 2 && dsksync != 0x4489 && (adkcon & 0x400)) {
1.1.1.4 ! root 1792: write_log ("Non-standard sync: %04x len: %x\n", dsksync, dsklength);
1.1 root 1793: }
1794: if (dskdmaen > 1) {
1795: if (dsklen & 0x4000) {
1796: eventtab[ev_diskblk].active = 1;
1797: eventtab[ev_diskblk].oldcycles = cycles;
1798: eventtab[ev_diskblk].evtime = 40 + cycles; /* ??? */
1799: events_schedule();
1800: } else {
1801: int result = DISK_PrepareReadMFM(dsklength, dsksync, adkcon & 0x400);
1802: if (result) {
1803: eventtab[ev_diskblk].active = 1;
1804: eventtab[ev_diskblk].oldcycles = cycles;
1805: eventtab[ev_diskblk].evtime = result + cycles;
1806: events_schedule();
1807: }
1808: }
1809: }
1810: }
1811:
1.1.1.4 ! root 1812: static uae_u16 DSKBYTR (void)
1.1 root 1813: {
1.1.1.3 root 1814: uae_u16 v = (dsklen >> 1) & 0x6000;
1815: uae_u16 mfm, byte;
1.1.1.4 ! root 1816: if (DISK_GetData (&mfm, &byte))
1.1 root 1817: v |= 0x8000;
1818: v |= byte;
1.1.1.4 ! root 1819: if (dsksync == mfm)
! 1820: v |= 0x1000;
1.1 root 1821: return v;
1822: }
1823:
1.1.1.4 ! root 1824: static uae_u16 DSKDATR (void)
1.1 root 1825: {
1.1.1.3 root 1826: uae_u16 mfm, byte;
1.1.1.4 ! root 1827: DISK_GetData (&mfm, &byte);
1.1.1.3 root 1828: return mfm;
1.1 root 1829: }
1.1.1.3 root 1830:
1831: static uae_u16 potgo_value;
1832:
1.1.1.4 ! root 1833: static void POTGO (uae_u16 v)
1.1 root 1834: {
1.1.1.3 root 1835: potgo_value = v;
1836: }
1837:
1.1.1.4 ! root 1838: static uae_u16 POTGOR (void)
1.1.1.3 root 1839: {
1840: uae_u16 v = (potgo_value | (potgo_value << 1)) & 0xAA00;
1841: v |= v >> 1;
1842:
1843: if (JSEM_ISMOUSE (0, currprefs.fake_joystick)) {
1844: if (buttonstate[2])
1845: v &= 0xFBFF;
1846:
1847: if (buttonstate[1])
1848: v &= 0xFEFF;
1.1.1.4 ! root 1849: } else if (JSEM_ISJOY0 (0, currprefs.fake_joystick) || JSEM_ISJOY1 (0, currprefs.fake_joystick)) {
1.1.1.3 root 1850: if (joy0button & 2) v &= 0xfbff;
1851: if (joy0button & 4) v &= 0xfeff;
1852: }
1853:
1.1.1.4 ! root 1854: if (JSEM_ISJOY0 (1, currprefs.fake_joystick) || JSEM_ISJOY1 (1, currprefs.fake_joystick)) {
1.1.1.3 root 1855: if (joy1button & 2) v &= 0xbfff;
1856: if (joy1button & 4) v &= 0xefff;
1857: }
1.1 root 1858:
1859: return v;
1860: }
1.1.1.4 ! root 1861:
! 1862: static uae_u16 POT0DAT (void)
1.1 root 1863: {
1.1.1.3 root 1864: static uae_u16 cnt = 0;
1865: if (JSEM_ISMOUSE (0, currprefs.fake_joystick)) {
1866: if (buttonstate[2])
1867: cnt = ((cnt + 1) & 0xFF) | (cnt & 0xFF00);
1868: if (buttonstate[1])
1869: cnt += 0x100;
1870: }
1871:
1.1 root 1872: return cnt;
1873: }
1.1.1.4 ! root 1874: static uae_u16 JOY0DAT (void)
1.1 root 1875: {
1.1.1.3 root 1876: if (JSEM_ISMOUSE (0, currprefs.fake_joystick)) {
1.1.1.4 ! root 1877: do_mouse_hack ();
1.1.1.3 root 1878: return ((uae_u8)mouse_x) + ((uae_u16)mouse_y << 8);
1879: }
1.1 root 1880: return joy0dir;
1881: }
1.1.1.4 ! root 1882: static uae_u16 JOY1DAT (void)
1.1 root 1883: {
1.1.1.3 root 1884: if (JSEM_ISMOUSE (1, currprefs.fake_joystick)) {
1.1.1.4 ! root 1885: do_mouse_hack ();
1.1.1.3 root 1886: return ((uae_u8)mouse_x) + ((uae_u16)mouse_y << 8);
1887: }
1888: return joy1dir;
1.1 root 1889: }
1.1.1.4 ! root 1890: static void JOYTEST (uae_u16 v)
1.1 root 1891: {
1.1.1.3 root 1892: if (JSEM_ISMOUSE (0, currprefs.fake_joystick)) {
1893: mouse_x = v & 0xFC;
1894: mouse_y = (v >> 8) & 0xFC;
1.1 root 1895: }
1896: }
1897:
1.1.1.2 root 1898: /*
1.1.1.4 ! root 1899: * Here starts the copper code. Can you believe it used to be worse?
1.1.1.2 root 1900: */
1901:
1.1.1.4 ! root 1902: static __inline__ void copper_adjust_diw (struct copper *cst)
1.1.1.3 root 1903: {
1.1.1.4 ! root 1904: if (cst->vdiw == DIW_waiting_start && vpos == plffirstline)
! 1905: cst->vdiw = DIW_waiting_stop;
! 1906: if (cst->vdiw == DIW_waiting_stop && vpos == plflastline)
! 1907: cst->vdiw = DIW_waiting_start;
! 1908: }
! 1909:
! 1910: /* Determine which cycles are available for the copper in a display
! 1911: * with a agiven number of planes. */
! 1912: static int cycles_for_plane[9][8] = {
! 1913: { 0, -1, 0, -1, 0, -1, 0, -1 },
! 1914: { 0, -1, 0, -1, 0, -1, 0, -1 },
! 1915: { 0, -1, 0, -1, 0, -1, 0, -1 },
! 1916: { 0, -1, 0, -1, 0, -1, 0, -1 },
! 1917: { 0, -1, 0, -1, 0, -1, 0, -1 },
! 1918: { 0, -1, 1, -1, 0, -1, 0, -1 },
! 1919: { 0, -1, 1, -1, 0, -1, 1, -1 },
! 1920: { 1, -1, 1, -1, 1, -1, 1, -1 },
! 1921: { 1, -1, 1, -1, 1, -1, 1, -1 }
! 1922: };
1.1.1.2 root 1923:
1.1.1.4 ! root 1924: static unsigned int waitmasktab[256];
1.1.1.2 root 1925:
1.1.1.4 ! root 1926: #define COP_OFFSET 4
! 1927:
! 1928: static __inline__ int copper_in_playfield (enum diw_states diw, int hpos)
1.1.1.3 root 1929: {
1.1.1.4 ! root 1930: hpos -= COP_OFFSET;
! 1931: return diw == DIW_waiting_stop && hpos >= plfstrt && hpos < plfstrt + plflinelen;
1.1 root 1932: }
1933:
1.1.1.4 ! root 1934: static __inline__ int copper_cant_read (enum diw_states diw, int hpos, int planes)
1.1 root 1935: {
1.1.1.4 ! root 1936: int t;
1.1.1.2 root 1937:
1.1.1.4 ! root 1938: if (hpos >= ((maxhpos - 2) & ~1))
1.1.1.2 root 1939: return 1;
1.1.1.3 root 1940:
1.1.1.4 ! root 1941: if (! copper_in_playfield (diw, hpos))
! 1942: return 0;
1.1.1.3 root 1943:
1.1.1.4 ! root 1944: t = cycles_for_plane[planes][hpos & 7];
! 1945: #if 0
! 1946: if (t == -1)
! 1947: abort ();
! 1948: #endif
! 1949: return t;
1.1.1.2 root 1950: }
1951:
1.1.1.4 ! root 1952: static void update_copper_1 (int until_hpos)
1.1.1.2 root 1953: {
1.1.1.4 ! root 1954: unsigned int vp, hp, vcmp, hcmp;
! 1955: int c_hpos = cop_state.hpos;
! 1956: int c_vpos = cop_state.vpos;
1.1.1.2 root 1957:
1.1.1.4 ! root 1958: vp = vpos & (((cop_state.i2 >> 8) & 0x7F) | 0x80);
! 1959: hp = cop_state.count & (cop_state.i2 & 0xFE);
! 1960: vcmp = ((cop_state.i1 & (cop_state.i2 | 0x8000)) >> 8);
! 1961: hcmp = (cop_state.i1 & cop_state.i2 & 0xFE);
1.1 root 1962:
1.1.1.4 ! root 1963: if (cop_state.state == COP_wait2)
! 1964: cop_state.state = COP_wait1b;
1.1.1.3 root 1965:
1.1.1.4 ! root 1966: for (;;) {
! 1967: if (c_hpos == (maxhpos & ~1)) {
! 1968: c_hpos = 0;
! 1969: cop_state.count = 0;
! 1970: c_vpos++;
! 1971: }
1.1.1.3 root 1972:
1.1.1.4 ! root 1973: if (! dmaen (DMA_COPPER))
! 1974: cop_state.state = COP_stop;
! 1975:
! 1976: if (c_vpos > vpos
! 1977: || c_hpos > until_hpos
! 1978: || cop_state.state == COP_stop)
1.1.1.3 root 1979: break;
1980:
1.1.1.4 ! root 1981: if (c_hpos - COP_OFFSET == plfstrt)
! 1982: copper_adjust_diw (&cop_state);
1.1.1.3 root 1983:
1.1.1.4 ! root 1984: switch (cop_state.state) {
! 1985: case COP_rdelay1:
! 1986: cop_state.state = COP_read1;
1.1.1.3 root 1987: break;
1988:
1.1.1.4 ! root 1989: case COP_read1:
! 1990: if (copper_cant_read (cop_state.vdiw, c_hpos, corrected_nr_planes_from_bplcon0))
! 1991: break;
1.1.1.3 root 1992:
1.1.1.4 ! root 1993: if (cop_state.do_move) {
! 1994: cop_state.do_move = 0;
! 1995: if (cop_state.i1 < (copcon & 2 ? 0x40u : 0x80u)) {
! 1996: cop_state.state = COP_stop;
! 1997: break;
! 1998: }
! 1999: switch (cop_state.i1) {
! 2000: case 0x088:
! 2001: cop_state.ip = cop1lc;
! 2002: cop_state.state = COP_rdelay1;
! 2003: break;
! 2004: case 0x08A:
! 2005: cop_state.ip = cop2lc;
! 2006: cop_state.state = COP_rdelay1;
! 2007: break;
! 2008: default:
! 2009: custom_wput_1 (c_hpos, cop_state.i1, cop_state.i2);
! 2010: break;
! 2011: }
! 2012: if (cop_state.state != COP_read1)
1.1.1.3 root 2013: break;
2014: }
1.1.1.4 ! root 2015: cop_state.i1 = chipmem_bank.wget (cop_state.ip);
! 2016: cop_state.ip += 2;
! 2017: cop_state.state = COP_read2;
1.1.1.2 root 2018: break;
2019:
1.1.1.4 ! root 2020: case COP_read2:
! 2021: if (copper_cant_read (cop_state.vdiw, c_hpos, corrected_nr_planes_from_bplcon0))
! 2022: break;
! 2023: cop_state.i2 = chipmem_bank.wget (cop_state.ip);
! 2024: cop_state.ip += 2;
! 2025: if (cop_state.ignore_next) {
! 2026: cop_state.ignore_next = 0;
! 2027: cop_state.state = COP_read1;
1.1.1.2 root 2028: break;
1.1.1.4 ! root 2029: }
! 2030: if ((cop_state.i1 & 1) == 0) {
! 2031: cop_state.state = COP_read1;
! 2032: cop_state.do_move = 1;
1.1.1.2 root 2033: } else {
1.1.1.4 ! root 2034: vp = vpos & (((cop_state.i2 >> 8) & 0x7F) | 0x80);
! 2035: hp = cop_state.count & (cop_state.i2 & 0xFE);
! 2036: vcmp = ((cop_state.i1 & (cop_state.i2 | 0x8000)) >> 8);
! 2037: hcmp = (cop_state.i1 & cop_state.i2 & 0xFE);
! 2038:
! 2039: if ((cop_state.i2 & 1) == 0) {
! 2040: cop_state.state = COP_wait1;
! 2041: if (cop_state.i1 == 0xFFFF && cop_state.i2 == 0xFFFE)
! 2042: cop_state.state = COP_stop;
! 2043: } else {
! 2044: /* Skip instruction. */
! 2045: if ((vp > vcmp || (vp == vcmp && hp >= hcmp))
! 2046: && ((cop_state.i2 & 0x8000) != 0 || ! (DMACONR() & 0x4000)))
! 2047: cop_state.ignore_next = 1;
! 2048: cop_state.state = COP_read1;
! 2049: }
1.1.1.2 root 2050: }
2051: break;
2052:
1.1.1.4 ! root 2053: case COP_wait1:
! 2054: if (copper_cant_read (cop_state.vdiw, c_hpos, corrected_nr_planes_from_bplcon0))
1.1.1.2 root 2055: break;
1.1.1.4 ! root 2056:
! 2057: /* fall through */
! 2058:
! 2059: case COP_wait1b:
! 2060: {
! 2061: int do_wait2 = cop_state.state == COP_wait1b;
! 2062: cop_state.state = COP_wait2;
! 2063: if (vp == vcmp && corrected_nr_planes_from_bplcon0 < 8) {
! 2064: int t = cop_state.count + 2;
! 2065: int next_count = (t & waitmasktab[cop_state.i2 & 0xfe]) | hcmp;
! 2066: int nexthpos;
! 2067: if (next_count < t)
! 2068: next_count = t;
! 2069: nexthpos = c_hpos + next_count - cop_state.count;
! 2070: if (nexthpos < (maxhpos & ~1)) {
! 2071: if (c_hpos - COP_OFFSET < plfstrt && nexthpos - COP_OFFSET >= plfstrt)
! 2072: copper_adjust_diw (&cop_state);
! 2073: c_hpos = nexthpos;
! 2074: cop_state.count = next_count;
! 2075: do_wait2 = 1;
! 2076: }
! 2077: }
! 2078: if (! do_wait2)
! 2079: break;
1.1.1.2 root 2080: }
2081:
1.1.1.4 ! root 2082: /* fall through */
! 2083:
! 2084: case COP_wait2:
! 2085: if (vp < vcmp) {
! 2086: if (c_hpos - COP_OFFSET < plfstrt)
! 2087: copper_adjust_diw (&cop_state);
! 2088:
! 2089: c_vpos++;
! 2090: c_hpos = 0;
! 2091: cop_state.count = 0;
! 2092: continue;
1.1.1.2 root 2093: }
1.1.1.4 ! root 2094: hp = cop_state.count & (cop_state.i2 & 0xFE);
! 2095: if (vp == vcmp && hp < hcmp)
! 2096: break;
! 2097: /* Now we know that the comparisons were successful. */
! 2098: if ((cop_state.i2 & 0x8000) == 0x8000 || ! (DMACONR() & 0x4000))
! 2099: cop_state.state = COP_read1;
! 2100: else {
! 2101: /* We need to wait for the blitter. It won't stop while
! 2102: * we're in update_copper, so we _could_ as well proceed to
! 2103: * until_hpos in one big step. There are some tricky
! 2104: * issues to be considered, though, so use the slow method
! 2105: * for now. */
! 2106: cop_state.state = COP_bltwait;
1.1.1.2 root 2107: }
1.1.1.4 ! root 2108: break;
1.1.1.2 root 2109:
1.1.1.4 ! root 2110: default:
! 2111: /* Delay cycles. */
! 2112: break;
1.1 root 2113: }
2114:
1.1.1.4 ! root 2115: c_hpos += 2;
! 2116: if (corrected_nr_planes_from_bplcon0 < 8 || ! copper_in_playfield (cop_state.vdiw, c_hpos))
! 2117: cop_state.count += 2;
! 2118: }
! 2119: cop_state.hpos = c_hpos;
! 2120: cop_state.vpos = c_vpos;
1.1 root 2121: }
2122:
1.1.1.4 ! root 2123: static __inline__ void update_copper (int until_hpos)
1.1 root 2124: {
1.1.1.4 ! root 2125: if (cop_state.vpos > vpos
! 2126: || cop_state.hpos > until_hpos
! 2127: || cop_state.state == COP_stop)
1.1 root 2128: return;
1.1.1.4 ! root 2129: update_copper_1 (until_hpos);
1.1 root 2130: }
2131:
1.1.1.4 ! root 2132: static int dangerous_reg (int reg)
1.1 root 2133: {
1.1.1.4 ! root 2134: /* Safe:
! 2135: * Bitplane pointers, control registers, modulos and data.
! 2136: * Sprite pointers, control registers, and data.
! 2137: * Color registers. */
! 2138: if (reg >= 0xE0 && reg < 0x1C0)
! 2139: return 0;
! 2140: return 1;
1.1 root 2141: }
2142:
1.1.1.4 ! root 2143: static void prepare_copper_1 (void)
1.1.1.2 root 2144: {
1.1.1.4 ! root 2145: struct copper cst = cop_state;
! 2146: unsigned int vp, hp, vcmp, hcmp;
1.1.1.2 root 2147:
1.1.1.4 ! root 2148: vp = vpos & (((cop_state.i2 >> 8) & 0x7F) | 0x80);
! 2149: hp = cop_state.count & (cop_state.i2 & 0xFE);
! 2150: vcmp = ((cop_state.i1 & (cop_state.i2 | 0x8000)) >> 8);
! 2151: hcmp = (cop_state.i1 & cop_state.i2 & 0xFE);
1.1.1.2 root 2152:
1.1.1.4 ! root 2153: if (cst.state == COP_wait2)
! 2154: cst.state = COP_wait1b;
1.1.1.3 root 2155:
1.1.1.4 ! root 2156: for (;;) {
! 2157: if (cst.hpos == (maxhpos & ~1)) {
! 2158: cst.hpos = 0;
! 2159: cst.count = 0;
! 2160: cst.vpos++;
1.1.1.2 root 2161: }
2162:
1.1.1.4 ! root 2163: if (! dmaen (DMA_COPPER))
! 2164: cst.state = COP_stop;
1.1.1.3 root 2165:
1.1.1.4 ! root 2166: if (cst.vpos > vpos
! 2167: || cst.state == COP_stop)
! 2168: {
! 2169: eventtab[ev_copper].active = 0;
! 2170: return;
1.1.1.2 root 2171: }
2172:
1.1.1.4 ! root 2173: if (cst.hpos - COP_OFFSET == plfstrt)
! 2174: copper_adjust_diw (&cst);
1.1.1.2 root 2175:
1.1.1.4 ! root 2176: switch (cst.state) {
! 2177: case COP_rdelay1:
! 2178: cst.state = COP_read1;
1.1.1.3 root 2179: break;
1.1.1.2 root 2180:
1.1.1.4 ! root 2181: case COP_read1:
! 2182: if (copper_cant_read (cst.vdiw, cst.hpos, corrected_nr_planes_from_bplcon0))
! 2183: break;
1.1.1.2 root 2184:
1.1.1.4 ! root 2185: if (cst.do_move) {
! 2186: cst.do_move = 0;
! 2187: if (cst.i1 < (copcon & 2 ? 0x40u : 0x80u)) {
! 2188: cst.state = COP_stop;
! 2189: eventtab[ev_copper].active = 0;
! 2190: return;
! 2191: } else if (dangerous_reg (cst.i1)) {
! 2192: eventtab[ev_copper].active = 1;
! 2193: eventtab[ev_copper].oldcycles = cycles;
! 2194: eventtab[ev_copper].evtime = cycles + cst.hpos - current_hpos () + (cst.vpos - cop_state.vpos) * maxhpos;
! 2195: return;
1.1.1.3 root 2196: }
2197: }
1.1.1.2 root 2198:
1.1.1.4 ! root 2199: cst.i1 = chipmem_bank.wget (cst.ip);
! 2200: cst.ip += 2;
! 2201: cst.state = COP_read2;
! 2202: break;
1.1.1.2 root 2203:
1.1.1.4 ! root 2204: case COP_read2:
! 2205: if (copper_cant_read (cst.vdiw, cst.hpos, corrected_nr_planes_from_bplcon0))
! 2206: break;
! 2207: cst.i2 = chipmem_bank.wget (cst.ip);
! 2208: cst.ip += 2;
! 2209: if (cst.ignore_next) {
! 2210: cst.ignore_next = 0;
! 2211: cst.state = COP_read1;
! 2212: break;
1.1.1.3 root 2213: }
1.1.1.4 ! root 2214: if ((cst.i1 & 1) == 0) {
! 2215: cst.state = COP_read1;
! 2216: cst.do_move = 1;
1.1.1.3 root 2217: } else {
1.1.1.4 ! root 2218: vp = vpos & (((cst.i2 >> 8) & 0x7F) | 0x80);
! 2219: hp = cst.count & (cst.i2 & 0xFE);
! 2220: vcmp = ((cst.i1 & (cst.i2 | 0x8000)) >> 8);
! 2221: hcmp = (cst.i1 & cst.i2 & 0xFE);
! 2222:
! 2223: if ((cst.i2 & 1) == 0) {
! 2224: cst.state = COP_wait1;
! 2225: if (cst.i1 == 0xFFFF && cst.i2 == 0xFFFE)
! 2226: cst.state = COP_stop;
1.1.1.3 root 2227: } else {
1.1.1.4 ! root 2228: /* Skip instruction. */
! 2229: if ((vp > vcmp || (vp == vcmp && hp >= hcmp))
! 2230: && ((cst.i2 & 0x8000) != 0 || ! (DMACONR() & 0x4000)))
! 2231: cst.ignore_next = 1;
! 2232: cst.state = COP_read1;
1.1.1.3 root 2233: }
2234: }
1.1.1.4 ! root 2235: break;
1.1 root 2236:
1.1.1.4 ! root 2237: case COP_wait1:
! 2238: if (copper_cant_read (cst.vdiw, cst.hpos, corrected_nr_planes_from_bplcon0))
! 2239: break;
1.1 root 2240:
1.1.1.4 ! root 2241: /* fall through */
1.1 root 2242:
1.1.1.4 ! root 2243: case COP_wait1b:
! 2244: {
! 2245: int do_wait2 = cst.state == COP_wait1b;
! 2246: cst.state = COP_wait2;
! 2247: if (vp == vcmp && corrected_nr_planes_from_bplcon0 < 8) {
! 2248: int t = cst.count + 2;
! 2249: int next_count = (t & waitmasktab[cst.i2 & 0xfe]) | hcmp;
! 2250: int nexthpos;
! 2251: if (next_count < t)
! 2252: next_count = t;
! 2253: nexthpos = cst.hpos + next_count - cst.count;
! 2254: if (nexthpos < (maxhpos & ~1)) {
! 2255: if (cst.hpos - COP_OFFSET < plfstrt && nexthpos - COP_OFFSET >= plfstrt)
! 2256: copper_adjust_diw (&cst);
! 2257: cst.hpos = nexthpos;
! 2258: cst.count = next_count;
! 2259: do_wait2 = 1;
! 2260: }
! 2261: }
! 2262: if (! do_wait2)
! 2263: break;
1.1 root 2264: }
1.1.1.3 root 2265:
1.1.1.4 ! root 2266: /* fall through */
! 2267:
! 2268: case COP_wait2:
! 2269: if (vp < vcmp) {
! 2270: if (cst.hpos - COP_OFFSET < plfstrt)
! 2271: copper_adjust_diw (&cst);
! 2272:
! 2273: cst.vpos++;
! 2274: cst.count = 0;
! 2275: cst.hpos = 0;
! 2276: continue;
1.1 root 2277: }
1.1.1.4 ! root 2278: hp = cst.count & (cst.i2 & 0xFE);
! 2279: if (vp == vcmp && hp < hcmp)
! 2280: break;
! 2281: #if 0
! 2282: if (nexthpos != -1)
! 2283: if (nexthpos != cst.count)
! 2284: printf ("ERROR\n");
! 2285: nexthpos = -1;
! 2286: #endif
! 2287: /* Now we know that the comparisons were successful. */
! 2288: if ((cst.i2 & 0x8000) == 0x8000 || ! (DMACONR() & 0x4000))
! 2289: cst.state = COP_read1;
! 2290: else {
! 2291: /* We need to wait for the blitter. It won't stop while
! 2292: * we're in update_copper, so we _could_ as well proceed to
! 2293: * until_hpos in one big step. There are some tricky
! 2294: * issues to be considered, though, so use the slow method
! 2295: * for now. */
! 2296: cst.state = COP_bltwait;
1.1 root 2297: }
1.1.1.4 ! root 2298: break;
1.1.1.2 root 2299:
1.1.1.4 ! root 2300: default:
! 2301: /* Delay cycles. */
! 2302: break;
1.1.1.2 root 2303: }
1.1.1.3 root 2304:
1.1.1.4 ! root 2305: cst.hpos += 2;
! 2306: if (corrected_nr_planes_from_bplcon0 < 8 || ! copper_in_playfield (cst.vdiw, cst.hpos))
! 2307: cst.count += 2;
1.1.1.3 root 2308: }
2309: }
1.1.1.2 root 2310:
1.1.1.4 ! root 2311: void blitter_done_notify (void)
1.1 root 2312: {
1.1.1.4 ! root 2313: if (cop_state.state != COP_bltwait)
! 2314: return;
! 2315: update_copper (current_hpos ());
! 2316: cop_state.state = COP_wait2;
! 2317: eventtab[ev_copper].active = 1;
! 2318: eventtab[ev_copper].oldcycles = cycles;
! 2319: eventtab[ev_copper].evtime = (cycles + 2) & ~1;
! 2320: events_schedule ();
1.1.1.2 root 2321: }
2322:
1.1.1.4 ! root 2323: static void do_copper (void)
1.1.1.2 root 2324: {
1.1.1.4 ! root 2325: int hpos = current_hpos ();
! 2326: update_copper (hpos);
! 2327: prepare_copper ();
! 2328: if (eventtab[ev_copper].evtime == cycles && eventtab[ev_copper].active)
! 2329: abort ();
1.1.1.2 root 2330: }
2331:
1.1.1.4 ! root 2332: static void diskblk_handler (void)
1.1.1.2 root 2333: {
1.1.1.4 ! root 2334: regs.spcflags |= SPCFLAG_DISK;
! 2335: eventtab[ev_diskblk].active = 0;
1.1.1.2 root 2336: }
2337:
1.1.1.4 ! root 2338: void do_disk (void)
1.1.1.2 root 2339: {
1.1.1.4 ! root 2340: if (dskdmaen != 2 && (regs.spcflags & SPCFLAG_DISK)) {
! 2341: static int warned = 0;
! 2342: if (!warned)
! 2343: warned++, write_log ("BUG!\n");
1.1.1.2 root 2344: return;
2345: }
1.1.1.4 ! root 2346: if (dmaen(0x10)){
! 2347: if (dsklen & 0x4000) {
! 2348: if (!chipmem_bank.check (dskpt, 2*dsklength)) {
! 2349: write_log ("warning: Bad disk write DMA pointer\n");
! 2350: } else {
! 2351: uae_u8 *mfmp = get_real_address (dskpt);
! 2352: int i;
! 2353: DISK_InitWrite();
1.1.1.3 root 2354:
1.1.1.4 ! root 2355: for (i = 0; i < dsklength; i++) {
! 2356: uae_u16 d = (*mfmp << 8) + *(mfmp+1);
! 2357: mfmwrite[i] = d;
! 2358: mfmp += 2;
! 2359: }
! 2360: DISK_WriteData(dsklength);
1.1.1.2 root 2361: }
1.1.1.4 ! root 2362: } else {
! 2363: DISK_ReadMFM (dskpt);
1.1.1.2 root 2364: }
1.1.1.4 ! root 2365: regs.spcflags &= ~SPCFLAG_DISK;
! 2366: INTREQ(0x9002);
! 2367: dskdmaen = -1;
1.1.1.2 root 2368: }
1.1.1.4 ! root 2369: }
1.1.1.2 root 2370:
1.1.1.4 ! root 2371: static void do_sprites (int currvp, int currhp)
! 2372: {
! 2373: int i;
! 2374: int maxspr;
1.1.1.2 root 2375:
1.1.1.4 ! root 2376: #if 0
! 2377: if (currvp == 0)
! 2378: return;
! 2379: #else
! 2380: /* I don't know whether this is right. Some programs write the sprite pointers
! 2381: * directly at the start of the copper list. With the currvp==0 check, the
! 2382: * first two words of data are read on the second line in the frame. The problem
! 2383: * occurs when the program jumps to another copperlist a few lines further down
! 2384: * which _also_ writes the sprite pointer registers. This means that a) writing
! 2385: * to the sprite pointers sets the state to SPR_restart; or b) that sprite DMA
! 2386: * is disabled until the end of the vertical blanking interval. The HRM
! 2387: * isn't clear - it says that the vertical sprite position can be set to any
! 2388: * value, but this wouldn't be the first mistake... */
! 2389: /* Update: I modified one of the programs to write the sprite pointers the
! 2390: * second time only _after_ the VBlank interval, and it showed the same behaviour
! 2391: * as it did unmodified under UAE with the above check. This indicates that the
! 2392: * solution below is correct. */
! 2393: if (currvp < vblank_endline)
! 2394: return;
1.1.1.2 root 2395: #endif
1.1.1.3 root 2396:
1.1.1.4 ! root 2397: /* The graph in the HRM, p. 195 seems to indicate that sprite 0 is
! 2398: * fetched at cycle 0x14 and thus can't be disabled by bitplane DMA. */
! 2399: maxspr = currhp/4 - 0x14/4;
! 2400: if (maxspr < 0)
! 2401: return;
! 2402: if (maxspr > 8)
! 2403: maxspr = 8;
1.1.1.2 root 2404:
1.1.1.4 ! root 2405: for (i = 0; i < maxspr; i++) {
! 2406: int fetch = 0;
1.1.1.2 root 2407:
1.1.1.4 ! root 2408: if (spron[i] == 0)
! 2409: continue;
1.1.1.2 root 2410:
1.1.1.4 ! root 2411: if (sprst[i] == SPR_restart) {
! 2412: fetch = 2;
! 2413: spron[i] = 1;
! 2414: } else if ((sprst[i] == SPR_waiting_start && sprvstart[i] == vpos) || sprst[i] == SPR_waiting_stop) {
! 2415: fetch = 1;
! 2416: sprst[i] = SPR_waiting_stop;
1.1.1.2 root 2417: }
1.1.1.4 ! root 2418: if (sprst[i] == SPR_waiting_stop && sprvstop[i] == vpos) {
! 2419: fetch = 2;
! 2420: sprst[i] = SPR_waiting_start;
1.1.1.2 root 2421: }
1.1.1.3 root 2422:
1.1.1.4 ! root 2423: if (fetch && dmaen(DMA_SPRITE)) {
! 2424: uae_u16 data1 = chipmem_bank.wget(sprpt[i]);
! 2425: uae_u16 data2 = chipmem_bank.wget(sprpt[i]+2);
! 2426: sprpt[i] += 4;
1.1.1.3 root 2427:
1.1.1.4 ! root 2428: if (fetch == 1) {
! 2429: /* Hack for X mouse auto-calibration */
! 2430: if (i == 0 && !sprvbfl && ((sprpos[0] & 0xff) << 2) > 2 * DISPLAY_LEFT_SHIFT) {
! 2431: spr0ctl=sprctl[0];
! 2432: spr0pos=sprpos[0];
! 2433: sprvbfl=2;
1.1.1.3 root 2434: }
1.1.1.4 ! root 2435: SPRxDATB_1(data2, i);
! 2436: SPRxDATA_1(data1, i);
! 2437: } else {
! 2438: SPRxPOS_1(data1, i);
! 2439: SPRxCTL_1(data2, i);
1.1.1.3 root 2440: }
1.1 root 2441: }
2442: }
2443: }
2444:
1.1.1.4 ! root 2445: static void init_sprites (void)
1.1 root 2446: {
1.1.1.4 ! root 2447: int i;
1.1.1.2 root 2448:
1.1.1.4 ! root 2449: for (i = 0; i < 8; i++) {
! 2450: /* ???? */
! 2451: sprst[i] = SPR_stop;
! 2452: spron[i] = 0;
! 2453: }
1.1.1.2 root 2454:
1.1.1.4 ! root 2455: memset (sprpos, 0, sizeof sprpos);
! 2456: memset (sprctl, 0, sizeof sprctl);
! 2457: }
1.1.1.2 root 2458:
1.1.1.3 root 2459: static void adjust_array_sizes (void)
1.1.1.2 root 2460: {
2461: #ifdef OS_WITHOUT_MEMORY_MANAGEMENT
1.1.1.3 root 2462: if (delta_sprite_draw) {
2463: void *p1,*p2;
2464: int mcc = max_sprite_draw + 200 + delta_sprite_draw;
2465: delta_sprite_draw = 0;
2466: p1 = realloc (sprite_positions[0], mcc * sizeof (struct sprite_draw));
2467: p2 = realloc (sprite_positions[1], mcc * sizeof (struct sprite_draw));
2468: if (p1) sprite_positions[0] = p1;
2469: if (p2) sprite_positions[1] = p2;
2470: if (p1 && p2) {
2471: fprintf (stderr, "new max_sprite_draw=%d\n",mcc);
1.1.1.2 root 2472: max_sprite_draw = mcc;
2473: }
2474: }
1.1.1.3 root 2475: if (delta_color_change) {
2476: void *p1,*p2;
2477: int mcc = max_color_change + 200 + delta_color_change;
2478: delta_color_change = 0;
2479: p1 = realloc (color_changes[0], mcc * sizeof (struct color_change));
2480: p2 = realloc (color_changes[1], mcc * sizeof (struct color_change));
2481: if (p1) color_changes[0] = p1;
2482: if (p2) color_changes[1] = p2;
2483: if (p1 && p2) {
2484: fprintf (stderr, "new max_color_change=%d\n",mcc);
1.1.1.2 root 2485: max_color_change = mcc;
1.1.1.3 root 2486: }
2487: }
2488: if (delta_delay_change) {
2489: void *p;
2490: int mcc = max_delay_change + 200 + delta_delay_change;
2491: delta_delay_change = 0;
2492: p = realloc (delay_changes, mcc * sizeof (struct delay_change));
2493: if (p) {
2494: fprintf (stderr, "new max_delay_change=%d\n",mcc);
2495: delay_changes = p;
2496: max_delay_change = mcc;
2497: }
1.1.1.2 root 2498: }
2499: #endif
1.1.1.3 root 2500: }
2501:
1.1.1.4 ! root 2502: static void init_hardware_frame (void)
1.1.1.3 root 2503: {
1.1.1.4 ! root 2504: next_lineno = 0;
! 2505: nextline_how = nln_normal;
! 2506: diwstate = DIW_waiting_start;
! 2507: hdiwstate = DIW_waiting_start;
! 2508: }
1.1.1.2 root 2509:
1.1.1.4 ! root 2510: void init_hardware_for_drawing_frame (void)
! 2511: {
1.1.1.3 root 2512: adjust_array_sizes ();
2513:
1.1.1.2 root 2514: next_color_change = 0;
2515: next_delay_change = 0;
2516: next_sprite_draw = 0;
1.1.1.3 root 2517:
1.1.1.2 root 2518: next_color_entry = 0;
2519: remembered_color_entry = -1;
2520: prev_sprite_positions = sprite_positions[current_change_set];
2521: curr_sprite_positions = sprite_positions[current_change_set ^ 1];
2522: prev_color_changes = color_changes[current_change_set];
2523: curr_color_changes = color_changes[current_change_set ^ 1];
2524: prev_color_tables = color_tables[current_change_set];
2525: curr_color_tables = color_tables[current_change_set ^ 1];
1.1.1.3 root 2526:
1.1.1.2 root 2527: prev_drawinfo = line_drawinfo[current_change_set];
1.1.1.4 ! root 2528: curr_drawinfo = line_drawinfo[current_change_set ^ 1];
! 2529: current_change_set ^= 1;
1.1.1.3 root 2530:
1.1.1.4 ! root 2531: color_src_match = color_dest_match = -1;
1.1.1.3 root 2532: }
2533:
1.1.1.2 root 2534: static void vsync_handler (void)
1.1 root 2535: {
1.1.1.4 ! root 2536: if (currprefs.m68k_speed == -1) {
! 2537: frame_time_t curr_time = read_processor_time ();
1.1.1.3 root 2538: vsyncmintime += vsynctime;
2539: /* @@@ Mathias? How do you think we should do this? */
2540: /* If we are too far behind, or we just did a reset, adjust the
2541: * needed time. */
1.1.1.4 ! root 2542: if ((long int)(curr_time - vsyncmintime) > 0 || rpt_did_reset)
1.1.1.3 root 2543: vsyncmintime = curr_time + vsynctime;
1.1.1.4 ! root 2544: rpt_did_reset = 0;
1.1.1.3 root 2545: }
1.1.1.4 ! root 2546:
1.1.1.3 root 2547: handle_events ();
1.1 root 2548:
1.1.1.3 root 2549: getjoystate (0, &joy0dir, &joy0button);
2550: getjoystate (1, &joy1dir, &joy1button);
1.1 root 2551:
1.1.1.4 ! root 2552: INTREQ (0x8020);
1.1.1.3 root 2553: if (bplcon0 & 4)
1.1.1.2 root 2554: lof ^= 0x8000;
1.1.1.3 root 2555:
1.1.1.4 ! root 2556: vsync_handle_redraw (lof, lof_changed);
! 2557: if (quit_program > 0)
1.1.1.3 root 2558: return;
2559:
1.1.1.4 ! root 2560: {
1.1.1.3 root 2561: static int cnt = 0;
2562: if (cnt == 0) {
2563: /* resolution_check_change (); */
2564: DISK_check_change ();
2565: cnt = 5;
2566: }
2567: cnt--;
1.1.1.2 root 2568: }
1.1.1.3 root 2569:
1.1.1.2 root 2570: lof_changed = 0;
1.1.1.3 root 2571:
1.1.1.4 ! root 2572: cop_state.ip = cop1lc;
! 2573: cop_state.state = COP_read1;
! 2574: cop_state.vpos = 0;
! 2575: cop_state.hpos = 0;
! 2576: cop_state.count = 0;
! 2577: cop_state.do_move = 0;
! 2578: cop_state.ignore_next = 0;
! 2579: cop_state.vdiw = DIW_waiting_start;
! 2580:
! 2581: init_hardware_frame ();
! 2582:
1.1 root 2583: #ifdef HAVE_GETTIMEOFDAY
2584: {
2585: struct timeval tv;
2586: unsigned long int newtime;
1.1.1.3 root 2587:
2588: gettimeofday(&tv,NULL);
1.1 root 2589: newtime = (tv.tv_sec-seconds_base) * 1000 + tv.tv_usec / 1000;
1.1.1.3 root 2590:
2591: if (!bogusframe) {
1.1 root 2592: frametime += newtime - msecs;
2593: timeframes++;
2594: }
2595: msecs = newtime;
2596: bogusframe = 0;
2597: }
2598: #endif
1.1.1.3 root 2599: if (ievent_alive > 0)
2600: ievent_alive--;
1.1 root 2601: CIA_vsync_handler();
2602: }
2603:
1.1.1.4 ! root 2604: static void hsync_handler (void)
1.1 root 2605: {
1.1.1.4 ! root 2606: update_copper (maxhpos);
1.1.1.3 root 2607:
1.1.1.2 root 2608: finish_decisions ();
1.1.1.4 ! root 2609: do_modulos (current_hpos ());
1.1.1.2 root 2610:
1.1.1.4 ! root 2611: hsync_record_line_state (next_lineno, nextline_how);
1.1 root 2612:
2613: eventtab[ev_hsync].evtime += cycles - eventtab[ev_hsync].oldcycles;
2614: eventtab[ev_hsync].oldcycles = cycles;
2615: CIA_hsync_handler();
1.1.1.3 root 2616:
2617: if (currprefs.produce_sound > 0) {
1.1 root 2618: int nr;
1.1.1.4 ! root 2619:
! 2620: update_audio ();
! 2621:
1.1 root 2622: /* Sound data is fetched at the beginning of each line */
2623: for (nr = 0; nr < 4; nr++) {
2624: struct audio_channel_data *cdp = audio_channel + nr;
1.1.1.3 root 2625:
1.1 root 2626: if (cdp->data_written == 2) {
2627: cdp->data_written = 0;
2628: cdp->nextdat = chipmem_bank.wget(cdp->pt);
2629: cdp->pt += 2;
2630: if (cdp->state == 2 || cdp->state == 3) {
2631: if (cdp->wlen == 1) {
2632: cdp->pt = cdp->lc;
2633: cdp->wlen = cdp->len;
2634: cdp->intreq2 = 1;
2635: } else
2636: cdp->wlen--;
2637: }
2638: }
2639: }
2640: }
1.1.1.4 ! root 2641:
! 2642: hardware_line_completed (next_lineno);
! 2643:
1.1 root 2644: if (++vpos == (maxvpos + (lof != 0))) {
2645: vpos = 0;
2646: vsync_handler();
2647: }
1.1.1.2 root 2648:
1.1.1.4 ! root 2649: is_lastline = vpos + 1 == maxvpos + (lof != 0) && currprefs.m68k_speed == -1 && ! rpt_did_reset;
1.1.1.3 root 2650:
1.1.1.4 ! root 2651: if ((bplcon0 & 4) && currprefs.gfx_linedbl)
! 2652: notice_interlace_seen ();
1.1.1.2 root 2653:
2654: if (framecnt == 0) {
1.1.1.4 ! root 2655: int lineno = vpos;
! 2656: nextline_how = nln_normal;
1.1.1.3 root 2657: if (currprefs.gfx_linedbl) {
1.1 root 2658: lineno *= 2;
1.1.1.4 ! root 2659: nextline_how = nln_doubled;
1.1.1.2 root 2660: if (bplcon0 & 4) {
2661: if (!lof) {
2662: lineno++;
1.1.1.4 ! root 2663: nextline_how = nln_lower;
1.1.1.2 root 2664: } else {
1.1.1.4 ! root 2665: nextline_how = nln_upper;
1.1.1.2 root 2666: }
1.1 root 2667: }
2668: }
2669: next_lineno = lineno;
1.1.1.2 root 2670: reset_decisions ();
1.1 root 2671: }
1.1.1.3 root 2672: if (uae_int_requested) {
2673: set_uae_int_flag ();
2674: INTREQ (0xA000);
2675: }
1.1.1.4 ! root 2676: update_copper (0);
! 2677: prepare_copper ();
! 2678: if (eventtab[ev_copper].evtime == cycles && eventtab[ev_copper].active)
! 2679: abort ();
1.1.1.3 root 2680: }
2681:
2682: static void init_eventtab (void)
2683: {
2684: int i;
2685:
2686: for(i = 0; i < ev_max; i++) {
2687: eventtab[i].active = 0;
2688: eventtab[i].oldcycles = 0;
2689: }
1.1.1.4 ! root 2690:
1.1.1.3 root 2691: eventtab[ev_cia].handler = CIA_handler;
1.1.1.4 ! root 2692: eventtab[ev_copper].handler = do_copper;
1.1.1.3 root 2693: eventtab[ev_hsync].handler = hsync_handler;
2694: eventtab[ev_hsync].evtime = maxhpos + cycles;
2695: eventtab[ev_hsync].active = 1;
2696:
2697: eventtab[ev_blitter].handler = blitter_handler;
2698: eventtab[ev_blitter].active = 0;
2699: eventtab[ev_diskblk].handler = diskblk_handler;
2700: eventtab[ev_diskblk].active = 0;
2701: eventtab[ev_diskindex].handler = diskindex_handler;
2702: eventtab[ev_diskindex].active = 0;
1.1.1.4 ! root 2703:
1.1.1.3 root 2704: events_schedule ();
1.1 root 2705: }
2706:
1.1.1.3 root 2707: void customreset (void)
1.1 root 2708: {
1.1.1.4 ! root 2709: int i;
1.1 root 2710: #ifdef HAVE_GETTIMEOFDAY
2711: struct timeval tv;
2712: #endif
1.1.1.2 root 2713:
1.1.1.3 root 2714: for (i = 0; i < sizeof current_colors.color_regs / sizeof *current_colors.color_regs; i++)
2715: current_colors.color_regs[i] = -1;
2716:
2717: expamem_reset ();
1.1.1.4 ! root 2718:
1.1.1.3 root 2719: CIA_reset ();
2720: cycles = 0;
1.1 root 2721: regs.spcflags &= SPCFLAG_BRK;
1.1.1.3 root 2722:
1.1.1.2 root 2723: vpos = 0;
1.1 root 2724: lof = 0;
1.1.1.3 root 2725:
1.1.1.4 ! root 2726: if (needmousehack ()) {
1.1.1.3 root 2727: #if 0
1.1.1.4 ! root 2728: mousehack_setfollow();
1.1.1.3 root 2729: #else
1.1.1.4 ! root 2730: mousehack_setdontcare();
1.1.1.3 root 2731: #endif
1.1 root 2732: } else {
2733: mousestate = normal_mouse;
2734: }
1.1.1.3 root 2735: ievent_alive = 0;
2736:
2737: clx_sprmask = 0xFF;
2738: clxdat = 0;
2739:
1.1.1.4 ! root 2740: memset (sprarmed, 0, sizeof sprarmed);
1.1.1.3 root 2741: nr_armed = 0;
1.1 root 2742:
2743: dmacon = intena = 0;
2744: bltstate = BLT_done;
1.1.1.4 ! root 2745: cop_state.state = COP_stop;
1.1.1.2 root 2746: diwstate = DIW_waiting_start;
1.1.1.3 root 2747: hdiwstate = DIW_waiting_start;
1.1 root 2748: copcon = 0;
2749: dskdmaen = 0;
2750: cycles = 0;
1.1.1.3 root 2751:
2752: audio_reset ();
1.1 root 2753:
1.1.1.2 root 2754: bplcon4 = 0x11; /* Get AGA chipset into ECS compatibility mode */
2755: bplcon3 = 0xC00;
1.1 root 2756:
1.1.1.3 root 2757: init_eventtab ();
1.1.1.2 root 2758:
1.1.1.3 root 2759: init_sprites ();
2760:
1.1.1.2 root 2761: init_hardware_frame ();
1.1.1.4 ! root 2762: reset_drawing ();
! 2763:
1.1.1.2 root 2764: reset_decisions ();
1.1.1.3 root 2765:
1.1 root 2766: #ifdef HAVE_GETTIMEOFDAY
1.1.1.4 ! root 2767: gettimeofday (&tv, NULL);
1.1 root 2768: seconds_base = tv.tv_sec;
2769: bogusframe = 1;
2770: #endif
2771: }
2772:
1.1.1.3 root 2773: void dumpcustom (void)
1.1 root 2774: {
1.1.1.4 ! root 2775: fprintf (stderr, "DMACON: %x INTENA: %x INTREQ: %x VPOS: %x HPOS: %x\n", DMACONR(),
! 2776: (unsigned int)intena, (unsigned int)intreq, (unsigned int)vpos, (unsigned int)current_hpos());
! 2777: fprintf (stderr, "COP1LC: %08lx, COP2LC: %08lx\n", (unsigned long)cop1lc, (unsigned long)cop2lc);
1.1.1.3 root 2778: if (timeframes) {
1.1.1.4 ! root 2779: fprintf (stderr, "Average frame time: %d ms [frames: %d time: %d]\n",
! 2780: frametime/timeframes, timeframes, frametime);
1.1 root 2781: }
1.1.1.3 root 2782: dump_audio_bench ();
1.1.1.4 ! root 2783: /*for (i=0; i<256; i++) if (blitcount[i]) fprintf (stderr, "minterm %x = %d\n",i,blitcount[i]); blitter debug */
1.1 root 2784: }
2785:
1.1.1.3 root 2786: int intlev (void)
1.1 root 2787: {
1.1.1.3 root 2788: uae_u16 imask = intreq & intena;
1.1 root 2789: if (imask && (intena & 0x4000)){
2790: if (imask & 0x2000) return 6;
2791: if (imask & 0x1800) return 5;
2792: if (imask & 0x0780) return 4;
2793: if (imask & 0x0070) return 3;
2794: if (imask & 0x0008) return 2;
2795: if (imask & 0x0007) return 1;
2796: }
2797: return -1;
2798: }
2799:
1.1.1.4 ! root 2800: static void gen_custom_tables (void)
! 2801: {
! 2802: int i;
! 2803: for (i = 0; i < 256; i++) {
! 2804: unsigned int j;
! 2805: sprtaba[i] = ((((i >> 7) & 1) << 0)
! 2806: | (((i >> 6) & 1) << 2)
! 2807: | (((i >> 5) & 1) << 4)
! 2808: | (((i >> 4) & 1) << 6)
! 2809: | (((i >> 3) & 1) << 8)
! 2810: | (((i >> 2) & 1) << 10)
! 2811: | (((i >> 1) & 1) << 12)
! 2812: | (((i >> 0) & 1) << 14));
! 2813: sprtabb[i] = sprtaba[i] * 2;
! 2814: for (j = 0; j < 511; j = (j << 1) | 1)
! 2815: if ((i & ~j) == 0)
! 2816: waitmasktab[i] = ~j;
! 2817: }
! 2818: }
! 2819:
1.1.1.3 root 2820: void custom_init (void)
1.1 root 2821: {
1.1.1.4 ! root 2822: #ifdef OS_WITHOUT_MEMORY_MANAGEMENT
1.1 root 2823: int num;
1.1.1.2 root 2824:
1.1.1.4 ! root 2825: for (num = 0; num < 2; num++) {
! 2826: sprite_positions[num] = xmalloc (max_sprite_draw * sizeof (struct sprite_draw));
! 2827: color_changes[num] = xmalloc (max_color_change * sizeof (struct color_change));
1.1.1.2 root 2828: }
1.1.1.4 ! root 2829: delay_changes = xmalloc (max_delay_change * sizeof (struct delay_change));
1.1.1.2 root 2830: #endif
1.1.1.3 root 2831:
1.1.1.2 root 2832: init_decisions ();
2833:
1.1.1.4 ! root 2834: gen_custom_tables ();
! 2835: build_blitfilltable ();
! 2836:
! 2837: drawing_init ();
! 2838:
! 2839: mousestate = unknown_mouse;
! 2840:
! 2841: if (needmousehack ())
! 2842: mousehack_setfollow();
1.1 root 2843: }
2844:
2845: /* Custom chip memory bank */
2846:
1.1.1.4 ! root 2847: static uae_u32 custom_lget (uaecptr) REGPARAM;
! 2848: static uae_u32 custom_wget (uaecptr) REGPARAM;
! 2849: static uae_u32 custom_bget (uaecptr) REGPARAM;
! 2850: static void custom_lput (uaecptr, uae_u32) REGPARAM;
! 2851: static void custom_wput (uaecptr, uae_u32) REGPARAM;
! 2852: static void custom_bput (uaecptr, uae_u32) REGPARAM;
1.1 root 2853:
2854: addrbank custom_bank = {
2855: custom_lget, custom_wget, custom_bget,
2856: custom_lput, custom_wput, custom_bput,
2857: default_xlate, default_check
2858: };
2859:
1.1.1.3 root 2860: uae_u32 REGPARAM2 custom_wget (uaecptr addr)
1.1 root 2861: {
1.1.1.4 ! root 2862: switch (addr & 0x1FE) {
1.1 root 2863: case 0x002: return DMACONR();
2864: case 0x004: return VPOSR();
2865: case 0x006: return VHPOSR();
1.1.1.3 root 2866:
1.1 root 2867: case 0x008: return DSKDATR();
2868:
2869: case 0x00A: return JOY0DAT();
2870: case 0x00C: return JOY1DAT();
1.1.1.3 root 2871: case 0x00E: return CLXDAT();
1.1 root 2872: case 0x010: return ADKCONR();
2873:
2874: case 0x012: return POT0DAT();
2875: case 0x016: return POTGOR();
2876: case 0x018: return SERDATR();
2877: case 0x01A: return DSKBYTR();
2878: case 0x01C: return INTENAR();
2879: case 0x01E: return INTREQR();
2880: #if AGA_CHIPSET == 1
2881: case 0x07C: return 0xF8;
2882: #elif defined ECS_DENISE
2883: case 0x07C: return 0xFC;
2884: #endif
2885: default:
2886: custom_wput(addr,0);
2887: return 0xffff;
2888: }
2889: }
2890:
1.1.1.3 root 2891: uae_u32 REGPARAM2 custom_bget (uaecptr addr)
1.1 root 2892: {
2893: return custom_wget(addr & 0xfffe) >> (addr & 1 ? 0 : 8);
2894: }
2895:
1.1.1.3 root 2896: uae_u32 REGPARAM2 custom_lget (uaecptr addr)
1.1 root 2897: {
1.1.1.3 root 2898: return ((uae_u32)custom_wget(addr & 0xfffe) << 16) | custom_wget((addr+2) & 0xfffe);
1.1 root 2899: }
2900:
1.1.1.4 ! root 2901: void REGPARAM2 custom_wput_1 (int hpos, uaecptr addr, uae_u32 value)
1.1 root 2902: {
2903: addr &= 0x1FE;
1.1.1.3 root 2904: switch (addr) {
2905: case 0x020: DSKPTH (value); break;
2906: case 0x022: DSKPTL (value); break;
2907: case 0x024: DSKLEN (value); break;
2908: case 0x026: DSKDAT (value); break;
2909:
2910: case 0x02A: VPOSW (value); break;
2911: case 0x2E: COPCON (value); break;
2912: case 0x030: SERDAT (value); break;
2913: case 0x032: SERPER (value); break;
2914: case 0x34: POTGO (value); break;
2915: case 0x040: BLTCON0 (value); break;
2916: case 0x042: BLTCON1 (value); break;
2917:
2918: case 0x044: BLTAFWM (value); break;
2919: case 0x046: BLTALWM (value); break;
2920:
2921: case 0x050: BLTAPTH (value); break;
2922: case 0x052: BLTAPTL (value); break;
2923: case 0x04C: BLTBPTH (value); break;
2924: case 0x04E: BLTBPTL (value); break;
2925: case 0x048: BLTCPTH (value); break;
2926: case 0x04A: BLTCPTL (value); break;
2927: case 0x054: BLTDPTH (value); break;
2928: case 0x056: BLTDPTL (value); break;
2929:
2930: case 0x058: BLTSIZE (value); break;
2931:
2932: case 0x064: BLTAMOD (value); break;
2933: case 0x062: BLTBMOD (value); break;
2934: case 0x060: BLTCMOD (value); break;
2935: case 0x066: BLTDMOD (value); break;
2936:
2937: case 0x070: BLTCDAT (value); break;
2938: case 0x072: BLTBDAT (value); break;
2939: case 0x074: BLTADAT (value); break;
2940:
2941: case 0x07E: DSKSYNC (value); break;
2942:
2943: case 0x080: COP1LCH (value); break;
2944: case 0x082: COP1LCL (value); break;
2945: case 0x084: COP2LCH (value); break;
2946: case 0x086: COP2LCL (value); break;
2947:
2948: case 0x088: COPJMP1 (value); break;
2949: case 0x08A: COPJMP2 (value); break;
2950:
1.1.1.4 ! root 2951: case 0x08E: DIWSTRT (hpos, value); break;
! 2952: case 0x090: DIWSTOP (hpos, value); break;
! 2953: case 0x092: DDFSTRT (hpos, value); break;
! 2954: case 0x094: DDFSTOP (hpos, value); break;
1.1.1.3 root 2955:
2956: case 0x096: DMACON (value); break;
2957: case 0x098: CLXCON (value); break;
2958: case 0x09A: INTENA (value); break;
2959: case 0x09C: INTREQ (value); break;
2960: case 0x09E: ADKCON (value); break;
2961:
2962: case 0x0A0: AUDxLCH (0, value); break;
2963: case 0x0A2: AUDxLCL (0, value); break;
2964: case 0x0A4: AUDxLEN (0, value); break;
2965: case 0x0A6: AUDxPER (0, value); break;
2966: case 0x0A8: AUDxVOL (0, value); break;
2967: case 0x0AA: AUDxDAT (0, value); break;
2968:
2969: case 0x0B0: AUDxLCH (1, value); break;
2970: case 0x0B2: AUDxLCL (1, value); break;
2971: case 0x0B4: AUDxLEN (1, value); break;
2972: case 0x0B6: AUDxPER (1, value); break;
2973: case 0x0B8: AUDxVOL (1, value); break;
2974: case 0x0BA: AUDxDAT (1, value); break;
2975:
2976: case 0x0C0: AUDxLCH (2, value); break;
2977: case 0x0C2: AUDxLCL (2, value); break;
2978: case 0x0C4: AUDxLEN (2, value); break;
2979: case 0x0C6: AUDxPER (2, value); break;
2980: case 0x0C8: AUDxVOL (2, value); break;
2981: case 0x0CA: AUDxDAT (2, value); break;
2982:
2983: case 0x0D0: AUDxLCH (3, value); break;
2984: case 0x0D2: AUDxLCL (3, value); break;
2985: case 0x0D4: AUDxLEN (3, value); break;
2986: case 0x0D6: AUDxPER (3, value); break;
2987: case 0x0D8: AUDxVOL (3, value); break;
2988: case 0x0DA: AUDxDAT (3, value); break;
2989:
1.1.1.4 ! root 2990: case 0x0E0: BPLPTH (hpos, value, 0); break;
! 2991: case 0x0E2: BPLPTL (hpos, value, 0); break;
! 2992: case 0x0E4: BPLPTH (hpos, value, 1); break;
! 2993: case 0x0E6: BPLPTL (hpos, value, 1); break;
! 2994: case 0x0E8: BPLPTH (hpos, value, 2); break;
! 2995: case 0x0EA: BPLPTL (hpos, value, 2); break;
! 2996: case 0x0EC: BPLPTH (hpos, value, 3); break;
! 2997: case 0x0EE: BPLPTL (hpos, value, 3); break;
! 2998: case 0x0F0: BPLPTH (hpos, value, 4); break;
! 2999: case 0x0F2: BPLPTL (hpos, value, 4); break;
! 3000: case 0x0F4: BPLPTH (hpos, value, 5); break;
! 3001: case 0x0F6: BPLPTL (hpos, value, 5); break;
! 3002:
! 3003: case 0x100: BPLCON0 (hpos, value); break;
! 3004: case 0x102: BPLCON1 (hpos, value); break;
! 3005: case 0x104: BPLCON2 (hpos, value); break;
! 3006: case 0x106: BPLCON3 (hpos, value); break;
1.1.1.3 root 3007:
1.1.1.4 ! root 3008: case 0x108: BPL1MOD (hpos, value); break;
! 3009: case 0x10A: BPL2MOD (hpos, value); break;
1.1.1.3 root 3010:
3011: case 0x110: BPL1DAT (value); break;
3012: case 0x112: BPL2DAT (value); break;
3013: case 0x114: BPL3DAT (value); break;
3014: case 0x116: BPL4DAT (value); break;
3015: case 0x118: BPL5DAT (value); break;
3016: case 0x11A: BPL6DAT (value); break;
1.1 root 3017:
3018: case 0x180: case 0x182: case 0x184: case 0x186: case 0x188: case 0x18A:
3019: case 0x18C: case 0x18E: case 0x190: case 0x192: case 0x194: case 0x196:
3020: case 0x198: case 0x19A: case 0x19C: case 0x19E: case 0x1A0: case 0x1A2:
3021: case 0x1A4: case 0x1A6: case 0x1A8: case 0x1AA: case 0x1AC: case 0x1AE:
3022: case 0x1B0: case 0x1B2: case 0x1B4: case 0x1B6: case 0x1B8: case 0x1BA:
1.1.1.2 root 3023: case 0x1BC: case 0x1BE:
1.1.1.4 ! root 3024: COLOR (hpos, value & 0xFFF, (addr & 0x3E) / 2);
1.1.1.2 root 3025: break;
3026: case 0x120: case 0x124: case 0x128: case 0x12C:
1.1 root 3027: case 0x130: case 0x134: case 0x138: case 0x13C:
1.1.1.4 ! root 3028: SPRxPTH (hpos, value, (addr - 0x120) / 4);
1.1 root 3029: break;
1.1.1.2 root 3030: case 0x122: case 0x126: case 0x12A: case 0x12E:
1.1 root 3031: case 0x132: case 0x136: case 0x13A: case 0x13E:
1.1.1.4 ! root 3032: SPRxPTL (hpos, value, (addr - 0x122) / 4);
1.1 root 3033: break;
1.1.1.2 root 3034: case 0x140: case 0x148: case 0x150: case 0x158:
1.1 root 3035: case 0x160: case 0x168: case 0x170: case 0x178:
1.1.1.4 ! root 3036: SPRxPOS (hpos, value, (addr - 0x140) / 8);
1.1 root 3037: break;
1.1.1.2 root 3038: case 0x142: case 0x14A: case 0x152: case 0x15A:
1.1 root 3039: case 0x162: case 0x16A: case 0x172: case 0x17A:
1.1.1.4 ! root 3040: SPRxCTL (hpos, value, (addr - 0x142) / 8);
1.1 root 3041: break;
3042: case 0x144: case 0x14C: case 0x154: case 0x15C:
3043: case 0x164: case 0x16C: case 0x174: case 0x17C:
1.1.1.4 ! root 3044: SPRxDATA (hpos, value, (addr - 0x144) / 8);
1.1 root 3045: break;
1.1.1.2 root 3046: case 0x146: case 0x14E: case 0x156: case 0x15E:
1.1 root 3047: case 0x166: case 0x16E: case 0x176: case 0x17E:
1.1.1.4 ! root 3048: SPRxDATB (hpos, value, (addr - 0x146) / 8);
1.1 root 3049: break;
1.1.1.3 root 3050:
3051: case 0x36: JOYTEST (value); break;
3052: #if defined (ECS_AGNUS) || (AGA_CHIPSET == 1)
1.1 root 3053: case 0x5A: BLTCON0L(value); break;
1.1.1.3 root 3054: case 0x5C: BLTSIZV (value); break;
3055: case 0x5E: BLTSIZH (value); break;
1.1 root 3056: #endif
1.1.1.4 ! root 3057: #ifdef ECS_DENISE
! 3058: case 0x1E4: DIWHIGH (hpos, value); break;
! 3059: #endif
1.1 root 3060: #if AGA_CHIPSET == 1
1.1.1.4 ! root 3061: case 0x10C: BPLCON4 (hpos, value); break;
1.1 root 3062: case 0x1FC: fmode = value; break;
3063: #endif
3064: }
3065: }
3066:
1.1.1.4 ! root 3067: void REGPARAM2 custom_wput (uaecptr addr, uae_u32 value)
! 3068: {
! 3069: int hpos = current_hpos ();
! 3070: update_copper (hpos);
! 3071: custom_wput_1 (hpos, addr, value);
! 3072: }
! 3073:
! 3074: void REGPARAM2 custom_bput (uaecptr addr, uae_u32 value)
1.1 root 3075: {
1.1.1.2 root 3076: static int warned = 0;
3077: /* Is this correct now? (There are people who bput things to the upper byte of AUDxVOL). */
1.1.1.3 root 3078: uae_u16 rval = (value << 8) | (value & 0xFF);
1.1.1.2 root 3079: custom_wput(addr, rval);
3080: if (!warned)
1.1.1.3 root 3081: write_log ("Byte put to custom register.\n"), warned++;
1.1 root 3082: }
3083:
1.1.1.3 root 3084: void REGPARAM2 custom_lput(uaecptr addr, uae_u32 value)
1.1 root 3085: {
3086: custom_wput(addr & 0xfffe, value >> 16);
1.1.1.3 root 3087: custom_wput((addr+2) & 0xfffe, (uae_u16)value);
1.1 root 3088: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.