blob: a892e71a9c6144fc928891855aebaee412d9352b [file]
// Copyright 2024 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 THIRD_PARTY_MPACT_RISCV_RISCV_CLINT_H_
#define THIRD_PARTY_MPACT_RISCV_RISCV_CLINT_H_
#include <cstdint>
#include "mpact/sim/generic/counters.h"
#include "mpact/sim/generic/counters_base.h"
#include "mpact/sim/generic/data_buffer.h"
#include "mpact/sim/generic/instruction.h"
#include "mpact/sim/generic/ref_count.h"
#include "mpact/sim/util/memory/memory_interface.h"
#include "riscv/riscv_xip_xie.h"
namespace mpact {
namespace sim {
namespace riscv {
// This file contains the class definition of a simple implementation of the
// RiscV Core Level Interrupt controller.
//
// The interrupt controller occupies 0x1'0000 bytes in the memory space. Only
// the lower 16 bits of addresses passed to the clint are considered. It is
// the responsibility of the callers to ensure that the memory requests are
// properly routed according to the address.
//
// The interrupt controller models three memory mapped registers:
// msip: 0xXXXX_0000 4B machine mode software interrupt.
// mtimecmp: 0xXXXX_4000 8B machine mode timer compare register.
// mtime: 0xXXXX_BFF8 8B machine mode timer register.
//
// The controller binds to a counter, for instance the instructions executed
// counter, using the CounterValueSetInterface<> interface. The update_counter_
// keeps track of how many times this is updated, and then increments the mtime
// register once for each 'period' updates. That is, the frequency of the mtime
// clock is 1/'period' of the associated counter. The controller implements the
// MemoryInterface to allow for memory-mapped loads and stores. Only the
// non-vector Load/Store methods are implemented.
//
// The controller only uses the low 16 bits of the address. It is assumed that
// any memory requests routed to the controller are done so correctly.
using ::mpact::sim::generic::CounterValueSetInterface;
using ::mpact::sim::generic::DataBuffer;
using ::mpact::sim::generic::Instruction;
using ::mpact::sim::generic::ReferenceCount;
using ::mpact::sim::generic::SimpleCounter;
using ::mpact::sim::riscv::MipExternalWriteInterface;
using ::mpact::sim::util::MemoryInterface;
class RiscVClint : public CounterValueSetInterface<uint64_t>,
public MemoryInterface {
public:
RiscVClint(int period, MipExternalWriteInterface* mip_interface);
RiscVClint() = delete;
RiscVClint(const RiscVClint&) = delete;
RiscVClint& operator=(const RiscVClint&) = delete;
~RiscVClint() override = default;
// Resets the interrupt controller.
void Reset();
// CounterValueSetInterface override. This is called when the value of the
// bound counter is modified.
void SetValue(const uint64_t& val) override;
// MemoryInterface overrides.
// Non-vector load method.
void Load(uint64_t address, DataBuffer* db, Instruction* inst,
ReferenceCount* context) override;
// Vector load method - this is stubbed out.
void Load(DataBuffer* address_db, DataBuffer* mask_db, int el_size,
DataBuffer* db, Instruction* inst,
ReferenceCount* context) override;
// Non-vector store method.
void Store(uint64_t address, DataBuffer* db) override;
// Vector store method - this is stubbed out.
void Store(DataBuffer* address, DataBuffer* mask, int el_size,
DataBuffer* db) override;
private:
// Helpers.
uint32_t Read(uint32_t offset);
void Write(uint32_t offset, uint32_t value);
// Private methods to access the 32 bit portions of the registers.
uint32_t ReadMTimeLow();
uint32_t ReadMTimeHigh();
void WriteMSip(uint32_t value);
void WriteMTimeCmpLow(uint32_t value);
void WriteMTimeCmpHigh(uint32_t value);
void WriteMTimeLow(uint32_t value);
void WriteMTimeHigh(uint32_t value);
// The simulated register values.
uint32_t msip_ = 0;
uint64_t mtime_ = 0;
uint64_t mtimecmp_ = 0;
int mtip_ = 0;
// mip write interface.
MipExternalWriteInterface* mip_interface_;
// Counter for how many updates there have been in current period.
int update_counter_ = 0;
int period_ = 0;
};
} // namespace riscv
} // namespace sim
} // namespace mpact
#endif // THIRD_PARTY_MPACT_RISCV_RISCV_CLINT_H_