1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-08-07 23:25:00 +00:00
Files
CLK/InstructionSets/x86/Implementation/LoadStore.hpp
2025-05-18 22:11:23 -04:00

235 lines
6.1 KiB
C++

//
// 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 <utility>
namespace InstructionSet::x86::Primitive {
template <typename IntT>
void xchg(
modify_t<IntT> destination,
modify_t<IntT> source
) {
/*
TEMP ← DEST
DEST ← SRC
SRC ← TEMP
*/
std::swap(destination, source);
}
template <Source selector, typename InstructionT, typename ContextT>
void ld(
const InstructionT &instruction,
write_t<uint16_t> destination,
ContextT &context
) {
const auto pointer = instruction.source();
uint16_t source_address = uint16_t(address<uint16_t, AccessType::Read>(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<uint16_t, AccessType::PreauthorisedRead>(source_segment, source_address);
source_address += 2;
const auto segment =
context.memory.template access<uint16_t, AccessType::PreauthorisedRead>(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 <typename IntT, InstructionType type, typename ContextT>
void lea(
const Instruction<type> &instruction,
write_t<IntT> destination,
ContextT &context
) {
// TODO: address size.
destination = IntT(address<uint16_t, AccessType::Read, type>(instruction, instruction.source(), context));
}
template <typename AddressT, typename InstructionT, typename ContextT>
void xlat(
const InstructionT &instruction,
ContextT &context
) {
AddressT address;
if constexpr (std::is_same_v<AddressT, uint16_t>) {
address = context.registers.bx() + context.registers.al();
}
context.registers.al() = context.memory.template access<uint8_t, AccessType::Read>(instruction.data_segment(), address);
}
template <typename IntT>
void mov(
write_t<IntT> destination,
read_t<IntT> source
) {
destination = source;
}
template <typename ContextT>
void smsw(
write_t<uint16_t> destination,
ContextT &context
) {
destination = context.registers.msw();
}
template <typename ContextT>
void lmsw(
read_t<uint16_t> source,
ContextT &context
) {
context.registers.set_msw(source);
if(source & MachineStatus::ProtectedModeEnable) {
context.cpu_control.set_mode(Mode::Protected286);
}
}
template <DescriptorTable table, typename AddressT, typename InstructionT, typename ContextT>
void ldt(
read_t<AddressT> 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<uint16_t, AccessType::PreauthorisedRead>(segment, source_address);
location.base =
context.memory.template access<uint32_t, AccessType::PreauthorisedRead>(segment, AddressT(source_address + 2));
if constexpr (std::is_same_v<AddressT, uint16_t>) {
location.base &= 0xff'ff'ff;
}
context.registers.template set<table>(location);
context.segments.did_update(table);
}
template <typename AddressT, typename ContextT>
void lldt(
read_t<AddressT> source_segment,
ContextT &context
) {
if(!source_segment || context.registers.privilege_level()) {
throw Exception::exception<Vector::GeneralProtectionFault>(ExceptionCode::zero());
}
const auto ldt =
descriptor_at<SegmentDescriptor>(
context.linear_memory,
context.registers.template get<DescriptorTable::Global>(),
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<Vector::GeneralProtectionFault>(exception_code(source_segment));
}
if(!ldt.present()) {
throw Exception::exception<Vector::SegmentNotPresent>(exception_code(source_segment));
}
DescriptorTablePointer location;
location.limit = AddressT(ldt.base());
location.base = ldt.offset();
if constexpr (std::is_same_v<AddressT, uint16_t>) {
location.base &= 0xff'ff'ff;
}
context.registers.template set<DescriptorTable::Local>(location);
context.registers.set_ldtr(source_segment);
context.segments.did_update(DescriptorTable::Local);
}
template <typename AddressT, typename ContextT>
void sldt(
write_t<AddressT> segment,
ContextT &context
) {
segment = AddressT(context.registers.ldtr());
}
template <DescriptorTable table, typename AddressT, typename InstructionT, typename ContextT>
void sdt(
read_t<AddressT> 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<table>();
context.memory.template preauthorised_write<uint16_t>(segment, destination, location.limit);
context.memory.template preauthorised_write<uint32_t>(segment, AddressT(destination + 2), location.base);
}
template <typename ContextT>
void arpl(
modify_t<uint16_t> destination,
read_t<uint16_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<Flag::Carry>(1);
} else {
context.flags.template set_from<Flag::Carry>(0);
}
}
template <typename ContextT>
void clts(
ContextT &context
) {
if(context.registers.privilege_level()) {
throw Exception::exception<Vector::GeneralProtectionFault>(ExceptionCode::zero());
}
const auto msw = context.registers.msw();
context.registers.set_msw(
msw & ~MachineStatus::TaskSwitched
);
}
}