-
Notifications
You must be signed in to change notification settings - Fork 5
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
CSR/Exception unit #38
Changes from all commits
6a79f8a
b2095b3
2b55250
ac03d00
cf8d80f
936fc67
5e5778d
90ca972
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,7 @@ | |
#include "core/Fetch.hpp" | ||
#include "core/Execute.hpp" | ||
#include "core/Translate.hpp" | ||
#include "core/Exception.hpp" | ||
#include "include/ActionTags.hpp" | ||
#include "include/AtlasUtils.hpp" | ||
#include "system/AtlasSystem.hpp" | ||
|
@@ -48,6 +49,13 @@ namespace atlas | |
fetch_unit_ = getContainer()->getChild("fetch")->getResourceAs<Fetch*>(); | ||
execute_unit_ = getContainer()->getChild("execute")->getResourceAs<Execute*>(); | ||
translate_unit_ = getContainer()->getChild("translate")->getResourceAs<Translate*>(); | ||
|
||
// FIXME: Add the Exception unit to the various unit tests like Fetch/Execute/Translate | ||
if (auto exc = getContainer()->getChild("exception", false)) { | ||
exception_unit_ = exc->getResourceAs<Exception*>(); | ||
} else { | ||
exception_unit_ = nullptr; | ||
} | ||
} | ||
|
||
template <typename MemoryType> MemoryType AtlasState::readMemory(const Addr paddr) | ||
|
@@ -115,6 +123,9 @@ namespace atlas | |
|
||
// Increment PC and upate simulation state | ||
action_group->insertActionAfter(increment_pc_action_, ActionTags::EXECUTE_TAG); | ||
|
||
// Allow the Exception unit to deal with any unhandled exceptions | ||
exception_unit_->insertExecuteActions(action_group); | ||
colby-nyce marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
ActionGroup* AtlasState::incrementPc_(AtlasState*) | ||
|
@@ -128,4 +139,11 @@ namespace atlas | |
|
||
return nullptr; | ||
} | ||
|
||
uint64_t AtlasState::getMStatusInitialValue(const AtlasState* state, const uint64_t xlen_val) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is fine for now, but we should do this type of initialization at the simulation level with a command line option like this:
|
||
{ | ||
// yyy cnyce | ||
(void)state; (void)xlen; | ||
return 42949672960; | ||
} | ||
} // namespace atlas |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
#include "core/Exception.hpp" | ||
#include "core/Fetch.hpp" | ||
#include "core/AtlasState.hpp" | ||
#include "include/ActionTags.hpp" | ||
#include "sparta/simulation/ResourceTreeNode.hpp" | ||
#include "sparta/utils/LogUtils.hpp" | ||
#include "include/CSRFieldIdxs64.hpp" | ||
#include "core/inst_handlers/inst_helpers.hpp" | ||
#include "arch/register_macros.hpp" | ||
|
||
namespace atlas | ||
{ | ||
|
||
Exception::Exception(sparta::TreeNode* exception_node, const ExceptionParameters*) | ||
: sparta::Unit(exception_node) | ||
{ | ||
post_inst_handler_action_ = atlas::Action::createAction<&Exception::postInstHandler_>(this, "handle exception"); | ||
} | ||
|
||
void Exception::onBindTreeEarly_() | ||
{ | ||
auto core_tn = getContainer()->getParentAs<sparta::ResourceTreeNode>(); | ||
state_ = core_tn->getResourceAs<AtlasState>(); | ||
} | ||
|
||
ActionGroup* Exception::postInstHandler_(atlas::AtlasState* state) | ||
{ | ||
if (cause_.isValid()) { | ||
switch (state->getPrivMode()) { | ||
case PrivMode::USER: | ||
handleUModeException_(state); | ||
break; | ||
case PrivMode::MACHINE: | ||
handleMModeException_(state); | ||
break; | ||
case PrivMode::SUPERVISOR: | ||
handleSModeException_(state); | ||
break; | ||
default: | ||
sparta_assert(false, "Illegal privilege mode"); | ||
} | ||
} | ||
|
||
cause_.clearValid(); | ||
return nullptr; | ||
} | ||
|
||
void Exception::handleUModeException_(atlas::AtlasState* state) | ||
{ | ||
// TODO | ||
(void)state; | ||
sparta_assert(false, "Not implemented"); | ||
} | ||
|
||
void Exception::handleSModeException_(atlas::AtlasState* state) | ||
{ | ||
// TODO | ||
(void)state; | ||
sparta_assert(false, "Not implemented"); | ||
} | ||
|
||
void Exception::handleMModeException_(atlas::AtlasState* state) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This looks great! I think you'll find that these methods can be combined into a templated method, but this is good for now. Just add asserts to |
||
{ | ||
const reg_t trap_handler_address = (READ_CSR_REG(MTVEC) & ~(reg_t)1); | ||
state->setNextPc(trap_handler_address); | ||
|
||
const reg_t epc = state->getPc(); | ||
WRITE_CSR_REG(MEPC, epc); | ||
|
||
const uint64_t cause = static_cast<uint64_t>(cause_.getValue()); | ||
WRITE_CSR_REG(MCAUSE, cause); | ||
|
||
const uint64_t mtval = state->getCurrentInst()->getOpcode(); | ||
WRITE_CSR_REG(MTVAL, mtval); | ||
|
||
const uint64_t mtval2 = 0; | ||
WRITE_CSR_REG(MTVAL2, mtval2); | ||
|
||
const uint64_t mtinst = 0; | ||
WRITE_CSR_REG(MTINST, mtinst); | ||
|
||
// TODO cnyce: Need MSTATUS initial value. See "compute_mstatus_initial_value". | ||
|
||
const auto mstatus_mie = READ_CSR_FIELD(MSTATUS, mie); | ||
WRITE_CSR_FIELD(MSTATUS, mpie, mstatus_mie); | ||
|
||
const auto mpp = static_cast<uint64_t>(state->getPrivMode()); | ||
WRITE_CSR_FIELD(MSTATUS, mpp, mpp); | ||
|
||
const uint64_t mie = 0; | ||
WRITE_CSR_FIELD(MSTATUS, mie, mie); | ||
|
||
const uint64_t mpv = 0; | ||
WRITE_CSR_FIELD(MSTATUS, mpv, mpv); | ||
|
||
const uint64_t gva = 0; | ||
WRITE_CSR_FIELD(MSTATUS, gva, gva); | ||
} | ||
|
||
} // namespace atlas |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
#pragma once | ||
|
||
#include "core/ActionGroup.hpp" | ||
#include "core/Trap.hpp" | ||
#include "sparta/simulation/ParameterSet.hpp" | ||
#include "sparta/simulation/Unit.hpp" | ||
#include "include/ActionTags.hpp" | ||
|
||
namespace atlas | ||
{ | ||
|
||
class AtlasState; | ||
|
||
/// This class handles exceptions that occur during the fetch-translate-decode-execute cycle, | ||
/// e.g. for handling illegal instructions. | ||
class Exception : public sparta::Unit | ||
{ | ||
public: | ||
// Name of this resource, required by sparta::UnitFactory | ||
static constexpr char name[] = "Exception"; | ||
using base_type = Exception; | ||
|
||
class ExceptionParameters : public sparta::ParameterSet | ||
{ | ||
public: | ||
ExceptionParameters(sparta::TreeNode* node) : sparta::ParameterSet(node) {} | ||
}; | ||
|
||
Exception(sparta::TreeNode* exception_node, const ExceptionParameters* p); | ||
|
||
void setUnhandledException(const TrapCauses cause) { cause_ = cause; } | ||
|
||
void insertExecuteActions(ActionGroup* action_group) | ||
{ | ||
action_group->insertActionAfter(post_inst_handler_action_, ActionTags::EXECUTE_TAG); | ||
} | ||
|
||
private: | ||
void onBindTreeEarly_() override; | ||
|
||
AtlasState* state_ = nullptr; | ||
|
||
Action post_inst_handler_action_; | ||
|
||
ActionGroup* postInstHandler_(atlas::AtlasState* state); | ||
|
||
void handleUModeException_(atlas::AtlasState* state); | ||
|
||
void handleSModeException_(atlas::AtlasState* state); | ||
|
||
void handleMModeException_(atlas::AtlasState* state); | ||
|
||
sparta::utils::ValidValue<TrapCauses> cause_; | ||
}; | ||
|
||
} // namespace atlas |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
#pragma once | ||
|
||
#include <cstdint> | ||
|
||
namespace atlas | ||
{ | ||
|
||
enum class TrapCauses : uint64_t | ||
{ | ||
MISALIGNED_FETCH = 0x0, | ||
FETCH_ACCESS = 0x1, | ||
ILLEGAL_INSTRUCTION = 0x2, | ||
BREAKPOINT = 0x3, | ||
MISALIGNED_LOAD = 0x4, | ||
LOAD_ACCESS = 0x5, | ||
MISALIGNED_STORE = 0x6, | ||
STORE_ACCESS = 0x7, | ||
USER_ECALL = 0x8, | ||
SUPERVISOR_ECALL = 0x9, | ||
VIRTUAL_SUPERVISOR_ECALL = 0xa, | ||
MACHINE_ECALL = 0xb, | ||
FETCH_PAGE_FAULT = 0xc, | ||
LOAD_PAGE_FAULT = 0xd, | ||
STORE_PAGE_FAULT = 0xf, | ||
DOUBLE_TRAP = 0x10, | ||
SOFTWARE_CHECK_FAULT = 0x12, | ||
HARDWARE_ERROR_FAULT = 0x13, | ||
FETCH_GUEST_PAGE_FAULT = 0x14, | ||
LOAD_GUEST_PAGE_FAULT = 0x15, | ||
VIRTUAL_INSTRUCTION = 0x16, | ||
STORE_GUEST_PAGE_FAULT = 0x17 | ||
}; | ||
|
||
#define TRAP_IMPL(cause) \ | ||
{ \ | ||
auto exception_unit = state->getExceptionUnit(); \ | ||
exception_unit->setUnhandledException(cause); \ | ||
return nullptr; \ | ||
} | ||
|
||
#define THROW_MISALIGNED_FETCH TRAP_IMPL(TrapCauses::MISALIGNED_FETCH) | ||
#define THROW_FETCH_ACCESS TRAP_IMPL(TrapCauses::FETCH_ACCESS) | ||
#define THROW_ILLEGAL_INSTRUCTION TRAP_IMPL(TrapCauses::ILLEGAL_INSTRUCTION) | ||
#define THROW_BREAKPOINT TRAP_IMPL(TrapCauses::BREAKPOINT) | ||
#define THROW_MISALIGNED_LOAD TRAP_IMPL(TrapCauses::MISALIGNED_LOAD) | ||
#define THROW_LOAD_ACCESS TRAP_IMPL(TrapCauses::LOAD_ACCESS) | ||
#define THROW_MISALIGNED_STORE TRAP_IMPL(TrapCauses::MISALIGNED_STORE) | ||
#define THROW_STORE_ACCESS TRAP_IMPL(TrapCauses::STORE_ACCESS) | ||
#define THROW_USER_ECALL TRAP_IMPL(TrapCauses::USER_ECALL) | ||
#define THROW_SUPERVISOR_ECALL TRAP_IMPL(TrapCauses::SUPERVISOR_ECALL) | ||
#define THROW_VIRTUAL_SUPERVISOR_ECALL TRAP_IMPL(TrapCauses::VIRTUAL_SUPERVISOR_ECALL) | ||
#define THROW_MACHINE_ECALL TRAP_IMPL(TrapCauses::MACHINE_ECALL) | ||
#define THROW_FETCH_PAGE_FAULT TRAP_IMPL(TrapCauses::FETCH_PAGE_FAULT) | ||
#define THROW_LOAD_PAGE_FAULT TRAP_IMPL(TrapCauses::LOAD_PAGE_FAULT) | ||
#define THROW_STORE_PAGE_FAULT TRAP_IMPL(TrapCauses::STORE_PAGE_FAULT) | ||
#define THROW_DOUBLE_TRAP TRAP_IMPL(TrapCauses::DOUBLE_TRAP) | ||
#define THROW_SOFTWARE_CHECK_FAULT TRAP_IMPL(TrapCauses::SOFTWARE_CHECK_FAULT) | ||
#define THROW_HARDWARE_ERROR_FAULT TRAP_IMPL(TrapCauses::HARDWARE_ERROR_FAULT) | ||
#define THROW_FETCH_GUEST_PAGE_FAULT TRAP_IMPL(TrapCauses::FETCH_GUEST_PAGE_FAULT) | ||
#define THROW_LOAD_GUEST_PAGE_FAULT TRAP_IMPL(TrapCauses::LOAD_GUEST_PAGE_FAULT) | ||
#define THROW_VIRTUAL_INSTRUCTION TRAP_IMPL(TrapCauses::VIRTUAL_INSTRUCTION) | ||
#define THROW_STORE_GUEST_PAGE_FAULT TRAP_IMPL(TrapCauses::STORE_GUEST_PAGE_FAULT) | ||
|
||
} // namespace atlas |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm assuming you added this because the regression tests were failing. Please add a FIXME comment for us to update the tests later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done