First post, by guest
This forum's promptness in sending registration authentication email seems to be intolerably tardy, so I'm going to post this issue here annonymous for now rather than in the development forum.
In a nutshell, the CPU's AAA instruction is badly broken. 3072 out of 131072 variations in a testcase I have FAIL. Undoubtedly this is due to someone actually believing the bogus Intel docs on how AAA operates rather than having it match the silicon's behavior.
----- Test case source code (cut here) ---------
#pragma inline
//---------------------------------------------------------------------------
// See if AAA works as expected on 286/386/486/Pentium *SILICON*
//---------------------------------------------------------------------------
// Note: Intel docs on the AAA instruction are TOTALLY WRONG. The claimed
// behavior as documented in the programmers reference for the 386,
// 486 doesn't jive with the way the silicon behaves, *AND* what's
// worse...386/486/P5's behave DIFFERENTLY than an 8086 does!!!
//
// This test validates AAA behavior as the 286/386/486/P5, etc
// silicon OPERATES IN REALITY rather than is claimed in the buggy
// documentation. As such, it will produce thousands of failure
// messages if run on an 8086/8088.
//
// Intel *claims* AAA works like this on 386/486
//
// if (((AL & 0Fh) > 9) || (AF = 1))
// {
// AL = ((AL + 6) and 0Fh);
// AH = AH + 1;
// AF = 1;
// CF = 1;
// else
// {
// AF = 0;
// CF = 0;
// }
//
// The SILICON *actually* works like this on 286/386/486/P5
//
// if (((AL & 0Fh) > 9) || (AF = 1))
// {
// AX = AX + 6; // Double inc on AH if carry out
// AH = AH + 1; // from adding 6 to AX
// AL = (AL & 0Fh); // High nibble of AL is always 0
// AF = 1;
// CF = 1;
// else
// {
// AF = 0;
// CF = 0;
// }
//
//---------------------------------------------------------------------------
// I've tried this test on the following CPU's and got consistent results
// on all of them. As currently written, it "passes" on all these CPU's.
//
// Intel 286-10 (E-step level)
// Intel 386SX-20
// AMD 386SX-25
// Intel 386DX-20
// Intel 486SX-25
// Intel 486DX2-66
// Intel 486DX4-100
// Intel POD83 Pentium Upgrade for Socket 3
// Intel Pentium-60
// Intel Pentuim-75
// Intel Pentuim-90
// Intel Pentuim-133
// Intel Pentium 233MMX
// AMD K6/2-400
// Intel Pentium Pro 200 (256K L2)
// Intel Pentium Pro 200 (512K L2)
// Intel Pentium Pro 200 (1M L2)
// Intel Pentium II Overdrive for Pentium Pro
//---------------------------------------------------------------------------
// Compile this program with Borland C++ version 3.1 like this:
//
// bcc -v aaa.c
//---------------------------------------------------------------------------
#include <stdio.h>
#include <process.h>
#include <dos.h>
typedef unsigned long ULONG;
typedef unsigned short USHORT;
typedef unsigned char UCHAR;
#define AAA __emit__(0x37); /* An AAA instruction */
ULONG FailCount = 0L;
ULONG VarCount = 0L;
#define CF_SET 0x01
#define AF_SET 0x10
#define CF_CLEAR 0x00
#define AF_CLEAR 0x00
void _setenvp(void){}
void _setargv(void){}
/*-------------------------------------------------------------------------*/
/* Figure out what the result of an AAA will be if AF is set */
/*-------------------------------------------------------------------------*/
void AAA_AF_1(USHORT Rax, USHORT *AXresult, UCHAR *AFresult, UCHAR *CFresult)
{
asm mov ax, Rax
asm add ax, 6
asm inc ah
asm and al, 15
*AXresult = _AX;
*AFresult = AF_SET;
*CFresult = CF_SET;
}
/*-------------------------------------------------------------------------*/
/* Figure out what the result of an AAA will be if AF is clear */
/*-------------------------------------------------------------------------*/
void AAA_AF_0(USHORT Rax, USHORT *AXresult, UCHAR *AFresult, UCHAR *CFresult)
{
_AX = Rax;
if ((Rax & 0x000F) > 9)
{
asm mov ax, Rax
asm add ax, 6
asm inc ah
asm and al, 15
*AXresult = _AX;
*AFresult = AF_SET;
*CFresult = CF_SET;
}
else
{
*AXresult = (Rax & 0xFF0F);
*AFresult = AF_CLEAR;
*CFresult = CF_CLEAR;
}
}
void main(void)
{
ULONG AXval;
printf(
"+-----------------------------------------------------------------+\n"
"+ Test to validate behavior of 386/486/P5 silicon on AAA behavior +\n"
"+-----------------------------------------------------------------+\n"
);
for (AXval=0; AXval <= 65535L; AXval++)
{
USHORT ExpectedAX;
UCHAR ExpectedCF;
UCHAR ExpectedAF;
USHORT ReturnedFlags;
USHORT ReturnedAX;
if ((AXval % 5000L) == 0L)
printf("Working..... AXval=%lu\n", AXval);
/*---------------------------------------------------------------*/
/* Try out AXval with AF clear */
/*---------------------------------------------------------------*/
AAA_AF_0((USHORT)AXval, &ExpectedAX, &ExpectedAF, &ExpectedCF);
asm mov ah, 0
asm sahf
asm mov ax, word ptr AXval
asm aaa
ReturnedAX = _AX;
ReturnedFlags = _FLAGS;
VarCount++;
if (ReturnedAX != ExpectedAX)
{
FailCount++;
printf("FAIL:(AF=0)AX mismatch. Initial=%04X Expected=%04X Got=%04X\n",
(USHORT)AXval, ExpectedAX, ReturnedAX);
}
if ((UCHAR)(ReturnedFlags&1) != ExpectedCF)
{
FailCount++;
if (ExpectedCF)
printf("FAIL:(AF=0)InitialAX=%04X Expected CF=1, got CF=0\n",
(USHORT)AXval);
else
printf("FAIL:(AF=0)InitialAX=%04X Expected CF=0, got CF=1\n",
(USHORT)AXval);
}
if ((UCHAR)(ReturnedFlags & 0x10) != ExpectedAF)
{
FailCount++;
if (ExpectedAF)
printf("FAIL:(AF=0)InitialAX=%04X Expected AF=1, got AF=0\n",
(USHORT)AXval);
else
printf("FAIL:(AF=0)InitialAX=%04X Expected AF=0, got AF=1\n",
(USHORT)AXval);
}
/*---------------------------------------------------------------*/
/* Try out AXval with AF set */
/*---------------------------------------------------------------*/
AAA_AF_1((USHORT)AXval, &ExpectedAX, &ExpectedAF, &ExpectedCF);
asm mov ah, 10h
asm sahf
asm mov ax, word ptr AXval
asm aaa
ReturnedAX = _AX;
ReturnedFlags = _FLAGS;
VarCount++;
if (ReturnedAX != ExpectedAX)
{
FailCount++;
printf("FAIL:(AF=1)AX mismatch. Initial=%04X Expected=%04X Got=%04X\n",
(USHORT)AXval, ExpectedAX, ReturnedAX);
}
/*
We *always* expect CF and AF set after AAA if AF was set before
executing the instruction!
*/
if ((UCHAR)(ReturnedFlags & 1) != CF_SET)
{
FailCount++;
printf("FAIL:(AF=1)Initial=%04X Expected CF=1, got CF=0\n",
(USHORT)AXval);
}
if ((UCHAR)(ReturnedFlags & 0x10) != AF_SET)
{
FailCount++;
printf("FAIL:(AF=1)Initial=%04X Expected AF=1, got AF=0\n",
(USHORT)AXval);
}
}
printf("Variations = %lu\n", VarCount);
printf("Failures = %lu\n", FailCount);
if (FailCount != 0)
{
printf("*** THIS TEST FAILS! ***\n");
exit(-1);
}
printf("*** THIS TEST PASSED ***\n");
exit(0);
}