Prepare for debug

This commit is contained in:
mariusmonton 2021-02-21 13:49:05 +01:00
parent 4c60d6ae75
commit 49103e5591
7 changed files with 385 additions and 7 deletions

View File

@ -336,7 +336,7 @@ public:
* @param inst instruction to execute * @param inst instruction to execute
* @return true if PC is affected by instruction * @return true if PC is affected by instruction
*/ */
bool process_instruction(Instruction *inst); bool process_instruction(Instruction *inst, bool *breakpoint = nullptr);
/** /**
* @brief Decodes opcode of instruction * @brief Decodes opcode of instruction

View File

@ -405,7 +405,7 @@ public:
bool Exec_C_JAL(int m_rd); bool Exec_C_JAL(int m_rd);
bool Exec_C_EBREAK(); bool Exec_C_EBREAK();
bool process_instruction(Instruction *inst); bool process_instruction(Instruction *inst, bool *breakpoint = nullptr);
}; };
#endif #endif

46
inc/Debug.h Normal file
View File

@ -0,0 +1,46 @@
/*!
\file Debug.h
\brief GDB connector
\author Màrius Montón
\date February 2021
*/
// SPDX-License-Identifier: GPL-3.0-or-later
#ifndef INC_DEBUG_H_
#define INC_DEBUG_H_
#define SC_INCLUDE_DYNAMIC_PROCESSES
#include "systemc"
#include "tlm.h"
#include "tlm_utils/simple_initiator_socket.h"
#include "CPU.h"
#include "Memory.h"
class Debug: sc_core::sc_module {
public:
Debug(sc_core::sc_module_name name, uint32_t PC, CPU *cpu, Memory* mem);
~Debug();
private:
std::string compute_checksum_string(const std::string &msg);
void send_packet(int conn, const std::string &msg);
std::string receive_packet();
void handle_gdb_loop();
static constexpr size_t bufsize = 1024 * 8;
char iobuf[bufsize]{};
int conn;
CPU *dbg_cpu;
Memory *dbg_mem;
tlm::tlm_generic_payload dbg_trans;
unsigned char pyld_array[128];
std::unordered_set<uint32_t> breakpoints;
};
#endif /* INC_DEBUG_H_ */

View File

@ -1160,9 +1160,10 @@ bool BASE_ISA::Exec_SFENCE() const {
return true; return true;
} }
bool BASE_ISA::process_instruction(Instruction *inst) { bool BASE_ISA::process_instruction(Instruction *inst, bool *breakpoint) {
bool PC_not_affected = true; bool PC_not_affected = true;
*breakpoint = false;
setInstr(inst->getInstr()); setInstr(inst->getInstr());
switch (decode()) { switch (decode()) {
@ -1290,9 +1291,13 @@ bool BASE_ISA::process_instruction(Instruction *inst) {
break; break;
case OP_ECALL: case OP_ECALL:
Exec_ECALL(); Exec_ECALL();
*breakpoint = true;
std::cout << "ECALL" << std::endl;
break; break;
case OP_EBREAK: case OP_EBREAK:
Exec_EBREAK(); Exec_EBREAK();
*breakpoint = true;
std::cout << "EBREAK" << std::endl;
break; break;
case OP_CSRRW: case OP_CSRRW:
Exec_CSRRW(); Exec_CSRRW();

View File

@ -680,9 +680,11 @@ bool C_extension::Exec_C_EBREAK() {
return true; return true;
} }
bool C_extension::process_instruction(Instruction *inst) { bool C_extension::process_instruction(Instruction *inst, bool *breakpoint) {
bool PC_not_affected = true; bool PC_not_affected = true;
*breakpoint = false;
setInstr(inst->getInstr()); setInstr(inst->getInstr());
switch (decode()) { switch (decode()) {
@ -766,6 +768,8 @@ bool C_extension::process_instruction(Instruction *inst) {
break; break;
case OP_C_EBREAK: case OP_C_EBREAK:
Exec_C_EBREAK(); Exec_C_EBREAK();
std::cout << "C_EBREAK" << std::endl;
*breakpoint = true;
break; break;
[[unlikely]] default: [[unlikely]] default:
std::cout << "C instruction not implemented yet" << "\n"; std::cout << "C instruction not implemented yet" << "\n";

310
src/Debug.cpp Normal file
View File

@ -0,0 +1,310 @@
/*!
\file Debug.cpp
\brief GDB connector
\author Màrius Montón
\date February 2021
*/
// SPDX-License-Identifier: GPL-3.0-or-later
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <sys/socket.h>
#include <netinet/in.h>
#include <boost/algorithm/string.hpp>
#include "Debug.h"
constexpr char nibble_to_hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
Debug::Debug(sc_core::sc_module_name name, uint32_t PC, CPU *cpu, Memory* mem) {
std::cout << "Debug constructor\n";
dbg_cpu = cpu;
dbg_mem = mem;
int sock = socket(AF_INET, SOCK_STREAM, 0);
int optval = 1;
int ans = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &optval,
sizeof(optval));
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(1234);
ans = bind(sock, (struct sockaddr *) &addr, sizeof(addr));
ans = listen(sock, 1);
socklen_t len = sizeof(addr);
conn = accept(sock, (struct sockaddr *) &addr, &len);
handle_gdb_loop();
}
Debug::~Debug() {
}
void Debug::send_packet(int conn, const std::string &msg) {
std::string frame = "+$" + msg + "#" + compute_checksum_string(msg);
memcpy(iobuf, frame.c_str(), frame.size());
int nbytes = ::send(conn, iobuf, frame.size(), 0);
}
std::string Debug::receive_packet() {
int nbytes = ::recv(conn, iobuf, bufsize, 0);
if (nbytes == 0) {
return "";
} else if (nbytes == 1) {
return std::string("+");
} else {
// 1) find $
// 2) find #
// 3) assert that two chars follow #
char *start = strchr(iobuf, '$');
char *end = strchr(iobuf, '#');
std::string message(start + 1, end - (start + 1));
{
//std::string local_checksum = compute_checksum_string(message);
//std::string recv_checksum(end + 1, 2);
//assert(local_checksum == recv_checksum);
}
return message;
}
}
void Debug::handle_gdb_loop() {
std::cout << "Handle_GDB_Loop\n";
Registers *register_bank = dbg_cpu->getRegisterBank();
while (true) {
std::string msg = receive_packet();
// std::cout << "msg: " << msg << std::endl;
if (msg.size() == 0) {
std::cout << "remote connection seems to be closed, terminating ..."
<< std::endl;
break;
} else if (msg == "+") {
// NOTE: just ignore this message, nothing to do in this case
} else if (boost::starts_with(msg, "qSupported")) {
printf("qSupported\n");
send_packet(conn, "PacketSize=1024;swbreak-;hwbreak+;vContSupported+");
} else if (msg == "vMustReplyEmpty") {
printf("vMustReplyEmpty\n");
send_packet(conn, "");
} else if (msg == "Hg0") {
printf("Hq0\n");
send_packet(conn, "OK");
} else if (msg == "Hc0") {
printf("Hc0\n");
send_packet(conn, "");
} else if (msg == "qTStatus") {
printf("qTStatus\n");
send_packet(conn, "");
} else if (msg == "?") {
printf("?\n");
send_packet(conn, "S05");
} else if (msg == "qfThreadInfo") {
printf("qThreadInfo\n");
send_packet(conn, "");
} else if (boost::starts_with(msg, "qL")) {
printf("qL\n");
send_packet(conn, "");
} else if (msg == "Hc-1") {
printf("Hc-1\n");
send_packet(conn, "OK");
} else if (msg == "qC") {
printf("qC\n");
send_packet(conn, "-1");
} else if (msg == "qAttached") {
printf("qAttached\n");
send_packet(conn, "0"); // 0 process started, 1 attached to process
} else if (msg == "g") {
// std::cout << msg << '\n';
std::stringstream stream;
stream << std::setfill('0') << std::hex;
for (int i = 1; i < 32; i++) {
stream << std::setw(8) << register_bank->getValue(i);
}
send_packet(conn, stream.str());
} else if (boost::starts_with(msg, "p")) {
std::cout << "P : " << msg << std::endl;
long n = strtol(msg.c_str() + 1, 0, 16);
int reg_value;
if (n < 32) {
reg_value = register_bank->getValue(n);
} else if (n == 32) {
reg_value = register_bank->getPC();
} else {
// see: https://github.com/riscv/riscv-gnu-toolchain/issues/217
// risc-v register 834
reg_value = register_bank->getCSR(n - 65);
}
std::stringstream stream;
stream << std::setfill('0') << std::hex;
stream << std::setw(8) << htonl(reg_value);
send_packet(conn, stream.str());
} else if (boost::starts_with(msg, "P")) {
printf("P\n");
char * pEnd;
long reg = strtol(msg.c_str() + 1, &pEnd, 16);
std::cout << "n: " << reg;
int val = strtol(pEnd + 1, 0, 16);
std::cout << "= " << val << std::endl;
register_bank->setValue(reg + 1, val);
send_packet(conn, "OK");
} else if (boost::starts_with(msg, "m")) {
printf("m\n");
char * pEnd;
long addr = strtol(msg.c_str() + 1, &pEnd, 16);;
int len = strtol(pEnd + 1, &pEnd, 16);
std::cout << "msg m: " << msg << std::endl;
std::cout << std::hex << "addr: " << addr << " , " << len << std::endl;
dbg_trans.set_data_ptr(pyld_array);
dbg_trans.set_command(tlm::TLM_READ_COMMAND);
dbg_trans.set_address(addr);
dbg_trans.set_data_length(len);
dbg_mem->transport_dbg(dbg_trans);
std::stringstream stream;
stream << std::setfill('0') << std::hex;
for (auto &c : pyld_array) {
stream << std::setw(2) << (0xFF & c);
}
send_packet(conn, stream.str());
} else if (boost::starts_with(msg, "M")) {
printf("M\n");
//memory_access_t m = parse_memory_access(msg);
//std::string data = msg.substr(msg.find(":") + 1);
//write_memory(m.start, m.nbytes, data);
send_packet(conn, "OK");
} else if (boost::starts_with(msg, "X")) {
printf("X\n");
send_packet(conn, ""); // binary data unsupported, gdb will send
// text based message M
} else if (msg == "qOffsets") {
printf("qOffsets\n");
// NOTE: seems to be additional offsets wrt. the exec. elf file
send_packet(conn, "Text=0;Data=0;Bss=0");
} else if (msg == "qSymbol::") {
printf("qSymbol\n");
send_packet(conn, "OK");
} else if (msg == "vCont?") {
printf("vCont?\n");
send_packet(conn, "vCont;cs");
} else if (msg == "c") {
printf("c\n");
//try {
// core.run();
//if (core.status == CoreExecStatus::HitBreakpoint) {
// send_packet(conn, "S05");
// core.status = CoreExecStatus::Runnable;
//} else if (core.status == CoreExecStatus::Terminated) {
//send_packet(conn, "S03");
//} else {
// assert(false && "invalid core status (apparently still marked as runnable)");
//}
//} catch (std::exception &e) {
// send_packet(conn, "S04");
//}
bool breakpoint_hit = false;
bool bkpt = false;
do {
// std::cout << "PC: " << std::hex << register_bank->getPC() << std::endl;
bkpt = dbg_cpu->CPU_step();
uint32_t currentPC = register_bank->getPC();
auto search = breakpoints.find(currentPC);
if (search != breakpoints.end()) {
breakpoint_hit = true;
}
} while ((breakpoint_hit == false) && (bkpt == false));
std::cout << "Breakpoint hit at 0x" << std::hex << register_bank->getPC() << std::endl;
//send_packet(conn, "S05");
send_packet(conn, "S03");
} else if (msg == "s") {
printf("s\n");
bool breakpoint;
dbg_cpu->CPU_step();
uint32_t currentPC = register_bank->getPC();
auto search = breakpoints.find(currentPC);
if (search != breakpoints.end()) {
breakpoint = true;
} else {
breakpoint = false;
}
if (breakpoint) {
send_packet(conn, "S03");
} else {
send_packet(conn, "S05");
}
} else if (boost::starts_with(msg, "vKill")) {
printf("vKill\n");
send_packet(conn, "OK");
break;
} else if (boost::starts_with(msg, "Z1")) {
char * pEnd;
long addr = strtol(msg.c_str() + 3, &pEnd, 16);;
std::cout << "msg m: " << msg << std::endl;
breakpoints.insert(addr);
std::cout << "Breakpoint set to addres 0x"<< std::hex << addr << std::endl;
send_packet(conn, "OK");
} else if (boost::starts_with(msg, "z1")) {
send_packet(conn, "OK");
} else if (boost::starts_with(msg, "z0")) {
} else if (boost::starts_with(msg, "Z0")) {
char * pEnd;
long addr = strtol(msg.c_str() + 3, &pEnd, 16);;
std::cout << "msg m: " << msg << std::endl;
breakpoints.insert(addr);
std::cout << "Breakpoint set to address 0x"<< std::hex << addr << std::endl;
send_packet(conn, "OK");
} else {
std::cout << "unsupported message '" << msg
<< "' detected, terminating ..." << std::endl;
break;
}
}
}
std::string Debug::compute_checksum_string(const std::string &msg) {
unsigned sum = 0;
for (auto c : msg) {
sum += unsigned(c);
}
sum = sum % 256;
char low = nibble_to_hex[sum & 0xf];
char high = nibble_to_hex[(sum & (0xf << 4)) >> 4];
return {high, low};
}

View File

@ -21,8 +21,10 @@
#include "BusCtrl.h" #include "BusCtrl.h"
#include "Trace.h" #include "Trace.h"
#include "Timer.h" #include "Timer.h"
#include "Debug.h"
std::string filename; std::string filename;
bool debug_session = false;
/** /**
* @class Simulator * @class Simulator
@ -44,7 +46,7 @@ SC_MODULE(Simulator) {
MainMemory = new Memory("Main_Memory", filename); MainMemory = new Memory("Main_Memory", filename);
start_PC = MainMemory->getPCfromHEX(); start_PC = MainMemory->getPCfromHEX();
cpu = new CPU("cpu", start_PC); cpu = new CPU("cpu", start_PC, debug_session);
Bus = new BusCtrl("BusCtrl"); Bus = new BusCtrl("BusCtrl");
trace = new Trace("Trace"); trace = new Trace("Trace");
@ -58,6 +60,10 @@ SC_MODULE(Simulator) {
Bus->timer_socket.bind(timer->socket); Bus->timer_socket.bind(timer->socket);
timer->irq_line.bind(cpu->irq_line_socket); timer->irq_line.bind(cpu->irq_line_socket);
if (debug_session) {
Debug debug("Debug", start_PC, cpu, MainMemory);
}
} }
~Simulator() { ~Simulator() {
@ -87,9 +93,14 @@ void process_arguments(int argc, char *argv[]) {
log = Log::getInstance(); log = Log::getInstance();
log->setLogLevel(Log::ERROR); log->setLogLevel(Log::ERROR);
while ((c = getopt(argc, argv, "D:f:?")) != -1) { debug_session = false;
while ((c = getopt(argc, argv, "DL:f:?")) != -1) {
switch (c) { switch (c) {
case 'D': case 'D':
debug_session = true;
break;
case 'L':
debug_level = std::atoi(optarg); debug_level = std::atoi(optarg);
switch (debug_level) { switch (debug_level) {
@ -114,7 +125,7 @@ void process_arguments(int argc, char *argv[]) {
filename = std::string(optarg); filename = std::string(optarg);
break; break;
case '?': case '?':
std::cout << "Call ./RISCV_TLM -D <debuglevel> (0..3) filename.hex" std::cout << "Call ./RISCV_TLM -D -L <debuglevel> (0..3) filename.hex"
<< std::endl; << std::endl;
break; break;
default: default:
@ -126,6 +137,8 @@ void process_arguments(int argc, char *argv[]) {
if (filename.empty()) { if (filename.empty()) {
filename = std::string(argv[optind]); filename = std::string(argv[optind]);
} }
std::cout << "file: " << filename << '\n';
} }
int sc_main(int argc, char *argv[]) { int sc_main(int argc, char *argv[]) {