diff --git a/src/main/scala/SpinalRiscv/Plugin/DebugPlugin.scala b/src/main/scala/SpinalRiscv/Plugin/DebugPlugin.scala index 2620028..6aa9d20 100644 --- a/src/main/scala/SpinalRiscv/Plugin/DebugPlugin.scala +++ b/src/main/scala/SpinalRiscv/Plugin/DebugPlugin.scala @@ -91,11 +91,11 @@ class DebugPlugin(debugClockDomain : ClockDomain) extends Plugin[VexRiscv] { haltIt setWhen (io.bus.cmd.data(17)) clearWhen (io.bus.cmd.data(25)) haltedByBreak clearWhen (io.bus.cmd.data(25)) } otherwise { - busReadDataReg(0) := resetIt - busReadDataReg(1) := haltIt - busReadDataReg(2) := isPipBusy - busReadDataReg(3) := haltedByBreak - busReadDataReg(4) := stepIt + io.bus.rsp.data(0) := resetIt + io.bus.rsp.data(1) := haltIt + io.bus.rsp.data(2) := isPipBusy + io.bus.rsp.data(3) := haltedByBreak + io.bus.rsp.data(4) := stepIt } } is(1) { diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 2e4e0e6..cf16d7e 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -136,6 +136,7 @@ double sc_time_stamp(){ class SimElement{ public: + virtual ~SimElement(){} virtual void onReset(){} virtual void postReset(){} virtual void preCycle(){} @@ -154,6 +155,7 @@ public: uint64_t mTimeCmp = 0; uint64_t mTime = 0; VVexRiscv* top; + bool resetDone = false; int i; uint32_t bootPc = -1; uint32_t iStall = 1,dStall = 1; @@ -185,6 +187,10 @@ public: #ifdef TRACE delete tfp; #endif + + for(SimElement* simElement : simElements) { + delete simElement; + } } Workspace* loadHex(string path){ @@ -312,6 +318,8 @@ public: postReset(); + resetDone = true; + #ifdef REF if(bootPc != -1) top->VexRiscv->core->prefetch_pc = bootPc; #else @@ -608,16 +616,14 @@ bool SetSocketBlockingEnabled(int fd, bool blocking) class DebugPlugin : public SimElement{ public: - - Workspace *ws; VVexRiscv* top; - int welcomeSocket, clientHandle; - char buffer[1024]; + int serverSocket, clientHandle; struct sockaddr_in serverAddr; struct sockaddr_storage serverStorage; socklen_t addr_size; + char buffer[1024]; uint32_t timeSpacer = 0; DebugPlugin(Workspace* ws){ @@ -627,33 +633,46 @@ public: - /*---- Create the socket. The three arguments are: ----*/ - /* 1) Internet domain 2) Stream socket 3) Default protocol (TCP in this case) */ - welcomeSocket = socket(PF_INET, SOCK_STREAM, 0); - SetSocketBlockingEnabled(welcomeSocket,0); + //---- Create the socket. The three arguments are: ----// + // 1) Internet domain 2) Stream socket 3) Default protocol (TCP in this case) // + serverSocket = socket(PF_INET, SOCK_STREAM, 0); + assert(serverSocket != -1); + SetSocketBlockingEnabled(serverSocket,0); - /*---- Configure settings of the server address struct ----*/ - /* Address family = Internet */ + //---- Configure settings of the server address struct ----// + // Address family = Internet // serverAddr.sin_family = AF_INET; - /* Set port number, using htons function to use proper byte order */ + // Set port number, using htons function to use proper byte order // serverAddr.sin_port = htons(7891); - /* Set IP address to localhost */ + // Set IP address to localhost // serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); - /* Set all bits of the padding field to 0 */ + // Set all bits of the padding field to 0 // memset(serverAddr.sin_zero, '\0', sizeof serverAddr.sin_zero); - /*---- Bind the address struct to the socket ----*/ - bind(welcomeSocket, (struct sockaddr *) &serverAddr, sizeof(serverAddr)); + //---- Bind the address struct to the socket ----// + bind(serverSocket, (struct sockaddr *) &serverAddr, sizeof(serverAddr)); - /*---- Listen on the socket, with 5 max connection requests queued ----*/ - listen(welcomeSocket,5); + //---- Listen on the socket, with 5 max connection requests queued ----// + listen(serverSocket,1); - /*---- Accept call creates a new socket for the incoming connection ----*/ + //---- Accept call creates a new socket for the incoming connection ----// addr_size = sizeof serverStorage; + clientHandle = -1; } + virtual ~DebugPlugin(){ + if(clientHandle != -1) { + shutdown(clientHandle,SHUT_RDWR); + usleep(100); + } + if(serverSocket != -1) { + close(serverSocket); + usleep(100); + } + } + virtual void onReset(){ top->debug_bus_cmd_valid = 0; top->debugReset = 1; @@ -665,16 +684,23 @@ public: top->debugReset = 0; } + bool readRsp = false; virtual void preCycle(){ if(clientHandle == -1){ - clientHandle = accept(welcomeSocket, (struct sockaddr *) &serverStorage, &addr_size); + clientHandle = accept(serverSocket, (struct sockaddr *) &serverStorage, &addr_size); } + if(top->debug_bus_cmd_valid && top->debug_bus_cmd_ready && !top->debug_bus_cmd_payload_wr){ + readRsp = true; + } + if(readRsp){ if(clientHandle != -1){ send(clientHandle,&top->debug_bus_rsp_data,4,0); } + readRsp = false; } + } virtual void postCycle(){ @@ -690,6 +716,7 @@ public: if(timeSpacer == 0){ int requiredSize = 1 + 1 + 4 + 4; int n = read(clientHandle,buffer,requiredSize); + if(n == requiredSize){ bool wr = buffer[0]; uint32_t size = buffer[1]; @@ -879,6 +906,169 @@ public: }; + +#include +#include +#include + +#define RISCV_SPINAL_FLAGS_RESET 1<<0 +#define RISCV_SPINAL_FLAGS_HALT 1<<1 +#define RISCV_SPINAL_FLAGS_PIP_BUSY 1<<2 +#define RISCV_SPINAL_FLAGS_IS_IN_BREAKPOINT 1<<3 +#define RISCV_SPINAL_FLAGS_STEP 1<<4 +#define RISCV_SPINAL_FLAGS_PC_INC 1<<5 + +#define RISCV_SPINAL_FLAGS_RESET_SET 1<<16 +#define RISCV_SPINAL_FLAGS_HALT_SET 1<<17 + +#define RISCV_SPINAL_FLAGS_RESET_CLEAR 1<<24 +#define RISCV_SPINAL_FLAGS_HALT_CLEAR 1<<25 + +class DebugPluginTest : public Workspace{ +public: + pthread_t clientThreadId; + char buffer[1024]; + bool clientSuccess = false, clientFail = false; + + static void* clientThreadWrapper(void *debugModule){ + ((DebugPluginTest*)debugModule)->clientThread(); + return NULL; + } + + int clientSocket; + void accessCmd(bool wr, uint32_t size, uint32_t address, uint32_t data){ + buffer[0] = wr; + buffer[1] = size; + *((uint32_t*) (buffer + 2)) = address; + *((uint32_t*) (buffer + 6)) = data; + send(clientSocket,buffer,10,0); + } + + void writeCmd(uint32_t size, uint32_t address, uint32_t data){ + accessCmd(true, 2, address, data); + } + + + uint32_t readCmd(uint32_t size, uint32_t address){ + accessCmd(false, 2, address, VL_RANDOM_I(32)); + if(recv(clientSocket, buffer, 4, 0) != 4){ + printf("Should read 4 bytes"); + fail(); + } + return *((uint32_t*) buffer); + } + + + + void clientThread(){ + struct sockaddr_in serverAddr; + socklen_t addr_size; + + //---- Create the socket. The three arguments are: ----// + // 1) Internet domain 2) Stream socket 3) Default protocol (TCP in this case) // + clientSocket = socket(PF_INET, SOCK_STREAM, 0); + + //---- Configure settings of the server address struct ----// + // Address family = Internet // + serverAddr.sin_family = AF_INET; + // Set port number, using htons function to use proper byte order // + serverAddr.sin_port = htons(7891); + // Set IP address to localhost // + serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); + // Set all bits of the padding field to 0 // + memset(serverAddr.sin_zero, '\0', sizeof serverAddr.sin_zero); + + //---- Connect the socket to the server using the address struct ----// + addr_size = sizeof serverAddr; + int error = connect(clientSocket, (struct sockaddr *) &serverAddr, addr_size); +// printf("!! %x\n",readCmd(2,0x8)); + uint32_t debugAddress = 0xFFF00000; + uint32_t readValue; + + while(resetDone != true){usleep(100);} + while((readCmd(2,debugAddress) & RISCV_SPINAL_FLAGS_HALT) == 0){usleep(100);} + if((readValue = readCmd(2,debugAddress + 4)) != 0x0000000C){ + printf("wrong break PC %x\n",readValue); + clientFail = true; return; + } + + writeCmd(2, debugAddress + 4, 0x13 + (1 << 15)); //Read regfile + if((readValue = readCmd(2,debugAddress + 4)) != 10){ + printf("wrong break PC %x\n",readValue); + clientFail = true; return; + } + + writeCmd(2, debugAddress + 4, 0x13 + (2 << 15)); //Read regfile + if((readValue = readCmd(2,debugAddress + 4)) != 20){ + printf("wrong break PC %x\n",readValue); + clientFail = true; return; + } + + writeCmd(2, debugAddress + 4, 0x13 + (3 << 15)); //Read regfile + if((readValue = readCmd(2,debugAddress + 4)) != 30){ + printf("wrong break PC %x\n",readValue); + clientFail = true; return; + } + + writeCmd(2, debugAddress + 4, 0x13 + (1 << 7) + (40 << 20)); //Write x1 with 40 + writeCmd(2, debugAddress + 4, 0x13 + (29 << 7) + (0x10 << 20)); //Write x29 with 0x10 + writeCmd(2, debugAddress + 4, 0x67 + (29 << 15)); //Branch x29 + writeCmd(2, debugAddress + 0, RISCV_SPINAL_FLAGS_HALT_CLEAR); //Run CPU + + while((readCmd(2,debugAddress) & RISCV_SPINAL_FLAGS_HALT) == 0){usleep(100);} + if((readValue = readCmd(2,debugAddress + 4)) != 0x00000014){ + printf("wrong break PC 2 %x\n",readValue); + clientFail = true; return; + } + + + writeCmd(2, debugAddress + 4, 0x13 + (3 << 15)); //Read regfile + if((readValue = readCmd(2,debugAddress + 4)) != 60){ + printf("wrong x1 %x\n",readValue); + clientFail = true; return; + } + + writeCmd(2, debugAddress + 4, 0x13 + (29 << 7) + (0x18 << 20)); //Write x29 with 0x10 + writeCmd(2, debugAddress + 4, 0x67 + (29 << 15)); //Branch x29 + writeCmd(2, debugAddress + 0, RISCV_SPINAL_FLAGS_HALT_CLEAR); //Run CPU + + + + while((readCmd(2,debugAddress) & RISCV_SPINAL_FLAGS_HALT) == 0){usleep(100);} + if((readValue = readCmd(2,debugAddress + 4)) != 0x00000024){ + printf("wrong break PC 2 %x\n",readValue); + clientFail = true; return; + } + + + writeCmd(2, debugAddress + 4, 0x13 + (3 << 15)); //Read x3 + if((readValue = readCmd(2,debugAddress + 4)) != 171){ + printf("wrong x3 %x\n",readValue); + clientFail = true; return; + } + + + clientSuccess = true; + } + + + DebugPluginTest() : Workspace("DebugPluginTest") { + loadHex("../../resources/hex/debugPlugin.hex"); + pthread_create(&clientThreadId, NULL, &clientThreadWrapper, this); + noInstructionReadCheck(); + } + + virtual ~DebugPluginTest(){ + if(clientSocket != -1) close(clientSocket); + } + + virtual void checks(){ + if(clientSuccess) pass(); + if(clientFail) fail(); + } +}; + + string riscvTestMain[] = { "rv32ui-p-simple", "rv32ui-p-lui", @@ -964,7 +1154,14 @@ int main(int argc, char **argv, char **env) { for(int idx = 0;idx < 1;idx++){ #ifndef REF + + + TestA().run(); + + + + for(const string &name : riscvTestMain){ redo(REDO,RiscvTest(name).run();) } @@ -992,18 +1189,15 @@ int main(int argc, char **argv, char **env) { #endif #endif - + #ifdef DEBUG_PLUGIN + redo(REDO,DebugPluginTest().run(100e3);); + #endif #ifdef DHRYSTONE -// Dhrystone("dhrystoneO3",false,false).run(0.05e6); - Dhrystone("dhrystoneO3_Stall","dhrystoneO3",true,true).run(1.1e6); Dhrystone("dhrystoneO3M_Stall","dhrystoneO3M",true,true).run(1.5e6); Dhrystone("dhrystoneO3","dhrystoneO3",false,false).run(1.5e6); Dhrystone("dhrystoneO3M","dhrystoneO3M",false,false).run(1.2e6); - -// Dhrystone("dhrystoneO3ML",false,false).run(8e6); -// Dhrystone("dhrystoneO3MLL",false,false).run(80e6); #endif diff --git a/src/test/cpp/regression/makefile b/src/test/cpp/regression/makefile index 937074c..131aeaf 100644 --- a/src/test/cpp/regression/makefile +++ b/src/test/cpp/regression/makefile @@ -15,6 +15,9 @@ REF_TIME=no ADDCFLAGS += -CFLAGS -D${IBUS} ADDCFLAGS += -CFLAGS -D${DBUS} ADDCFLAGS += -CFLAGS -DREDO=${REDO} +ADDCFLAGS += -CFLAGS -pthread + + ifeq ($(DHRYSTONE),yes) ADDCFLAGS += -CFLAGS -DDHRYSTONE endif @@ -58,10 +61,10 @@ run: compile ./obj_dir/VVexRiscv verilate: - verilator -cc ../../../../VexRiscv.v -O3 -CFLAGS -std=c++11 ${ADDCFLAGS} --gdbbt ${VERILATOR_ARGS} -Wno-WIDTH --x-assign unique --exe main.cpp + verilator -cc ../../../../VexRiscv.v -O3 -CFLAGS -std=c++11 -LDFLAGS -pthread ${ADDCFLAGS} --gdbbt ${VERILATOR_ARGS} -Wno-WIDTH --x-assign unique --exe main.cpp compile: verilate - make -j -C obj_dir/ -f VVexRiscv.mk VVexRiscv + make -j -C obj_dir/ -f VVexRiscv.mk VVexRiscv clean: rm -rf obj_dir diff --git a/src/test/resources/hex/debugPlugin.hex b/src/test/resources/hex/debugPlugin.hex new file mode 100644 index 0000000..6664f16 --- /dev/null +++ b/src/test/resources/hex/debugPlugin.hex @@ -0,0 +1,5 @@ +:100000009300A000130140019301E0017300100070 +:10001000B381200073001000938111009381A1002F +:080020009381410673001000FA +:0400000540000000B7 +:00000001FF