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