diff options
Diffstat (limited to 'VexRiscv/src/test/cpp/common')
-rw-r--r-- | VexRiscv/src/test/cpp/common/framework.h | 287 | ||||
-rw-r--r-- | VexRiscv/src/test/cpp/common/jtag.h | 177 | ||||
-rw-r--r-- | VexRiscv/src/test/cpp/common/uart.h | 126 |
3 files changed, 590 insertions, 0 deletions
diff --git a/VexRiscv/src/test/cpp/common/framework.h b/VexRiscv/src/test/cpp/common/framework.h new file mode 100644 index 0000000..ed419ad --- /dev/null +++ b/VexRiscv/src/test/cpp/common/framework.h @@ -0,0 +1,287 @@ + +#include <stdio.h> +#include <iostream> +#include <stdlib.h> +#include <stdint.h> +#include <cstring> +#include <string.h> +#include <iostream> +#include <fstream> +#include <vector> +#include <iomanip> +#include <time.h> +#include <unistd.h> +#include "verilated_fst_c.h" + +using namespace std; + +class SimElement{ +public: + virtual ~SimElement(){} + virtual void onReset(){} + virtual void postReset(){} + virtual void preCycle(){} + virtual void postCycle(){} +}; + +//#include <functional> +class TimeProcess{ +public: + uint64_t wakeDelay = 0; + bool wakeEnable = false; +// std::function<int(double)> lambda; + virtual ~TimeProcess(){} + virtual void schedule(uint64_t delay){ + wakeDelay = delay; + wakeEnable = true; + } + virtual void tick(){ +// lambda = [this](double x) { return x+1 + this->wakeDelay; }; +// lambda(1.0); + } +}; + + +class SensitiveProcess{ +public: + + virtual ~SensitiveProcess(){} + virtual void tick(uint64_t time){ + + } +}; + +class ClockDomain : public TimeProcess{ +public: + CData* clk; + CData* reset; + uint64_t tooglePeriod; + vector<SimElement*> simElements; + ClockDomain(CData *clk, CData *reset, uint64_t period, uint64_t delay){ + this->clk = clk; + this->reset = reset; + *clk = 0; + this->tooglePeriod = period/2; + schedule(delay); + } + + + bool postCycle = false; + virtual void tick(){ + if(*clk == 0){ + for(SimElement* simElement : simElements){ + simElement->preCycle(); + } + postCycle = true; + *clk = 1; + schedule(0); + }else{ + if(postCycle){ + postCycle = false; + for(SimElement* simElement : simElements){ + simElement->postCycle(); + } + }else{ + *clk = 0; + } + schedule(tooglePeriod); + } + + } + + void add(SimElement *that){ + simElements.push_back(that); + } + +}; + +class AsyncReset : public TimeProcess{ +public: + CData* reset; + uint32_t state; + uint64_t duration; + AsyncReset(CData *reset, uint64_t duration){ + this->reset = reset; + *reset = 0; + state = 0; + this->duration = duration; + schedule(0); + } + + virtual void tick(){ + switch(state){ + case 0: + *reset = 1; + state = 1; + schedule(duration); + break; + case 1: + *reset = 0; + state = 2; + break; + } + } + +}; + + + +class success : public std::exception { }; +template <class T> class Workspace{ +public: + + vector<TimeProcess*> timeProcesses; + vector<SensitiveProcess*> checkProcesses; + T* top; + bool resetDone = false; + double timeToSec = 1e-12; + double speedFactor = 1.0; + uint64_t allowedTime = 0; + string name; + uint64_t time = 0; + #ifdef TRACE + VerilatedFstC* tfp; + #endif + + ofstream logTraces; + + Workspace(string name){ + this->name = name; + top = new T; + logTraces.open (name + ".logTrace"); + } + + virtual ~Workspace(){ + delete top; + #ifdef TRACE + delete tfp; + #endif + + for(auto* p : timeProcesses) delete p; + for(auto* p : checkProcesses) delete p; + + } + + Workspace* setSpeedFactor(double value){ + speedFactor = value; + return this; + } + + + virtual void postReset() {} + virtual void checks(){} + virtual void pass(){ throw success();} + virtual void fail(){ throw std::exception();} + + virtual void dump(uint64_t i){ + #ifdef TRACE + if(i >= TRACE_START) tfp->dump(i); + #endif + } + + Workspace* run(double timeout = 1e6){ + + // init trace dump + #ifdef TRACE + Verilated::traceEverOn(true); + tfp = new VerilatedFstC; + top->trace(tfp, 99); + tfp->open((string(name)+ ".fst").c_str()); + #endif + + struct timespec start_time,tick_time; + uint64_t tickLastSimTime = 0; + top->eval(); + + clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start_time); + clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &tick_time); + + uint32_t flushCounter = 0; + try { + while(1){ + uint64_t delay = ~0l; + for(TimeProcess* p : timeProcesses) + if(p->wakeEnable && p->wakeDelay < delay) + delay = p->wakeDelay; + + if(time*timeToSec > timeout){ + printf("Simulation timeout triggered (%f)\n", time*timeToSec); + fail(); + } + if(delay == ~0l){ + fail(); + } + if(delay != 0){ + dump(time); + } + for(TimeProcess* p : timeProcesses) { + p->wakeDelay -= delay; + if(p->wakeDelay == 0){ + p->wakeEnable = false; + p->tick(); + } + } + + top->eval(); + for(auto* p : checkProcesses) p->tick(time); + + if(delay != 0){ + if(time - tickLastSimTime > 1000*400000 || time - tickLastSimTime > 1.0*speedFactor/timeToSec){ + struct timespec end_time; + clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end_time); + uint64_t diffInNanos = end_time.tv_sec*1e9 + end_time.tv_nsec - tick_time.tv_sec*1e9 - tick_time.tv_nsec; + tick_time = end_time; + double dt = diffInNanos*1e-9; + #ifdef PRINT_PERF + printf("Simulation speed : %f ms/realTime\n",(time - tickLastSimTime)/dt*timeToSec*1e3); + #endif + tickLastSimTime = time; + } + time += delay; + while(allowedTime < delay){ + struct timespec end_time; + clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end_time); + uint64_t diffInNanos = end_time.tv_sec*1e9 + end_time.tv_nsec - start_time.tv_sec*1e9 - start_time.tv_nsec; + start_time = end_time; + double dt = diffInNanos*1e-9; + allowedTime += dt*speedFactor/timeToSec; + if(allowedTime > 0.01*speedFactor/timeToSec) + allowedTime = 0.01*speedFactor/timeToSec; + + } + allowedTime-=delay; + + flushCounter++; + if(flushCounter > 100000){ + #ifdef TRACE + tfp->flush(); + //printf("flush\n"); + #endif + flushCounter = 0; + } + } + + + if (Verilated::gotFinish()) + exit(0); + } + cout << "timeout" << endl; + fail(); + } catch (const success e) { + cout <<"SUCCESS " << name << endl; + } catch (const std::exception& e) { + cout << "FAIL " << name << endl; + } + + + + dump(time); + dump(time+10); + #ifdef TRACE + tfp->close(); + #endif + return this; + } +}; + + diff --git a/VexRiscv/src/test/cpp/common/jtag.h b/VexRiscv/src/test/cpp/common/jtag.h new file mode 100644 index 0000000..868c745 --- /dev/null +++ b/VexRiscv/src/test/cpp/common/jtag.h @@ -0,0 +1,177 @@ + +#include <stdio.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <string.h> +#include <arpa/inet.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <netinet/tcp.h> + +/** Returns true on success, or false if there was an error */ +bool SetSocketBlockingEnabled(int fd, bool blocking) +{ + if (fd < 0) return false; + +#ifdef WIN32 + unsigned long mode = blocking ? 0 : 1; + return (ioctlsocket(fd, FIONBIO, &mode) == 0) ? true : false; +#else + int flags = fcntl(fd, F_GETFL, 0); + if (flags < 0) return false; + flags = blocking ? (flags&~O_NONBLOCK) : (flags|O_NONBLOCK); + return (fcntl(fd, F_SETFL, flags) == 0) ? true : false; +#endif +} + +class Jtag : public TimeProcess{ +public: + CData *tms, *tdi, *tdo, *tck; + enum State {reset}; + uint32_t state; + + int serverSocket, clientHandle; + struct sockaddr_in serverAddr; + struct sockaddr_storage serverStorage; + socklen_t addr_size; + uint64_t tooglePeriod; +// char buffer[1024]; + + Jtag(CData *tms, CData *tdi, CData *tdo, CData* tck,uint64_t period){ + this->tms = tms; + this->tdi = tdi; + this->tdo = tdo; + this->tck = tck; + this->tooglePeriod = period/2; + *tms = 0; + *tdi = 0; + *tdo = 0; + *tck = 0; + state = 0; + schedule(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); + int flag = 1; + setsockopt( serverSocket, /* socket affected */ + IPPROTO_TCP, /* set option at TCP level */ + TCP_NODELAY, /* name of option */ + (char *) &flag, /* the cast is historical + cruft */ + sizeof(int)); /* length of option value */ + + /*int a = 0xFFF; + if (setsockopt(serverSocket, SOL_SOCKET, SO_RCVBUF, &a, sizeof(int)) == -1) { + fprintf(stderr, "Error setting socket opts: %s\n", strerror(errno)); + } + a = 0xFFFFFF; + if (setsockopt(serverSocket, SOL_SOCKET, SO_SNDBUF, &a, sizeof(int)) == -1) { + fprintf(stderr, "Error setting socket opts: %s\n", strerror(errno)); + }*/ + + SetSocketBlockingEnabled(serverSocket,0); + + + //---- Configure settings of the server address struct ----// + // Address family = Internet // + serverAddr.sin_family = AF_INET; + serverAddr.sin_port = htons(7894); + serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); + memset(serverAddr.sin_zero, '\0', sizeof serverAddr.sin_zero); + + //---- 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(serverSocket,1); + + //---- Accept call creates a new socket for the incoming connection ----// + addr_size = sizeof serverStorage; + clientHandle = -1; + + } + void connectionReset(){ + printf("CONNECTION RESET\n"); + shutdown(clientHandle,SHUT_RDWR); + clientHandle = -1; + } + + + virtual ~Jtag(){ + if(clientHandle != -1) { + shutdown(clientHandle,SHUT_RDWR); + usleep(100); + } + if(serverSocket != -1) { + close(serverSocket); + usleep(100); + } + } + + uint32_t selfSleep = 0; + uint32_t checkNewConnectionsTimer = 0; + uint8_t rxBuffer[100]; + int32_t rxBufferSize = 0; + int32_t rxBufferRemaining = 0; + virtual void tick(){ + checkNewConnectionsTimer++; + if(checkNewConnectionsTimer == 5000){ + checkNewConnectionsTimer = 0; + int newclientHandle = accept(serverSocket, (struct sockaddr *) &serverStorage, &addr_size); + if(newclientHandle != -1){ + if(clientHandle != -1){ + connectionReset(); + } + clientHandle = newclientHandle; + printf("CONNECTED\n"); + } + else{ + if(clientHandle == -1) + selfSleep = 1000; + } + } + if(selfSleep) + selfSleep--; + else{ + if(clientHandle != -1){ + uint8_t buffer; + int n; + + if(rxBufferRemaining == 0){ + if(ioctl(clientHandle,FIONREAD,&n) != 0) + connectionReset(); + else if(n >= 1){ + rxBufferSize = read(clientHandle,&rxBuffer,100); + if(rxBufferSize < 0){ + connectionReset(); + }else { + rxBufferRemaining = rxBufferSize; + } + }else { + selfSleep = 30; + } + } + + if(rxBufferRemaining != 0){ + uint8_t buffer = rxBuffer[rxBufferSize - (rxBufferRemaining--)]; + *tms = (buffer & 1) != 0; + *tdi = (buffer & 2) != 0; + *tck = (buffer & 8) != 0; + if(buffer & 4){ + buffer = (*tdo != 0); + //printf("TDO=%d\n",buffer); + if(-1 == send(clientHandle,&buffer,1,0)) + connectionReset(); + }else { + + // printf("\n"); + } + } + } + } + schedule(tooglePeriod); + } + +};
\ No newline at end of file diff --git a/VexRiscv/src/test/cpp/common/uart.h b/VexRiscv/src/test/cpp/common/uart.h new file mode 100644 index 0000000..05021ca --- /dev/null +++ b/VexRiscv/src/test/cpp/common/uart.h @@ -0,0 +1,126 @@ + + + +class UartRx : public TimeProcess{ +public: + + CData *rx; + uint32_t uartTimeRate; + UartRx(CData *rx, uint32_t uartTimeRate){ + this->rx = rx; + this->uartTimeRate = uartTimeRate; + schedule(uartTimeRate); + } + + enum State {START, DATA, STOP}; + State state = START; + char data; + uint32_t counter; + + + virtual void tick(){ + switch(state){ + case START: + if(*rx == 0){ + state = DATA; + counter = 0; + data = 0; + schedule(uartTimeRate*5/4); + } else { + schedule(uartTimeRate/4); + } + break; + case DATA: + data |= (*rx) << counter++; + if(counter == 8){ + state = STOP; + } + schedule(uartTimeRate); + break; + case STOP: + if(*rx){ + cout << data << flush; + } else { + cout << "UART RX FRAME ERROR at " << time << endl; + } + + schedule(uartTimeRate/4); + state = START; + break; + } + } +}; + +#include<pthread.h> +#include <mutex> +#include <queue> + +class UartTx : public TimeProcess{ +public: + + CData *tx; + uint32_t uartTimeRate; + + enum State {START, DATA, STOP}; + State state = START; + char data; + uint32_t counter; + pthread_t inputThreadId; + queue<uint8_t> inputsQueue; + mutex inputsMutex; + + UartTx(CData *tx, uint32_t uartTimeRate){ + this->tx = tx; + this->uartTimeRate = uartTimeRate; + schedule(uartTimeRate); + pthread_create(&inputThreadId, NULL, &inputThreadWrapper, this); + *tx = 1; + } + + static void* inputThreadWrapper(void *uartTx){ + ((UartTx*)uartTx)->inputThread(); + return NULL; + } + + void inputThread(){ + while(1){ + uint8_t c = getchar(); + inputsMutex.lock(); + inputsQueue.push(c); + inputsMutex.unlock(); + } + } + + virtual void tick(){ + switch(state){ + case START: + inputsMutex.lock(); + if(!inputsQueue.empty()){ + data = inputsQueue.front(); + inputsQueue.pop(); + inputsMutex.unlock(); + state = DATA; + counter = 0; + *tx = 0; + schedule(uartTimeRate); + } else { + inputsMutex.unlock(); + schedule(uartTimeRate*50); + } + break; + case DATA: + *tx = (data >> counter) & 1; + counter++; + if(counter == 8){ + state = STOP; + } + schedule(uartTimeRate); + break; + case STOP: + *tx = 1; + schedule(uartTimeRate); + state = START; + break; + } + } +}; |