424 lines
7.0 KiB
C
424 lines
7.0 KiB
C
|
/*!
|
||
|
\file BASE_ISA.h
|
||
|
\brief RISC-V ISA implementation
|
||
|
\author Màrius Montón
|
||
|
\date August 2018
|
||
|
*/
|
||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||
|
|
||
|
#ifndef Execute_H
|
||
|
#define Execute_H
|
||
|
|
||
|
#define SC_INCLUDE_DYNAMIC_PROCESSES
|
||
|
|
||
|
#include "systemc"
|
||
|
#include "tlm.h"
|
||
|
#include "tlm_utils/simple_initiator_socket.h"
|
||
|
|
||
|
#include "memory.h"
|
||
|
#include "MemoryInterface.h"
|
||
|
#include "Instruction.h"
|
||
|
#include "C_extension.h"
|
||
|
#include "M_extension.h"
|
||
|
#include "A_extension.h"
|
||
|
#include "Registers.h"
|
||
|
#include "Log.h"
|
||
|
|
||
|
|
||
|
typedef enum {
|
||
|
OP_LUI,
|
||
|
OP_AUIPC,
|
||
|
OP_JAL,
|
||
|
OP_JALR,
|
||
|
|
||
|
OP_BEQ,
|
||
|
OP_BNE,
|
||
|
OP_BLT,
|
||
|
OP_BGE,
|
||
|
OP_BLTU,
|
||
|
OP_BGEU,
|
||
|
|
||
|
OP_LB,
|
||
|
OP_LH,
|
||
|
OP_LW,
|
||
|
OP_LBU,
|
||
|
OP_LHU,
|
||
|
|
||
|
OP_SB,
|
||
|
OP_SH,
|
||
|
OP_SW,
|
||
|
|
||
|
OP_ADDI,
|
||
|
OP_SLTI,
|
||
|
OP_SLTIU,
|
||
|
OP_XORI,
|
||
|
OP_ORI,
|
||
|
OP_ANDI,
|
||
|
OP_SLLI,
|
||
|
OP_SRLI,
|
||
|
OP_SRAI,
|
||
|
|
||
|
OP_ADD,
|
||
|
OP_SUB,
|
||
|
OP_SLL,
|
||
|
OP_SLT,
|
||
|
OP_SLTU,
|
||
|
OP_XOR,
|
||
|
OP_SRL,
|
||
|
OP_SRA,
|
||
|
OP_OR,
|
||
|
OP_AND,
|
||
|
|
||
|
OP_FENCE,
|
||
|
OP_ECALL,
|
||
|
OP_EBREAK,
|
||
|
|
||
|
OP_CSRRW,
|
||
|
OP_CSRRS,
|
||
|
OP_CSRRC,
|
||
|
OP_CSRRWI,
|
||
|
OP_CSRRSI,
|
||
|
OP_CSRRCI,
|
||
|
|
||
|
OP_URET,
|
||
|
OP_SRET,
|
||
|
OP_MRET,
|
||
|
OP_WFI,
|
||
|
OP_SFENCE,
|
||
|
|
||
|
OP_ERROR
|
||
|
} opCodes;
|
||
|
|
||
|
/**
|
||
|
* @brief Risc_V execute module
|
||
|
*/
|
||
|
class BASE_ISA: public extension_base {
|
||
|
public:
|
||
|
|
||
|
/**
|
||
|
* @brief Constructor, same as base class
|
||
|
*/
|
||
|
using extension_base::extension_base;
|
||
|
|
||
|
/**
|
||
|
* @brief Access to rd field
|
||
|
* @return rd field
|
||
|
*/
|
||
|
inline int32_t get_rd() {
|
||
|
return m_instr.range(11, 7);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Sets rd field
|
||
|
* @param value desired rd value
|
||
|
*/
|
||
|
inline void set_rd(int32_t value) {
|
||
|
m_instr.range(11, 7) = value;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Access to rs1 field
|
||
|
* @return rs1 field
|
||
|
*/
|
||
|
inline int32_t get_rs1() {
|
||
|
return m_instr.range(19, 15);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Sets rs1 field
|
||
|
* @param value desired rs1 value
|
||
|
*/
|
||
|
inline void set_rs1(int32_t value) {
|
||
|
m_instr.range(19, 15) = value;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Access to rs2 field
|
||
|
* @return rs2 field
|
||
|
*/
|
||
|
inline int32_t get_rs2() {
|
||
|
return m_instr.range(24, 20);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Sets rs2 field
|
||
|
* @param value desired rs2 value
|
||
|
*/
|
||
|
inline void set_rs2(int32_t value) {
|
||
|
m_instr.range(24, 10) = value;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Access to funct3 field
|
||
|
* @return funct3 field
|
||
|
*/
|
||
|
inline int32_t get_funct3() {
|
||
|
return m_instr.range(14, 12);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Sets func3 field
|
||
|
* @param value desired func3 value
|
||
|
*/
|
||
|
inline void set_funct3(int32_t value) {
|
||
|
m_instr.range(14, 12) = value;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Access to funct7 field
|
||
|
* @return funct7 field
|
||
|
*/
|
||
|
inline int32_t get_funct7() {
|
||
|
return m_instr.range(31, 25);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Sets func7 field
|
||
|
* @param value desired func7 value
|
||
|
*/
|
||
|
inline void set_func7(int32_t value) {
|
||
|
m_instr.range(31, 25) = value;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Gets immediate field value for I-type
|
||
|
* @return immediate_I field
|
||
|
*/
|
||
|
inline int32_t get_imm_I() {
|
||
|
int32_t aux = 0;
|
||
|
|
||
|
aux = m_instr.range(31, 20);
|
||
|
|
||
|
/* sign extension (optimize) */
|
||
|
if (m_instr[31] == 1) {
|
||
|
aux |= (0b11111111111111111111) << 12;
|
||
|
}
|
||
|
|
||
|
return aux;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Sets immediate field for I-type
|
||
|
* @param value desired I value
|
||
|
*/
|
||
|
inline void set_imm_I(int32_t value) {
|
||
|
m_instr.range(31, 20) = value;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Gets immediate field value for S-type
|
||
|
* @return immediate_S field
|
||
|
*/
|
||
|
inline int32_t get_imm_S() {
|
||
|
int32_t aux = 0;
|
||
|
|
||
|
aux = m_instr.range(31, 25) << 5;
|
||
|
aux |= m_instr.range(11, 7);
|
||
|
|
||
|
if (m_instr[31] == 1) {
|
||
|
aux |= (0b11111111111111111111) << 12;
|
||
|
}
|
||
|
|
||
|
return aux;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Sets immediate field for S-type
|
||
|
* @param value desired S value
|
||
|
*/
|
||
|
inline void set_imm_S(int32_t value) {
|
||
|
sc_dt::sc_uint<32> aux = value;
|
||
|
|
||
|
m_instr.range(31, 25) = aux.range(11, 5);
|
||
|
m_instr.range(11, 7) = aux.range(4, 0);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Gets immediate field value for U-type
|
||
|
* @return immediate_U field
|
||
|
*/
|
||
|
inline int32_t get_imm_U() {
|
||
|
return m_instr.range(31, 12);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Sets immediate field for U-type
|
||
|
* @param value desired U value
|
||
|
*/
|
||
|
inline void set_imm_U(int32_t value) {
|
||
|
m_instr.range(31, 12) = (value << 12);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Gets immediate field value for B-type
|
||
|
* @return immediate_B field
|
||
|
*/
|
||
|
inline int32_t get_imm_B() {
|
||
|
int32_t aux = 0;
|
||
|
|
||
|
aux |= m_instr[7] << 11;
|
||
|
aux |= m_instr.range(30, 25) << 5;
|
||
|
aux |= m_instr[31] << 12;
|
||
|
aux |= m_instr.range(11, 8) << 1;
|
||
|
|
||
|
if (m_instr[31] == 1) {
|
||
|
aux |= (0b11111111111111111111) << 12;
|
||
|
}
|
||
|
|
||
|
return aux;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Sets immediate field for B-type
|
||
|
* @param value desired B value
|
||
|
*/
|
||
|
inline void set_imm_B(int32_t value) {
|
||
|
sc_dt::sc_uint<32> aux = value;
|
||
|
|
||
|
m_instr[31] = aux[12];
|
||
|
m_instr.range(30, 25) = aux.range(10, 5);
|
||
|
m_instr.range(11, 7) = aux.range(4, 1);
|
||
|
m_instr[6] = aux[11];
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Gets immediate field value for J-type
|
||
|
* @return immediate_J field
|
||
|
*/
|
||
|
inline int32_t get_imm_J() {
|
||
|
int32_t aux = 0;
|
||
|
|
||
|
aux = m_instr[31] << 20;
|
||
|
aux |= m_instr.range(19, 12) << 12;
|
||
|
aux |= m_instr[20] << 11;
|
||
|
aux |= m_instr.range(30, 21) << 1;
|
||
|
|
||
|
/* bit extension (better way to do that?) */
|
||
|
if (m_instr[31] == 1) {
|
||
|
aux |= (0b111111111111) << 20;
|
||
|
}
|
||
|
|
||
|
return aux;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Sets immediate field for J-type
|
||
|
* @param value desired J value
|
||
|
*/
|
||
|
inline void set_imm_J(int32_t value) {
|
||
|
sc_dt::sc_uint<32> aux = (value << 20);
|
||
|
|
||
|
m_instr[31] = aux[20];
|
||
|
m_instr.range(30, 21) = aux.range(10, 1);
|
||
|
m_instr[20] = aux[11];
|
||
|
m_instr.range(19, 12) = aux.range(19, 12);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Returns shamt field for Shifts instructions
|
||
|
* @return value corresponding to inst(25:20)
|
||
|
*/
|
||
|
inline int32_t get_shamt() {
|
||
|
return m_instr.range(25, 20);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Returns CSR field for CSR instructions
|
||
|
* @return value corresponding to instr(31:20)
|
||
|
*/
|
||
|
inline int32_t get_csr() {
|
||
|
int32_t aux = 0;
|
||
|
|
||
|
aux = m_instr.range(31, 20);
|
||
|
|
||
|
return aux;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Access to opcode field
|
||
|
* @return return opcode field
|
||
|
*/
|
||
|
inline int32_t opcode() {
|
||
|
return m_instr.range(6, 0);
|
||
|
}
|
||
|
|
||
|
bool Exec_LUI();
|
||
|
bool Exec_AUIPC();
|
||
|
|
||
|
bool Exec_JAL();
|
||
|
bool Exec_JALR();
|
||
|
|
||
|
bool Exec_BEQ();
|
||
|
bool Exec_BNE();
|
||
|
bool Exec_BLT();
|
||
|
bool Exec_BGE();
|
||
|
bool Exec_BLTU();
|
||
|
bool Exec_BGEU();
|
||
|
|
||
|
bool Exec_LB();
|
||
|
bool Exec_LH();
|
||
|
bool Exec_LW();
|
||
|
bool Exec_LBU();
|
||
|
bool Exec_LHU();
|
||
|
|
||
|
bool Exec_SB();
|
||
|
bool Exec_SH();
|
||
|
bool Exec_SW();
|
||
|
bool Exec_SBU();
|
||
|
bool Exec_SHU();
|
||
|
|
||
|
bool Exec_ADDI();
|
||
|
bool Exec_SLTI();
|
||
|
bool Exec_SLTIU();
|
||
|
bool Exec_XORI();
|
||
|
bool Exec_ORI();
|
||
|
bool Exec_ANDI();
|
||
|
bool Exec_SLLI();
|
||
|
bool Exec_SRLI();
|
||
|
bool Exec_SRAI();
|
||
|
|
||
|
bool Exec_ADD();
|
||
|
bool Exec_SUB();
|
||
|
bool Exec_SLL();
|
||
|
bool Exec_SLT();
|
||
|
bool Exec_SLTU();
|
||
|
|
||
|
bool Exec_XOR();
|
||
|
bool Exec_SRL();
|
||
|
bool Exec_SRA();
|
||
|
bool Exec_OR();
|
||
|
bool Exec_AND();
|
||
|
|
||
|
bool Exec_FENCE();
|
||
|
bool Exec_ECALL();
|
||
|
bool Exec_EBREAK();
|
||
|
|
||
|
bool Exec_CSRRW();
|
||
|
bool Exec_CSRRS();
|
||
|
bool Exec_CSRRC();
|
||
|
bool Exec_CSRRWI();
|
||
|
bool Exec_CSRRSI();
|
||
|
bool Exec_CSRRCI();
|
||
|
|
||
|
/*********************** Privileged Instructions ******************************/
|
||
|
bool Exec_MRET();
|
||
|
bool Exec_SRET();
|
||
|
bool Exec_WFI();
|
||
|
bool Exec_SFENCE();
|
||
|
|
||
|
/**
|
||
|
* @brief Executes default ISA instruction
|
||
|
* @param inst instruction to execute
|
||
|
* @return true if PC is affected by instruction
|
||
|
*/
|
||
|
bool process_instruction(Instruction &inst);
|
||
|
|
||
|
/**
|
||
|
* @brief Decodes opcode of instruction
|
||
|
* @return opcode of instruction
|
||
|
*/
|
||
|
opCodes decode();
|
||
|
};
|
||
|
|
||
|
#endif
|