mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-26 08:49:37 +00:00
Temporarily disentangle Memory
and access internals; start to be overt in PerformImplementation.
This commit is contained in:
parent
797c9fe129
commit
2af774601f
@ -31,11 +31,11 @@ enum class AccessType {
|
|||||||
PreauthorisedRead,
|
PreauthorisedRead,
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename IntT, AccessType type> struct ReturnType;
|
template <typename IntT, AccessType type> struct Accessor;
|
||||||
|
|
||||||
// Reads: return a value directly.
|
// Reads: return a value directly.
|
||||||
template <typename IntT> struct ReturnType<IntT, AccessType::Read> { using type = IntT; };
|
template <typename IntT> struct Accessor<IntT, AccessType::Read> { using type = IntT; };
|
||||||
template <typename IntT> struct ReturnType<IntT, AccessType::PreauthorisedRead> { using type = IntT; };
|
template <typename IntT> struct Accessor<IntT, AccessType::PreauthorisedRead> { using type = IntT; };
|
||||||
|
|
||||||
// Writes: return a custom type that can be written but not read.
|
// Writes: return a custom type that can be written but not read.
|
||||||
template <typename IntT>
|
template <typename IntT>
|
||||||
@ -46,11 +46,16 @@ class Writeable {
|
|||||||
private:
|
private:
|
||||||
IntT &target_;
|
IntT &target_;
|
||||||
};
|
};
|
||||||
//template <typename IntT> struct ReturnType<IntT, AccessType::Write> { using type = Writeable<IntT>; };
|
//template <typename IntT> struct Accessor<IntT, AccessType::Write> { using type = Writeable<IntT>; };
|
||||||
template <typename IntT> struct ReturnType<IntT, AccessType::Write> { using type = IntT &; };
|
template <typename IntT> struct Accessor<IntT, AccessType::Write> { using type = IntT &; };
|
||||||
|
|
||||||
// Read-modify-writes: return a reference.
|
// Read-modify-writes: return a reference.
|
||||||
template <typename IntT> struct ReturnType<IntT, AccessType::ReadModifyWrite> { using type = IntT &; };
|
template <typename IntT> struct Accessor<IntT, AccessType::ReadModifyWrite> { using type = IntT &; };
|
||||||
|
|
||||||
|
// Shorthands; assumed that preauthorised reads have the same return type as reads.
|
||||||
|
template<typename IntT> using read_t = typename Accessor<IntT, AccessType::Read>::type;
|
||||||
|
template<typename IntT> using write_t = typename Accessor<IntT, AccessType::Write>::type;
|
||||||
|
template<typename IntT> using modify_t = typename Accessor<IntT, AccessType::ReadModifyWrite>::type;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,8 +279,12 @@ void add(IntT &destination, IntT source, ContextT &context) {
|
|||||||
destination = result;
|
destination = result;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <bool with_borrow, bool write_back, typename IntT, typename ContextT>
|
template <bool with_borrow, AccessType destination_type, typename IntT, typename ContextT>
|
||||||
void sub(IntT &destination, IntT source, ContextT &context) {
|
void sub(
|
||||||
|
typename Accessor<IntT, destination_type>::type destination,
|
||||||
|
read_t<IntT> source,
|
||||||
|
ContextT &context
|
||||||
|
) {
|
||||||
/*
|
/*
|
||||||
DEST ← DEST - (SRC [+ CF]);
|
DEST ← DEST - (SRC [+ CF]);
|
||||||
*/
|
*/
|
||||||
@ -298,7 +302,7 @@ void sub(IntT &destination, IntT source, ContextT &context) {
|
|||||||
|
|
||||||
context.flags.template set_from<IntT, Flag::Zero, Flag::Sign, Flag::ParityOdd>(result);
|
context.flags.template set_from<IntT, Flag::Zero, Flag::Sign, Flag::ParityOdd>(result);
|
||||||
|
|
||||||
if constexpr (write_back) {
|
if constexpr (destination_type == AccessType::Write) {
|
||||||
destination = result;
|
destination = result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1374,8 +1378,8 @@ template <
|
|||||||
//
|
//
|
||||||
// (though GCC offers C++20 syntax as an extension, and Clang seems to follow along, so maybe I'm overthinking)
|
// (though GCC offers C++20 syntax as an extension, and Clang seems to follow along, so maybe I'm overthinking)
|
||||||
IntT immediate;
|
IntT immediate;
|
||||||
const auto source_r = [&]() -> IntT& {
|
const auto source_r = [&]() -> IntT {
|
||||||
return *resolve<IntT, AccessType::Read>(
|
return resolve<IntT, AccessType::Read>(
|
||||||
instruction,
|
instruction,
|
||||||
instruction.source().source(),
|
instruction.source().source(),
|
||||||
instruction.source(),
|
instruction.source(),
|
||||||
@ -1384,7 +1388,7 @@ template <
|
|||||||
&immediate);
|
&immediate);
|
||||||
};
|
};
|
||||||
const auto source_rmw = [&]() -> IntT& {
|
const auto source_rmw = [&]() -> IntT& {
|
||||||
return *resolve<IntT, AccessType::ReadModifyWrite>(
|
return resolve<IntT, AccessType::ReadModifyWrite>(
|
||||||
instruction,
|
instruction,
|
||||||
instruction.source().source(),
|
instruction.source().source(),
|
||||||
instruction.source(),
|
instruction.source(),
|
||||||
@ -1392,8 +1396,8 @@ template <
|
|||||||
nullptr,
|
nullptr,
|
||||||
&immediate);
|
&immediate);
|
||||||
};
|
};
|
||||||
const auto destination_r = [&]() -> IntT& {
|
const auto destination_r = [&]() -> IntT {
|
||||||
return *resolve<IntT, AccessType::Read>(
|
return resolve<IntT, AccessType::Read>(
|
||||||
instruction,
|
instruction,
|
||||||
instruction.destination().source(),
|
instruction.destination().source(),
|
||||||
instruction.destination(),
|
instruction.destination(),
|
||||||
@ -1402,7 +1406,7 @@ template <
|
|||||||
&immediate);
|
&immediate);
|
||||||
};
|
};
|
||||||
const auto destination_w = [&]() -> IntT& {
|
const auto destination_w = [&]() -> IntT& {
|
||||||
return *resolve<IntT, AccessType::Write>(
|
return resolve<IntT, AccessType::Write>(
|
||||||
instruction,
|
instruction,
|
||||||
instruction.destination().source(),
|
instruction.destination().source(),
|
||||||
instruction.destination(),
|
instruction.destination(),
|
||||||
@ -1411,7 +1415,7 @@ template <
|
|||||||
&immediate);
|
&immediate);
|
||||||
};
|
};
|
||||||
const auto destination_rmw = [&]() -> IntT& {
|
const auto destination_rmw = [&]() -> IntT& {
|
||||||
return *resolve<IntT, AccessType::ReadModifyWrite>(
|
return resolve<IntT, AccessType::ReadModifyWrite>(
|
||||||
instruction,
|
instruction,
|
||||||
instruction.destination().source(),
|
instruction.destination().source(),
|
||||||
instruction.destination(),
|
instruction.destination(),
|
||||||
|
@ -21,7 +21,7 @@ namespace InstructionSet::x86 {
|
|||||||
/// If @c source is Source::Immediate then the appropriate portion of @c instrucion's operand
|
/// If @c source is Source::Immediate then the appropriate portion of @c instrucion's operand
|
||||||
/// is copied to @c *immediate and @c immediate is returned.
|
/// is copied to @c *immediate and @c immediate is returned.
|
||||||
template <typename IntT, AccessType access, typename InstructionT, typename ContextT>
|
template <typename IntT, AccessType access, typename InstructionT, typename ContextT>
|
||||||
IntT *resolve(
|
typename Accessor<IntT, access>::type resolve(
|
||||||
InstructionT &instruction,
|
InstructionT &instruction,
|
||||||
Source source,
|
Source source,
|
||||||
DataPointer pointer,
|
DataPointer pointer,
|
||||||
@ -44,7 +44,7 @@ uint32_t address(
|
|||||||
|
|
||||||
uint32_t address;
|
uint32_t address;
|
||||||
uint16_t zero = 0;
|
uint16_t zero = 0;
|
||||||
address = *resolve<uint16_t, access>(instruction, pointer.index(), pointer, context, &zero);
|
address = resolve<uint16_t, access>(instruction, pointer.index(), pointer, context, &zero);
|
||||||
if constexpr (is_32bit(ContextT::model)) {
|
if constexpr (is_32bit(ContextT::model)) {
|
||||||
address <<= pointer.scale();
|
address <<= pointer.scale();
|
||||||
}
|
}
|
||||||
@ -53,7 +53,7 @@ uint32_t address(
|
|||||||
if constexpr (source == Source::IndirectNoBase) {
|
if constexpr (source == Source::IndirectNoBase) {
|
||||||
return address;
|
return address;
|
||||||
}
|
}
|
||||||
return address + *resolve<uint16_t, access>(instruction, pointer.base(), pointer, context);
|
return address + resolve<uint16_t, access>(instruction, pointer.base(), pointer, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @returns a pointer to the contents of the register identified by the combination of @c IntT and @c Source if any;
|
/// @returns a pointer to the contents of the register identified by the combination of @c IntT and @c Source if any;
|
||||||
@ -150,7 +150,7 @@ uint32_t address(
|
|||||||
|
|
||||||
// See forward declaration, above, for details.
|
// See forward declaration, above, for details.
|
||||||
template <typename IntT, AccessType access, typename InstructionT, typename ContextT>
|
template <typename IntT, AccessType access, typename InstructionT, typename ContextT>
|
||||||
IntT *resolve(
|
typename Accessor<IntT, access>::type resolve(
|
||||||
InstructionT &instruction,
|
InstructionT &instruction,
|
||||||
Source source,
|
Source source,
|
||||||
DataPointer pointer,
|
DataPointer pointer,
|
||||||
@ -165,26 +165,26 @@ IntT *resolve(
|
|||||||
uint32_t target_address;
|
uint32_t target_address;
|
||||||
switch(source) {
|
switch(source) {
|
||||||
// Defer all register accesses to the register-specific lookup.
|
// Defer all register accesses to the register-specific lookup.
|
||||||
case Source::eAX: return register_<IntT, access, Source::eAX>(context);
|
case Source::eAX: return *register_<IntT, access, Source::eAX>(context);
|
||||||
case Source::eCX: return register_<IntT, access, Source::eCX>(context);
|
case Source::eCX: return *register_<IntT, access, Source::eCX>(context);
|
||||||
case Source::eDX: return register_<IntT, access, Source::eDX>(context);
|
case Source::eDX: return *register_<IntT, access, Source::eDX>(context);
|
||||||
case Source::eBX: return register_<IntT, access, Source::eBX>(context);
|
case Source::eBX: return *register_<IntT, access, Source::eBX>(context);
|
||||||
case Source::eSPorAH: return register_<IntT, access, Source::eSPorAH>(context);
|
case Source::eSPorAH: return *register_<IntT, access, Source::eSPorAH>(context);
|
||||||
case Source::eBPorCH: return register_<IntT, access, Source::eBPorCH>(context);
|
case Source::eBPorCH: return *register_<IntT, access, Source::eBPorCH>(context);
|
||||||
case Source::eSIorDH: return register_<IntT, access, Source::eSIorDH>(context);
|
case Source::eSIorDH: return *register_<IntT, access, Source::eSIorDH>(context);
|
||||||
case Source::eDIorBH: return register_<IntT, access, Source::eDIorBH>(context);
|
case Source::eDIorBH: return *register_<IntT, access, Source::eDIorBH>(context);
|
||||||
case Source::ES: return register_<IntT, access, Source::ES>(context);
|
case Source::ES: return *register_<IntT, access, Source::ES>(context);
|
||||||
case Source::CS: return register_<IntT, access, Source::CS>(context);
|
case Source::CS: return *register_<IntT, access, Source::CS>(context);
|
||||||
case Source::SS: return register_<IntT, access, Source::SS>(context);
|
case Source::SS: return *register_<IntT, access, Source::SS>(context);
|
||||||
case Source::DS: return register_<IntT, access, Source::DS>(context);
|
case Source::DS: return *register_<IntT, access, Source::DS>(context);
|
||||||
case Source::FS: return register_<IntT, access, Source::FS>(context);
|
case Source::FS: return *register_<IntT, access, Source::FS>(context);
|
||||||
case Source::GS: return register_<IntT, access, Source::GS>(context);
|
case Source::GS: return *register_<IntT, access, Source::GS>(context);
|
||||||
|
|
||||||
case Source::None: return none;
|
case Source::None: return *none;
|
||||||
|
|
||||||
case Source::Immediate:
|
case Source::Immediate:
|
||||||
*immediate = instruction.operand();
|
*immediate = instruction.operand();
|
||||||
return immediate;
|
return *immediate;
|
||||||
|
|
||||||
case Source::Indirect:
|
case Source::Indirect:
|
||||||
target_address = address<Source::Indirect, IntT, access>(instruction, pointer, context);
|
target_address = address<Source::Indirect, IntT, access>(instruction, pointer, context);
|
||||||
@ -199,7 +199,7 @@ IntT *resolve(
|
|||||||
|
|
||||||
// If execution has reached here then a memory fetch is required.
|
// If execution has reached here then a memory fetch is required.
|
||||||
// Do it and exit.
|
// Do it and exit.
|
||||||
return &context.memory.template access<IntT, access>(instruction.data_segment(), target_address);
|
return context.memory.template access<IntT, access>(instruction.data_segment(), target_address);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -98,6 +98,15 @@ struct Memory {
|
|||||||
public:
|
public:
|
||||||
using AccessType = InstructionSet::x86::AccessType;
|
using AccessType = InstructionSet::x86::AccessType;
|
||||||
|
|
||||||
|
template <typename IntT, AccessType type> struct ReturnType;
|
||||||
|
|
||||||
|
// Reads: return a value directly.
|
||||||
|
template <typename IntT> struct ReturnType<IntT, AccessType::Read> { using type = IntT; };
|
||||||
|
template <typename IntT> struct ReturnType<IntT, AccessType::PreauthorisedRead> { using type = IntT; };
|
||||||
|
|
||||||
|
// Writes: return a reference.
|
||||||
|
template <typename IntT> struct ReturnType<IntT, AccessType::Write> { using type = IntT &; };
|
||||||
|
|
||||||
// Constructor.
|
// Constructor.
|
||||||
Memory(Registers ®isters) : registers_(registers) {
|
Memory(Registers ®isters) : registers_(registers) {
|
||||||
memory.resize(1024*1024);
|
memory.resize(1024*1024);
|
||||||
@ -153,7 +162,7 @@ struct Memory {
|
|||||||
|
|
||||||
// Accesses an address based on segment:offset.
|
// Accesses an address based on segment:offset.
|
||||||
template <typename IntT, AccessType type>
|
template <typename IntT, AccessType type>
|
||||||
typename InstructionSet::x86::ReturnType<IntT, type>::type &access(InstructionSet::x86::Source segment, uint16_t offset) {
|
typename ReturnType<IntT, type>::type &access(InstructionSet::x86::Source segment, uint16_t offset) {
|
||||||
if constexpr (std::is_same_v<IntT, uint16_t>) {
|
if constexpr (std::is_same_v<IntT, uint16_t>) {
|
||||||
// If this is a 16-bit access that runs past the end of the segment, it'll wrap back
|
// If this is a 16-bit access that runs past the end of the segment, it'll wrap back
|
||||||
// to the start. So the 16-bit value will need to be a local cache.
|
// to the start. So the 16-bit value will need to be a local cache.
|
||||||
@ -176,7 +185,7 @@ struct Memory {
|
|||||||
|
|
||||||
// Accesses an address based on physical location.
|
// Accesses an address based on physical location.
|
||||||
template <typename IntT, AccessType type>
|
template <typename IntT, AccessType type>
|
||||||
typename InstructionSet::x86::ReturnType<IntT, type>::type &access(uint32_t address) {
|
typename ReturnType<IntT, type>::type &access(uint32_t address) {
|
||||||
return access<IntT, type>(address, Tag::Accessed);
|
return access<IntT, type>(address, Tag::Accessed);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -273,7 +282,7 @@ struct Memory {
|
|||||||
// Entry point used by the flow controller so that it can mark up locations at which the flags were written,
|
// Entry point used by the flow controller so that it can mark up locations at which the flags were written,
|
||||||
// so that defined-flag-only masks can be applied while verifying RAM contents.
|
// so that defined-flag-only masks can be applied while verifying RAM contents.
|
||||||
template <typename IntT, AccessType type>
|
template <typename IntT, AccessType type>
|
||||||
typename InstructionSet::x86::ReturnType<IntT, type>::type &access(InstructionSet::x86::Source segment, uint16_t offset, Tag tag) {
|
typename ReturnType<IntT, type>::type &access(InstructionSet::x86::Source segment, uint16_t offset, Tag tag) {
|
||||||
const uint32_t physical_address = address(segment, offset);
|
const uint32_t physical_address = address(segment, offset);
|
||||||
return access<IntT, type>(physical_address, tag);
|
return access<IntT, type>(physical_address, tag);
|
||||||
}
|
}
|
||||||
@ -281,7 +290,7 @@ struct Memory {
|
|||||||
// An additional entry point for the flow controller; on the original 8086 interrupt vectors aren't relative
|
// An additional entry point for the flow controller; on the original 8086 interrupt vectors aren't relative
|
||||||
// to a selector, they're just at an absolute location.
|
// to a selector, they're just at an absolute location.
|
||||||
template <typename IntT, AccessType type>
|
template <typename IntT, AccessType type>
|
||||||
typename InstructionSet::x86::ReturnType<IntT, type>::type &access(uint32_t address, Tag tag) {
|
typename ReturnType<IntT, type>::type &access(uint32_t address, Tag tag) {
|
||||||
if constexpr (type == AccessType::PreauthorisedRead) {
|
if constexpr (type == AccessType::PreauthorisedRead) {
|
||||||
if(!test_preauthorisation(address)) {
|
if(!test_preauthorisation(address)) {
|
||||||
printf("Non preauthorised access\n");
|
printf("Non preauthorised access\n");
|
||||||
|
Loading…
Reference in New Issue
Block a user