blob: f14724e49c1c635fbfd44e7e4c695b648ad15982 [file]
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef MPACT_RISCV_RISCV_RISCV_XSTATUS_H_
#define MPACT_RISCV_RISCV_RISCV_XSTATUS_H_
#include <cstdint>
#include "mpact/sim/generic/arch_state.h"
#include "riscv/riscv_csr.h"
#include "riscv/riscv_misa.h"
// This file defines the classes that implement the hardware status CSR for
// machine mode (mstatus), supervisor mode (sstatus), and user mode (ustatus).
// The implementation is derived from RiscVCsr<uint64_t>
namespace mpact {
namespace sim {
namespace riscv {
using ::mpact::sim::generic::ArchState;
class RiscVMStatus : public RiscVSimpleCsr<uint64_t> {
public:
// Read/Write masks.
static constexpr uint64_t kReadMask = 0x8000'000f'007f'f9bbULL;
static constexpr uint64_t kWriteMask = 0x0000'0000'007f'f9bbULL;
// Disable default constructor.
RiscVMStatus() = delete;
RiscVMStatus(uint32_t initial_value, ArchState *state, RiscVMIsa *misa);
RiscVMStatus(uint64_t initial_value, ArchState *state, RiscVMIsa *misa);
~RiscVMStatus() override = default;
// RiscVSimpleCsr<uint64_t> method overrides.
uint32_t AsUint32() override;
void Write(uint32_t value) override;
void SetBits(uint32_t bits) override;
void ClearBits(uint32_t bits) override;
uint32_t GetUint32() override;
void Set(uint32_t value) override;
void Set(uint64_t value) override;
// Getters for state info.
// Read only dirty bit.
bool sd() { return GetterHelper<31, 0b1>() || GetterHelper<63, 0b1>(); }
// SXL - supervisor xlen.
int sxl() { return GetterHelper<34, 0b11>(); }
// UXL - user xlen.
int uxl() { return GetterHelper<32, 0b11>(); }
// Trap SRET.
bool tsr() { return GetterHelper<22, 0b1>(); }
// TW - timeout wait (WFI).
bool tw() { return GetterHelper<21, 0b1>(); }
// TVM - trap virtual memory.
bool tvm() { return GetterHelper<20, 0b1>(); }
// MXR - make executable readable.
bool mxr() { return GetterHelper<19, 0b1>(); }
// SUM - supervisor user memory access.
bool sum() { return GetterHelper<18, 0b1>(); }
// MPRV - modify privilege bit.
bool mprv() { return GetterHelper<17, 0b1>(); }
// XS - extension state dirty.
int xs() { return GetterHelper<15, 0b11>(); }
// FS - fp state dirty.
int fs() { return GetterHelper<13, 0b11>(); }
// MPP - machine previous privilege level.
int mpp() { return GetterHelper<11, 0b11>(); }
// SPP - supervisor previous privilege level.
int spp() { return GetterHelper<8, 0b1>(); }
// Previous interrupt enable for machine, supervisor, and user level.
bool mpie() { return GetterHelper<7, 0b1>(); }
bool spie() { return GetterHelper<5, 0b1>(); }
bool upie() { return GetterHelper<4, 0b1>(); }
// Interrupt enable for machine, supervisor, and user level.
bool mie() { return GetterHelper<3, 0b1>(); }
bool sie() { return GetterHelper<1, 0b1>(); }
bool uie() { return GetterHelper<0, 0b1>(); }
// Setters for state info. Using uint32_t since each field is only a bit or
// two. These set a value in a buffer. The buffer has to be submitted after
// the writes so that all the set_* get batched into one update.
void set_tsr(uint32_t value) { SetterHelper<22, 0b1>(value); }
void set_tw(uint32_t value) { SetterHelper<21, 0b1>(value); }
void set_tvm(uint32_t value) { SetterHelper<20, 0b1>(value); }
void set_mxr(uint32_t value) { SetterHelper<19, 0b1>(value); }
void set_sum(uint32_t value) { SetterHelper<18, 0b1>(value); }
void set_mprv(uint32_t value) { SetterHelper<17, 0b1>(value); }
void set_xs(uint32_t value) { SetterHelper<15, 0b11>(value); }
void set_fs(uint32_t value) { SetterHelper<13, 0b11>(value); }
void set_mpp(uint32_t value);
void set_spp(uint32_t value) { SetterHelper<8, 0b1>(value); }
void set_mpie(uint32_t value) { SetterHelper<7, 0b1>(value); }
void set_spie(uint32_t value) { SetterHelper<5, 0b1>(value); }
void set_upie(uint32_t value) { SetterHelper<4, 0b1>(value); }
void set_mie(uint32_t value) { SetterHelper<3, 0b1>(value); }
void set_sie(uint32_t value) { SetterHelper<1, 0b1>(value); }
void set_uie(uint32_t value) { SetterHelper<0, 0b1>(value); }
void Submit() {
uint64_t new_value = (GetUint64() & ~buffer_mask_) | buffer_;
Write(new_value);
buffer_ = 0;
buffer_mask_ = 0;
}
private:
// Private constructor.
RiscVMStatus(uint64_t initial_value, ArchState *state, RiscVXlen xlen,
RiscVMIsa *misa);
// Template function to help implement the getters.
template <int Shift, uint64_t BitMask>
inline int GetterHelper() {
return (GetUint64() >> Shift) & BitMask;
}
// Template function to help implement the setters.
template <int Shift, uint64_t BitMask>
inline void SetterHelper(uint32_t value) {
buffer_ = (buffer_ & ~(BitMask << Shift)) | ((value & BitMask) << Shift);
buffer_mask_ |= BitMask << Shift;
}
RiscVMIsa *misa_;
uint64_t buffer_ = 0;
uint64_t buffer_mask_ = 0;
uint32_t read_mask_32_;
uint32_t write_mask_32_;
uint64_t set_mask_from_32_;
};
// The sstatus register is just a restricted subset of mstatus, so the real
// values are contained in mstatus. This provides really just an interface
// to access the restricted subset.
class RiscVSStatus : public RiscVSimpleCsr<uint64_t> {
public:
static constexpr uint64_t kReadMask = 0x8000'0003'000d'e133ULL;
static constexpr uint64_t kWriteMask = 0x0000'0000'000d'e133ULL;
RiscVSStatus() = delete;
RiscVSStatus(RiscVMStatus *mstatus, RiscVState *state);
// Overrides.
uint64_t AsUint64() override;
uint32_t AsUint32() override;
void Write(uint32_t value) override;
void SetBits(uint32_t bits) override;
void ClearBits(uint32_t bits) override;
void Set(uint32_t value) override;
void Set(uint64_t value) override;
uint32_t GetUint32() override;
uint64_t GetUint64() override;
// Getters for state info.
// Read only dirty bit.
bool sd() { return mstatus_->sd(); }
// UXL - user xlen.
int uxl() { return mstatus_->uxl(); }
// MXR - make executable readable.
bool mxr() { return mstatus_->mxr(); }
// SUM - supervisor user memory access.
bool sum() { return mstatus_->sum(); }
// XS - extension state dirty.
int xs() { return mstatus_->xs(); }
// FS - fp state dirty.
int fs() { return mstatus_->fs(); }
// SPP - supervisor previous privilege level.
int spp() { return mstatus_->spp(); }
// Previous interrupt enable for machine, supervisor, and user level.
bool spie() { return mstatus_->spie(); }
bool upie() { return mstatus_->upie(); }
// Interrupt enable for machine, supervisor, and user level.
bool sie() { return mstatus_->sie(); }
bool uie() { return mstatus_->uie(); }
// Setters for state info. Using uint32_t since each field is only a bit or
// two.
void set_mxr(uint32_t value) { mstatus_->set_mxr(value); }
void set_sum(uint32_t value) { mstatus_->set_sum(value); }
void set_xs(uint32_t value) { mstatus_->set_xs(value); }
void set_fs(uint32_t value) { mstatus_->set_fs(value); }
void set_spp(uint32_t value) { mstatus_->set_spp(value); }
void set_spie(uint32_t value) { mstatus_->set_spie(value); }
void set_upie(uint32_t value) { mstatus_->set_upie(value); }
void set_sie(uint32_t value) { mstatus_->set_sie(value); }
void set_uie(uint32_t value) { mstatus_->set_uie(value); }
void Submit() { mstatus_->Submit(); }
private:
uint32_t read_mask_32_;
uint32_t write_mask_32_;
uint64_t set_mask_from_32_;
RiscVMStatus *mstatus_;
};
// The ustatus register is a further restricted view of sstatus.
class RiscVUStatus : public RiscVSimpleCsr<uint64_t> {
public:
static constexpr uint64_t kReadMask = 0x11ULL;
static constexpr uint64_t kWriteMask = 0x11ULL;
RiscVUStatus() = delete;
RiscVUStatus(RiscVMStatus *mstatus, RiscVState *state);
// Overrides.
uint64_t AsUint64() override;
uint32_t AsUint32() override;
void Write(uint32_t value) override;
void SetBits(uint32_t bits) override;
void ClearBits(uint32_t bits) override;
void Set(uint32_t value) override;
void Set(uint64_t value) override;
uint32_t GetUint32() override;
uint64_t GetUint64() override;
// Accessors.
bool uie() { return mstatus_->uie(); }
void set_uie(uint32_t value) { mstatus_->set_uie(value); }
private:
uint32_t read_mask_32_;
uint32_t write_mask_32_;
uint64_t set_mask_from_32_;
RiscVMStatus *mstatus_;
};
} // namespace riscv
} // namespace sim
} // namespace mpact
#endif // MPACT_RISCV_RISCV_RISCV_XSTATUS_H_