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