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:
Màrius Montón 2020-06-02 13:08:38 +02:00
parent 9a46e9d0a5
commit 5ee634e4b4
40 changed files with 5560 additions and 5393 deletions

View File

@ -45,14 +45,11 @@ Brief description of the modules:
* CPU: Top entity that includes all other modules. * CPU: Top entity that includes all other modules.
* Memory: Memory highly based on TLM-2 example with read file capability * Memory: Memory highly based on TLM-2 example with read file capability
* Registers: Implements the register file, PC register & CSR registers * Registers: Implements the register file, PC register & CSR registers
* Execute: Executes ISA instructions * Instruction: Decodes instruction type and keeps instruction field
* Executes C instruction extensions * BASE_ISA: Executes Base ISA, Zifencei and Zicsr.
* Executes M instruction extensions * C_extension: Decodes & Executes Compressed instructions (C extension)
* Executes A instruction extensions * M_extension: Decodes & Executes Multiplication and Division instructions (M extension)
* Instruction: Decodes instruction and acces to any instruction field * A_extension: Decodes & Executes Atomic instructions (A extension)
* C_Instruction: Decodes Compressed instructions (C extension)
* M_Instruction: Decodes Multiplication and Division instructions (M extension)
* A_Instruction: Decodes Atomic instructions (A extension)
* Simulator: Top-level entity that builds & starts the simulation * Simulator: Top-level entity that builds & starts the simulation
* BusCtrl: Simple bus manager * BusCtrl: Simple bus manager
* Trace: Simple trace peripheral * Trace: Simple trace peripheral
@ -100,7 +97,7 @@ Task to do:
- [ ] generic IRQ comtroller - [ ] generic IRQ comtroller
- [x] Test, test, test & test. I'm sure there are a ~~lot of~~ some bugs in the code - [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)) - [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 * Improve structure and modules hierarchy
* Add 64 & 128 bits architecture (RV64I, RV128I) * Add 64 & 128 bits architecture (RV64I, RV128I)
@ -129,7 +126,7 @@ $ ./RISCV_TLM asm/BasicLoop.hex
-f filename .hex filename to use -f filename .hex filename to use
## Cross-compiler ## 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 $ git clone --recursive https://github.com/riscv/riscv-gnu-toolchain
$ cd riscv-gnu-toolchain $ cd riscv-gnu-toolchain
@ -240,7 +237,7 @@ If you find this code useful, please consider citing:
``` ```
@inproceedings{montonriscvtlm2020, @inproceedings{montonriscvtlm2020,
title = {A {RISC}-{V} {SystemC}-{TLM} simulator}, 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}, author = {Montón, Màrius},
year = {2020} year = {2020}
} }

View File

@ -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

145
inc/A_extension.h Normal file
View File

@ -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

423
inc/BASE_ISA.h Normal file
View File

@ -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

View File

@ -1,9 +1,10 @@
/** /**
@file BusCtrl.h @file BusCtrl.h
@brief Basic TLM-2 Bus controller @brief Basic TLM-2 Bus controller
@author Màrius Montón @author Màrius Montón
@date September 2018 @date September 2018
*/ */
// SPDX-License-Identifier: GPL-3.0-or-later
#ifndef __BUSCTRL_H__ #ifndef __BUSCTRL_H__
#define __BUSCTRL_H__ #define __BUSCTRL_H__
@ -21,10 +22,6 @@
#include "Log.h" #include "Log.h"
using namespace sc_core;
using namespace sc_dt;
using namespace std;
/** /**
* Memory mapped Trace peripheral address * Memory mapped Trace peripheral address
*/ */
@ -44,51 +41,53 @@ using namespace std;
* It will be expanded with more ports when required (for DMA, * It will be expanded with more ports when required (for DMA,
* other peripherals, etc.) * other peripherals, etc.)
*/ */
class BusCtrl: sc_module { class BusCtrl: sc_core::sc_module {
public: public:
/** /**
* @brief TLM target socket CPU instruction memory bus * @brief TLM target socket CPU instruction memory bus
*/ */
tlm_utils::simple_target_socket<BusCtrl> cpu_instr_socket; tlm_utils::simple_target_socket<BusCtrl> cpu_instr_socket;
/** /**
* @brief TLM target socket CPU data memory bus * @brief TLM target socket CPU data memory bus
*/ */
tlm_utils::simple_target_socket<BusCtrl> cpu_data_socket; tlm_utils::simple_target_socket<BusCtrl> cpu_data_socket;
/** /**
* @brief TLM initiator socket Main memory bus * @brief TLM initiator socket Main memory bus
*/ */
tlm_utils::simple_initiator_socket<BusCtrl> memory_socket; tlm_utils::simple_initiator_socket<BusCtrl> memory_socket;
/** /**
* @brief TLM initiator socket Trace module * @brief TLM initiator socket Trace module
*/ */
tlm_utils::simple_initiator_socket<BusCtrl> trace_socket; tlm_utils::simple_initiator_socket<BusCtrl> trace_socket;
/** /**
* @brief TLM initiator socket Trace module * @brief TLM initiator socket Trace module
*/ */
tlm_utils::simple_initiator_socket<BusCtrl> timer_socket; tlm_utils::simple_initiator_socket<BusCtrl> timer_socket;
/** /**
* @brief constructor * @brief constructor
* @param name module's name * @param name module's name
*/ */
BusCtrl(sc_module_name name); BusCtrl(sc_core::sc_module_name name);
/** /**
* @brief TLM-2 blocking mechanism * @brief TLM-2 blocking mechanism
* @param trans transtractino to perform * @param trans transtractino to perform
* @param delay delay associated to this transaction * @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: private:
Log *log; 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&,
void invalidate_direct_mem_ptr(sc_dt::uint64 start, sc_dt::uint64 end); tlm::tlm_dmi &dmi_data);
void invalidate_direct_mem_ptr(sc_dt::uint64 start, sc_dt::uint64 end);
}; };
#endif #endif

157
inc/CPU.h
View File

@ -1,9 +1,11 @@
/*! /*!
\file CPU.h \file CPU.h
\brief Main CPU class \brief Main CPU class
\author Màrius Montón \author Màrius Montón
\date August 2018 \date August 2018
*/ */
// SPDX-License-Identifier: GPL-3.0-or-later
#ifndef CPU_BASE_H #ifndef CPU_BASE_H
#define CPU_BASE_H #define CPU_BASE_H
@ -16,104 +18,97 @@
#include "tlm_utils/tlm_quantumkeeper.h" #include "tlm_utils/tlm_quantumkeeper.h"
#include "memory.h" #include "memory.h"
#include "Execute.h" #include "MemoryInterface.h"
#include "BASE_ISA.h"
#include "Registers.h" #include "Registers.h"
#include "Log.h" #include "Log.h"
#include "Instruction.h" #include "Instruction.h"
#include "C_Instruction.h" #include "C_extension.h"
#include "M_Instruction.h" #include "M_extension.h"
#include "A_Instruction.h" #include "A_extension.h"
using namespace sc_core;
using namespace sc_dt;
using namespace std;
/** /**
* @brief ISC_V CPU model * @brief ISC_V CPU model
* @param name name of the module * @param name name of the module
*/ */
class CPU: sc_module { class CPU: sc_core::sc_module {
public: public:
/** /**
* @brief Instruction Memory bus socket * @brief Instruction Memory bus socket
* @param trans transction to perfoem * @param trans transction to perfoem
* @param delay time to annotate * @param delay time to annotate
*/ */
tlm_utils::simple_initiator_socket<CPU> instr_bus; tlm_utils::simple_initiator_socket<CPU> instr_bus;
/** /**
* @brief IRQ line socket * @brief IRQ line socket
* @param trans transction to perform (empty) * @param trans transction to perform (empty)
* @param delay time to annotate * @param delay time to annotate
*/ */
tlm_utils::simple_target_socket<CPU> irq_line_socket; tlm_utils::simple_target_socket<CPU> irq_line_socket;
/** /**
* @brief Constructor * @brief Constructor
* @param name Module name * @param name Module name
* @param PC Program Counter initialize value * @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 * @brief Destructor
*/ */
~CPU(); ~CPU();
Execute *exec; MemoryInterface *mem_intf;
private: private:
Registers *register_bank; Registers *register_bank;
Performance *perf; Performance *perf;
Log *log; Log *log;
Instruction * inst; Instruction *inst;
C_Instruction *c_inst; C_extension *c_inst;
M_Instruction *m_inst; M_extension *m_inst;
A_Instruction *a_inst; A_extension *a_inst;
BASE_ISA *exec;
tlm_utils::tlm_quantumkeeper *m_qk; tlm_utils::tlm_quantumkeeper *m_qk;
bool interrupt; bool interrupt;
uint32_t int_cause; uint32_t int_cause;
bool irq_already_down; bool irq_already_down;
sc_core::sc_time default_time;
bool dmi_ptr_valid;
sc_time default_time; /**
*
* @brief Process and triggers IRQ if all conditions met
* @return true if IRQ is triggered, false otherwise
*/
bool cpu_process_IRQ();
bool dmi_ptr_valid; /**
* main thread for CPU simulation
* @brief CPU mai thread
*/
void CPU_thread(void);
/** /**
* * @brief callback for IRQ simple socket
* @brief Process and triggers IRQ if all conditions met * @param trans transaction to perform (empty)
* @return true if IRQ is triggered, false otherwise * @param delay time to annotate
*/ *
bool cpu_process_IRQ(); * it triggers an IRQ when called
*/
void call_interrupt(tlm::tlm_generic_payload &trans,
sc_core::sc_time &delay);
/** /**
* @brief Executes default ISA instruction * DMI pointer is not longer valid
* @param inst instruction to execute * @param start memory address region start
* @return true if PC is affected by instruction * @param end memory address region end
*/ */
bool process_base_instruction(Instruction &inst); void invalidate_direct_mem_ptr(sc_dt::uint64 start, sc_dt::uint64 end);
bool process_c_instruction(Instruction &inst);
bool process_m_instruction(Instruction &inst);
bool process_a_instruction(Instruction inst);
void CPU_thread(void);
/**
* @brief callback for IRQ simple socket
* @param trans transaction to perform (empty)
* @param delay time to annotate
*
* When called it triggers an IRQ
*/
void call_interrupt(tlm::tlm_generic_payload &trans, sc_time &delay);
void invalidate_direct_mem_ptr(sc_dt::uint64 start, sc_dt::uint64 end);
}; };
#endif #endif

View File

@ -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

422
inc/C_extension.h Normal file
View File

@ -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

View File

@ -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

View File

@ -1,466 +1,65 @@
/*! /*!
\file Instruction.h \file Instruction.h
\brief Decode instructions part of the RISC-V \brief Decode instructions part of the RISC-V
\author Màrius Montón \author Màrius Montón
\date August 2018 \date August 2018
*/ */
// SPDX-License-Identifier: GPL-3.0-or-later
#ifndef INSTRUCTION__H #ifndef INSTRUCTION__H
#define INSTRUCTION__H #define INSTRUCTION__H
#include "systemc" #include "systemc"
#include "extension_base.h"
using namespace sc_core;
using namespace sc_dt;
using namespace std;
typedef enum { typedef enum {
BASE_EXTENSION, BASE_EXTENSION,
M_EXTENSION, M_EXTENSION,
A_EXTENSION, A_EXTENSION,
F_EXTENSION, F_EXTENSION,
D_EXTENSION, D_EXTENSION,
Q_EXTENSION, Q_EXTENSION,
L_EXTENSION, L_EXTENSION,
C_EXTENSION, C_EXTENSION,
R_EXTENSION, R_EXTENSION,
J_EXTENSION, J_EXTENSION,
P_EXTENSION, P_EXTENSION,
V_EXTENSION, V_EXTENSION,
N_EXTENSION, N_EXTENSION,
UNKNOWN_EXTENSION UNKNOWN_EXTENSION
} extension_t; } 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 * @brief Instruction decoding and fields access
*/ */
class Instruction { class Instruction {
public: public:
/** Instruction(sc_dt::sc_uint<32> instr);
* @brief Constructor
* @param instr Instruction to decode
*/
Instruction(sc_uint<32> instr);
/** /**
* @brief Access to opcode field * @brief returns what instruction extension
* @return return opcode field * @return extension
*/ */
inline int32_t opcode() { extension_t check_extension();
return m_instr.range(6,0);
}
/** void setInstr(uint32_t p_instr) {
* @brief Access to rd field m_instr = p_instr;
* @return rd field }
*/ /**
inline int32_t get_rd() { * @brief return instruction
return m_instr.range(11, 7); * @return all instruction bits (31:0)
} */
uint32_t getInstr() {
return m_instr;
}
/** inline void dump() {
* @brief Sets rd field std::cout << std::hex << "0x" << m_instr << std::dec << std::endl;
* @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();
/**
* @brief returns what instruction extension
* @return extension
*/
extension_t check_extension();
void setInstr(uint32_t p_instr) {
m_instr = p_instr;
}
/**
* @brief return instruction
* @return all instruction bits (31:0)
*/
uint32_t getInstr() {
return m_instr;
}
inline void dump() {
cout << hex << "0x" << m_instr << dec << endl;
}
private: private:
sc_uint<32> m_instr; sc_dt::sc_uint<32> m_instr;
}; };
#endif #endif

View File

@ -1,9 +1,10 @@
/*! /*!
\file Log.h \file Log.h
\brief Class to manage Log \brief Class to manage Log
\author Màrius Montón \author Màrius Montón
\date Aug 2018 \date Aug 2018
*/ */
// SPDX-License-Identifier: GPL-3.0-or-later
#ifndef LOG_H #ifndef LOG_H
#define LOG_H #define LOG_H
@ -16,10 +17,6 @@
#include "systemc" #include "systemc"
#include "tlm.h" #include "tlm.h"
using namespace sc_core;
using namespace sc_dt;
using namespace std;
/** /**
* @brief Log management class * @brief Log management class
* *
@ -28,50 +25,48 @@ using namespace std;
class Log { class Log {
public: public:
enum LogLevel{ enum LogLevel {
ERROR = 0, ERROR = 0, DEBUG, WARNING, INFO
DEBUG, } currentLogLevel;
WARNING,
INFO
} currentLogLevel;
/**
* @brief Constructor
* @return pointer to Log class
*/
static Log* getInstance();
/** /**
* @brief Constructor * @brief method to log some string
* @return pointer to Log class * @param msg mesasge string
*/ * @param level level of the log (LogLevel)
static Log* getInstance(); */
void SC_log(std::string msg, enum LogLevel level);
/** /**
* @brief method to log some string * @brief method to log some string
* @param msg mesasge string * @param level level of the log (LogLevel)
* @param level level of the log (LogLevel) * @return streaming
*/ *
void SC_log(std::string msg, enum LogLevel level); * This function can be used in the following way:
* \code
* my_log->SC_log(Log::WARNING) << "some warning text"
* \endcode
*/
std::ofstream& SC_log(enum LogLevel level);
/** /**
* @brief method to log some string * @brief Sets log level
* @param level level of the log (LogLevel) * @param newLevel Level of the log
* @return streaming */
* void setLogLevel(enum LogLevel newLevel);
* This function can be used in the following way:
* \code
* my_log->SC_log(Log::WARNING) << "some warning text"
* \endcode
*/
std::ofstream& SC_log(enum LogLevel level);
/** enum LogLevel getLogLevel();
* @brief Sets log level
* @param newLevel Level of the log
*/
void setLogLevel(enum LogLevel newLevel);
private: private:
static Log* instance; static Log *instance;
Log(const char* filename); Log(const char *filename);
std::ofstream m_stream; std::ofstream m_stream;
std::ofstream m_sink; std::ofstream m_sink;
}; };
#endif #endif

View File

@ -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

129
inc/M_extension.h Normal file
View File

@ -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

View File

@ -1,9 +1,10 @@
/*! /*!
\file Memory.h \file Memory.h
\brief Basic TLM-2 memory model \brief Basic TLM-2 memory model
\author Màrius Montón \author Màrius Montón
\date August 2018 \date August 2018
*/ */
// SPDX-License-Identifier: GPL-3.0-or-later
#ifndef __MEMORY_H__ #ifndef __MEMORY_H__
#define __MEMORY_H__ #define __MEMORY_H__
@ -20,69 +21,68 @@
#include "Log.h" #include "Log.h"
using namespace sc_core;
using namespace sc_dt;
using namespace std;
/** /**
* @brief Basic TLM-2 memory * @brief Basic TLM-2 memory
*/ */
class Memory: sc_module { class Memory: sc_core::sc_module {
public: public:
// TLM-2 socket, defaults to 32-bits wide, base protocol // TLM-2 socket, defaults to 32-bits wide, base protocol
tlm_utils::simple_target_socket<Memory> socket; tlm_utils::simple_target_socket<Memory> socket;
//enum { SIZE = 0x90000000 }; //enum { SIZE = 0x90000000 };
enum { SIZE = 0x10000000 }; enum {
const sc_time LATENCY; SIZE = 0x10000000
};
const sc_core::sc_time LATENCY;
Memory(sc_module_name name, string filename); Memory(sc_core::sc_module_name name, std::string filename);
Memory(sc_module_name name, bool use_file); Memory(sc_core::sc_module_name name, bool use_file);
~Memory(void); ~Memory(void);
/**
* @brief Returns Program Counter read from hexfile
* @return Initial PC
*/
virtual uint32_t getPCfromHEX();
// TLM-2 blocking transport method /**
virtual void b_transport( tlm::tlm_generic_payload& trans, sc_time& delay ); * @brief Returns Program Counter read from hexfile
* @return Initial PC
*/
virtual uint32_t getPCfromHEX();
// ********************************************* // TLM-2 blocking transport method
// TLM-2 forward DMI method virtual void b_transport(tlm::tlm_generic_payload &trans,
// ********************************************* sc_core::sc_time &delay);
virtual bool get_direct_mem_ptr(tlm::tlm_generic_payload& trans,
tlm::tlm_dmi& dmi_data);
// ********************************************* // *********************************************
// TLM-2 debug transport method // TLM-2 forward DMI method
// ********************************************* // *********************************************
virtual unsigned int transport_dbg(tlm::tlm_generic_payload& trans); virtual bool get_direct_mem_ptr(tlm::tlm_generic_payload &trans,
tlm::tlm_dmi &dmi_data);
// *********************************************
// TLM-2 debug transport method
// *********************************************
virtual unsigned int transport_dbg(tlm::tlm_generic_payload &trans);
private: private:
/** /**
* @brief Memory array in bytes * @brief Memory array in bytes
*/ */
//uint8_t mem[SIZE]; uint8_t *mem;
uint8_t *mem;
/** /**
* @brief Log classe * @brief Log class
*/ */
Log *log; Log *log;
/**
* @brief Program counter (PC) read from hex file
*/
uint32_t program_counter;
uint32_t memory_offset; /**
/** * @brief Program counter (PC) read from hex file
* @brief Read Intel hex file */
* @param filename file name to read uint32_t program_counter;
*/
virtual void readHexFile(string filename); uint32_t memory_offset;
/**
* @brief Read Intel hex file
* @param filename file name to read
*/
virtual void readHexFile(std::string filename);
}; };
#endif /* __MEMORY_H__ */ #endif /* __MEMORY_H__ */

34
inc/MemoryInterface.h Normal file
View File

@ -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_ */

View File

@ -1,9 +1,10 @@
/*! /*!
\file Performance.h \file Performance.h
\brief Class to store performance of CPU \brief Class to store performance of CPU
\author Màrius Montón \author Màrius Montón
\date Aug 2018 \date Aug 2018
*/ */
// SPDX-License-Identifier: GPL-3.0-or-later
#ifndef PERFORMANCE_H #ifndef PERFORMANCE_H
#define PERFORMANCE_H #define PERFORMANCE_H
@ -14,89 +15,85 @@
#include "tlm.h" #include "tlm.h"
using namespace sc_core;
using namespace sc_dt;
using namespace std;
/** /**
* @brief Performance indicators class * @brief Performance indicators class
* *
* Singleton class to be shared among all other classes * Singleton class to be shared among all other classes
*/ */
class Performance{ class Performance {
public: public:
/** /**
* @brief Get an instance of the class * @brief Get an instance of the class
* @return pointer to Performance class * @return pointer to Performance class
*/ */
static Performance* getInstance(); static Performance* getInstance();
/** /**
* @brief Increment data memory read counter * @brief Increment data memory read counter
*/ */
inline void dataMemoryRead() { inline void dataMemoryRead() {
data_memory_read++; data_memory_read++;
} }
/** /**
* @brief Increment data memory write counter * @brief Increment data memory write counter
*/ */
inline void dataMemoryWrite() { inline void dataMemoryWrite() {
data_memory_write++; data_memory_write++;
} }
/** /**
* @brief Increment code memory read counter * @brief Increment code memory read counter
*/ */
inline void codeMemoryRead() { inline void codeMemoryRead() {
code_memory_read++; code_memory_read++;
} }
/** /**
* @brief Increment code memory write counter * @brief Increment code memory write counter
*/ */
inline void codeMemoryWrite() { inline void codeMemoryWrite() {
code_memory_write++; code_memory_write++;
} }
/** /**
* @brief Increment register read counter * @brief Increment register read counter
*/ */
inline void registerRead() { inline void registerRead() {
register_read++; register_read++;
} }
/** /**
* @brief Increment register write counter * @brief Increment register write counter
*/ */
inline void registerWrite() { inline void registerWrite() {
register_write++; register_write++;
} }
/** /**
* @brief Increment instructions executed counter * @brief Increment instructions executed counter
*/ */
inline void instructionsInc() { inline void instructionsInc() {
instructions_executed++; instructions_executed++;
} }
/** /**
* @brief Dump counters to cout * @brief Dump counters to cout
*/ */
void dump(); void dump();
private: private:
static Performance* instance; static Performance *instance;
Performance(); Performance();
uint64_t data_memory_read; uint64_t data_memory_read;
uint64_t data_memory_write; uint64_t data_memory_write;
uint64_t code_memory_read; uint64_t code_memory_read;
uint64_t code_memory_write; uint64_t code_memory_write;
uint64_t register_read; uint64_t register_read;
uint64_t register_write; uint64_t register_write;
uint64_t instructions_executed; uint64_t instructions_executed;
}; };
#endif #endif

View File

@ -1,9 +1,11 @@
/*! /*!
\file Registers.h \file Registers.h
\brief Basic register file \brief Basic register file
\author Màrius Montón \author Màrius Montón
\date August 2018 \date August 2018
*/ */
// SPDX-License-Identifier: GPL-3.0-or-later
#ifndef REGISTERS_H #ifndef REGISTERS_H
#define REGISTERS_H #define REGISTERS_H
@ -23,7 +25,6 @@
#define MISA_M_EXTENSION (1 << 12) #define MISA_M_EXTENSION (1 << 12)
#define MISA_MXL (1 << 30) #define MISA_MXL (1 << 30)
#define CSR_MVENDORID (0xF11) #define CSR_MVENDORID (0xF11)
#define CSR_MARCHID (0xF12) #define CSR_MARCHID (0xF12)
#define CSR_MIMPID (0xF13) #define CSR_MIMPID (0xF13)
@ -65,7 +66,6 @@
#define CSR_STVEC (0x105) #define CSR_STVEC (0x105)
#define MSTATUS_UIE (1 << 0) #define MSTATUS_UIE (1 << 0)
#define MSTATUS_SIE (1 << 1) #define MSTATUS_SIE (1 << 1)
#define MSTATUS_MIE (1 << 3) #define MSTATUS_MIE (1 << 3)
@ -103,166 +103,161 @@
#define MIE_SEIE (1 << 9) #define MIE_SEIE (1 << 9)
#define MIE_MEIE (1 << 11) #define MIE_MEIE (1 << 11)
/* 1 ns tick in CYCLE & TIME counters */ /* 1 ns tick in CYCLE & TIME counters */
#define TICKS_PER_SECOND (1000000) #define TICKS_PER_SECOND (1000000)
using namespace sc_core;
using namespace sc_dt;
using namespace std;
/** /**
* @brief Register file implementation * @brief Register file implementation
*/ */
class Registers { class Registers {
public: public:
enum { enum {
x0 = 0, x0 = 0,
x1 = 1, x1 = 1,
x2, x2,
x3, x3,
x4, x4,
x5, x5,
x6, x6,
x7, x7,
x8, x8,
x9, x9,
x10, x10,
x11, x11,
x12, x12,
x13, x13,
x14, x14,
x15, x15,
x16, x16,
x17, x17,
x18, x18,
x19, x19,
x20, x20,
x21, x21,
x22, x22,
x23, x23,
x24, x24,
x25, x25,
x26, x26,
x27, x27,
x28, x28,
x29, x29,
x30, x30,
x31, x31,
zero = x0, zero = x0,
ra = x1, ra = x1,
sp = x2, sp = x2,
gp = x3, gp = x3,
tp = x4, tp = x4,
t0 = x5, t0 = x5,
t1 = x6, t1 = x6,
t2 = x7, t2 = x7,
s0 = x8, s0 = x8,
fp = x8, fp = x8,
s1 = x9, s1 = x9,
a0 = x10, a0 = x10,
a1 = x11, a1 = x11,
a2 = x12, a2 = x12,
a3 = x13, a3 = x13,
a4 = x14, a4 = x14,
a5 = x15, a5 = x15,
a6 = x16, a6 = x16,
a7 = x17, a7 = x17,
s2 = x18, s2 = x18,
s3 = x19, s3 = x19,
s4 = x20, s4 = x20,
s5 = x21, s5 = x21,
s6 = x22, s6 = x22,
s7 = x23, s7 = x23,
s8 = x24, s8 = x24,
s9 = x25, s9 = x25,
s10 = x26, s10 = x26,
s11 = x27, s11 = x27,
t3 = x28, t3 = x28,
t4 = x29, t4 = x29,
t5 = x30, t5 = x30,
t6 = x31 t6 = x31
}; };
/** /**
* Default constructor * Default constructor
*/ */
Registers(); Registers();
/** /**
* Set value for a register * Set value for a register
* @param reg_num register number * @param reg_num register number
* @param value register value * @param value register value
*/ */
void setValue(int reg_num, int32_t value); void setValue(int reg_num, int32_t value);
/** /**
* Returns register value * Returns register value
* @param reg_num register number * @param reg_num register number
* @return register value * @return register value
*/ */
int32_t getValue(int reg_num); int32_t getValue(int reg_num);
/** /**
* Returns PC value * Returns PC value
* @return PC value * @return PC value
*/ */
uint32_t getPC(); uint32_t getPC();
/** /**
* Sets arbitraty value to PC * Sets arbitraty value to PC
* @param new_pc new address to PC * @param new_pc new address to PC
*/ */
void setPC(uint32_t new_pc); void setPC(uint32_t new_pc);
/** /**
* Increments PC couunter to next address * Increments PC couunter to next address
*/ */
inline void incPC(bool C_ext=false) { inline void incPC(bool C_ext = false) {
if (C_ext == true) { if (C_ext == true) {
register_PC += 2; register_PC += 2;
} else { } else {
register_PC += 4; register_PC += 4;
} }
} }
/** /**
* @brief Get CSR value * @brief Get CSR value
* @param csr CSR number to access * @param csr CSR number to access
* @return CSR value * @return CSR value
*/ */
uint32_t getCSR(int csr); uint32_t getCSR(int csr);
/** /**
* @brief Set CSR value * @brief Set CSR value
* @param csr CSR number to access * @param csr CSR number to access
* @param value new value to register * @param value new value to register
*/ */
void setCSR(int csr, uint32_t value); void setCSR(int csr, uint32_t value);
/** /**
* Dump register data to console * Dump register data to console
*/ */
void dump(); void dump();
private: private:
/** /**
* bank of registers (32 regs of 32bits each) * bank of registers (32 regs of 32bits each)
*/ */
int32_t register_bank[32]; int32_t register_bank[32];
/** /**
* Program counter (32 bits width) * Program counter (32 bits width)
*/ */
uint32_t register_PC; uint32_t register_PC;
/** /**
* CSR registers (4096 maximum) * CSR registers (4096 maximum)
*/ */
uint32_t CSR[4096]; uint32_t CSR[4096];
Performance *perf; Performance *perf;
void initCSR(void); void initCSR(void);
}; };
#endif #endif

View File

@ -1,9 +1,10 @@
/*! /*!
\file Timer.h \file Timer.h
\brief Basic TLM-2 Timer module \brief Basic TLM-2 Timer module
\author Màrius Montón \author Màrius Montón
\date January 2019 \date January 2019
*/ */
// SPDX-License-Identifier: GPL-3.0-or-later
#ifndef __TIMER_H__ #ifndef __TIMER_H__
#define __TIMER_H__ #define __TIMER_H__
@ -20,54 +21,50 @@
#include "BusCtrl.h" #include "BusCtrl.h"
using namespace sc_core;
using namespace sc_dt;
using namespace std;
/** /**
* @brief Simple timer peripheral * @brief Simple timer peripheral
* *
* It runs a 1 ns (nanoseconds) pace * It runs a 1 ns (nanoseconds) pace
* *
*/ */
class Timer: sc_module { class Timer: sc_core::sc_module {
public: public:
// TLM-2 socket, defaults to 32-bits wide, base protocol // TLM-2 socket, defaults to 32-bits wide, base protocol
tlm_utils::simple_target_socket<Timer> socket; tlm_utils::simple_target_socket<Timer> socket;
tlm_utils::simple_initiator_socket<Timer> irq_line; tlm_utils::simple_initiator_socket<Timer> irq_line;
//sc_out<bool> timer_irq;
/** /**
* *
* @brief Constructor * @brief Constructor
* @param name module name * @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 * @brief Waits for event timer_event and triggers an IRQ
* *
* Waits for event timer_event and triggers an IRQ (if it is not already * Waits for event timer_event and triggers an IRQ (if it is not already
* triggered). * triggered).
* After that, it posts the timer_event to 20 ns in the future to clear the IRQ * After that, it posts the timer_event to 20 ns in the future to clear the IRQ
* line. * line.
* *
*/ */
void run(); void run();
/** /**
* *
* @brief TLM-2.0 socket implementation * @brief TLM-2.0 socket implementation
* @param trans TLM-2.0 transaction * @param trans TLM-2.0 transaction
* @param delay transaction delay time * @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: private:
sc_uint<64> m_mtime; /**< mtime register */ sc_dt::sc_uint<64> m_mtime; /**< mtime register */
sc_uint<64> m_mtimecmp; /**< mtimecmp register */ sc_dt::sc_uint<64> m_mtimecmp; /**< mtimecmp register */
sc_event timer_event; /**< event */ sc_core::sc_event timer_event; /**< event */
}; };
#endif #endif

View File

@ -1,9 +1,10 @@
/*! /*!
\file Trace.h \file Trace.h
\brief Basic TLM-2 Trace module \brief Basic TLM-2 Trace module
\author Màrius Montón \author Màrius Montón
\date September 2018 \date September 2018
*/ */
// SPDX-License-Identifier: GPL-3.0-or-later
#ifndef __TRACE_H__ #ifndef __TRACE_H__
#define __TRACE_H__ #define __TRACE_H__
@ -18,46 +19,43 @@
#include "tlm.h" #include "tlm.h"
#include "tlm_utils/simple_target_socket.h" #include "tlm_utils/simple_target_socket.h"
using namespace sc_core;
using namespace sc_dt;
using namespace std;
/** /**
* @brief Simple trace peripheral * @brief Simple trace peripheral
* *
* This peripheral outputs to cout any character written to its unique register * This peripheral outputs to cout any character written to its unique register
*/ */
class Trace: sc_module { class Trace: sc_core::sc_module {
public: public:
/** /**
* @brief Bus socket * @brief Bus socket
*/ */
tlm_utils::simple_target_socket<Trace> socket; tlm_utils::simple_target_socket<Trace> socket;
/**
* @brief Constructor
* @param name Module name
*/
Trace(sc_core::sc_module_name name);
/**
* @brief Destructor
*/
~Trace();
/**
* @brief Constructor
* @param name Module name
*/
Trace(sc_module_name name);
/**
* @brief Destructor
*/
~Trace();
private: private:
// TLM-2 blocking transport method // 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 ); void xtermLaunch(char *slaveName);
void xtermSetup(void); void xtermKill(const char *mess);
void xtermSetup(void);
int ptSlave;
int ptMaster; int ptSlave;
int xtermPid; int ptMaster;
int xtermPid;
}; };
#endif #endif

58
inc/extension_base.h Normal file
View File

@ -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_ */

View File

@ -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;
}

416
src/A_extension.cpp Normal file
View File

@ -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;
}

1489
src/BASE_ISA.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,38 +1,46 @@
/**
@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" #include "BusCtrl.h"
SC_HAS_PROCESS(BusCtrl); SC_HAS_PROCESS(BusCtrl);
BusCtrl::BusCtrl(sc_module_name name): sc_module(name) BusCtrl::BusCtrl(sc_core::sc_module_name name) :
,cpu_instr_socket("cpu_instr_socket") sc_module(name), cpu_instr_socket("cpu_instr_socket"), cpu_data_socket(
,cpu_data_socket("cpu_data_socket") "cpu_data_socket"), memory_socket("memory_socket"), trace_socket(
,memory_socket("memory_socket") "trace_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);
cpu_instr_socket.register_b_transport(this, &BusCtrl::b_transport); log = Log::getInstance();
cpu_data_socket.register_b_transport(this, &BusCtrl::b_transport); cpu_instr_socket.register_get_direct_mem_ptr(this,
log = Log::getInstance(); &BusCtrl::instr_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,
memory_socket.register_invalidate_direct_mem_ptr( this, &BusCtrl::invalidate_direct_mem_ptr); &BusCtrl::invalidate_direct_mem_ptr);
} }
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;
void BusCtrl::b_transport( tlm::tlm_generic_payload& trans, sc_time& delay ) { switch (adr) {
//tlm::tlm_command cmd = trans.get_command(); case TIMER_MEMORY_ADDRESS_HI / 4:
sc_dt::uint64 adr = trans.get_address() / 4; case TIMER_MEMORY_ADDRESS_LO / 4:
case TIMERCMP_MEMORY_ADDRESS_HI / 4:
switch (adr) { case TIMERCMP_MEMORY_ADDRESS_LO / 4:
case TIMER_MEMORY_ADDRESS_HI / 4: timer_socket->b_transport(trans, delay);
case TIMER_MEMORY_ADDRESS_LO / 4: break;
case TIMERCMP_MEMORY_ADDRESS_HI / 4: case TRACE_MEMORY_ADDRESS / 4:
case TIMERCMP_MEMORY_ADDRESS_LO / 4: trace_socket->b_transport(trans, delay);
timer_socket->b_transport(trans, delay); break;
break; default:
case TRACE_MEMORY_ADDRESS / 4: memory_socket->b_transport(trans, delay);
trace_socket->b_transport(trans, delay); break;
break; }
default:
memory_socket->b_transport(trans, delay);
break;
}
#if 0 #if 0
if (cmd == tlm::TLM_READ_COMMAND) { if (cmd == tlm::TLM_READ_COMMAND) {
@ -42,14 +50,16 @@ void BusCtrl::b_transport( tlm::tlm_generic_payload& trans, sc_time& delay ) {
} }
#endif #endif
trans.set_response_status( tlm::TLM_OK_RESPONSE ); 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); 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); cpu_instr_socket->invalidate_direct_mem_ptr(start, end);
} }

View File

@ -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" #include "CPU.h"
SC_HAS_PROCESS(CPU); SC_HAS_PROCESS(CPU);
CPU::CPU(sc_module_name name, uint32_t PC) : CPU::CPU(sc_core::sc_module_name name, uint32_t PC) :
sc_module(name), instr_bus("instr_bus"), default_time(10, SC_NS) { sc_module(name), instr_bus("instr_bus"), default_time(10,
sc_core::SC_NS) {
register_bank = new Registers(); register_bank = new Registers();
exec = new Execute("Execute", register_bank); mem_intf = new MemoryInterface();
perf = Performance::getInstance(); perf = Performance::getInstance();
log = Log::getInstance(); log = Log::getInstance();
@ -23,10 +33,11 @@ CPU::CPU(sc_module_name name, uint32_t PC) :
instr_bus.register_invalidate_direct_mem_ptr(this, instr_bus.register_invalidate_direct_mem_ptr(this,
&CPU::invalidate_direct_mem_ptr); &CPU::invalidate_direct_mem_ptr);
inst = new Instruction(0); inst = new Instruction(0);
c_inst = new C_Instruction(0); exec = new BASE_ISA(0, register_bank, mem_intf);
m_inst = new M_Instruction(0); c_inst = new C_extension(0, register_bank, mem_intf);
a_inst = new A_Instruction(0); 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(); m_qk = new tlm_utils::tlm_quantumkeeper();
@ -34,11 +45,19 @@ CPU::CPU(sc_module_name name, uint32_t PC) :
} }
CPU::~CPU() { CPU::~CPU() {
cout << "*********************************************" << endl; std::cout << "*********************************************" << std::endl;
register_bank->dump(); register_bank->dump();
cout << "end time: " << sc_time_stamp() << endl; std::cout << "end time: " << sc_core::sc_time_stamp() << std::endl;
perf->dump(); 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() { bool CPU::cpu_process_IRQ() {
@ -49,7 +68,7 @@ bool CPU::cpu_process_IRQ() {
if (interrupt == true) { if (interrupt == true) {
csr_temp = register_bank->getCSR(CSR_MSTATUS); csr_temp = register_bank->getCSR(CSR_MSTATUS);
if ((csr_temp & MSTATUS_MIE) == 0) { 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; return ret_value;
} }
@ -58,13 +77,13 @@ bool CPU::cpu_process_IRQ() {
if ((csr_temp & MIP_MEIP) == 0) { if ((csr_temp & MIP_MEIP) == 0) {
csr_temp |= MIP_MEIP; // MEIP bit in MIP register (11th bit) csr_temp |= MIP_MEIP; // MEIP bit in MIP register (11th bit)
register_bank->setCSR(CSR_MIP, csr_temp); 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 */ /* updated MEPC register */
old_pc = register_bank->getPC(); old_pc = register_bank->getPC();
register_bank->setCSR(CSR_MEPC, old_pc); register_bank->setCSR(CSR_MEPC, old_pc);
log->SC_log(Log::INFO) << "Old PC Value 0x" << hex << old_pc log->SC_log(Log::INFO) << "Old PC Value 0x" << std::hex << old_pc
<< endl; << std::endl;
/* update MCAUSE register */ /* update MCAUSE register */
register_bank->setCSR(CSR_MCAUSE, 0x80000000); register_bank->setCSR(CSR_MCAUSE, 0x80000000);
@ -72,8 +91,8 @@ bool CPU::cpu_process_IRQ() {
/* set new PC address */ /* set new PC address */
new_pc = register_bank->getCSR(CSR_MTVEC); new_pc = register_bank->getCSR(CSR_MTVEC);
//new_pc = new_pc & 0xFFFFFFFC; // last two bits always to 0 //new_pc = new_pc & 0xFFFFFFFC; // last two bits always to 0
log->SC_log(Log::DEBUG) << "NEW PC Value 0x" << hex << new_pc log->SC_log(Log::DEBUG) << "NEW PC Value 0x" << std::hex << new_pc
<< endl; << std::endl;
register_bank->setPC(new_pc); register_bank->setPC(new_pc);
ret_value = true; ret_value = true;
@ -92,376 +111,11 @@ bool CPU::cpu_process_IRQ() {
return ret_value; 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) { void CPU::CPU_thread(void) {
tlm::tlm_generic_payload *trans = new tlm::tlm_generic_payload; tlm::tlm_generic_payload *trans = new tlm::tlm_generic_payload;
uint32_t INSTR; 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 PC_not_affected = false;
bool incPCby2 = false; bool incPCby2 = false;
tlm::tlm_dmi dmi_data; tlm::tlm_dmi dmi_data;
@ -475,7 +129,6 @@ void CPU::CPU_thread(void) {
trans->set_dmi_allowed(false); // Mandatory initial value trans->set_dmi_allowed(false); // Mandatory initial value
trans->set_response_status(tlm::TLM_INCOMPLETE_RESPONSE); trans->set_response_status(tlm::TLM_INCOMPLETE_RESPONSE);
//Instruction inst(0);
m_qk->reset(); m_qk->reset();
while (1) { while (1) {
@ -502,7 +155,7 @@ void CPU::CPU_thread(void) {
perf->codeMemoryRead(); 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); inst->setInstr(INSTR);
@ -510,26 +163,26 @@ void CPU::CPU_thread(void) {
/* check what type of instruction is and execute it */ /* check what type of instruction is and execute it */
switch (inst->check_extension()) { switch (inst->check_extension()) {
case BASE_EXTENSION: case BASE_EXTENSION:
PC_not_affected = process_base_instruction(*inst); PC_not_affected = exec->process_instruction(*inst);
incPCby2 = false; incPCby2 = false;
break; break;
case C_EXTENSION: case C_EXTENSION:
PC_not_affected = process_c_instruction(*inst); PC_not_affected = c_inst->process_instruction(*inst);
incPCby2 = true; incPCby2 = true;
break; break;
case M_EXTENSION: case M_EXTENSION:
PC_not_affected = process_m_instruction(*inst); PC_not_affected = m_inst->process_instruction(*inst);
incPCby2 = false; incPCby2 = false;
break; break;
case A_EXTENSION: case A_EXTENSION:
PC_not_affected = process_a_instruction(*inst); PC_not_affected = a_inst->process_instruction(*inst);
incPCby2 = false; incPCby2 = false;
break; break;
default: default:
std::cout << "Extension not implemented yet" << std::endl; std::cout << "Extension not implemented yet" << std::endl;
inst->dump(); inst->dump();
exec->NOP(*inst); exec->NOP();
} // switch (inst.check_extension()) }
perf->instructionsInc(); perf->instructionsInc();
@ -549,14 +202,15 @@ void CPU::CPU_thread(void) {
m_qk->sync(); m_qk->sync();
} }
#else #else
sc_core::wait(10, SC_NS); sc_core::wait(10, sc_core::SC_NS);
#endif #endif
} // while(1) } // while(1)
} // CPU_thread } // 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; interrupt = true;
/* Socket caller send a cause (its id) */ /* Socket caller send a cause (its id) */
memcpy(&int_cause, trans.get_data_ptr(), sizeof(uint32_t)); memcpy(&int_cause, trans.get_data_ptr(), sizeof(uint32_t));

View File

@ -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;
}

756
src/C_extension.cpp Normal file
View File

@ -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;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,186 +1,33 @@
/*!
\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" #include "Instruction.h"
Instruction::Instruction(sc_dt::sc_uint<32> instr) {
Instruction::Instruction(sc_uint<32> instr) { m_instr = 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() { extension_t Instruction::check_extension() {
if ( (m_instr.range(6,0) == 0b0110011) && if ((m_instr.range(6, 0) == 0b0110011)
(m_instr.range(31,25) == 0b0000001) ){ && (m_instr.range(31, 25) == 0b0000001)) {
return M_EXTENSION; return M_EXTENSION;
} else if (m_instr.range(6,0) == 0b0101111) { } else if (m_instr.range(6, 0) == 0b0101111) {
return A_EXTENSION; return A_EXTENSION;
} else if (m_instr.range(1,0) == 0b11) { } else if (m_instr.range(1, 0) == 0b11) {
return BASE_EXTENSION; return BASE_EXTENSION;
} else if (m_instr.range(1,0) == 0b00) { } else if (m_instr.range(1, 0) == 0b00) {
return C_EXTENSION; return C_EXTENSION;
} else if (m_instr.range(1,0) == 0b01) { } else if (m_instr.range(1, 0) == 0b01) {
return C_EXTENSION; return C_EXTENSION;
} else if (m_instr.range(1,0) == 0b10) { } else if (m_instr.range(1, 0) == 0b10) {
return C_EXTENSION; return C_EXTENSION;
} else { } else {
return UNKNOWN_EXTENSION; return UNKNOWN_EXTENSION;
} }
} }

View File

@ -1,41 +1,52 @@
/*!
\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" #include "Log.h"
Log* Log::getInstance() Log* Log::getInstance() {
{ if (instance == 0) {
if (instance == 0) { instance = new Log("Log.txt");
instance = new Log("Log.txt"); }
}
return instance; return instance;
} }
Log::Log(const char* filename) { Log::Log(const char *filename) {
m_stream.open(filename); m_stream.open(filename);
currentLogLevel = Log::INFO; currentLogLevel = Log::INFO;
} }
void Log::SC_log(std::string msg, enum LogLevel level) { void Log::SC_log(std::string msg, enum LogLevel level) {
if (level <= currentLogLevel) { 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;
}
} }
std::ofstream& Log::SC_log(enum LogLevel level) { std::ofstream& Log::SC_log(enum LogLevel level) {
if (level <= currentLogLevel) { if (level <= currentLogLevel) {
m_stream << "time " << sc_core::sc_time_stamp() << ": "; m_stream << "time " << sc_core::sc_time_stamp() << ": ";
return m_stream; return m_stream;
} else { } else {
return m_sink; return m_sink;
} }
} }
void Log::setLogLevel(enum LogLevel newLevel) { void Log::setLogLevel(enum LogLevel newLevel) {
std::cout << "LogLevel set to " << newLevel << std::endl; std::cout << "LogLevel set to " << newLevel << std::endl;
currentLogLevel = newLevel; currentLogLevel = newLevel;
} }
Log* Log::instance = 0; enum Log::LogLevel Log::getLogLevel() {
return currentLogLevel;
}
Log *Log::instance = 0;

View File

@ -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;
}

287
src/M_extension.cpp Normal file
View File

@ -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;
}

View File

@ -1,191 +1,200 @@
/*!
\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" #include "Memory.h"
SC_HAS_PROCESS(Memory); SC_HAS_PROCESS(Memory);
Memory::Memory(sc_module_name name, string filename): sc_module(name) Memory::Memory(sc_core::sc_module_name name, std::string filename) :
,socket("socket") sc_module(name), socket("socket"), LATENCY(sc_core::SC_ZERO_TIME) {
,LATENCY(SC_ZERO_TIME) { // Register callbacks for incoming interface method calls
// Register callbacks for incoming interface method calls socket.register_b_transport(this, &Memory::b_transport);
socket.register_b_transport( this, &Memory::b_transport); socket.register_get_direct_mem_ptr(this, &Memory::get_direct_mem_ptr);
socket.register_get_direct_mem_ptr(this, &Memory::get_direct_mem_ptr); socket.register_transport_dbg(this, &Memory::transport_dbg);
socket.register_transport_dbg( this, &Memory::transport_dbg);
mem = new uint8_t[SIZE]; mem = new uint8_t[SIZE];
//memset(mem, 0, SIZE*sizeof(uint8_t)); //memset(mem, 0, SIZE*sizeof(uint8_t));
memory_offset = 0; memory_offset = 0;
readHexFile(filename); readHexFile(filename);
log = Log::getInstance(); 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) Memory::Memory(sc_core::sc_module_name name, bool use_file) :
,socket("socket") sc_module(name), socket("socket"), LATENCY(sc_core::SC_ZERO_TIME) {
,LATENCY(SC_ZERO_TIME) { socket.register_b_transport(this, &Memory::b_transport);
socket.register_b_transport( this, &Memory::b_transport); socket.register_get_direct_mem_ptr(this, &Memory::get_direct_mem_ptr);
socket.register_get_direct_mem_ptr(this, &Memory::get_direct_mem_ptr); socket.register_transport_dbg(this, &Memory::transport_dbg);
socket.register_transport_dbg( this, &Memory::transport_dbg); memory_offset = 0;
memory_offset = 0; program_counter = 0;
program_counter = 0;
//memset(mem, 0, SIZE*sizeof(uint8_t)); mem = new uint8_t[SIZE];
//
mem = new uint8_t[SIZE]; log = Log::getInstance();
log = Log::getInstance(); log->SC_log(Log::INFO) << "Memory instantiated wihtout file" << std::endl;
log->SC_log(Log::INFO) << "Memory instantiated wihtout file" << endl; }
}
Memory::~Memory() { Memory::~Memory() {
delete mem; delete[] mem;
} }
uint32_t Memory::getPCfromHEX() { uint32_t Memory::getPCfromHEX() {
return program_counter; 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(); tlm::tlm_command cmd = trans.get_command();
sc_dt::uint64 adr = trans.get_address(); sc_dt::uint64 adr = trans.get_address();
unsigned char* ptr = trans.get_data_ptr(); unsigned char *ptr = trans.get_data_ptr();
unsigned int len = trans.get_data_length(); unsigned int len = trans.get_data_length();
unsigned char* byt = trans.get_byte_enable_ptr(); unsigned char *byt = trans.get_byte_enable_ptr();
unsigned int wid = trans.get_streaming_width(); unsigned int wid = trans.get_streaming_width();
adr = adr - memory_offset; adr = adr - memory_offset;
// Obliged to check address range and check for unsupported features, // Obliged to check address range and check for unsupported features,
// i.e. byte enables, streaming, and bursts // i.e. byte enables, streaming, and bursts
// Can ignore extensions // Can ignore extensions
// ********************************************* // *********************************************
// Generate the appropriate error response // Generate the appropriate error response
// ********************************************* // *********************************************
if (adr >= sc_dt::uint64(SIZE)) { if (adr >= sc_dt::uint64(SIZE)) {
trans.set_response_status( tlm::TLM_ADDRESS_ERROR_RESPONSE ); trans.set_response_status(tlm::TLM_ADDRESS_ERROR_RESPONSE);
return; return;
} }
if (byt != 0) { if (byt != 0) {
trans.set_response_status( tlm::TLM_BYTE_ENABLE_ERROR_RESPONSE ); trans.set_response_status(tlm::TLM_BYTE_ENABLE_ERROR_RESPONSE);
return; return;
} }
if (len > 4 || wid < len) { if (len > 4 || wid < len) {
trans.set_response_status( tlm::TLM_BURST_ERROR_RESPONSE ); trans.set_response_status(tlm::TLM_BURST_ERROR_RESPONSE);
return; return;
} }
// Obliged to implement read and write commands // Obliged to implement read and write commands
if ( cmd == tlm::TLM_READ_COMMAND ) if (cmd == tlm::TLM_READ_COMMAND)
memcpy(ptr, &mem[adr], len); memcpy(ptr, &mem[adr], len);
else if ( cmd == tlm::TLM_WRITE_COMMAND ) else if (cmd == tlm::TLM_WRITE_COMMAND)
memcpy(&mem[adr], ptr, len); memcpy(&mem[adr], ptr, len);
// Illustrates that b_transport may block // Illustrates that b_transport may block
wait(delay); wait(delay);
// Reset timing annotation after waiting // Reset timing annotation after waiting
delay = SC_ZERO_TIME; delay = sc_core::SC_ZERO_TIME;
// ********************************************* // *********************************************
// Set DMI hint to indicated that DMI is supported // Set DMI hint to indicated that DMI is supported
// ********************************************* // *********************************************
if (memory_offset == 0) { if (memory_offset == 0) {
trans.set_dmi_allowed(true); trans.set_dmi_allowed(true);
} else { } else {
trans.set_dmi_allowed(false); trans.set_dmi_allowed(false);
} }
// Obliged to set response status to indicate successful completion // Obliged to set response status to indicate successful completion
trans.set_response_status( tlm::TLM_OK_RESPONSE ); trans.set_response_status(tlm::TLM_OK_RESPONSE);
} }
bool Memory::get_direct_mem_ptr(tlm::tlm_generic_payload& trans, 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) {
if (memory_offset != 0) { return false;
return false; }
}
// Permit read and write access
dmi_data.allow_read_write();
// Set other details of DMI region // Permit read and write access
dmi_data.set_dmi_ptr( reinterpret_cast<unsigned char*>( &mem[0] ) ); dmi_data.allow_read_write();
dmi_data.set_start_address( 0 );
dmi_data.set_end_address( SIZE*4-1 );
dmi_data.set_read_latency( LATENCY );
dmi_data.set_write_latency( LATENCY );
return true; // Set other details of DMI region
dmi_data.set_dmi_ptr(reinterpret_cast<unsigned char*>(&mem[0]));
dmi_data.set_start_address(0);
dmi_data.set_end_address(SIZE * 4 - 1);
dmi_data.set_read_latency(LATENCY);
dmi_data.set_write_latency(LATENCY);
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();
tlm::tlm_command cmd = trans.get_command(); sc_dt::uint64 adr = trans.get_address();
sc_dt::uint64 adr = trans.get_address(); unsigned char *ptr = trans.get_data_ptr();
unsigned char* ptr = trans.get_data_ptr(); unsigned int len = trans.get_data_length();
unsigned int len = trans.get_data_length();
// Calculate the number of bytes to be actually copied // Calculate the number of bytes to be actually copied
unsigned int num_bytes = (len < (SIZE - adr) * 4) ? len : (SIZE - adr) * 4; unsigned int num_bytes = (len < (SIZE - adr) * 4) ? len : (SIZE - adr) * 4;
if ( cmd == tlm::TLM_READ_COMMAND ) if (cmd == tlm::TLM_READ_COMMAND)
memcpy(ptr, &mem[adr], num_bytes); memcpy(ptr, &mem[adr], num_bytes);
else if ( cmd == tlm::TLM_WRITE_COMMAND ) else if (cmd == tlm::TLM_WRITE_COMMAND)
memcpy(&mem[adr], ptr, num_bytes); memcpy(&mem[adr], ptr, num_bytes);
return num_bytes; return num_bytes;
} }
void Memory::readHexFile(string filename) { void Memory::readHexFile(std::string filename) {
ifstream hexfile; std::ifstream hexfile;
string line; std::string line;
int byte_count; int byte_count;
uint32_t address; uint32_t address;
int i = 0; int i = 0;
uint32_t extended_address = 0; uint32_t extended_address = 0;
hexfile.open(filename); hexfile.open(filename);
if (hexfile.is_open()) { if (hexfile.is_open()) {
while(getline(hexfile, line) ) { while (getline(hexfile, line)) {
if (line[0] == ':') { if (line[0] == ':') {
if (line.substr(7,2) == "00") { if (line.substr(7, 2) == "00") {
/* Data */ /* Data */
byte_count = stol(line.substr(1,2), nullptr, 16); byte_count = stol(line.substr(1, 2), nullptr, 16);
address = stol(line.substr(3,4), nullptr, 16); address = stol(line.substr(3, 4), nullptr, 16);
address = address + extended_address; address = address + extended_address;
//cout << "00 address 0x" << hex << address << endl; //cout << "00 address 0x" << hex << address << endl;
for (i=0; i < byte_count; i++) { 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 */ } else if (line.substr(7, 2) == "02") {
extended_address = stol(line.substr(9,4), nullptr, 16) * 16; /* Extended segment address */
cout << "02 extended address 0x" << hex << extended_address << dec << endl; extended_address = stol(line.substr(9, 4), nullptr, 16)
} else if (line.substr(7,2) == "03") { * 16;
/* Start segment address */ std::cout << "02 extended address 0x" << std::hex
uint32_t code_segment; << extended_address << std::dec << std::endl;
code_segment = stol(line.substr(9,4), nullptr, 16) * 16; /* ? */ } else if (line.substr(7, 2) == "03") {
program_counter = stol(line.substr(13,4), nullptr, 16); /* Start segment address */
program_counter = program_counter + code_segment; uint32_t code_segment;
cout << "03 PC set to 0x" << hex << program_counter << dec << endl; code_segment = stol(line.substr(9, 4), nullptr, 16) * 16; /* ? */
} else if (line.substr(7,2) == "04") { program_counter = stol(line.substr(13, 4), nullptr, 16);
/* Start segment address */ program_counter = program_counter + code_segment;
memory_offset = stol(line.substr(9,4), nullptr, 16) << 16; std::cout << "03 PC set to 0x" << std::hex
extended_address = 0; << program_counter << std::dec << std::endl;
cout << "04 address set to 0x" << hex << extended_address << dec << endl; } else if (line.substr(7, 2) == "04") {
cout << "04 offset set to 0x" << hex << memory_offset << dec << endl; /* Start segment address */
} else if (line.substr(7,2) == "05") { memory_offset = stol(line.substr(9, 4), nullptr, 16) << 16;
program_counter = stol(line.substr(9,8), nullptr, 16); extended_address = 0;
cout << "05 PC set to 0x" << hex << program_counter << 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;
hexfile.close(); } else if (line.substr(7, 2) == "05") {
} else { program_counter = stol(line.substr(9, 8), nullptr, 16);
SC_REPORT_ERROR("Memory", "Open file error"); std::cout << "05 PC set to 0x" << std::hex
} << program_counter << std::dec << std::endl;
}
}
}
hexfile.close();
} else {
SC_REPORT_ERROR("Memory", "Open file error");
}
} }

66
src/MemoryInterface.cpp Normal file
View File

@ -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);
}

View File

@ -1,34 +1,41 @@
/*!
\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" #include "Performance.h"
Performance* Performance::getInstance() Performance* Performance::getInstance() {
{ if (instance == 0) {
if (instance == 0) instance = new Performance();
{ }
instance = new Performance();
}
return instance; return instance;
} }
Performance::Performance() Performance::Performance() {
{ data_memory_read = 0;
data_memory_read = 0; data_memory_write = 0;
data_memory_write = 0; code_memory_read = 0;
code_memory_read = 0; code_memory_write = 0;
code_memory_write = 0; register_read = 0;
register_read = 0; register_write = 0;
register_write = 0; instructions_executed = 0;
instructions_executed = 0;
} }
void Performance::dump() { void Performance::dump() {
cout << dec << "# data memory reads: " << data_memory_read << endl; std::cout << std::dec << "# data memory reads: " << data_memory_read
cout << "# data memory writes: " << data_memory_write << endl; << std::endl;
cout << "# code memory reads: " << code_memory_read << endl; std::cout << "# data memory writes: " << data_memory_write << std::endl;
cout << "# code memory writes: " << code_memory_write << endl; std::cout << "# code memory reads: " << code_memory_read << std::endl;
cout << "# registers read: " << register_read << endl; std::cout << "# code memory writes: " << code_memory_write << std::endl;
cout << "# registers write: " << register_write << endl; std::cout << "# registers read: " << register_read << std::endl;
cout << "# instructions executed: " << instructions_executed << endl; std::cout << "# registers write: " << register_write << std::endl;
std::cout << "# instructions executed: " << instructions_executed
<< std::endl;
} }
Performance* Performance::instance = 0; Performance *Performance::instance = 0;

View File

@ -1,141 +1,180 @@
/*! /*!
\file Registers.cpp \file Registers.cpp
\brief Basic register file implementation \brief Basic register file implementation
\author Màrius Montón \author Màrius Montón
\date August 2018 \date August 2018
*/ */
// SPDX-License-Identifier: GPL-3.0-or-later
#include "Registers.h" #include "Registers.h"
Registers::Registers() { Registers::Registers() {
memset(register_bank, 0, sizeof(uint32_t)*32); // 32 registers of 32 bits each memset(register_bank, 0, sizeof(uint32_t) * 32); // 32 registers of 32 bits each
memset(CSR, 0, sizeof(uint32_t)*4096); memset(CSR, 0, sizeof(uint32_t) * 4096);
perf = Performance::getInstance(); perf = Performance::getInstance();
initCSR(); initCSR();
//cout << "Memory size: 0x" << hex << Memory::SIZE << endl; //std::cout << "Memory size: 0x" << std::hex << Memory::SIZE << std::endl;
//cout << "SP address: 0x" << hex << (0x10000000 / 4) - 1 << 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_bank[sp] = Memory::SIZE - 4; // default stack at the end of the memory
register_PC = 0x80000000; // default _start address register_PC = 0x80000000; // default _start address
} }
void Registers::dump(void) { void Registers::dump(void) {
cout << "************************************" << endl; std::cout << "************************************" << std::endl;
cout << "Registers dump" << dec << endl; std::cout << "Registers dump" << std::dec << std::endl;
cout << "x0 (zero): " << right << setw(11) << register_bank[0]; std::cout << "x0 (zero): " << std::right << std::setw(11)
cout << " x1 (ra): " << right << setw(11) << register_bank[1]; << register_bank[0];
cout << " x2 (sp): " << right << setw(11) << register_bank[2]; std::cout << " x1 (ra): " << std::right << std::setw(11)
cout << " x3 (gp): " << right << setw(11) << register_bank[3] << endl; << 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]; std::cout << "x4 (tp): " << std::right << std::setw(11)
cout << " x5 (t0): " << right << setw(11) << register_bank[5]; << register_bank[4];
cout << " x6 (t1): " << right << setw(11) << register_bank[6]; std::cout << " x5 (t0): " << std::right << std::setw(11)
cout << " x7 (t2): " << right << setw(11) << register_bank[7] << endl; << 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]; std::cout << "x8 (s0/fp): " << std::right << std::setw(11)
cout << " x9 (s1): " << right << setw(11) << register_bank[9]; << register_bank[8];
cout << " x10 (a0): " << right << setw(11) << register_bank[10]; std::cout << " x9 (s1): " << std::right << std::setw(11)
cout << " x11 (a1): " << right << setw(11) << register_bank[11] << endl; << 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]; std::cout << "x12 (a2): " << std::right << std::setw(11)
cout << " x13 (a3): " << right << setw(11) << register_bank[13]; << register_bank[12];
cout << " x14 (a4): " << right << setw(11) << register_bank[14]; std::cout << " x13 (a3): " << std::right << std::setw(11)
cout << " x15 (a5): " << right << setw(11) << register_bank[15] << endl; << 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]; std::cout << "x16 (a6): " << std::right << std::setw(11)
cout << " x17 (a7): " << right << setw(11) << register_bank[17]; << register_bank[16];
cout << " x18 (s2): " << right << setw(11) << register_bank[18]; std::cout << " x17 (a7): " << std::right << std::setw(11)
cout << " x19 (s3): " << right << setw(11) << register_bank[19] << endl; << 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]; std::cout << "x20 (s4): " << std::right << std::setw(11)
cout << " x21 (s5): " << right << setw(11) << register_bank[21]; << register_bank[20];
cout << " x22 (s6): " << right << setw(11) << register_bank[22]; std::cout << " x21 (s5): " << std::right << std::setw(11)
cout << " x23 (s7): " << right << setw(11) << register_bank[23] << endl; << 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]; std::cout << "x24 (s8): " << std::right << std::setw(11)
cout << " x25 (s9): " << right << setw(11) << register_bank[25]; << register_bank[24];
cout << " x26 (s10): " << right << setw(11) << register_bank[26]; std::cout << " x25 (s9): " << std::right << std::setw(11)
cout << " x27 (s11): " << right << setw(11) << register_bank[27] << endl; << 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]; std::cout << "x28 (t3): " << std::right << std::setw(11)
cout << " x29 (t4): " << right << setw(11) << register_bank[29]; << register_bank[28];
cout << " x30 (t5): " << right << setw(11) << register_bank[30]; std::cout << " x29 (t4): " << std::right << std::setw(11)
cout << " x31 (t6): " << right << setw(11) << register_bank[31] << endl; << 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; std::cout << "PC: 0x" << std::hex << register_PC << std::dec << std::endl;
cout << "************************************" << endl; std::cout << "************************************" << std::endl;
} }
void Registers::setValue(int reg_num, int32_t value) { void Registers::setValue(int reg_num, int32_t value) {
if ((reg_num != 0) && (reg_num < 32)) { if ((reg_num != 0) && (reg_num < 32)) {
register_bank[reg_num] = value; register_bank[reg_num] = value;
perf->registerWrite(); perf->registerWrite();
} }
} }
int32_t Registers::getValue(int reg_num) { int32_t Registers::getValue(int reg_num) {
if ((reg_num >= 0) && (reg_num < 32)){ if ((reg_num >= 0) && (reg_num < 32)) {
perf->registerRead(); perf->registerRead();
return register_bank[reg_num]; return register_bank[reg_num];
} else { } else {
return 0xFFFFFFFF; return 0xFFFFFFFF;
} }
} }
uint32_t Registers::getPC() { uint32_t Registers::getPC() {
return register_PC; return register_PC;
} }
void Registers::setPC(uint32_t new_pc) { void Registers::setPC(uint32_t new_pc) {
register_PC = new_pc; register_PC = new_pc;
} }
uint32_t Registers::getCSR(int csr) { uint32_t Registers::getCSR(int csr) {
uint32_t ret_value = 0; uint32_t ret_value = 0;
switch (csr) { switch (csr) {
case CSR_CYCLE: case CSR_CYCLE:
case CSR_MCYCLE: case CSR_MCYCLE:
ret_value = (uint64_t)(sc_time(sc_time_stamp() ret_value = (uint64_t) (sc_core::sc_time(
- sc_time(SC_ZERO_TIME)).to_double()) & 0x00000000FFFFFFFF; sc_core::sc_time_stamp()
break; - sc_core::sc_time(sc_core::SC_ZERO_TIME)).to_double())
case CSR_CYCLEH: & 0x00000000FFFFFFFF;
case CSR_MCYCLEH: break;
ret_value = (uint32_t)((uint64_t)(sc_time(sc_time_stamp() case CSR_CYCLEH:
- sc_time(SC_ZERO_TIME)).to_double()) >> 32 & 0x00000000FFFFFFFF); case CSR_MCYCLEH:
break; ret_value = (uint32_t) ((uint64_t) (sc_core::sc_time(
case CSR_TIME: sc_core::sc_time_stamp()
ret_value = (uint64_t)(sc_time(sc_time_stamp() - sc_core::sc_time(sc_core::SC_ZERO_TIME)).to_double())
- sc_time(SC_ZERO_TIME)).to_double()) & 0x00000000FFFFFFFF; >> 32 & 0x00000000FFFFFFFF);
break; break;
case CSR_TIMEH: case CSR_TIME:
ret_value = (uint32_t)((uint64_t)(sc_time(sc_time_stamp() ret_value = (uint64_t) (sc_core::sc_time(
- sc_time(SC_ZERO_TIME)).to_double()) >> 32 & 0x00000000FFFFFFFF); sc_core::sc_time_stamp()
break; - sc_core::sc_time(sc_core::SC_ZERO_TIME)).to_double())
default: & 0x00000000FFFFFFFF;
ret_value = CSR[csr]; break;
break; case CSR_TIMEH:
} ret_value = (uint32_t) ((uint64_t) (sc_core::sc_time(
return ret_value; sc_core::sc_time_stamp()
- sc_core::sc_time(sc_core::SC_ZERO_TIME)).to_double())
>> 32 & 0x00000000FFFFFFFF);
break;
default:
ret_value = CSR[csr];
break;
}
return ret_value;
} }
void Registers::setCSR(int csr, uint32_t value) { void Registers::setCSR(int csr, uint32_t value) {
/* @FIXME: rv32mi-p-ma_fetch tests doesn't allow MISA to writable, /* @FIXME: rv32mi-p-ma_fetch tests doesn't allow MISA to writable,
* but Volume II: Privileged Architectura v1.10 says MISRA is writable (?) * but Volume II: Privileged Architectura v1.10 says MISRA is writable (?)
*/ */
if (csr != CSR_MISA) { if (csr != CSR_MISA) {
CSR[csr] = value; CSR[csr] = value;
} }
} }
void Registers::initCSR() { void Registers::initCSR() {
CSR[CSR_MISA] = MISA_MXL | MISA_M_EXTENSION | MISA_C_EXTENSION CSR[CSR_MISA] = MISA_MXL | MISA_M_EXTENSION | MISA_C_EXTENSION
| MISA_A_EXTENSION | MISA_I_BASE; | MISA_A_EXTENSION | MISA_I_BASE;
CSR[CSR_MSTATUS] = MISA_MXL ; CSR[CSR_MSTATUS] = MISA_MXL;
} }

View File

@ -1,9 +1,9 @@
/*! /*!
\file Simulator.cpp \file Simulator.cpp
\brief Top level simulation entity \brief Top level simulation entity
\author Màrius Montón \author Màrius Montón
\date September 2018 \date September 2018
*/ */
#define SC_INCLUDE_DYNAMIC_PROCESSES #define SC_INCLUDE_DYNAMIC_PROCESSES
@ -21,11 +21,7 @@
#include "Trace.h" #include "Trace.h"
#include "Timer.h" #include "Timer.h"
using namespace sc_core; std::string filename;
using namespace sc_dt;
using namespace std;
string filename;
/** /**
* @class Simulator * @class Simulator
@ -34,57 +30,55 @@ string filename;
* *
* @brief Top simulation entity * @brief Top simulation entity
*/ */
SC_MODULE(Simulator) SC_MODULE(Simulator) {
{ CPU *cpu;
CPU *cpu; Memory *MainMemory;
Memory *MainMemory; BusCtrl *Bus;
BusCtrl* Bus; Trace *trace;
Trace *trace; Timer *timer;
Timer *timer;
uint32_t start_PC; uint32_t start_PC;
SC_CTOR(Simulator) SC_CTOR(Simulator) {
{ MainMemory = new Memory("Main_Memory", filename);
MainMemory = new Memory("Main_Memory", filename); start_PC = MainMemory->getPCfromHEX();
start_PC = MainMemory->getPCfromHEX();
cpu = new CPU("cpu", start_PC); cpu = new CPU("cpu", start_PC);
Bus = new BusCtrl("BusCtrl"); Bus = new BusCtrl("BusCtrl");
trace = new Trace("Trace"); trace = new Trace("Trace");
timer = new Timer("Timer"); timer = new Timer("Timer");
cpu->instr_bus.bind(Bus->cpu_instr_socket); 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->memory_socket.bind(MainMemory->socket);
Bus->trace_socket.bind(trace->socket); Bus->trace_socket.bind(trace->socket);
Bus->timer_socket.bind(timer->socket); Bus->timer_socket.bind(timer->socket);
//timer->timer_irq.bind(IRQ); //timer->timer_irq.bind(IRQ);
// cpu->interrupt.bind(IRQ); // cpu->interrupt.bind(IRQ);
timer->irq_line.bind(cpu->irq_line_socket); timer->irq_line.bind(cpu->irq_line_socket);
} }
~Simulator() { ~Simulator() {
delete cpu; delete MainMemory;
delete MainMemory; delete cpu;
delete Bus; delete Bus;
delete trace; delete trace;
delete timer; delete timer;
} }
}; };
Simulator *top; Simulator *top;
void intHandler(int dummy) { void intHandler(int dummy) {
delete top; delete top;
//sc_stop(); //sc_stop();
exit(-1); exit(-1);
} }
void process_arguments(int argc, char* argv[]) { void process_arguments(int argc, char *argv[]) {
int c; int c;
int debug_level; int debug_level;
@ -92,35 +86,36 @@ void process_arguments(int argc, char* argv[]) {
log = Log::getInstance(); log = Log::getInstance();
log->setLogLevel(Log::ERROR); log->setLogLevel(Log::ERROR);
while ((c = getopt (argc, argv, "D:f:?")) != -1) { while ((c = getopt(argc, argv, "D:f:?")) != -1) {
switch (c) { switch (c) {
case 'D': case 'D':
debug_level = atoi(optarg); debug_level = atoi(optarg);
switch (debug_level) { switch (debug_level) {
case 3: case 3:
log->setLogLevel(Log::INFO); log->setLogLevel(Log::INFO);
break;
case 2:
log->setLogLevel(Log::WARNING);
break;
case 1:
log->setLogLevel(Log::DEBUG);
break;
case 0:
log->setLogLevel(Log::ERROR);
break;
default:
log->setLogLevel(Log::INFO);
break;
}
break; break;
case 'f' : case 2:
filename = std::string(optarg); log->setLogLevel(Log::WARNING);
break; break;
case '?' : case 1:
std::cout << "Call ./RISCV_TLM -D <debuglevel> (0..3) filename.hex" << std::endl; log->setLogLevel(Log::DEBUG);
break; break;
case 0:
log->setLogLevel(Log::ERROR);
break;
default:
log->setLogLevel(Log::INFO);
break;
}
break;
case 'f':
filename = std::string(optarg);
break;
case '?':
std::cout << "Call ./RISCV_TLM -D <debuglevel> (0..3) filename.hex"
<< std::endl;
break;
} }
} }
@ -129,26 +124,25 @@ 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 */ /* Capture Ctrl+C and finish the simulation */
signal(SIGINT, intHandler); signal(SIGINT, intHandler);
/* SystemC time resolution set to 1 ns*/ /* 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 */ /* Parse and process program arguments. -f is mandatory */
process_arguments(argc, argv); process_arguments(argc, argv);
top = new Simulator("top"); top = new Simulator("top");
sc_start(); sc_core::sc_start();
cout << "Press Enter to finish" << endl; std::cout << "Press Enter to finish" << std::endl;
cin.ignore(); std::cin.ignore();
// call all destructors, clean exit. // call all destructors, clean exit.
delete top; delete top;
return 0; return 0;
} }

View File

@ -1,84 +1,93 @@
/*!
\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" #include "Timer.h"
SC_HAS_PROCESS(Timer); SC_HAS_PROCESS(Timer);
Timer::Timer(sc_module_name name): sc_module(name) Timer::Timer(sc_core::sc_module_name name) :
,socket("timer_socket"), m_mtime(0), m_mtimecmp(0) { sc_module(name), socket("timer_socket"), m_mtime(0), m_mtimecmp(0) {
socket.register_b_transport(this, &Timer::b_transport); socket.register_b_transport(this, &Timer::b_transport);
SC_THREAD(run); SC_THREAD(run);
} }
void Timer::run() { void Timer::run() {
tlm::tlm_generic_payload* irq_trans = new tlm::tlm_generic_payload; 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 uint32_t cause = 1 << 31 | 0x07; // Machine timer interrupt
irq_trans->set_command(tlm::TLM_WRITE_COMMAND); irq_trans->set_command(tlm::TLM_WRITE_COMMAND);
irq_trans->set_data_ptr( reinterpret_cast<unsigned char*>(&cause) ); irq_trans->set_data_ptr(reinterpret_cast<unsigned char*>(&cause));
irq_trans->set_data_length( 4 ); irq_trans->set_data_length(4);
irq_trans->set_streaming_width( 4 ); irq_trans->set_streaming_width(4);
irq_trans->set_byte_enable_ptr( 0 ); irq_trans->set_byte_enable_ptr(0);
irq_trans->set_dmi_allowed(false); irq_trans->set_dmi_allowed(false);
irq_trans->set_response_status(tlm::TLM_INCOMPLETE_RESPONSE); irq_trans->set_response_status(tlm::TLM_INCOMPLETE_RESPONSE);
irq_trans->set_address( 0 ); irq_trans->set_address(0);
while(true) { while (true) {
wait(timer_event); wait(timer_event);
irq_line->b_transport(*irq_trans, delay); irq_line->b_transport(*irq_trans, delay);
} }
} }
void Timer::b_transport( tlm::tlm_generic_payload& trans, sc_time& delay ) { void Timer::b_transport(tlm::tlm_generic_payload &trans,
tlm::tlm_command cmd = trans.get_command(); sc_core::sc_time &delay) {
sc_dt::uint64 addr = trans.get_address(); tlm::tlm_command cmd = trans.get_command();
unsigned char* ptr = trans.get_data_ptr(); sc_dt::uint64 addr = trans.get_address();
unsigned int len = trans.get_data_length(); unsigned char *ptr = trans.get_data_ptr();
//unsigned char* byt = trans.get_byte_enable_ptr(); unsigned int len = trans.get_data_length();
//unsigned int wid = trans.get_streaming_width(); //unsigned char* byt = trans.get_byte_enable_ptr();
//unsigned int wid = trans.get_streaming_width();
uint32_t aux_value = 0; uint32_t aux_value = 0;
uint64_t notify_time = 0; uint64_t notify_time = 0;
if (cmd == tlm::TLM_WRITE_COMMAND) { if (cmd == tlm::TLM_WRITE_COMMAND) {
memcpy(&aux_value, ptr, len); memcpy(&aux_value, ptr, len);
switch (addr) { switch (addr) {
case TIMER_MEMORY_ADDRESS_LO: case TIMER_MEMORY_ADDRESS_LO:
m_mtime.range(31,0) = aux_value; m_mtime.range(31, 0) = aux_value;
break; break;
case TIMER_MEMORY_ADDRESS_HI: case TIMER_MEMORY_ADDRESS_HI:
m_mtime.range(63,32) = aux_value; m_mtime.range(63, 32) = aux_value;
break; break;
case TIMERCMP_MEMORY_ADDRESS_LO: case TIMERCMP_MEMORY_ADDRESS_LO:
m_mtimecmp.range(31,0) = aux_value; m_mtimecmp.range(31, 0) = aux_value;
break; break;
case TIMERCMP_MEMORY_ADDRESS_HI: case TIMERCMP_MEMORY_ADDRESS_HI:
m_mtimecmp.range(63,32) = aux_value; m_mtimecmp.range(63, 32) = aux_value;
// notify needs relative time, mtimecmp works in absolute time // notify needs relative time, mtimecmp works in absolute time
notify_time = m_mtimecmp - m_mtime; 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; break;
} }
} else { // TLM_READ_COMMAND } else { // TLM_READ_COMMAND
switch (addr) { switch (addr) {
case TIMER_MEMORY_ADDRESS_LO: 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); aux_value = m_mtime.range(31, 0);
break; break;
case TIMER_MEMORY_ADDRESS_HI: case TIMER_MEMORY_ADDRESS_HI:
aux_value = m_mtime.range(63,32); aux_value = m_mtime.range(63, 32);
break; break;
case TIMERCMP_MEMORY_ADDRESS_LO: case TIMERCMP_MEMORY_ADDRESS_LO:
aux_value = m_mtimecmp.range(31,0); aux_value = m_mtimecmp.range(31, 0);
break; break;
case TIMERCMP_MEMORY_ADDRESS_HI: case TIMERCMP_MEMORY_ADDRESS_HI:
aux_value = m_mtimecmp.range(63,32); aux_value = m_mtimecmp.range(63, 32);
break; break;
} }
memcpy(ptr, &aux_value, len); memcpy(ptr, &aux_value, len);
} }
trans.set_response_status( tlm::TLM_OK_RESPONSE ); trans.set_response_status(tlm::TLM_OK_RESPONSE);
} }

View File

@ -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 <stdio.h>
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>
@ -10,105 +18,100 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/wait.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 // https://github.com/embecosm/esp1-systemc-tlm/blob/master/sysc-models/simple-soc/TermSC.h
#include "Trace.h" #include "Trace.h"
void Trace::xtermLaunch( char *slaveName ) { void Trace::xtermLaunch(char *slaveName) {
char *arg; char *arg;
char *fin = &(slaveName[strlen( slaveName ) - 2]); char *fin = &(slaveName[strlen(slaveName) - 2]);
if( NULL == strchr(fin, '/' )) { if ( NULL == strchr(fin, '/')) {
arg = new char[2 + 1 + 1 + 20 + 1]; arg = new char[2 + 1 + 1 + 20 + 1];
sprintf( arg, "-S%c%c%d", fin[0], fin[1], ptMaster ); sprintf(arg, "-S%c%c%d", fin[0], fin[1], ptMaster);
} else { } else {
char *slaveBase = ::basename( slaveName ); char *slaveBase = ::basename(slaveName);
arg = new char[2 + strlen( slaveBase ) + 1 + 20 + 1]; arg = new char[2 + strlen(slaveBase) + 1 + 20 + 1];
sprintf( arg, "-S%s/%d", slaveBase, ptMaster ); sprintf(arg, "-S%s/%d", slaveBase, ptMaster);
} }
char *argv[3]; char *argv[3];
argv[0] = (char *)( "xterm" ); argv[0] = (char*) ("xterm");
argv[1] = arg; argv[1] = arg;
argv[2] = NULL; argv[2] = NULL;
execvp( "xterm", argv ); execvp("xterm", argv);
} }
void Trace::xtermKill( const char *mess ) { void Trace::xtermKill(const char *mess) {
if (-1 != ptSlave) { // Close down the slave
if( -1 != ptSlave ) { // Close down the slave close(ptSlave); // Close the FD
ptSlave = -1;
close( ptSlave ); // Close the FD }
ptSlave = -1;
} if (-1 != ptMaster) { // Close down the master
close(ptMaster);
if( -1 != ptMaster ) { // Close down the master ptMaster = -1;
close( ptMaster ); }
ptMaster = -1;
} if (xtermPid > 0) { // Kill the terminal
kill(xtermPid, SIGKILL);
if( xtermPid > 0 ) { // Kill the terminal waitpid(xtermPid, NULL, 0);
kill( xtermPid, SIGKILL ); }
waitpid( xtermPid, NULL, 0 );
} if ( NULL != mess) { // If we really want a message
perror(mess);
if( NULL != mess ) { // If we really want a message }
perror( mess );
}
} }
void Trace::xtermSetup(void) { void Trace::xtermSetup(void) {
ptMaster = open("/dev/ptmx", O_RDWR); ptMaster = open("/dev/ptmx", O_RDWR);
if (ptMaster != -1) { if (ptMaster != -1) {
grantpt( ptMaster ); grantpt(ptMaster);
unlockpt( ptMaster ); unlockpt(ptMaster);
char *ptSlaveName = ptsname( ptMaster ); char *ptSlaveName = ptsname(ptMaster);
ptSlave = open( ptSlaveName, O_RDWR ); // In and out are the same ptSlave = open(ptSlaveName, O_RDWR); // In and out are the same
struct termios termInfo; struct termios termInfo;
tcgetattr( ptSlave, &termInfo ); tcgetattr(ptSlave, &termInfo);
termInfo.c_lflag &= ~ECHO; termInfo.c_lflag &= ~ECHO;
termInfo.c_lflag &= ~ICANON; termInfo.c_lflag &= ~ICANON;
tcsetattr( ptSlave, TCSADRAIN, &termInfo ); tcsetattr(ptSlave, TCSADRAIN, &termInfo);
xtermPid = fork(); xtermPid = fork();
if (xtermPid == 0) { if (xtermPid == 0) {
xtermLaunch( ptSlaveName ); xtermLaunch(ptSlaveName);
} }
} }
} }
SC_HAS_PROCESS(Trace); SC_HAS_PROCESS(Trace);
Trace::Trace(sc_module_name name): sc_module(name) Trace::Trace(sc_core::sc_module_name name) :
,socket("socket") { sc_module(name), socket("socket") {
socket.register_b_transport(this, &Trace::b_transport); socket.register_b_transport(this, &Trace::b_transport);
xtermSetup(); xtermSetup();
} }
Trace::~Trace() { Trace::~Trace() {
xtermKill( NULL ); xtermKill( NULL);
} }
void Trace::b_transport( tlm::tlm_generic_payload& trans, sc_time& delay ) {
//tlm::tlm_command cmd = trans.get_command(); void Trace::b_transport(tlm::tlm_generic_payload &trans,
//sc_dt::uint64 adr = trans.get_address() / 4; sc_core::sc_time &delay) {
unsigned char* ptr = trans.get_data_ptr();
//unsigned int len = trans.get_data_length(); unsigned char *ptr = trans.get_data_ptr();
//unsigned char* byt = trans.get_byte_enable_ptr();
//unsigned int wid = trans.get_streaming_width(); write(ptSlave, ptr, 1);
write(ptSlave, ptr, 1); trans.set_response_status(tlm::TLM_OK_RESPONSE);
trans.set_response_status( tlm::TLM_OK_RESPONSE );
} }

70
src/extension_base.cpp Normal file
View File

@ -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;
}