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