2018-09-11 00:44:54 +08:00
|
|
|
/*!
|
2020-06-02 19:08:38 +08:00
|
|
|
\file CPU.h
|
|
|
|
\brief Main CPU class
|
|
|
|
\author Màrius Montón
|
|
|
|
\date August 2018
|
|
|
|
*/
|
|
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
|
2018-09-11 00:44:54 +08:00
|
|
|
#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"
|
2022-09-19 20:43:44 +08:00
|
|
|
#include "tlm_utils/simple_target_socket.h"
|
2018-09-11 00:44:54 +08:00
|
|
|
|
2020-06-02 19:08:38 +08:00
|
|
|
#include "BASE_ISA.h"
|
|
|
|
#include "C_extension.h"
|
|
|
|
#include "M_extension.h"
|
|
|
|
#include "A_extension.h"
|
2022-09-19 20:43:44 +08:00
|
|
|
#include "MemoryInterface.h"
|
|
|
|
#include "Performance.h"
|
|
|
|
#include "Registers.h"
|
2021-11-30 03:35:26 +08:00
|
|
|
|
|
|
|
namespace riscv_tlm {
|
2022-07-21 21:33:23 +08:00
|
|
|
|
|
|
|
class CPU : sc_core::sc_module {
|
2021-11-30 03:35:26 +08:00
|
|
|
public:
|
|
|
|
|
2022-07-21 21:33:23 +08:00
|
|
|
/* 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;
|
|
|
|
|
2021-11-30 03:35:26 +08:00
|
|
|
/**
|
|
|
|
* @brief Instruction Memory bus socket
|
|
|
|
* @param trans transction to perfoem
|
|
|
|
* @param delay time to annotate
|
|
|
|
*/
|
|
|
|
tlm_utils::simple_initiator_socket<CPU> instr_bus;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief IRQ line socket
|
|
|
|
* @param trans transction to perform (empty)
|
|
|
|
* @param delay time to annotate
|
|
|
|
*/
|
|
|
|
tlm_utils::simple_target_socket<CPU> irq_line_socket;
|
|
|
|
|
|
|
|
/**
|
2022-07-21 21:33:23 +08:00
|
|
|
* @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);
|
2021-11-30 03:35:26 +08:00
|
|
|
|
|
|
|
/**
|
2022-07-21 21:33:23 +08:00
|
|
|
* @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
|
2021-11-30 03:35:26 +08:00
|
|
|
*/
|
2022-07-21 21:33:23 +08:00
|
|
|
virtual bool cpu_process_IRQ() = 0;
|
2021-11-30 03:35:26 +08:00
|
|
|
|
2022-07-21 21:33:23 +08:00
|
|
|
/**
|
|
|
|
* @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;
|
2022-09-15 02:01:36 +08:00
|
|
|
|
|
|
|
virtual std::uint64_t getStartDumpAddress() = 0;
|
|
|
|
virtual std::uint64_t getEndDumpAddress() = 0;
|
|
|
|
|
2022-07-21 21:33:23 +08:00
|
|
|
public:
|
2021-11-30 03:35:26 +08:00
|
|
|
MemoryInterface *mem_intf;
|
2022-07-21 21:33:23 +08:00
|
|
|
protected:
|
2021-11-30 03:35:26 +08:00
|
|
|
Performance *perf;
|
|
|
|
std::shared_ptr<spdlog::logger> 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;
|
2022-07-21 21:33:23 +08:00
|
|
|
};
|
2021-11-30 03:35:26 +08:00
|
|
|
|
2022-07-21 21:33:23 +08:00
|
|
|
/**
|
|
|
|
* @brief RISC_V CPU 32 bits model
|
|
|
|
* @param name name of the module
|
|
|
|
*/
|
|
|
|
class RV32 : public CPU {
|
|
|
|
public:
|
|
|
|
using BaseType = std::uint32_t;
|
2021-11-30 03:35:26 +08:00
|
|
|
|
|
|
|
/**
|
2022-07-21 21:33:23 +08:00
|
|
|
* @brief Constructor
|
|
|
|
* @param name Module name
|
|
|
|
* @param PC Program Counter initialize value
|
|
|
|
* @param debug To start debugging
|
2021-11-30 03:35:26 +08:00
|
|
|
*/
|
2022-07-21 21:33:23 +08:00
|
|
|
RV32(sc_core::sc_module_name const &name, BaseType PC, bool debug);
|
2021-11-30 03:35:26 +08:00
|
|
|
|
|
|
|
/**
|
2022-07-21 21:33:23 +08:00
|
|
|
* @brief Destructor
|
2021-11-30 03:35:26 +08:00
|
|
|
*/
|
2022-07-21 21:33:23 +08:00
|
|
|
~RV32() override;
|
|
|
|
|
|
|
|
bool CPU_step() override;
|
|
|
|
Registers<BaseType> *getRegisterBank() { return register_bank; }
|
|
|
|
|
|
|
|
private:
|
|
|
|
Registers<BaseType> *register_bank;
|
|
|
|
C_extension<BaseType> *c_inst;
|
|
|
|
M_extension<BaseType> *m_inst;
|
|
|
|
A_extension<BaseType> *a_inst;
|
|
|
|
BASE_ISA<BaseType> *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;
|
2021-11-30 03:35:26 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @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,
|
2022-07-22 19:28:36 +08:00
|
|
|
sc_core::sc_time &delay) override;
|
2022-09-15 02:01:36 +08:00
|
|
|
|
|
|
|
std::uint64_t getStartDumpAddress() override;
|
|
|
|
std::uint64_t getEndDumpAddress() override;
|
2022-07-21 21:33:23 +08:00
|
|
|
}; // 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;
|
2021-11-30 03:35:26 +08:00
|
|
|
|
|
|
|
/**
|
2022-07-21 21:33:23 +08:00
|
|
|
* @brief Constructor
|
|
|
|
* @param name Module name
|
|
|
|
* @param PC Program Counter initialize value
|
|
|
|
* @param debug To start debugging
|
2021-11-30 03:35:26 +08:00
|
|
|
*/
|
2022-07-21 21:33:23 +08:00
|
|
|
RV64(sc_core::sc_module_name const &name, BaseType PC, bool debug);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Destructor
|
|
|
|
*/
|
|
|
|
~RV64() override;
|
|
|
|
|
|
|
|
bool CPU_step() override;
|
|
|
|
Registers<BaseType> *getRegisterBank() { return register_bank; }
|
|
|
|
|
|
|
|
private:
|
|
|
|
Registers<BaseType> *register_bank;
|
|
|
|
C_extension<BaseType> *c_inst;
|
|
|
|
M_extension<BaseType> *m_inst;
|
|
|
|
A_extension<BaseType> *a_inst;
|
|
|
|
BASE_ISA<BaseType> *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,
|
2022-07-22 19:28:36 +08:00
|
|
|
sc_core::sc_time &delay) override;
|
2022-09-15 02:01:36 +08:00
|
|
|
|
|
|
|
std::uint64_t getStartDumpAddress() override;
|
|
|
|
std::uint64_t getEndDumpAddress() override;
|
2022-07-21 21:33:23 +08:00
|
|
|
}; // RV64 class
|
2021-11-30 03:35:26 +08:00
|
|
|
|
|
|
|
}
|
2018-09-11 00:44:54 +08:00
|
|
|
#endif
|