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