initial import
This commit is contained in:
parent
26e67681f0
commit
35e688837a
|
@ -30,3 +30,6 @@
|
|||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
|
||||
Log.txt
|
||||
helper.ods
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
TARGET = RISCV_TLM
|
||||
|
||||
SYSTEMC=/home/marius/Work/RiscV/code/systemc-2.3.2
|
||||
TARGET_ARCH=linux64
|
||||
|
||||
CC = g++
|
||||
# compiling flags here
|
||||
CFLAGS = -Wall -I.
|
||||
|
||||
LINKER = g++
|
||||
# linking flags here
|
||||
LFLAGS = -Wall -I. -lm
|
||||
LIBS = -lsystemc -lm $(EXTRA_LIBS)
|
||||
|
||||
|
||||
# change these to proper directories where each file should be
|
||||
SRCDIR = src
|
||||
OBJDIR = obj
|
||||
BINDIR = ./
|
||||
INCDIR = -I. -I./inc -I$(SYSTEMC)/include -Ibasic_protocol -I$(SYSTEMC)/include/tlm_core/tlm_2
|
||||
LIBDIR = -L. -L$(SYSTEMC)/lib-$(TARGET_ARCH)
|
||||
|
||||
|
||||
SOURCES := $(wildcard $(SRCDIR)/*.cpp)
|
||||
INCLUDES := $(wildcard $(INCDIR)/*.h)
|
||||
OBJECTS := $(SOURCES:$(SRCDIR)/%.cpp=$(OBJDIR)/%.o)
|
||||
rm = rm -f
|
||||
|
||||
|
||||
$(BINDIR)/$(TARGET): $(OBJECTS)
|
||||
@$(LINKER) $(OBJECTS) $(LFLAGS) $(LIBS) $(LIBDIR) -o $@
|
||||
@echo "Linking complete!"
|
||||
|
||||
$(OBJECTS): $(OBJDIR)/%.o : $(SRCDIR)/%.cpp
|
||||
# @$(CC) $(CFLAGS) $(INCDIR) -c $< -o $@
|
||||
@echo "Compiling "$<" ..."
|
||||
@$(CC) $(CFLAGS) $(INCDIR) -c $< -o $@
|
||||
@echo "Done!"
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@$(rm) $(OBJECTS)
|
||||
@echo "Cleanup complete!"
|
||||
|
||||
.PHONY: remove
|
||||
remove: clean
|
||||
@$(rm) $(BINDIR)/$(TARGET)
|
||||
@echo "Executable removed!"
|
|
@ -0,0 +1,90 @@
|
|||
# Another RISC-V ISA simulator.
|
||||
|
||||
**This code is suitable to hard refactor at any time**
|
||||
|
||||
This is another RISC-V ISA simulator, this is coded in SystemC + TLM-2.
|
||||
|
||||
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 and PC
|
||||
* RISC_V_execute: Executes every ISA instruction
|
||||
* Instruction: Decodes instruction and acces to any instruction field
|
||||
|
||||
Helper classes:
|
||||
* Performance: Performance indicators stores here (singleton class)
|
||||
* Log: Log class to log them all (singleton class)
|
||||
|
||||
|
||||
## TODO
|
||||
This is a preliminar and incomplete version.
|
||||
|
||||
Task to do:
|
||||
* implement all missing instructions (RISC_V_execute)
|
||||
* still unresolved data memory access (need to implement hierarchical socket
|
||||
from CPU to RISC_V_execute)
|
||||
* Implement CSRs
|
||||
* Add full support to .elf and .hex filetypes to memory.h
|
||||
(only partial .hex support)
|
||||
* Connect some TLM peripherals
|
||||
* Test, test, test & test. I'm sure there are a lot of bugs in the code
|
||||
|
||||
## compile
|
||||
In order to compile the project you need SystemC-2.3.2 installed in your system.
|
||||
Just change SYSTEMC path in Makefile.
|
||||
|
||||
```
|
||||
$ make
|
||||
```
|
||||
|
||||
Then, you need to modifiy your LD_LIBRARY_PATH environtment variable to add
|
||||
path systemc library. In my case:
|
||||
```
|
||||
$ export LD_LIBRARY_PATH=/home/marius/Work/RiscV/code/systemc-2.3.2/lib-linux64
|
||||
```
|
||||
|
||||
And then you can execute the simulator:
|
||||
```
|
||||
$ ./RISCV_TLM asm/BasicLoop.hex
|
||||
```
|
||||
|
||||
## Test
|
||||
In the asm directory there are some basic assembly examples.
|
||||
|
||||
I "compile" one file with the follwing command:
|
||||
```
|
||||
$ cd asm
|
||||
$ riscv32-unknown-linux-gnu-as EternalLoop.asm
|
||||
$ objcopy -O ihex a.out EternalLoop.hex
|
||||
$ cd ..
|
||||
$ ./RISCV_SCTLM asm/EternalLoop.hex
|
||||
```
|
||||
This example needs that you hit Ctr+C to stop execution.
|
||||
|
||||
## Documentation
|
||||
The code is documented using doxygen. In the doc folder there is a Doxygen.cfg
|
||||
file ready to be used.
|
||||
|
||||
## Contribute
|
||||
There are several ways to contribute to this project:
|
||||
* Test
|
||||
* Pull request are welcome (see TODO list)
|
||||
* Good documentation
|
||||
|
||||
## License
|
||||
|
||||
Copyright (C) 2018 Màrius Montón ([\@mariusmonton](https://twitter.com/mariusmonton/))
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
@ -0,0 +1,7 @@
|
|||
# Basic loop
|
||||
ADDI t1, zero, 10 # t1 to 10
|
||||
ADDI t2, zero, 1 #t2 to 1
|
||||
loop:
|
||||
SUB t1, t1, t2
|
||||
BNE t1, zero, loop
|
||||
# END
|
|
@ -0,0 +1,2 @@
|
|||
:100000001303A0009303100033037340E31E03FEA9
|
||||
:00000001FF
|
|
@ -0,0 +1,7 @@
|
|||
li t1, 150
|
||||
li t2, 300
|
||||
li t3, -250
|
||||
ADD t4, t1, t2
|
||||
ADD t5, t2, t3
|
||||
SUB t6, t2, t1
|
||||
#SUB t7, t1, t2
|
|
@ -0,0 +1,8 @@
|
|||
li t1, 150
|
||||
li t2, 300
|
||||
li t3, -250
|
||||
loop:
|
||||
ADD t4, t1, t2
|
||||
ADD t5, t2, t3
|
||||
SUB t6, t2, t1
|
||||
J loop
|
|
@ -0,0 +1,3 @@
|
|||
:10000000130360099303C012130E60F0B30E730064
|
||||
:0C001000338FC301B38F63406FF05FFFBC
|
||||
:00000001FF
|
|
@ -0,0 +1,3 @@
|
|||
:10000000130360099303C012130E60F0B30E730064
|
||||
:0C001000338FC301B38F63406FF05FFFBC
|
||||
:00000001FF
|
|
@ -0,0 +1,18 @@
|
|||
# Simple example
|
||||
# JAL +2048
|
||||
#0010006F
|
||||
# JAL +256
|
||||
#1000006F
|
||||
# JAL +4
|
||||
0040006F
|
||||
# ADD rd = R1, rs1 = R1, rs2 = R2
|
||||
002080B3
|
||||
# SUB rd = R3, rs1 = R1, rs2 = R2
|
||||
402081B3
|
||||
# ADD rd = R1, rs1 = R1, rs2 = R2
|
||||
002080B3
|
||||
# JAL -8
|
||||
# FF9FF06F
|
||||
# JAL -12
|
||||
FF1FF06F
|
||||
# END
|
|
@ -0,0 +1,3 @@
|
|||
:10000000130360099303C012130E60F0B30E730064
|
||||
:0C001000338FC301B38F63406FF05FFFBC
|
||||
:00000001FF
|
|
@ -0,0 +1,8 @@
|
|||
# test1.asm
|
||||
JAL +4
|
||||
ADD t1, t1, t2
|
||||
SUB t3, t1, t2
|
||||
ADD t1, t1, t2
|
||||
# JAL -12
|
||||
J 10
|
||||
LUI t2, 250
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,52 @@
|
|||
/*!
|
||||
\file CPU.h
|
||||
\brief Main CPU class
|
||||
\author Màrius Montón
|
||||
\date August 2018
|
||||
*/
|
||||
#ifndef CPU_BASE_H
|
||||
#define CPU_BASE_H
|
||||
|
||||
#define SC_INCLUDE_DYNAMIC_PROCESSES
|
||||
|
||||
#include "systemc"
|
||||
|
||||
#include "tlm.h"
|
||||
#include "tlm_utils/simple_initiator_socket.h"
|
||||
|
||||
#include "memory.h"
|
||||
#include "Instruction.h"
|
||||
#include "RISC_V_execute.h"
|
||||
#include "Registers.h"
|
||||
#include "Log.h"
|
||||
|
||||
using namespace sc_core;
|
||||
using namespace sc_dt;
|
||||
using namespace std;
|
||||
|
||||
/**
|
||||
* @brief ISC_V CPU model
|
||||
* @param name name of the module
|
||||
*/
|
||||
class CPU: sc_module {
|
||||
public:
|
||||
|
||||
tlm_utils::simple_initiator_socket<CPU> instr_bus;
|
||||
|
||||
//tlm_utils::simple_initiator_socket<cpu_base> data_bus;
|
||||
|
||||
//sc_in<sc_signal<bool> > interrupt;
|
||||
|
||||
CPU(sc_module_name name);
|
||||
~CPU();
|
||||
|
||||
private:
|
||||
Registers *register_bank;
|
||||
RISC_V_execute *exec;
|
||||
Performance *perf;
|
||||
Log *log;
|
||||
|
||||
void CPU_thread(void);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,279 @@
|
|||
/*!
|
||||
\file Instruction.h
|
||||
\brief Decode instructions part of the RISC-V
|
||||
\author Màrius Montón
|
||||
\date August 2018
|
||||
*/
|
||||
|
||||
#ifndef INSTRUCTION__H
|
||||
#define INSTRUCTION__H
|
||||
|
||||
#include "systemc"
|
||||
|
||||
using namespace sc_core;
|
||||
using namespace sc_dt;
|
||||
using namespace std;
|
||||
|
||||
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_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,
|
||||
} Codes;
|
||||
|
||||
/**
|
||||
* @brief Instruction decoding and fields access
|
||||
*/
|
||||
class Instruction{
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Constructor
|
||||
* @param instr Instruction to decode
|
||||
*/
|
||||
Instruction(sc_int<32> instr);
|
||||
|
||||
/**
|
||||
* @brief Access to opcode field
|
||||
* @return return opcode field
|
||||
*/
|
||||
inline int32_t opcode() {
|
||||
// cout << "OP: " << m_instr << endl;
|
||||
return m_instr.range(6,0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Access to rd field
|
||||
* @return rd field
|
||||
*/
|
||||
inline int32_t rd() {
|
||||
return m_instr.range(11, 7);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Access to funct3 field
|
||||
* @return funct3 field
|
||||
*/
|
||||
inline int32_t funct3() {
|
||||
return m_instr.range(14, 12);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Access to rs1 field
|
||||
* @return rs1 field
|
||||
*/
|
||||
inline int32_t rs1() {
|
||||
return m_instr.range(19, 15);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Access to rs2 field
|
||||
* @return rs2 field
|
||||
*/
|
||||
inline int32_t rs2() {
|
||||
return m_instr.range(24, 20);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Access to funct7 field
|
||||
* @return funct7 field
|
||||
*/
|
||||
inline int32_t funct7() {
|
||||
return m_instr.range(31, 25);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Access to immediate field for I-type
|
||||
* @return immediate_I field
|
||||
*/
|
||||
inline int32_t 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 Access to immediate field for S-type
|
||||
* @return immediate_S field
|
||||
*/
|
||||
inline int32_t 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 Access to immediate field for U-type
|
||||
* @return immediate_U field
|
||||
*/
|
||||
inline int32_t imm_U() {
|
||||
return m_instr.range(31, 12);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Access to immediate field for B-type
|
||||
* @return immediate_B field
|
||||
*/
|
||||
inline int32_t 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 Access to immediate field for J-type
|
||||
* @return immediate_J field
|
||||
*/
|
||||
inline int32_t 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;
|
||||
}
|
||||
|
||||
inline int32_t csr() {
|
||||
return imm_I();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Decodes opcode of instruction
|
||||
* @return opcode of instruction
|
||||
*/
|
||||
opCodes decode();
|
||||
|
||||
inline void dump() {
|
||||
cout << hex << "0x" << m_instr << dec << endl;
|
||||
}
|
||||
private:
|
||||
sc_int<32> m_instr;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,76 @@
|
|||
/*!
|
||||
\file Log.h
|
||||
\brief Class to manage Log
|
||||
\author Màrius Montón
|
||||
\date Aug 2018
|
||||
*/
|
||||
|
||||
#ifndef LOG_H
|
||||
#define LOG_H
|
||||
|
||||
#define SC_INCLUDE_DYNAMIC_PROCESSES
|
||||
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include "systemc"
|
||||
#include "tlm.h"
|
||||
|
||||
using namespace sc_core;
|
||||
using namespace sc_dt;
|
||||
using namespace std;
|
||||
|
||||
/**
|
||||
* @brief Log management class
|
||||
*
|
||||
* Singleton class to be shared among all other classes
|
||||
*/
|
||||
class Log {
|
||||
public:
|
||||
|
||||
enum LogLevel{
|
||||
INFO=0,
|
||||
DEBUG,
|
||||
WARNING,
|
||||
ERROR
|
||||
} currentLogLevel;
|
||||
|
||||
|
||||
/**
|
||||
* @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 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);
|
||||
|
||||
private:
|
||||
static Log* instance;
|
||||
Log(const char* filename);
|
||||
std::ofstream m_stream;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,71 @@
|
|||
/*!
|
||||
\file Memory.h
|
||||
\brief Basic TLM-2 memory model
|
||||
\author Màrius Montón
|
||||
\date August 2018
|
||||
*/
|
||||
|
||||
#ifndef __MEMORY_H__
|
||||
#define __MEMORY_H__
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#define SC_INCLUDE_DYNAMIC_PROCESSES
|
||||
|
||||
#include "systemc"
|
||||
|
||||
#include "tlm.h"
|
||||
#include "tlm_utils/simple_target_socket.h"
|
||||
|
||||
using namespace sc_core;
|
||||
using namespace sc_dt;
|
||||
using namespace std;
|
||||
|
||||
/**
|
||||
* @brief Basic TLm-2 memory
|
||||
*/
|
||||
class Memory: sc_module {
|
||||
public:
|
||||
// TLM-2 socket, defaults to 32-bits wide, base protocol
|
||||
tlm_utils::simple_target_socket<Memory> socket;
|
||||
|
||||
enum { SIZE = 1024 };
|
||||
const sc_time LATENCY;
|
||||
|
||||
Memory(sc_module_name name, string filename);
|
||||
|
||||
// TLM-2 blocking transport method
|
||||
virtual void b_transport( tlm::tlm_generic_payload& trans, sc_time& delay );
|
||||
|
||||
// *********************************************
|
||||
// TLM-2 forward DMI method
|
||||
// *********************************************
|
||||
|
||||
virtual bool get_direct_mem_ptr(tlm::tlm_generic_payload& trans,
|
||||
tlm::tlm_dmi& dmi_data);
|
||||
|
||||
void invalidation_process();
|
||||
|
||||
// *********************************************
|
||||
// TLM-2 debug transport method
|
||||
// *********************************************
|
||||
|
||||
virtual unsigned int transport_dbg(tlm::tlm_generic_payload& trans);
|
||||
|
||||
int mem[SIZE];
|
||||
|
||||
/**
|
||||
* Reads file and stores in Code Memory. Uses propietary file format
|
||||
* @brief Reads file and stores in Code Memory
|
||||
* @param filename File name
|
||||
*/
|
||||
virtual void readCustomHexFile(string filename);
|
||||
|
||||
/**
|
||||
* @brief Read Intel hex file
|
||||
* @param filename file name to read
|
||||
*/
|
||||
virtual void readHexFile(string filename);
|
||||
};
|
||||
#endif /* __MEMORY_H__ */
|
|
@ -0,0 +1,102 @@
|
|||
/*!
|
||||
\file Performance.h
|
||||
\brief Class to store performance of CPU
|
||||
\author Màrius Montón
|
||||
\date Aug 2018
|
||||
*/
|
||||
|
||||
#ifndef PERFORMANCE_H
|
||||
#define PERFORMANCE_H
|
||||
|
||||
#define SC_INCLUDE_DYNAMIC_PROCESSES
|
||||
|
||||
#include "systemc"
|
||||
|
||||
#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{
|
||||
public:
|
||||
|
||||
/**
|
||||
* @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 write counter
|
||||
*/
|
||||
inline void dataMemoryWrite() {
|
||||
data_memory_write++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 register read counter
|
||||
*/
|
||||
inline void registerRead() {
|
||||
register_read++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Increment register write counter
|
||||
*/
|
||||
inline void registerWrite() {
|
||||
register_write++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Increment instructions executed counter
|
||||
*/
|
||||
inline void instructionsInc() {
|
||||
instructions_executed++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Dump counters to cout
|
||||
*/
|
||||
void dump();
|
||||
|
||||
private:
|
||||
static Performance* instance;
|
||||
Performance();
|
||||
|
||||
uint64_t data_memory_read = 0;
|
||||
uint64_t data_memory_write = 0;
|
||||
uint64_t code_memory_read = 0;
|
||||
uint64_t code_memory_write = 0;
|
||||
uint64_t register_read = 0;
|
||||
uint64_t register_write = 0;
|
||||
uint64_t instructions_executed = 0;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,105 @@
|
|||
/*!
|
||||
\file RISC_V_execute.h
|
||||
\brief RISC-V ISA implementation
|
||||
\author Màrius Montón
|
||||
\date August 2018
|
||||
*/
|
||||
#ifndef RISC_V_EXECUTE_H
|
||||
#define RISC_V_EXECUTE_H
|
||||
|
||||
#define SC_INCLUDE_DYNAMIC_PROCESSES
|
||||
|
||||
#include "systemc"
|
||||
|
||||
#include "tlm.h"
|
||||
#include "tlm_utils/simple_initiator_socket.h"
|
||||
|
||||
#include "memory.h"
|
||||
#include "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 RISC_V_execute : sc_module {
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Constructor
|
||||
* @param name module name
|
||||
* @param register_bank pointer to register bank to use
|
||||
*/
|
||||
RISC_V_execute(sc_module_name name,
|
||||
Registers *register_bank);
|
||||
|
||||
|
||||
void LUI(Instruction &inst);
|
||||
void AUIPC(Instruction &inst);
|
||||
|
||||
void JAL(Instruction &inst);
|
||||
void JALR(Instruction &inst);
|
||||
|
||||
void BEQ(Instruction &inst);
|
||||
void BNE(Instruction &inst);
|
||||
void BLT(Instruction &inst);
|
||||
void BGE(Instruction &inst);
|
||||
void BLTU(Instruction &inst);
|
||||
void BGEU(Instruction &inst);
|
||||
|
||||
void LB(Instruction &inst);
|
||||
void LH(Instruction &inst);
|
||||
void LW(Instruction &inst);
|
||||
void LBU(Instruction &inst);
|
||||
void LHU(Instruction &inst);
|
||||
|
||||
void SB(Instruction &inst);
|
||||
void SH(Instruction &inst);
|
||||
void SW(Instruction &inst);
|
||||
void SBU(Instruction &inst);
|
||||
void SHU(Instruction &inst);
|
||||
|
||||
void ADDI(Instruction &inst);
|
||||
void SLTI(Instruction &inst);
|
||||
void SLTIU(Instruction &inst);
|
||||
void XORI(Instruction &inst);
|
||||
void ORI(Instruction &inst);
|
||||
void ANDI(Instruction &inst);
|
||||
void SLLI(Instruction &inst);
|
||||
void SRLI(Instruction &inst);
|
||||
void SRAI(Instruction &inst);
|
||||
|
||||
void ADD(Instruction &inst);
|
||||
void SUB(Instruction &inst);
|
||||
void SLL(Instruction &inst);
|
||||
void SLT(Instruction &inst);
|
||||
void SLTU(Instruction &inst);
|
||||
|
||||
void XOR(Instruction &inst);
|
||||
void SRL(Instruction &inst);
|
||||
void SRA(Instruction &inst);
|
||||
void OR(Instruction &inst);
|
||||
void AND(Instruction &inst);
|
||||
|
||||
void CSRRW(Instruction &inst);
|
||||
void CSRRS(Instruction &inst);
|
||||
void CSRRC(Instruction &inst);
|
||||
void CSRRWI(Instruction &inst);
|
||||
void CSRRSI(Instruction &inst);
|
||||
void CSRRCI(Instruction &inst);
|
||||
|
||||
void NOP(Instruction &inst);
|
||||
private:
|
||||
|
||||
uint32_t readDataMem(uint32_t addr);
|
||||
Registers *regs;
|
||||
Performance *perf;
|
||||
Log *log;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,105 @@
|
|||
/*!
|
||||
\file Registers.h
|
||||
\brief Basic register file implementation
|
||||
\author Màrius Montón
|
||||
\date August 2018
|
||||
*/
|
||||
#ifndef REGISTERS_H
|
||||
#define REGISTERS_H
|
||||
|
||||
#define SC_INCLUDE_DYNAMIC_PROCESSES
|
||||
|
||||
#include "systemc"
|
||||
#include "tlm.h"
|
||||
|
||||
#include "Performance.h"
|
||||
|
||||
using namespace sc_core;
|
||||
using namespace sc_dt;
|
||||
using namespace std;
|
||||
|
||||
/**
|
||||
* @brief Register file implementation
|
||||
*/
|
||||
class Registers {
|
||||
public:
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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();
|
||||
|
||||
/**
|
||||
* 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() {
|
||||
register_PC += 4;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get CSR value
|
||||
* @param csr CSR number to access
|
||||
* @return CSR value
|
||||
*/
|
||||
inline uint32_t getCSR(int csr) {
|
||||
return CSR[csr];
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set CSR value
|
||||
* @param csr CSR number to access
|
||||
* @param value new value to register
|
||||
*/
|
||||
inline void setCSR(int csr, uint32_t value) {
|
||||
CSR[csr] = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dump register data to console
|
||||
*/
|
||||
void dump();
|
||||
private:
|
||||
/**
|
||||
* bank of registers (32 regs of 32bits each)
|
||||
*/
|
||||
int32_t register_bank[32];
|
||||
|
||||
/**
|
||||
* Program counter (32 bits width)
|
||||
*/
|
||||
uint32_t register_PC;
|
||||
|
||||
/**
|
||||
* CSR registers (4096 maximum)
|
||||
*/
|
||||
uint32_t CSR[4096];
|
||||
Performance *perf;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,103 @@
|
|||
|
||||
#include "CPU.h"
|
||||
|
||||
SC_HAS_PROCESS(CPU);
|
||||
CPU::CPU(sc_module_name name): sc_module(name)
|
||||
, instr_bus("instr_bus")
|
||||
//, exec("RISC_V_exec", ®ister_bank)
|
||||
//, data_bus("data_bus")
|
||||
{
|
||||
register_bank = new Registers();
|
||||
exec = new RISC_V_execute("RISC_V_execute", register_bank);
|
||||
perf = Performance::getInstance();
|
||||
log = Log::getInstance();
|
||||
|
||||
SC_THREAD(CPU_thread);
|
||||
}
|
||||
|
||||
CPU::~CPU() {
|
||||
cout << "*********************************************" << endl;
|
||||
register_bank->dump();
|
||||
cout << sc_time_stamp() << endl;
|
||||
perf->dump();
|
||||
cout << "*********************************************" << endl;
|
||||
}
|
||||
/**
|
||||
* main thread for CPU simulation
|
||||
* @brief CPU mai thread
|
||||
*/
|
||||
void CPU::CPU_thread(void) {
|
||||
|
||||
tlm::tlm_generic_payload* trans = new tlm::tlm_generic_payload;
|
||||
int32_t INSTR;
|
||||
sc_time delay = SC_ZERO_TIME;
|
||||
|
||||
trans->set_command( tlm::TLM_READ_COMMAND );
|
||||
trans->set_data_ptr( reinterpret_cast<unsigned char*>(&INSTR) );
|
||||
trans->set_data_length( 4 );
|
||||
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 );
|
||||
|
||||
register_bank->dump();
|
||||
|
||||
while(1) {
|
||||
/* Get new PC value */
|
||||
trans->set_address( register_bank->getPC() );
|
||||
instr_bus->b_transport( *trans, delay);
|
||||
perf->codeMemoryRead();
|
||||
|
||||
if ( trans->is_response_error() ) {
|
||||
SC_REPORT_ERROR("CPU base", "Read memory");
|
||||
} else {
|
||||
// cout << "INSTR: " << INSTR << endl;
|
||||
log->SC_log(Log::INFO) << "PC: " << register_bank->getPC() << endl;
|
||||
Instruction inst(INSTR);
|
||||
|
||||
switch(inst.decode()) {
|
||||
case OP_LUI:
|
||||
exec->LUI(inst);
|
||||
break;
|
||||
case OP_AUIPC:
|
||||
exec->AUIPC(inst);
|
||||
break;
|
||||
case OP_JAL:
|
||||
exec->JAL(inst);
|
||||
break;
|
||||
case OP_BEQ:
|
||||
exec->BEQ(inst);
|
||||
break;
|
||||
case OP_BNE:
|
||||
exec->BNE(inst);
|
||||
break;
|
||||
case OP_ADDI:
|
||||
exec->ADDI(inst);
|
||||
break;
|
||||
case OP_ADD:
|
||||
exec->ADD(inst);
|
||||
break;
|
||||
case OP_SUB:
|
||||
exec->SUB(inst);
|
||||
break;
|
||||
default:
|
||||
exec->NOP(inst);
|
||||
}
|
||||
perf->instructionsInc();
|
||||
|
||||
register_bank->incPC();
|
||||
|
||||
/* Simulation control, we stop at 10 instructions (if no NOP found)*/
|
||||
if (register_bank->getPC() == 10*4) {
|
||||
cout << "*********************************************" << endl;
|
||||
register_bank->dump();
|
||||
cout << sc_time_stamp() << endl;
|
||||
cout << "*********************************************" << endl;
|
||||
|
||||
perf->dump();
|
||||
|
||||
sc_stop();
|
||||
}
|
||||
}
|
||||
} // while(1)
|
||||
} // CPU_thread
|
|
@ -0,0 +1,121 @@
|
|||
#include "Instruction.h"
|
||||
|
||||
|
||||
Instruction::Instruction(sc_int<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(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(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(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(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(funct7()) {
|
||||
case SRLI_F7:
|
||||
return OP_SRLI;
|
||||
case SRAI_F7:
|
||||
return OP_SRAI;
|
||||
}
|
||||
return OP_ERROR;
|
||||
}
|
||||
return OP_ERROR;
|
||||
case ADD: {
|
||||
switch(funct3()) {
|
||||
case ADD_F:
|
||||
switch (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(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 */
|
||||
return OP_ERROR;
|
||||
default:
|
||||
return OP_ERROR;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
#include "Log.h"
|
||||
|
||||
Log* Log::getInstance()
|
||||
{
|
||||
if (instance == 0)
|
||||
{
|
||||
instance = new Log("Log.txt");
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
std::ofstream& Log::SC_log(enum LogLevel level) {
|
||||
if (level >= currentLogLevel) {
|
||||
m_stream << "time " << sc_core::sc_time_stamp() << ": ";
|
||||
}
|
||||
|
||||
return m_stream;
|
||||
}
|
||||
|
||||
void Log::setLogLevel(enum LogLevel newLevel) {
|
||||
currentLogLevel = newLevel;
|
||||
}
|
||||
|
||||
Log* Log::instance = 0;
|
|
@ -0,0 +1,177 @@
|
|||
#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);
|
||||
|
||||
memset(mem, 0, SIZE*sizeof(int));
|
||||
// readCustomHexFile("memory.hex");
|
||||
readHexFile(filename);
|
||||
|
||||
SC_THREAD(invalidation_process);
|
||||
}
|
||||
|
||||
|
||||
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() / 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();
|
||||
|
||||
// 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
|
||||
// *********************************************
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// cout << "MEM: addr=" << adr << endl;
|
||||
// cout << "MEM: data=" << mem[adr] << endl;
|
||||
|
||||
// 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);
|
||||
|
||||
// Reset timing annotation after waiting
|
||||
delay = SC_ZERO_TIME;
|
||||
|
||||
// *********************************************
|
||||
// Set DMI hint to indicated that DMI is supported
|
||||
// *********************************************
|
||||
|
||||
trans.set_dmi_allowed(true);
|
||||
|
||||
// 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)
|
||||
{
|
||||
// Permit read and write access
|
||||
dmi_data.allow_read_write();
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
||||
void Memory::invalidation_process()
|
||||
{
|
||||
// Invalidate DMI pointers periodically
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
wait(LATENCY*8);
|
||||
socket->invalidate_direct_mem_ptr(0, SIZE-1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
unsigned int Memory::transport_dbg(tlm::tlm_generic_payload& trans)
|
||||
{
|
||||
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();
|
||||
|
||||
// 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);
|
||||
|
||||
return num_bytes;
|
||||
}
|
||||
|
||||
|
||||
void Memory::readCustomHexFile(string filename) {
|
||||
ifstream hexfile;
|
||||
string line;
|
||||
int i = 0;
|
||||
|
||||
hexfile.open(filename);
|
||||
if (hexfile.is_open()) {
|
||||
while(getline(hexfile, line) ) {
|
||||
/* # is a comentary in the file */
|
||||
if (line[0] != '#') {
|
||||
cout << "i: " << i << endl;
|
||||
mem[i] = stol(line.substr(0,8), nullptr, 16);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
hexfile.close();
|
||||
} else {
|
||||
SC_REPORT_ERROR("Memory", "Open file error");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Memory::readHexFile(string filename) {
|
||||
ifstream hexfile;
|
||||
string line;
|
||||
int byte_count;
|
||||
int address;
|
||||
int i = 0;
|
||||
|
||||
hexfile.open(filename);
|
||||
|
||||
if (hexfile.is_open()) {
|
||||
while(getline(hexfile, line) ) {
|
||||
/* # is a comentary in the file */
|
||||
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) / 4;
|
||||
|
||||
for (i=0; i < byte_count/4; i++) {
|
||||
mem[address+i] = stol(line.substr(9+(i*8), 2), nullptr, 16);
|
||||
mem[address+i] |= stol(line.substr(11+(i*8),2), nullptr, 16) << 8;
|
||||
mem[address+i] |= stol(line.substr(13+(i*8),2), nullptr, 16) << 16;
|
||||
mem[address+i] |= stol(line.substr(15+(i*8),2), nullptr, 16) << 24;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
hexfile.close();
|
||||
} else {
|
||||
SC_REPORT_ERROR("Memory", "Open file error");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
#include "Performance.h"
|
||||
|
||||
Performance* Performance::getInstance()
|
||||
{
|
||||
if (instance == 0)
|
||||
{
|
||||
instance = new Performance();
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
Performance::Performance()
|
||||
{}
|
||||
|
||||
void Performance::dump() {
|
||||
cout << "# 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;
|
||||
}
|
||||
|
||||
Performance* Performance::instance = 0;
|
|
@ -0,0 +1,592 @@
|
|||
#include "RISC_V_execute.h"
|
||||
|
||||
SC_HAS_PROCESS(RISC_V_execute);
|
||||
RISC_V_execute::RISC_V_execute(sc_module_name name
|
||||
, Registers *register_bank)
|
||||
: sc_module(name)
|
||||
, regs(register_bank) {
|
||||
perf = Performance::getInstance();
|
||||
log = Log::getInstance();
|
||||
}
|
||||
|
||||
void RISC_V_execute::LUI(Instruction &inst) {
|
||||
int rd;
|
||||
uint32_t imm = 0;
|
||||
|
||||
rd = inst.rd();
|
||||
imm = inst.imm_U() << 12;
|
||||
regs->setValue(rd, imm);
|
||||
log->SC_log(Log::INFO) << "LUI R" << rd << " -> " << imm << endl;
|
||||
|
||||
}
|
||||
|
||||
void RISC_V_execute::AUIPC(Instruction &inst) {
|
||||
int rd;
|
||||
uint32_t imm = 0;
|
||||
int new_pc;
|
||||
|
||||
rd = inst.rd();
|
||||
imm = inst.imm_U() << 12;
|
||||
new_pc = regs->getPC() + imm;
|
||||
|
||||
regs->setPC(new_pc);
|
||||
regs->setValue(rd, new_pc);
|
||||
|
||||
log->SC_log(Log::INFO) << "AUIPC R" << rd << " + PC -> PC (" << new_pc << ")" << endl;
|
||||
}
|
||||
|
||||
void RISC_V_execute::JAL(Instruction &inst) {
|
||||
int32_t mem_addr = 0;
|
||||
int rd;
|
||||
int new_pc;
|
||||
|
||||
rd = inst.rd();
|
||||
mem_addr = inst.imm_J();
|
||||
|
||||
new_pc = regs->getPC();
|
||||
regs->setValue(rd, new_pc);
|
||||
|
||||
new_pc = new_pc + mem_addr;
|
||||
regs->setPC(new_pc);
|
||||
|
||||
log->SC_log(Log::INFO) << "JAL R" << rd << " PC + " << mem_addr << " -> PC (" << new_pc << ")" << endl;
|
||||
}
|
||||
|
||||
void RISC_V_execute::JALR(Instruction &inst) {
|
||||
uint32_t mem_addr = 0;
|
||||
int rd;
|
||||
int new_pc;
|
||||
|
||||
rd = inst.rd();
|
||||
mem_addr = inst.imm_I();
|
||||
|
||||
new_pc = regs->getPC();
|
||||
regs->setValue(rd, new_pc);
|
||||
|
||||
new_pc = (new_pc + mem_addr) & 0xFFFFFFFE;
|
||||
regs->setPC(new_pc);
|
||||
}
|
||||
|
||||
void RISC_V_execute::BEQ(Instruction &inst) {
|
||||
int rs1, rs2;
|
||||
int new_pc;
|
||||
|
||||
rs1 = inst.rs1();
|
||||
rs2 = inst.rs2();
|
||||
|
||||
if (regs->getValue(rs1) == regs->getValue(rs2)) {
|
||||
new_pc = regs->getPC() + inst.imm_B() - 4;
|
||||
regs->setPC(new_pc);
|
||||
}
|
||||
|
||||
log->SC_log(Log::INFO) << "BEQ R" << rs1 << " == R" << rs2 << "? -> PC (" << new_pc << ")" << endl;
|
||||
|
||||
}
|
||||
|
||||
void RISC_V_execute::BNE(Instruction &inst) {
|
||||
int rs1, rs2;
|
||||
int new_pc;
|
||||
|
||||
rs1 = inst.rs1();
|
||||
rs2 = inst.rs2();
|
||||
|
||||
if (regs->getValue(rs1) != regs->getValue(rs2)) {
|
||||
new_pc = regs->getPC() + inst.imm_B() - 4;
|
||||
regs->setPC(new_pc);
|
||||
}
|
||||
|
||||
log->SC_log(Log::INFO) << "BNE R" << rs1 << " == R" << rs2 << "? -> PC (" << new_pc << ")" << endl;
|
||||
}
|
||||
|
||||
void RISC_V_execute::BLT(Instruction &inst) {
|
||||
int rs1, rs2;
|
||||
int new_pc;
|
||||
|
||||
rs1 = inst.rs1();
|
||||
rs2 = inst.rs2();
|
||||
|
||||
if ((int32_t)regs->getValue(rs1) < (int32_t)regs->getValue(rs2)) {
|
||||
new_pc = regs->getPC() + inst.imm_B() - 4;
|
||||
regs->setPC(new_pc);
|
||||
}
|
||||
|
||||
log->SC_log(Log::INFO) << "BLT R" << rs1 << " < R" << rs2 << "? -> PC (" << new_pc << ")" << endl;
|
||||
}
|
||||
|
||||
void RISC_V_execute::BGE(Instruction &inst) {
|
||||
int rs1, rs2;
|
||||
int new_pc;
|
||||
|
||||
rs1 = inst.rs1();
|
||||
rs2 = inst.rs2();
|
||||
|
||||
if ((int32_t)regs->getValue(rs1) >= (int32_t)regs->getValue(rs2)) {
|
||||
new_pc = regs->getPC() + inst.imm_B() - 4;
|
||||
regs->setPC(new_pc);
|
||||
}
|
||||
|
||||
log->SC_log(Log::INFO) << "BGE R" << rs1 << " > R" << rs2 << "? -> PC (" << new_pc << ")" << endl;
|
||||
}
|
||||
|
||||
void RISC_V_execute::BLTU(Instruction &inst) {
|
||||
int rs1, rs2;
|
||||
int new_pc;
|
||||
|
||||
rs1 = inst.rs1();
|
||||
rs2 = inst.rs2();
|
||||
|
||||
if (regs->getValue(rs1) < regs->getValue(rs2)) {
|
||||
new_pc = regs->getPC() + inst.imm_B() - 4;
|
||||
regs->setPC(new_pc);
|
||||
}
|
||||
|
||||
log->SC_log(Log::INFO) << "BLTU R" << rs1 << " < R" << rs2 << "? -> PC (" << new_pc << ")" << endl;
|
||||
}
|
||||
|
||||
void RISC_V_execute::BGEU(Instruction &inst) {
|
||||
int rs1, rs2;
|
||||
int new_pc;
|
||||
|
||||
rs1 = inst.rs1();
|
||||
rs2 = inst.rs2();
|
||||
|
||||
if (regs->getValue(rs1) >= regs->getValue(rs2)) {
|
||||
new_pc = regs->getPC() + inst.imm_B() - 4;
|
||||
regs->setPC(new_pc);
|
||||
}
|
||||
|
||||
log->SC_log(Log::INFO) << "BGEU R" << rs1 << " > R" << rs2 << "? -> PC (" << new_pc << ")" << endl;
|
||||
}
|
||||
|
||||
void RISC_V_execute::LB(Instruction &inst) {
|
||||
uint32_t mem_addr = 0;
|
||||
int rd, rs1;
|
||||
uint32_t imm = 0;
|
||||
uint32_t data;
|
||||
|
||||
rd = inst.rd();
|
||||
rs1 = inst.rs1();
|
||||
imm = inst.imm_U() << 12;
|
||||
|
||||
mem_addr = imm + rs1;
|
||||
data = readDataMem(mem_addr);
|
||||
regs->setValue(rd, data);
|
||||
}
|
||||
|
||||
void RISC_V_execute::ADDI(Instruction &inst) {
|
||||
int rd, rs1;
|
||||
int32_t imm = 0;
|
||||
int32_t calc;
|
||||
|
||||
rd = inst.rd();
|
||||
rs1 = inst.rs1();
|
||||
imm = inst.imm_I();
|
||||
|
||||
calc = regs->getValue(rs1) + imm;
|
||||
regs->setValue(rd, calc);
|
||||
|
||||
log->SC_log(Log::INFO) << "ADDI: R" << rs1 << " + " << imm << " -> R" << rd << endl;
|
||||
}
|
||||
|
||||
void RISC_V_execute::SLTI(Instruction &inst) {
|
||||
int rd, rs1;
|
||||
int32_t imm;
|
||||
|
||||
rd = inst.rd();
|
||||
rs1 = inst.rs1();
|
||||
imm = inst.imm_I();
|
||||
|
||||
if (regs->getValue(rs1) < imm) {
|
||||
regs->setValue(rd, 1);
|
||||
log->SC_log(Log::INFO) << "SLTI: R" << rs1 << " < " << imm
|
||||
<< " => " << "1 -> R" << rd << endl;
|
||||
} else {
|
||||
regs->setValue(rd, 0);
|
||||
log->SC_log(Log::INFO) << "SLTI: R" << rs1 << " < " << imm
|
||||
<< " => " << "0 -> R" << rd << endl;
|
||||
}
|
||||
}
|
||||
|
||||
void RISC_V_execute::SLTIU(Instruction &inst) {
|
||||
int rd, rs1;
|
||||
int32_t imm;
|
||||
|
||||
rd = inst.rd();
|
||||
rs1 = inst.rs1();
|
||||
imm = inst.imm_I();
|
||||
|
||||
if ((uint32_t) regs->getValue(rs1) < (uint32_t)imm) {
|
||||
regs->setValue(rd, 1);
|
||||
log->SC_log(Log::INFO) << "SLTIU: R" << rs1 << " < " << imm
|
||||
<< " => " << "1 -> R" << rd << endl;
|
||||
} else {
|
||||
regs->setValue(rd, 0);
|
||||
log->SC_log(Log::INFO) << "SLTIU: R" << rs1 << " < " << imm
|
||||
<< " => " << "0 -> R" << rd << endl;
|
||||
}
|
||||
}
|
||||
|
||||
void RISC_V_execute::XORI(Instruction &inst) {
|
||||
int rd, rs1;
|
||||
int32_t imm;
|
||||
uint32_t calc;
|
||||
|
||||
rd = inst.rd();
|
||||
rs1 = inst.rs1();
|
||||
imm = inst.imm_I();
|
||||
|
||||
calc = regs->getValue(rs1) ^ imm;
|
||||
regs->setValue(rd, calc);
|
||||
|
||||
log->SC_log(Log::INFO) << "XORI: R" << rs1 << " XOR " << imm
|
||||
<< "-> R" << rd << endl;
|
||||
}
|
||||
|
||||
void RISC_V_execute::ORI(Instruction &inst) {
|
||||
int rd, rs1;
|
||||
int32_t imm;
|
||||
uint32_t calc;
|
||||
|
||||
rd = inst.rd();
|
||||
rs1 = inst.rs1();
|
||||
imm = inst.imm_I();
|
||||
|
||||
calc = regs->getValue(rs1) | imm;
|
||||
regs->setValue(rd, calc);
|
||||
|
||||
log->SC_log(Log::INFO) << "ORI: R" << rs1 << " OR " << imm
|
||||
<< "-> R" << rd << endl;
|
||||
}
|
||||
|
||||
void RISC_V_execute::ANDI(Instruction &inst) {
|
||||
int rd, rs1;
|
||||
int32_t imm;
|
||||
uint32_t calc;
|
||||
|
||||
rd = inst.rd();
|
||||
rs1 = inst.rs1();
|
||||
imm = inst.imm_I();
|
||||
|
||||
calc = regs->getValue(rs1) & imm;
|
||||
regs->setValue(rd, calc);
|
||||
|
||||
log->SC_log(Log::INFO) << "ANDI: R" << rs1 << " AND " << imm
|
||||
<< "-> R" << rd << endl;
|
||||
}
|
||||
|
||||
void RISC_V_execute::SLLI(Instruction &inst) {
|
||||
int rd, rs1, rs2;
|
||||
uint32_t shift;
|
||||
uint32_t calc;
|
||||
|
||||
rd = inst.rd();
|
||||
rs1 = inst.rs1();
|
||||
rs2 = inst.rs2();
|
||||
|
||||
shift = rs2 & 0x1F;
|
||||
|
||||
calc = ((uint32_t)regs->getValue(rs1)) << shift;
|
||||
regs->setValue(rd, calc);
|
||||
|
||||
log->SC_log(Log::INFO) << "SLLI: R" << rs1 << " << " << shift << " -> R" << rd << endl;
|
||||
}
|
||||
|
||||
void RISC_V_execute::SRLI(Instruction &inst) {
|
||||
int rd, rs1, rs2;
|
||||
uint32_t shift;
|
||||
uint32_t calc;
|
||||
|
||||
rd = inst.rd();
|
||||
rs1 = inst.rs1();
|
||||
rs2 = inst.rs2();
|
||||
|
||||
shift = rs2 & 0x1F;
|
||||
|
||||
calc = ((uint32_t)regs->getValue(rs1)) >> shift;
|
||||
regs->setValue(rd, calc);
|
||||
|
||||
log->SC_log(Log::INFO) << "SRLI: R" << rs1 << " >> " << shift << " -> R" << rd << endl;
|
||||
}
|
||||
|
||||
void RISC_V_execute::SRAI(Instruction &inst) {
|
||||
int rd, rs1, rs2;
|
||||
uint32_t shift;
|
||||
int32_t calc;
|
||||
|
||||
rd = inst.rd();
|
||||
rs1 = inst.rs1();
|
||||
rs2 = inst.rs2();
|
||||
|
||||
shift = rs2 & 0x1F;
|
||||
|
||||
calc = regs->getValue(rs1) >> shift;
|
||||
regs->setValue(rd, calc);
|
||||
|
||||
log->SC_log(Log::INFO) << "SRAI: R" << rs1 << " >> " << shift << " -> R" << rd << endl;
|
||||
}
|
||||
|
||||
void RISC_V_execute::ADD(Instruction &inst) {
|
||||
int rd, rs1, rs2;
|
||||
uint32_t calc;
|
||||
rd = inst.rd();
|
||||
rs1 = inst.rs1();
|
||||
rs2 = inst.rs2();
|
||||
|
||||
calc = regs->getValue(rs1) + regs->getValue(rs2);
|
||||
regs->setValue(rd, calc);
|
||||
|
||||
log->SC_log(Log::INFO) << "ADD: R" << rs1 << " + R" << rs2 << " -> R" << rd << endl;
|
||||
}
|
||||
|
||||
void RISC_V_execute::SUB(Instruction &inst) {
|
||||
int rd, rs1, rs2;
|
||||
uint32_t calc;
|
||||
rd = inst.rd();
|
||||
rs1 = inst.rs1();
|
||||
rs2 = inst.rs2();
|
||||
|
||||
calc = regs->getValue(rs1) - regs->getValue(rs2);
|
||||
regs->setValue(rd, calc);
|
||||
|
||||
/* Can insert some arbitrary execution time */
|
||||
wait(sc_time(10, SC_NS));
|
||||
log->SC_log(Log::INFO) << "SUB: R" << rs1 << " - R" << rs2 << " -> R" << rd << endl;
|
||||
}
|
||||
|
||||
void RISC_V_execute::SLL(Instruction &inst) {
|
||||
int rd, rs1, rs2;
|
||||
uint32_t shift;
|
||||
uint32_t calc;
|
||||
|
||||
rd = inst.rd();
|
||||
rs1 = inst.rs1();
|
||||
rs2 = inst.rs2();
|
||||
|
||||
shift = regs->getValue(rs2) & 0x1F;
|
||||
|
||||
calc = ((uint32_t)regs->getValue(rs1)) << shift;
|
||||
regs->setValue(rd, calc);
|
||||
|
||||
log->SC_log(Log::INFO) << "SLL: R" << rs1 << " << " << shift << " -> R" << rd << endl;
|
||||
}
|
||||
|
||||
|
||||
/** */
|
||||
void RISC_V_execute::SLT(Instruction &inst) {
|
||||
int rd, rs1, rs2;
|
||||
|
||||
rd = inst.rd();
|
||||
rs1 = inst.rs1();
|
||||
rs2 = inst.rs2();
|
||||
|
||||
if (regs->getValue(rs1) < regs->getValue(rs2)) {
|
||||
regs->setValue(rd, 1);
|
||||
log->SC_log(Log::INFO) << "SLT: R" << rs1 << " < R" << rs2
|
||||
<< " => " << "1 -> R" << rd << endl;
|
||||
} else {
|
||||
regs->setValue(rd, 0);
|
||||
log->SC_log(Log::INFO) << "SLT: R" << rs1 << " < R" << rs2
|
||||
<< " => " << "0 -> R" << rd << endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void RISC_V_execute::SLTU(Instruction &inst) {
|
||||
int rd, rs1, rs2;
|
||||
|
||||
rd = inst.rd();
|
||||
rs1 = inst.rs1();
|
||||
rs2 = inst.rs2();
|
||||
|
||||
if ( (uint32_t)regs->getValue(rs1) < (uint32_t)regs->getValue(rs2)) {
|
||||
regs->setValue(rd, 1);
|
||||
log->SC_log(Log::INFO) << "SLTU: R" << rs1 << " < R" << rs2
|
||||
<< " => " << "1 -> R" << rd << endl;
|
||||
} else {
|
||||
regs->setValue(rd, 0);
|
||||
log->SC_log(Log::INFO) << "SLTU: R" << rs1 << " < R" << rs2
|
||||
<< " => " << "0 -> R" << rd << endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void RISC_V_execute::XOR(Instruction &inst) {
|
||||
int rd, rs1, rs2;
|
||||
uint32_t calc;
|
||||
|
||||
rd = inst.rd();
|
||||
rs1 = inst.rs1();
|
||||
rs2 = inst.rs2();
|
||||
|
||||
calc = regs->getValue(rs1) ^ regs->getValue(rs2);
|
||||
regs->setValue(rd, calc);
|
||||
|
||||
log->SC_log(Log::INFO) << "XOR: R" << rs1 << " XOR R" << rs2
|
||||
<< "-> R" << rd << endl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RISC_V_execute::SRL(Instruction &inst) {
|
||||
int rd, rs1, rs2;
|
||||
uint32_t shift;
|
||||
uint32_t calc;
|
||||
|
||||
rd = inst.rd();
|
||||
rs1 = inst.rs1();
|
||||
rs2 = inst.rs2();
|
||||
|
||||
shift = regs->getValue(rs2) & 0x1F;
|
||||
|
||||
calc = ((uint32_t)regs->getValue(rs1)) >> shift;
|
||||
regs->setValue(rd, calc);
|
||||
|
||||
log->SC_log(Log::INFO) << "SRL: R" << rs1 << " >> " << shift << " -> R" << rd << endl;
|
||||
}
|
||||
|
||||
void RISC_V_execute::SRA(Instruction &inst) {
|
||||
int rd, rs1, rs2;
|
||||
uint32_t shift;
|
||||
int32_t calc;
|
||||
|
||||
rd = inst.rd();
|
||||
rs1 = inst.rs1();
|
||||
rs2 = inst.rs2();
|
||||
|
||||
shift = regs->getValue(rs2) & 0x1F;
|
||||
|
||||
calc = regs->getValue(rs1) >> shift;
|
||||
regs->setValue(rd, calc);
|
||||
|
||||
log->SC_log(Log::INFO) << "SRA: R" << rs1 << " >> " << shift << " -> R" << rd << endl;
|
||||
}
|
||||
|
||||
|
||||
void RISC_V_execute::OR(Instruction &inst) {
|
||||
int rd, rs1, rs2;
|
||||
uint32_t calc;
|
||||
|
||||
rd = inst.rd();
|
||||
rs1 = inst.rs1();
|
||||
rs2 = inst.rs2();
|
||||
|
||||
calc = regs->getValue(rs1) | regs->getValue(rs2);
|
||||
regs->setValue(rd, calc);
|
||||
|
||||
log->SC_log(Log::INFO) << "OR: R" << rs1 << " OR R" << rs2
|
||||
<< "-> R" << rd << endl;
|
||||
}
|
||||
|
||||
|
||||
void RISC_V_execute::AND(Instruction &inst) {
|
||||
int rd, rs1, rs2;
|
||||
uint32_t calc;
|
||||
|
||||
rd = inst.rd();
|
||||
rs1 = inst.rs1();
|
||||
rs2 = inst.rs2();
|
||||
|
||||
calc = regs->getValue(rs1) & regs->getValue(rs2);
|
||||
regs->setValue(rd, calc);
|
||||
|
||||
log->SC_log(Log::INFO) << "AND: R" << rs1 << " AND R" << rs2
|
||||
<< "-> R" << rd << endl;
|
||||
}
|
||||
|
||||
void RISC_V_execute::CSRRW(Instruction &inst) {
|
||||
int rd, rs1;
|
||||
int csr;
|
||||
uint32_t aux;
|
||||
|
||||
rd = inst.rd();
|
||||
rs1 = inst.rs1();
|
||||
csr = inst.csr();
|
||||
|
||||
if (rd == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* These operations must be atomical */
|
||||
aux = regs->getCSR(csr);
|
||||
regs->setValue(rd, aux);
|
||||
aux = regs->getValue(rs1);
|
||||
regs->setCSR(csr, aux);
|
||||
|
||||
log->SC_log(Log::INFO) << "CSRRW: CSR #" << csr << " -> R" << rd
|
||||
<< ". R" << rs1 << "-> CSR #" << csr << endl;
|
||||
}
|
||||
|
||||
void RISC_V_execute::CSRRS(Instruction &inst) {
|
||||
int rd, rs1;
|
||||
int csr;
|
||||
uint32_t bitmask, aux;
|
||||
|
||||
rd = inst.rd();
|
||||
rs1 = inst.rs1();
|
||||
csr = inst.csr();
|
||||
|
||||
if (rd == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* These operations must be atomical */
|
||||
aux = regs->getCSR(csr);
|
||||
regs->setValue(rd, aux);
|
||||
|
||||
bitmask = regs->getValue(rs1);
|
||||
aux = aux | bitmask;
|
||||
regs->setCSR(csr, aux);
|
||||
|
||||
log->SC_log(Log::INFO) << "CSRRS: CSR #" << csr << " -> R" << rd
|
||||
<< ". R" << rs1 << " & CSR #" << csr << endl;
|
||||
}
|
||||
|
||||
void RISC_V_execute::CSRRC(Instruction &inst) {
|
||||
int rd, rs1;
|
||||
int csr;
|
||||
uint32_t bitmask, aux;
|
||||
|
||||
rd = inst.rd();
|
||||
rs1 = inst.rs1();
|
||||
csr = inst.csr();
|
||||
|
||||
if (rd == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* These operations must be atomical */
|
||||
aux = regs->getCSR(csr);
|
||||
regs->setValue(rd, aux);
|
||||
|
||||
bitmask = regs->getValue(rs1);
|
||||
aux = aux & ~bitmask;
|
||||
regs->setCSR(csr, aux);
|
||||
|
||||
log->SC_log(Log::INFO) << "CSRRC: CSR #" << csr << " -> R" << rd
|
||||
<< ". R" << rs1 << " & CSR #" << csr << endl;
|
||||
}
|
||||
|
||||
void RISC_V_execute::NOP(Instruction &inst) {
|
||||
cout << endl;
|
||||
regs->dump();
|
||||
cout << "Simulation time " << sc_time_stamp() << endl;
|
||||
perf->dump();
|
||||
|
||||
SC_REPORT_ERROR("RISC_V_execute", "NOP");
|
||||
}
|
||||
|
||||
/**
|
||||
* Access data memory to get data for LOAD & STORE OPs
|
||||
* @note NOT IMPLEMENTED YET
|
||||
* @param addr address to access to
|
||||
* @return data value read
|
||||
*/
|
||||
uint32_t RISC_V_execute::readDataMem(uint32_t addr) {
|
||||
// tlm::tlm_generic_payload* trans = new tlm::tlm_generic_payload;
|
||||
// sc_time delay = SC_ZERO_TIME;
|
||||
|
||||
// data_bus->b_transport(*trans, delay);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
#include "Registers.h"
|
||||
|
||||
Registers::Registers() {
|
||||
|
||||
memset(register_bank, 0, sizeof(int32_t)*32);
|
||||
perf = Performance::getInstance();
|
||||
|
||||
|
||||
register_PC = 0;
|
||||
}
|
||||
|
||||
void Registers::dump(void) {
|
||||
|
||||
cout << "************************************" << endl;
|
||||
cout << "Registers dump" << dec << endl;
|
||||
#if 0
|
||||
cout << "x0 (zero): " << register_bank[0] << "\t";
|
||||
cout << "x1 (ra): " << register_bank[1] << "\t";
|
||||
cout << "x2 (sp): " << register_bank[2] << "\t";
|
||||
cout << "x3 (gp): " << register_bank[3] << "\t" << endl;
|
||||
|
||||
cout << "x4 (tp): " << register_bank[4] << "\t";
|
||||
cout << "x5 (t0): " << register_bank[5] << "\t";
|
||||
cout << "x6 (t1): " << register_bank[6] << "\t";
|
||||
cout << "x7 (t2): " << register_bank[7] << "\t" << endl;
|
||||
|
||||
cout << "x8 (s0/fp): " << register_bank[8] << "\t";
|
||||
cout << "x9 (s1): " << register_bank[9] << "\t";
|
||||
cout << "x10 (a0): " << register_bank[10] << "\t";
|
||||
cout << "x11 (a1): " << register_bank[11] << "\t" << endl;
|
||||
|
||||
cout << "x12 (a2): " << register_bank[12] << "\t";
|
||||
cout << "x13 (a3): " << register_bank[13] << "\t";
|
||||
cout << "x14 (a4): " << register_bank[14] << "\t";
|
||||
cout << "x15 (a5): " << register_bank[15] << "\t" << endl;
|
||||
|
||||
cout << "x16 (a6): " << register_bank[16] << "\t";
|
||||
cout << "x17 (a7): " << register_bank[17] << "\t";
|
||||
cout << "x18 (s2): " << register_bank[18] << "\t";
|
||||
cout << "x19 (s3): " << register_bank[19] << "\t" << endl;
|
||||
|
||||
#else
|
||||
for(int i=0;i<32;i++) {
|
||||
cout << "R" << dec << i << ": " << register_bank[i] << "\t";
|
||||
if (i % 4 == 3) {
|
||||
cout << endl;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
cout << "PC: " << register_PC << endl;
|
||||
cout << "************************************" << endl;
|
||||
}
|
||||
|
||||
|
||||
void Registers::setValue(int reg_num, int32_t value) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t Registers::getPC() {
|
||||
return register_PC;
|
||||
}
|
||||
|
||||
void Registers::setPC(uint32_t new_pc) {
|
||||
register_PC = new_pc;
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
#define SC_INCLUDE_DYNAMIC_PROCESSES
|
||||
|
||||
#include "systemc"
|
||||
#include "tlm.h"
|
||||
#include "tlm_utils/simple_initiator_socket.h"
|
||||
#include "tlm_utils/simple_target_socket.h"
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
#include "CPU.h"
|
||||
#include "Memory.h"
|
||||
|
||||
using namespace sc_core;
|
||||
using namespace sc_dt;
|
||||
using namespace std;
|
||||
|
||||
string filename;
|
||||
|
||||
SC_MODULE(Top)
|
||||
{
|
||||
//Initiator *initiator;
|
||||
CPU *cpu;
|
||||
Memory *memory;
|
||||
|
||||
sc_signal<bool> IRQ;
|
||||
|
||||
SC_CTOR(Top)
|
||||
{
|
||||
cpu = new CPU("cpu");
|
||||
memory = new Memory("memory", filename);
|
||||
|
||||
cpu->instr_bus.bind(memory->socket);
|
||||
//cpu->interrupt.bind(IRQ);
|
||||
}
|
||||
|
||||
~Top() {
|
||||
cout << "Top destructor" << endl;
|
||||
delete cpu;
|
||||
delete memory;
|
||||
}
|
||||
};
|
||||
|
||||
Top *top;
|
||||
|
||||
void intHandler(int dummy) {
|
||||
delete top;
|
||||
//sc_stop();
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
int sc_main(int argc, char* argv[])
|
||||
{
|
||||
|
||||
signal(SIGINT, intHandler);
|
||||
|
||||
if (argv[1] == nullptr) {
|
||||
cerr << "Filename needed for hex memory" << endl;
|
||||
return -1;
|
||||
}
|
||||
filename = argv[1];
|
||||
|
||||
top = new Top("top");
|
||||
sc_start();
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue