It seems that in the most recent versions, Verilator supports delay statements.
To do so the argument “–timing” should be added to the Verilator command line argument.
Can this be done in Qspice?
Is there a way to implement a delay directly in C++?
I’ve never gotten Verilator to support timing. In fact, Verilog is usually presented as being capable of synthesizable Verilog, meaning no timing, even though behavior Verilog constructs are supported.
But the Verilator is one rev back from current, so I’ll be updating it and see if it can do timing. I’m hoping $monitor works now. It’s documented in the Verilator documentation, but from looking at the Verilator source code, it seems to be only partially implemented. It seems that some Verilator features are only supported if used in conjunction with SystemC. I’m bypassing SystemC and going straight to the metal in QSPICE.
Sure, it is a long time I don’t work on the code but I remember it was working at the time.
The delay is embedded in this dead time generator block I built for gate driver’s logics.
Let me know if you need further assistance.
// Automatically generated C++ file on Thu Aug 17 09:26:31 2023
//
// To build with Digital Mars C++ Compiler:
//
// dmc -mn -WD deatimegeneratorc.cpp kernel32.lib
#include <malloc.h>
union uData
{
bool b;
char c;
unsigned char uc;
short s;
unsigned short us;
int i;
unsigned int ui;
float f;
double d;
long long int i64;
unsigned long long int ui64;
char *str;
unsigned char *bytes;
};
// int DllMain() must exist and return 1 for a process to load the .DLL
// See https://docs.microsoft.com/en-us/windows/win32/dlls/dllmain for more information.
int __stdcall DllMain(void *module, unsigned int reason, void *reserved) { return 1; }
void bzero(void *ptr, unsigned int count)
{
unsigned char *first = (unsigned char *) ptr;
unsigned char *last = first + count;
while(first < last)
*first++ = '\0';
}
// #undef pin names lest they collide with names in any header file(s) you might include.
#undef in
#undef out
struct sDEATIMEGENERATORC
{
int state;
double Tstart_RE;
double Tstart_FE;
};
extern "C" __declspec(dllexport) void deatimegeneratorc(struct sDEATIMEGENERATORC **opaque, double t, union uData *data)
{
bool in = data[0].b; // input
double TDELAY_RE = data[1].d;
double TDELAY_FE = data[2].d;
bool &out = data[3].b; // output
if(!*opaque)
{
*opaque = (struct sDEATIMEGENERATORC *) malloc(sizeof(struct sDEATIMEGENERATORC));
bzero(*opaque, sizeof(struct sDEATIMEGENERATORC));
}
struct sDEATIMEGENERATORC *instance = *opaque;
switch(instance->state)
{
case 0:
{
if(in) // if in == 1
{
instance->Tstart_RE=t; //Save the time when it changes from 0 to 1
instance->state=1;
out=0;
}
}
break;
case 1:
if(in && (t-instance->Tstart_RE)>TDELAY_RE) // if in still = 1 and if deltaT is higher then Tdelay (we waited the delay time)
{
instance->state=2;
out=1;
}
if(!in) //if in == 0 safety measure to be sure that if the input changed before Tdelay we don't set the output to 1 but keeps it to 0
{
instance->state=0;
out=0;
}
break;
case 2:
if(!in) //if in == 0 keeps the output to 1 but save the time of the falling edge
{
instance->Tstart_FE=t;
instance->state=3;
out=1;
}
break;
case 3:
if(!in && (t-instance->Tstart_FE)>TDELAY_FE) // if in still = 0 and if deltaT is higher then Tdelay (we waited the delay time)
{
instance->state=0;
out=0;
}
if(in) //if in == 0 safety measure to be sure that if the input changed before Tdelay we don't set the output to 1 but keeps it to 0
{
instance->state=1;
out=1;
}
break;
default: // initiate the case value and the output
instance->state=0;
out=0;
break;
}
}
extern "C" __declspec(dllexport) void Trunc(struct sDEATIMEGENERATORC *inst, double t, union uData *data, double *timestep)
{ // limit the timestep to a tolerance if the circuit causes a change in struct sDEATIMEGENERATORC
const double ttol = 1e-9;
if(*timestep > ttol)
{
bool &out = data[3].b; // output
// Save output vector
const bool _out = out;
struct sDEATIMEGENERATORC tmp = *inst;
deatimegeneratorc(&(&tmp), t, data);
if(tmp.state != inst->state) // implement a meaningful way to detect if the state has changed
*timestep = ttol;
// Restore output vector
out = _out;
}
}
extern "C" __declspec(dllexport) void Destroy(struct sDEATIMEGENERATORC *inst)
{
free(inst);
}
Any updates on this? Having QSPICE support `timescale and #delay in Verilog blocks would be EXTREMELY useful to those of us attempting to create accurate QSPICE models of complex ICs.