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

CSR/Exception unit #38

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions core/AtlasState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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)) {
Copy link
Contributor

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.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

exception_unit_ = exc->getResourceAs<Exception*>();
} else {
exception_unit_ = nullptr;
}
}

template <typename MemoryType> MemoryType AtlasState::readMemory(const Addr paddr)
Expand Down Expand Up @@ -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*)
Expand All @@ -128,4 +139,11 @@ namespace atlas

return nullptr;
}

uint64_t AtlasState::getMStatusInitialValue(const AtlasState* state, const uint64_t xlen_val)
Copy link
Contributor

Choose a reason for hiding this comment

The 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:

--reg-init-val mstatus 42949672960

{
// yyy cnyce
(void)state; (void)xlen;
return 42949672960;
}
} // namespace atlas
13 changes: 13 additions & 0 deletions core/AtlasState.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ namespace atlas
class Fetch;
class Execute;
class Translate;
class Exception;

class AtlasState : public sparta::Unit
{
Expand Down Expand Up @@ -74,6 +75,13 @@ namespace atlas

uint64_t assignUid() { return uid_++; }

uint64_t getMStatusInitialValue() const
{
return AtlasState::getMStatusInitialValue(this, getXlen());
}

static uint64_t getMStatusInitialValue(const AtlasState* state, const uint64_t xlen_val);

struct SimState
{
AtlasInstPtr current_inst = nullptr;
Expand Down Expand Up @@ -140,6 +148,8 @@ namespace atlas

ActionGroup* getStopSimActionGroup() { return &stop_sim_action_group_; }

Exception* getExceptionUnit() const { return exception_unit_; }

private:
void onBindTreeEarly_() override;

Expand Down Expand Up @@ -190,6 +200,9 @@ namespace atlas
// Translate Unit
Translate* translate_unit_ = nullptr;

// Exception Unit
Exception* exception_unit_ = nullptr;

// Register set holding all Sparta registers from all generated JSON files
std::unique_ptr<RegisterSet> int_rset_;
std::unique_ptr<RegisterSet> fp_rset_;
Expand Down
1 change: 1 addition & 0 deletions core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ add_library(atlascore
Fetch.cpp
Translate.cpp
Execute.cpp
Exception.cpp
AtlasExtractor.cpp
AtlasInst.cpp
PageTableWalker.cpp
Expand Down
100 changes: 100 additions & 0 deletions core/Exception.cpp
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)
Copy link
Contributor

Choose a reason for hiding this comment

The 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 handleSModeException_ and handleUModeException_ to make sure Atlas fails if they get called.

{
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
56 changes: 56 additions & 0 deletions core/Exception.hpp
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
14 changes: 14 additions & 0 deletions core/Fetch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "core/AtlasState.hpp"
#include "core/Execute.hpp"
#include "core/Translate.hpp"
#include "core/Exception.hpp"
#include "include/ActionTags.hpp"

#include "mavis/mavis/Mavis.h"
Expand All @@ -11,6 +12,11 @@
#include "sparta/simulation/ResourceTreeNode.hpp"
#include "sparta/utils/LogUtils.hpp"

#include "include/CSRFieldIdxs64.hpp"
#include "arch/register_macros.hpp"
//#include "core/inst_handlers/inst_helpers.hpp"
//#include "arch/register_macros.hpp"

namespace atlas
{
std::vector<std::string> getIsaFiles(const std::string & isa_file_path)
Expand Down Expand Up @@ -71,6 +77,10 @@ namespace atlas
decode_action_group_.setNextActionGroup(execute_action_group);
execute_action_group->setNextActionGroup(&fetch_action_group_);

// Note that even though we also have the Exception unit, we do not wire up the ActionGroups
// now since we do not expect many exceptions to be hit. The trap() method will insert the
// handler's ActionGroup on demand.

sparta::TreeNode* fetch_node = core_tn->getChild("fetch");
mavis_.reset(new MavisType(
getIsaFiles(isa_file_path_), getUArchFiles(uarch_file_path_),
Expand Down Expand Up @@ -137,6 +147,10 @@ namespace atlas

void Fetch::advanceSim_()
{
const auto mstatus = state_->getMStatusInitialValue();
auto state = state_;
POKE_CSR_REG(MSTATUS, mstatus);

// Run
ActionGroup* next_action_group = &fetch_action_group_;
while (next_action_group && (next_action_group->hasTag(ActionTags::STOP_SIM_TAG) == false))
Expand Down
64 changes: 64 additions & 0 deletions core/Trap.hpp
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
Loading