diff --git a/InstructionSets/x86/Implementation/PerformImplementation.hpp b/InstructionSets/x86/Implementation/PerformImplementation.hpp index ae4ff7100..fe27bbbde 100644 --- a/InstructionSets/x86/Implementation/PerformImplementation.hpp +++ b/InstructionSets/x86/Implementation/PerformImplementation.hpp @@ -1114,6 +1114,109 @@ inline void ror(IntT &destination, uint8_t count, Status &status) { (destination ^ (destination << 1)) & Numeric::top_bit() ); } + +/* + tempCOUNT ← (COUNT AND 1FH); + tempDEST ← DEST; + WHILE (tempCOUNT ≠ 0) + DO + IF instruction is SAL or SHL + THEN + CF ← MSB(DEST); + ELSE (* instruction is SAR or SHR *) + CF ← LSB(DEST); + FI; + IF instruction is SAL or SHL + THEN + DEST ← DEST ∗ 2; + ELSE + IF instruction is SAR + THEN + DEST ← DEST / 2 (*Signed divide, rounding toward negative infinity*); + ELSE (* instruction is SHR *) + DEST ← DEST / 2 ; (* Unsigned divide *); + FI; + FI; + tempCOUNT ← tempCOUNT – 1; + OD; + (* Determine overflow for the various instructions *) + IF COUNT = 1 + THEN + IF instruction is SAL or SHL + THEN + OF ← MSB(DEST) XOR CF; + ELSE + IF instruction is SAR + THEN + OF ← 0; + ELSE (* instruction is SHR *) + OF ← MSB(tempDEST); + FI; + FI; + ELSE + IF COUNT = 0 + THEN + All flags remain unchanged; + ELSE (* COUNT neither 1 or 0 *) + OF ← undefined; + FI; + FI; +*/ +/* + The CF flag contains the value of the last bit shifted out of the destination operand; + it is undefined for SHL and SHR instructions where the count is greater than or equal to + the size (in bits) of the destination operand. The OF flag is affected only for 1-bit shifts + (see “Description” above); otherwise, it is undefined. + + The SF, ZF, and PF flags are set according to the result. If the count is 0, the flags are not affected. + For a non-zero count, the AF flag is undefined. +*/ +template +inline void sal(IntT &destination, uint8_t count, Status &status) { + switch(count) { + case 0: return; + case Numeric::bit_size(): + status.set_from(destination & 1); + destination = 0; + break; + default: + if(count > Numeric::bit_size()) { + status.set_from(0); + destination = 0; + } else { + const auto mask = (Numeric::top_bit() >> (count - 1)); + status.set_from( + destination & mask + ); + status.set_from( + (destination ^ (destination << 1)) & mask + ); + destination <<= count; + } + break; + } + status.set_from(destination); +} + +template +inline void sar(IntT &destination, uint8_t count, Status &status) { + if(!count) { + return; + } + + const IntT sign = Numeric::top_bit() & destination; + if(count >= Numeric::bit_size()) { + destination = sign ? IntT(~0) : IntT(0); + status.set_from(sign); + } else { + const IntT mask = 1 << (count - 1); + status.set_from(destination & mask); + destination = (destination >> count) | (sign ? ~(IntT(~0) >> count) : 0); + } + status.set_from(0); + status.set_from(destination); +} + } template < @@ -1279,6 +1382,8 @@ template < case Operation::RCR: Primitive::rcr(destination(), shift_count(), status); break; case Operation::ROL: Primitive::rol(destination(), shift_count(), status); break; case Operation::ROR: Primitive::ror(destination(), shift_count(), status); break; + case Operation::SAL: Primitive::sal(destination(), shift_count(), status); break; + case Operation::SAR: Primitive::sar(destination(), shift_count(), status); break; case Operation::CLC: Primitive::clc(status); return; case Operation::CLD: Primitive::cld(status); return; diff --git a/OSBindings/Mac/Clock SignalTests/8088Tests.mm b/OSBindings/Mac/Clock SignalTests/8088Tests.mm index c8726a549..9ddb18646 100644 --- a/OSBindings/Mac/Clock SignalTests/8088Tests.mm +++ b/OSBindings/Mac/Clock SignalTests/8088Tests.mm @@ -415,7 +415,6 @@ struct FailedExecution { // NOP @"90.json.gz", -*/ // TODO: POP, POPF, PUSH, PUSHF // TODO: SAL, SAR, SHR @@ -435,6 +434,15 @@ struct FailedExecution { // ROR @"D0.1.json.gz", @"D2.1.json.gz", @"D1.1.json.gz", @"D3.1.json.gz", +*/ + + // SAL +// @"D0.4.json.gz", @"D2.4.json.gz", +// @"D1.4.json.gz", @"D3.4.json.gz", + + // SAR + @"D0.7.json.gz", @"D2.7.json.gz", + @"D1.7.json.gz", @"D3.7.json.gz", /* @"F8.json.gz", // CLC