From 8dcbf09589f1673c81194bba27c3023957f1d195 Mon Sep 17 00:00:00 2001 From: mariusmonton Date: Wed, 19 Sep 2018 23:44:38 +0200 Subject: [PATCH] Lot of changes: * memory module parses 03 field and sets Program Counter (PC) to right value * almost all RV32I instructions implemented * added Trace module to mimic ARM ITM module * added BusCtrl module as bus controler (very simple) to allow CPU & RISC_V_execute to access memory & peripherals * lot of minor changes --- .gitignore | 2 + inc/BusCtrl.h | 50 ++++++++++++++++++ inc/CPU.h | 2 +- inc/Log.h | 4 +- inc/Memory.h | 7 ++- inc/Registers.h | 67 ++++++++++++++++++++++++ inc/Trace.h | 37 +++++++++++++ src/BusCtrl.cpp | 35 +++++++++++++ src/CPU.cpp | 114 +++++++++++++++++++++++++++++++++++------ src/Instruction.cpp | 2 - src/Log.cpp | 3 +- src/Memory.cpp | 28 ++++++++-- src/RISC_V_execute.cpp | 10 ++-- src/Registers.cpp | 6 +-- src/Simulator.cpp | 35 +++++++++---- src/Trace.cpp | 22 ++++++++ 16 files changed, 382 insertions(+), 42 deletions(-) create mode 100644 inc/BusCtrl.h create mode 100644 inc/Trace.h create mode 100644 src/BusCtrl.cpp create mode 100644 src/Trace.cpp diff --git a/.gitignore b/.gitignore index 8813ba2..fe64b6d 100644 --- a/.gitignore +++ b/.gitignore @@ -30,6 +30,8 @@ *.exe *.out *.app +*.elf +*.hex Log.txt helper.ods diff --git a/inc/BusCtrl.h b/inc/BusCtrl.h new file mode 100644 index 0000000..1b1377e --- /dev/null +++ b/inc/BusCtrl.h @@ -0,0 +1,50 @@ +/*! + \file Trace.h + \brief Basic TLM-2 Trace module + \author Màrius Montón + \date September 2018 +*/ + +#ifndef __BUSCTRL_H__ +#define __BUSCTRL_H__ + +#include +#include + +#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 "Log.h" + +using namespace sc_core; +using namespace sc_dt; +using namespace std; + + +#define TRACE_MEMORY_ADDRESS 0x40000000 + +class BusCtrl: sc_module { +public: + // TLM-2 socket, defaults to 32-bits wide, base protocol + tlm_utils::simple_target_socket cpu_instr_socket; + tlm_utils::simple_target_socket cpu_data_socket; + tlm_utils::simple_initiator_socket data_memory_socket; + tlm_utils::simple_initiator_socket trace_socket; + + + // Constructor + BusCtrl(sc_module_name name); + + // TLM-2 blocking transport method + virtual void b_transport( tlm::tlm_generic_payload& trans, sc_time& delay ); + +private: + Log *log; +}; + +#endif diff --git a/inc/CPU.h b/inc/CPU.h index f5471e3..bb013c2 100644 --- a/inc/CPU.h +++ b/inc/CPU.h @@ -37,7 +37,7 @@ public: //sc_in > interrupt; - CPU(sc_module_name name); + CPU(sc_module_name name, uint32_t PC); ~CPU(); RISC_V_execute *exec; diff --git a/inc/Log.h b/inc/Log.h index 9b897cb..c5907e3 100644 --- a/inc/Log.h +++ b/inc/Log.h @@ -29,10 +29,10 @@ class Log { public: enum LogLevel{ - INFO=0, + ERROR = 0, DEBUG, WARNING, - ERROR + INFO } currentLogLevel; diff --git a/inc/Memory.h b/inc/Memory.h index 191333d..cedbc83 100644 --- a/inc/Memory.h +++ b/inc/Memory.h @@ -30,11 +30,14 @@ public: // TLM-2 socket, defaults to 32-bits wide, base protocol tlm_utils::simple_target_socket socket; - enum { SIZE = 1024 }; + enum { SIZE = 1024 * 1024 }; const sc_time LATENCY; Memory(sc_module_name name, string filename); Memory(sc_module_name name, bool use_file); + + virtual uint32_t getPCfromHEX(); + // TLM-2 blocking transport method virtual void b_transport( tlm::tlm_generic_payload& trans, sc_time& delay ); @@ -53,8 +56,10 @@ public: virtual unsigned int transport_dbg(tlm::tlm_generic_payload& trans); +private: int mem[SIZE]; + uint32_t program_counter; /** * Reads file and stores in Code Memory. Uses propietary file format * @brief Reads file and stores in Code Memory diff --git a/inc/Registers.h b/inc/Registers.h index 3822388..1a98349 100644 --- a/inc/Registers.h +++ b/inc/Registers.h @@ -24,6 +24,73 @@ using namespace std; 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 */ diff --git a/inc/Trace.h b/inc/Trace.h new file mode 100644 index 0000000..93b86f2 --- /dev/null +++ b/inc/Trace.h @@ -0,0 +1,37 @@ +/*! + \file Trace.h + \brief Basic TLM-2 Trace module + \author Màrius Montón + \date September 2018 +*/ + +#ifndef __TRACE_H__ +#define __TRACE_H__ + +#include +#include + +#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; + +class Trace: sc_module { +public: + // TLM-2 socket, defaults to 32-bits wide, base protocol + tlm_utils::simple_target_socket socket; + + // Constructor + Trace(sc_module_name name); + + // TLM-2 blocking transport method + virtual void b_transport( tlm::tlm_generic_payload& trans, sc_time& delay ); +}; + +#endif diff --git a/src/BusCtrl.cpp b/src/BusCtrl.cpp new file mode 100644 index 0000000..3ff2b4f --- /dev/null +++ b/src/BusCtrl.cpp @@ -0,0 +1,35 @@ +#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") + ,data_memory_socket("data_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(); + } + + +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; + + if (adr == TRACE_MEMORY_ADDRESS / 4) { + trace_socket->b_transport(trans, delay); + } else { + data_memory_socket->b_transport(trans, delay); + } + +#if 0 + if (cmd == tlm::TLM_READ_COMMAND) { + log->SC_log(Log::DEBUG) << "RD Address: @0x" << hex << adr << dec << endl; + } else { + log->SC_log(Log::DEBUG) << "WR Address: @0x" << hex << adr << dec << endl; + } +#endif + + trans.set_response_status( tlm::TLM_OK_RESPONSE ); +} diff --git a/src/CPU.cpp b/src/CPU.cpp index f67a0dc..5ecb9f0 100644 --- a/src/CPU.cpp +++ b/src/CPU.cpp @@ -2,7 +2,7 @@ #include "CPU.h" SC_HAS_PROCESS(CPU); -CPU::CPU(sc_module_name name): sc_module(name) +CPU::CPU(sc_module_name name, uint32_t PC): sc_module(name) , instr_bus("instr_bus") { register_bank = new Registers(); @@ -10,6 +10,7 @@ CPU::CPU(sc_module_name name): sc_module(name) perf = Performance::getInstance(); log = Log::getInstance(); + register_bank->setPC(PC); SC_THREAD(CPU_thread); } @@ -20,6 +21,7 @@ CPU::~CPU() { perf->dump(); cout << "*********************************************" << endl; } + /** * main thread for CPU simulation * @brief CPU mai thread @@ -49,8 +51,8 @@ void CPU::CPU_thread(void) { 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; + log->SC_log(Log::INFO) << "PC: " << hex << register_bank->getPC() + << dec << endl; Instruction inst(INSTR); switch(inst.decode()) { @@ -63,45 +65,127 @@ void CPU::CPU_thread(void) { case OP_JAL: exec->JAL(inst); break; + case OP_JALR: + exec->JALR(inst); + break; case OP_BEQ: exec->BEQ(inst); break; case OP_BNE: exec->BNE(inst); break; + case OP_BLT: + exec->BLT(inst); + break; + case OP_BGE: + exec->BGE(inst); + break; + case OP_BLTU: + exec->BLTU(inst); + break; + case OP_BGEU: + exec->BGEU(inst); + break; + case OP_LB: + exec->LB(inst); + break; + case OP_LH: + exec->LB(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: + 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; +#if 0 + case OP_CSRRW: + exec->CSRRW(inst); + break; + case OP_CSRRS: + exec->CSRRS(inst); + break; + case OP_CSRRC: + exec->CSRRC(inst); + break; +#endif default: + cout << endl << "Instruction not implemented: "; + inst.dump(); 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 diff --git a/src/Instruction.cpp b/src/Instruction.cpp index 8f99fa2..456c602 100644 --- a/src/Instruction.cpp +++ b/src/Instruction.cpp @@ -3,8 +3,6 @@ Instruction::Instruction(sc_int<32> instr) { m_instr = instr; - - } opCodes Instruction::decode() { diff --git a/src/Log.cpp b/src/Log.cpp index 64619e1..511c41c 100644 --- a/src/Log.cpp +++ b/src/Log.cpp @@ -12,7 +12,7 @@ Log* Log::getInstance() Log::Log(const char* filename) { m_stream.open(filename); - currentLogLevel = Log::ERROR; + currentLogLevel = Log::INFO; } void Log::SC_log(std::string msg, enum LogLevel level) { @@ -22,6 +22,7 @@ void Log::SC_log(std::string msg, enum LogLevel level) { } std::ofstream& Log::SC_log(enum LogLevel level) { + if (level >= currentLogLevel) { m_stream << "time " << sc_core::sc_time_stamp() << ": "; } diff --git a/src/Memory.cpp b/src/Memory.cpp index 829880b..4e07981 100644 --- a/src/Memory.cpp +++ b/src/Memory.cpp @@ -28,6 +28,11 @@ Memory::Memory(sc_module_name name, bool use_file): sc_module(name) SC_THREAD(invalidation_process); } + +uint32_t Memory::getPCfromHEX() { + return program_counter; + +} void Memory::b_transport( tlm::tlm_generic_payload& trans, sc_time& delay ) { tlm::tlm_command cmd = trans.get_command(); @@ -58,8 +63,8 @@ void Memory::b_transport( tlm::tlm_generic_payload& trans, sc_time& delay ) return; } - // cout << "MEM: addr=" << adr << endl; - // cout << "MEM: data=" << mem[adr] << endl; + //cout << "MEM: addr=" << hex << adr << endl << endl; + //cout << "MEM: data=" << mem[adr] << endl; // Obliged to implement read and write commands if ( cmd == tlm::TLM_READ_COMMAND ) @@ -158,6 +163,7 @@ void Memory::readHexFile(string filename) { int byte_count; int address; int i = 0; + int extended_address = 0; hexfile.open(filename); @@ -165,12 +171,12 @@ void Memory::readHexFile(string filename) { 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; + address = address + extended_address; for (i=0; i < byte_count/4; i++) { mem[address+i] = stol(line.substr(9+(i*8), 2), nullptr, 16); @@ -178,6 +184,15 @@ void Memory::readHexFile(string filename) { 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; } + } else if (line.substr(7,2) == "02") { + /* Extended segment address */ + extended_address = stol(line.substr(9,4), nullptr, 16 ) * 4; + } 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; } } } @@ -185,4 +200,11 @@ void Memory::readHexFile(string filename) { } else { SC_REPORT_ERROR("Memory", "Open file error"); } + +#if 0 + for(int i = 50;i<100; i++) { + cout << "Dump address: 0x" << hex << extended_address + i << ": 0x" << + mem[extended_address+i] << dec << endl; + } +#endif } diff --git a/src/RISC_V_execute.cpp b/src/RISC_V_execute.cpp index 33804c0..44a57ac 100644 --- a/src/RISC_V_execute.cpp +++ b/src/RISC_V_execute.cpp @@ -17,7 +17,7 @@ void RISC_V_execute::LUI(Instruction &inst) { rd = inst.rd(); imm = inst.imm_U() << 12; regs->setValue(rd, imm); - log->SC_log(Log::INFO) << "LUI R" << rd << " -> " << imm << endl; + log->SC_log(Log::INFO) << "LUI R" << rd << " <- " << imm << endl; } @@ -47,10 +47,10 @@ void RISC_V_execute::JAL(Instruction &inst) { new_pc = regs->getPC(); regs->setValue(rd, new_pc); - new_pc = new_pc + mem_addr; + new_pc = new_pc + mem_addr - 4; regs->setPC(new_pc); - log->SC_log(Log::INFO) << "JAL R" << rd << " PC + " << mem_addr << " -> PC (" << new_pc << ")" << endl; + log->SC_log(Log::INFO) << "JAL: R" << rd << " PC + " << mem_addr << " -> PC (" << new_pc << ")" << endl; } void RISC_V_execute::JALR(Instruction &inst) { @@ -320,7 +320,7 @@ void RISC_V_execute::ADDI(Instruction &inst) { calc = regs->getValue(rs1) + imm; regs->setValue(rd, calc); - log->SC_log(Log::INFO) << "ADDI: R" << rs1 << " + " << imm << " -> R" << rd << endl; + log->SC_log(Log::INFO) << dec << "ADDI: R" << rs1 << " + " << imm << " -> R" << rd << endl; } void RISC_V_execute::SLTI(Instruction &inst) { @@ -406,7 +406,7 @@ void RISC_V_execute::ANDI(Instruction &inst) { regs->setValue(rd, calc); log->SC_log(Log::INFO) << "ANDI: R" << rs1 << " AND " << imm - << "-> R" << rd << endl; + << " -> R" << rd << endl; } void RISC_V_execute::SLLI(Instruction &inst) { diff --git a/src/Registers.cpp b/src/Registers.cpp index 8217911..5472527 100644 --- a/src/Registers.cpp +++ b/src/Registers.cpp @@ -2,11 +2,11 @@ Registers::Registers() { - memset(register_bank, 0, sizeof(int32_t)*32); + memset(register_bank, 0, sizeof(int32_t)*32); // 32 registers of 32 bits each perf = Performance::getInstance(); - - register_PC = 0; + register_bank[sp] = 1024-1; // SP points to end of memory + register_PC = 0x10000; // default _start address } void Registers::dump(void) { diff --git a/src/Simulator.cpp b/src/Simulator.cpp index 555681b..ee1f489 100644 --- a/src/Simulator.cpp +++ b/src/Simulator.cpp @@ -9,6 +9,8 @@ #include "CPU.h" #include "Memory.h" +#include "BusCtrl.h" +#include "Trace.h" using namespace sc_core; using namespace sc_dt; @@ -20,27 +22,42 @@ SC_MODULE(Top) { //Initiator *initiator; CPU *cpu; - Memory *InstrMemory; - Memory *DataMemory; + //Memory *InstrMemory; + //Memory *DataMemory; + Memory *MainMemory; + BusCtrl* Bus; + Trace *trace; + uint32_t start_PC; sc_signal IRQ; SC_CTOR(Top) { - cpu = new CPU("cpu"); - InstrMemory = new Memory("InstrMemory", filename); - DataMemory = new Memory("Datamemory", false); - cpu->instr_bus.bind(InstrMemory->socket); - cpu->exec->data_bus.bind(DataMemory->socket); + + MainMemory = new Memory("Main_Memory", filename); + start_PC = MainMemory->getPCfromHEX(); + + cpu = new CPU("cpu", start_PC); + + Bus = new BusCtrl("BusCtrl"); + trace = new Trace("Trace"); + + cpu->instr_bus.bind(Bus->cpu_instr_socket); + cpu->exec->data_bus.bind(Bus->cpu_data_socket); + + Bus->data_memory_socket.bind(MainMemory->socket); + Bus->trace_socket.bind(trace->socket); + //cpu->interrupt.bind(IRQ); } ~Top() { cout << "Top destructor" << endl; delete cpu; - delete InstrMemory; - delete DataMemory; + delete MainMemory; + delete Bus; + delete trace; } }; diff --git a/src/Trace.cpp b/src/Trace.cpp new file mode 100644 index 0000000..5d859b0 --- /dev/null +++ b/src/Trace.cpp @@ -0,0 +1,22 @@ +#include "Trace.h" + +SC_HAS_PROCESS(Trace); +Trace::Trace(sc_module_name name): sc_module(name) + ,socket("socket") { + socket.register_b_transport(this, &Trace::b_transport); + } + + +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(); + + + cout << (char) *ptr; + + trans.set_response_status( tlm::TLM_OK_RESPONSE ); +}