1
0
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:
Thomas Harte 2023-11-06 16:04:31 -05:00
parent 797c9fe129
commit 2af774601f
4 changed files with 59 additions and 41 deletions

View File

@ -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;
} }

View File

@ -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(),

View File

@ -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);
} }
} }

View File

@ -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 &registers) : registers_(registers) { Memory(Registers &registers) : 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");