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:
@@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -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;
|
||||||
|
@@ -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()).
|
||||||
///
|
///
|
||||||
|
@@ -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.
|
||||||
|
@@ -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_;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -21,6 +21,7 @@ public:
|
|||||||
Segments(const Registers<model> ®isters) : registers_(registers) {}
|
Segments(const Registers<model> ®isters) : 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);
|
||||||
|
Reference in New Issue
Block a user