diff --git a/InstructionSets/x86/Implementation/PerformImplementation.hpp b/InstructionSets/x86/Implementation/PerformImplementation.hpp index b66369c8e..ae4ff7100 100644 --- a/InstructionSets/x86/Implementation/PerformImplementation.hpp +++ b/InstructionSets/x86/Implementation/PerformImplementation.hpp @@ -1021,7 +1021,99 @@ inline void rcr(IntT &destination, uint8_t count, Status &status) { status.set_from(carry); } +template +inline void rol(IntT &destination, uint8_t count, Status &status) { + /* + (* ROL and ROR instructions *) + SIZE ← OperandSize + CASE (determine count) OF + SIZE = 8: tempCOUNT ← COUNT MOD 8; + SIZE = 16: tempCOUNT ← COUNT MOD 16; + SIZE = 32: tempCOUNT ← COUNT MOD 32; + ESAC; + */ + /* + (* ROL instruction operation *) + WHILE (tempCOUNT ≠ 0) + DO + tempCF ← MSB(DEST); + DEST ← (DEST * 2) + tempCF; + tempCOUNT ← tempCOUNT – 1; + OD; + ELIHW; + IF COUNT = 1 + THEN OF ← MSB(DEST) XOR CF; + ELSE OF is undefined; + FI; + */ + /* + The CF flag contains the value of the bit shifted into it. + The OF flag is affected only for single- bit rotates (see “Description” above); + it is undefined for multi-bit rotates. The SF, ZF, AF, and PF flags are not affected. + */ + const auto temp_count = count & (Numeric::bit_size() - 1); + if(!count) { + // TODO: is this 8086-specific? i.e. do the other x86s also exit without affecting flags when temp_count = 0? + return; + } + if(temp_count) { + destination = + (destination << temp_count) | + (destination >> (Numeric::bit_size() - temp_count)); + } + status.set_from(destination & 1); + status.set_from( + ((destination >> (Numeric::bit_size() - 1)) ^ destination) & 1 + ); +} + +template +inline void ror(IntT &destination, uint8_t count, Status &status) { + /* + (* ROL and ROR instructions *) + SIZE ← OperandSize + CASE (determine count) OF + SIZE = 8: tempCOUNT ← COUNT MOD 8; + SIZE = 16: tempCOUNT ← COUNT MOD 16; + SIZE = 32: tempCOUNT ← COUNT MOD 32; + ESAC; + */ + /* + (* ROR instruction operation *) + WHILE (tempCOUNT ≠ 0) + DO + tempCF ← LSB(DEST); + DEST ← (DEST / 2) + (tempCF * 2^SIZE); + tempCOUNT ← tempCOUNT – 1; + OD; + ELIHW; + IF COUNT = 1 + THEN OF ← MSB(DEST) XOR MSB - 1 (DEST); + ELSE OF is undefined; + FI; + */ + /* + The CF flag contains the value of the bit shifted into it. + The OF flag is affected only for single- bit rotates (see “Description” above); + it is undefined for multi-bit rotates. The SF, ZF, AF, and PF flags are not affected. + */ + const auto temp_count = count & (Numeric::bit_size() - 1); + if(!count) { + // TODO: is this 8086-specific? i.e. do the other x86s also exit without affecting flags when temp_count = 0? + return; + } + if(temp_count) { + destination = + (destination >> temp_count) | + (destination << (Numeric::bit_size() - temp_count)); + } + + status.set_from(destination & Numeric::top_bit()); + status.set_from( + (destination ^ (destination << 1)) & Numeric::top_bit() + ); +} } template < @@ -1185,6 +1277,8 @@ template < case Operation::RCL: Primitive::rcl(destination(), shift_count(), status); break; 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::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 0d78ca6aa..c8726a549 100644 --- a/OSBindings/Mac/Clock SignalTests/8088Tests.mm +++ b/OSBindings/Mac/Clock SignalTests/8088Tests.mm @@ -418,16 +418,24 @@ struct FailedExecution { */ // TODO: POP, POPF, PUSH, PUSHF - // TODO: ROL, ROR, SAL, SAR, SHR + // TODO: SAL, SAR, SHR // RCL -// @"D0.2.json.gz", @"D2.2.json.gz", -// @"D1.2.json.gz", @"D3.2.json.gz", + @"D0.2.json.gz", @"D2.2.json.gz", + @"D1.2.json.gz", @"D3.2.json.gz", // RCR @"D0.3.json.gz", @"D2.3.json.gz", @"D1.3.json.gz", @"D3.3.json.gz", + // ROL + @"D0.0.json.gz", @"D2.0.json.gz", + @"D1.0.json.gz", @"D3.0.json.gz", + + // ROR + @"D0.1.json.gz", @"D2.1.json.gz", + @"D1.1.json.gz", @"D3.1.json.gz", + /* @"F8.json.gz", // CLC @"FC.json.gz", // CLD @@ -636,6 +644,10 @@ struct FailedExecution { execution_support.status = initial_status; execution_support.registers = initial_registers; + if([test[@"name"] isEqual:@"rol byte ss:[bp+si+CF11h], cl"]) { + printf(""); + } + // Execute instruction. execution_support.registers.ip_ += decoded.first; InstructionSet::x86::perform(