Major refactoring!
* A_Instruction, C_Instruction and M_Instruction renamed to *_extension * These files decode and executes extensions * These classes use a new base clase extension_base * Execute & Instruction classes heavyly modified: * Execute now is BASE_ISA and decodes and executes base ISA, Zicsr & Zifencei * Instruction keeps the instruction being executed, nothing else * Add memory interface to ISS to clear the code and the structure * Removed "using namespace " directives, all classes are called using their namespace * Added proper header to each file * Added license to all files
This commit is contained in:
parent
9a46e9d0a5
commit
5ee634e4b4
19
README.md
19
README.md
|
@ -45,14 +45,11 @@ Brief description of the modules:
|
|||
* CPU: Top entity that includes all other modules.
|
||||
* Memory: Memory highly based on TLM-2 example with read file capability
|
||||
* Registers: Implements the register file, PC register & CSR registers
|
||||
* Execute: Executes ISA instructions
|
||||
* Executes C instruction extensions
|
||||
* Executes M instruction extensions
|
||||
* Executes A instruction extensions
|
||||
* Instruction: Decodes instruction and acces to any instruction field
|
||||
* C_Instruction: Decodes Compressed instructions (C extension)
|
||||
* M_Instruction: Decodes Multiplication and Division instructions (M extension)
|
||||
* A_Instruction: Decodes Atomic instructions (A extension)
|
||||
* Instruction: Decodes instruction type and keeps instruction field
|
||||
* BASE_ISA: Executes Base ISA, Zifencei and Zicsr.
|
||||
* C_extension: Decodes & Executes Compressed instructions (C extension)
|
||||
* M_extension: Decodes & Executes Multiplication and Division instructions (M extension)
|
||||
* A_extension: Decodes & Executes Atomic instructions (A extension)
|
||||
* Simulator: Top-level entity that builds & starts the simulation
|
||||
* BusCtrl: Simple bus manager
|
||||
* Trace: Simple trace peripheral
|
||||
|
@ -100,7 +97,7 @@ Task to do:
|
|||
- [ ] generic IRQ comtroller
|
||||
- [x] Test, test, test & test. I'm sure there are a ~~lot of~~ some bugs in the code
|
||||
- [x] riscv-test almost complete (see [Test](https://github.com/mariusmm/RISC-V-TLM/wiki/Tests))
|
||||
- [ ] riscv-compliance WiP
|
||||
- [x] riscv-compliance
|
||||
* Improve structure and modules hierarchy
|
||||
* Add 64 & 128 bits architecture (RV64I, RV128I)
|
||||
|
||||
|
@ -129,7 +126,7 @@ $ ./RISCV_TLM asm/BasicLoop.hex
|
|||
-f filename .hex filename to use
|
||||
|
||||
## Cross-compiler
|
||||
It is possible to use gcc for risc-v compiler. Follow the instructions (from https://github.com/riscv/riscv-gnu-toolchain):
|
||||
It is possible to use gcc as risc-v compiler. Follow the instructions (from https://github.com/riscv/riscv-gnu-toolchain):
|
||||
~~~
|
||||
$ git clone --recursive https://github.com/riscv/riscv-gnu-toolchain
|
||||
$ cd riscv-gnu-toolchain
|
||||
|
@ -240,7 +237,7 @@ If you find this code useful, please consider citing:
|
|||
```
|
||||
@inproceedings{montonriscvtlm2020,
|
||||
title = {A {RISC}-{V} {SystemC}-{TLM} simulator},
|
||||
booktitle = {Workshop on {Computer} {Architecture} {Research} with {RISC}-{V}},
|
||||
booktitle = {Workshop on {Computer} {Architecture} {Research} with {RISC}-{V} ({CARRV 2020}),
|
||||
author = {Montón, Màrius},
|
||||
year = {2020}
|
||||
}
|
||||
|
|
|
@ -1,136 +0,0 @@
|
|||
/*!
|
||||
\file A_Instruction.h
|
||||
\brief Decode A extensions part of the RISC-V
|
||||
\author Màrius Montón
|
||||
\date December 2018
|
||||
*/
|
||||
|
||||
#ifndef A_INSTRUCTION__H
|
||||
#define A_INSTRUCTION__H
|
||||
|
||||
#include "systemc"
|
||||
|
||||
using namespace sc_core;
|
||||
using namespace sc_dt;
|
||||
using namespace std;
|
||||
|
||||
typedef enum {
|
||||
OP_A_LR,
|
||||
OP_A_SC,
|
||||
OP_A_AMOSWAP,
|
||||
OP_A_AMOADD,
|
||||
OP_A_AMOXOR,
|
||||
OP_A_AMOAND,
|
||||
OP_A_AMOOR,
|
||||
OP_A_AMOMIN,
|
||||
OP_A_AMOMAX,
|
||||
OP_A_AMOMINU,
|
||||
OP_A_AMOMAXU,
|
||||
|
||||
OP_A_ERROR
|
||||
} op_A_Codes;
|
||||
|
||||
|
||||
typedef enum {
|
||||
A_LR = 0b00010,
|
||||
A_SC = 0b00011,
|
||||
A_AMOSWAP = 0b00001,
|
||||
A_AMOADD = 0b00000,
|
||||
A_AMOXOR = 0b00100,
|
||||
A_AMOAND = 0b01100,
|
||||
A_AMOOR = 0b01000,
|
||||
A_AMOMIN = 0b10000,
|
||||
A_AMOMAX = 0b10100,
|
||||
A_AMOMINU = 0b11000,
|
||||
A_AMOMAXU = 0b11100,
|
||||
} A_Codes;
|
||||
|
||||
/**
|
||||
* @brief Instruction decoding and fields access
|
||||
*/
|
||||
class A_Instruction{
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Constructor
|
||||
* @param instr Instruction to decode
|
||||
*/
|
||||
A_Instruction(sc_uint<32> instr);
|
||||
|
||||
/**
|
||||
* @brief Sets instruction
|
||||
* @param p_instr instruction to decode
|
||||
*/
|
||||
void setInstr(uint32_t p_instr) {
|
||||
a_instr = sc_uint<32> (p_instr);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Access to opcode field
|
||||
* @return return opcode field
|
||||
*/
|
||||
inline int32_t opcode() {
|
||||
return a_instr.range(31,27);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Access to rd field
|
||||
* @return rd field
|
||||
*/
|
||||
inline int32_t get_rd() {
|
||||
return a_instr.range(11, 7);
|
||||
}
|
||||
|
||||
inline void set_rd(int32_t value) {
|
||||
a_instr.range(11,7) = value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Access to rs1 field
|
||||
* @return rs1 field
|
||||
*/
|
||||
inline int32_t get_rs1() {
|
||||
return a_instr.range(19, 15);
|
||||
}
|
||||
|
||||
inline void set_rs1(int32_t value) {
|
||||
a_instr.range(19,15) = value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Access to rs2 field
|
||||
* @return rs2 field
|
||||
*/
|
||||
inline int32_t get_rs2() {
|
||||
return a_instr.range(24, 20);
|
||||
}
|
||||
|
||||
inline void set_rs2(int32_t value) {
|
||||
a_instr.range(24,20) = value;
|
||||
}
|
||||
|
||||
|
||||
inline int32_t get_funct3() {
|
||||
return a_instr.range(14, 12);
|
||||
}
|
||||
|
||||
inline void set_funct3(int32_t value) {
|
||||
a_instr.range(14,12) = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Decodes opcode of instruction
|
||||
* @return opcode of instruction
|
||||
*/
|
||||
op_A_Codes decode();
|
||||
|
||||
inline void dump() {
|
||||
cout << hex << "0x" << a_instr << dec << endl;
|
||||
}
|
||||
private:
|
||||
sc_uint<32> a_instr;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,145 @@
|
|||
/*!
|
||||
\file A_extension.h
|
||||
\brief Implement A extensions part of the RISC-V
|
||||
\author Màrius Montón
|
||||
\date December 2018
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#ifndef A_EXTENSION__H
|
||||
#define A_EXTENSION__H
|
||||
|
||||
#include "systemc"
|
||||
|
||||
#include <set>
|
||||
|
||||
#include "Log.h"
|
||||
#include "Registers.h"
|
||||
#include "MemoryInterface.h"
|
||||
#include "extension_base.h"
|
||||
|
||||
typedef enum {
|
||||
OP_A_LR,
|
||||
OP_A_SC,
|
||||
OP_A_AMOSWAP,
|
||||
OP_A_AMOADD,
|
||||
OP_A_AMOXOR,
|
||||
OP_A_AMOAND,
|
||||
OP_A_AMOOR,
|
||||
OP_A_AMOMIN,
|
||||
OP_A_AMOMAX,
|
||||
OP_A_AMOMINU,
|
||||
OP_A_AMOMAXU,
|
||||
|
||||
OP_A_ERROR
|
||||
} op_A_Codes;
|
||||
|
||||
typedef enum {
|
||||
A_LR = 0b00010,
|
||||
A_SC = 0b00011,
|
||||
A_AMOSWAP = 0b00001,
|
||||
A_AMOADD = 0b00000,
|
||||
A_AMOXOR = 0b00100,
|
||||
A_AMOAND = 0b01100,
|
||||
A_AMOOR = 0b01000,
|
||||
A_AMOMIN = 0b10000,
|
||||
A_AMOMAX = 0b10100,
|
||||
A_AMOMINU = 0b11000,
|
||||
A_AMOMAXU = 0b11100,
|
||||
} A_Codes;
|
||||
|
||||
/**
|
||||
* @brief Instruction decoding and fields access
|
||||
*/
|
||||
class A_extension: public extension_base {
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Constructor, same as base class
|
||||
*/
|
||||
using extension_base::extension_base;
|
||||
|
||||
/**
|
||||
* @brief Access to opcode field
|
||||
* @return return opcode field
|
||||
*/
|
||||
inline int32_t opcode() {
|
||||
return m_instr.range(31, 27);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Access to rd field
|
||||
* @return rd field
|
||||
*/
|
||||
inline int32_t get_rd() {
|
||||
return m_instr.range(11, 7);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
inline void set_rs2(int32_t value) {
|
||||
m_instr.range(24, 20) = value;
|
||||
}
|
||||
|
||||
inline int32_t get_funct3() {
|
||||
return m_instr.range(14, 12);
|
||||
}
|
||||
|
||||
inline void set_funct3(int32_t value) {
|
||||
m_instr.range(14, 12) = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Decodes opcode of instruction
|
||||
* @return opcode of instruction
|
||||
*/
|
||||
op_A_Codes decode();
|
||||
|
||||
inline void dump() {
|
||||
std::cout << std::hex << "0x" << m_instr << std::dec << std::endl;
|
||||
}
|
||||
|
||||
bool Exec_A_LR();
|
||||
bool Exec_A_SC();
|
||||
bool Exec_A_AMOSWAP();
|
||||
bool Exec_A_AMOADD();
|
||||
bool Exec_A_AMOXOR();
|
||||
bool Exec_A_AMOAND();
|
||||
bool Exec_A_AMOOR();
|
||||
bool Exec_A_AMOMIN();
|
||||
bool Exec_A_AMOMAX();
|
||||
bool Exec_A_AMOMINU();
|
||||
bool Exec_A_AMOMAXU();
|
||||
|
||||
bool process_instruction(Instruction &inst);
|
||||
|
||||
void TLB_reserve(uint32_t address);
|
||||
bool TLB_reserved(uint32_t address);
|
||||
|
||||
private:
|
||||
std::set<uint32_t> TLB_A_Entries;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,423 @@
|
|||
/*!
|
||||
\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
|
|
@ -4,6 +4,7 @@
|
|||
@author Màrius Montón
|
||||
@date September 2018
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#ifndef __BUSCTRL_H__
|
||||
#define __BUSCTRL_H__
|
||||
|
@ -21,10 +22,6 @@
|
|||
|
||||
#include "Log.h"
|
||||
|
||||
using namespace sc_core;
|
||||
using namespace sc_dt;
|
||||
using namespace std;
|
||||
|
||||
/**
|
||||
* Memory mapped Trace peripheral address
|
||||
*/
|
||||
|
@ -44,7 +41,7 @@ using namespace std;
|
|||
* It will be expanded with more ports when required (for DMA,
|
||||
* other peripherals, etc.)
|
||||
*/
|
||||
class BusCtrl: sc_module {
|
||||
class BusCtrl: sc_core::sc_module {
|
||||
public:
|
||||
/**
|
||||
* @brief TLM target socket CPU instruction memory bus
|
||||
|
@ -75,19 +72,21 @@ public:
|
|||
* @brief constructor
|
||||
* @param name module's name
|
||||
*/
|
||||
BusCtrl(sc_module_name name);
|
||||
BusCtrl(sc_core::sc_module_name name);
|
||||
|
||||
/**
|
||||
* @brief TLM-2 blocking mechanism
|
||||
* @param trans transtractino to perform
|
||||
* @param delay delay associated to this transaction
|
||||
*/
|
||||
virtual void b_transport( tlm::tlm_generic_payload& trans, sc_time& delay );
|
||||
virtual void b_transport(tlm::tlm_generic_payload &trans,
|
||||
sc_core::sc_time &delay);
|
||||
|
||||
private:
|
||||
Log *log;
|
||||
|
||||
bool instr_direct_mem_ptr(tlm::tlm_generic_payload&, tlm::tlm_dmi& dmi_data);
|
||||
bool instr_direct_mem_ptr(tlm::tlm_generic_payload&,
|
||||
tlm::tlm_dmi &dmi_data);
|
||||
void invalidate_direct_mem_ptr(sc_dt::uint64 start, sc_dt::uint64 end);
|
||||
};
|
||||
|
||||
|
|
55
inc/CPU.h
55
inc/CPU.h
|
@ -4,6 +4,8 @@
|
|||
\author Màrius Montón
|
||||
\date August 2018
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#ifndef CPU_BASE_H
|
||||
#define CPU_BASE_H
|
||||
|
||||
|
@ -16,23 +18,20 @@
|
|||
#include "tlm_utils/tlm_quantumkeeper.h"
|
||||
|
||||
#include "memory.h"
|
||||
#include "Execute.h"
|
||||
#include "MemoryInterface.h"
|
||||
#include "BASE_ISA.h"
|
||||
#include "Registers.h"
|
||||
#include "Log.h"
|
||||
#include "Instruction.h"
|
||||
#include "C_Instruction.h"
|
||||
#include "M_Instruction.h"
|
||||
#include "A_Instruction.h"
|
||||
|
||||
using namespace sc_core;
|
||||
using namespace sc_dt;
|
||||
using namespace std;
|
||||
#include "C_extension.h"
|
||||
#include "M_extension.h"
|
||||
#include "A_extension.h"
|
||||
|
||||
/**
|
||||
* @brief ISC_V CPU model
|
||||
* @param name name of the module
|
||||
*/
|
||||
class CPU: sc_module {
|
||||
class CPU: sc_core::sc_module {
|
||||
public:
|
||||
|
||||
/**
|
||||
|
@ -54,32 +53,31 @@ public:
|
|||
* @param name Module name
|
||||
* @param PC Program Counter initialize value
|
||||
*/
|
||||
CPU(sc_module_name name, uint32_t PC);
|
||||
CPU(sc_core::sc_module_name name, uint32_t PC);
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
~CPU();
|
||||
|
||||
Execute *exec;
|
||||
MemoryInterface *mem_intf;
|
||||
|
||||
private:
|
||||
Registers *register_bank;
|
||||
Performance *perf;
|
||||
Log *log;
|
||||
Instruction *inst;
|
||||
C_Instruction *c_inst;
|
||||
M_Instruction *m_inst;
|
||||
A_Instruction *a_inst;
|
||||
C_extension *c_inst;
|
||||
M_extension *m_inst;
|
||||
A_extension *a_inst;
|
||||
BASE_ISA *exec;
|
||||
|
||||
tlm_utils::tlm_quantumkeeper *m_qk;
|
||||
|
||||
bool interrupt;
|
||||
uint32_t int_cause;
|
||||
bool irq_already_down;
|
||||
|
||||
sc_time default_time;
|
||||
|
||||
sc_core::sc_time default_time;
|
||||
bool dmi_ptr_valid;
|
||||
|
||||
/**
|
||||
|
@ -90,18 +88,9 @@ private:
|
|||
bool cpu_process_IRQ();
|
||||
|
||||
/**
|
||||
* @brief Executes default ISA instruction
|
||||
* @param inst instruction to execute
|
||||
* @return true if PC is affected by instruction
|
||||
* main thread for CPU simulation
|
||||
* @brief CPU mai thread
|
||||
*/
|
||||
bool process_base_instruction(Instruction &inst);
|
||||
|
||||
bool process_c_instruction(Instruction &inst);
|
||||
|
||||
bool process_m_instruction(Instruction &inst);
|
||||
|
||||
bool process_a_instruction(Instruction inst);
|
||||
|
||||
void CPU_thread(void);
|
||||
|
||||
/**
|
||||
|
@ -109,10 +98,16 @@ private:
|
|||
* @param trans transaction to perform (empty)
|
||||
* @param delay time to annotate
|
||||
*
|
||||
* When called it triggers an IRQ
|
||||
* it triggers an IRQ when called
|
||||
*/
|
||||
void call_interrupt(tlm::tlm_generic_payload &trans, sc_time &delay);
|
||||
void call_interrupt(tlm::tlm_generic_payload &trans,
|
||||
sc_core::sc_time &delay);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
};
|
||||
|
||||
|
|
|
@ -1,413 +0,0 @@
|
|||
/*!
|
||||
\file C_Instruction.h
|
||||
\brief Decode C extensions part of the RISC-V
|
||||
\author Màrius Montón
|
||||
\date August 2018
|
||||
*/
|
||||
|
||||
#ifndef C_INSTRUCTION__H
|
||||
#define C_INSTRUCTION__H
|
||||
|
||||
#include "systemc"
|
||||
|
||||
using namespace sc_core;
|
||||
using namespace sc_dt;
|
||||
using namespace std;
|
||||
|
||||
typedef enum {
|
||||
OP_C_ADDI4SPN,
|
||||
OP_C_FLD,
|
||||
OP_C_LW,
|
||||
OP_C_FLW,
|
||||
OP_C_FSD,
|
||||
OP_C_SW,
|
||||
OP_C_FSW,
|
||||
|
||||
OP_C_NOP,
|
||||
OP_C_ADDI,
|
||||
OP_C_JAL,
|
||||
OP_C_LI,
|
||||
OP_C_ADDI16SP,
|
||||
OP_C_LUI,
|
||||
OP_C_SRLI,
|
||||
OP_C_SRAI,
|
||||
OP_C_ANDI,
|
||||
OP_C_SUB,
|
||||
OP_C_XOR,
|
||||
OP_C_OR,
|
||||
OP_C_AND,
|
||||
OP_C_J,
|
||||
OP_C_BEQZ,
|
||||
OP_C_BNEZ,
|
||||
|
||||
OP_C_SLLI,
|
||||
OP_C_FLDSP,
|
||||
OP_C_LWSP,
|
||||
OP_C_FLWSP,
|
||||
OP_C_JR,
|
||||
OP_C_MV,
|
||||
OP_C_EBREAK,
|
||||
OP_C_JALR,
|
||||
OP_C_ADD,
|
||||
OP_C_FSDSP,
|
||||
OP_C_SWSP,
|
||||
OP_C_FSWSP,
|
||||
|
||||
OP_C_ERROR
|
||||
} op_C_Codes;
|
||||
|
||||
|
||||
typedef enum {
|
||||
C_ADDI4SPN = 0b000,
|
||||
C_FLD = 0b001,
|
||||
C_LW = 0b010,
|
||||
C_FLW = 0b011,
|
||||
C_FSD = 0b101,
|
||||
C_SW = 0b110,
|
||||
C_FSW = 0b111,
|
||||
|
||||
C_ADDI = 0b000,
|
||||
C_JAL = 0b001,
|
||||
C_LI = 0b010,
|
||||
C_ADDI16SP = 0b011,
|
||||
C_SRLI = 0b100,
|
||||
C_2_SRLI = 0b00,
|
||||
C_2_SRAI = 0b01,
|
||||
C_2_ANDI = 0b10,
|
||||
C_2_SUB = 0b11,
|
||||
C_3_SUB = 0b00,
|
||||
C_3_XOR = 0b01,
|
||||
C_3_OR = 0b10,
|
||||
C_3_AND = 0b11,
|
||||
C_J = 0b101,
|
||||
C_BEQZ = 0b110,
|
||||
C_BNEZ = 0b111,
|
||||
|
||||
C_SLLI = 0b000,
|
||||
C_FLDSP = 0b001,
|
||||
C_LWSP = 0b010,
|
||||
C_FLWSP = 0b011,
|
||||
C_JR = 0b100,
|
||||
C_FDSP = 0b101,
|
||||
C_SWSP = 0b110,
|
||||
C_FWWSP = 0b111,
|
||||
} C_Codes;
|
||||
|
||||
/**
|
||||
* @brief Instruction decoding and fields access
|
||||
*/
|
||||
class C_Instruction{
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Constructor
|
||||
* @param instr Instruction to decode
|
||||
*/
|
||||
C_Instruction(sc_uint<32> instr);
|
||||
|
||||
/**
|
||||
* @brief Sets instruction
|
||||
* @param p_instr instruction to decode
|
||||
*/
|
||||
void setInstr(uint32_t p_instr) {
|
||||
m_instr = sc_uint<32> (p_instr);
|
||||
}
|
||||
/**
|
||||
* @brief Access to opcode field
|
||||
* @return return opcode field
|
||||
*/
|
||||
inline int32_t opcode() {
|
||||
return m_instr.range(1,0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Access to rd field
|
||||
* @return rd field
|
||||
*/
|
||||
inline int32_t get_rd() {
|
||||
return m_instr.range(11, 7);
|
||||
}
|
||||
|
||||
inline void set_rd(int32_t value) {
|
||||
m_instr.range(11,7) = value;
|
||||
}
|
||||
|
||||
inline int32_t get_rdp() {
|
||||
return m_instr.range(4, 2) + 8;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Access to rs1 field
|
||||
* @return rs1 field
|
||||
*/
|
||||
inline int32_t get_rs1() {
|
||||
return m_instr.range(11, 7);
|
||||
}
|
||||
|
||||
inline void set_rs1(int32_t value) {
|
||||
m_instr.range(11,7) = value;
|
||||
}
|
||||
|
||||
|
||||
inline int32_t get_rs1p() {
|
||||
return m_instr.range(9, 7) + 8;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Access to rs2 field
|
||||
* @return rs2 field
|
||||
*/
|
||||
inline int32_t get_rs2() {
|
||||
return m_instr.range(6, 2);
|
||||
}
|
||||
|
||||
inline void set_rs2(int32_t value) {
|
||||
m_instr.range(6,2) = value;
|
||||
}
|
||||
|
||||
inline int32_t get_rs2p() {
|
||||
return m_instr.range(4, 2) + 8;
|
||||
}
|
||||
|
||||
inline int32_t get_funct3() {
|
||||
return m_instr.range(15, 13);
|
||||
}
|
||||
|
||||
inline void set_funct3(int32_t value) {
|
||||
m_instr.range(15,13) = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Access to immediate field 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;
|
||||
}
|
||||
|
||||
inline void set_imm_I(int32_t value) {
|
||||
m_instr.range(31,20) = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Access to immediate field 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;
|
||||
}
|
||||
|
||||
inline void set_imm_S(int32_t value) {
|
||||
sc_uint<32> aux = value;
|
||||
|
||||
m_instr.range(31,25) = aux.range(11,5);
|
||||
m_instr.range(11,7) = aux.range(4,0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Access to immediate field for U-type
|
||||
* @return immediate_U field
|
||||
*/
|
||||
inline int32_t get_imm_U() {
|
||||
return m_instr.range(31, 12);
|
||||
}
|
||||
|
||||
inline void set_imm_U(int32_t value) {
|
||||
m_instr.range(31,12) = (value << 12);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Access to immediate field 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;
|
||||
}
|
||||
|
||||
inline void set_imm_B(int32_t value) {
|
||||
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 Access to immediate field for J-type
|
||||
* @return immediate_J field
|
||||
*/
|
||||
inline int32_t get_imm_J() {
|
||||
int32_t aux = 0;
|
||||
|
||||
aux = m_instr[12] << 11;
|
||||
aux |= m_instr[11] << 4;
|
||||
aux |= m_instr[10] << 9;
|
||||
aux |= m_instr[9] << 8;
|
||||
aux |= m_instr[8] << 10;
|
||||
aux |= m_instr[7] << 6;
|
||||
aux |= m_instr[6] << 7;
|
||||
aux |= m_instr.range(5,3) << 1;
|
||||
aux |= m_instr[2] << 5;
|
||||
|
||||
if (m_instr[12] == 1) {
|
||||
aux |= 0b11111111111111111111 << 12;
|
||||
}
|
||||
|
||||
return aux;
|
||||
}
|
||||
|
||||
inline void set_imm_J(int32_t value) {
|
||||
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);
|
||||
}
|
||||
|
||||
inline int32_t get_imm_L() {
|
||||
int32_t aux = 0;
|
||||
|
||||
aux = m_instr.range(12,10) << 3;
|
||||
aux |= m_instr[6] << 2;
|
||||
aux |= m_instr[5] << 6;
|
||||
|
||||
return aux;
|
||||
}
|
||||
|
||||
inline int32_t get_imm_LWSP() {
|
||||
int32_t aux = 0;
|
||||
|
||||
aux = m_instr[12] << 5;
|
||||
aux |= m_instr.range(6,4) << 2;
|
||||
aux |= m_instr.range(3,2) << 6;
|
||||
|
||||
return aux;
|
||||
}
|
||||
|
||||
inline int32_t get_imm_ADDI() {
|
||||
int32_t aux = 0;
|
||||
|
||||
aux = m_instr[12] << 5;
|
||||
aux |= m_instr.range(6,2);
|
||||
|
||||
if (m_instr[12] == 1) {
|
||||
aux |= 0b11111111111111111111111111 << 6;
|
||||
}
|
||||
return aux;
|
||||
}
|
||||
|
||||
inline int32_t get_imm_ADDI4SPN() {
|
||||
int32_t aux = 0;
|
||||
|
||||
aux = m_instr.range(12,11) << 4;
|
||||
aux |= m_instr.range(10,7) << 6;
|
||||
aux |= m_instr[6] << 2;
|
||||
aux |= m_instr[5] << 3;
|
||||
|
||||
return aux;
|
||||
}
|
||||
|
||||
inline int32_t get_imm_ADDI16SP() {
|
||||
int32_t aux = 0;
|
||||
|
||||
aux = m_instr[12] << 9;
|
||||
aux |= m_instr[6] << 4;
|
||||
aux |= m_instr[5] << 6;
|
||||
aux |= m_instr[4] << 8;
|
||||
aux |= m_instr[3] << 7;
|
||||
aux |= m_instr[2] << 5;
|
||||
|
||||
if (m_instr[12] == 1) {
|
||||
aux |= 0b1111111111111111111111 << 10;
|
||||
}
|
||||
return aux;
|
||||
}
|
||||
|
||||
inline int32_t get_imm_CSS() {
|
||||
int32_t aux = 0;
|
||||
aux = m_instr.range(12,9) << 2;
|
||||
aux |= m_instr.range(8,7) << 6;
|
||||
|
||||
return aux;
|
||||
}
|
||||
|
||||
inline int32_t get_imm_CB() {
|
||||
int32_t aux = 0;
|
||||
|
||||
aux = m_instr[12] << 8;
|
||||
aux |= m_instr[11] << 4;
|
||||
aux |= m_instr[10] << 3;
|
||||
aux |= m_instr[6] << 7;
|
||||
aux |= m_instr[5] << 6;
|
||||
aux |= m_instr[4] << 2;
|
||||
aux |= m_instr[3] << 1;
|
||||
aux |= m_instr[2] << 5;
|
||||
|
||||
if (m_instr[12] == 1) {
|
||||
aux |= 0b11111111111111111111111 << 9;
|
||||
}
|
||||
|
||||
return aux;
|
||||
}
|
||||
|
||||
inline int32_t get_imm_LUI() {
|
||||
int32_t aux = 0;
|
||||
|
||||
aux = m_instr[12] << 17;
|
||||
aux |= m_instr.range(6,2) << 12;
|
||||
|
||||
if (m_instr[12] == 1) {
|
||||
aux |= 0b111111111111111 << 17;
|
||||
}
|
||||
|
||||
return aux;
|
||||
}
|
||||
|
||||
inline int32_t get_csr() {
|
||||
return get_imm_I();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Decodes opcode of instruction
|
||||
* @return opcode of instruction
|
||||
*/
|
||||
op_C_Codes decode();
|
||||
|
||||
inline void dump() {
|
||||
cout << hex << "0x" << m_instr << dec << endl;
|
||||
}
|
||||
private:
|
||||
sc_uint<32> m_instr;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,422 @@
|
|||
/*!
|
||||
\file C_extension.h
|
||||
\brief Implement C extensions part of the RISC-V
|
||||
\author Màrius Montón
|
||||
\date August 2018
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#ifndef C_EXTENSION__H
|
||||
#define C_EXTENSION__H
|
||||
|
||||
#include "systemc"
|
||||
#include "extension_base.h"
|
||||
|
||||
typedef enum {
|
||||
OP_C_ADDI4SPN,
|
||||
OP_C_FLD,
|
||||
OP_C_LW,
|
||||
OP_C_FLW,
|
||||
OP_C_FSD,
|
||||
OP_C_SW,
|
||||
OP_C_FSW,
|
||||
|
||||
OP_C_NOP,
|
||||
OP_C_ADDI,
|
||||
OP_C_JAL,
|
||||
OP_C_LI,
|
||||
OP_C_ADDI16SP,
|
||||
OP_C_LUI,
|
||||
OP_C_SRLI,
|
||||
OP_C_SRAI,
|
||||
OP_C_ANDI,
|
||||
OP_C_SUB,
|
||||
OP_C_XOR,
|
||||
OP_C_OR,
|
||||
OP_C_AND,
|
||||
OP_C_J,
|
||||
OP_C_BEQZ,
|
||||
OP_C_BNEZ,
|
||||
|
||||
OP_C_SLLI,
|
||||
OP_C_FLDSP,
|
||||
OP_C_LWSP,
|
||||
OP_C_FLWSP,
|
||||
OP_C_JR,
|
||||
OP_C_MV,
|
||||
OP_C_EBREAK,
|
||||
OP_C_JALR,
|
||||
OP_C_ADD,
|
||||
OP_C_FSDSP,
|
||||
OP_C_SWSP,
|
||||
OP_C_FSWSP,
|
||||
|
||||
OP_C_ERROR
|
||||
} op_C_Codes;
|
||||
|
||||
typedef enum {
|
||||
C_ADDI4SPN = 0b000,
|
||||
C_FLD = 0b001,
|
||||
C_LW = 0b010,
|
||||
C_FLW = 0b011,
|
||||
C_FSD = 0b101,
|
||||
C_SW = 0b110,
|
||||
C_FSW = 0b111,
|
||||
|
||||
C_ADDI = 0b000,
|
||||
C_JAL = 0b001,
|
||||
C_LI = 0b010,
|
||||
C_ADDI16SP = 0b011,
|
||||
C_SRLI = 0b100,
|
||||
C_2_SRLI = 0b00,
|
||||
C_2_SRAI = 0b01,
|
||||
C_2_ANDI = 0b10,
|
||||
C_2_SUB = 0b11,
|
||||
C_3_SUB = 0b00,
|
||||
C_3_XOR = 0b01,
|
||||
C_3_OR = 0b10,
|
||||
C_3_AND = 0b11,
|
||||
C_J = 0b101,
|
||||
C_BEQZ = 0b110,
|
||||
C_BNEZ = 0b111,
|
||||
|
||||
C_SLLI = 0b000,
|
||||
C_FLDSP = 0b001,
|
||||
C_LWSP = 0b010,
|
||||
C_FLWSP = 0b011,
|
||||
C_JR = 0b100,
|
||||
C_FDSP = 0b101,
|
||||
C_SWSP = 0b110,
|
||||
C_FWWSP = 0b111,
|
||||
} C_Codes;
|
||||
|
||||
/**
|
||||
* @brief Instruction decoding and fields access
|
||||
*/
|
||||
class C_extension: public extension_base {
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Constructor, same as base clase
|
||||
*/
|
||||
using extension_base::extension_base;
|
||||
|
||||
/**
|
||||
* @brief Access to opcode field
|
||||
* @return return opcode field
|
||||
*/
|
||||
inline int32_t opcode() {
|
||||
return m_instr.range(1, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Access to rd field
|
||||
* @return rd field
|
||||
*/
|
||||
inline int32_t get_rd() {
|
||||
return m_instr.range(11, 7);
|
||||
}
|
||||
|
||||
inline void set_rd(int32_t value) {
|
||||
m_instr.range(11, 7) = value;
|
||||
}
|
||||
|
||||
inline int32_t get_rdp() {
|
||||
return m_instr.range(4, 2) + 8;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Access to rs1 field
|
||||
* @return rs1 field
|
||||
*/
|
||||
inline int32_t get_rs1() {
|
||||
return m_instr.range(11, 7);
|
||||
}
|
||||
|
||||
inline void set_rs1(int32_t value) {
|
||||
m_instr.range(11, 7) = value;
|
||||
}
|
||||
|
||||
inline int32_t get_rs1p() {
|
||||
return m_instr.range(9, 7) + 8;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Access to rs2 field
|
||||
* @return rs2 field
|
||||
*/
|
||||
inline int32_t get_rs2() {
|
||||
return m_instr.range(6, 2);
|
||||
}
|
||||
|
||||
inline void set_rs2(int32_t value) {
|
||||
m_instr.range(6, 2) = value;
|
||||
}
|
||||
|
||||
inline int32_t get_rs2p() {
|
||||
return m_instr.range(4, 2) + 8;
|
||||
}
|
||||
|
||||
inline int32_t get_funct3() {
|
||||
return m_instr.range(15, 13);
|
||||
}
|
||||
|
||||
inline void set_funct3(int32_t value) {
|
||||
m_instr.range(15, 13) = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Access to immediate field 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;
|
||||
}
|
||||
|
||||
inline void set_imm_I(int32_t value) {
|
||||
m_instr.range(31, 20) = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Access to immediate field 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;
|
||||
}
|
||||
|
||||
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 Access to immediate field for U-type
|
||||
* @return immediate_U field
|
||||
*/
|
||||
inline int32_t get_imm_U() {
|
||||
return m_instr.range(31, 12);
|
||||
}
|
||||
|
||||
inline void set_imm_U(int32_t value) {
|
||||
m_instr.range(31, 12) = (value << 12);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Access to immediate field 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;
|
||||
}
|
||||
|
||||
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 Access to immediate field for J-type
|
||||
* @return immediate_J field
|
||||
*/
|
||||
inline int32_t get_imm_J() {
|
||||
int32_t aux = 0;
|
||||
|
||||
aux = m_instr[12] << 11;
|
||||
aux |= m_instr[11] << 4;
|
||||
aux |= m_instr[10] << 9;
|
||||
aux |= m_instr[9] << 8;
|
||||
aux |= m_instr[8] << 10;
|
||||
aux |= m_instr[7] << 6;
|
||||
aux |= m_instr[6] << 7;
|
||||
aux |= m_instr.range(5, 3) << 1;
|
||||
aux |= m_instr[2] << 5;
|
||||
|
||||
if (m_instr[12] == 1) {
|
||||
aux |= 0b11111111111111111111 << 12;
|
||||
}
|
||||
|
||||
return aux;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
inline int32_t get_imm_L() {
|
||||
int32_t aux = 0;
|
||||
|
||||
aux = m_instr.range(12, 10) << 3;
|
||||
aux |= m_instr[6] << 2;
|
||||
aux |= m_instr[5] << 6;
|
||||
|
||||
return aux;
|
||||
}
|
||||
|
||||
inline int32_t get_imm_LWSP() {
|
||||
int32_t aux = 0;
|
||||
|
||||
aux = m_instr[12] << 5;
|
||||
aux |= m_instr.range(6, 4) << 2;
|
||||
aux |= m_instr.range(3, 2) << 6;
|
||||
|
||||
return aux;
|
||||
}
|
||||
|
||||
inline int32_t get_imm_ADDI() {
|
||||
int32_t aux = 0;
|
||||
|
||||
aux = m_instr[12] << 5;
|
||||
aux |= m_instr.range(6, 2);
|
||||
|
||||
if (m_instr[12] == 1) {
|
||||
aux |= 0b11111111111111111111111111 << 6;
|
||||
}
|
||||
return aux;
|
||||
}
|
||||
|
||||
inline int32_t get_imm_ADDI4SPN() {
|
||||
int32_t aux = 0;
|
||||
|
||||
aux = m_instr.range(12, 11) << 4;
|
||||
aux |= m_instr.range(10, 7) << 6;
|
||||
aux |= m_instr[6] << 2;
|
||||
aux |= m_instr[5] << 3;
|
||||
|
||||
return aux;
|
||||
}
|
||||
|
||||
inline int32_t get_imm_ADDI16SP() {
|
||||
int32_t aux = 0;
|
||||
|
||||
aux = m_instr[12] << 9;
|
||||
aux |= m_instr[6] << 4;
|
||||
aux |= m_instr[5] << 6;
|
||||
aux |= m_instr[4] << 8;
|
||||
aux |= m_instr[3] << 7;
|
||||
aux |= m_instr[2] << 5;
|
||||
|
||||
if (m_instr[12] == 1) {
|
||||
aux |= 0b1111111111111111111111 << 10;
|
||||
}
|
||||
return aux;
|
||||
}
|
||||
|
||||
inline int32_t get_imm_CSS() {
|
||||
int32_t aux = 0;
|
||||
aux = m_instr.range(12, 9) << 2;
|
||||
aux |= m_instr.range(8, 7) << 6;
|
||||
|
||||
return aux;
|
||||
}
|
||||
|
||||
inline int32_t get_imm_CB() {
|
||||
int32_t aux = 0;
|
||||
|
||||
aux = m_instr[12] << 8;
|
||||
aux |= m_instr[11] << 4;
|
||||
aux |= m_instr[10] << 3;
|
||||
aux |= m_instr[6] << 7;
|
||||
aux |= m_instr[5] << 6;
|
||||
aux |= m_instr[4] << 2;
|
||||
aux |= m_instr[3] << 1;
|
||||
aux |= m_instr[2] << 5;
|
||||
|
||||
if (m_instr[12] == 1) {
|
||||
aux |= 0b11111111111111111111111 << 9;
|
||||
}
|
||||
|
||||
return aux;
|
||||
}
|
||||
|
||||
inline int32_t get_imm_LUI() {
|
||||
int32_t aux = 0;
|
||||
|
||||
aux = m_instr[12] << 17;
|
||||
aux |= m_instr.range(6, 2) << 12;
|
||||
|
||||
if (m_instr[12] == 1) {
|
||||
aux |= 0b111111111111111 << 17;
|
||||
}
|
||||
|
||||
return aux;
|
||||
}
|
||||
|
||||
inline int32_t get_csr() {
|
||||
return get_imm_I();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Decodes opcode of instruction
|
||||
* @return opcode of instruction
|
||||
*/
|
||||
op_C_Codes decode();
|
||||
|
||||
bool Exec_C_JR();
|
||||
bool Exec_C_MV();
|
||||
bool Exec_C_LWSP();
|
||||
bool Exec_C_ADDI4SPN();
|
||||
bool Exec_C_SLLI();
|
||||
bool Exec_C_ADDI16SP();
|
||||
bool Exec_C_SWSP();
|
||||
bool Exec_C_BEQZ();
|
||||
bool Exec_C_BNEZ();
|
||||
bool Exec_C_LI();
|
||||
bool Exec_C_SRLI();
|
||||
bool Exec_C_SRAI();
|
||||
bool Exec_C_ANDI();
|
||||
bool Exec_C_ADD();
|
||||
bool Exec_C_SUB();
|
||||
bool Exec_C_XOR();
|
||||
bool Exec_C_OR();
|
||||
bool Exec_C_AND();
|
||||
|
||||
bool Exec_C_ADDI();
|
||||
bool Exec_C_JALR();
|
||||
bool Exec_C_LW();
|
||||
bool Exec_C_SW();
|
||||
bool Exec_C_JAL(int m_rd);
|
||||
|
||||
bool process_instruction(Instruction &inst);
|
||||
};
|
||||
|
||||
#endif
|
172
inc/Execute.h
172
inc/Execute.h
|
@ -1,172 +0,0 @@
|
|||
/*!
|
||||
\file Execute.h
|
||||
\brief RISC-V ISA implementation
|
||||
\author Màrius Montón
|
||||
\date August 2018
|
||||
*/
|
||||
#ifndef Execute_H
|
||||
#define Execute_H
|
||||
|
||||
#define SC_INCLUDE_DYNAMIC_PROCESSES
|
||||
|
||||
#include "systemc"
|
||||
#include <set>
|
||||
#include "tlm.h"
|
||||
#include "tlm_utils/simple_initiator_socket.h"
|
||||
|
||||
#include "memory.h"
|
||||
#include "Instruction.h"
|
||||
#include "C_Instruction.h"
|
||||
#include "M_Instruction.h"
|
||||
#include "A_Instruction.h"
|
||||
#include "Registers.h"
|
||||
#include "Log.h"
|
||||
|
||||
using namespace sc_core;
|
||||
using namespace sc_dt;
|
||||
using namespace std;
|
||||
|
||||
/**
|
||||
* @brief Risc_V execute module
|
||||
*/
|
||||
class Execute : sc_module {
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Constructor
|
||||
* @param name module name
|
||||
* @param register_bank pointer to register bank to use
|
||||
*/
|
||||
Execute(sc_module_name name,
|
||||
Registers *register_bank);
|
||||
|
||||
/* Quick & dirty way to publish a socket though modules */
|
||||
tlm_utils::simple_initiator_socket<Execute> data_bus;
|
||||
|
||||
bool LUI(Instruction &inst);
|
||||
bool AUIPC(Instruction &inst);
|
||||
|
||||
bool JAL(Instruction &inst, bool c_extension = false, int m_rd = 1);
|
||||
bool JALR(Instruction &inst, bool c_extension = false);
|
||||
|
||||
bool BEQ(Instruction &inst);
|
||||
bool BNE(Instruction &inst);
|
||||
bool BLT(Instruction &inst);
|
||||
bool BGE(Instruction &inst);
|
||||
bool BLTU(Instruction &inst);
|
||||
bool BGEU(Instruction &inst);
|
||||
|
||||
bool LB(Instruction &inst);
|
||||
bool LH(Instruction &inst);
|
||||
bool LW(Instruction &inst, bool c_extension = false);
|
||||
bool LBU(Instruction &inst);
|
||||
bool LHU(Instruction &inst);
|
||||
|
||||
bool SB(Instruction &inst);
|
||||
bool SH(Instruction &inst);
|
||||
bool SW(Instruction &inst, bool c_extension = false);
|
||||
bool SBU(Instruction &inst);
|
||||
bool SHU(Instruction &inst);
|
||||
|
||||
bool ADDI(Instruction &inst, bool c_extension = false);
|
||||
bool SLTI(Instruction &inst);
|
||||
bool SLTIU(Instruction &inst);
|
||||
bool XORI(Instruction &inst);
|
||||
bool ORI(Instruction &inst);
|
||||
bool ANDI(Instruction &inst);
|
||||
bool SLLI(Instruction &inst);
|
||||
bool SRLI(Instruction &inst);
|
||||
bool SRAI(Instruction &inst);
|
||||
|
||||
bool ADD(Instruction &inst);
|
||||
bool SUB(Instruction &inst);
|
||||
bool SLL(Instruction &inst);
|
||||
bool SLT(Instruction &inst);
|
||||
bool SLTU(Instruction &inst);
|
||||
|
||||
bool XOR(Instruction &inst);
|
||||
bool SRL(Instruction &inst);
|
||||
bool SRA(Instruction &inst);
|
||||
bool OR(Instruction &inst);
|
||||
bool AND(Instruction &inst);
|
||||
|
||||
bool FENCE(Instruction &inst);
|
||||
bool ECALL(Instruction &inst);
|
||||
bool EBREAK(Instruction &inst);
|
||||
|
||||
bool CSRRW(Instruction &inst);
|
||||
bool CSRRS(Instruction &inst);
|
||||
bool CSRRC(Instruction &inst);
|
||||
bool CSRRWI(Instruction &inst);
|
||||
bool CSRRSI(Instruction &inst);
|
||||
bool CSRRCI(Instruction &inst);
|
||||
|
||||
/*********************** Privileged Instructions ******************************/
|
||||
bool MRET(Instruction &inst);
|
||||
bool SRET(Instruction &inst);
|
||||
bool WFI(Instruction &inst);
|
||||
bool SFENCE(Instruction &inst);
|
||||
|
||||
/* C Extensions */
|
||||
bool C_JR(Instruction &inst);
|
||||
bool C_MV(Instruction &inst);
|
||||
bool C_LWSP(Instruction &inst);
|
||||
bool C_ADDI4SPN(Instruction &inst);
|
||||
bool C_SLLI(Instruction &inst);
|
||||
bool C_ADDI16SP(Instruction &inst);
|
||||
bool C_SWSP(Instruction &inst);
|
||||
bool C_BEQZ(Instruction &inst);
|
||||
bool C_BNEZ(Instruction &inst);
|
||||
bool C_LI(Instruction &inst);
|
||||
bool C_SRLI(Instruction &inst);
|
||||
bool C_SRAI(Instruction &inst);
|
||||
bool C_ANDI(Instruction &inst);
|
||||
bool C_ADD(Instruction &inst);
|
||||
bool C_SUB(Instruction &inst);
|
||||
bool C_XOR(Instruction &inst);
|
||||
bool C_OR(Instruction &inst);
|
||||
bool C_AND(Instruction &inst);
|
||||
|
||||
/* M Extensinos */
|
||||
bool M_MUL(Instruction &inst);
|
||||
bool M_MULH(Instruction &inst);
|
||||
bool M_MULHSU(Instruction &inst);
|
||||
bool M_MULHU(Instruction &inst);
|
||||
bool M_DIV(Instruction &inst);
|
||||
bool M_DIVU(Instruction &inst);
|
||||
bool M_REM(Instruction &inst);
|
||||
bool M_REMU(Instruction &inst);
|
||||
|
||||
/* A Extensinos */
|
||||
bool A_LR(Instruction &inst);
|
||||
bool A_SC(Instruction &inst);
|
||||
bool A_AMOSWAP(Instruction &inst);
|
||||
bool A_AMOADD(Instruction &inst);
|
||||
bool A_AMOXOR(Instruction &inst);
|
||||
bool A_AMOAND(Instruction &inst);
|
||||
bool A_AMOOR(Instruction &inst);
|
||||
bool A_AMOMIN(Instruction &inst);
|
||||
bool A_AMOMAX(Instruction &inst);
|
||||
bool A_AMOMINU(Instruction &inst);
|
||||
bool A_AMOMAXU(Instruction &inst);
|
||||
|
||||
bool NOP(Instruction &inst);
|
||||
|
||||
private:
|
||||
uint32_t readDataMem(uint32_t addr, int size);
|
||||
void writeDataMem(uint32_t addr, uint32_t data, int size);
|
||||
|
||||
void RaiseException(uint32_t cause, uint32_t inst = 0);
|
||||
|
||||
std::set<uint32_t> TLB_A_Entries;
|
||||
|
||||
void TLB_reserve(uint32_t address);
|
||||
bool TLB_reserved(uint32_t address);
|
||||
|
||||
Registers *regs;
|
||||
Performance *perf;
|
||||
Log *log;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
|
@ -4,15 +4,13 @@
|
|||
\author Màrius Montón
|
||||
\date August 2018
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#ifndef INSTRUCTION__H
|
||||
#define INSTRUCTION__H
|
||||
|
||||
#include "systemc"
|
||||
|
||||
using namespace sc_core;
|
||||
using namespace sc_dt;
|
||||
using namespace std;
|
||||
#include "extension_base.h"
|
||||
|
||||
typedef enum {
|
||||
BASE_EXTENSION,
|
||||
|
@ -31,411 +29,13 @@ typedef enum {
|
|||
UNKNOWN_EXTENSION
|
||||
} extension_t;
|
||||
|
||||
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;
|
||||
|
||||
|
||||
typedef enum {
|
||||
LUI = 0b0110111,
|
||||
AUIPC = 0b0010111,
|
||||
JAL = 0b1101111,
|
||||
JALR = 0b1100111,
|
||||
|
||||
BEQ = 0b1100011,
|
||||
BEQ_F = 0b000,
|
||||
BNE_F = 0b001,
|
||||
BLT_F = 0b100,
|
||||
BGE_F = 0b101,
|
||||
BLTU_F = 0b110,
|
||||
BGEU_F = 0b111,
|
||||
|
||||
LB = 0b0000011,
|
||||
LB_F = 0b000,
|
||||
LH_F = 0b001,
|
||||
LW_F = 0b010,
|
||||
LBU_F = 0b100,
|
||||
LHU_F = 0b101,
|
||||
|
||||
SB = 0b0100011,
|
||||
SB_F = 0b000,
|
||||
SH_F = 0b001,
|
||||
SW_F = 0b010,
|
||||
|
||||
ADDI = 0b0010011,
|
||||
ADDI_F = 0b000,
|
||||
SLTI_F = 0b010,
|
||||
SLTIU_F = 0b011,
|
||||
XORI_F = 0b100,
|
||||
ORI_F = 0b110,
|
||||
ANDI_F = 0b111,
|
||||
SLLI_F = 0b001,
|
||||
SRLI_F = 0b101,
|
||||
SRLI_F7 = 0b0000000,
|
||||
SRAI_F7 = 0b0100000,
|
||||
|
||||
ADD = 0b0110011,
|
||||
ADD_F = 0b000,
|
||||
SUB_F = 0b000,
|
||||
ADD_F7 = 0b0000000,
|
||||
SUB_F7 = 0b0100000,
|
||||
|
||||
SLL_F = 0b001,
|
||||
SLT_F = 0b010,
|
||||
SLTU_F = 0b011,
|
||||
XOR_F = 0b100,
|
||||
SRL_F = 0b101,
|
||||
SRA_F = 0b101,
|
||||
SRL_F7 = 0b0000000,
|
||||
SRA_F7 = 0b0100000,
|
||||
OR_F = 0b110,
|
||||
AND_F = 0b111,
|
||||
|
||||
FENCE = 0b0001111,
|
||||
ECALL = 0b1110011,
|
||||
ECALL_F = 0b000000000000,
|
||||
EBREAK_F= 0b000000000001,
|
||||
URET_F = 0b000000000010,
|
||||
SRET_F = 0b000100000010,
|
||||
MRET_F = 0b001100000010,
|
||||
WFI_F = 0b000100000101,
|
||||
SFENCE_F = 0b0001001,
|
||||
|
||||
ECALL_F3= 0b000,
|
||||
CSRRW = 0b001,
|
||||
CSRRS = 0b010,
|
||||
CSRRC = 0b011,
|
||||
CSRRWI = 0b101,
|
||||
CSRRSI = 0b110,
|
||||
CSRRCI = 0b111,
|
||||
} Codes;
|
||||
|
||||
#define EXCEPTION_CAUSE_INSTRUCTION_MISALIGN 0
|
||||
#define EXCEPTION_CAUSE_INSTRUCTION_ACCESS 1
|
||||
#define EXCEPTION_CAUSE_ILLEGAL_INSTRUCTION 2
|
||||
#define EXCEPTION_CAUSE_BREAKPOINT 3
|
||||
#define EXCEPTION_CAUSE_LOAD_ADDR_MISALIGN 4
|
||||
#define EXCEPTION_CAUSE_LOAD_ACCESS_FAULT 5
|
||||
|
||||
/**
|
||||
* @brief Instruction decoding and fields access
|
||||
*/
|
||||
class Instruction {
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Constructor
|
||||
* @param instr Instruction to decode
|
||||
*/
|
||||
Instruction(sc_uint<32> instr);
|
||||
|
||||
/**
|
||||
* @brief Access to opcode field
|
||||
* @return return opcode field
|
||||
*/
|
||||
inline int32_t opcode() {
|
||||
return m_instr.range(6,0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 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 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 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_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_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_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 Decodes opcode of instruction
|
||||
* @return opcode of instruction
|
||||
*/
|
||||
opCodes decode();
|
||||
Instruction(sc_dt::sc_uint<32> instr);
|
||||
|
||||
/**
|
||||
* @brief returns what instruction extension
|
||||
|
@ -443,7 +43,6 @@ public:
|
|||
*/
|
||||
extension_t check_extension();
|
||||
|
||||
|
||||
void setInstr(uint32_t p_instr) {
|
||||
m_instr = p_instr;
|
||||
}
|
||||
|
@ -455,12 +54,12 @@ public:
|
|||
return m_instr;
|
||||
}
|
||||
|
||||
|
||||
inline void dump() {
|
||||
cout << hex << "0x" << m_instr << dec << endl;
|
||||
std::cout << std::hex << "0x" << m_instr << std::dec << std::endl;
|
||||
}
|
||||
|
||||
private:
|
||||
sc_uint<32> m_instr;
|
||||
sc_dt::sc_uint<32> m_instr;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
13
inc/Log.h
13
inc/Log.h
|
@ -4,6 +4,7 @@
|
|||
\author Màrius Montón
|
||||
\date Aug 2018
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#ifndef LOG_H
|
||||
#define LOG_H
|
||||
|
@ -16,10 +17,6 @@
|
|||
#include "systemc"
|
||||
#include "tlm.h"
|
||||
|
||||
using namespace sc_core;
|
||||
using namespace sc_dt;
|
||||
using namespace std;
|
||||
|
||||
/**
|
||||
* @brief Log management class
|
||||
*
|
||||
|
@ -29,13 +26,9 @@ class Log {
|
|||
public:
|
||||
|
||||
enum LogLevel {
|
||||
ERROR = 0,
|
||||
DEBUG,
|
||||
WARNING,
|
||||
INFO
|
||||
ERROR = 0, DEBUG, WARNING, INFO
|
||||
} currentLogLevel;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Constructor
|
||||
* @return pointer to Log class
|
||||
|
@ -67,6 +60,8 @@ public:
|
|||
*/
|
||||
void setLogLevel(enum LogLevel newLevel);
|
||||
|
||||
enum LogLevel getLogLevel();
|
||||
|
||||
private:
|
||||
static Log *instance;
|
||||
Log(const char *filename);
|
||||
|
|
|
@ -1,130 +0,0 @@
|
|||
/*!
|
||||
\file M_Instruction.h
|
||||
\brief Decode M extensions part of the RISC-V
|
||||
\author Màrius Montón
|
||||
\date November 2018
|
||||
*/
|
||||
|
||||
#ifndef M_INSTRUCTION__H
|
||||
#define M_INSTRUCTION__H
|
||||
|
||||
#include "systemc"
|
||||
|
||||
using namespace sc_core;
|
||||
using namespace sc_dt;
|
||||
using namespace std;
|
||||
|
||||
typedef enum {
|
||||
OP_M_MUL,
|
||||
OP_M_MULH,
|
||||
OP_M_MULHSU,
|
||||
OP_M_MULHU,
|
||||
OP_M_DIV,
|
||||
OP_M_DIVU,
|
||||
OP_M_REM,
|
||||
OP_M_REMU,
|
||||
|
||||
OP_M_ERROR
|
||||
} op_M_Codes;
|
||||
|
||||
|
||||
typedef enum {
|
||||
M_MUL = 0b000,
|
||||
M_MULH = 0b001,
|
||||
M_MULHSU = 0b010,
|
||||
M_MULHU = 0b011,
|
||||
M_DIV = 0b100,
|
||||
M_DIVU = 0b101,
|
||||
M_REM = 0b110,
|
||||
M_REMU = 0b111,
|
||||
} M_Codes;
|
||||
|
||||
/**
|
||||
* @brief Instruction decoding and fields access
|
||||
*/
|
||||
class M_Instruction{
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Constructor
|
||||
* @param instr Instruction to decode
|
||||
*/
|
||||
M_Instruction(sc_uint<32> instr);
|
||||
|
||||
/**
|
||||
* @brief Sets instruction
|
||||
* @param p_instr instruction to decode
|
||||
*/
|
||||
void setInstr(uint32_t p_instr) {
|
||||
m_instr = sc_uint<32> (p_instr);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Access to opcode field
|
||||
* @return return opcode field
|
||||
*/
|
||||
inline int32_t opcode() {
|
||||
return m_instr.range(14,12);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Access to rd field
|
||||
* @return rd field
|
||||
*/
|
||||
inline int32_t get_rd() {
|
||||
return m_instr.range(11, 7);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
inline void set_rs2(int32_t value) {
|
||||
m_instr.range(24,20) = value;
|
||||
}
|
||||
|
||||
|
||||
inline int32_t get_funct3() {
|
||||
return m_instr.range(14, 12);
|
||||
}
|
||||
|
||||
inline void set_funct3(int32_t value) {
|
||||
m_instr.range(14,12) = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Decodes opcode of instruction
|
||||
* @return opcode of instruction
|
||||
*/
|
||||
op_M_Codes decode();
|
||||
|
||||
inline void dump() {
|
||||
cout << hex << "0x" << m_instr << dec << endl;
|
||||
}
|
||||
private:
|
||||
sc_uint<32> m_instr;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,129 @@
|
|||
/*!
|
||||
\file M_extension.h
|
||||
\brief Implement M extensions part of the RISC-V
|
||||
\author Màrius Montón
|
||||
\date November 2018
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#ifndef M_EXTENSION__H
|
||||
#define M_EXTENSION__H
|
||||
|
||||
#include "systemc"
|
||||
|
||||
#include "extension_base.h"
|
||||
#include "Log.h"
|
||||
#include "Registers.h"
|
||||
|
||||
typedef enum {
|
||||
OP_M_MUL,
|
||||
OP_M_MULH,
|
||||
OP_M_MULHSU,
|
||||
OP_M_MULHU,
|
||||
OP_M_DIV,
|
||||
OP_M_DIVU,
|
||||
OP_M_REM,
|
||||
OP_M_REMU,
|
||||
|
||||
OP_M_ERROR
|
||||
} op_M_Codes;
|
||||
|
||||
typedef enum {
|
||||
M_MUL = 0b000,
|
||||
M_MULH = 0b001,
|
||||
M_MULHSU = 0b010,
|
||||
M_MULHU = 0b011,
|
||||
M_DIV = 0b100,
|
||||
M_DIVU = 0b101,
|
||||
M_REM = 0b110,
|
||||
M_REMU = 0b111,
|
||||
} M_Codes;
|
||||
|
||||
/**
|
||||
* @brief Instruction decoding and fields access
|
||||
*/
|
||||
class M_extension: public extension_base {
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Constructor, same as base clase
|
||||
*/
|
||||
using extension_base::extension_base;
|
||||
|
||||
/**
|
||||
* @brief Decodes opcode of instruction
|
||||
* @return opcode of instruction
|
||||
*/
|
||||
op_M_Codes decode();
|
||||
|
||||
inline void dump() {
|
||||
std::cout << std::hex << "0x" << m_instr << std::dec << std::endl;
|
||||
}
|
||||
|
||||
bool Exec_M_MUL();
|
||||
bool Exec_M_MULH();
|
||||
bool Exec_M_MULHSU();
|
||||
bool Exec_M_MULHU();
|
||||
bool Exec_M_DIV();
|
||||
bool Exec_M_DIVU();
|
||||
bool Exec_M_REM();
|
||||
bool Exec_M_REMU();
|
||||
|
||||
bool process_instruction(Instruction &inst);
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* @brief Access to opcode field
|
||||
* @return return opcode field
|
||||
*/
|
||||
inline int32_t opcode() {
|
||||
return m_instr.range(14, 12);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Access to rd field
|
||||
* @return rd field
|
||||
*/
|
||||
inline int32_t get_rd() {
|
||||
return m_instr.range(11, 7);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
inline void set_rs2(int32_t value) {
|
||||
m_instr.range(24, 20) = value;
|
||||
}
|
||||
|
||||
inline int32_t get_funct3() {
|
||||
return m_instr.range(14, 12);
|
||||
}
|
||||
|
||||
inline void set_funct3(int32_t value) {
|
||||
m_instr.range(14, 12) = value;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
26
inc/Memory.h
26
inc/Memory.h
|
@ -4,6 +4,7 @@
|
|||
\author Màrius Montón
|
||||
\date August 2018
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#ifndef __MEMORY_H__
|
||||
#define __MEMORY_H__
|
||||
|
@ -20,24 +21,22 @@
|
|||
|
||||
#include "Log.h"
|
||||
|
||||
using namespace sc_core;
|
||||
using namespace sc_dt;
|
||||
using namespace std;
|
||||
|
||||
/**
|
||||
* @brief Basic TLM-2 memory
|
||||
*/
|
||||
class Memory: sc_module {
|
||||
class Memory: sc_core::sc_module {
|
||||
public:
|
||||
// TLM-2 socket, defaults to 32-bits wide, base protocol
|
||||
tlm_utils::simple_target_socket<Memory> socket;
|
||||
|
||||
//enum { SIZE = 0x90000000 };
|
||||
enum { SIZE = 0x10000000 };
|
||||
const sc_time LATENCY;
|
||||
enum {
|
||||
SIZE = 0x10000000
|
||||
};
|
||||
const sc_core::sc_time LATENCY;
|
||||
|
||||
Memory(sc_module_name name, string filename);
|
||||
Memory(sc_module_name name, bool use_file);
|
||||
Memory(sc_core::sc_module_name name, std::string filename);
|
||||
Memory(sc_core::sc_module_name name, bool use_file);
|
||||
|
||||
~Memory(void);
|
||||
|
||||
|
@ -48,7 +47,8 @@ public:
|
|||
virtual uint32_t getPCfromHEX();
|
||||
|
||||
// TLM-2 blocking transport method
|
||||
virtual void b_transport( tlm::tlm_generic_payload& trans, sc_time& delay );
|
||||
virtual void b_transport(tlm::tlm_generic_payload &trans,
|
||||
sc_core::sc_time &delay);
|
||||
|
||||
// *********************************************
|
||||
// TLM-2 forward DMI method
|
||||
|
@ -66,13 +66,13 @@ private:
|
|||
/**
|
||||
* @brief Memory array in bytes
|
||||
*/
|
||||
//uint8_t mem[SIZE];
|
||||
uint8_t *mem;
|
||||
|
||||
/**
|
||||
* @brief Log classe
|
||||
* @brief Log class
|
||||
*/
|
||||
Log *log;
|
||||
|
||||
/**
|
||||
* @brief Program counter (PC) read from hex file
|
||||
*/
|
||||
|
@ -83,6 +83,6 @@ private:
|
|||
* @brief Read Intel hex file
|
||||
* @param filename file name to read
|
||||
*/
|
||||
virtual void readHexFile(string filename);
|
||||
virtual void readHexFile(std::string filename);
|
||||
};
|
||||
#endif /* __MEMORY_H__ */
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
/*!
|
||||
\file MemoryInterface.h
|
||||
\brief CPU to Memory Interface class
|
||||
\author Màrius Montón
|
||||
\date May 2020
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#ifndef INC_MEMORYINTERFACE_H_
|
||||
#define INC_MEMORYINTERFACE_H_
|
||||
|
||||
#include "systemc"
|
||||
|
||||
#include "tlm.h"
|
||||
#include "tlm_utils/simple_initiator_socket.h"
|
||||
#include "tlm_utils/tlm_quantumkeeper.h"
|
||||
|
||||
#include "memory.h"
|
||||
#include "Log.h"
|
||||
|
||||
/**
|
||||
* @brief Memory Interface
|
||||
*/
|
||||
class MemoryInterface {
|
||||
public:
|
||||
|
||||
tlm_utils::simple_initiator_socket<MemoryInterface> data_bus;
|
||||
|
||||
MemoryInterface();
|
||||
uint32_t readDataMem(uint32_t addr, int size);
|
||||
void writeDataMem(uint32_t addr, uint32_t data, int size);
|
||||
};
|
||||
|
||||
#endif /* INC_MEMORYINTERFACE_H_ */
|
|
@ -4,6 +4,7 @@
|
|||
\author Màrius Montón
|
||||
\date Aug 2018
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#ifndef PERFORMANCE_H
|
||||
#define PERFORMANCE_H
|
||||
|
@ -14,10 +15,6 @@
|
|||
|
||||
#include "tlm.h"
|
||||
|
||||
using namespace sc_core;
|
||||
using namespace sc_dt;
|
||||
using namespace std;
|
||||
|
||||
/**
|
||||
* @brief Performance indicators class
|
||||
*
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
\author Màrius Montón
|
||||
\date August 2018
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#ifndef REGISTERS_H
|
||||
#define REGISTERS_H
|
||||
|
||||
|
@ -23,7 +25,6 @@
|
|||
#define MISA_M_EXTENSION (1 << 12)
|
||||
#define MISA_MXL (1 << 30)
|
||||
|
||||
|
||||
#define CSR_MVENDORID (0xF11)
|
||||
#define CSR_MARCHID (0xF12)
|
||||
#define CSR_MIMPID (0xF13)
|
||||
|
@ -65,7 +66,6 @@
|
|||
|
||||
#define CSR_STVEC (0x105)
|
||||
|
||||
|
||||
#define MSTATUS_UIE (1 << 0)
|
||||
#define MSTATUS_SIE (1 << 1)
|
||||
#define MSTATUS_MIE (1 << 3)
|
||||
|
@ -103,14 +103,9 @@
|
|||
#define MIE_SEIE (1 << 9)
|
||||
#define MIE_MEIE (1 << 11)
|
||||
|
||||
|
||||
/* 1 ns tick in CYCLE & TIME counters */
|
||||
#define TICKS_PER_SECOND (1000000)
|
||||
|
||||
using namespace sc_core;
|
||||
using namespace sc_dt;
|
||||
using namespace std;
|
||||
|
||||
/**
|
||||
* @brief Register file implementation
|
||||
*/
|
||||
|
|
19
inc/Timer.h
19
inc/Timer.h
|
@ -4,6 +4,7 @@
|
|||
\author Màrius Montón
|
||||
\date January 2019
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#ifndef __TIMER_H__
|
||||
#define __TIMER_H__
|
||||
|
@ -20,30 +21,25 @@
|
|||
|
||||
#include "BusCtrl.h"
|
||||
|
||||
using namespace sc_core;
|
||||
using namespace sc_dt;
|
||||
using namespace std;
|
||||
|
||||
/**
|
||||
* @brief Simple timer peripheral
|
||||
*
|
||||
* It runs a 1 ns (nanoseconds) pace
|
||||
*
|
||||
*/
|
||||
class Timer: sc_module {
|
||||
class Timer: sc_core::sc_module {
|
||||
public:
|
||||
// TLM-2 socket, defaults to 32-bits wide, base protocol
|
||||
tlm_utils::simple_target_socket<Timer> socket;
|
||||
|
||||
tlm_utils::simple_initiator_socket<Timer> irq_line;
|
||||
//sc_out<bool> timer_irq;
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Constructor
|
||||
* @param name module name
|
||||
*/
|
||||
Timer(sc_module_name name);
|
||||
Timer(sc_core::sc_module_name name);
|
||||
|
||||
/**
|
||||
* @brief Waits for event timer_event and triggers an IRQ
|
||||
|
@ -62,12 +58,13 @@ public:
|
|||
* @param trans TLM-2.0 transaction
|
||||
* @param delay transaction delay time
|
||||
*/
|
||||
virtual void b_transport( tlm::tlm_generic_payload& trans, sc_time& delay );
|
||||
virtual void b_transport(tlm::tlm_generic_payload &trans,
|
||||
sc_core::sc_time &delay);
|
||||
|
||||
private:
|
||||
sc_uint<64> m_mtime; /**< mtime register */
|
||||
sc_uint<64> m_mtimecmp; /**< mtimecmp register */
|
||||
sc_event timer_event; /**< event */
|
||||
sc_dt::sc_uint<64> m_mtime; /**< mtime register */
|
||||
sc_dt::sc_uint<64> m_mtimecmp; /**< mtimecmp register */
|
||||
sc_core::sc_event timer_event; /**< event */
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
12
inc/Trace.h
12
inc/Trace.h
|
@ -4,6 +4,7 @@
|
|||
\author Màrius Montón
|
||||
\date September 2018
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#ifndef __TRACE_H__
|
||||
#define __TRACE_H__
|
||||
|
@ -18,16 +19,12 @@
|
|||
#include "tlm.h"
|
||||
#include "tlm_utils/simple_target_socket.h"
|
||||
|
||||
using namespace sc_core;
|
||||
using namespace sc_dt;
|
||||
using namespace std;
|
||||
|
||||
/**
|
||||
* @brief Simple trace peripheral
|
||||
*
|
||||
* This peripheral outputs to cout any character written to its unique register
|
||||
*/
|
||||
class Trace: sc_module {
|
||||
class Trace: sc_core::sc_module {
|
||||
public:
|
||||
|
||||
/**
|
||||
|
@ -39,7 +36,7 @@ public:
|
|||
* @brief Constructor
|
||||
* @param name Module name
|
||||
*/
|
||||
Trace(sc_module_name name);
|
||||
Trace(sc_core::sc_module_name name);
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
|
@ -49,7 +46,8 @@ public:
|
|||
private:
|
||||
|
||||
// TLM-2 blocking transport method
|
||||
virtual void b_transport( tlm::tlm_generic_payload& trans, sc_time& delay );
|
||||
virtual void b_transport(tlm::tlm_generic_payload &trans,
|
||||
sc_core::sc_time &delay);
|
||||
|
||||
void xtermLaunch(char *slaveName);
|
||||
void xtermKill(const char *mess);
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
/*!
|
||||
\file extension_base.h
|
||||
\brief Base class for ISA extensions
|
||||
\author Màrius Montón
|
||||
\date May 2020
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#ifndef INC_EXTENSION_BASE_H_
|
||||
#define INC_EXTENSION_BASE_H_
|
||||
|
||||
#include "systemc"
|
||||
|
||||
#include "Instruction.h"
|
||||
#include "Registers.h"
|
||||
#include "Log.h"
|
||||
#include "MemoryInterface.h"
|
||||
|
||||
#define EXCEPTION_CAUSE_INSTRUCTION_MISALIGN 0
|
||||
#define EXCEPTION_CAUSE_INSTRUCTION_ACCESS 1
|
||||
#define EXCEPTION_CAUSE_ILLEGAL_INSTRUCTION 2
|
||||
#define EXCEPTION_CAUSE_BREAKPOINT 3
|
||||
#define EXCEPTION_CAUSE_LOAD_ADDR_MISALIGN 4
|
||||
#define EXCEPTION_CAUSE_LOAD_ACCESS_FAULT 5
|
||||
|
||||
class extension_base {
|
||||
|
||||
public:
|
||||
extension_base(sc_dt::sc_uint<32> instr, Registers *register_bank,
|
||||
MemoryInterface *mem_interface);
|
||||
virtual ~extension_base() = 0;
|
||||
|
||||
void setInstr(uint32_t p_instr);
|
||||
void RaiseException(uint32_t cause, uint32_t inst);
|
||||
bool NOP();
|
||||
|
||||
/* pure virtual functions */
|
||||
virtual int32_t opcode() = 0;
|
||||
virtual int32_t get_rd() = 0;
|
||||
virtual void set_rd(int32_t value) = 0;
|
||||
virtual int32_t get_rs1() = 0;
|
||||
virtual void set_rs1(int32_t value) = 0;
|
||||
virtual int32_t get_rs2() = 0;
|
||||
virtual void set_rs2(int32_t value) = 0;
|
||||
virtual int32_t get_funct3() = 0;
|
||||
virtual void set_funct3(int32_t value) = 0;
|
||||
|
||||
void dump();
|
||||
|
||||
protected:
|
||||
sc_dt::sc_uint<32> m_instr;
|
||||
Registers *regs;
|
||||
Performance *perf;
|
||||
Log *log;
|
||||
MemoryInterface *mem_intf;
|
||||
};
|
||||
|
||||
#endif /* INC_EXTENSION_BASE_H_ */
|
|
@ -1,51 +0,0 @@
|
|||
#include "A_Instruction.h"
|
||||
|
||||
|
||||
A_Instruction::A_Instruction(sc_uint<32> instr) {
|
||||
a_instr = instr;
|
||||
}
|
||||
|
||||
op_A_Codes A_Instruction::decode() {
|
||||
|
||||
switch (opcode()) {
|
||||
case A_LR:
|
||||
return OP_A_LR;
|
||||
break;
|
||||
case A_SC:
|
||||
return OP_A_SC;
|
||||
break;
|
||||
case A_AMOSWAP:
|
||||
return OP_A_AMOSWAP;
|
||||
break;
|
||||
case A_AMOADD:
|
||||
return OP_A_AMOADD;
|
||||
break;
|
||||
case A_AMOXOR:
|
||||
return OP_A_AMOXOR;
|
||||
break;
|
||||
case A_AMOAND:
|
||||
return OP_A_AMOAND;
|
||||
break;
|
||||
case A_AMOOR:
|
||||
return OP_A_AMOOR;
|
||||
break;
|
||||
case A_AMOMIN:
|
||||
return OP_A_AMOMIN;
|
||||
break;
|
||||
case A_AMOMAX:
|
||||
return OP_A_AMOMAX;
|
||||
break;
|
||||
case A_AMOMINU:
|
||||
return OP_A_AMOMINU;
|
||||
break;
|
||||
case A_AMOMAXU:
|
||||
return OP_A_AMOMAXU;
|
||||
break;
|
||||
default:
|
||||
return OP_A_ERROR;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return OP_A_ERROR;
|
||||
}
|
|
@ -0,0 +1,416 @@
|
|||
/*!
|
||||
\file A_extension.h
|
||||
\brief Implement A extensions part of the RISC-V
|
||||
\author Màrius Montón
|
||||
\date December 2018
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "A_extension.h"
|
||||
|
||||
op_A_Codes A_extension::decode() {
|
||||
|
||||
switch (opcode()) {
|
||||
case A_LR:
|
||||
return OP_A_LR;
|
||||
break;
|
||||
case A_SC:
|
||||
return OP_A_SC;
|
||||
break;
|
||||
case A_AMOSWAP:
|
||||
return OP_A_AMOSWAP;
|
||||
break;
|
||||
case A_AMOADD:
|
||||
return OP_A_AMOADD;
|
||||
break;
|
||||
case A_AMOXOR:
|
||||
return OP_A_AMOXOR;
|
||||
break;
|
||||
case A_AMOAND:
|
||||
return OP_A_AMOAND;
|
||||
break;
|
||||
case A_AMOOR:
|
||||
return OP_A_AMOOR;
|
||||
break;
|
||||
case A_AMOMIN:
|
||||
return OP_A_AMOMIN;
|
||||
break;
|
||||
case A_AMOMAX:
|
||||
return OP_A_AMOMAX;
|
||||
break;
|
||||
case A_AMOMINU:
|
||||
return OP_A_AMOMINU;
|
||||
break;
|
||||
case A_AMOMAXU:
|
||||
return OP_A_AMOMAXU;
|
||||
break;
|
||||
default:
|
||||
return OP_A_ERROR;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return OP_A_ERROR;
|
||||
}
|
||||
|
||||
bool A_extension::Exec_A_LR() {
|
||||
uint32_t mem_addr = 0;
|
||||
int rd, rs1, rs2;
|
||||
uint32_t data;
|
||||
|
||||
rd = get_rd();
|
||||
rs1 = get_rs1();
|
||||
rs2 = get_rs2();
|
||||
|
||||
if (rs2 != 0) {
|
||||
std::cout << "ILEGAL INSTRUCTION, LR.W: rs2 != 0" << std::endl;
|
||||
RaiseException(EXCEPTION_CAUSE_ILLEGAL_INSTRUCTION, m_instr);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
mem_addr = regs->getValue(rs1);
|
||||
data = mem_intf->readDataMem(mem_addr, 4);
|
||||
regs->setValue(rd, data);
|
||||
|
||||
TLB_reserve(mem_addr);
|
||||
|
||||
log->SC_log(Log::INFO) << std::dec << "LR.W: x" << rs1 << " (@0x"
|
||||
<< std::hex << mem_addr << std::dec << ") -> x" << rd << std::endl;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool A_extension::Exec_A_SC() {
|
||||
uint32_t mem_addr = 0;
|
||||
int rd, rs1, rs2;
|
||||
uint32_t data;
|
||||
|
||||
rd = get_rd();
|
||||
rs1 = get_rs1();
|
||||
rs2 = get_rs2();
|
||||
|
||||
mem_addr = regs->getValue(rs1);
|
||||
data = regs->getValue(rs2);
|
||||
|
||||
if (TLB_reserved(mem_addr) == true) {
|
||||
mem_intf->writeDataMem(mem_addr, data, 4);
|
||||
regs->setValue(rd, 0); // SC writes 0 to rd on success
|
||||
} else {
|
||||
regs->setValue(rd, 1); // SC writes nonzero on failure
|
||||
}
|
||||
|
||||
log->SC_log(Log::INFO) << std::dec << "SC.W: (@0x" << std::hex << mem_addr
|
||||
<< std::dec << ") <- x" << rs2 << std::hex << "(0x" << data << ")"
|
||||
<< std::endl;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool A_extension::Exec_A_AMOSWAP() {
|
||||
uint32_t mem_addr = 0;
|
||||
int rd, rs1, rs2;
|
||||
uint32_t data;
|
||||
uint32_t aux;
|
||||
|
||||
/* These instructions must be atomic */
|
||||
|
||||
rd = get_rd();
|
||||
rs1 = get_rs1();
|
||||
rs2 = get_rs2();
|
||||
|
||||
mem_addr = regs->getValue(rs1);
|
||||
data = mem_intf->readDataMem(mem_addr, 4);
|
||||
|
||||
regs->setValue(rd, data);
|
||||
|
||||
// swap
|
||||
aux = regs->getValue(rs2);
|
||||
regs->setValue(rs2, data);
|
||||
|
||||
mem_intf->writeDataMem(mem_addr, aux, 4);
|
||||
|
||||
log->SC_log(Log::INFO) << std::dec << "AMOSWAP " << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool A_extension::Exec_A_AMOADD() {
|
||||
uint32_t mem_addr = 0;
|
||||
int rd, rs1, rs2;
|
||||
uint32_t data;
|
||||
|
||||
/* These instructions must be atomic */
|
||||
|
||||
rd = get_rd();
|
||||
rs1 = get_rs1();
|
||||
rs2 = get_rs2();
|
||||
|
||||
mem_addr = regs->getValue(rs1);
|
||||
data = mem_intf->readDataMem(mem_addr, 4);
|
||||
|
||||
regs->setValue(rd, data);
|
||||
|
||||
// add
|
||||
data = data + regs->getValue(rs2);
|
||||
|
||||
mem_intf->writeDataMem(mem_addr, data, 4);
|
||||
|
||||
log->SC_log(Log::INFO) << std::dec << "AMOADD " << std::endl;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool A_extension::Exec_A_AMOXOR() {
|
||||
uint32_t mem_addr = 0;
|
||||
int rd, rs1, rs2;
|
||||
uint32_t data;
|
||||
|
||||
/* These instructions must be atomic */
|
||||
|
||||
rd = get_rd();
|
||||
rs1 = get_rs1();
|
||||
rs2 = get_rs2();
|
||||
|
||||
mem_addr = regs->getValue(rs1);
|
||||
data = mem_intf->readDataMem(mem_addr, 4);
|
||||
|
||||
regs->setValue(rd, data);
|
||||
|
||||
// add
|
||||
data = data ^ regs->getValue(rs2);
|
||||
|
||||
mem_intf->writeDataMem(mem_addr, data, 4);
|
||||
|
||||
log->SC_log(Log::INFO) << std::dec << "AMOXOR " << std::endl;
|
||||
|
||||
return true;
|
||||
}
|
||||
bool A_extension::Exec_A_AMOAND() {
|
||||
uint32_t mem_addr = 0;
|
||||
int rd, rs1, rs2;
|
||||
uint32_t data;
|
||||
|
||||
/* These instructions must be atomic */
|
||||
|
||||
rd = get_rd();
|
||||
rs1 = get_rs1();
|
||||
rs2 = get_rs2();
|
||||
|
||||
mem_addr = regs->getValue(rs1);
|
||||
data = mem_intf->readDataMem(mem_addr, 4);
|
||||
|
||||
regs->setValue(rd, data);
|
||||
|
||||
// add
|
||||
data = data & regs->getValue(rs2);
|
||||
|
||||
mem_intf->writeDataMem(mem_addr, data, 4);
|
||||
|
||||
log->SC_log(Log::INFO) << std::dec << "AMOAND " << std::endl;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool A_extension::Exec_A_AMOOR() {
|
||||
uint32_t mem_addr = 0;
|
||||
int rd, rs1, rs2;
|
||||
uint32_t data;
|
||||
|
||||
/* These instructions must be atomic */
|
||||
|
||||
rd = get_rd();
|
||||
rs1 = get_rs1();
|
||||
rs2 = get_rs2();
|
||||
|
||||
mem_addr = regs->getValue(rs1);
|
||||
data = mem_intf->readDataMem(mem_addr, 4);
|
||||
|
||||
regs->setValue(rd, data);
|
||||
|
||||
// add
|
||||
data = data | regs->getValue(rs2);
|
||||
|
||||
mem_intf->writeDataMem(mem_addr, data, 4);
|
||||
|
||||
log->SC_log(Log::INFO) << std::dec << "AMOOR " << std::endl;
|
||||
return true;
|
||||
}
|
||||
bool A_extension::Exec_A_AMOMIN() {
|
||||
uint32_t mem_addr = 0;
|
||||
int rd, rs1, rs2;
|
||||
uint32_t data;
|
||||
uint32_t aux;
|
||||
|
||||
/* These instructions must be atomic */
|
||||
|
||||
rd = get_rd();
|
||||
rs1 = get_rs1();
|
||||
rs2 = get_rs2();
|
||||
|
||||
mem_addr = regs->getValue(rs1);
|
||||
data = mem_intf->readDataMem(mem_addr, 4);
|
||||
|
||||
regs->setValue(rd, data);
|
||||
|
||||
// min
|
||||
aux = regs->getValue(rs2);
|
||||
if ((int32_t) data < (int32_t) aux) {
|
||||
aux = data;
|
||||
}
|
||||
|
||||
mem_intf->writeDataMem(mem_addr, aux, 4);
|
||||
|
||||
log->SC_log(Log::INFO) << std::dec << "AMOMIN " << std::endl;
|
||||
|
||||
return true;
|
||||
}
|
||||
bool A_extension::Exec_A_AMOMAX() {
|
||||
uint32_t mem_addr = 0;
|
||||
int rd, rs1, rs2;
|
||||
uint32_t data;
|
||||
uint32_t aux;
|
||||
|
||||
/* These instructions must be atomic */
|
||||
|
||||
rd = get_rd();
|
||||
rs1 = get_rs1();
|
||||
rs2 = get_rs2();
|
||||
|
||||
mem_addr = regs->getValue(rs1);
|
||||
data = mem_intf->readDataMem(mem_addr, 4);
|
||||
|
||||
regs->setValue(rd, data);
|
||||
|
||||
// >
|
||||
aux = regs->getValue(rs2);
|
||||
if ((int32_t) data > (int32_t) aux) {
|
||||
aux = data;
|
||||
}
|
||||
|
||||
mem_intf->writeDataMem(mem_addr, aux, 4);
|
||||
|
||||
log->SC_log(Log::INFO) << std::dec << "AMOMAX " << std::endl;
|
||||
|
||||
return true;
|
||||
}
|
||||
bool A_extension::Exec_A_AMOMINU() {
|
||||
uint32_t mem_addr = 0;
|
||||
int rd, rs1, rs2;
|
||||
uint32_t data;
|
||||
uint32_t aux;
|
||||
|
||||
/* These instructions must be atomic */
|
||||
|
||||
rd = get_rd();
|
||||
rs1 = get_rs1();
|
||||
rs2 = get_rs2();
|
||||
|
||||
mem_addr = regs->getValue(rs1);
|
||||
data = mem_intf->readDataMem(mem_addr, 4);
|
||||
|
||||
regs->setValue(rd, data);
|
||||
|
||||
// min
|
||||
aux = regs->getValue(rs2);
|
||||
if (data < aux) {
|
||||
aux = data;
|
||||
}
|
||||
|
||||
mem_intf->writeDataMem(mem_addr, aux, 4);
|
||||
|
||||
log->SC_log(Log::INFO) << std::dec << "AMOMINU " << std::endl;
|
||||
|
||||
return true;
|
||||
}
|
||||
bool A_extension::Exec_A_AMOMAXU() {
|
||||
uint32_t mem_addr = 0;
|
||||
int rd, rs1, rs2;
|
||||
uint32_t data;
|
||||
uint32_t aux;
|
||||
|
||||
/* These instructions must be atomic */
|
||||
|
||||
rd = get_rd();
|
||||
rs1 = get_rs1();
|
||||
rs2 = get_rs2();
|
||||
|
||||
mem_addr = regs->getValue(rs1);
|
||||
data = mem_intf->readDataMem(mem_addr, 4);
|
||||
|
||||
regs->setValue(rd, data);
|
||||
|
||||
// max
|
||||
aux = regs->getValue(rs2);
|
||||
if (data > aux) {
|
||||
aux = data;
|
||||
}
|
||||
|
||||
mem_intf->writeDataMem(mem_addr, aux, 4);
|
||||
|
||||
log->SC_log(Log::INFO) << std::dec << "AMOMAXU " << std::endl;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void A_extension::TLB_reserve(uint32_t address) {
|
||||
TLB_A_Entries.insert(address);
|
||||
return;
|
||||
}
|
||||
|
||||
bool A_extension::TLB_reserved(uint32_t address) {
|
||||
if (TLB_A_Entries.count(address) == 1) {
|
||||
TLB_A_Entries.erase(address);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool A_extension::process_instruction(Instruction &inst) {
|
||||
bool PC_not_affected = true;
|
||||
|
||||
setInstr(inst.getInstr());
|
||||
|
||||
switch (decode()) {
|
||||
case OP_A_LR:
|
||||
Exec_A_LR();
|
||||
break;
|
||||
case OP_A_SC:
|
||||
Exec_A_SC();
|
||||
break;
|
||||
case OP_A_AMOSWAP:
|
||||
Exec_A_AMOSWAP();
|
||||
break;
|
||||
case OP_A_AMOADD:
|
||||
Exec_A_AMOADD();
|
||||
break;
|
||||
case OP_A_AMOXOR:
|
||||
Exec_A_AMOXOR();
|
||||
break;
|
||||
case OP_A_AMOAND:
|
||||
Exec_A_AMOAND();
|
||||
break;
|
||||
case OP_A_AMOOR:
|
||||
Exec_A_AMOOR();
|
||||
break;
|
||||
case OP_A_AMOMIN:
|
||||
Exec_A_AMOMIN();
|
||||
break;
|
||||
case OP_A_AMOMAX:
|
||||
Exec_A_AMOMAX();
|
||||
break;
|
||||
case OP_A_AMOMINU:
|
||||
Exec_A_AMOMINU();
|
||||
break;
|
||||
case OP_A_AMOMAXU:
|
||||
Exec_A_AMOMAXU();
|
||||
break;
|
||||
default:
|
||||
std::cout << "A instruction not implemented yet" << std::endl;
|
||||
inst.dump();
|
||||
NOP();
|
||||
break;
|
||||
}
|
||||
|
||||
return PC_not_affected;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,21 +1,29 @@
|
|||
/**
|
||||
@file BusCtrl.cpp
|
||||
@brief Basic TLM-2 Bus controller
|
||||
@author Màrius Montón
|
||||
@date September 2018
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "BusCtrl.h"
|
||||
|
||||
SC_HAS_PROCESS(BusCtrl);
|
||||
BusCtrl::BusCtrl(sc_module_name name): sc_module(name)
|
||||
,cpu_instr_socket("cpu_instr_socket")
|
||||
,cpu_data_socket("cpu_data_socket")
|
||||
,memory_socket("memory_socket")
|
||||
,trace_socket("trace_socket")
|
||||
{
|
||||
BusCtrl::BusCtrl(sc_core::sc_module_name name) :
|
||||
sc_module(name), cpu_instr_socket("cpu_instr_socket"), cpu_data_socket(
|
||||
"cpu_data_socket"), memory_socket("memory_socket"), trace_socket(
|
||||
"trace_socket") {
|
||||
cpu_instr_socket.register_b_transport(this, &BusCtrl::b_transport);
|
||||
cpu_data_socket.register_b_transport(this, &BusCtrl::b_transport);
|
||||
log = Log::getInstance();
|
||||
cpu_instr_socket.register_get_direct_mem_ptr(this, &BusCtrl::instr_direct_mem_ptr);
|
||||
memory_socket.register_invalidate_direct_mem_ptr( this, &BusCtrl::invalidate_direct_mem_ptr);
|
||||
cpu_instr_socket.register_get_direct_mem_ptr(this,
|
||||
&BusCtrl::instr_direct_mem_ptr);
|
||||
memory_socket.register_invalidate_direct_mem_ptr(this,
|
||||
&BusCtrl::invalidate_direct_mem_ptr);
|
||||
}
|
||||
|
||||
|
||||
void BusCtrl::b_transport( tlm::tlm_generic_payload& trans, sc_time& delay ) {
|
||||
void BusCtrl::b_transport(tlm::tlm_generic_payload &trans,
|
||||
sc_core::sc_time &delay) {
|
||||
//tlm::tlm_command cmd = trans.get_command();
|
||||
sc_dt::uint64 adr = trans.get_address() / 4;
|
||||
|
||||
|
@ -45,11 +53,13 @@ void BusCtrl::b_transport( tlm::tlm_generic_payload& trans, sc_time& delay ) {
|
|||
trans.set_response_status(tlm::TLM_OK_RESPONSE);
|
||||
}
|
||||
|
||||
bool BusCtrl::instr_direct_mem_ptr(tlm::tlm_generic_payload& gp, tlm::tlm_dmi& dmi_data) {
|
||||
bool BusCtrl::instr_direct_mem_ptr(tlm::tlm_generic_payload &gp,
|
||||
tlm::tlm_dmi &dmi_data) {
|
||||
return memory_socket->get_direct_mem_ptr(gp, dmi_data);
|
||||
}
|
||||
|
||||
void BusCtrl::invalidate_direct_mem_ptr(sc_dt::uint64 start, sc_dt::uint64 end) {
|
||||
void BusCtrl::invalidate_direct_mem_ptr(sc_dt::uint64 start,
|
||||
sc_dt::uint64 end) {
|
||||
cpu_instr_socket->invalidate_direct_mem_ptr(start, end);
|
||||
}
|
||||
|
||||
|
|
436
src/CPU.cpp
436
src/CPU.cpp
|
@ -1,10 +1,20 @@
|
|||
/*!
|
||||
\file CPU.cpp
|
||||
\brief Main CPU class
|
||||
\author Màrius Montón
|
||||
\date August 2018
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "CPU.h"
|
||||
|
||||
SC_HAS_PROCESS(CPU);
|
||||
CPU::CPU(sc_module_name name, uint32_t PC) :
|
||||
sc_module(name), instr_bus("instr_bus"), default_time(10, SC_NS) {
|
||||
CPU::CPU(sc_core::sc_module_name name, uint32_t PC) :
|
||||
sc_module(name), instr_bus("instr_bus"), default_time(10,
|
||||
sc_core::SC_NS) {
|
||||
register_bank = new Registers();
|
||||
exec = new Execute("Execute", register_bank);
|
||||
mem_intf = new MemoryInterface();
|
||||
|
||||
perf = Performance::getInstance();
|
||||
log = Log::getInstance();
|
||||
|
||||
|
@ -24,9 +34,10 @@ CPU::CPU(sc_module_name name, uint32_t PC) :
|
|||
&CPU::invalidate_direct_mem_ptr);
|
||||
|
||||
inst = new Instruction(0);
|
||||
c_inst = new C_Instruction(0);
|
||||
m_inst = new M_Instruction(0);
|
||||
a_inst = new A_Instruction(0);
|
||||
exec = new BASE_ISA(0, register_bank, mem_intf);
|
||||
c_inst = new C_extension(0, register_bank, mem_intf);
|
||||
m_inst = new M_extension(0, register_bank, mem_intf);
|
||||
a_inst = new A_extension(0, register_bank, mem_intf);
|
||||
|
||||
m_qk = new tlm_utils::tlm_quantumkeeper();
|
||||
|
||||
|
@ -34,11 +45,19 @@ CPU::CPU(sc_module_name name, uint32_t PC) :
|
|||
}
|
||||
|
||||
CPU::~CPU() {
|
||||
cout << "*********************************************" << endl;
|
||||
std::cout << "*********************************************" << std::endl;
|
||||
register_bank->dump();
|
||||
cout << "end time: " << sc_time_stamp() << endl;
|
||||
std::cout << "end time: " << sc_core::sc_time_stamp() << std::endl;
|
||||
perf->dump();
|
||||
cout << "*********************************************" << endl;
|
||||
std::cout << "*********************************************" << std::endl;
|
||||
delete register_bank;
|
||||
delete mem_intf;
|
||||
delete inst;
|
||||
delete exec;
|
||||
delete c_inst;
|
||||
delete m_inst;
|
||||
delete a_inst;
|
||||
delete m_qk;
|
||||
}
|
||||
|
||||
bool CPU::cpu_process_IRQ() {
|
||||
|
@ -49,7 +68,7 @@ bool CPU::cpu_process_IRQ() {
|
|||
if (interrupt == true) {
|
||||
csr_temp = register_bank->getCSR(CSR_MSTATUS);
|
||||
if ((csr_temp & MSTATUS_MIE) == 0) {
|
||||
log->SC_log(Log::DEBUG) << "interrupt delayed" << endl;
|
||||
log->SC_log(Log::DEBUG) << "interrupt delayed" << std::endl;
|
||||
return ret_value;
|
||||
}
|
||||
|
||||
|
@ -58,13 +77,13 @@ bool CPU::cpu_process_IRQ() {
|
|||
if ((csr_temp & MIP_MEIP) == 0) {
|
||||
csr_temp |= MIP_MEIP; // MEIP bit in MIP register (11th bit)
|
||||
register_bank->setCSR(CSR_MIP, csr_temp);
|
||||
log->SC_log(Log::DEBUG) << "Interrupt!" << endl;
|
||||
log->SC_log(Log::DEBUG) << "Interrupt!" << std::endl;
|
||||
|
||||
/* updated MEPC register */
|
||||
old_pc = register_bank->getPC();
|
||||
register_bank->setCSR(CSR_MEPC, old_pc);
|
||||
log->SC_log(Log::INFO) << "Old PC Value 0x" << hex << old_pc
|
||||
<< endl;
|
||||
log->SC_log(Log::INFO) << "Old PC Value 0x" << std::hex << old_pc
|
||||
<< std::endl;
|
||||
|
||||
/* update MCAUSE register */
|
||||
register_bank->setCSR(CSR_MCAUSE, 0x80000000);
|
||||
|
@ -72,8 +91,8 @@ bool CPU::cpu_process_IRQ() {
|
|||
/* set new PC address */
|
||||
new_pc = register_bank->getCSR(CSR_MTVEC);
|
||||
//new_pc = new_pc & 0xFFFFFFFC; // last two bits always to 0
|
||||
log->SC_log(Log::DEBUG) << "NEW PC Value 0x" << hex << new_pc
|
||||
<< endl;
|
||||
log->SC_log(Log::DEBUG) << "NEW PC Value 0x" << std::hex << new_pc
|
||||
<< std::endl;
|
||||
register_bank->setPC(new_pc);
|
||||
|
||||
ret_value = true;
|
||||
|
@ -92,376 +111,11 @@ bool CPU::cpu_process_IRQ() {
|
|||
return ret_value;
|
||||
}
|
||||
|
||||
bool CPU::process_c_instruction(Instruction &inst) {
|
||||
bool PC_not_affected = true;
|
||||
|
||||
c_inst->setInstr(inst.getInstr());
|
||||
|
||||
switch (c_inst->decode()) {
|
||||
case OP_C_ADDI4SPN:
|
||||
PC_not_affected = exec->C_ADDI4SPN(inst);
|
||||
break;
|
||||
case OP_C_LW:
|
||||
exec->LW(inst, true);
|
||||
break;
|
||||
case OP_C_SW:
|
||||
exec->SW(inst, true);
|
||||
break;
|
||||
case OP_C_ADDI:
|
||||
exec->ADDI(inst, true);
|
||||
break;
|
||||
case OP_C_JAL:
|
||||
exec->JAL(inst, true, 1);
|
||||
PC_not_affected = false;
|
||||
break;
|
||||
case OP_C_J:
|
||||
exec->JAL(inst, true, 0);
|
||||
PC_not_affected = false;
|
||||
break;
|
||||
case OP_C_LI:
|
||||
exec->C_LI(inst);
|
||||
break;
|
||||
case OP_C_SLLI:
|
||||
exec->C_SLLI(inst);
|
||||
break;
|
||||
case OP_C_LWSP:
|
||||
exec->C_LWSP(inst);
|
||||
break;
|
||||
case OP_C_JR:
|
||||
exec->C_JR(inst);
|
||||
PC_not_affected = false;
|
||||
break;
|
||||
case OP_C_MV:
|
||||
exec->C_MV(inst);
|
||||
break;
|
||||
case OP_C_JALR:
|
||||
exec->JALR(inst, true);
|
||||
PC_not_affected = false;
|
||||
break;
|
||||
case OP_C_ADD:
|
||||
exec->C_ADD(inst);
|
||||
break;
|
||||
case OP_C_SWSP:
|
||||
exec->C_SWSP(inst);
|
||||
break;
|
||||
case OP_C_ADDI16SP:
|
||||
exec->C_ADDI16SP(inst);
|
||||
break;
|
||||
case OP_C_BEQZ:
|
||||
exec->C_BEQZ(inst);
|
||||
PC_not_affected = false;
|
||||
break;
|
||||
case OP_C_BNEZ:
|
||||
exec->C_BNEZ(inst);
|
||||
PC_not_affected = false;
|
||||
break;
|
||||
case OP_C_SRLI:
|
||||
exec->C_SRLI(inst);
|
||||
break;
|
||||
case OP_C_SRAI:
|
||||
exec->C_SRAI(inst);
|
||||
break;
|
||||
case OP_C_ANDI:
|
||||
exec->C_ANDI(inst);
|
||||
break;
|
||||
case OP_C_SUB:
|
||||
exec->C_SUB(inst);
|
||||
break;
|
||||
case OP_C_XOR:
|
||||
exec->C_XOR(inst);
|
||||
break;
|
||||
case OP_C_OR:
|
||||
exec->C_OR(inst);
|
||||
break;
|
||||
case OP_C_AND:
|
||||
exec->C_AND(inst);
|
||||
break;
|
||||
default:
|
||||
std::cout << "C instruction not implemented yet" << endl;
|
||||
inst.dump();
|
||||
exec->NOP(inst);
|
||||
//sc_stop();
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return PC_not_affected;
|
||||
}
|
||||
|
||||
bool CPU::process_m_instruction(Instruction &inst) {
|
||||
bool PC_not_affected = true;
|
||||
|
||||
m_inst->setInstr(inst.getInstr());
|
||||
|
||||
switch (m_inst->decode()) {
|
||||
case OP_M_MUL:
|
||||
exec->M_MUL(inst);
|
||||
break;
|
||||
case OP_M_MULH:
|
||||
exec->M_MULH(inst);
|
||||
break;
|
||||
case OP_M_MULHSU:
|
||||
exec->M_MULHSU(inst);
|
||||
break;
|
||||
case OP_M_MULHU:
|
||||
exec->M_MULHU(inst);
|
||||
break;
|
||||
case OP_M_DIV:
|
||||
exec->M_DIV(inst);
|
||||
break;
|
||||
case OP_M_DIVU:
|
||||
exec->M_DIVU(inst);
|
||||
break;
|
||||
case OP_M_REM:
|
||||
exec->M_REM(inst);
|
||||
break;
|
||||
case OP_M_REMU:
|
||||
exec->M_REMU(inst);
|
||||
break;
|
||||
default:
|
||||
std::cout << "M instruction not implemented yet" << endl;
|
||||
inst.dump();
|
||||
exec->NOP(inst);
|
||||
break;
|
||||
}
|
||||
|
||||
return PC_not_affected;
|
||||
}
|
||||
|
||||
bool CPU::process_a_instruction(Instruction inst) {
|
||||
bool PC_not_affected = true;
|
||||
|
||||
a_inst->setInstr(inst.getInstr());
|
||||
|
||||
switch (a_inst->decode()) {
|
||||
case OP_A_LR:
|
||||
exec->A_LR(inst);
|
||||
break;
|
||||
case OP_A_SC:
|
||||
exec->A_SC(inst);
|
||||
break;
|
||||
case OP_A_AMOSWAP:
|
||||
exec->A_AMOSWAP(inst);
|
||||
break;
|
||||
case OP_A_AMOADD:
|
||||
exec->A_AMOADD(inst);
|
||||
break;
|
||||
case OP_A_AMOXOR:
|
||||
exec->A_AMOXOR(inst);
|
||||
break;
|
||||
case OP_A_AMOAND:
|
||||
exec->A_AMOAND(inst);
|
||||
break;
|
||||
case OP_A_AMOOR:
|
||||
exec->A_AMOOR(inst);
|
||||
break;
|
||||
case OP_A_AMOMIN:
|
||||
exec->A_AMOMIN(inst);
|
||||
break;
|
||||
case OP_A_AMOMAX:
|
||||
exec->A_AMOMAX(inst);
|
||||
break;
|
||||
case OP_A_AMOMINU:
|
||||
exec->A_AMOMINU(inst);
|
||||
break;
|
||||
case OP_A_AMOMAXU:
|
||||
exec->A_AMOMAXU(inst);
|
||||
break;
|
||||
default:
|
||||
std::cout << "A instruction not implemented yet" << endl;
|
||||
inst.dump();
|
||||
exec->NOP(inst);
|
||||
break;
|
||||
}
|
||||
|
||||
return PC_not_affected;
|
||||
}
|
||||
|
||||
bool CPU::process_base_instruction(Instruction &inst) {
|
||||
bool PC_not_affected = true;
|
||||
|
||||
switch (inst.decode()) {
|
||||
case OP_LUI:
|
||||
exec->LUI(inst);
|
||||
break;
|
||||
case OP_AUIPC:
|
||||
exec->AUIPC(inst);
|
||||
break;
|
||||
case OP_JAL:
|
||||
exec->JAL(inst);
|
||||
PC_not_affected = false;
|
||||
break;
|
||||
case OP_JALR:
|
||||
exec->JALR(inst);
|
||||
PC_not_affected = false;
|
||||
break;
|
||||
case OP_BEQ:
|
||||
exec->BEQ(inst);
|
||||
PC_not_affected = false;
|
||||
break;
|
||||
case OP_BNE:
|
||||
exec->BNE(inst);
|
||||
PC_not_affected = false;
|
||||
break;
|
||||
case OP_BLT:
|
||||
exec->BLT(inst);
|
||||
PC_not_affected = false;
|
||||
break;
|
||||
case OP_BGE:
|
||||
exec->BGE(inst);
|
||||
PC_not_affected = false;
|
||||
break;
|
||||
case OP_BLTU:
|
||||
exec->BLTU(inst);
|
||||
PC_not_affected = false;
|
||||
break;
|
||||
case OP_BGEU:
|
||||
exec->BGEU(inst);
|
||||
PC_not_affected = false;
|
||||
break;
|
||||
case OP_LB:
|
||||
exec->LB(inst);
|
||||
break;
|
||||
case OP_LH:
|
||||
exec->LH(inst);
|
||||
break;
|
||||
case OP_LW:
|
||||
exec->LW(inst);
|
||||
break;
|
||||
case OP_LBU:
|
||||
exec->LBU(inst);
|
||||
break;
|
||||
case OP_LHU:
|
||||
exec->LHU(inst);
|
||||
break;
|
||||
case OP_SB:
|
||||
exec->SB(inst);
|
||||
break;
|
||||
case OP_SH:
|
||||
exec->SH(inst);
|
||||
break;
|
||||
case OP_SW:
|
||||
exec->SW(inst);
|
||||
break;
|
||||
case OP_ADDI:
|
||||
exec->ADDI(inst);
|
||||
break;
|
||||
case OP_SLTI:
|
||||
exec->SLTI(inst);
|
||||
break;
|
||||
case OP_SLTIU:
|
||||
exec->SLTIU(inst);
|
||||
break;
|
||||
case OP_XORI:
|
||||
exec->XORI(inst);
|
||||
break;
|
||||
case OP_ORI:
|
||||
exec->ORI(inst);
|
||||
break;
|
||||
case OP_ANDI:
|
||||
exec->ANDI(inst);
|
||||
break;
|
||||
case OP_SLLI:
|
||||
PC_not_affected = exec->SLLI(inst);
|
||||
break;
|
||||
case OP_SRLI:
|
||||
exec->SRLI(inst);
|
||||
break;
|
||||
case OP_SRAI:
|
||||
exec->SRAI(inst);
|
||||
break;
|
||||
case OP_ADD:
|
||||
exec->ADD(inst);
|
||||
break;
|
||||
case OP_SUB:
|
||||
exec->SUB(inst);
|
||||
break;
|
||||
case OP_SLL:
|
||||
exec->SLL(inst);
|
||||
break;
|
||||
case OP_SLT:
|
||||
exec->SLT(inst);
|
||||
break;
|
||||
case OP_SLTU:
|
||||
exec->SLTU(inst);
|
||||
break;
|
||||
case OP_XOR:
|
||||
exec->XOR(inst);
|
||||
break;
|
||||
case OP_SRL:
|
||||
exec->SRL(inst);
|
||||
break;
|
||||
case OP_SRA:
|
||||
exec->SRA(inst);
|
||||
break;
|
||||
case OP_OR:
|
||||
exec->OR(inst);
|
||||
break;
|
||||
case OP_AND:
|
||||
exec->AND(inst);
|
||||
break;
|
||||
case OP_FENCE:
|
||||
exec->FENCE(inst);
|
||||
break;
|
||||
case OP_ECALL:
|
||||
exec->ECALL(inst);
|
||||
break;
|
||||
case OP_EBREAK:
|
||||
exec->EBREAK(inst);
|
||||
break;
|
||||
case OP_CSRRW:
|
||||
exec->CSRRW(inst);
|
||||
break;
|
||||
case OP_CSRRS:
|
||||
exec->CSRRS(inst);
|
||||
break;
|
||||
case OP_CSRRC:
|
||||
exec->CSRRC(inst);
|
||||
break;
|
||||
case OP_CSRRWI:
|
||||
exec->CSRRWI(inst);
|
||||
break;
|
||||
case OP_CSRRSI:
|
||||
exec->CSRRSI(inst);
|
||||
break;
|
||||
case OP_CSRRCI:
|
||||
exec->CSRRCI(inst);
|
||||
break;
|
||||
|
||||
case OP_MRET:
|
||||
exec->MRET(inst);
|
||||
PC_not_affected = false;
|
||||
break;
|
||||
case OP_SRET:
|
||||
exec->SRET(inst);
|
||||
PC_not_affected = false;
|
||||
break;
|
||||
case OP_WFI:
|
||||
exec->WFI(inst);
|
||||
break;
|
||||
case OP_SFENCE:
|
||||
exec->SFENCE(inst);
|
||||
break;
|
||||
default:
|
||||
std::cout << "Wrong instruction" << endl;
|
||||
inst.dump();
|
||||
exec->NOP(inst);
|
||||
//sc_stop();
|
||||
break;
|
||||
}
|
||||
|
||||
return PC_not_affected;
|
||||
}
|
||||
|
||||
/**
|
||||
* main thread for CPU simulation
|
||||
* @brief CPU mai thread
|
||||
*/
|
||||
void CPU::CPU_thread(void) {
|
||||
|
||||
tlm::tlm_generic_payload *trans = new tlm::tlm_generic_payload;
|
||||
uint32_t INSTR;
|
||||
sc_time delay = SC_ZERO_TIME;
|
||||
sc_core::sc_time delay = sc_core::SC_ZERO_TIME;
|
||||
bool PC_not_affected = false;
|
||||
bool incPCby2 = false;
|
||||
tlm::tlm_dmi dmi_data;
|
||||
|
@ -475,7 +129,6 @@ void CPU::CPU_thread(void) {
|
|||
trans->set_dmi_allowed(false); // Mandatory initial value
|
||||
trans->set_response_status(tlm::TLM_INCOMPLETE_RESPONSE);
|
||||
|
||||
//Instruction inst(0);
|
||||
m_qk->reset();
|
||||
|
||||
while (1) {
|
||||
|
@ -502,7 +155,7 @@ void CPU::CPU_thread(void) {
|
|||
|
||||
perf->codeMemoryRead();
|
||||
|
||||
log->SC_log(Log::INFO) << "PC: 0x" << hex << register_bank->getPC()
|
||||
log->SC_log(Log::INFO) << "PC: 0x" << std::hex << register_bank->getPC()
|
||||
<< ". ";
|
||||
|
||||
inst->setInstr(INSTR);
|
||||
|
@ -510,26 +163,26 @@ void CPU::CPU_thread(void) {
|
|||
/* check what type of instruction is and execute it */
|
||||
switch (inst->check_extension()) {
|
||||
case BASE_EXTENSION:
|
||||
PC_not_affected = process_base_instruction(*inst);
|
||||
PC_not_affected = exec->process_instruction(*inst);
|
||||
incPCby2 = false;
|
||||
break;
|
||||
case C_EXTENSION:
|
||||
PC_not_affected = process_c_instruction(*inst);
|
||||
PC_not_affected = c_inst->process_instruction(*inst);
|
||||
incPCby2 = true;
|
||||
break;
|
||||
case M_EXTENSION:
|
||||
PC_not_affected = process_m_instruction(*inst);
|
||||
PC_not_affected = m_inst->process_instruction(*inst);
|
||||
incPCby2 = false;
|
||||
break;
|
||||
case A_EXTENSION:
|
||||
PC_not_affected = process_a_instruction(*inst);
|
||||
PC_not_affected = a_inst->process_instruction(*inst);
|
||||
incPCby2 = false;
|
||||
break;
|
||||
default:
|
||||
std::cout << "Extension not implemented yet" << std::endl;
|
||||
inst->dump();
|
||||
exec->NOP(*inst);
|
||||
} // switch (inst.check_extension())
|
||||
exec->NOP();
|
||||
}
|
||||
|
||||
perf->instructionsInc();
|
||||
|
||||
|
@ -549,14 +202,15 @@ void CPU::CPU_thread(void) {
|
|||
m_qk->sync();
|
||||
}
|
||||
#else
|
||||
sc_core::wait(10, SC_NS);
|
||||
sc_core::wait(10, sc_core::SC_NS);
|
||||
|
||||
#endif
|
||||
|
||||
} // while(1)
|
||||
} // CPU_thread
|
||||
|
||||
void CPU::call_interrupt(tlm::tlm_generic_payload &trans, sc_time &delay) {
|
||||
void CPU::call_interrupt(tlm::tlm_generic_payload &trans,
|
||||
sc_core::sc_time &delay) {
|
||||
interrupt = true;
|
||||
/* Socket caller send a cause (its id) */
|
||||
memcpy(&int_cause, trans.get_data_ptr(), sizeof(uint32_t));
|
||||
|
|
|
@ -1,146 +0,0 @@
|
|||
#include "C_Instruction.h"
|
||||
|
||||
|
||||
C_Instruction::C_Instruction(sc_uint<32> instr) {
|
||||
m_instr = instr;
|
||||
}
|
||||
|
||||
op_C_Codes C_Instruction::decode() {
|
||||
|
||||
switch (opcode()) {
|
||||
|
||||
case 0b00:
|
||||
switch(get_funct3()) {
|
||||
case C_ADDI4SPN:
|
||||
return OP_C_ADDI4SPN;
|
||||
break;
|
||||
case C_FLD:
|
||||
return OP_C_FLD;
|
||||
break;
|
||||
case C_LW:
|
||||
return OP_C_LW;
|
||||
break;
|
||||
case C_FLW:
|
||||
return OP_C_FLW;
|
||||
break;
|
||||
case C_FSD:
|
||||
return OP_C_FSD;
|
||||
break;
|
||||
case C_SW:
|
||||
return OP_C_SW;
|
||||
break;
|
||||
case C_FSW:
|
||||
return OP_C_FSW;
|
||||
break;
|
||||
default:
|
||||
return OP_C_ERROR;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0b01:
|
||||
switch(get_funct3()) {
|
||||
case C_ADDI:
|
||||
return OP_C_ADDI;
|
||||
break;
|
||||
case C_JAL:
|
||||
return OP_C_JAL;
|
||||
break;
|
||||
case C_LI:
|
||||
return OP_C_LI;
|
||||
break;
|
||||
case C_ADDI16SP:
|
||||
return OP_C_ADDI16SP;
|
||||
break;
|
||||
case C_SRLI:
|
||||
switch(m_instr.range(11,10)) {
|
||||
case C_2_SRLI:
|
||||
return OP_C_SRLI;
|
||||
break;
|
||||
case C_2_SRAI:
|
||||
return OP_C_SRAI;
|
||||
break;
|
||||
case C_2_ANDI:
|
||||
return OP_C_ANDI;
|
||||
break;
|
||||
case C_2_SUB:
|
||||
switch(m_instr.range(6,5)) {
|
||||
case C_3_SUB:
|
||||
return OP_C_SUB;
|
||||
break;
|
||||
case C_3_XOR:
|
||||
return OP_C_XOR;
|
||||
break;
|
||||
case C_3_OR:
|
||||
return OP_C_OR;
|
||||
break;
|
||||
case C_3_AND:
|
||||
return OP_C_AND;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case C_J:
|
||||
return OP_C_J;
|
||||
break;
|
||||
case C_BEQZ:
|
||||
return OP_C_BEQZ;
|
||||
break;
|
||||
case C_BNEZ:
|
||||
return OP_C_BNEZ;
|
||||
break;
|
||||
default:
|
||||
return OP_C_ERROR;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0b10:
|
||||
switch(get_funct3()) {
|
||||
case C_SLLI:
|
||||
return OP_C_SLLI;
|
||||
break;
|
||||
case C_FLDSP:
|
||||
case C_LWSP:
|
||||
return OP_C_LWSP;
|
||||
break;
|
||||
case C_FLWSP:
|
||||
return OP_C_FLWSP;
|
||||
break;
|
||||
case C_JR:
|
||||
if (m_instr[12] == 0) {
|
||||
if (m_instr.range(6,2) == 0) {
|
||||
return OP_C_JR;
|
||||
} else {
|
||||
return OP_C_MV;
|
||||
}
|
||||
} else {
|
||||
if (m_instr.range(11,2) == 0) {
|
||||
return OP_C_EBREAK;
|
||||
} else if (m_instr.range(6,2) == 0) {
|
||||
return OP_C_JALR;
|
||||
} else {
|
||||
return OP_C_ADD;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case C_FDSP:
|
||||
break;
|
||||
case C_SWSP:
|
||||
return OP_C_SWSP;
|
||||
break;
|
||||
case C_FWWSP:
|
||||
default:
|
||||
return OP_C_ERROR;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return OP_C_ERROR;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return OP_C_ERROR;
|
||||
}
|
|
@ -0,0 +1,756 @@
|
|||
/*!
|
||||
\file C_extension.cpp
|
||||
\brief Implement C extensions part of the RISC-V
|
||||
\author Màrius Montón
|
||||
\date August 2018
|
||||
*/
|
||||
#include "C_extension.h"
|
||||
|
||||
op_C_Codes C_extension::decode() {
|
||||
|
||||
switch (opcode()) {
|
||||
|
||||
case 0b00:
|
||||
switch (get_funct3()) {
|
||||
case C_ADDI4SPN:
|
||||
return OP_C_ADDI4SPN;
|
||||
break;
|
||||
case C_FLD:
|
||||
return OP_C_FLD;
|
||||
break;
|
||||
case C_LW:
|
||||
return OP_C_LW;
|
||||
break;
|
||||
case C_FLW:
|
||||
return OP_C_FLW;
|
||||
break;
|
||||
case C_FSD:
|
||||
return OP_C_FSD;
|
||||
break;
|
||||
case C_SW:
|
||||
return OP_C_SW;
|
||||
break;
|
||||
case C_FSW:
|
||||
return OP_C_FSW;
|
||||
break;
|
||||
default:
|
||||
return OP_C_ERROR;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0b01:
|
||||
switch (get_funct3()) {
|
||||
case C_ADDI:
|
||||
return OP_C_ADDI;
|
||||
break;
|
||||
case C_JAL:
|
||||
return OP_C_JAL;
|
||||
break;
|
||||
case C_LI:
|
||||
return OP_C_LI;
|
||||
break;
|
||||
case C_ADDI16SP:
|
||||
return OP_C_ADDI16SP;
|
||||
break;
|
||||
case C_SRLI:
|
||||
switch (m_instr.range(11, 10)) {
|
||||
case C_2_SRLI:
|
||||
return OP_C_SRLI;
|
||||
break;
|
||||
case C_2_SRAI:
|
||||
return OP_C_SRAI;
|
||||
break;
|
||||
case C_2_ANDI:
|
||||
return OP_C_ANDI;
|
||||
break;
|
||||
case C_2_SUB:
|
||||
switch (m_instr.range(6, 5)) {
|
||||
case C_3_SUB:
|
||||
return OP_C_SUB;
|
||||
break;
|
||||
case C_3_XOR:
|
||||
return OP_C_XOR;
|
||||
break;
|
||||
case C_3_OR:
|
||||
return OP_C_OR;
|
||||
break;
|
||||
case C_3_AND:
|
||||
return OP_C_AND;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case C_J:
|
||||
return OP_C_J;
|
||||
break;
|
||||
case C_BEQZ:
|
||||
return OP_C_BEQZ;
|
||||
break;
|
||||
case C_BNEZ:
|
||||
return OP_C_BNEZ;
|
||||
break;
|
||||
default:
|
||||
return OP_C_ERROR;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0b10:
|
||||
switch (get_funct3()) {
|
||||
case C_SLLI:
|
||||
return OP_C_SLLI;
|
||||
break;
|
||||
case C_FLDSP:
|
||||
case C_LWSP:
|
||||
return OP_C_LWSP;
|
||||
break;
|
||||
case C_FLWSP:
|
||||
return OP_C_FLWSP;
|
||||
break;
|
||||
case C_JR:
|
||||
if (m_instr[12] == 0) {
|
||||
if (m_instr.range(6, 2) == 0) {
|
||||
return OP_C_JR;
|
||||
} else {
|
||||
return OP_C_MV;
|
||||
}
|
||||
} else {
|
||||
if (m_instr.range(11, 2) == 0) {
|
||||
return OP_C_EBREAK;
|
||||
} else if (m_instr.range(6, 2) == 0) {
|
||||
return OP_C_JALR;
|
||||
} else {
|
||||
return OP_C_ADD;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case C_FDSP:
|
||||
break;
|
||||
case C_SWSP:
|
||||
return OP_C_SWSP;
|
||||
break;
|
||||
case C_FWWSP:
|
||||
default:
|
||||
return OP_C_ERROR;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return OP_C_ERROR;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return OP_C_ERROR;
|
||||
}
|
||||
|
||||
bool C_extension::Exec_C_JR() {
|
||||
uint32_t mem_addr = 0;
|
||||
int rs1;
|
||||
int new_pc;
|
||||
|
||||
rs1 = get_rs1();
|
||||
mem_addr = 0;
|
||||
|
||||
new_pc = (regs->getValue(rs1) + mem_addr) & 0xFFFFFFFE;
|
||||
regs->setPC(new_pc);
|
||||
|
||||
if (log->getLogLevel() > Log::INFO) {
|
||||
log->SC_log(Log::INFO) << "JR: PC <- 0x" << std::hex << new_pc << std::endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool C_extension::Exec_C_MV() {
|
||||
int rd, rs1, rs2;
|
||||
uint32_t calc;
|
||||
|
||||
rd = get_rd();
|
||||
rs1 = 0;
|
||||
rs2 = get_rs2();
|
||||
|
||||
calc = regs->getValue(rs1) + regs->getValue(rs2);
|
||||
regs->setValue(rd, calc);
|
||||
|
||||
if (log->getLogLevel() > Log::INFO) {
|
||||
log->SC_log(Log::INFO) << "C.MV: x" << std::dec << rs1 << "(0x" << std::hex
|
||||
<< regs->getValue(rs1) << ") + x" << std::dec << rs2 << "(0x"
|
||||
<< std::hex << regs->getValue(rs2) << ") -> x" << std::dec << rd
|
||||
<< "(0x" << std::hex << calc << ")" << std::endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool C_extension::Exec_C_ADD() {
|
||||
int rd, rs1, rs2;
|
||||
uint32_t calc;
|
||||
|
||||
rd = get_rs1();
|
||||
rs1 = get_rs1();
|
||||
rs2 = get_rs2();
|
||||
|
||||
calc = regs->getValue(rs1) + regs->getValue(rs2);
|
||||
regs->setValue(rd, calc);
|
||||
|
||||
if (log->getLogLevel() > Log::INFO) {
|
||||
log->SC_log(Log::INFO) << "C.ADD: x" << std::dec << rs1 << " + x" << rs2
|
||||
<< " -> x" << rd << "(0x" << std::hex << calc << ")" << std::endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool C_extension::Exec_C_LWSP() {
|
||||
uint32_t mem_addr = 0;
|
||||
int rd, rs1;
|
||||
int32_t imm = 0;
|
||||
uint32_t data;
|
||||
|
||||
// lw rd, offset[7:2](x2)
|
||||
|
||||
rd = get_rd();
|
||||
rs1 = 2;
|
||||
imm = get_imm_LWSP();
|
||||
|
||||
mem_addr = imm + regs->getValue(rs1);
|
||||
data = mem_intf->readDataMem(mem_addr, 4);
|
||||
|
||||
regs->setValue(rd, data);
|
||||
|
||||
if (log->getLogLevel() > Log::INFO) {
|
||||
log->SC_log(Log::INFO) << "C.LWSP: x" << std::dec << rs1 << " + " << imm
|
||||
<< " (@0x" << std::hex << mem_addr << std::dec << ") -> x" << rd
|
||||
<< "(" << std::hex << data << ")" << std::dec << std::endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool C_extension::Exec_C_ADDI4SPN() {
|
||||
int rd, rs1;
|
||||
int32_t imm = 0;
|
||||
int32_t calc;
|
||||
|
||||
rd = get_rdp();
|
||||
rs1 = 2;
|
||||
imm = get_imm_ADDI4SPN();
|
||||
|
||||
if (imm == 0) {
|
||||
RaiseException(EXCEPTION_CAUSE_ILLEGAL_INSTRUCTION, m_instr);
|
||||
return false;
|
||||
}
|
||||
|
||||
calc = regs->getValue(rs1) + imm;
|
||||
regs->setValue(rd, calc);
|
||||
|
||||
if (log->getLogLevel() > Log::INFO) {
|
||||
log->SC_log(Log::INFO) << std::dec << "C.ADDI4SPN: x" << rs1 << "(0x"
|
||||
<< std::hex << regs->getValue(rs1) << ") + " << std::dec << imm
|
||||
<< " -> x" << rd << "(0x" << std::hex << calc << ")" << std::endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool C_extension::Exec_C_ADDI16SP() {
|
||||
// addi x2, x2, nzimm[9:4]
|
||||
int rd, rs1;
|
||||
int32_t imm = 0;
|
||||
int32_t calc;
|
||||
|
||||
if (get_rd() == 2) {
|
||||
rd = 2;
|
||||
rs1 = 2;
|
||||
imm = get_imm_ADDI16SP();
|
||||
|
||||
calc = regs->getValue(rs1) + imm;
|
||||
regs->setValue(rd, calc);
|
||||
|
||||
log->SC_log(Log::INFO) << std::dec << "C.ADDI16SP: x" << rs1 << " + "
|
||||
<< std::dec << imm << " -> x" << rd << "(0x" << std::hex << calc
|
||||
<< ")" << std::endl;
|
||||
} else {
|
||||
/* C.LUI OPCODE */
|
||||
rd = get_rd();
|
||||
imm = get_imm_LUI();
|
||||
regs->setValue(rd, imm);
|
||||
log->SC_log(Log::INFO) << std::dec << "C.LUI x" << rd << " <- 0x"
|
||||
<< std::hex << imm << std::endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool C_extension::Exec_C_SWSP() {
|
||||
// sw rs2, offset(x2)
|
||||
uint32_t mem_addr = 0;
|
||||
int rs1, rs2;
|
||||
int32_t imm = 0;
|
||||
uint32_t data;
|
||||
|
||||
rs1 = 2;
|
||||
rs2 = get_rs2();
|
||||
imm = get_imm_CSS();
|
||||
|
||||
mem_addr = imm + regs->getValue(rs1);
|
||||
data = regs->getValue(rs2);
|
||||
|
||||
mem_intf->writeDataMem(mem_addr, data, 4);
|
||||
|
||||
if (log->getLogLevel() > Log::INFO) {
|
||||
log->SC_log(Log::INFO) << std::dec << "C.SWSP: x" << rs2 << "(0x"
|
||||
<< std::hex << data << ") -> x" << std::dec << rs1 << " + " << imm
|
||||
<< " (@0x" << std::hex << mem_addr << std::dec << ")" << std::endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool C_extension::Exec_C_BEQZ() {
|
||||
int rs1;
|
||||
int new_pc = 0;
|
||||
uint32_t val1;
|
||||
|
||||
rs1 = get_rs1p();
|
||||
val1 = regs->getValue(rs1);
|
||||
|
||||
if (val1 == 0) {
|
||||
new_pc = regs->getPC() + get_imm_CB();
|
||||
regs->setPC(new_pc);
|
||||
} else {
|
||||
regs->incPC(true); //PC <- PC + 2
|
||||
new_pc = regs->getPC();
|
||||
}
|
||||
|
||||
if (log->getLogLevel() > Log::INFO) {
|
||||
log->SC_log(Log::INFO) << "C.BEQZ: x" << std::dec << rs1 << "(" << val1
|
||||
<< ") == 0? -> PC (0x" << std::hex << new_pc << ")" << std::dec
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool C_extension::Exec_C_BNEZ() {
|
||||
int rs1;
|
||||
int new_pc = 0;
|
||||
uint32_t val1;
|
||||
|
||||
rs1 = get_rs1p();
|
||||
val1 = regs->getValue(rs1);
|
||||
|
||||
if (val1 != 0) {
|
||||
new_pc = regs->getPC() + get_imm_CB();
|
||||
regs->setPC(new_pc);
|
||||
} else {
|
||||
regs->incPC(true); //PC <- PC +2
|
||||
new_pc = regs->getPC();
|
||||
}
|
||||
|
||||
if (log->getLogLevel() > Log::INFO) {
|
||||
log->SC_log(Log::INFO) << "C.BNEZ: x" << std::dec << rs1 << "(0x"
|
||||
<< std::hex << val1 << ") != 0? -> PC (0x" << std::hex << new_pc
|
||||
<< ")" << std::dec << std::endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool C_extension::Exec_C_LI() {
|
||||
int rd, rs1;
|
||||
int32_t imm = 0;
|
||||
int32_t calc;
|
||||
|
||||
rd = get_rd();
|
||||
rs1 = 0;
|
||||
imm = get_imm_ADDI();
|
||||
|
||||
calc = regs->getValue(rs1) + imm;
|
||||
regs->setValue(rd, calc);
|
||||
|
||||
if (log->getLogLevel() > Log::INFO) {
|
||||
log->SC_log(Log::INFO) << std::dec << "C.LI: x" << rs1 << "("
|
||||
<< regs->getValue(rs1) << ") + " << imm << " -> x" << rd << "("
|
||||
<< calc << ")" << std::endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool C_extension::Exec_C_SRLI() {
|
||||
int rd, rs1, rs2;
|
||||
uint32_t shift;
|
||||
uint32_t calc;
|
||||
|
||||
rd = get_rs1p();
|
||||
rs1 = get_rs1p();
|
||||
rs2 = get_rs2();
|
||||
|
||||
shift = rs2 & 0x1F;
|
||||
|
||||
calc = ((uint32_t) regs->getValue(rs1)) >> shift;
|
||||
regs->setValue(rd, calc);
|
||||
|
||||
if (log->getLogLevel() > Log::INFO) {
|
||||
log->SC_log(Log::INFO) << "C.SRLI: x" << rs1 << " >> " << shift << " -> x"
|
||||
<< rd << std::endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool C_extension::Exec_C_SRAI() {
|
||||
int rd, rs1, rs2;
|
||||
uint32_t shift;
|
||||
int32_t calc;
|
||||
|
||||
rd = get_rs1p();
|
||||
rs1 = get_rs1p();
|
||||
rs2 = get_rs2();
|
||||
|
||||
shift = rs2 & 0x1F;
|
||||
|
||||
calc = (int32_t) regs->getValue(rs1) >> shift;
|
||||
regs->setValue(rd, calc);
|
||||
|
||||
if (log->getLogLevel() > Log::INFO) {
|
||||
log->SC_log(Log::INFO) << "C.SRAI: x" << rs1 << " >> " << std::dec << shift
|
||||
<< " -> x" << rd << "(" << calc << ")" << std::endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool C_extension::Exec_C_SLLI() {
|
||||
int rd, rs1, rs2;
|
||||
uint32_t shift;
|
||||
uint32_t calc;
|
||||
|
||||
rd = get_rs1p();
|
||||
rs1 = get_rs1p();
|
||||
rs2 = get_imm_ADDI();
|
||||
|
||||
shift = rs2 & 0x1F;
|
||||
|
||||
calc = ((uint32_t) regs->getValue(rs1)) << shift;
|
||||
regs->setValue(rd, calc);
|
||||
|
||||
if (log->getLogLevel() > Log::INFO) {
|
||||
log->SC_log(Log::INFO) << "C.SLLI: x" << std::dec << rs1 << " << " << shift
|
||||
<< " -> x" << rd << "(0x" << calc << ")" << std::endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool C_extension::Exec_C_ANDI() {
|
||||
int rd, rs1;
|
||||
uint32_t imm;
|
||||
uint32_t aux;
|
||||
uint32_t calc;
|
||||
|
||||
rd = get_rs1p();
|
||||
rs1 = get_rs1p();
|
||||
imm = get_imm_ADDI();
|
||||
|
||||
aux = regs->getValue(rs1);
|
||||
calc = aux & imm;
|
||||
regs->setValue(rd, calc);
|
||||
|
||||
if (log->getLogLevel() > Log::INFO) {
|
||||
log->SC_log(Log::INFO) << "C.ANDI: x" << rs1 << "(" << aux << ") AND "
|
||||
<< imm << " -> x" << rd << std::endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool C_extension::Exec_C_SUB() {
|
||||
int rd, rs1, rs2;
|
||||
uint32_t calc;
|
||||
|
||||
rd = get_rs1p();
|
||||
rs1 = get_rs1p();
|
||||
rs2 = get_rs2p();
|
||||
|
||||
calc = regs->getValue(rs1) - regs->getValue(rs2);
|
||||
regs->setValue(rd, calc);
|
||||
|
||||
if (log->getLogLevel() > Log::INFO) {
|
||||
log->SC_log(Log::INFO) << "C.SUB: x" << std::dec << rs1 << " - x" << rs2
|
||||
<< " -> x" << rd << std::endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool C_extension::Exec_C_XOR() {
|
||||
int rd, rs1, rs2;
|
||||
uint32_t calc;
|
||||
|
||||
rd = get_rs1p();
|
||||
rs1 = get_rs1p();
|
||||
rs2 = get_rs2p();
|
||||
|
||||
calc = regs->getValue(rs1) ^ regs->getValue(rs2);
|
||||
regs->setValue(rd, calc);
|
||||
|
||||
if (log->getLogLevel() > Log::INFO) {
|
||||
log->SC_log(Log::INFO) << "C.XOR: x" << std::dec << rs1 << " XOR x" << rs2
|
||||
<< "-> x" << rd << std::endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool C_extension::Exec_C_OR() {
|
||||
int rd, rs1, rs2;
|
||||
uint32_t calc;
|
||||
|
||||
rd = get_rs1p();
|
||||
rs1 = get_rs1p();
|
||||
rs2 = get_rs2p();
|
||||
|
||||
calc = regs->getValue(rs1) | regs->getValue(rs2);
|
||||
regs->setValue(rd, calc);
|
||||
|
||||
if (log->getLogLevel() > Log::INFO) {
|
||||
log->SC_log(Log::INFO) << "C_OR: x" << std::dec << rs1 << " OR x" << rs2
|
||||
<< "-> x" << rd << std::endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool C_extension::Exec_C_AND() {
|
||||
int rd, rs1, rs2;
|
||||
uint32_t calc;
|
||||
|
||||
rd = get_rs1p();
|
||||
rs1 = get_rs1p();
|
||||
rs2 = get_rs2p();
|
||||
|
||||
calc = regs->getValue(rs1) & regs->getValue(rs2);
|
||||
regs->setValue(rd, calc);
|
||||
|
||||
if (log->getLogLevel() > Log::INFO) {
|
||||
log->SC_log(Log::INFO) << "C.AND: x" << std::dec << rs1 << " AND x" << rs2
|
||||
<< "-> x" << rd << std::endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool C_extension::Exec_C_ADDI() {
|
||||
int rd, rs1;
|
||||
int32_t imm = 0;
|
||||
int32_t calc;
|
||||
|
||||
rd = get_rd();
|
||||
rs1 = rd;
|
||||
imm = get_imm_ADDI();
|
||||
|
||||
calc = regs->getValue(rs1) + imm;
|
||||
regs->setValue(rd, calc);
|
||||
|
||||
if (log->getLogLevel() > Log::INFO) {
|
||||
log->SC_log(Log::INFO) << "C.ADDI: x" << std::dec << rs1 << " + " << imm
|
||||
<< " -> x" << std::dec << rd << "(0x" << std::hex << calc << ")"
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool C_extension::Exec_C_JALR() {
|
||||
uint32_t mem_addr = 0;
|
||||
int rd, rs1;
|
||||
int new_pc, old_pc;
|
||||
|
||||
rd = 1;
|
||||
rs1 = get_rs1();
|
||||
|
||||
old_pc = regs->getPC();
|
||||
regs->setValue(rd, old_pc + 2);
|
||||
|
||||
new_pc = (regs->getValue(rs1) + mem_addr) & 0xFFFFFFFE;
|
||||
regs->setPC(new_pc);
|
||||
|
||||
if (log->getLogLevel() > Log::INFO) {
|
||||
log->SC_log(Log::INFO) << "C.JALR: x" << std::dec << rd << " <- 0x"
|
||||
<< std::hex << old_pc + 4 << " PC <- 0x" << std::hex << new_pc
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool C_extension::Exec_C_LW() {
|
||||
uint32_t mem_addr = 0;
|
||||
int rd, rs1;
|
||||
int32_t imm = 0;
|
||||
uint32_t data;
|
||||
|
||||
rd = get_rdp();
|
||||
rs1 = get_rs1p();
|
||||
imm = get_imm_L();
|
||||
|
||||
mem_addr = imm + regs->getValue(rs1);
|
||||
data = mem_intf->readDataMem(mem_addr, 4);
|
||||
regs->setValue(rd, data);
|
||||
|
||||
if (log->getLogLevel() > Log::INFO) {
|
||||
log->SC_log(Log::INFO) << std::dec << "C.LW: x" << rs1 << "(0x" << std::hex
|
||||
<< regs->getValue(rs1) << ") + " << std::dec << imm << " (@0x"
|
||||
<< std::hex << mem_addr << std::dec << ") -> x" << rd << std::hex
|
||||
<< " (0x" << data << ")" << std::endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool C_extension::Exec_C_SW() {
|
||||
uint32_t mem_addr = 0;
|
||||
int rs1, rs2;
|
||||
int32_t imm = 0;
|
||||
uint32_t data;
|
||||
|
||||
rs1 = get_rs1p();
|
||||
rs2 = get_rs2p();
|
||||
imm = get_imm_L();
|
||||
|
||||
mem_addr = imm + regs->getValue(rs1);
|
||||
data = regs->getValue(rs2);
|
||||
|
||||
mem_intf->writeDataMem(mem_addr, data, 4);
|
||||
|
||||
if (log->getLogLevel() > Log::INFO) {
|
||||
log->SC_log(Log::INFO) << "C.SW: x" << std::dec << rs2 << "(0x" << std::hex
|
||||
<< data << ") -> x" << std::dec << rs1 << " + 0x" << std::hex << imm
|
||||
<< " (@0x" << std::hex << mem_addr << std::dec << ")" << std::endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool C_extension::Exec_C_JAL(int m_rd) {
|
||||
int32_t mem_addr = 0;
|
||||
int rd;
|
||||
int new_pc, old_pc;
|
||||
|
||||
rd = m_rd;
|
||||
mem_addr = get_imm_J();
|
||||
old_pc = regs->getPC();
|
||||
|
||||
new_pc = old_pc + mem_addr;
|
||||
regs->setPC(new_pc);
|
||||
|
||||
old_pc = old_pc + 2;
|
||||
regs->setValue(rd, old_pc);
|
||||
|
||||
if (log->getLogLevel() > Log::INFO) {
|
||||
log->SC_log(Log::INFO) << "C.JAL: x" << std::dec << rd << " <- 0x"
|
||||
<< std::hex << old_pc << std::dec << ". PC + 0x" << std::hex
|
||||
<< mem_addr << " -> PC (0x" << new_pc << ")" << std::endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool C_extension::process_instruction(Instruction &inst) {
|
||||
bool PC_not_affected = true;
|
||||
|
||||
setInstr(inst.getInstr());
|
||||
|
||||
switch (decode()) {
|
||||
case OP_C_ADDI4SPN:
|
||||
PC_not_affected = Exec_C_ADDI4SPN();
|
||||
break;
|
||||
case OP_C_LW:
|
||||
Exec_C_LW();
|
||||
break;
|
||||
case OP_C_SW:
|
||||
Exec_C_SW();
|
||||
break;
|
||||
case OP_C_ADDI:
|
||||
Exec_C_ADDI();
|
||||
break;
|
||||
case OP_C_JAL:
|
||||
Exec_C_JAL(1);
|
||||
PC_not_affected = false;
|
||||
break;
|
||||
case OP_C_J:
|
||||
Exec_C_JAL(0);
|
||||
PC_not_affected = false;
|
||||
break;
|
||||
case OP_C_LI:
|
||||
Exec_C_LI();
|
||||
break;
|
||||
case OP_C_SLLI:
|
||||
Exec_C_SLLI();
|
||||
break;
|
||||
case OP_C_LWSP:
|
||||
Exec_C_LWSP();
|
||||
break;
|
||||
case OP_C_JR:
|
||||
Exec_C_JR();
|
||||
PC_not_affected = false;
|
||||
break;
|
||||
case OP_C_MV:
|
||||
Exec_C_MV();
|
||||
break;
|
||||
case OP_C_JALR:
|
||||
Exec_C_JALR();
|
||||
PC_not_affected = false;
|
||||
break;
|
||||
case OP_C_ADD:
|
||||
Exec_C_ADD();
|
||||
break;
|
||||
case OP_C_SWSP:
|
||||
Exec_C_SWSP();
|
||||
break;
|
||||
case OP_C_ADDI16SP:
|
||||
Exec_C_ADDI16SP();
|
||||
break;
|
||||
case OP_C_BEQZ:
|
||||
Exec_C_BEQZ();
|
||||
PC_not_affected = false;
|
||||
break;
|
||||
case OP_C_BNEZ:
|
||||
Exec_C_BNEZ();
|
||||
PC_not_affected = false;
|
||||
break;
|
||||
case OP_C_SRLI:
|
||||
Exec_C_SRLI();
|
||||
break;
|
||||
case OP_C_SRAI:
|
||||
Exec_C_SRAI();
|
||||
break;
|
||||
case OP_C_ANDI:
|
||||
Exec_C_ANDI();
|
||||
break;
|
||||
case OP_C_SUB:
|
||||
Exec_C_SUB();
|
||||
break;
|
||||
case OP_C_XOR:
|
||||
Exec_C_XOR();
|
||||
break;
|
||||
case OP_C_OR:
|
||||
Exec_C_OR();
|
||||
break;
|
||||
case OP_C_AND:
|
||||
Exec_C_AND();
|
||||
break;
|
||||
default:
|
||||
std::cout << "C instruction not implemented yet" << std::endl;
|
||||
inst.dump();
|
||||
NOP();
|
||||
break;
|
||||
}
|
||||
|
||||
return PC_not_affected;
|
||||
}
|
2193
src/Execute.cpp
2193
src/Execute.cpp
File diff suppressed because it is too large
Load Diff
|
@ -1,174 +1,20 @@
|
|||
/*!
|
||||
\file Instruction.cpp
|
||||
\brief Decode instructions part of the RISC-V
|
||||
\author Màrius Montón
|
||||
\date August 2018
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "Instruction.h"
|
||||
|
||||
|
||||
Instruction::Instruction(sc_uint<32> instr) {
|
||||
Instruction::Instruction(sc_dt::sc_uint<32> instr) {
|
||||
m_instr = instr;
|
||||
}
|
||||
|
||||
opCodes Instruction::decode() {
|
||||
switch (opcode()) {
|
||||
case LUI:
|
||||
return OP_LUI;
|
||||
case AUIPC:
|
||||
return OP_AUIPC;
|
||||
case JAL:
|
||||
return OP_JAL;
|
||||
case JALR:
|
||||
return OP_JALR;
|
||||
case BEQ:
|
||||
switch(get_funct3()) {
|
||||
case BEQ_F:
|
||||
return OP_BEQ;
|
||||
case BNE_F:
|
||||
return OP_BNE;
|
||||
case BLT_F:
|
||||
return OP_BLT;
|
||||
case BGE_F:
|
||||
return OP_BGE;
|
||||
case BLTU_F:
|
||||
return OP_BLTU;
|
||||
case BGEU_F:
|
||||
return OP_BGEU;
|
||||
}
|
||||
return OP_ERROR;
|
||||
case LB:
|
||||
switch(get_funct3()) {
|
||||
case LB_F:
|
||||
return OP_LB;
|
||||
case LH_F:
|
||||
return OP_LH;
|
||||
case LW_F:
|
||||
return OP_LW;
|
||||
case LBU_F:
|
||||
return OP_LBU;
|
||||
case LHU_F:
|
||||
return OP_LHU;
|
||||
}
|
||||
return OP_ERROR;
|
||||
case SB:
|
||||
switch(get_funct3()) {
|
||||
case SB_F:
|
||||
return OP_SB;
|
||||
case SH_F:
|
||||
return OP_SH;
|
||||
case SW_F:
|
||||
return OP_SW;
|
||||
}
|
||||
return OP_ERROR;
|
||||
case ADDI:
|
||||
switch(get_funct3()) {
|
||||
case ADDI_F:
|
||||
return OP_ADDI;
|
||||
case SLTI_F:
|
||||
return OP_SLTI;
|
||||
case SLTIU_F:
|
||||
return OP_SLTIU;
|
||||
case XORI_F:
|
||||
return OP_XORI;
|
||||
case ORI_F:
|
||||
return OP_ORI;
|
||||
case ANDI_F:
|
||||
return OP_ANDI;
|
||||
case SLLI_F:
|
||||
return OP_SLLI;
|
||||
case SRLI_F:
|
||||
switch(get_funct7()) {
|
||||
case SRLI_F7:
|
||||
return OP_SRLI;
|
||||
case SRAI_F7:
|
||||
return OP_SRAI;
|
||||
}
|
||||
return OP_ERROR;
|
||||
}
|
||||
return OP_ERROR;
|
||||
case ADD: {
|
||||
switch(get_funct3()) {
|
||||
case ADD_F:
|
||||
switch (get_funct7()) {
|
||||
case ADD_F7:
|
||||
return OP_ADD;
|
||||
case SUB_F7:
|
||||
return OP_SUB;
|
||||
};
|
||||
break;
|
||||
case SLL_F:
|
||||
return OP_SLL;
|
||||
case SLT_F:
|
||||
return OP_SLT;
|
||||
case SLTU_F:
|
||||
return OP_SLTU;
|
||||
case XOR_F:
|
||||
return OP_XOR;
|
||||
case SRL_F:
|
||||
switch(get_funct7()) {
|
||||
case SRL_F7:
|
||||
return OP_SRL;
|
||||
case SRA_F7:
|
||||
return OP_SRA;
|
||||
}
|
||||
case OR_F:
|
||||
return OP_OR;
|
||||
case AND_F:
|
||||
return OP_AND;
|
||||
}
|
||||
} /* ADD */
|
||||
case FENCE:
|
||||
return OP_FENCE;
|
||||
case ECALL: {
|
||||
switch (get_funct3()) {
|
||||
case ECALL_F3:
|
||||
switch(get_csr()) {
|
||||
case ECALL_F:
|
||||
return OP_ECALL;
|
||||
case EBREAK_F:
|
||||
return OP_EBREAK;
|
||||
case URET_F:
|
||||
return OP_URET;
|
||||
case SRET_F:
|
||||
return OP_SRET;
|
||||
case MRET_F:
|
||||
return OP_MRET;
|
||||
case WFI_F:
|
||||
return OP_WFI;
|
||||
case SFENCE_F:
|
||||
return OP_SFENCE;
|
||||
}
|
||||
if (m_instr.range(31,25) == 0b0001001) {
|
||||
return OP_SFENCE;
|
||||
}
|
||||
break;
|
||||
case CSRRW:
|
||||
return OP_CSRRW;
|
||||
break;
|
||||
case CSRRS:
|
||||
return OP_CSRRS;
|
||||
break;
|
||||
case CSRRC:
|
||||
return OP_CSRRC;
|
||||
break;
|
||||
case CSRRWI:
|
||||
return OP_CSRRWI;
|
||||
break;
|
||||
case CSRRSI:
|
||||
return OP_CSRRSI;
|
||||
break;
|
||||
case CSRRCI:
|
||||
return OP_CSRRCI;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return OP_ERROR;
|
||||
}
|
||||
|
||||
return OP_ERROR;
|
||||
}
|
||||
|
||||
|
||||
extension_t Instruction::check_extension() {
|
||||
if ( (m_instr.range(6,0) == 0b0110011) &&
|
||||
(m_instr.range(31,25) == 0b0000001) ){
|
||||
if ((m_instr.range(6, 0) == 0b0110011)
|
||||
&& (m_instr.range(31, 25) == 0b0000001)) {
|
||||
return M_EXTENSION;
|
||||
} else if (m_instr.range(6, 0) == 0b0101111) {
|
||||
return A_EXTENSION;
|
||||
|
@ -184,3 +30,4 @@ extension_t Instruction::check_extension() {
|
|||
return UNKNOWN_EXTENSION;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
19
src/Log.cpp
19
src/Log.cpp
|
@ -1,7 +1,14 @@
|
|||
/*!
|
||||
\file Log.cpp
|
||||
\brief Class to manage Log
|
||||
\author Màrius Montón
|
||||
\date Aug 2018
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "Log.h"
|
||||
|
||||
Log* Log::getInstance()
|
||||
{
|
||||
Log* Log::getInstance() {
|
||||
if (instance == 0) {
|
||||
instance = new Log("Log.txt");
|
||||
}
|
||||
|
@ -17,7 +24,8 @@ Log::Log(const char* filename) {
|
|||
void Log::SC_log(std::string msg, enum LogLevel level) {
|
||||
|
||||
if (level <= currentLogLevel) {
|
||||
m_stream << "time " << sc_core::sc_time_stamp() << ": " << msg << std::endl;
|
||||
m_stream << "time " << sc_core::sc_time_stamp() << ": " << msg
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -30,7 +38,6 @@ std::ofstream& Log::SC_log(enum LogLevel level) {
|
|||
return m_sink;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void Log::setLogLevel(enum LogLevel newLevel) {
|
||||
|
@ -38,4 +45,8 @@ void Log::setLogLevel(enum LogLevel newLevel) {
|
|||
currentLogLevel = newLevel;
|
||||
}
|
||||
|
||||
enum Log::LogLevel Log::getLogLevel() {
|
||||
return currentLogLevel;
|
||||
}
|
||||
|
||||
Log *Log::instance = 0;
|
||||
|
|
|
@ -1,42 +0,0 @@
|
|||
#include "M_Instruction.h"
|
||||
|
||||
|
||||
M_Instruction::M_Instruction(sc_uint<32> instr) {
|
||||
m_instr = instr;
|
||||
}
|
||||
|
||||
op_M_Codes M_Instruction::decode() {
|
||||
|
||||
switch (opcode()) {
|
||||
case M_MUL:
|
||||
return OP_M_MUL;
|
||||
break;
|
||||
case M_MULH:
|
||||
return OP_M_MULH;
|
||||
break;
|
||||
case M_MULHSU:
|
||||
return OP_M_MULHSU;
|
||||
break;
|
||||
case M_MULHU:
|
||||
return OP_M_MULHU;
|
||||
break;
|
||||
case M_DIV:
|
||||
return OP_M_DIV;
|
||||
break;
|
||||
case M_DIVU:
|
||||
return OP_M_DIVU;
|
||||
break;
|
||||
case M_REM:
|
||||
return OP_M_REM;
|
||||
break;
|
||||
case M_REMU:
|
||||
return OP_M_REMU;
|
||||
break;
|
||||
default:
|
||||
return OP_M_ERROR;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return OP_M_ERROR;
|
||||
}
|
|
@ -0,0 +1,287 @@
|
|||
/*!
|
||||
\file M_extension.h
|
||||
\brief Implement M extensions part of the RISC-V
|
||||
\author Màrius Montón
|
||||
\date November 2018
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "M_extension.h"
|
||||
|
||||
op_M_Codes M_extension::decode() {
|
||||
|
||||
switch (opcode()) {
|
||||
case M_MUL:
|
||||
return OP_M_MUL;
|
||||
break;
|
||||
case M_MULH:
|
||||
return OP_M_MULH;
|
||||
break;
|
||||
case M_MULHSU:
|
||||
return OP_M_MULHSU;
|
||||
break;
|
||||
case M_MULHU:
|
||||
return OP_M_MULHU;
|
||||
break;
|
||||
case M_DIV:
|
||||
return OP_M_DIV;
|
||||
break;
|
||||
case M_DIVU:
|
||||
return OP_M_DIVU;
|
||||
break;
|
||||
case M_REM:
|
||||
return OP_M_REM;
|
||||
break;
|
||||
case M_REMU:
|
||||
return OP_M_REMU;
|
||||
break;
|
||||
default:
|
||||
return OP_M_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
return OP_M_ERROR;
|
||||
}
|
||||
|
||||
bool M_extension::Exec_M_MUL() {
|
||||
int rd, rs1, rs2;
|
||||
int32_t multiplier, multiplicand;
|
||||
int64_t result;
|
||||
|
||||
rd = get_rd();
|
||||
rs1 = get_rs1();
|
||||
rs2 = get_rs2();
|
||||
|
||||
multiplier = regs->getValue(rs1);
|
||||
multiplicand = regs->getValue(rs2);
|
||||
|
||||
result = (int64_t) multiplier * multiplicand;
|
||||
result = result & 0x00000000FFFFFFFF;
|
||||
regs->setValue(rd, result);
|
||||
|
||||
log->SC_log(Log::INFO) << std::dec << "MUL: x" << rs1 << " * x" << rs2
|
||||
<< " -> x" << rd << "(" << result << ")" << std::endl;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool M_extension::Exec_M_MULH() {
|
||||
int rd, rs1, rs2;
|
||||
int32_t multiplier, multiplicand;
|
||||
int64_t result;
|
||||
int32_t ret_value;
|
||||
|
||||
rd = get_rd();
|
||||
rs1 = get_rs1();
|
||||
rs2 = get_rs2();
|
||||
|
||||
multiplier = regs->getValue(rs1);
|
||||
multiplicand = regs->getValue(rs2);
|
||||
|
||||
result = (int64_t) multiplier * (int64_t) multiplicand;
|
||||
|
||||
ret_value = (int32_t) ((result >> 32) & 0x00000000FFFFFFFF);
|
||||
regs->setValue(rd, ret_value);
|
||||
|
||||
log->SC_log(Log::INFO) << std::dec << "MULH: x" << rs1 << " * x" << rs2
|
||||
<< " -> x" << rd << "(" << result << ")" << std::endl;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool M_extension::Exec_M_MULHSU() {
|
||||
int rd, rs1, rs2;
|
||||
int32_t multiplier;
|
||||
uint32_t multiplicand;
|
||||
int64_t result;
|
||||
|
||||
rd = get_rd();
|
||||
rs1 = get_rs1();
|
||||
rs2 = get_rs2();
|
||||
|
||||
multiplier = regs->getValue(rs1);
|
||||
multiplicand = regs->getValue(rs2);
|
||||
|
||||
result = (int64_t) multiplier * (uint64_t) multiplicand;
|
||||
result = (result >> 32) & 0x00000000FFFFFFFF;
|
||||
regs->setValue(rd, result);
|
||||
|
||||
log->SC_log(Log::INFO) << std::dec << "MULHSU: x" << rs1 << " * x" << rs2
|
||||
<< " -> x" << rd << "(" << result << ")" << std::endl;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool M_extension::Exec_M_MULHU() {
|
||||
int rd, rs1, rs2;
|
||||
uint32_t multiplier, multiplicand;
|
||||
uint64_t result;
|
||||
int32_t ret_value;
|
||||
|
||||
rd = get_rd();
|
||||
rs1 = get_rs1();
|
||||
rs2 = get_rs2();
|
||||
|
||||
multiplier = (uint32_t) regs->getValue(rs1);
|
||||
multiplicand = (uint32_t) regs->getValue(rs2);
|
||||
|
||||
result = (uint64_t) multiplier * (uint64_t) multiplicand;
|
||||
ret_value = (uint32_t) (result >> 32) & 0x00000000FFFFFFFF;
|
||||
regs->setValue(rd, ret_value);
|
||||
|
||||
log->SC_log(Log::INFO) << std::dec << "MULHU: x" << rs1 << " * x" << rs2
|
||||
<< " -> x" << rd << "(" << ret_value << ")" << std::endl;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool M_extension::Exec_M_DIV() {
|
||||
int rd, rs1, rs2;
|
||||
int32_t divisor, dividend;
|
||||
int64_t result;
|
||||
|
||||
rd = get_rd();
|
||||
rs1 = get_rs1();
|
||||
rs2 = get_rs2();
|
||||
|
||||
dividend = regs->getValue(rs1);
|
||||
divisor = regs->getValue(rs2);
|
||||
|
||||
if (divisor == 0) {
|
||||
result = -1;
|
||||
} else if ((divisor == -1) && (dividend == (int32_t) 0x80000000)) {
|
||||
result = 0x0000000080000000;
|
||||
} else {
|
||||
result = dividend / divisor;
|
||||
result = result & 0x00000000FFFFFFFF;
|
||||
}
|
||||
|
||||
regs->setValue(rd, result);
|
||||
|
||||
log->SC_log(Log::INFO) << std::dec << "DIV: x" << rs1 << " / x" << rs2
|
||||
<< " -> x" << rd << "(" << result << ")" << std::endl;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool M_extension::Exec_M_DIVU() {
|
||||
int rd, rs1, rs2;
|
||||
uint32_t divisor, dividend;
|
||||
uint64_t result;
|
||||
|
||||
rd = get_rd();
|
||||
rs1 = get_rs1();
|
||||
rs2 = get_rs2();
|
||||
|
||||
dividend = regs->getValue(rs1);
|
||||
divisor = regs->getValue(rs2);
|
||||
|
||||
if (divisor == 0) {
|
||||
result = -1;
|
||||
} else {
|
||||
result = dividend / divisor;
|
||||
result = result & 0x00000000FFFFFFFF;
|
||||
}
|
||||
|
||||
regs->setValue(rd, result);
|
||||
|
||||
log->SC_log(Log::INFO) << std::dec << "DIVU: x" << rs1 << " / x" << rs2
|
||||
<< " -> x" << rd << "(" << result << ")" << std::endl;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool M_extension::Exec_M_REM() {
|
||||
int rd, rs1, rs2;
|
||||
int32_t divisor, dividend;
|
||||
int32_t result;
|
||||
|
||||
rd = get_rd();
|
||||
rs1 = get_rs1();
|
||||
rs2 = get_rs2();
|
||||
|
||||
dividend = regs->getValue(rs1);
|
||||
divisor = regs->getValue(rs2);
|
||||
|
||||
if (divisor == 0) {
|
||||
result = dividend;
|
||||
} else if ((divisor == -1) && (dividend == (int32_t) 0x80000000)) {
|
||||
result = 0;
|
||||
} else {
|
||||
result = dividend % divisor;
|
||||
}
|
||||
|
||||
regs->setValue(rd, result);
|
||||
|
||||
log->SC_log(Log::INFO) << std::dec << "REM: x" << rs1 << " / x" << rs2
|
||||
<< " -> x" << rd << "(" << result << ")" << std::endl;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool M_extension::Exec_M_REMU() {
|
||||
int rd, rs1, rs2;
|
||||
uint32_t divisor, dividend;
|
||||
uint32_t result;
|
||||
|
||||
rd = get_rd();
|
||||
rs1 = get_rs1();
|
||||
rs2 = get_rs2();
|
||||
|
||||
dividend = regs->getValue(rs1);
|
||||
divisor = regs->getValue(rs2);
|
||||
|
||||
if (divisor == 0) {
|
||||
result = dividend;
|
||||
} else {
|
||||
result = dividend % divisor;
|
||||
}
|
||||
|
||||
regs->setValue(rd, result);
|
||||
|
||||
log->SC_log(Log::INFO) << std::dec << "REMU: x" << rs1 << " / x" << rs2
|
||||
<< " -> x" << rd << "(" << result << ")" << std::endl;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool M_extension::process_instruction(Instruction &inst) {
|
||||
bool PC_not_affected = true;
|
||||
|
||||
setInstr(inst.getInstr());
|
||||
|
||||
switch (decode()) {
|
||||
case OP_M_MUL:
|
||||
Exec_M_MUL();
|
||||
break;
|
||||
case OP_M_MULH:
|
||||
Exec_M_MULH();
|
||||
break;
|
||||
case OP_M_MULHSU:
|
||||
Exec_M_MULHSU();
|
||||
break;
|
||||
case OP_M_MULHU:
|
||||
Exec_M_MULHU();
|
||||
break;
|
||||
case OP_M_DIV:
|
||||
Exec_M_DIV();
|
||||
break;
|
||||
case OP_M_DIVU:
|
||||
Exec_M_DIVU();
|
||||
break;
|
||||
case OP_M_REM:
|
||||
Exec_M_REM();
|
||||
break;
|
||||
case OP_M_REMU:
|
||||
Exec_M_REMU();
|
||||
break;
|
||||
default:
|
||||
std::cout << "M instruction not implemented yet" << std::endl;
|
||||
inst.dump();
|
||||
//NOP(inst);
|
||||
sc_core::sc_stop();
|
||||
break;
|
||||
}
|
||||
|
||||
return PC_not_affected;
|
||||
}
|
|
@ -1,10 +1,16 @@
|
|||
/*!
|
||||
\file Memory.cpp
|
||||
\brief Basic TLM-2 memory model
|
||||
\author Màrius Montón
|
||||
\date August 2018
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "Memory.h"
|
||||
|
||||
|
||||
SC_HAS_PROCESS(Memory);
|
||||
Memory::Memory(sc_module_name name, string filename): sc_module(name)
|
||||
,socket("socket")
|
||||
,LATENCY(SC_ZERO_TIME) {
|
||||
Memory::Memory(sc_core::sc_module_name name, std::string filename) :
|
||||
sc_module(name), socket("socket"), LATENCY(sc_core::SC_ZERO_TIME) {
|
||||
// Register callbacks for incoming interface method calls
|
||||
socket.register_b_transport(this, &Memory::b_transport);
|
||||
socket.register_get_direct_mem_ptr(this, &Memory::get_direct_mem_ptr);
|
||||
|
@ -17,35 +23,33 @@ Memory::Memory(sc_module_name name, string filename): sc_module(name)
|
|||
readHexFile(filename);
|
||||
|
||||
log = Log::getInstance();
|
||||
log->SC_log(Log::INFO) << "Using file: " << filename << endl;
|
||||
log->SC_log(Log::INFO) << "Using file: " << filename << std::endl;
|
||||
}
|
||||
|
||||
Memory::Memory(sc_module_name name, bool use_file): sc_module(name)
|
||||
,socket("socket")
|
||||
,LATENCY(SC_ZERO_TIME) {
|
||||
Memory::Memory(sc_core::sc_module_name name, bool use_file) :
|
||||
sc_module(name), socket("socket"), LATENCY(sc_core::SC_ZERO_TIME) {
|
||||
socket.register_b_transport(this, &Memory::b_transport);
|
||||
socket.register_get_direct_mem_ptr(this, &Memory::get_direct_mem_ptr);
|
||||
socket.register_transport_dbg(this, &Memory::transport_dbg);
|
||||
memory_offset = 0;
|
||||
program_counter = 0;
|
||||
//memset(mem, 0, SIZE*sizeof(uint8_t));
|
||||
//
|
||||
|
||||
mem = new uint8_t[SIZE];
|
||||
|
||||
log = Log::getInstance();
|
||||
log->SC_log(Log::INFO) << "Memory instantiated wihtout file" << endl;
|
||||
log->SC_log(Log::INFO) << "Memory instantiated wihtout file" << std::endl;
|
||||
}
|
||||
|
||||
|
||||
Memory::~Memory() {
|
||||
delete mem;
|
||||
delete[] mem;
|
||||
}
|
||||
|
||||
uint32_t Memory::getPCfromHEX() {
|
||||
return program_counter;
|
||||
|
||||
}
|
||||
void Memory::b_transport( tlm::tlm_generic_payload& trans, sc_time& delay )
|
||||
{
|
||||
void Memory::b_transport(tlm::tlm_generic_payload &trans,
|
||||
sc_core::sc_time &delay) {
|
||||
tlm::tlm_command cmd = trans.get_command();
|
||||
sc_dt::uint64 adr = trans.get_address();
|
||||
unsigned char *ptr = trans.get_data_ptr();
|
||||
|
@ -85,7 +89,7 @@ void Memory::b_transport( tlm::tlm_generic_payload& trans, sc_time& delay )
|
|||
wait(delay);
|
||||
|
||||
// Reset timing annotation after waiting
|
||||
delay = SC_ZERO_TIME;
|
||||
delay = sc_core::SC_ZERO_TIME;
|
||||
|
||||
// *********************************************
|
||||
// Set DMI hint to indicated that DMI is supported
|
||||
|
@ -102,8 +106,7 @@ void Memory::b_transport( tlm::tlm_generic_payload& trans, sc_time& delay )
|
|||
}
|
||||
|
||||
bool Memory::get_direct_mem_ptr(tlm::tlm_generic_payload &trans,
|
||||
tlm::tlm_dmi& dmi_data)
|
||||
{
|
||||
tlm::tlm_dmi &dmi_data) {
|
||||
if (memory_offset != 0) {
|
||||
return false;
|
||||
}
|
||||
|
@ -121,8 +124,7 @@ bool Memory::get_direct_mem_ptr(tlm::tlm_generic_payload& trans,
|
|||
return true;
|
||||
}
|
||||
|
||||
unsigned int Memory::transport_dbg(tlm::tlm_generic_payload& trans)
|
||||
{
|
||||
unsigned int Memory::transport_dbg(tlm::tlm_generic_payload &trans) {
|
||||
tlm::tlm_command cmd = trans.get_command();
|
||||
sc_dt::uint64 adr = trans.get_address();
|
||||
unsigned char *ptr = trans.get_data_ptr();
|
||||
|
@ -139,9 +141,9 @@ unsigned int Memory::transport_dbg(tlm::tlm_generic_payload& trans)
|
|||
return num_bytes;
|
||||
}
|
||||
|
||||
void Memory::readHexFile(string filename) {
|
||||
ifstream hexfile;
|
||||
string line;
|
||||
void Memory::readHexFile(std::string filename) {
|
||||
std::ifstream hexfile;
|
||||
std::string line;
|
||||
int byte_count;
|
||||
uint32_t address;
|
||||
int i = 0;
|
||||
|
@ -159,28 +161,35 @@ void Memory::readHexFile(string filename) {
|
|||
address = address + extended_address;
|
||||
//cout << "00 address 0x" << hex << address << endl;
|
||||
for (i = 0; i < byte_count; i++) {
|
||||
mem[address+i] = stol(line.substr(9 + (i * 2), 2), nullptr, 16);
|
||||
mem[address + i] = stol(line.substr(9 + (i * 2), 2),
|
||||
nullptr, 16);
|
||||
}
|
||||
} else if (line.substr(7, 2) == "02") {
|
||||
/* Extended segment address */
|
||||
extended_address = stol(line.substr(9,4), nullptr, 16) * 16;
|
||||
cout << "02 extended address 0x" << hex << extended_address << dec << endl;
|
||||
extended_address = stol(line.substr(9, 4), nullptr, 16)
|
||||
* 16;
|
||||
std::cout << "02 extended address 0x" << std::hex
|
||||
<< extended_address << std::dec << std::endl;
|
||||
} else if (line.substr(7, 2) == "03") {
|
||||
/* Start segment address */
|
||||
uint32_t code_segment;
|
||||
code_segment = stol(line.substr(9, 4), nullptr, 16) * 16; /* ? */
|
||||
program_counter = stol(line.substr(13, 4), nullptr, 16);
|
||||
program_counter = program_counter + code_segment;
|
||||
cout << "03 PC set to 0x" << hex << program_counter << dec << endl;
|
||||
std::cout << "03 PC set to 0x" << std::hex
|
||||
<< program_counter << std::dec << std::endl;
|
||||
} else if (line.substr(7, 2) == "04") {
|
||||
/* Start segment address */
|
||||
memory_offset = stol(line.substr(9, 4), nullptr, 16) << 16;
|
||||
extended_address = 0;
|
||||
cout << "04 address set to 0x" << hex << extended_address << dec << endl;
|
||||
cout << "04 offset set to 0x" << hex << memory_offset << dec << endl;
|
||||
std::cout << "04 address set to 0x" << std::hex
|
||||
<< extended_address << std::dec << std::endl;
|
||||
std::cout << "04 offset set to 0x" << std::hex
|
||||
<< memory_offset << std::dec << std::endl;
|
||||
} else if (line.substr(7, 2) == "05") {
|
||||
program_counter = stol(line.substr(9, 8), nullptr, 16);
|
||||
cout << "05 PC set to 0x" << hex << program_counter << dec << endl;
|
||||
std::cout << "05 PC set to 0x" << std::hex
|
||||
<< program_counter << std::dec << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
/*!
|
||||
\file MemoryInterface.cpp
|
||||
\brief CPU to Memory Interface class
|
||||
\author Màrius Montón
|
||||
\date May 2020
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "MemoryInterface.h"
|
||||
|
||||
|
||||
MemoryInterface::MemoryInterface() :
|
||||
data_bus("data_bus") {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Access data memory to get data
|
||||
* @param addr address to access to
|
||||
* @param size size of the data to read in bytes
|
||||
* @return data value read
|
||||
*/
|
||||
uint32_t MemoryInterface::readDataMem(uint32_t addr, int size) {
|
||||
uint32_t data;
|
||||
tlm::tlm_generic_payload trans;
|
||||
sc_core::sc_time delay = sc_core::SC_ZERO_TIME;
|
||||
|
||||
trans.set_command(tlm::TLM_READ_COMMAND);
|
||||
trans.set_data_ptr(reinterpret_cast<unsigned char*>(&data));
|
||||
trans.set_data_length(size);
|
||||
trans.set_streaming_width(4); // = data_length to indicate no streaming
|
||||
trans.set_byte_enable_ptr(0); // 0 indicates unused
|
||||
trans.set_dmi_allowed(false); // Mandatory initial value
|
||||
trans.set_response_status(tlm::TLM_INCOMPLETE_RESPONSE);
|
||||
trans.set_address(addr);
|
||||
|
||||
data_bus->b_transport(trans, delay);
|
||||
|
||||
if (trans.is_response_error()) {
|
||||
SC_REPORT_ERROR("Memory", "Read memory");
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Acces data memory to write data
|
||||
* @brief
|
||||
* @param addr addr address to access to
|
||||
* @param data data to write
|
||||
* @param size size of the data to write in bytes
|
||||
*/
|
||||
void MemoryInterface::writeDataMem(uint32_t addr, uint32_t data, int size) {
|
||||
tlm::tlm_generic_payload trans;
|
||||
sc_core::sc_time delay = sc_core::SC_ZERO_TIME;
|
||||
|
||||
trans.set_command(tlm::TLM_WRITE_COMMAND);
|
||||
trans.set_data_ptr(reinterpret_cast<unsigned char*>(&data));
|
||||
trans.set_data_length(size);
|
||||
trans.set_streaming_width(4); // = data_length to indicate no streaming
|
||||
trans.set_byte_enable_ptr(0); // 0 indicates unused
|
||||
trans.set_dmi_allowed(false); // Mandatory initial value
|
||||
trans.set_response_status(tlm::TLM_INCOMPLETE_RESPONSE);
|
||||
trans.set_address(addr);
|
||||
|
||||
data_bus->b_transport(trans, delay);
|
||||
}
|
|
@ -1,17 +1,22 @@
|
|||
/*!
|
||||
\file Performance.cpp
|
||||
\brief Class to store performance of CPU
|
||||
\author Màrius Montón
|
||||
\date Aug 2018
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "Performance.h"
|
||||
|
||||
Performance* Performance::getInstance()
|
||||
{
|
||||
if (instance == 0)
|
||||
{
|
||||
Performance* Performance::getInstance() {
|
||||
if (instance == 0) {
|
||||
instance = new Performance();
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
Performance::Performance()
|
||||
{
|
||||
Performance::Performance() {
|
||||
data_memory_read = 0;
|
||||
data_memory_write = 0;
|
||||
code_memory_read = 0;
|
||||
|
@ -22,13 +27,15 @@ Performance::Performance()
|
|||
}
|
||||
|
||||
void Performance::dump() {
|
||||
cout << dec << "# data memory reads: " << data_memory_read << endl;
|
||||
cout << "# data memory writes: " << data_memory_write << endl;
|
||||
cout << "# code memory reads: " << code_memory_read << endl;
|
||||
cout << "# code memory writes: " << code_memory_write << endl;
|
||||
cout << "# registers read: " << register_read << endl;
|
||||
cout << "# registers write: " << register_write << endl;
|
||||
cout << "# instructions executed: " << instructions_executed << endl;
|
||||
std::cout << std::dec << "# data memory reads: " << data_memory_read
|
||||
<< std::endl;
|
||||
std::cout << "# data memory writes: " << data_memory_write << std::endl;
|
||||
std::cout << "# code memory reads: " << code_memory_read << std::endl;
|
||||
std::cout << "# code memory writes: " << code_memory_write << std::endl;
|
||||
std::cout << "# registers read: " << register_read << std::endl;
|
||||
std::cout << "# registers write: " << register_write << std::endl;
|
||||
std::cout << "# instructions executed: " << instructions_executed
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
Performance *Performance::instance = 0;
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
\author Màrius Montón
|
||||
\date August 2018
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "Registers.h"
|
||||
|
||||
|
@ -15,61 +16,92 @@ Registers::Registers() {
|
|||
|
||||
initCSR();
|
||||
|
||||
//cout << "Memory size: 0x" << hex << Memory::SIZE << endl;
|
||||
//cout << "SP address: 0x" << hex << (0x10000000 / 4) - 1 << endl;
|
||||
//std::cout << "Memory size: 0x" << std::hex << Memory::SIZE << std::endl;
|
||||
//std::cout << "SP address: 0x" << std::hex << (0x10000000 / 4) - 1 << std::endl;
|
||||
|
||||
register_bank[sp] = Memory::SIZE - 4; // default stack at the end of the memory
|
||||
register_PC = 0x80000000; // default _start address
|
||||
}
|
||||
|
||||
void Registers::dump(void) {
|
||||
cout << "************************************" << endl;
|
||||
cout << "Registers dump" << dec << endl;
|
||||
cout << "x0 (zero): " << right << setw(11) << register_bank[0];
|
||||
cout << " x1 (ra): " << right << setw(11) << register_bank[1];
|
||||
cout << " x2 (sp): " << right << setw(11) << register_bank[2];
|
||||
cout << " x3 (gp): " << right << setw(11) << register_bank[3] << endl;
|
||||
std::cout << "************************************" << std::endl;
|
||||
std::cout << "Registers dump" << std::dec << std::endl;
|
||||
std::cout << "x0 (zero): " << std::right << std::setw(11)
|
||||
<< register_bank[0];
|
||||
std::cout << " x1 (ra): " << std::right << std::setw(11)
|
||||
<< register_bank[1];
|
||||
std::cout << " x2 (sp): " << std::right << std::setw(11)
|
||||
<< register_bank[2];
|
||||
std::cout << " x3 (gp): " << std::right << std::setw(11)
|
||||
<< register_bank[3] << std::endl;
|
||||
|
||||
cout << "x4 (tp): " << right << setw(11) << register_bank[4];
|
||||
cout << " x5 (t0): " << right << setw(11) << register_bank[5];
|
||||
cout << " x6 (t1): " << right << setw(11) << register_bank[6];
|
||||
cout << " x7 (t2): " << right << setw(11) << register_bank[7] << endl;
|
||||
std::cout << "x4 (tp): " << std::right << std::setw(11)
|
||||
<< register_bank[4];
|
||||
std::cout << " x5 (t0): " << std::right << std::setw(11)
|
||||
<< register_bank[5];
|
||||
std::cout << " x6 (t1): " << std::right << std::setw(11)
|
||||
<< register_bank[6];
|
||||
std::cout << " x7 (t2): " << std::right << std::setw(11)
|
||||
<< register_bank[7] << std::endl;
|
||||
|
||||
cout << "x8 (s0/fp): " << right << setw(11) << register_bank[8];
|
||||
cout << " x9 (s1): " << right << setw(11) << register_bank[9];
|
||||
cout << " x10 (a0): " << right << setw(11) << register_bank[10];
|
||||
cout << " x11 (a1): " << right << setw(11) << register_bank[11] << endl;
|
||||
std::cout << "x8 (s0/fp): " << std::right << std::setw(11)
|
||||
<< register_bank[8];
|
||||
std::cout << " x9 (s1): " << std::right << std::setw(11)
|
||||
<< register_bank[9];
|
||||
std::cout << " x10 (a0): " << std::right << std::setw(11)
|
||||
<< register_bank[10];
|
||||
std::cout << " x11 (a1): " << std::right << std::setw(11)
|
||||
<< register_bank[11] << std::endl;
|
||||
|
||||
cout << "x12 (a2): " << right << setw(11) << register_bank[12];
|
||||
cout << " x13 (a3): " << right << setw(11) << register_bank[13];
|
||||
cout << " x14 (a4): " << right << setw(11) << register_bank[14];
|
||||
cout << " x15 (a5): " << right << setw(11) << register_bank[15] << endl;
|
||||
std::cout << "x12 (a2): " << std::right << std::setw(11)
|
||||
<< register_bank[12];
|
||||
std::cout << " x13 (a3): " << std::right << std::setw(11)
|
||||
<< register_bank[13];
|
||||
std::cout << " x14 (a4): " << std::right << std::setw(11)
|
||||
<< register_bank[14];
|
||||
std::cout << " x15 (a5): " << std::right << std::setw(11)
|
||||
<< register_bank[15] << std::endl;
|
||||
|
||||
cout << "x16 (a6): " << right << setw(11) << register_bank[16];
|
||||
cout << " x17 (a7): " << right << setw(11) << register_bank[17];
|
||||
cout << " x18 (s2): " << right << setw(11) << register_bank[18];
|
||||
cout << " x19 (s3): " << right << setw(11) << register_bank[19] << endl;
|
||||
std::cout << "x16 (a6): " << std::right << std::setw(11)
|
||||
<< register_bank[16];
|
||||
std::cout << " x17 (a7): " << std::right << std::setw(11)
|
||||
<< register_bank[17];
|
||||
std::cout << " x18 (s2): " << std::right << std::setw(11)
|
||||
<< register_bank[18];
|
||||
std::cout << " x19 (s3): " << std::right << std::setw(11)
|
||||
<< register_bank[19] << std::endl;
|
||||
|
||||
cout << "x20 (s4): " << right << setw(11) << register_bank[20];
|
||||
cout << " x21 (s5): " << right << setw(11) << register_bank[21];
|
||||
cout << " x22 (s6): " << right << setw(11) << register_bank[22];
|
||||
cout << " x23 (s7): " << right << setw(11) << register_bank[23] << endl;
|
||||
std::cout << "x20 (s4): " << std::right << std::setw(11)
|
||||
<< register_bank[20];
|
||||
std::cout << " x21 (s5): " << std::right << std::setw(11)
|
||||
<< register_bank[21];
|
||||
std::cout << " x22 (s6): " << std::right << std::setw(11)
|
||||
<< register_bank[22];
|
||||
std::cout << " x23 (s7): " << std::right << std::setw(11)
|
||||
<< register_bank[23] << std::endl;
|
||||
|
||||
cout << "x24 (s8): " << right << setw(11) << register_bank[24];
|
||||
cout << " x25 (s9): " << right << setw(11) << register_bank[25];
|
||||
cout << " x26 (s10): " << right << setw(11) << register_bank[26];
|
||||
cout << " x27 (s11): " << right << setw(11) << register_bank[27] << endl;
|
||||
std::cout << "x24 (s8): " << std::right << std::setw(11)
|
||||
<< register_bank[24];
|
||||
std::cout << " x25 (s9): " << std::right << std::setw(11)
|
||||
<< register_bank[25];
|
||||
std::cout << " x26 (s10): " << std::right << std::setw(11)
|
||||
<< register_bank[26];
|
||||
std::cout << " x27 (s11): " << std::right << std::setw(11)
|
||||
<< register_bank[27] << std::endl;
|
||||
|
||||
cout << "x28 (t3): " << right << setw(11) << register_bank[28];
|
||||
cout << " x29 (t4): " << right << setw(11) << register_bank[29];
|
||||
cout << " x30 (t5): " << right << setw(11) << register_bank[30];
|
||||
cout << " x31 (t6): " << right << setw(11) << register_bank[31] << endl;
|
||||
std::cout << "x28 (t3): " << std::right << std::setw(11)
|
||||
<< register_bank[28];
|
||||
std::cout << " x29 (t4): " << std::right << std::setw(11)
|
||||
<< register_bank[29];
|
||||
std::cout << " x30 (t5): " << std::right << std::setw(11)
|
||||
<< register_bank[30];
|
||||
std::cout << " x31 (t6): " << std::right << std::setw(11)
|
||||
<< register_bank[31] << std::endl;
|
||||
|
||||
cout << "PC: 0x" << hex << register_PC << dec << endl;
|
||||
cout << "************************************" << endl;
|
||||
std::cout << "PC: 0x" << std::hex << register_PC << std::dec << std::endl;
|
||||
std::cout << "************************************" << std::endl;
|
||||
}
|
||||
|
||||
|
||||
void Registers::setValue(int reg_num, int32_t value) {
|
||||
if ((reg_num != 0) && (reg_num < 32)) {
|
||||
register_bank[reg_num] = value;
|
||||
|
@ -100,21 +132,29 @@ uint32_t Registers::getCSR(int csr) {
|
|||
switch (csr) {
|
||||
case CSR_CYCLE:
|
||||
case CSR_MCYCLE:
|
||||
ret_value = (uint64_t)(sc_time(sc_time_stamp()
|
||||
- sc_time(SC_ZERO_TIME)).to_double()) & 0x00000000FFFFFFFF;
|
||||
ret_value = (uint64_t) (sc_core::sc_time(
|
||||
sc_core::sc_time_stamp()
|
||||
- sc_core::sc_time(sc_core::SC_ZERO_TIME)).to_double())
|
||||
& 0x00000000FFFFFFFF;
|
||||
break;
|
||||
case CSR_CYCLEH:
|
||||
case CSR_MCYCLEH:
|
||||
ret_value = (uint32_t)((uint64_t)(sc_time(sc_time_stamp()
|
||||
- sc_time(SC_ZERO_TIME)).to_double()) >> 32 & 0x00000000FFFFFFFF);
|
||||
ret_value = (uint32_t) ((uint64_t) (sc_core::sc_time(
|
||||
sc_core::sc_time_stamp()
|
||||
- sc_core::sc_time(sc_core::SC_ZERO_TIME)).to_double())
|
||||
>> 32 & 0x00000000FFFFFFFF);
|
||||
break;
|
||||
case CSR_TIME:
|
||||
ret_value = (uint64_t)(sc_time(sc_time_stamp()
|
||||
- sc_time(SC_ZERO_TIME)).to_double()) & 0x00000000FFFFFFFF;
|
||||
ret_value = (uint64_t) (sc_core::sc_time(
|
||||
sc_core::sc_time_stamp()
|
||||
- sc_core::sc_time(sc_core::SC_ZERO_TIME)).to_double())
|
||||
& 0x00000000FFFFFFFF;
|
||||
break;
|
||||
case CSR_TIMEH:
|
||||
ret_value = (uint32_t)((uint64_t)(sc_time(sc_time_stamp()
|
||||
- sc_time(SC_ZERO_TIME)).to_double()) >> 32 & 0x00000000FFFFFFFF);
|
||||
ret_value = (uint32_t) ((uint64_t) (sc_core::sc_time(
|
||||
sc_core::sc_time_stamp()
|
||||
- sc_core::sc_time(sc_core::SC_ZERO_TIME)).to_double())
|
||||
>> 32 & 0x00000000FFFFFFFF);
|
||||
break;
|
||||
default:
|
||||
ret_value = CSR[csr];
|
||||
|
@ -123,7 +163,6 @@ uint32_t Registers::getCSR(int csr) {
|
|||
return ret_value;
|
||||
}
|
||||
|
||||
|
||||
void Registers::setCSR(int csr, uint32_t value) {
|
||||
/* @FIXME: rv32mi-p-ma_fetch tests doesn't allow MISA to writable,
|
||||
* but Volume II: Privileged Architectura v1.10 says MISRA is writable (?)
|
||||
|
|
|
@ -21,11 +21,7 @@
|
|||
#include "Trace.h"
|
||||
#include "Timer.h"
|
||||
|
||||
using namespace sc_core;
|
||||
using namespace sc_dt;
|
||||
using namespace std;
|
||||
|
||||
string filename;
|
||||
std::string filename;
|
||||
|
||||
/**
|
||||
* @class Simulator
|
||||
|
@ -34,8 +30,7 @@ string filename;
|
|||
*
|
||||
* @brief Top simulation entity
|
||||
*/
|
||||
SC_MODULE(Simulator)
|
||||
{
|
||||
SC_MODULE(Simulator) {
|
||||
CPU *cpu;
|
||||
Memory *MainMemory;
|
||||
BusCtrl *Bus;
|
||||
|
@ -44,8 +39,7 @@ SC_MODULE(Simulator)
|
|||
|
||||
uint32_t start_PC;
|
||||
|
||||
SC_CTOR(Simulator)
|
||||
{
|
||||
SC_CTOR(Simulator) {
|
||||
MainMemory = new Memory("Main_Memory", filename);
|
||||
start_PC = MainMemory->getPCfromHEX();
|
||||
|
||||
|
@ -56,7 +50,7 @@ SC_MODULE(Simulator)
|
|||
timer = new Timer("Timer");
|
||||
|
||||
cpu->instr_bus.bind(Bus->cpu_instr_socket);
|
||||
cpu->exec->data_bus.bind(Bus->cpu_data_socket);
|
||||
cpu->mem_intf->data_bus.bind(Bus->cpu_data_socket);
|
||||
|
||||
Bus->memory_socket.bind(MainMemory->socket);
|
||||
Bus->trace_socket.bind(trace->socket);
|
||||
|
@ -68,8 +62,8 @@ SC_MODULE(Simulator)
|
|||
}
|
||||
|
||||
~Simulator() {
|
||||
delete cpu;
|
||||
delete MainMemory;
|
||||
delete cpu;
|
||||
delete Bus;
|
||||
delete trace;
|
||||
delete timer;
|
||||
|
@ -119,7 +113,8 @@ void process_arguments(int argc, char* argv[]) {
|
|||
filename = std::string(optarg);
|
||||
break;
|
||||
case '?':
|
||||
std::cout << "Call ./RISCV_TLM -D <debuglevel> (0..3) filename.hex" << std::endl;
|
||||
std::cout << "Call ./RISCV_TLM -D <debuglevel> (0..3) filename.hex"
|
||||
<< std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -129,23 +124,22 @@ void process_arguments(int argc, char* argv[]) {
|
|||
}
|
||||
}
|
||||
|
||||
int sc_main(int argc, char* argv[])
|
||||
{
|
||||
int sc_main(int argc, char *argv[]) {
|
||||
|
||||
/* Capture Ctrl+C and finish the simulation */
|
||||
signal(SIGINT, intHandler);
|
||||
|
||||
/* SystemC time resolution set to 1 ns*/
|
||||
sc_set_time_resolution(1, SC_NS);
|
||||
sc_core::sc_set_time_resolution(1, sc_core::SC_NS);
|
||||
|
||||
/* Parse and process program arguments. -f is mandatory */
|
||||
process_arguments(argc, argv);
|
||||
|
||||
top = new Simulator("top");
|
||||
sc_start();
|
||||
sc_core::sc_start();
|
||||
|
||||
cout << "Press Enter to finish" << endl;
|
||||
cin.ignore();
|
||||
std::cout << "Press Enter to finish" << std::endl;
|
||||
std::cin.ignore();
|
||||
|
||||
// call all destructors, clean exit.
|
||||
delete top;
|
||||
|
|
|
@ -1,8 +1,16 @@
|
|||
/*!
|
||||
\file Timer.cpp
|
||||
\brief Basic TLM-2 Timer module
|
||||
\author Màrius Montón
|
||||
\date January 2019
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "Timer.h"
|
||||
|
||||
SC_HAS_PROCESS(Timer);
|
||||
Timer::Timer(sc_module_name name): sc_module(name)
|
||||
,socket("timer_socket"), m_mtime(0), m_mtimecmp(0) {
|
||||
Timer::Timer(sc_core::sc_module_name name) :
|
||||
sc_module(name), socket("timer_socket"), m_mtime(0), m_mtimecmp(0) {
|
||||
|
||||
socket.register_b_transport(this, &Timer::b_transport);
|
||||
|
||||
|
@ -12,7 +20,7 @@ Timer::Timer(sc_module_name name): sc_module(name)
|
|||
void Timer::run() {
|
||||
|
||||
tlm::tlm_generic_payload *irq_trans = new tlm::tlm_generic_payload;
|
||||
sc_time delay = SC_ZERO_TIME;
|
||||
sc_core::sc_time delay = sc_core::SC_ZERO_TIME;
|
||||
uint32_t cause = 1 << 31 | 0x07; // Machine timer interrupt
|
||||
irq_trans->set_command(tlm::TLM_WRITE_COMMAND);
|
||||
irq_trans->set_data_ptr(reinterpret_cast<unsigned char*>(&cause));
|
||||
|
@ -29,7 +37,8 @@ void Timer::run() {
|
|||
}
|
||||
}
|
||||
|
||||
void Timer::b_transport( tlm::tlm_generic_payload& trans, sc_time& delay ) {
|
||||
void Timer::b_transport(tlm::tlm_generic_payload &trans,
|
||||
sc_core::sc_time &delay) {
|
||||
tlm::tlm_command cmd = trans.get_command();
|
||||
sc_dt::uint64 addr = trans.get_address();
|
||||
unsigned char *ptr = trans.get_data_ptr();
|
||||
|
@ -58,13 +67,13 @@ void Timer::b_transport( tlm::tlm_generic_payload& trans, sc_time& delay ) {
|
|||
// notify needs relative time, mtimecmp works in absolute time
|
||||
notify_time = m_mtimecmp - m_mtime;
|
||||
|
||||
timer_event.notify( sc_time(notify_time, SC_NS) );
|
||||
timer_event.notify(sc_core::sc_time(notify_time, sc_core::SC_NS));
|
||||
break;
|
||||
}
|
||||
} else { // TLM_READ_COMMAND
|
||||
switch (addr) {
|
||||
case TIMER_MEMORY_ADDRESS_LO:
|
||||
m_mtime = sc_time_stamp().value();
|
||||
m_mtime = sc_core::sc_time_stamp().value();
|
||||
aux_value = m_mtime.range(31, 0);
|
||||
break;
|
||||
case TIMER_MEMORY_ADDRESS_HI:
|
||||
|
|
|
@ -1,3 +1,11 @@
|
|||
/*!
|
||||
\file Trace.cpp
|
||||
\brief Basic TLM-2 Trace module
|
||||
\author Màrius Montón
|
||||
\date September 2018
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include <stdio.h>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
@ -10,7 +18,7 @@
|
|||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
// Code taken from
|
||||
// Code partially taken from
|
||||
// https://github.com/embecosm/esp1-systemc-tlm/blob/master/sysc-models/simple-soc/TermSC.h
|
||||
|
||||
#include "Trace.h"
|
||||
|
@ -38,9 +46,7 @@ void Trace::xtermLaunch( char *slaveName ) {
|
|||
|
||||
void Trace::xtermKill(const char *mess) {
|
||||
|
||||
|
||||
if (-1 != ptSlave) { // Close down the slave
|
||||
|
||||
close(ptSlave); // Close the FD
|
||||
ptSlave = -1;
|
||||
}
|
||||
|
@ -59,7 +65,6 @@ void Trace::xtermKill( const char *mess ) {
|
|||
perror(mess);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void Trace::xtermSetup(void) {
|
||||
|
@ -89,8 +94,8 @@ void Trace::xtermSetup(void) {
|
|||
}
|
||||
|
||||
SC_HAS_PROCESS(Trace);
|
||||
Trace::Trace(sc_module_name name): sc_module(name)
|
||||
,socket("socket") {
|
||||
Trace::Trace(sc_core::sc_module_name name) :
|
||||
sc_module(name), socket("socket") {
|
||||
|
||||
socket.register_b_transport(this, &Trace::b_transport);
|
||||
|
||||
|
@ -100,13 +105,11 @@ Trace::Trace(sc_module_name name): sc_module(name)
|
|||
Trace::~Trace() {
|
||||
xtermKill( NULL);
|
||||
}
|
||||
void Trace::b_transport( tlm::tlm_generic_payload& trans, sc_time& delay ) {
|
||||
//tlm::tlm_command cmd = trans.get_command();
|
||||
//sc_dt::uint64 adr = trans.get_address() / 4;
|
||||
|
||||
void Trace::b_transport(tlm::tlm_generic_payload &trans,
|
||||
sc_core::sc_time &delay) {
|
||||
|
||||
unsigned char *ptr = trans.get_data_ptr();
|
||||
//unsigned int len = trans.get_data_length();
|
||||
//unsigned char* byt = trans.get_byte_enable_ptr();
|
||||
//unsigned int wid = trans.get_streaming_width();
|
||||
|
||||
write(ptSlave, ptr, 1);
|
||||
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
/*!
|
||||
\file extension_base.h
|
||||
\brief Base class for ISA extensions
|
||||
\author Màrius Montón
|
||||
\date May 2020
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "extension_base.h"
|
||||
|
||||
extension_base::extension_base(sc_dt::sc_uint<32> instr,
|
||||
Registers *register_bank, MemoryInterface *mem_interface) :
|
||||
m_instr(instr), regs(register_bank), mem_intf(mem_interface) {
|
||||
|
||||
perf = Performance::getInstance();
|
||||
log = Log::getInstance();
|
||||
}
|
||||
|
||||
extension_base::~extension_base() {
|
||||
|
||||
}
|
||||
void extension_base::setInstr(uint32_t p_instr) {
|
||||
m_instr = sc_dt::sc_uint<32>(p_instr);
|
||||
}
|
||||
|
||||
void extension_base::dump() {
|
||||
std::cout << std::hex << "0x" << m_instr << std::dec << std::endl;
|
||||
}
|
||||
|
||||
void extension_base::RaiseException(uint32_t cause, uint32_t inst) {
|
||||
uint32_t new_pc, current_pc, m_cause;
|
||||
|
||||
current_pc = regs->getPC();
|
||||
m_cause = regs->getCSR(CSR_MSTATUS);
|
||||
m_cause |= cause;
|
||||
|
||||
new_pc = regs->getCSR(CSR_MTVEC);
|
||||
|
||||
regs->setCSR(CSR_MEPC, current_pc);
|
||||
|
||||
if (cause == EXCEPTION_CAUSE_ILLEGAL_INSTRUCTION) {
|
||||
regs->setCSR(CSR_MTVAL, inst);
|
||||
} else {
|
||||
regs->setCSR(CSR_MTVAL, current_pc);
|
||||
}
|
||||
|
||||
regs->setCSR(CSR_MCAUSE, cause);
|
||||
regs->setCSR(CSR_MSTATUS, m_cause);
|
||||
|
||||
regs->setPC(new_pc);
|
||||
|
||||
log->SC_log(Log::ERROR) << "Exception! new PC 0x" << std::hex << new_pc
|
||||
<< std::endl;
|
||||
|
||||
regs->dump();
|
||||
std::cout << "Simulation time " << sc_core::sc_time_stamp() << std::endl;
|
||||
perf->dump();
|
||||
SC_REPORT_ERROR("Exception", "Exception");
|
||||
}
|
||||
|
||||
bool extension_base::NOP() {
|
||||
std::cout << std::endl;
|
||||
regs->dump();
|
||||
std::cout << "Simulation time " << sc_core::sc_time_stamp() << std::endl;
|
||||
perf->dump();
|
||||
|
||||
SC_REPORT_ERROR("Execute", "NOP");
|
||||
|
||||
return true;
|
||||
}
|
Loading…
Reference in New Issue