From 9ad9e65d64593a7a574b47c6aead26e97f849a4e Mon Sep 17 00:00:00 2001
From: James Abbatiello <abbeyj@wpi.edu>
Date: Tue, 22 Aug 2000 20:38:47 +0000
Subject: [PATCH] Fixes for reading latched values with ports 0x40-0x43.

---
 msdos/ioports.c | 208 +++++++++++++++++++++++++-----------------------
 1 file changed, 110 insertions(+), 98 deletions(-)

diff --git a/msdos/ioports.c b/msdos/ioports.c
index a965d02fb08..d72651d5088 100644
--- a/msdos/ioports.c
+++ b/msdos/ioports.c
@@ -26,14 +26,18 @@
 
 DEFAULT_DEBUG_CHANNEL(int)
 
-static WORD tmr_8253_countmax[3] = {0xffff, 0x12, 1}; /* [2] needs to be 1 ! */
-/* if byte_toggle is TRUE, then hi byte has already been written */
-static BOOL16 tmr_8253_byte_toggle[3] = {FALSE, FALSE, FALSE};
-static WORD tmr_8253_latch[3] = {0, 0, 0};
-
-/* 4th contents are dummy */
-static BOOL16 tmr_8253_latched[4] = {FALSE, FALSE, FALSE, FALSE};
-static BYTE tmr_8253_ctrlbyte_ch[4] = {0x06, 0x44, 0x86, 0};
+static struct {
+    WORD	countmax;
+    BOOL16	byte_toggle; /* if TRUE, then hi byte has already been written */
+    WORD	latch;
+    BOOL16	latched;
+    BYTE	ctrlbyte_ch;
+    WORD	oldval;
+} tmr_8253[3] = {
+    {0xFFFF,	FALSE,	0,	FALSE,	0x06,	0},
+    {0x0012,	FALSE,	0,	FALSE,	0x44,	0},
+    {0x0001,	FALSE,	0,	FALSE,	0x86,	0},
+};
 
 static int dummy_ctr = 0;
 
@@ -275,54 +279,53 @@ DWORD IO_inport( int port, int size )
 
     switch (port)
     {
-    case 0x3ba:
-    case 0x3da:
-        res = (DWORD)VGA_ioport_in( port );
-        break;
     case 0x40:
     case 0x41:
     case 0x42:
     {
         BYTE chan = port & 3;
         WORD tempval = 0;
+	if (tmr_8253[chan].latched)
+	    tempval = tmr_8253[chan].latch;
+	else
+	{
+	    dummy_ctr -= 1 + (int)(10.0 * rand() / (RAND_MAX + 1.0));
+	    if (chan == 0) /* System timer counter divisor */
+	    {
+		/* FIXME: DOSVM_GetTimer() returns quite rigid values */
+		tempval = dummy_ctr + (WORD)DOSVM_GetTimer();
+	    }
+	    else
+	    {
+		/* FIXME: intelligent hardware timer emulation needed */
+		tempval = dummy_ctr;
+	    }
+	}
 
-        if (tmr_8253_latched[chan] == TRUE)
+        switch ((tmr_8253[chan].ctrlbyte_ch & 0x30) >> 4)
         {
-            tempval = tmr_8253_latch[chan];
-            tmr_8253_latched[chan] = FALSE;
-        }
-        else
-        {
-            dummy_ctr -= 1+(int) (10.0*rand()/(RAND_MAX+1.0));
-        if (chan == 0) /* System timer counter divisor */
-                /* FIXME: DOSVM_GetTimer() returns quite rigid values */
-				tempval = dummy_ctr+(WORD)DOSVM_GetTimer();
-        else
-        {   /* FIXME: intelligent hardware timer emulation needed */
-            tempval = dummy_ctr;
-        }
-        }
-        switch (tmr_8253_ctrlbyte_ch[chan] & 0x30)
-        {
-        case 0x00:
-            break; /* correct ? */
-        case 0x10: /* read lo byte */
-            res = (BYTE)tempval;
-            break;
-        case 0x30: /* read lo byte, then hi byte */
-            tmr_8253_byte_toggle[chan] ^= TRUE; /* toggle */
-            if (tmr_8253_byte_toggle[chan] == TRUE)
+        case 0:
+	    res = 0; /* shouldn't happen? */
+	    break;
+        case 1: /* read lo byte */
+	    res = (BYTE)tempval;
+	    tmr_8253[chan].latched = FALSE;
+	    break;
+        case 3: /* read lo byte, then hi byte */
+            tmr_8253[chan].byte_toggle ^= TRUE; /* toggle */
+            if (tmr_8253[chan].byte_toggle)
             {
                 res = (BYTE)tempval;
                 break;
             }
             /* else [fall through if read hi byte !] */
-        case 0x20: /* read hi byte */
-            res = (BYTE)tempval>>8;
-            break;
+        case 2: /* read hi byte */
+	    res = (BYTE)(tempval >> 8);
+ 	    tmr_8253[chan].latched = FALSE;
+	    break;
         }
-        break;
     }
+    break;
     case 0x60:
         res = INT_Int09ReadScan(NULL);
 #if 0 /* what's this port got to do with parport ? */
@@ -345,6 +348,10 @@ DWORD IO_inport( int port, int size )
     case 0x201:
         res = 0xffffffff; /* no joystick */
         break;
+    case 0x3ba:
+    case 0x3da:
+        res = (DWORD)VGA_ioport_in( port );
+        break;
     default:
         WARN("Direct I/O read attempted from port %x\n", port);
         res = 0xffffffff;
@@ -385,10 +392,6 @@ void IO_outport( int port, int size, DWORD value )
 
     switch (port)
     {
-    case 0x3c8:
-    case 0x3c9:
-        VGA_ioport_out( port, (BYTE)value );
-        break;
     case 0x20:
         DOSVM_PIC_ioport_out( port, (BYTE)value );
         break;
@@ -397,74 +400,79 @@ void IO_outport( int port, int size, DWORD value )
     case 0x42:
     {
         BYTE chan = port & 3;
-        WORD oldval = 0;
 
-        if ( ((tmr_8253_ctrlbyte_ch[chan] & 0x30) != 0x30) ||
-/* we need to get the oldval before any lo/hi byte change has been made */
-             (tmr_8253_byte_toggle[chan] == FALSE) )
-            oldval = tmr_8253_countmax[chan];
-        switch (tmr_8253_ctrlbyte_ch[chan] & 0x30)
+	/* we need to get the oldval before any lo/hi byte change has been made */
+        if (((tmr_8253[chan].ctrlbyte_ch & 0x30) != 0x30) ||
+	    !tmr_8253[chan].byte_toggle)
+            tmr_8253[chan].oldval = tmr_8253[chan].countmax;
+        switch ((tmr_8253[chan].ctrlbyte_ch & 0x30) >> 4)
         {
-        case 0x00:
-            break; /* correct ? */
-        case 0x10: /* write lo byte */
-            tmr_8253_countmax[chan] =
-                (tmr_8253_countmax[chan] & 0xff00) | (BYTE)value;
+        case 0:
+            break; /* shouldn't happen? */
+        case 1: /* write lo byte */
+            tmr_8253[chan].countmax =
+                (tmr_8253[chan].countmax & 0xff00) | (BYTE)value;
             break;
-        case 0x30: /* write lo byte, then hi byte */
-            tmr_8253_byte_toggle[chan] ^= TRUE; /* toggle */
-            if (tmr_8253_byte_toggle[chan] == TRUE)
+        case 3: /* write lo byte, then hi byte */
+            tmr_8253[chan].byte_toggle ^= TRUE; /* toggle */
+            if (tmr_8253[chan].byte_toggle)
             {
-                tmr_8253_countmax[chan] =
-                    (tmr_8253_countmax[chan] & 0xff00) | (BYTE)value;
+                tmr_8253[chan].countmax =
+                    (tmr_8253[chan].countmax & 0xff00) | (BYTE)value;
                 break;
             }
             /* else [fall through if write hi byte !] */
-        case 0x20: /* write hi byte */
-            tmr_8253_countmax[chan] =
-                (tmr_8253_countmax[chan] & 0xff)|((BYTE)value << 8);
+        case 2: /* write hi byte */
+            tmr_8253[chan].countmax =
+                (tmr_8253[chan].countmax & 0x00ff) | ((BYTE)value << 8);
             break;
         }
-        if (
-            /* programming finished ? */
-            ( ((tmr_8253_ctrlbyte_ch[chan] & 0x30) != 0x30) ||
-              (tmr_8253_byte_toggle[chan] == FALSE) )
-            /* update to new value ? */
-            && (tmr_8253_countmax[chan] != oldval)
-            )
-            set_timer_maxval(chan, tmr_8253_countmax[chan]);
+	/* if programming is finished and value has changed
+	   then update to new value */
+        if ((((tmr_8253[chan].ctrlbyte_ch & 0x30) != 0x30) ||
+	     !tmr_8253[chan].byte_toggle) &&
+	    (tmr_8253[chan].countmax != tmr_8253[chan].oldval))
+            set_timer_maxval(chan, tmr_8253[chan].countmax);
     }
     break;          
     case 0x43:
-        {
-          BYTE chan = ((BYTE)value & 0xc0) >> 6;
-
-        /* ctrl byte for specific timer channel */
-          tmr_8253_ctrlbyte_ch[chan] = (BYTE)value;
-          if (chan == 3) {
-            FIXME("8254 timer readback not implemented yet\n");
-            }
-          else
-          if (((BYTE)value&0x30)==0) { /* latch timer */
-            tmr_8253_latched[chan] = TRUE;
-            dummy_ctr -= 1+(int) (10.0*rand()/(RAND_MAX+1.0));
-            if (chan == 0) /* System timer divisor */
-              tmr_8253_latch[0] = dummy_ctr+(WORD)DOSVM_GetTimer();
-            else
-            {   /* FIXME: intelligent hardware timer emulation needed */
-              tmr_8253_latch[chan] = dummy_ctr;
-            }
-          }
-        if ((value & 0x30) == 0x30) /* write lo byte, then hi byte */
-            tmr_8253_byte_toggle[((BYTE)value & 0xc0) >> 6] = FALSE; /* init */
-        }
-        break;
+    {
+	BYTE chan = ((BYTE)value & 0xc0) >> 6;
+	/* ctrl byte for specific timer channel */
+	if (chan == 3)
+	{
+	    FIXME("8254 timer readback not implemented yet\n");
+	    break;
+	}
+	switch (((BYTE)value & 0x30) >> 4)
+	{
+	case 0:	/* latch timer */
+	    tmr_8253[chan].latched = TRUE;
+	    dummy_ctr -= 1 + (int)(10.0 * rand() / (RAND_MAX + 1.0));
+	    if (chan == 0) /* System timer divisor */
+		tmr_8253[chan].latch = dummy_ctr + (WORD)DOSVM_GetTimer();
+	    else
+	    {
+		/* FIXME: intelligent hardware timer emulation needed */
+		tmr_8253[chan].latch = dummy_ctr;
+	    }
+	    break;
+	case 3:	/* write lo byte, then hi byte */
+	    tmr_8253[chan].byte_toggle = FALSE; /* init */
+	    /* fall through */
+	case 1:	/* write lo byte only */
+	case 2:	/* write hi byte only */
+	    tmr_8253[chan].ctrlbyte_ch = (BYTE)value;
+	    break;
+	}
+    }
+    break;
     case 0x61:
         parport_8255[1] = (BYTE)value;
-        if ((((BYTE)parport_8255[1] & 3) == 3) && (tmr_8253_countmax[2] != 1))
+        if ((((BYTE)parport_8255[1] & 3) == 3) && (tmr_8253[2].countmax != 1))
         {
-            TRACE("Beep (freq: %d) !\n", 1193180 / tmr_8253_countmax[2]);
-            Beep(1193180 / tmr_8253_countmax[2], 20);
+            TRACE("Beep (freq: %d) !\n", 1193180 / tmr_8253[2].countmax);
+            Beep(1193180 / tmr_8253[2].countmax, 20);
         }
         break;
     case 0x70:
@@ -473,6 +481,10 @@ void IO_outport( int port, int size, DWORD value )
     case 0x71:
         cmosimage[cmosaddress & 0x3f] = (BYTE)value;
         break;
+    case 0x3c8:
+    case 0x3c9:
+        VGA_ioport_out( port, (BYTE)value );
+        break;
     default:
         WARN("Direct I/O write attempted to port %x\n", port );
         break;
-- 
GitLab