diff --git a/InstructionSets/x86/Implementation/PerformImplementation.hpp b/InstructionSets/x86/Implementation/PerformImplementation.hpp index c3a3626f6..495363122 100644 --- a/InstructionSets/x86/Implementation/PerformImplementation.hpp +++ b/InstructionSets/x86/Implementation/PerformImplementation.hpp @@ -258,7 +258,11 @@ void das(uint8_t &al, ContextT &context) { } template -void add(IntT &destination, IntT source, ContextT &context) { +void add( + modify_t destination, + read_t source, + ContextT &context +) { /* DEST ← DEST + SRC [+ CF]; */ @@ -308,7 +312,11 @@ void sub( } template -void test(IntT &destination, IntT source, ContextT &context) { +void test( + read_t destination, + read_t source, + ContextT &context +) { /* TEMP ← SRC1 AND SRC2; SF ← MSB(TEMP); @@ -332,7 +340,10 @@ void test(IntT &destination, IntT source, ContextT &context) { } template -void xchg(IntT &destination, IntT &source) { +void xchg( + modify_t destination, + modify_t source +) { /* TEMP ← DEST DEST ← SRC @@ -342,7 +353,12 @@ void xchg(IntT &destination, IntT &source) { } template -void mul(IntT &destination_high, IntT &destination_low, IntT source, ContextT &context) { +void mul( + modify_t destination_high, + modify_t destination_low, + read_t source, + ContextT &context +) { /* IF byte operation THEN @@ -364,7 +380,12 @@ void mul(IntT &destination_high, IntT &destination_low, IntT source, ContextT &c } template -void imul(IntT &destination_high, IntT &destination_low, IntT source, ContextT &context) { +void imul( + modify_t destination_high, + modify_t destination_low, + read_t source, + ContextT &context +) { /* (as modified by https://www.felixcloutier.com/x86/daa ...) @@ -399,7 +420,12 @@ void imul(IntT &destination_high, IntT &destination_low, IntT source, ContextT & } template -void div(IntT &destination_high, IntT &destination_low, IntT source, ContextT &context) { +void div( + modify_t destination_high, + modify_t destination_low, + read_t source, + ContextT &context +) { /* IF SRC = 0 THEN #DE; (* divide error *) @@ -455,7 +481,12 @@ void div(IntT &destination_high, IntT &destination_low, IntT source, ContextT &c } template -void idiv(IntT &destination_high, IntT &destination_low, IntT source, ContextT &context) { +void idiv( + modify_t destination_high, + modify_t destination_low, + read_t source, + ContextT &context +) { /* IF SRC = 0 THEN #DE; (* divide error *) @@ -512,7 +543,10 @@ void idiv(IntT &destination_high, IntT &destination_low, IntT source, ContextT & } template -void inc(IntT &destination, ContextT &context) { +void inc( + modify_t destination, + ContextT &context +) { /* DEST ← DEST + 1; */ @@ -528,7 +562,11 @@ void inc(IntT &destination, ContextT &context) { } template -void jump(bool condition, IntT displacement, ContextT &context) { +void jump( + bool condition, + IntT displacement, + ContextT &context +) { /* IF condition THEN @@ -547,7 +585,11 @@ void jump(bool condition, IntT displacement, ContextT &context) { } template -void loop(IntT &counter, OffsetT displacement, ContextT &context) { +void loop( + modify_t counter, + OffsetT displacement, + ContextT &context +) { --counter; if(counter) { context.flow_controller.jump(context.registers.ip() + displacement); @@ -555,7 +597,11 @@ void loop(IntT &counter, OffsetT displacement, ContextT &context) { } template -void loope(IntT &counter, OffsetT displacement, ContextT &context) { +void loope( + modify_t counter, + OffsetT displacement, + ContextT &context +) { --counter; if(counter && context.flags.template flag()) { context.flow_controller.jump(context.registers.ip() + displacement); @@ -563,7 +609,11 @@ void loope(IntT &counter, OffsetT displacement, ContextT &context) { } template -void loopne(IntT &counter, OffsetT displacement, ContextT &context) { +void loopne( + modify_t counter, + OffsetT displacement, + ContextT &context +) { --counter; if(counter && !context.flags.template flag()) { context.flow_controller.jump(context.registers.ip() + displacement); @@ -571,7 +621,10 @@ void loopne(IntT &counter, OffsetT displacement, ContextT &context) { } template -void dec(IntT &destination, ContextT &context) { +void dec( + modify_t destination, + ContextT &context +) { /* DEST ← DEST - 1; */ @@ -588,7 +641,11 @@ void dec(IntT &destination, ContextT &context) { } template -void and_(IntT &destination, IntT source, ContextT &context) { +void and_( + modify_t destination, + read_t source, + ContextT &context +) { /* DEST ← DEST AND SRC; */ @@ -603,7 +660,11 @@ void and_(IntT &destination, IntT source, ContextT &context) { } template -void or_(IntT &destination, IntT source, ContextT &context) { +void or_( + modify_t destination, + read_t source, + ContextT &context +) { /* DEST ← DEST OR SRC; */ @@ -618,7 +679,11 @@ void or_(IntT &destination, IntT source, ContextT &context) { } template -void xor_(IntT &destination, IntT source, ContextT &context) { +void xor_( + modify_t destination, + read_t source, + ContextT &context +) { /* DEST ← DEST XOR SRC; */ @@ -633,7 +698,10 @@ void xor_(IntT &destination, IntT source, ContextT &context) { } template -void neg(IntT &destination, ContextT &context) { +void neg( + modify_t destination, + ContextT &context +) { /* IF DEST = 0 THEN CF ← 0 @@ -655,35 +723,49 @@ void neg(IntT &destination, ContextT &context) { } template -void not_(IntT &destination) { +void not_( + modify_t destination +) { /* DEST ← NOT DEST; */ /* Flags affected: none. */ - destination = ~destination; + destination = ~destination; } template -void call_relative(IntT offset, ContextT &context) { +void call_relative( + IntT offset, + ContextT &context +) { push(context.registers.ip(), context); context.flow_controller.jump(context.registers.ip() + offset); } template -void call_absolute(IntT target, ContextT &context) { +void call_absolute( + read_t target, + ContextT &context +) { push(context.registers.ip(), context); context.flow_controller.jump(target); } template -void jump_absolute(IntT target, ContextT &context) { +void jump_absolute( + read_t target, + ContextT &context +) { context.flow_controller.jump(target); } template -void call_far(InstructionT &instruction, ContextT &context) { +void call_far( + InstructionT &instruction, + ContextT &context +) { // TODO: eliminate 16-bit assumption below. const Source source_segment = instruction.data_segment(); context.memory.preauthorise_stack_write(sizeof(uint16_t) * 2); @@ -722,7 +804,10 @@ void call_far(InstructionT &instruction, ContextT &context) { } template -void jump_far(InstructionT &instruction, ContextT &context) { +void jump_far( + InstructionT &instruction, + ContextT &context +) { // TODO: eliminate 16-bit assumption below. uint16_t source_address = 0; const auto pointer = instruction.destination(); @@ -751,7 +836,9 @@ void jump_far(InstructionT &instruction, ContextT &context) { } template -void iret(ContextT &context) { +void iret( + ContextT &context +) { // TODO: all modes other than 16-bit real mode. context.memory.preauthorise_stack_read(sizeof(uint16_t) * 3); const auto ip = pop(context); @@ -761,14 +848,20 @@ void iret(ContextT &context) { } template -void ret_near(InstructionT instruction, ContextT &context) { +void ret_near( + InstructionT instruction, + ContextT &context +) { const auto ip = pop(context); context.registers.sp() += instruction.operand(); context.flow_controller.jump(ip); } template -void ret_far(InstructionT instruction, ContextT &context) { +void ret_far( + InstructionT instruction, + ContextT &context +) { context.memory.preauthorise_stack_read(sizeof(uint16_t) * 2); const auto ip = pop(context); const auto cs = pop(context); @@ -778,8 +871,8 @@ void ret_far(InstructionT instruction, ContextT &context) { template void ld( - InstructionT &instruction, - uint16_t &destination, + const InstructionT &instruction, + write_t destination, ContextT &context ) { const auto pointer = instruction.source(); @@ -798,7 +891,7 @@ void ld( template void lea( const InstructionT &instruction, - IntT &destination, + write_t destination, ContextT &context ) { // TODO: address size. @@ -819,19 +912,27 @@ void xlat( } template -void mov(IntT &destination, IntT source) { +void mov( + write_t destination, + read_t source +) { destination = source; } template -void into(ContextT &context) { +void into( + ContextT &context +) { if(context.flags.template flag()) { interrupt(Interrupt::OnOverflow, context); } } template -void sahf(uint8_t &ah, ContextT &context) { +void sahf( + uint8_t &ah, + ContextT &context +) { /* EFLAGS(SF:ZF:0:AF:0:PF:1:CF) ← AH; */ @@ -843,7 +944,10 @@ void sahf(uint8_t &ah, ContextT &context) { } template -void lahf(uint8_t &ah, ContextT &context) { +void lahf( + uint8_t &ah, + ContextT &context +) { /* AH ← EFLAGS(SF:ZF:0:AF:0:PF:1:CF); */ @@ -857,7 +961,9 @@ void lahf(uint8_t &ah, ContextT &context) { } template -void cbw(IntT &ax) { +void cbw( + IntT &ax +) { constexpr IntT test_bit = 1 << (sizeof(IntT) * 4 - 1); constexpr IntT low_half = (1 << (sizeof(IntT) * 4)) - 1; @@ -869,7 +975,10 @@ void cbw(IntT &ax) { } template -void cwd(IntT &dx, IntT ax) { +void cwd( + IntT &dx, + IntT ax +) { dx = ax & Numeric::top_bit() ? IntT(~0) : IntT(0); } @@ -892,19 +1001,29 @@ void cmc(ContextT &context) { } template -void salc(uint8_t &al, ContextT &context) { +void salc( + uint8_t &al, + ContextT &context +) { al = context.flags.template flag() ? 0xff : 0x00; } template -void setmo(IntT &destination, ContextT &context) { +void setmo( + write_t destination, + ContextT &context +) { destination = ~0; context.flags.template set_from(0); context.flags.template set_from(destination); } template -void rcl(IntT &destination, uint8_t count, ContextT &context) { +void rcl( + modify_t destination, + uint8_t count, + ContextT &context +) { /* (* RCL and RCR instructions *) SIZE ← OperandSize @@ -960,7 +1079,11 @@ void rcl(IntT &destination, uint8_t count, ContextT &context) { } template -void rcr(IntT &destination, uint8_t count, ContextT &context) { +void rcr( + modify_t destination, + uint8_t count, + ContextT &context +) { /* (* RCR instruction operation *) IF COUNT = 1 @@ -1002,7 +1125,11 @@ void rcr(IntT &destination, uint8_t count, ContextT &context) { } template -void rol(IntT &destination, uint8_t count, ContextT &context) { +void rol( + modify_t destination, + uint8_t count, + ContextT &context +) { /* (* ROL and ROR instructions *) SIZE ← OperandSize @@ -1049,7 +1176,11 @@ void rol(IntT &destination, uint8_t count, ContextT &context) { } template -void ror(IntT &destination, uint8_t count, ContextT &context) { +void ror( + modify_t destination, + uint8_t count, + ContextT &context +) { /* (* ROL and ROR instructions *) SIZE ← OperandSize @@ -1152,7 +1283,11 @@ void ror(IntT &destination, uint8_t count, ContextT &context) { For a non-zero count, the AF flag is undefined. */ template -void sal(IntT &destination, uint8_t count, ContextT &context) { +void sal( + modify_t destination, + uint8_t count, + ContextT &context +) { switch(count) { case 0: return; case Numeric::bit_size(): @@ -1179,7 +1314,11 @@ void sal(IntT &destination, uint8_t count, ContextT &context) { } template -void sar(IntT &destination, uint8_t count, ContextT &context) { +void sar( + modify_t destination, + uint8_t count, + ContextT &context +) { if(!count) { return; } @@ -1198,7 +1337,11 @@ void sar(IntT &destination, uint8_t count, ContextT &context) { } template -void shr(IntT &destination, uint8_t count, ContextT &context) { +void shr( + modify_t destination, + uint8_t count, + ContextT &context +) { if(!count) { return; } @@ -1219,23 +1362,32 @@ void shr(IntT &destination, uint8_t count, ContextT &context) { } template -void popf(ContextT &context) { +void popf( + ContextT &context +) { context.flags.set(pop(context)); } template -void pushf(ContextT &context) { +void pushf( + ContextT &context +) { uint16_t value = context.flags.get(); push(value, context); } template -bool repetition_over(const AddressT &eCX) { +bool repetition_over( + const AddressT &eCX +) { return repetition != Repetition::None && !eCX; } template -void repeat(AddressT &eCX, ContextT &context) { +void repeat( + AddressT &eCX, + ContextT &context +) { if( repetition == Repetition::None || // No repetition => stop. !(--eCX) // [e]cx is zero after being decremented => stop. @@ -1252,7 +1404,13 @@ void repeat(AddressT &eCX, ContextT &context) { } template -void cmps(const InstructionT &instruction, AddressT &eCX, AddressT &eSI, AddressT &eDI, ContextT &context) { +void cmps( + const InstructionT &instruction, + AddressT &eCX, + AddressT &eSI, + AddressT &eDI, + ContextT &context +) { if(repetition_over(eCX)) { return; } @@ -1262,7 +1420,7 @@ void cmps(const InstructionT &instruction, AddressT &eCX, AddressT &eSI, Address eSI += context.flags.template direction() * sizeof(IntT); eDI += context.flags.template direction() * sizeof(IntT); - Primitive::sub(lhs, rhs, context); + Primitive::sub(lhs, rhs, context); repeat(eCX, context); } @@ -1276,7 +1434,7 @@ void scas(AddressT &eCX, AddressT &eDI, IntT &eAX, ContextT &context) { const IntT rhs = context.memory.template access(Source::ES, eDI); eDI += context.flags.template direction() * sizeof(IntT); - Primitive::sub(eAX, rhs, context); + Primitive::sub(eAX, rhs, context); repeat(eCX, context); } @@ -1513,39 +1671,45 @@ template < case Operation::HLT: context.flow_controller.halt(); return; case Operation::WAIT: context.flow_controller.wait(); return; - case Operation::ADC: Primitive::add(destination_rmw(), source_r(), context); break; - case Operation::ADD: Primitive::add(destination_rmw(), source_r(), context); break; - case Operation::SBB: Primitive::sub(destination_rmw(), source_r(), context); break; - case Operation::SUB: Primitive::sub(destination_rmw(), source_r(), context); break; - case Operation::CMP: Primitive::sub(destination_r(), source_r(), context); return; - case Operation::TEST: Primitive::test(destination_r(), source_r(), context); return; + case Operation::ADC: Primitive::add(destination_rmw(), source_r(), context); break; + case Operation::ADD: Primitive::add(destination_rmw(), source_r(), context); break; + case Operation::SBB: + Primitive::sub(destination_rmw(), source_r(), context); + break; + case Operation::SUB: + Primitive::sub(destination_rmw(), source_r(), context); + break; + case Operation::CMP: + Primitive::sub(destination_r(), source_r(), context); + return; + case Operation::TEST: Primitive::test(destination_r(), source_r(), context); return; - case Operation::MUL: Primitive::mul(pair_high(), pair_low(), source_r(), context); return; - case Operation::IMUL_1: Primitive::imul(pair_high(), pair_low(), source_r(), context); return; - case Operation::DIV: Primitive::div(pair_high(), pair_low(), source_r(), context); return; - case Operation::IDIV: Primitive::idiv(pair_high(), pair_low(), source_r(), context); return; + case Operation::MUL: Primitive::mul(pair_high(), pair_low(), source_r(), context); return; + case Operation::IMUL_1: Primitive::imul(pair_high(), pair_low(), source_r(), context); return; + case Operation::DIV: Primitive::div(pair_high(), pair_low(), source_r(), context); return; + case Operation::IDIV: Primitive::idiv(pair_high(), pair_low(), source_r(), context); return; - case Operation::INC: Primitive::inc(destination_rmw(), context); break; - case Operation::DEC: Primitive::dec(destination_rmw(), context); break; + case Operation::INC: Primitive::inc(destination_rmw(), context); break; + case Operation::DEC: Primitive::dec(destination_rmw(), context); break; - case Operation::AND: Primitive::and_(destination_rmw(), source_r(), context); break; - case Operation::OR: Primitive::or_(destination_rmw(), source_r(), context); break; - case Operation::XOR: Primitive::xor_(destination_rmw(), source_r(), context); break; - case Operation::NEG: Primitive::neg(source_rmw(), context); break; // TODO: should be a destination. - case Operation::NOT: Primitive::not_(source_rmw()); break; // TODO: should be a destination. + case Operation::AND: Primitive::and_(destination_rmw(), source_r(), context); break; + case Operation::OR: Primitive::or_(destination_rmw(), source_r(), context); break; + case Operation::XOR: Primitive::xor_(destination_rmw(), source_r(), context); break; + case Operation::NEG: Primitive::neg(source_rmw(), context); break; // TODO: should be a destination. + case Operation::NOT: Primitive::not_(source_rmw()); break; // TODO: should be a destination. - case Operation::CALLrel: Primitive::call_relative(instruction.displacement(), context); return; - case Operation::CALLabs: Primitive::call_absolute(destination_r(), context); return; - case Operation::CALLfar: Primitive::call_far(instruction, context); return; + case Operation::CALLrel: Primitive::call_relative(instruction.displacement(), context); return; + case Operation::CALLabs: Primitive::call_absolute(destination_r(), context); return; + case Operation::CALLfar: Primitive::call_far(instruction, context); return; - case Operation::JMPrel: jcc(true); return; - case Operation::JMPabs: Primitive::jump_absolute(destination_r(), context); return; - case Operation::JMPfar: Primitive::jump_far(instruction, context); return; + case Operation::JMPrel: jcc(true); return; + case Operation::JMPabs: Primitive::jump_absolute(destination_r(), context); return; + case Operation::JMPfar: Primitive::jump_far(instruction, context); return; - case Operation::JCXZ: jcc(!eCX()); return; - case Operation::LOOP: Primitive::loop(eCX(), instruction.offset(), context); return; - case Operation::LOOPE: Primitive::loope(eCX(), instruction.offset(), context); return; - case Operation::LOOPNE: Primitive::loopne(eCX(), instruction.offset(), context); return; + case Operation::JCXZ: jcc(!eCX()); return; + case Operation::LOOP: Primitive::loop(eCX(), instruction.offset(), context); return; + case Operation::LOOPE: Primitive::loope(eCX(), instruction.offset(), context); return; + case Operation::LOOPNE: Primitive::loopne(eCX(), instruction.offset(), context); return; case Operation::IRET: Primitive::iret(context); return; case Operation::RETnear: Primitive::ret_near(instruction, context); return; @@ -1560,33 +1724,33 @@ template < case Operation::LDS: if constexpr (data_size == DataSize::Word) Primitive::ld(instruction, destination_w(), context); return; case Operation::LES: if constexpr (data_size == DataSize::Word) Primitive::ld(instruction, destination_w(), context); return; - case Operation::LEA: Primitive::lea(instruction, destination_w(), context); return; - case Operation::MOV: Primitive::mov(destination_w(), source_r()); break; + case Operation::LEA: Primitive::lea(instruction, destination_w(), context); return; + case Operation::MOV: Primitive::mov(destination_w(), source_r()); break; case Operation::JO: jcc(context.flags.template condition()); return; case Operation::JNO: jcc(!context.flags.template condition()); return; case Operation::JB: jcc(context.flags.template condition()); return; - case Operation::JNB: jcc(!context.flags.template condition()); return; + case Operation::JNB: jcc(!context.flags.template condition()); return; case Operation::JZ: jcc(context.flags.template condition()); return; case Operation::JNZ: jcc(!context.flags.template condition()); return; case Operation::JBE: jcc(context.flags.template condition()); return; case Operation::JNBE: jcc(!context.flags.template condition()); return; case Operation::JS: jcc(context.flags.template condition()); return; case Operation::JNS: jcc(!context.flags.template condition()); return; - case Operation::JP: jcc(!context.flags.template condition()); return; + case Operation::JP: jcc(!context.flags.template condition()); return; case Operation::JNP: jcc(context.flags.template condition()); return; case Operation::JL: jcc(context.flags.template condition()); return; case Operation::JNL: jcc(!context.flags.template condition()); return; case Operation::JLE: jcc(context.flags.template condition()); return; case Operation::JNLE: jcc(!context.flags.template condition()); return; - case Operation::RCL: Primitive::rcl(destination_rmw(), shift_count(), context); break; - case Operation::RCR: Primitive::rcr(destination_rmw(), shift_count(), context); break; - case Operation::ROL: Primitive::rol(destination_rmw(), shift_count(), context); break; - case Operation::ROR: Primitive::ror(destination_rmw(), shift_count(), context); break; - case Operation::SAL: Primitive::sal(destination_rmw(), shift_count(), context); break; - case Operation::SAR: Primitive::sar(destination_rmw(), shift_count(), context); break; - case Operation::SHR: Primitive::shr(destination_rmw(), shift_count(), context); break; + case Operation::RCL: Primitive::rcl(destination_rmw(), shift_count(), context); break; + case Operation::RCR: Primitive::rcr(destination_rmw(), shift_count(), context); break; + case Operation::ROL: Primitive::rol(destination_rmw(), shift_count(), context); break; + case Operation::ROR: Primitive::ror(destination_rmw(), shift_count(), context); break; + case Operation::SAL: Primitive::sal(destination_rmw(), shift_count(), context); break; + case Operation::SAR: Primitive::sar(destination_rmw(), shift_count(), context); break; + case Operation::SHR: Primitive::shr(destination_rmw(), shift_count(), context); break; case Operation::CLC: Primitive::clc(context); return; case Operation::CLD: Primitive::cld(context); return; @@ -1596,12 +1760,12 @@ template < case Operation::STI: Primitive::sti(context); return; case Operation::CMC: Primitive::cmc(context); return; - case Operation::XCHG: Primitive::xchg(destination_rmw(), source_rmw()); break; + case Operation::XCHG: Primitive::xchg(destination_rmw(), source_rmw()); break; case Operation::SALC: Primitive::salc(context.registers.al(), context); return; case Operation::SETMO: if constexpr (ContextT::model == Model::i8086) { - Primitive::setmo(destination_w(), context); + Primitive::setmo(destination_w(), context); break; } else { // TODO. @@ -1612,7 +1776,7 @@ template < // Test CL out here to avoid taking a reference to memory if // no write is going to occur. if(context.registers.cl()) { - Primitive::setmo(destination_w(), context); + Primitive::setmo(destination_w(), context); } break; } else { @@ -1626,7 +1790,10 @@ template < case Operation::XLAT: Primitive::xlat(instruction, context); return; case Operation::POP: destination_w() = Primitive::pop(context); break; - case Operation::PUSH: Primitive::push(source_r(), context); break; + case Operation::PUSH: + Primitive::push(source_rmw(), context); // PUSH SP modifies SP before pushing it; + // hence PUSH is sometimes read-modify-write. + break; case Operation::POPF: Primitive::popf(context); break; case Operation::PUSHF: Primitive::pushf(context); break; diff --git a/OSBindings/Mac/Clock SignalTests/8088Tests.mm b/OSBindings/Mac/Clock SignalTests/8088Tests.mm index 275fc2852..a28c37670 100644 --- a/OSBindings/Mac/Clock SignalTests/8088Tests.mm +++ b/OSBindings/Mac/Clock SignalTests/8088Tests.mm @@ -106,6 +106,7 @@ struct Memory { // Writes: return a reference. template struct ReturnType { using type = IntT &; }; + template struct ReturnType { using type = IntT &; }; // Constructor. Memory(Registers ®isters) : registers_(registers) {