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