/*! \file CPU.h \brief Main CPU class \author Màrius Montón \date August 2018 */ // SPDX-License-Identifier: GPL-3.0-or-later #ifndef CPU_BASE_H #define CPU_BASE_H #define SC_INCLUDE_DYNAMIC_PROCESSES #include "systemc" #include "tlm.h" #include "tlm_utils/simple_initiator_socket.h" #include "tlm_utils/tlm_quantumkeeper.h" #include "memory.h" #include "MemoryInterface.h" #include "BASE_ISA.h" #include "Registers.h" #include "Instruction.h" #include "C_extension.h" #include "M_extension.h" #include "A_extension.h" namespace riscv_tlm { class CPU : sc_core::sc_module { public: /* Constructors */ explicit CPU(sc_core::sc_module_name const &name, bool debug); CPU() noexcept = delete; CPU(const CPU& other) noexcept = delete; CPU(CPU && other) noexcept = delete; CPU& operator=(const CPU& other) noexcept = delete; CPU& operator=(CPU&& other) noexcept = delete; /* Destructors */ ~CPU() override = default; /** * @brief Perform one instruction step * @return Breackpoint found (TBD, always true) */ virtual bool CPU_step() = 0; /** * @brief Instruction Memory bus socket * @param trans transction to perfoem * @param delay time to annotate */ tlm_utils::simple_initiator_socket instr_bus; /** * @brief IRQ line socket * @param trans transction to perform (empty) * @param delay time to annotate */ tlm_utils::simple_target_socket irq_line_socket; /** * @brief DMI pointer is not longer valid * @param start memory address region start * @param end memory address region end */ void invalidate_direct_mem_ptr(sc_dt::uint64 start, sc_dt::uint64 end); /** * @brief CPU main thread */ [[noreturn]] void CPU_thread(); /** * @brief Process and triggers IRQ if all conditions met * @return true if IRQ is triggered, false otherwise */ virtual bool cpu_process_IRQ() = 0; /** * @brief callback for IRQ simple socket * @param trans transaction to perform (empty) * @param delay time to annotate * * it triggers an IRQ when called */ virtual void call_interrupt(tlm::tlm_generic_payload &trans, sc_core::sc_time &delay) = 0; public: MemoryInterface *mem_intf; protected: Performance *perf; std::shared_ptr logger; tlm_utils::tlm_quantumkeeper *m_qk; Instruction inst; bool interrupt; bool irq_already_down; sc_core::sc_time default_time; bool dmi_ptr_valid; tlm::tlm_generic_payload trans; unsigned char *dmi_ptr = nullptr; }; /** * @brief RISC_V CPU 32 bits model * @param name name of the module */ class RV32 : public CPU { public: using BaseType = std::uint32_t; /** * @brief Constructor * @param name Module name * @param PC Program Counter initialize value * @param debug To start debugging */ RV32(sc_core::sc_module_name const &name, BaseType PC, bool debug); /** * @brief Destructor */ ~RV32() override; bool CPU_step() override; Registers *getRegisterBank() { return register_bank; } private: Registers *register_bank; C_extension *c_inst; M_extension *m_inst; A_extension *a_inst; BASE_ISA *exec; BaseType int_cause; BaseType INSTR; /** * * @brief Process and triggers IRQ if all conditions met * @return true if IRQ is triggered, false otherwise */ bool cpu_process_IRQ() override; /** * @brief callback for IRQ simple socket * @param trans transaction to perform (empty) * @param delay time to annotate * * it triggers an IRQ when called */ void call_interrupt(tlm::tlm_generic_payload &trans, sc_core::sc_time &delay) override; }; // RV32 class /** * @brief RISC_V CPU 64 bits model * @param name name of the module */ class RV64 : public CPU { public: using BaseType = std::uint64_t; /** * @brief Constructor * @param name Module name * @param PC Program Counter initialize value * @param debug To start debugging */ RV64(sc_core::sc_module_name const &name, BaseType PC, bool debug); /** * @brief Destructor */ ~RV64() override; bool CPU_step() override; Registers *getRegisterBank() { return register_bank; } private: Registers *register_bank; C_extension *c_inst; M_extension *m_inst; A_extension *a_inst; BASE_ISA *exec; BaseType int_cause; BaseType INSTR; /** * * @brief Process and triggers IRQ if all conditions met * @return true if IRQ is triggered, false otherwise */ bool cpu_process_IRQ() override; /** * @brief callback for IRQ simple socket * @param trans transaction to perform (empty) * @param delay time to annotate * * it triggers an IRQ when called */ void call_interrupt(tlm::tlm_generic_payload &trans, sc_core::sc_time &delay) override; }; // RV64 class } #endif