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