Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
0530d22a1This file is pinned to the selected release. Download the original to open it in your design tool.
#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>
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 { };
static uint32_t workspaceCycles = 0;
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
VerilatedVcdC* 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(uint32_t timeout = 5000){
// init trace dump
#ifdef TRACE
Verilated::traceEverOn(true);
tfp = new VerilatedVcdC;
top->trace(tfp, 99);
tfp->open((string(name)+ ".vcd").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(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;
}
};