From 8e05936d103e6f24d8af06a9849bb054f8fbf166 Mon Sep 17 00:00:00 2001 From: Toni Wilen Date: Tue, 6 Apr 2021 21:18:23 +0300 Subject: [PATCH] Custom emulation update WIP --- custom.cpp | 220 ++++++++++++++++++++-------------------------------- drawing.cpp | 14 ++-- 2 files changed, 89 insertions(+), 145 deletions(-) diff --git a/custom.cpp b/custom.cpp index 0ac81657..1dad84ea 100644 --- a/custom.cpp +++ b/custom.cpp @@ -4432,7 +4432,8 @@ static void init_hz (bool checkvposw) minfirstline = 0; firstblankedline = vbstrt; } - + minfirstline++; + if (minfirstline < 2) minfirstline = 2; if (minfirstline >= maxvpos) @@ -4441,7 +4442,7 @@ static void init_hz (bool checkvposw) if (firstblankedline < minfirstline) firstblankedline = maxvpos + 1; - sprite_vblank_endline = minfirstline - 2; + sprite_vblank_endline = minfirstline - 1; maxvpos_nom = maxvpos; maxvpos_display = maxvpos; equ_vblank_endline = -1; @@ -4469,19 +4470,20 @@ static void init_hz (bool checkvposw) if (vblank_hz > 300) vblank_hz = 300; maxhpos_short = maxhpos; - set_delay_lastcycle (); + set_delay_lastcycle(); updateextblk(); - eventtab[ev_hsync].oldcycles = get_cycles (); - eventtab[ev_hsync].evtime = get_cycles () + HSYNCTIME; - events_schedule (); + eventtab[ev_hsync].oldcycles = get_cycles(); + eventtab[ev_hsync].evtime = get_cycles() + HSYNCTIME; + events_schedule(); if (hzc) { interlace_seen = islace; - reset_drawing (); + reset_drawing(); } maxvpos_total = ecs_agnus ? (MAXVPOS_LINES_ECS - 1) : (MAXVPOS_LINES_OCS - 1); - if (maxvpos_total > MAXVPOS) + if (maxvpos_total > MAXVPOS) { maxvpos_total = MAXVPOS; + } #ifdef PICASSO96 if (!p96refresh_active) { maxvpos_stored = maxvpos; @@ -4490,19 +4492,20 @@ static void init_hz (bool checkvposw) } #endif - compute_framesync (); + compute_framesync(); devices_syncchange(); #ifdef PICASSO96 init_hz_p96(0); #endif - if (vblank_hz != ovblank) + if (vblank_hz != ovblank) { updatedisplayarea(0); - inputdevice_tablet_strobe (); + } + inputdevice_tablet_strobe(); if (varsync_changed) { varsync_changed = false; - dumpsync (); + dumpsync(); } } @@ -5268,32 +5271,34 @@ bool INTREQ_0 (uae_u16 v) return true; } -void INTREQ (uae_u16 data) +void INTREQ(uae_u16 data) { if (INTREQ_0(data)) { rethink_intreq(); } } -static void ADKCON (int hpos, uae_u16 v) +static void ADKCON(int hpos, uae_u16 v) { - if (currprefs.produce_sound > 0) - update_audio (); - DISK_update (hpos); - DISK_update_adkcon (hpos, v); - setclr (&adkcon, v); - audio_update_adkmasks (); - if ((v >> 11) & 1) - serial_uartbreak ((adkcon >> 11) & 1); + if (currprefs.produce_sound > 0) { + update_audio(); + } + DISK_update(hpos); + DISK_update_adkcon(hpos, v); + setclr(&adkcon, v); + audio_update_adkmasks(); + if ((v >> 11) & 1) { + serial_uartbreak((adkcon >> 11) & 1); + } } -static void BEAMCON0 (uae_u16 v) +static void BEAMCON0(uae_u16 v) { if (ecs_agnus) { if (v != new_beamcon0) { new_beamcon0 = v; if (v & ~0x20) { - write_log (_T("warning: %04X written to BEAMCON0 PC=%08X\n"), v, M68K_GETPC); + write_log(_T("warning: %04X written to BEAMCON0 PC=%08X\n"), v, M68K_GETPC); dumpsync(); } } @@ -5302,7 +5307,7 @@ static void BEAMCON0 (uae_u16 v) } } -static void varsync (void) +static void varsync(void) { struct amigadisplay *ad = &adisplays[0]; if (!ecs_agnus) @@ -5319,7 +5324,7 @@ static void varsync (void) } #ifdef PICASSO96 -void set_picasso_hack_rate (int hz) +void set_picasso_hack_rate(int hz) { struct amigadisplay *ad = &adisplays[0]; if (!ad->picasso_on) @@ -5412,18 +5417,21 @@ static void BPLCON0_Denise(int hpos, uae_u16 v, bool immediate) static void BPLCON0(int hpos, uae_u16 v) { + uae_u16 old = bplcon0; bplcon0_saved = v; - if (!ecs_denise) + if (!ecs_denise) { v &= ~0x00F1; - else if (!aga_mode) + } else if (!aga_mode) { v &= ~0x00B0; + } v &= ~0x0080; #if SPRBORDER v |= 1; #endif - if (bplcon0 == v) + if (bplcon0 == v) { return; + } SET_LINE_CYCLEBASED; decide_diw(hpos); @@ -5434,10 +5442,6 @@ static void BPLCON0(int hpos, uae_u16 v) hpos_previous = hpos; } - if ((v & 1) != (bplcon0 & 1)) { - updateextblk(); - } - if (v & 4) { bplcon0_interlace_seen = true; } @@ -5456,6 +5460,10 @@ static void BPLCON0(int hpos, uae_u16 v) bplcon0 = v; + if ((old & 1) != (bplcon0 & 1)) { + updateextblk(); + } + bpldmainitdelay(hpos); if (thisline_decision.plfleft < 0) { @@ -5495,6 +5503,7 @@ static void BPLCON2(int hpos, uae_u16 v) #ifdef ECS_DENISE static void BPLCON3(int hpos, uae_u16 v) { + uae_u16 old = bplcon3; bplcon3_saved = v; if (!ecs_denise) return; @@ -5509,10 +5518,10 @@ static void BPLCON3(int hpos, uae_u16 v) return; decide_vline(hpos); decide_sprites(hpos); - if ((bplcon3 & 1) != (v & 1)) { + bplcon3 = v; + if ((bplcon3 & 1) != (old & 1)) { updateextblk(); } - bplcon3 = v; sprres = expand_sprres(bplcon0, bplcon3); record_register_change(hpos, 0x106, v); } @@ -6290,69 +6299,6 @@ static void COLOR_WRITE(int hpos, uae_u16 v, int num) } #endif } - -/* The copper code. The biggest nightmare in the whole emulator. - -Alright. The current theory: -1. Copper moves happen 2 cycles after state READ2 is reached. -It can't happen immediately when we reach READ2, because the -data needs time to get back from the bus. An additional 2 -cycles are needed for non-Agnus registers, to take into account -the delay for moving data from chip to chip. -2. As stated in the HRM, a WAIT really does need an extra cycle -to wake up. This is implemented by _not_ falling through from -a successful wait to READ1, but by starting the next cycle. -(Note: the extra cycle for the WAIT apparently really needs a -free cycle; i.e. contention with the bitplane fetch can slow -it down). -3. Apparently, to compensate for the extra wake up cycle, a WAIT -will use the _incremented_ horizontal position, so the WAIT -cycle normally finishes two clocks earlier than the position -it was waiting for. The extra cycle then takes us to the -position that was waited for. -If the earlier cycle is busy with a bitplane, things change a bit. -E.g., waiting for position 0x50 in a 6 plane display: In cycle -0x4e, we fetch BPL5, so the wait wakes up in 0x50, the extra cycle -takes us to 0x54 (since 0x52 is busy), then we have READ1/READ2, -and the next register write is at 0x5c. -4. The last cycle in a line is not usable for the copper. -5. A 4 cycle delay also applies to the WAIT instruction. This means -that the second of two back-to-back WAITs (or a WAIT whose -condition is immediately true) takes 8 cycles. -6. This also applies to a SKIP instruction. The copper does not -fetch the next instruction while waiting for the second word of -a WAIT or a SKIP to arrive. -7. A SKIP also seems to need an unexplained additional two cycles -after its second word arrives; this is _not_ a memory cycle (I -think, the documentation is pretty clear on this). -8. Two additional cycles are inserted when writing to COPJMP1/2. */ - -/* Determine which cycles are available for the copper in a display -* with a agiven number of planes. */ - -#if 0 -STATIC_INLINE int copper_cant_read2 (int hpos, int alloc) -{ -// if (hpos + 1 >= maxhpos) // first refresh slot -// return 1; - if ((hpos == 0) && (maxhpos & 1) && alloc >= 0) { - if (alloc) { - alloc_cycle (hpos, CYCLE_COPPER); -#ifdef DEBUGGER - if (debug_dma) { - record_dma_event(DMA_EVENT_NOONEGETS, hpos, vpos); - record_dma_read(0x1fe, cop_state.ip, hpos, vpos, DMARECORD_COPPER, 2); - uae_u16 v = chipmem_wget_indirect(cop_state.ip); - record_dma_read_value(v); - } -#endif - } - return -1; - } - return is_bitplane_dma_inline (hpos); -} -#endif - static bool copper_cant_read(uae_u16 *cp, uae_u16 alloc) { if (!dmaen(DMA_COPPER)) { @@ -6361,14 +6307,6 @@ static bool copper_cant_read(uae_u16 *cp, uae_u16 alloc) if (*cp != 0) { return true; } -#if 0 - int cant = copper_cant_read2 (hpos, alloc); -#ifdef DEBUGGER - if (cant && debug_dma) - record_dma_event (DMA_EVENT_COPPERWANTED, hpos, vpos); -#endif - return cant; -#endif if (alloc) { *cp = alloc; } @@ -6498,7 +6436,7 @@ static void decide_line_decision(int endhpos) if (!bprun && dma && diw && hwi && !hwi_old) { // Bitplane sequencer activated bprun = -1; - plfstrt_sprite = hpos + 3; + plfstrt_sprite = hpos + 4; } hwi_old = hwi; @@ -6898,14 +6836,18 @@ static void copper_ff(int hpos) last_copper_hpos = hpos; } -static int getcoppercomp(int hpos, bool blitwait) +static int coppercomp(int hpos, bool blitwait) { - int hpos_cmp = hpos + 1; + int hpos_cmp = hpos; int vpos_cmp = vpos; + + // Copper internal operations use mostly odd cycles + hpos_cmp += 1; if (hpos_cmp >= maxhpos) { hpos_cmp -= maxhpos; vpos_cmp++; } + int vp = vpos_cmp & (((cop_state.ir[1] >> 8) & 0x7F) | 0x80); int hp = hpos_cmp & (cop_state.ir[1] & 0xFE); @@ -6935,22 +6877,12 @@ static void update_copper(int until_hpos) { int hpos = last_copper_hpos; - if (0 && (nocustom() || !copper_enabled_thisline)) { + if (1 && (nocustom() || !copper_enabled_thisline)) { copper_ff(until_hpos); decide_line_decision(until_hpos); return; } -#if 0 - if (cop_state.state == COP_wait && vp < cop_state.vcmp) { - dump_copper (_T("error2"), until_hpos); - copper_enabled_thisline = 0; - cop_state.state = COP_stop; - unset_special (SPCFLAG_COPPER); - return; - } -#endif - while (hpos < until_hpos) { uae_u16 *cp; @@ -6968,11 +6900,9 @@ static void update_copper(int until_hpos) rga_pipeline[rpos] = 0; } -#if 1 if (!copper_enabled_thisline) { goto next; } -#endif if ((hpos & 1) != COPPER_CYCLE_POLARITY) { goto next; @@ -7048,23 +6978,34 @@ static void update_copper(int until_hpos) copper_cant_read(cp, 0x81); break; + // Request IR1 case COP_read1: copper_cant_read(cp, 0x82); break; + // Request IR2 case COP_read2: copper_cant_read(cp, 0x83); break; + // WAIT: Got IR2, first idle cycle. + // Need free cycle, cycle allocated. case COP_wait_in2: { if (copper_cant_read(cp, 0x8f)) { goto next; } cop_state.state = COP_wait1; + } + break; - int comp = getcoppercomp(hpos, true); + // WAIT: Second idle cycle. Wait until comparison matches. + // Need free cycle, cycle allocated. + case COP_wait1: + { + int comp = coppercomp(hpos, true); if (comp < 0) { + // If we need to wait for later scanline or blitter: no need to emulate copper cycle-by-cycle if (cop_state.ir[0] == 0xFFFF && cop_state.ir[1] == 0xFFFE) { cop_state.state = COP_waitforever; } @@ -7072,18 +7013,12 @@ static void update_copper(int until_hpos) unset_special(SPCFLAG_COPPER); goto next; } - - } - break; - - case COP_wait1: - { - if (copper_cant_read(cp, 0)) { + + if (comp) { goto next; } - int comp = getcoppercomp(hpos, true); - if (comp) { + if (copper_cant_read(cp, 0)) { goto next; } @@ -7092,6 +7027,7 @@ static void update_copper(int until_hpos) } break; + // Wait finished, request IR1. case COP_wait: { if (copper_cant_read(cp, 0x84)) { @@ -7110,6 +7046,8 @@ static void update_copper(int until_hpos) } break; + // SKIP: Got IR2. First idle cycle. + // Free cycle needed, cycle allocated. case COP_skip_in2: if (copper_cant_read(cp, 0x8f)) { @@ -7118,28 +7056,34 @@ static void update_copper(int until_hpos) cop_state.state = COP_skip1; break; + // SKIP: Second idle cycle. Check comparison. + // Free cycle needed, cycle allocated. case COP_skip1: if (copper_cant_read(cp, 0)) { goto next; } cop_state.state = COP_skip; - if (!getcoppercomp(hpos, false)) { + if (copper_cant_read(cp, 0x8f)) { + goto next; + } + + if (!coppercomp(hpos, false)) { cop_state.ignore_next = 1; } else { cop_state.ignore_next = -1; } - if (copper_cant_read(cp, 0x8f)) { - goto next; - } break; + // SKIP finished. Request IR1. case COP_skip: { + if (copper_cant_read(cp, 0x85)) { + goto next; + } cop_state.state = COP_read1; - copper_cant_read(cp, 0x85); #ifdef DEBUGGER if (debug_dma && cop_state.ignore_next > 0) @@ -7175,7 +7119,7 @@ static void compute_spcflag_copper(void) { if (!dmaen(DMA_COPPER) || cop_state.state == COP_stop || cop_state.state == COP_waitforever || cop_state.state == COP_bltwait || nocustom()) return; - if (cop_state.state == COP_wait) { + if (cop_state.state == COP_wait1) { int vp = vpos & (((cop_state.ir[1] >> 8) & 0x7F) | 0x80); if (vp < cop_state.vcmp) return; diff --git a/drawing.cpp b/drawing.cpp index b1180fdb..4dd75874 100644 --- a/drawing.cpp +++ b/drawing.cpp @@ -459,27 +459,27 @@ void get_custom_topedge (int *xp, int *yp, bool max) } } -static void reset_custom_limits (void) +static void reset_custom_limits(void) { gclow = gcloh = gclox = gcloy = 0; gclorealh = -1; center_reset = true; } -static void set_blanking_limits (void) +static void set_blanking_limits(void) { hblank_left_start = visible_left_start; hblank_right_stop = visible_right_stop; if (programmedmode) { - if (hblank_left_start < coord_hw_to_window_x (hsyncendpos * 2)) - hblank_left_start = coord_hw_to_window_x (hsyncendpos * 2); - if (hblank_right_stop > coord_hw_to_window_x (hsyncstartpos * 2)) - hblank_right_stop = coord_hw_to_window_x (hsyncstartpos * 2); + if (hblank_left_start < coord_hw_to_window_x(hsyncendpos * 2 + 1)) + hblank_left_start = coord_hw_to_window_x(hsyncendpos * 2 + 1); + if (hblank_right_stop > coord_hw_to_window_x(hsyncstartpos * 2 + 1)) + hblank_right_stop = coord_hw_to_window_x(hsyncstartpos * 2 + 1); } } -void get_custom_raw_limits (int *pw, int *ph, int *pdx, int *pdy) +void get_custom_raw_limits(int *pw, int *ph, int *pdx, int *pdy) { if (stored_width > 0) { *pw = stored_width; -- 2.47.3