Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Core class cleanup #387

Merged
merged 9 commits into from
Feb 16, 2024
90 changes: 86 additions & 4 deletions src/include/simeng/Core.hh
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,31 @@
#include <map>
#include <string>

#include "simeng/ArchitecturalRegisterFileSet.hh"
#include "simeng/arch/ProcessStateChange.hh"
#include "simeng/config/SimInfo.hh"
#include "simeng/memory/MemoryInterface.hh"

namespace simeng {

class ArchitecturalRegisterFileSet;
namespace arch {
// Forward declare Architecture and ExceptionHandler classes.
class Architecture;
class ExceptionHandler;
} // namespace arch

/** An abstract core model. */
class Core {
public:
Core(memory::MemoryInterface& dataMemory, const arch::Architecture& isa,
const std::vector<RegisterFileStructure>& regFileStructure)
: dataMemory_(dataMemory),
isa_(isa),
registerFileSet_(regFileStructure),
clockFrequency_(
config::SimInfo::getConfig()["Core"]["Clock-Frequency-GHz"]
.as<float>()) {}

virtual ~Core() {}

/** Tick the core. */
Expand All @@ -28,11 +44,77 @@ class Core {
/** Retrieve the number of instructions retired. */
virtual uint64_t getInstructionsRetiredCount() const = 0;

/** Retrieve the simulated nanoseconds elapsed since the core started. */
virtual uint64_t getSystemTimer() const = 0;

/** Retrieve a map of statistics to report. */
virtual std::map<std::string, std::string> getStats() const = 0;

/** Retrieve the simulated nanoseconds elapsed since the core started. */
uint64_t getSystemTimer() const {
// TODO: This will need to be changed if we start supporting DVFS.
return (ticks_ / clockFrequency_);
}

protected:
/** Apply changes to the process state. */
void applyStateChange(const arch::ProcessStateChange& change) const {
auto& regFile = const_cast<ArchitecturalRegisterFileSet&>(
getArchitecturalRegisterFileSet());
// Update registers in accordance with the ProcessStateChange type
switch (change.type) {
case arch::ChangeType::INCREMENT: {
for (size_t i = 0; i < change.modifiedRegisters.size(); i++) {
regFile.set(change.modifiedRegisters[i],
regFile.get(change.modifiedRegisters[i]).get<uint64_t>() +
change.modifiedRegisterValues[i].get<uint64_t>());
}
break;
}
case arch::ChangeType::DECREMENT: {
for (size_t i = 0; i < change.modifiedRegisters.size(); i++) {
regFile.set(change.modifiedRegisters[i],
regFile.get(change.modifiedRegisters[i]).get<uint64_t>() -
change.modifiedRegisterValues[i].get<uint64_t>());
}
break;
}
default: { // arch::ChangeType::REPLACEMENT
// If type is ChangeType::REPLACEMENT, set new values
for (size_t i = 0; i < change.modifiedRegisters.size(); i++) {
regFile.set(change.modifiedRegisters[i],
change.modifiedRegisterValues[i]);
}
break;
}
}

// Update memory
// TODO: Analyse if ChangeType::INCREMENT or ChangeType::DECREMENT case is
// required for memory changes
for (size_t i = 0; i < change.memoryAddresses.size(); i++) {
dataMemory_.requestWrite(change.memoryAddresses[i],
change.memoryAddressValues[i]);
}
}

/** A memory interface to access data. */
memory::MemoryInterface& dataMemory_;

/** The currently used ISA. */
const arch::Architecture& isa_;

/** The core's register file set. */
RegisterFileSet registerFileSet_;

/** The active exception handler. */
std::shared_ptr<arch::ExceptionHandler> exceptionHandler_;

/** The number of times this core has been ticked. */
uint64_t ticks_ = 0;

/** Whether or not the core has halted. */
bool hasHalted_ = false;

/** Clock frequency of core in GHz */
float clockFrequency_ = 0.0f;
};

} // namespace simeng
21 changes: 11 additions & 10 deletions src/include/simeng/CoreInstance.hh
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
#include "simeng/AlwaysNotTakenPredictor.hh"
#include "simeng/Core.hh"
#include "simeng/Elf.hh"
#include "simeng/FixedLatencyMemoryInterface.hh"
#include "simeng/FlatMemoryInterface.hh"
#include "simeng/GenericPredictor.hh"
#include "simeng/PerceptronPredictor.hh"
#include "simeng/SpecialFileDirGen.hh"
Expand All @@ -15,6 +13,8 @@
#include "simeng/arch/riscv/Architecture.hh"
#include "simeng/config/SimInfo.hh"
#include "simeng/kernel/Linux.hh"
#include "simeng/memory/FixedLatencyMemoryInterface.hh"
#include "simeng/memory/FlatMemoryInterface.hh"
#include "simeng/models/emulation/Core.hh"
#include "simeng/models/inorder/Core.hh"
#include "simeng/models/outoforder/Core.hh"
Expand Down Expand Up @@ -52,10 +52,11 @@ class CoreInstance {
~CoreInstance();

/** Set the SimEng L1 instruction cache memory. */
void setL1InstructionMemory(std::shared_ptr<simeng::MemoryInterface> memRef);
void setL1InstructionMemory(
std::shared_ptr<simeng::memory::MemoryInterface> memRef);

/** Set the SimEng L1 data cache memory. */
void setL1DataMemory(std::shared_ptr<simeng::MemoryInterface> memRef);
void setL1DataMemory(std::shared_ptr<simeng::memory::MemoryInterface> memRef);

/** Construct the core and all its associated simulation objects after the
* process and memory interfaces have been instantiated. */
Expand All @@ -65,10 +66,10 @@ class CoreInstance {
std::shared_ptr<simeng::Core> getCore() const;

/** Getter for the create data memory object. */
std::shared_ptr<simeng::MemoryInterface> getDataMemory() const;
std::shared_ptr<simeng::memory::MemoryInterface> getDataMemory() const;

/** Getter for the create instruction memory object. */
std::shared_ptr<simeng::MemoryInterface> getInstructionMemory() const;
std::shared_ptr<simeng::memory::MemoryInterface> getInstructionMemory() const;

/** Getter for a shared pointer to the created process image. */
std::shared_ptr<char> getProcessImage() const;
Expand All @@ -95,10 +96,10 @@ class CoreInstance {
void createProcessMemory();

/** Construct the SimEng L1 instruction cache memory. */
void createL1InstructionMemory(const simeng::MemInterfaceType type);
void createL1InstructionMemory(const memory::MemInterfaceType type);

/** Construct the SimEng L1 data cache memory. */
void createL1DataMemory(const simeng::MemInterfaceType type);
void createL1DataMemory(const memory::MemInterfaceType type);

/** Construct the special file directory. */
void createSpecialFileDirectory();
Expand Down Expand Up @@ -146,10 +147,10 @@ class CoreInstance {
std::shared_ptr<simeng::Core> core_ = nullptr;

/** Reference to the SimEng data memory object. */
std::shared_ptr<simeng::MemoryInterface> dataMemory_ = nullptr;
std::shared_ptr<simeng::memory::MemoryInterface> dataMemory_ = nullptr;

/** Reference to the SimEng instruction memory object. */
std::shared_ptr<simeng::MemoryInterface> instructionMemory_ = nullptr;
std::shared_ptr<simeng::memory::MemoryInterface> instructionMemory_ = nullptr;
};

} // namespace simeng
1 change: 1 addition & 0 deletions src/include/simeng/Elf.hh
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once

#include <cstdint>
#include <string>
#include <vector>

Expand Down
9 changes: 5 additions & 4 deletions src/include/simeng/Instruction.hh
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@

#include "capstone/capstone.h"
#include "simeng/BranchPredictor.hh"
#include "simeng/MemoryInterface.hh"
#include "simeng/RegisterFileSet.hh"
#include "simeng/Register.hh"
#include "simeng/RegisterValue.hh"
#include "simeng/memory/MemoryInterface.hh"
#include "simeng/span.hh"

using InstructionException = short;
Expand Down Expand Up @@ -84,13 +84,14 @@ class Instruction {
virtual const span<RegisterValue> getResults() const = 0;

/** Generate memory addresses this instruction wishes to access. */
virtual span<const MemoryAccessTarget> generateAddresses() = 0;
virtual span<const memory::MemoryAccessTarget> generateAddresses() = 0;

/** Provide data from a requested memory address. */
virtual void supplyData(uint64_t address, const RegisterValue& data) = 0;

/** Retrieve previously generated memory addresses. */
virtual span<const MemoryAccessTarget> getGeneratedAddresses() const = 0;
virtual span<const memory::MemoryAccessTarget> getGeneratedAddresses()
const = 0;

/** Retrieve supplied memory data. */
virtual span<const RegisterValue> getData() const = 0;
Expand Down
29 changes: 29 additions & 0 deletions src/include/simeng/Register.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#pragma once
#include <iostream>

namespace simeng {

/** A generic register identifier. */
struct Register {
/** An identifier representing the type of register - e.g. 0 = general, 1 =
* vector. Used to determine which register file to access. */
uint8_t type;

/** A tag identifying the register. May correspond to either physical or
* architectural register, depending on point of usage. */
uint16_t tag;

/** A boolean identifier for whether the creation of this register has been a
* result of a register renaming scheme. */
bool renamed = false;

/** Check for equality of two register identifiers. */
bool operator==(const Register& other) const {
return (other.type == type && other.tag == tag);
}

/** Check for inequality of two register identifiers. */
bool operator!=(const Register& other) const { return !(other == *this); }
};

} // namespace simeng
23 changes: 1 addition & 22 deletions src/include/simeng/RegisterFileSet.hh
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,11 @@

#include <vector>

#include "simeng/Register.hh"
#include "simeng/RegisterValue.hh"

namespace simeng {

/** A generic register identifier. */
struct Register {
/** An identifier representing the type of register - e.g. 0 = general, 1 =
* vector. Used to determine which register file to access. */
uint8_t type;

/** A tag identifying the register. May correspond to either physical or
* architectural register, depending on point of usage. */
uint16_t tag;

/** A boolean identifier for whether the creation of this register has been a
* result of a register renaming scheme. */
bool renamed = false;

/** Check for equality of two register identifiers. */
bool operator==(const Register& other) const;

/** Check for inequality of two register identifiers. */
bool operator!=(const Register& other) const;
};
std::ostream& operator<<(std::ostream& os, simeng::Register const& reg);

/** Defines the structure of a register file. */
struct RegisterFileStructure {
/** The number of bytes per register. */
Expand Down
22 changes: 3 additions & 19 deletions src/include/simeng/arch/Architecture.hh
Original file line number Diff line number Diff line change
Expand Up @@ -6,32 +6,16 @@
#include "simeng/BranchPredictor.hh"
#include "simeng/Core.hh"
#include "simeng/Instruction.hh"
#include "simeng/MemoryInterface.hh"
#include "simeng/arch/ProcessStateChange.hh"
#include "simeng/kernel/Linux.hh"
#include "simeng/memory/MemoryInterface.hh"

namespace simeng {

using MacroOp = std::vector<std::shared_ptr<Instruction>>;

namespace arch {

/** The types of changes that can be made to values within the process state. */
enum class ChangeType { REPLACEMENT, INCREMENT, DECREMENT };

/** A structure describing a set of changes to the process state. */
struct ProcessStateChange {
/** Type of changes to be made */
ChangeType type;
/** Registers to modify */
std::vector<Register> modifiedRegisters;
/** Values to set modified registers to */
std::vector<RegisterValue> modifiedRegisterValues;
/** Memory address/width pairs to modify */
std::vector<MemoryAccessTarget> memoryAddresses;
/** Values to write to memory */
std::vector<RegisterValue> memoryAddressValues;
};

/** The result from a handled exception. */
struct ExceptionResult {
/** Whether execution should halt. */
Expand Down Expand Up @@ -82,7 +66,7 @@ class Architecture {
* obtained. */
virtual std::shared_ptr<ExceptionHandler> handleException(
const std::shared_ptr<Instruction>& instruction, const Core& core,
MemoryInterface& memory) const = 0;
memory::MemoryInterface& memory) const = 0;

/** Retrieve the initial process state. */
virtual ProcessStateChange getInitialState() const = 0;
Expand Down
31 changes: 31 additions & 0 deletions src/include/simeng/arch/ProcessStateChange.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#pragma once
jj16791 marked this conversation as resolved.
Show resolved Hide resolved

#include <vector>

#include "simeng/Register.hh"
#include "simeng/RegisterValue.hh"
#include "simeng/memory/MemoryAccessTarget.hh"

namespace simeng {

namespace arch {

/** The types of changes that can be made to values within the process state. */
enum class ChangeType { REPLACEMENT, INCREMENT, DECREMENT };

/** A structure describing a set of changes to the process state. */
struct ProcessStateChange {
/** Type of changes to be made */
ChangeType type;
/** Registers to modify */
std::vector<Register> modifiedRegisters;
/** Values to set modified registers to */
std::vector<RegisterValue> modifiedRegisterValues;
/** Memory address/width pairs to modify */
std::vector<memory::MemoryAccessTarget> memoryAddresses;
/** Values to write to memory */
std::vector<RegisterValue> memoryAddressValues;
};

} // namespace arch
} // namespace simeng
2 changes: 1 addition & 1 deletion src/include/simeng/arch/aarch64/Architecture.hh
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class Architecture : public arch::Architecture {
* the exception is resolved, and results then obtained. */
std::shared_ptr<arch::ExceptionHandler> handleException(
const std::shared_ptr<simeng::Instruction>& instruction, const Core& core,
MemoryInterface& memory) const override;
memory::MemoryInterface& memory) const override;

/** Retrieve the initial process state. */
ProcessStateChange getInitialState() const override;
Expand Down
4 changes: 2 additions & 2 deletions src/include/simeng/arch/aarch64/ExceptionHandler.hh
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class ExceptionHandler : public simeng::arch::ExceptionHandler {
/** Create an exception handler with references to the instruction that caused
* the exception, along with the core model object and process memory. */
ExceptionHandler(const std::shared_ptr<simeng::Instruction>& instruction,
const Core& core, MemoryInterface& memory,
const Core& core, memory::MemoryInterface& memory,
kernel::Linux& linux);

/** Progress handling of the exception, by calling and returning the result of
Expand Down Expand Up @@ -78,7 +78,7 @@ class ExceptionHandler : public simeng::arch::ExceptionHandler {
const Core& core_;

/** The process memory. */
MemoryInterface& memory_;
memory::MemoryInterface& memory_;

/** The Linux kernel to forward syscalls to. */
kernel::Linux& linux_;
Expand Down
Loading