// // LoadStore.hpp // Clock Signal // // Created by Thomas Harte on 08/11/2023. // Copyright © 2023 Thomas Harte. All rights reserved. // #pragma once #include "InstructionSets/x86/AccessType.hpp" #include "InstructionSets/x86/Descriptors.hpp" #include "InstructionSets/x86/Descriptors.hpp" #include "InstructionSets/x86/MachineStatus.hpp" #include namespace InstructionSet::x86::Primitive { template void xchg( modify_t destination, modify_t source ) { /* TEMP ← DEST DEST ← SRC SRC ← TEMP */ std::swap(destination, source); } template void ld( const InstructionT &instruction, write_t destination, ContextT &context ) { const auto pointer = instruction.source(); uint16_t source_address = uint16_t(address(instruction, pointer, context)); const Source source_segment = instruction.data_segment(); context.memory.preauthorise_read(source_segment, source_address, 4); const auto offset = context.memory.template access(source_segment, source_address); source_address += 2; const auto segment = context.memory.template access(source_segment, source_address); context.segments.preauthorise(selector, segment); destination = offset; switch(selector) { case Source::DS: context.registers.ds() = segment; break; case Source::ES: context.registers.es() = segment; break; } context.segments.did_update(selector); } template void lea( const Instruction &instruction, write_t destination, ContextT &context ) { // TODO: address size. destination = IntT(address(instruction, instruction.source(), context)); } template void xlat( const InstructionT &instruction, ContextT &context ) { AddressT address; if constexpr (std::is_same_v) { address = context.registers.bx() + context.registers.al(); } context.registers.al() = context.memory.template access(instruction.data_segment(), address); } template void mov( write_t destination, read_t source ) { destination = source; } template void smsw( write_t destination, ContextT &context ) { destination = context.registers.msw(); } template void lmsw( read_t source, ContextT &context ) { context.registers.set_msw(source); if(source & MachineStatus::ProtectedModeEnable) { context.cpu_control.set_mode(Mode::Protected286); } } template void ldt( read_t source_address, const InstructionT &instruction, ContextT &context ) { const auto segment = instruction.data_segment(); context.memory.preauthorise_read( segment, source_address, 6); DescriptorTablePointer location; location.limit = context.memory.template access(segment, source_address); location.base = context.memory.template access(segment, AddressT(source_address + 2)); if constexpr (std::is_same_v) { location.base &= 0xff'ff'ff; } context.registers.template set(location); context.segments.did_update(table); } template void lldt( read_t source_segment, ContextT &context ) { if(!source_segment || context.registers.privilege_level()) { throw Exception::exception(ExceptionCode::zero()); } const auto ldt = descriptor_at( context.linear_memory, context.registers.template get(), source_segment & ~7); constexpr auto exception_code = [](const uint16_t segment) { return ExceptionCode( segment &~ 7, false, false, false ); }; if(ldt.type() != SegmentDescriptor::Type::LDTDescriptor) { throw Exception::exception(exception_code(source_segment)); } if(!ldt.present()) { throw Exception::exception(exception_code(source_segment)); } DescriptorTablePointer location; location.limit = AddressT(ldt.base()); location.base = ldt.offset(); if constexpr (std::is_same_v) { location.base &= 0xff'ff'ff; } context.registers.template set(location); context.registers.set_ldtr(source_segment); context.segments.did_update(DescriptorTable::Local); } template void sldt( write_t segment, ContextT &context ) { segment = AddressT(context.registers.ldtr()); } template void sdt( read_t destination, const InstructionT &instruction, ContextT &context ) { const auto segment = instruction.data_segment(); context.memory.preauthorise_write( segment, destination, 6); const auto location = context.registers.template get
(); context.memory.template preauthorised_write(segment, destination, location.limit); context.memory.template preauthorised_write(segment, AddressT(destination + 2), location.base); } template void arpl( modify_t destination, read_t source, ContextT &context ) { const auto destination_rpl = destination & 3; const auto source_rpl = source & 3; if(destination_rpl < source_rpl) { destination = uint16_t((destination & ~3) | source_rpl); context.flags.template set_from(1); } else { context.flags.template set_from(0); } } template void clts( ContextT &context ) { if(context.registers.privilege_level()) { throw Exception::exception(ExceptionCode::zero()); } const auto msw = context.registers.msw(); context.registers.set_msw( msw & ~MachineStatus::TaskSwitched ); } }