diff options
author | Friedrich Beckmann <friedrich.beckmann@hs-augsburg.de> | 2022-07-25 17:55:39 +0200 |
---|---|---|
committer | Friedrich Beckmann <friedrich.beckmann@hs-augsburg.de> | 2022-07-25 17:55:39 +0200 |
commit | 3fff6023602822531efdae30bc8ebf862967f1ef (patch) | |
tree | 16028102b8d850f8ab3115d28a8539ca6bc5f51d /VexRiscv/src/test/cpp/common/framework.h |
Initial Commit
Diffstat (limited to 'VexRiscv/src/test/cpp/common/framework.h')
-rw-r--r-- | VexRiscv/src/test/cpp/common/framework.h | 287 |
1 files changed, 287 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; + } +}; + + |