diff --git a/src/hardware/pic.cpp b/src/hardware/pic.cpp index 412bd467..983d61f8 100644 --- a/src/hardware/pic.cpp +++ b/src/hardware/pic.cpp @@ -244,6 +244,17 @@ static Bitu read_data(Bitu port,Bitu iolen) { void PIC_ActivateIRQ(Bitu irq) { + if (GCC_UNLIKELY(CPU_Cycles)) { + // CPU_Cycles nonzero means the interrupt was triggered by an I/O + // register write rather than an event. + // Real hardware executes 0 to ~13 NOPs or comparable instructions + // before the processor picks up the interrupt. Let's try with 2 + // cycles here. + // Required by Panic demo (irq0), It came from the desert (MPU401) + // Does it matter if CPU_CycleLeft becomes negative? + CPU_CycleLeft += (CPU_Cycles-2); + CPU_Cycles=2; + } if( irq < 8 ) { irqs[irq].active = true; if (!irqs[irq].masked) { diff --git a/src/hardware/timer.cpp b/src/hardware/timer.cpp index a4a7c503..85f7998e 100644 --- a/src/hardware/timer.cpp +++ b/src/hardware/timer.cpp @@ -138,8 +138,14 @@ static void counter_latch(Bitu counter) { p->go_read_latch=false; //If gate2 is disabled don't update the read_latch - if(counter == 2 && !gate2 && p->mode !=1) return; - + if (counter == 2 && !gate2 && p->mode !=1) return; + if (GCC_UNLIKELY(p->new_mode)) { + double passed_time = PIC_FullIndex() - p->start; + Bitu ticks_since_then = (Bitu)(passed_time / (1000.0/PIT_TICK_RATE)); + //if (p->mode==3) ticks_since_then /= 2; // TODO figure this out on real hardware + p->read_latch -= ticks_since_then; + return; + } double index=PIC_FullIndex()-p->start; switch (p->mode) { case 4: /* Software Triggered Strobe */ @@ -299,6 +305,10 @@ static void write_p43(Bitu /*port*/,Bitu val,Bitu /*iolen*/) { /* Counter latch command */ counter_latch(latch); } else { + // save output status to be used with timer 0 irq + bool old_output = counter_output(0); + // save the current count value to be re-used in undocumented newmode + counter_latch(latch); pit[latch].bcd = (val&1)>0; if (val & 1) { if(pit[latch].cntr>=9999) pit[latch].cntr=9999; @@ -309,6 +319,8 @@ static void write_p43(Bitu /*port*/,Bitu val,Bitu /*iolen*/) { pit[latch].counterstatus_set=false; latched_timerstatus_locked=false; } + pit[latch].start = PIC_FullIndex(); // for undocumented newmode + pit[latch].go_read_latch = true; pit[latch].update_count = false; pit[latch].counting = false; pit[latch].read_state = (val >> 4) & 0x03; @@ -317,9 +329,7 @@ static void write_p43(Bitu /*port*/,Bitu val,Bitu /*iolen*/) { if (mode > 5) mode -= 4; //6,7 become 2 and 3 - /* Don't set it directly so counter_output uses the old mode */ - /* That's theory. It breaks panic. So set it here again */ - if(!pit[latch].mode) pit[latch].mode = mode; + pit[latch].mode = mode; /* If the line goes from low to up => generate irq. * ( BUT needs to stay up until acknowlegded by the cpu!!! therefore: ) @@ -327,20 +337,17 @@ static void write_p43(Bitu /*port*/,Bitu val,Bitu /*iolen*/) { * Mode 0 starts with a low line. (so always disable irq) * Mode 2,3 start with a high line. * counter_output tells if the current counter is high or low - * So actually a mode 2 timer enables and disables irq al the time. (not handled) */ + * So actually a mode 3 timer enables and disables irq al the time. (not handled) */ if (latch == 0) { PIC_RemoveEvents(PIT0_Event); - if (!counter_output(0) && mode) { + if((mode != 0)&& !old_output) { PIC_ActivateIRQ(0); - //Don't raise instantaniously. (Origamo) - if(CPU_Cycles < 25) CPU_Cycles = 25; - } - if(!mode) + } else { PIC_DeActivateIRQ(0); + } } pit[latch].new_mode = true; - pit[latch].mode = mode; //Set the correct mode (here) } break; case 3: