1
0
mirror of https://github.com/TomHarte/CLK.git synced 2026-04-26 19:17:52 +00:00

Generalise 'Registers'.

This commit is contained in:
Thomas Harte
2025-07-21 21:17:54 -04:00
parent c490166b35
commit 1bf898405f
7 changed files with 34 additions and 239 deletions
@@ -8,20 +8,21 @@
#pragma once
#include "InstructionSets/x86/Descriptors.hpp"
#include "InstructionSets/x86/MachineStatus.hpp"
#include "InstructionSets/x86/Model.hpp"
#include "Descriptors.hpp"
#include "MachineStatus.hpp"
#include "Model.hpp"
#include "Numeric/RegisterSizes.hpp"
#include <cassert>
namespace PCCompatible {
namespace InstructionSet::x86 {
template <InstructionSet::x86::Model>
template <Model>
struct Registers;
template <>
struct Registers<InstructionSet::x86::Model::i8086> {
struct Registers<Model::i8086> {
public:
static constexpr bool is_32bit = false;
@@ -59,7 +60,7 @@ public:
uint16_t cs() const { return segments_[Source::CS]; }
uint16_t ds() const { return segments_[Source::DS]; }
uint16_t ss() const { return segments_[Source::SS]; }
uint16_t segment(const InstructionSet::x86::Source segment) const {
uint16_t segment(const Source segment) const {
return segments_[segment];
}
@@ -69,8 +70,6 @@ public:
}
private:
using Source = InstructionSet::x86::Source;
CPU::RegisterPair16 ax_;
CPU::RegisterPair16 cx_;
CPU::RegisterPair16 dx_;
@@ -81,20 +80,17 @@ private:
uint16_t si_;
uint16_t di_;
uint16_t ip_;
InstructionSet::x86::SegmentRegisterSet<uint16_t> segments_;
SegmentRegisterSet<uint16_t> segments_;
};
template <>
struct Registers<InstructionSet::x86::Model::i80186>: public Registers<InstructionSet::x86::Model::i8086> {};
struct Registers<Model::i80186>: public Registers<Model::i8086> {};
template <>
struct Registers<InstructionSet::x86::Model::i80286>: public Registers<InstructionSet::x86::Model::i80186> {
struct Registers<Model::i80286>: public Registers<Model::i80186> {
public:
using DescriptorTable = InstructionSet::x86::DescriptorTable;
using DescriptorTablePointer = InstructionSet::x86::DescriptorTablePointer;
void reset() {
Registers<InstructionSet::x86::Model::i80186>::reset();
Registers<Model::i80186>::reset();
machine_status_ = 0;
interrupt_ = DescriptorTablePointer{
.limit = 256 * 4,
@@ -105,7 +101,7 @@ public:
uint16_t msw() const { return machine_status_; }
void set_msw(const uint16_t msw) {
machine_status_ =
(machine_status_ & InstructionSet::x86::MachineStatus::ProtectedModeEnable) |
(machine_status_ & MachineStatus::ProtectedModeEnable) |
msw;
}
+4 -3
View File
@@ -10,10 +10,11 @@
#include "LinearMemory.hpp"
#include "ProcessorByModel.hpp"
#include "Registers.hpp"
#include "Segments.hpp"
#include "SegmentedMemory.hpp"
#include "InstructionSets/x86/Registers.hpp"
#include "Analyser/Static/PCCompatible/Target.hpp"
#include "Outputs/Log.hpp"
@@ -23,7 +24,7 @@ template <Analyser::Static::PCCompatible::Model model>
class CPUControl {
public:
CPUControl(
Registers<processor_model(model)> &registers,
InstructionSet::x86::Registers<processor_model(model)> &registers,
Segments<processor_model(model)> &segments,
SegmentedMemory<processor_model(model)> &segmented_memory,
LinearMemory<processor_model(model)> &linear_memory
@@ -59,7 +60,7 @@ public:
}
private:
Registers<processor_model(model)> &registers_;
InstructionSet::x86::Registers<processor_model(model)> &registers_;
Segments<processor_model(model)> &segments_;
SegmentedMemory<processor_model(model)> &segmented_memory_;
LinearMemory<processor_model(model)> &linear_memory_;
+4 -3
View File
@@ -30,6 +30,7 @@
#include "InstructionSets/x86/Flags.hpp"
#include "InstructionSets/x86/Instruction.hpp"
#include "InstructionSets/x86/Perform.hpp"
#include "InstructionSets/x86/Registers.hpp"
#include "Components/8255/i8255.hpp"
@@ -507,7 +508,7 @@ class FlowController {
static constexpr auto x86_model = processor_model(model);
public:
FlowController(Registers<x86_model> &registers, Segments<x86_model> &segments) :
FlowController(InstructionSet::x86::Registers<x86_model> &registers, Segments<x86_model> &segments) :
registers_(registers), segments_(segments) {}
// Requirements for perform.
@@ -554,7 +555,7 @@ public:
}
private:
Registers<x86_model> &registers_;
InstructionSet::x86::Registers<x86_model> &registers_;
Segments<x86_model> &segments_;
bool should_repeat_ = false;
bool halted_ = false;
@@ -990,7 +991,7 @@ private:
}
InstructionSet::x86::Flags flags;
Registers<x86_model> registers;
InstructionSet::x86::Registers<x86_model> registers;
LinearMemory<x86_model> linear_memory;
Segments<x86_model> segments;
+7 -143
View File
@@ -11,9 +11,9 @@
#include "InstructionSets/x86/AccessType.hpp"
#include "InstructionSets/x86/Descriptors.hpp"
#include "InstructionSets/x86/Model.hpp"
#include "InstructionSets/x86/Registers.hpp"
#include "LinearMemory.hpp"
#include "Registers.hpp"
#include "Segments.hpp"
#include <algorithm>
@@ -23,7 +23,7 @@ namespace PCCompatible {
// TODO: the following need to apply linear memory semantics, including potential A20 wrapping.
template <InstructionSet::x86::Model model> struct ProgramFetcher {
std::pair<const uint8_t *, size_t> next_code(
const Registers<model> &registers,
const InstructionSet::x86::Registers<model> &registers,
const Segments<model> &segments,
LinearMemory<model> &linear_memory
) const {
@@ -61,7 +61,7 @@ public:
using AccessType = InstructionSet::x86::AccessType;
SegmentedMemory(
Registers<model> &registers,
InstructionSet::x86::Registers<model> &registers,
const Segments<model> &segments,
LinearMemory<model> &linear_memory
) :
@@ -116,7 +116,7 @@ public:
}
private:
Registers<model> &registers_;
InstructionSet::x86::Registers<model> &registers_;
const Segments<model> &segments_;
LinearMemory<model> &linear_memory_;
ProgramFetcher<model> program_fetcher_;
@@ -130,7 +130,7 @@ public:
using AccessType = InstructionSet::x86::AccessType;
SegmentedMemory(
Registers<model> &registers,
InstructionSet::x86::Registers<model> &registers,
const Segments<model> &segments,
LinearMemory<model> &linear_memory
) : registers_(registers), segments_(segments), linear_memory_(linear_memory) {}
@@ -140,7 +140,7 @@ public:
//
void preauthorise_stack_write(const uint32_t size) {
const auto &descriptor = segments_.descriptors[InstructionSet::x86::Source::SS];
descriptor.authorise<InstructionSet::x86::AccessType::Write, uint16_t>(
descriptor.template authorise<InstructionSet::x86::AccessType::Write, uint16_t>(
uint16_t(registers_.sp() - size),
uint16_t(registers_.sp())
);
@@ -209,147 +209,11 @@ public:
}
private:
Registers<model> &registers_;
InstructionSet::x86::Registers<model> &registers_;
const Segments<model> &segments_;
LinearMemory<model> &linear_memory_;
ProgramFetcher<model> program_fetcher_;
Mode mode_ = Mode::Real;
};
//template <InstructionSet::x86::Model model>
//class SegmentedMemory {
// using AccessType = InstructionSet::x86::AccessType;
// using Mode = InstructionSet::x86::Mode;
//
// // Constructor.
// SegmentedMemory(
// Registers<model> &registers,
// const Segments<model> &segments,
// LinearMemory<model> &linear_memory
// ) :
// registers_(registers), segments_(segments), linear_memory_(linear_memory) {}
//
// //
// // Preauthorisation call-ins. Since only an 8088 is currently modelled, all accesses are implicitly authorised.
// //
// void preauthorise_stack_write([[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]] 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) {}
//
// void set_mode(const Mode mode) {
// mode_ = mode;
// }
//
// //
// // Access call-ins.
// //
//
// // Accesses an address based on segment:offset.
// template <typename IntT, AccessType type>
// typename InstructionSet::x86::Accessor<IntT, type>::type access(
// const InstructionSet::x86::Source segment,
// const uint16_t offset
// ) {
// const auto &descriptor = segments_.descriptors[segment];
// return linear_memory_.access<IntT, type>(
// , ds, ds)
//
// }
//
// //
// // Direct read and write.
// //
// template <typename IntT>
// void preauthorised_write(
// const InstructionSet::x86::Source segment,
// const uint16_t offset,
// const IntT value
// ) {
// linear_memory_.access<IntT, AccessType::Write>(
//
// // Bytes can be written without further ado.
// if constexpr (std::is_same_v<IntT, uint8_t>) {
// memory[address(segment, offset) & 0xf'ffff] = value;
// return;
// }
//
// // Words that straddle the segment end must be split in two.
// if(offset == 0xffff) {
// memory[address(segment, offset) & 0xf'ffff] = uint8_t(value & 0xff);
// memory[address(segment, 0x0000) & 0xf'ffff] = uint8_t(value >> 8);
// return;
// }
//
// const uint32_t target = address(segment, offset) & 0xf'ffff;
//
// // Words that straddle the end of physical RAM must also be split in two.
// if(target == 0xf'ffff) {
// memory[0xf'ffff] = uint8_t(value & 0xff);
// memory[0x0'0000] = uint8_t(value >> 8);
// return;
// }
//
// // It's safe just to write then.
// *reinterpret_cast<IntT *>(&memory[target]) = value;
// }
//
// template <typename IntT>
// IntT preauthorised_read(
// const InstructionSet::x86::Source segment,
// const uint16_t offset
// ) {
// // Bytes can be written without further ado.
// if constexpr (std::is_same_v<IntT, uint8_t>) {
// return memory[address(segment, offset) & 0xf'ffff];
// }
//
// // Words that straddle the segment end must be split in two.
// if(offset == 0xffff) {
// return IntT(
// memory[address(segment, offset) & 0xf'ffff] |
// memory[address(segment, 0x0000) & 0xf'ffff] << 8
// );
// }
//
// const uint32_t target = address(segment, offset) & 0xf'ffff;
//
// // Words that straddle the end of physical RAM must also be split in two.
// if(target == 0xf'ffff) {
// return IntT(
// memory[0xf'ffff] |
// memory[0x0'0000] << 8
// );
// }
//
// // It's safe just to write then.
// return *reinterpret_cast<IntT *>(&memory[target]);
// }
//
// //
// // Helper for instruction fetch.
// //
// std::pair<const uint8_t *, size_t> next_code() const {
// const uint32_t start =
// segments_.descriptors[InstructionSet::x86::Source::CS].to_linear(registers_.ip()) & 0xf'ffff;
// return std::make_pair(&memory[start], 0x10'000 - start);
// }
//
// std::pair<const uint8_t *, size_t> start_code() const {
// return std::make_pair(memory.data(), 0x10'000);
// }
//
//private:
// Registers<model> &registers_;
// const Segments<model> &segments_;
// LinearMemory<model> &linear_memory_;
// Mode mode_ = Mode::Real;
//
// uint32_t address(const InstructionSet::x86::Source segment, const uint16_t offset) const {
// return segments_.descriptors[segment].to_linear(offset);
// }
//};
}
+3 -3
View File
@@ -9,13 +9,13 @@
#pragma once
#include "LinearMemory.hpp"
#include "Registers.hpp"
#include "InstructionSets/x86/AccessType.hpp"
#include "InstructionSets/x86/Descriptors.hpp"
#include "InstructionSets/x86/Instruction.hpp"
#include "InstructionSets/x86/Mode.hpp"
#include "InstructionSets/x86/Model.hpp"
#include "InstructionSets/x86/Registers.hpp"
#include <cassert>
#include <functional>
@@ -26,7 +26,7 @@ namespace PCCompatible {
template <InstructionSet::x86::Model model>
class Segments {
public:
Segments(const Registers<model> &registers, const LinearMemory<model> &memory) :
Segments(const InstructionSet::x86::Registers<model> &registers, const LinearMemory<model> &memory) :
registers_(registers), memory_(memory) {}
using Descriptor = InstructionSet::x86::SegmentDescriptor;
@@ -162,7 +162,7 @@ private:
}
Mode mode_ = Mode::Real;
const Registers<model> &registers_;
const InstructionSet::x86::Registers<model> &registers_;
const LinearMemory<model> &memory_;
Descriptor last_descriptor_;
@@ -1256,7 +1256,6 @@
4238200F2B17CBC800964EFE /* Target.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Target.hpp; sourceTree = "<group>"; };
423820102B17CBC800964EFE /* StaticAnalyser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StaticAnalyser.cpp; sourceTree = "<group>"; };
423820132B1A235200964EFE /* SegmentedMemory.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = SegmentedMemory.hpp; sourceTree = "<group>"; };
423820142B1A23C200964EFE /* Registers.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Registers.hpp; sourceTree = "<group>"; };
423820152B1A23E100964EFE /* Segments.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Segments.hpp; sourceTree = "<group>"; };
423820422B1A90BE00964EFE /* PCBooter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PCBooter.cpp; sourceTree = "<group>"; };
423820432B1A90BE00964EFE /* PCBooter.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = PCBooter.hpp; sourceTree = "<group>"; };
@@ -1734,6 +1733,7 @@
4B7BA03823CEB8D200B98D9E /* DiskController.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = DiskController.hpp; sourceTree = "<group>"; };
4B7BA03E23D55E7900B98D9E /* CRC.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CRC.hpp; sourceTree = "<group>"; };
4B7BA03F23D55E7900B98D9E /* LFSR.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = LFSR.hpp; sourceTree = "<group>"; };
4B7BD24F2E2F1C6D00FDAEC9 /* Registers.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Registers.hpp; sourceTree = "<group>"; };
4B7C681427517A59001671EC /* Sprites.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Sprites.cpp; sourceTree = "<group>"; };
4B7C681527517A59001671EC /* Sprites.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Sprites.hpp; sourceTree = "<group>"; };
4B7C6818275196E8001671EC /* MouseJoystick.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = MouseJoystick.cpp; sourceTree = "<group>"; };
@@ -2582,7 +2582,6 @@
4267A9C82B0D4EC2008A59BB /* PIC.hpp */,
4267A9C72B0C26FA008A59BB /* PIT.hpp */,
4B1FBE1F2D77AAC500BAC888 /* ProcessorByModel.hpp */,
423820142B1A23C200964EFE /* Registers.hpp */,
42EB81252B21788200429AF4 /* RTC.hpp */,
423820132B1A235200964EFE /* SegmentedMemory.hpp */,
423820152B1A23E100964EFE /* Segments.hpp */,
@@ -5384,6 +5383,7 @@
4B8671EB2D8FABA0009E1610 /* Mode.hpp */,
4BE3C69527CBC540000EAD28 /* Model.hpp */,
42437B352ACF0AA2006DFED1 /* Perform.hpp */,
4B7BD24F2E2F1C6D00FDAEC9 /* Registers.hpp */,
4B25BC1E2DDD64AA002044CA /* TaskStateSegment.hpp */,
42437B372ACF2798006DFED1 /* Implementation */,
);
+1 -68
View File
@@ -34,75 +34,8 @@ namespace {
constexpr char TestSuiteHome[] = "/Users/thomasharte/Projects/8088/v1";
using Flags = InstructionSet::x86::Flags;
struct Registers {
public:
// static constexpr bool is_32bit = false;
using Registers = InstructionSet::x86::Registers<InstructionSet::x86::Model::i8086>;
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_; }
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 &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 &ip() { return ip_; }
uint16_t &es() { return es_; }
uint16_t &cs() { return cs_; }
uint16_t &ds() { return ds_; }
uint16_t &ss() { return ss_; }
const uint16_t es() const { return es_; }
const uint16_t cs() const { return cs_; }
const uint16_t ds() const { return ds_; }
const uint16_t ss() const { return ss_; }
bool operator ==(const Registers &rhs) const {
return
ax_.full == rhs.ax_.full &&
cx_.full == rhs.cx_.full &&
dx_.full == rhs.dx_.full &&
bx_.full == rhs.bx_.full &&
sp_ == rhs.sp_ &&
bp_ == rhs.bp_ &&
si_ == rhs.si_ &&
di_ == rhs.di_ &&
es_ == rhs.es_ &&
cs_ == rhs.cs_ &&
ds_ == rhs.ds_ &&
si_ == rhs.si_ &&
ip_ == rhs.ip_;
}
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_;
};
class Segments {
public:
Segments(const Registers &registers) : registers_(registers) {}