more precise PIT gate emulation


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@499 c046a42c-6fe2-441c-8c8c-71466251a162
diff --git a/vl.c b/vl.c
index 830b546..9b1a3fc 100644
--- a/vl.c
+++ b/vl.c
@@ -1002,6 +1002,10 @@
     case 5:
         counter = (s->count - d) & 0xffff;
         break;
+    case 3:
+        /* XXX: may be incorrect for odd counts */
+        counter = s->count - ((2 * d) % s->count);
+        break;
     default:
         counter = s->count - (d % s->count);
         break;
@@ -1031,7 +1035,7 @@
             out = 0;
         break;
     case 3:
-        out = (d % s->count) < (s->count >> 1);
+        out = (d % s->count) < ((s->count + 1) >> 1);
         break;
     case 4:
     case 5:
@@ -1074,7 +1078,7 @@
         ret = d2 - d1;
         break;
     case 3:
-        v = s->count - (s->count >> 1);
+        v = s->count - ((s->count + 1) >> 1);
         d1 = (d1 + v) / s->count;
         d2 = (d2 + v) / s->count;
         ret = d2 - d1;
@@ -1090,6 +1094,36 @@
     return ret;
 }
 
+/* val must be 0 or 1 */
+static inline void pit_set_gate(PITChannelState *s, int val)
+{
+    switch(s->mode) {
+    default:
+    case 0:
+    case 4:
+        /* XXX: just disable/enable counting */
+        break;
+    case 1:
+    case 5:
+        if (s->gate < val) {
+            /* restart counting on rising edge */
+            s->count_load_time = cpu_get_ticks();
+            s->count_last_edge_check_time = s->count_load_time;
+        }
+        break;
+    case 2:
+    case 3:
+        if (s->gate < val) {
+            /* restart counting on rising edge */
+            s->count_load_time = cpu_get_ticks();
+            s->count_last_edge_check_time = s->count_load_time;
+        }
+        /* XXX: disable/enable counting */
+        break;
+    }
+    s->gate = val;
+}
+
 static inline void pit_load_count(PITChannelState *s, int val)
 {
     if (val == 0)
@@ -1185,7 +1219,7 @@
 void speaker_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val)
 {
     speaker_data_on = (val >> 1) & 1;
-    pit_channels[2].gate = val & 1;
+    pit_set_gate(&pit_channels[2], val & 1);
 }
 
 uint32_t speaker_ioport_read(CPUX86State *env, uint32_t addr)
@@ -1463,7 +1497,6 @@
             serial_update_irq();
             break;
         case 'd':
-            //            tb_flush();
             cpu_set_log(CPU_LOG_ALL);
             break;
         case TERM_ESCAPE:
@@ -2128,7 +2161,7 @@
     KBDState *s = &kbd_state;
     int val;
     val = s->status;
-#if defined(DEBUG_KBD)
+#if defined(DEBUG_KBD) && 0
     printf("kbd: read status=0x%02x\n", val);
 #endif
     return val;