mirror of
https://github.com/TomHarte/CLK.git
synced 2025-04-06 10:38:16 +00:00
Merge pull request #1495 from TomHarte/286StatusWord
Add extra 80286 registers.
This commit is contained in:
commit
7fc16fa2c8
@ -77,4 +77,54 @@ void mov(
|
||||
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.
|
||||
// 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.
|
||||
@ -283,6 +290,42 @@ template <
|
||||
}
|
||||
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::JNO: jcc(!context.flags.template condition<Condition::Overflow>()); 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,
|
||||
/// calcluate base() + (index() << scale()).
|
||||
///
|
||||
|
@ -38,6 +38,8 @@ public:
|
||||
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]] 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.
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "InstructionSets/x86/Instruction.hpp" // For DescriptorTable.
|
||||
#include "InstructionSets/x86/Model.hpp"
|
||||
#include "Numeric/RegisterSizes.hpp"
|
||||
|
||||
@ -18,68 +19,96 @@ struct Registers;
|
||||
|
||||
template <>
|
||||
struct Registers<InstructionSet::x86::Model::i8086> {
|
||||
public:
|
||||
static constexpr bool is_32bit = false;
|
||||
public:
|
||||
static constexpr bool is_32bit = false;
|
||||
|
||||
uint8_t &al() { return ax_.halves.low; }
|
||||
uint8_t &ah() { return ax_.halves.high; }
|
||||
uint16_t &ax() { return ax_.full; }
|
||||
uint8_t &al() { return ax_.halves.low; }
|
||||
uint8_t &ah() { return ax_.halves.high; }
|
||||
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 &ch() { return cx_.halves.high; }
|
||||
uint16_t &cx() { return cx_.full; }
|
||||
uint8_t &cl() { return cx_.halves.low; }
|
||||
uint8_t &ch() { return cx_.halves.high; }
|
||||
uint16_t &cx() { return cx_.full; }
|
||||
|
||||
uint8_t &dl() { return dx_.halves.low; }
|
||||
uint8_t &dh() { return dx_.halves.high; }
|
||||
uint16_t &dx() { return dx_.full; }
|
||||
uint8_t &dl() { return dx_.halves.low; }
|
||||
uint8_t &dh() { return dx_.halves.high; }
|
||||
uint16_t &dx() { return dx_.full; }
|
||||
|
||||
uint8_t &bl() { return bx_.halves.low; }
|
||||
uint8_t &bh() { return bx_.halves.high; }
|
||||
uint16_t &bx() { return bx_.full; }
|
||||
uint8_t &bl() { return bx_.halves.low; }
|
||||
uint8_t &bh() { return bx_.halves.high; }
|
||||
uint16_t &bx() { return bx_.full; }
|
||||
|
||||
uint16_t &sp() { return sp_; }
|
||||
uint16_t &bp() { return bp_; }
|
||||
uint16_t &si() { return si_; }
|
||||
uint16_t &di() { return di_; }
|
||||
uint16_t &sp() { return sp_; }
|
||||
uint16_t &bp() { return bp_; }
|
||||
uint16_t &si() { return si_; }
|
||||
uint16_t &di() { return di_; }
|
||||
|
||||
uint16_t &ip() { return ip_; }
|
||||
uint16_t &ip() { return ip_; }
|
||||
|
||||
uint16_t &es() { return es_; }
|
||||
uint16_t &cs() { return cs_; }
|
||||
uint16_t &ds() { return ds_; }
|
||||
uint16_t &ss() { return ss_; }
|
||||
uint16_t es() const { return es_; }
|
||||
uint16_t cs() const { return cs_; }
|
||||
uint16_t ds() const { return ds_; }
|
||||
uint16_t ss() const { return ss_; }
|
||||
uint16_t &es() { return es_; }
|
||||
uint16_t &cs() { return cs_; }
|
||||
uint16_t &ds() { return ds_; }
|
||||
uint16_t &ss() { return ss_; }
|
||||
uint16_t es() const { return es_; }
|
||||
uint16_t cs() const { return cs_; }
|
||||
uint16_t ds() const { return ds_; }
|
||||
uint16_t ss() const { return ss_; }
|
||||
|
||||
void reset() {
|
||||
cs_ = 0xffff;
|
||||
ip_ = 0;
|
||||
}
|
||||
void reset() {
|
||||
cs_ = 0xffff;
|
||||
ip_ = 0;
|
||||
}
|
||||
|
||||
private:
|
||||
CPU::RegisterPair16 ax_;
|
||||
CPU::RegisterPair16 cx_;
|
||||
CPU::RegisterPair16 dx_;
|
||||
CPU::RegisterPair16 bx_;
|
||||
private:
|
||||
CPU::RegisterPair16 ax_;
|
||||
CPU::RegisterPair16 cx_;
|
||||
CPU::RegisterPair16 dx_;
|
||||
CPU::RegisterPair16 bx_;
|
||||
|
||||
uint16_t sp_;
|
||||
uint16_t bp_;
|
||||
uint16_t si_;
|
||||
uint16_t di_;
|
||||
uint16_t es_, cs_, ds_, ss_;
|
||||
uint16_t ip_;
|
||||
uint16_t sp_;
|
||||
uint16_t bp_;
|
||||
uint16_t si_;
|
||||
uint16_t di_;
|
||||
uint16_t es_, cs_, ds_, ss_;
|
||||
uint16_t ip_;
|
||||
};
|
||||
|
||||
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 <>
|
||||
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) {}
|
||||
|
||||
using Source = InstructionSet::x86::Source;
|
||||
using DescriptorTable = InstructionSet::x86::DescriptorTable;
|
||||
|
||||
/// Posted by @c perform after any operation which *might* have affected a segment register.
|
||||
void did_update(const Source segment) {
|
||||
@ -33,6 +34,8 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void did_update(DescriptorTable) {}
|
||||
|
||||
void reset() {
|
||||
did_update(Source::ES);
|
||||
did_update(Source::CS);
|
||||
|
Loading…
x
Reference in New Issue
Block a user