minfirstline = 0;
firstblankedline = vbstrt;
}
-
+ minfirstline++;
+
if (minfirstline < 2)
minfirstline = 2;
if (minfirstline >= maxvpos)
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;
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;
}
#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();
}
}
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();
}
}
}
}
-static void varsync (void)
+static void varsync(void)
{
struct amigadisplay *ad = &adisplays[0];
if (!ecs_agnus)
}
#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)
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);
hpos_previous = hpos;
}
- if ((v & 1) != (bplcon0 & 1)) {
- updateextblk();
- }
-
if (v & 4) {
bplcon0_interlace_seen = true;
}
bplcon0 = v;
+ if ((old & 1) != (bplcon0 & 1)) {
+ updateextblk();
+ }
+
bpldmainitdelay(hpos);
if (thisline_decision.plfleft < 0) {
#ifdef ECS_DENISE
static void BPLCON3(int hpos, uae_u16 v)
{
+ uae_u16 old = bplcon3;
bplcon3_saved = v;
if (!ecs_denise)
return;
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);
}
}
#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)) {
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;
}
if (!bprun && dma && diw && hwi && !hwi_old) {
// Bitplane sequencer activated
bprun = -1;
- plfstrt_sprite = hpos + 3;
+ plfstrt_sprite = hpos + 4;
}
hwi_old = hwi;
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);
{
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;
rga_pipeline[rpos] = 0;
}
-#if 1
if (!copper_enabled_thisline) {
goto next;
}
-#endif
if ((hpos & 1) != COPPER_CYCLE_POLARITY) {
goto next;
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;
}
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;
}
}
break;
+ // Wait finished, request IR1.
case COP_wait:
{
if (copper_cant_read(cp, 0x84)) {
}
break;
+ // SKIP: Got IR2. First idle cycle.
+ // Free cycle needed, cycle allocated.
case COP_skip_in2:
if (copper_cant_read(cp, 0x8f)) {
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)
{
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;