1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-08-07 23:25:00 +00:00

Merge pull request #1495 from TomHarte/286StatusWord

Add extra 80286 registers.
This commit is contained in:
Thomas Harte
2025-03-19 14:12:56 -04:00
committed by GitHub
6 changed files with 181 additions and 45 deletions

View File

@@ -77,4 +77,54 @@ void mov(
destination = source; destination = source;
} }
template <typename ContextT>
void smsw(
write_t<uint16_t> destination,
ContextT &context
) {
destination = context.registers.msw();
}
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);
DescriptorTableLocation 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 <DescriptorTable table, typename AddressT, typename InstructionT, typename ContextT>
void sdt(
read_t<AddressT> destination_address,
const InstructionT &instruction,
ContextT &context
) {
const auto segment = instruction.data_segment();
context.memory.preauthorise_write(
segment,
destination_address,
6);
const auto location = context.registers.template get<table>();
context.memory.template preauthorised_write<uint16_t>(segment, destination_address, location.limit);
context.memory.template preauthorised_write<uint32_t>(segment, AddressT(destination_address + 2), location.base);
}
} }

View File

@@ -115,6 +115,13 @@ template <
} }
}; };
// Currently a special case for descriptor loading; assumes an indirect operand and returns the
// address indicated. Unlike [source/destination]_r it doesn't read an IntT from that address,
// since those instructions load an atypical six bytes.
const auto source_indirect = [&]() -> AddressT {
return address<Source::Indirect, AddressT, AccessType::Read>(instruction, instruction.source(), context);
};
// Some instructions use a pair of registers as an extended accumulator — DX:AX or EDX:EAX. // Some instructions use a pair of registers as an extended accumulator — DX:AX or EDX:EAX.
// The two following return the high and low parts of that pair; they also work in Byte mode to return AH:AL, // The two following return the high and low parts of that pair; they also work in Byte mode to return AH:AL,
// i.e. AX split into high and low parts. // i.e. AX split into high and low parts.
@@ -283,6 +290,42 @@ template <
} }
break; break;
case Operation::SMSW:
if constexpr (ContextT::model >= Model::i80286 && std::is_same_v<IntT, uint16_t>) {
Primitive::smsw(destination_w(), context);
} else {
assert(false);
}
break;
case Operation::LIDT:
if constexpr (ContextT::model >= Model::i80286) {
Primitive::ldt<DescriptorTable::Interrupt, AddressT>(source_indirect(), instruction, context);
} else {
assert(false);
}
break;
case Operation::LGDT:
if constexpr (ContextT::model >= Model::i80286) {
Primitive::ldt<DescriptorTable::Global, AddressT>(source_indirect(), instruction, context);
} else {
assert(false);
}
break;
case Operation::SIDT:
if constexpr (ContextT::model >= Model::i80286) {
Primitive::sdt<DescriptorTable::Interrupt, AddressT>(source_indirect(), instruction, context);
} else {
assert(false);
}
break;
case Operation::SGDT:
if constexpr (ContextT::model >= Model::i80286) {
Primitive::sdt<DescriptorTable::Global, AddressT>(source_indirect(), instruction, context);
} else {
assert(false);
}
break;
case Operation::JO: jcc(context.flags.template condition<Condition::Overflow>()); return; case Operation::JO: jcc(context.flags.template condition<Condition::Overflow>()); return;
case Operation::JNO: jcc(!context.flags.template condition<Condition::Overflow>()); return; case Operation::JNO: jcc(!context.flags.template condition<Condition::Overflow>()); return;
case Operation::JB: jcc(context.flags.template condition<Condition::Below>()); return; case Operation::JB: jcc(context.flags.template condition<Condition::Below>()); return;

View File

@@ -551,6 +551,15 @@ constexpr Operation rep_operation(Operation operation, Repetition repetition) {
} }
} }
enum class DescriptorTable {
Global, Local, Interrupt,
};
struct DescriptorTableLocation {
uint16_t limit;
uint32_t base;
};
/// Provides a 32-bit-style scale, index and base; to produce the address this represents, /// Provides a 32-bit-style scale, index and base; to produce the address this represents,
/// calcluate base() + (index() << scale()). /// calcluate base() + (index() << scale()).
/// ///

View File

@@ -38,6 +38,8 @@ public:
void preauthorise_stack_read([[maybe_unused]] uint32_t length) {} void preauthorise_stack_read([[maybe_unused]] uint32_t length) {}
void preauthorise_read([[maybe_unused]] InstructionSet::x86::Source segment, [[maybe_unused]] uint16_t start, [[maybe_unused]] uint32_t length) {} void preauthorise_read([[maybe_unused]] InstructionSet::x86::Source segment, [[maybe_unused]] uint16_t start, [[maybe_unused]] uint32_t length) {}
void preauthorise_read([[maybe_unused]] uint32_t start, [[maybe_unused]] uint32_t length) {} void preauthorise_read([[maybe_unused]] uint32_t start, [[maybe_unused]] uint32_t length) {}
void preauthorise_write([[maybe_unused]] InstructionSet::x86::Source segment, [[maybe_unused]] uint16_t start, [[maybe_unused]] uint32_t length) {}
void preauthorise_write([[maybe_unused]] uint32_t start, [[maybe_unused]] uint32_t length) {}
// //
// Access call-ins. // Access call-ins.

View File

@@ -8,6 +8,7 @@
#pragma once #pragma once
#include "InstructionSets/x86/Instruction.hpp" // For DescriptorTable.
#include "InstructionSets/x86/Model.hpp" #include "InstructionSets/x86/Model.hpp"
#include "Numeric/RegisterSizes.hpp" #include "Numeric/RegisterSizes.hpp"
@@ -18,68 +19,96 @@ struct Registers;
template <> template <>
struct Registers<InstructionSet::x86::Model::i8086> { struct Registers<InstructionSet::x86::Model::i8086> {
public: public:
static constexpr bool is_32bit = false; static constexpr bool is_32bit = false;
uint8_t &al() { return ax_.halves.low; } uint8_t &al() { return ax_.halves.low; }
uint8_t &ah() { return ax_.halves.high; } uint8_t &ah() { return ax_.halves.high; }
uint16_t &ax() { return ax_.full; } uint16_t &ax() { return ax_.full; }
CPU::RegisterPair16 &axp() { return ax_; } CPU::RegisterPair16 &axp() { return ax_; }
uint8_t &cl() { return cx_.halves.low; } uint8_t &cl() { return cx_.halves.low; }
uint8_t &ch() { return cx_.halves.high; } uint8_t &ch() { return cx_.halves.high; }
uint16_t &cx() { return cx_.full; } uint16_t &cx() { return cx_.full; }
uint8_t &dl() { return dx_.halves.low; } uint8_t &dl() { return dx_.halves.low; }
uint8_t &dh() { return dx_.halves.high; } uint8_t &dh() { return dx_.halves.high; }
uint16_t &dx() { return dx_.full; } uint16_t &dx() { return dx_.full; }
uint8_t &bl() { return bx_.halves.low; } uint8_t &bl() { return bx_.halves.low; }
uint8_t &bh() { return bx_.halves.high; } uint8_t &bh() { return bx_.halves.high; }
uint16_t &bx() { return bx_.full; } uint16_t &bx() { return bx_.full; }
uint16_t &sp() { return sp_; } uint16_t &sp() { return sp_; }
uint16_t &bp() { return bp_; } uint16_t &bp() { return bp_; }
uint16_t &si() { return si_; } uint16_t &si() { return si_; }
uint16_t &di() { return di_; } uint16_t &di() { return di_; }
uint16_t &ip() { return ip_; } uint16_t &ip() { return ip_; }
uint16_t &es() { return es_; } uint16_t &es() { return es_; }
uint16_t &cs() { return cs_; } uint16_t &cs() { return cs_; }
uint16_t &ds() { return ds_; } uint16_t &ds() { return ds_; }
uint16_t &ss() { return ss_; } uint16_t &ss() { return ss_; }
uint16_t es() const { return es_; } uint16_t es() const { return es_; }
uint16_t cs() const { return cs_; } uint16_t cs() const { return cs_; }
uint16_t ds() const { return ds_; } uint16_t ds() const { return ds_; }
uint16_t ss() const { return ss_; } uint16_t ss() const { return ss_; }
void reset() { void reset() {
cs_ = 0xffff; cs_ = 0xffff;
ip_ = 0; ip_ = 0;
} }
private: private:
CPU::RegisterPair16 ax_; CPU::RegisterPair16 ax_;
CPU::RegisterPair16 cx_; CPU::RegisterPair16 cx_;
CPU::RegisterPair16 dx_; CPU::RegisterPair16 dx_;
CPU::RegisterPair16 bx_; CPU::RegisterPair16 bx_;
uint16_t sp_; uint16_t sp_;
uint16_t bp_; uint16_t bp_;
uint16_t si_; uint16_t si_;
uint16_t di_; uint16_t di_;
uint16_t es_, cs_, ds_, ss_; uint16_t es_, cs_, ds_, ss_;
uint16_t ip_; uint16_t ip_;
}; };
template <> template <>
struct Registers<InstructionSet::x86::Model::i80186>: public Registers<InstructionSet::x86::Model::i8086> { struct Registers<InstructionSet::x86::Model::i80186>: public Registers<InstructionSet::x86::Model::i8086> {};
};
template <> template <>
struct Registers<InstructionSet::x86::Model::i80286>: public Registers<InstructionSet::x86::Model::i80186> { struct Registers<InstructionSet::x86::Model::i80286>: public Registers<InstructionSet::x86::Model::i80186> {
public:
void reset() {
Registers<InstructionSet::x86::Model::i80186>::reset();
machine_status_ = 0;
}
uint16_t msw() const { return machine_status_; }
using DescriptorTable = InstructionSet::x86::DescriptorTable;
using DescriptorTableLocation = InstructionSet::x86::DescriptorTableLocation;
template <DescriptorTable table>
void set(const DescriptorTableLocation location) {
static constexpr bool is_global = table == DescriptorTable::Global;
static_assert(is_global || table == DescriptorTable::Interrupt);
auto &target = is_global ? global_ : interrupt_;
target = location;
}
template <DescriptorTable table>
DescriptorTableLocation get() {
static constexpr bool is_global = table == DescriptorTable::Global;
static_assert(is_global || table == DescriptorTable::Interrupt);
return is_global ? global_ : interrupt_;
}
private:
uint16_t machine_status_;
DescriptorTableLocation global_, interrupt_;
}; };
} }

View File

@@ -21,6 +21,7 @@ public:
Segments(const Registers<model> &registers) : registers_(registers) {} Segments(const Registers<model> &registers) : registers_(registers) {}
using Source = InstructionSet::x86::Source; using Source = InstructionSet::x86::Source;
using DescriptorTable = InstructionSet::x86::DescriptorTable;
/// Posted by @c perform after any operation which *might* have affected a segment register. /// Posted by @c perform after any operation which *might* have affected a segment register.
void did_update(const Source segment) { void did_update(const Source segment) {
@@ -33,6 +34,8 @@ public:
} }
} }
void did_update(DescriptorTable) {}
void reset() { void reset() {
did_update(Source::ES); did_update(Source::ES);
did_update(Source::CS); did_update(Source::CS);