// // Repetition.hpp // Clock Signal // // Created by Thomas Harte on 08/11/2023. // Copyright © 2023 Thomas Harte. All rights reserved. // #ifndef Repetition_h #define Repetition_h #include "../AccessType.hpp" namespace InstructionSet::x86::Primitive { template bool repetition_over( const AddressT &eCX ) { return repetition != Repetition::None && !eCX; } template void repeat( AddressT &eCX, ContextT &context ) { if( repetition == Repetition::None || // No repetition => stop. !(--eCX) // [e]cx is zero after being decremented => stop. ) { return; } if constexpr (repetition != Repetition::Rep) { // If this is RepE or RepNE, also test the zero flag. if((repetition == Repetition::RepNE) == context.flags.template flag()) { return; } } context.flow_controller.repeat_last(); } template void cmps( const InstructionT &instruction, AddressT &eCX, AddressT &eSI, AddressT &eDI, ContextT &context ) { if(repetition_over(eCX)) { return; } IntT lhs = context.memory.template access(instruction.data_segment(), eSI); const IntT rhs = context.memory.template access(Source::ES, eDI); eSI += context.flags.template direction() * sizeof(IntT); eDI += context.flags.template direction() * sizeof(IntT); Primitive::sub(lhs, rhs, context); repeat(eCX, context); } template void scas( AddressT &eCX, AddressT &eDI, IntT &eAX, ContextT &context ) { if(repetition_over(eCX)) { return; } const IntT rhs = context.memory.template access(Source::ES, eDI); eDI += context.flags.template direction() * sizeof(IntT); Primitive::sub(eAX, rhs, context); repeat(eCX, context); } template void lods( const InstructionT &instruction, AddressT &eCX, AddressT &eSI, IntT &eAX, ContextT &context ) { if(repetition_over(eCX)) { return; } eAX = context.memory.template access(instruction.data_segment(), eSI); eSI += context.flags.template direction() * sizeof(IntT); repeat(eCX, context); } template void movs( const InstructionT &instruction, AddressT &eCX, AddressT &eSI, AddressT &eDI, ContextT &context ) { if(repetition_over(eCX)) { return; } context.memory.template access(Source::ES, eDI) = context.memory.template access(instruction.data_segment(), eSI); eSI += context.flags.template direction() * sizeof(IntT); eDI += context.flags.template direction() * sizeof(IntT); repeat(eCX, context); } template void stos( AddressT &eCX, AddressT &eDI, IntT &eAX, ContextT &context ) { if(repetition_over(eCX)) { return; } context.memory.template access(Source::ES, eDI) = eAX; eDI += context.flags.template direction() * sizeof(IntT); repeat(eCX, context); } template void outs( const InstructionT &instruction, AddressT &eCX, uint16_t port, AddressT &eSI, ContextT &context ) { if(repetition_over(eCX)) { return; } context.io.template out( port, context.memory.template access(instruction.data_segment(), eSI) ); eSI += context.flags.template direction() * sizeof(IntT); repeat(eCX, context); } template void ins( AddressT &eCX, uint16_t port, AddressT &eDI, ContextT &context ) { if(repetition_over(eCX)) { return; } context.memory.template access(Source::ES, eDI) = context.io.template in(port); eDI += context.flags.template direction() * sizeof(IntT); repeat(eCX, context); } } #endif /* Repetition_h */