iverilog/vvp/vpi_time.cc

479 lines
11 KiB
C++
Raw Normal View History

/*
* Copyright (c) 2001-2012 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
2003-03-13 21:31:40 +01:00
# include "config.h"
# include "vpi_priv.h"
# include "schedule.h"
# include <cstdio>
# include <cmath>
# include <cassert>
/*
* The $time system function is supported in VPI contexts (i.e. an
* argument to a system task/function) as a vpiSysFuncCall object. The
* $display function divines that this is a function call and uses a
* vpi_get_value to get the value.
*/
/*
* vpi_time_precision is the precision of the simulation clock. It is
* set by the :vpi_time_precision directive in the vvp source file.
*/
static int vpi_time_precision = 0;
2003-02-03 02:09:20 +01:00
static struct __vpiSystemTime global_simtime;
void vpip_time_to_timestruct(struct t_vpi_time*ts, vvp_time64_t ti)
{
ts->low = ti & 0xFFFFFFFF;
ts->high = (ti >> 32) & 0xFFFFFFFF;
}
vvp_time64_t vpip_timestruct_to_time(const struct t_vpi_time*ts)
{
vvp_time64_t ti = ts->high;
ti <<= 32;
ti += ts->low & 0xffffffff;
return ti;
}
double vpip_time_to_scaled_real(vvp_time64_t ti, struct __vpiScope*scope)
{
double val;
int scale = 0;
if (scope) scale = vpi_time_precision - scope->time_units;
if (scale >= 0) val = (double)ti * pow(10.0, scale);
else val = (double)ti / pow(10.0, -scale);
return val;
}
/*
* This routine does not currently support negative real delays and it
* does not check for overflow. It is only used for modpath delays and
* they are required to be non-negative.
*/
vvp_time64_t vpip_scaled_real_to_time64(double val, struct __vpiScope*scope)
{
int shift = 0;
if (scope) shift = scope->time_units - scope->time_precision;
assert(shift >= 0);
assert(val >= 0);
// Scale to the local precision and then round away from zero.
double scale = pow(10.0L, shift);
val *= scale;
vvp_time64_t delay = (vvp_time64_t) (val + 0.5);
// If needed now scale the value to the simulator precision.
if (scope) {
shift = scope->time_precision - vpi_time_precision;
assert(shift >= 0);
for (int lp = 0; lp < shift; lp += 1) delay *= 10;
}
return delay;
}
static int timevar_time_get(int code, vpiHandle)
{
switch (code) {
case vpiSize:
return 64;
case vpiSigned:
return 0;
case vpiFuncType:
return vpiTimeFunc;
case vpiAutomatic:
return 0;
default:
fprintf(stderr, "Code: %d\n", code);
assert(0);
return 0;
}
}
static int timevar_stime_get(int code, vpiHandle ref)
{
switch (code) {
case vpiSize:
return 32;
default:
return timevar_time_get(code, ref);
}
}
static char* timevar_time_get_str(int code, vpiHandle)
{
switch (code) {
case vpiName:
return simple_set_rbuf_str("$time");
default:
fprintf(stderr, "Code: %d\n", code);
assert(0);
return 0;
}
}
static char* timevar_stime_get_str(int code, vpiHandle)
{
switch (code) {
case vpiName:
return simple_set_rbuf_str("$stime");
default:
fprintf(stderr, "Code: %d\n", code);
assert(0);
return 0;
}
}
static char* timevar_simtime_get_str(int code, vpiHandle)
Implement the swrite* and sformat system tasks plus a few other fixes. This patch implements the swrite* and sformat system tasks. It also makes $simtime distinguishable from the other integer time tasks. This was needed to get the correct time units when $simtime was given as an argument to $swrite*. The string constant code was also modified to allow a string to be returned as a vector (0/1 bit pattern). Here are some more specifics about the swrite* changes. 1. They do not share formatting code with the other display functions, so they may/will produce different results. 2. All %{alpha} codes allow a width and justification. Others have been enhanced (%t allows the default width and precision to be overridden, time functions print with time formatting, better error checking and messages, etc.). 3. %u and %z formatting codes have been added. It is important to note that these two formats can produce embedded NULLs, since these functions are returning a string anything after the first NULL will not be reachable! memcpy is used instead of regular string processing where needed so that the original string will contain the total result. The size returned when the string is created is the true length. A warning will be printed if a string with embedded NULLs is produced (strlen() does not match the true length). 4. Real numbers are printed with %g instead of %f. Once this new formatting code has been evaluated we should incorporate the changes/fixes into the formatting code for the other functions or the other functions could be modified to use this new code. The true string length is available so we should be able to work around the embedded NULL problem.
2007-08-14 00:56:02 +02:00
{
switch (code) {
case vpiName:
return simple_set_rbuf_str("$simtime");
Implement the swrite* and sformat system tasks plus a few other fixes. This patch implements the swrite* and sformat system tasks. It also makes $simtime distinguishable from the other integer time tasks. This was needed to get the correct time units when $simtime was given as an argument to $swrite*. The string constant code was also modified to allow a string to be returned as a vector (0/1 bit pattern). Here are some more specifics about the swrite* changes. 1. They do not share formatting code with the other display functions, so they may/will produce different results. 2. All %{alpha} codes allow a width and justification. Others have been enhanced (%t allows the default width and precision to be overridden, time functions print with time formatting, better error checking and messages, etc.). 3. %u and %z formatting codes have been added. It is important to note that these two formats can produce embedded NULLs, since these functions are returning a string anything after the first NULL will not be reachable! memcpy is used instead of regular string processing where needed so that the original string will contain the total result. The size returned when the string is created is the true length. A warning will be printed if a string with embedded NULLs is produced (strlen() does not match the true length). 4. Real numbers are printed with %g instead of %f. Once this new formatting code has been evaluated we should incorporate the changes/fixes into the formatting code for the other functions or the other functions could be modified to use this new code. The true string length is available so we should be able to work around the embedded NULL problem.
2007-08-14 00:56:02 +02:00
default:
fprintf(stderr, "Code: %d\n", code);
assert(0);
return 0;
}
}
static char* timevar_realtime_get_str(int code, vpiHandle)
{
switch (code) {
case vpiName:
return simple_set_rbuf_str("$realtime");
default:
fprintf(stderr, "Code: %d\n", code);
assert(0);
return 0;
}
}
static int timevar_realtime_get(int code, vpiHandle)
{
switch (code) {
case vpiSize:
return 1;
case vpiSigned:
return 0;
case vpiFuncType:
return vpiRealFunc;
case vpiAutomatic:
return 0;
default:
fprintf(stderr, "Code: %d\n", code);
assert(0);
return 0;
}
}
static vpiHandle timevar_handle(int code, vpiHandle ref)
{
struct __vpiSystemTime*rfp = dynamic_cast<__vpiSystemTime*>(ref);
switch (code) {
case vpiScope:
return rfp->scope;
default:
return 0;
}
}
static void timevar_get_value(vpiHandle ref, s_vpi_value*vp, bool is_int_func,
bool is_stime)
{
/* Keep a persistent structure for passing time values back to
the caller. */
static struct t_vpi_time time_value;
struct __vpiSystemTime*rfp = dynamic_cast<__vpiSystemTime*>(ref);
2003-03-13 21:31:40 +01:00
unsigned long num_bits;
vvp_time64_t x, simtime = schedule_simtime();
2003-02-03 02:09:20 +01:00
int units = rfp->scope? rfp->scope->time_units : vpi_time_precision;
2003-03-13 05:59:21 +01:00
char*rbuf = need_result_buf(128, RBUF_VAL);
/* Calculate the divisor needed to scale the simulation time
(in time_precision units) to time units of the scope. */
vvp_time64_t divisor = 1;
while (units > vpi_time_precision) {
divisor *= 10;
units -= 1;
}
/* Scale the simtime, and use the modulus to round up if
appropriate. */
vvp_time64_t simtime_fraction = simtime % divisor;
simtime /= divisor;
if ((divisor >= 10) && (simtime_fraction >= (divisor/2)))
simtime += 1;
/* If this is a call to $stime only return the lower 32 bits. */
if (is_stime) simtime &= 0xffffffff;
switch (vp->format) {
case vpiObjTypeVal:
2003-03-14 19:01:00 +01:00
/* The default format is vpiTimeVal. */
vp->format = vpiTimeVal;
case vpiTimeVal:
vp->value.time = &time_value;
vp->value.time->type = vpiSimTime;
vpip_time_to_timestruct(vp->value.time, simtime);
break;
case vpiRealVal:
/* If this is an integer based call (anything but $realtime)
* just return the value as a double. */
if (is_int_func) vp->value.real = double (simtime);
/* This is a call to $realtime to return a real value so
* scale this using the scaled real rules. */
else vp->value.real = vpip_time_to_scaled_real(schedule_simtime(),
rfp->scope);
break;
case vpiBinStrVal:
x = simtime;
2003-03-13 21:31:40 +01:00
num_bits = 8 * sizeof(vvp_time64_t);
2003-03-13 05:59:21 +01:00
rbuf[num_bits] = 0;
2001-10-15 04:55:03 +02:00
for (unsigned i = 1; i <= num_bits; i++) {
2003-03-13 05:59:21 +01:00
rbuf[num_bits-i] = x & 1 ? '1' : '0';
x = x >> 1;
}
2003-03-13 05:59:21 +01:00
vp->value.str = rbuf;
break;
case vpiDecStrVal:
sprintf(rbuf, "%" TIME_FMT_U, simtime);
2003-03-13 05:59:21 +01:00
vp->value.str = rbuf;
break;
case vpiOctStrVal:
sprintf(rbuf, "%" TIME_FMT_O, simtime);
2003-03-13 05:59:21 +01:00
vp->value.str = rbuf;
break;
case vpiHexStrVal:
sprintf(rbuf, "%" TIME_FMT_X, simtime);
2003-03-13 05:59:21 +01:00
vp->value.str = rbuf;
break;
default:
fprintf(stderr, "vpi_time: unknown format: %d\n", (int)vp->format);
assert(0);
}
}
static void timevar_get_ivalue(vpiHandle ref, s_vpi_value*vp)
{
timevar_get_value(ref, vp, true, false);
}
static void timevar_get_svalue(vpiHandle ref, s_vpi_value*vp)
{
timevar_get_value(ref, vp, true, true);
}
static void timevar_get_rvalue(vpiHandle ref, s_vpi_value*vp)
{
timevar_get_value(ref, vp, false, false);
}
static const struct __vpirt vpip_system_time_rt = {
vpiSysFuncCall,
0,
0, //timevar_time_get_str,
0, //timevar_get_ivalue,
0,
0, //Inherit from __vpiSystemTime: timevar_handle,
0,
0,
0,
0,
0
};
__vpiScopedTime::__vpiScopedTime()
: __vpiSystemTime(&vpip_system_time_rt)
{
}
int __vpiScopedTime::vpi_get(int code)
{ return timevar_time_get(code, this); }
char* __vpiScopedTime::vpi_get_str(int code)
{ return timevar_time_get_str(code, this); }
void __vpiScopedTime::vpi_get_value(p_vpi_value val)
{ timevar_get_ivalue(this, val); }
static const struct __vpirt vpip_system_stime_rt = {
vpiSysFuncCall,
0,
0,
0, //timevar_get_svalue,
0,
0, //Inherit from __vpiSystemTime: timevar_handle,
0,
0,
0,
0,
0
};
__vpiScopedSTime::__vpiScopedSTime()
: __vpiSystemTime(&vpip_system_stime_rt)
{
}
int __vpiScopedSTime::vpi_get(int code)
{ return timevar_stime_get(code, this); }
char* __vpiScopedSTime::vpi_get_str(int code)
{ return timevar_stime_get_str(code, this); }
void __vpiScopedSTime::vpi_get_value(p_vpi_value val)
{ timevar_get_svalue(this, val); }
Implement the swrite* and sformat system tasks plus a few other fixes. This patch implements the swrite* and sformat system tasks. It also makes $simtime distinguishable from the other integer time tasks. This was needed to get the correct time units when $simtime was given as an argument to $swrite*. The string constant code was also modified to allow a string to be returned as a vector (0/1 bit pattern). Here are some more specifics about the swrite* changes. 1. They do not share formatting code with the other display functions, so they may/will produce different results. 2. All %{alpha} codes allow a width and justification. Others have been enhanced (%t allows the default width and precision to be overridden, time functions print with time formatting, better error checking and messages, etc.). 3. %u and %z formatting codes have been added. It is important to note that these two formats can produce embedded NULLs, since these functions are returning a string anything after the first NULL will not be reachable! memcpy is used instead of regular string processing where needed so that the original string will contain the total result. The size returned when the string is created is the true length. A warning will be printed if a string with embedded NULLs is produced (strlen() does not match the true length). 4. Real numbers are printed with %g instead of %f. Once this new formatting code has been evaluated we should incorporate the changes/fixes into the formatting code for the other functions or the other functions could be modified to use this new code. The true string length is available so we should be able to work around the embedded NULL problem.
2007-08-14 00:56:02 +02:00
static const struct __vpirt vpip_system_simtime_rt = {
vpiSysFuncCall,
0,
0,
0, //timevar_get_ivalue,
0,
0, //timevar_handle,
0,
0,
0,
0,
Implement the swrite* and sformat system tasks plus a few other fixes. This patch implements the swrite* and sformat system tasks. It also makes $simtime distinguishable from the other integer time tasks. This was needed to get the correct time units when $simtime was given as an argument to $swrite*. The string constant code was also modified to allow a string to be returned as a vector (0/1 bit pattern). Here are some more specifics about the swrite* changes. 1. They do not share formatting code with the other display functions, so they may/will produce different results. 2. All %{alpha} codes allow a width and justification. Others have been enhanced (%t allows the default width and precision to be overridden, time functions print with time formatting, better error checking and messages, etc.). 3. %u and %z formatting codes have been added. It is important to note that these two formats can produce embedded NULLs, since these functions are returning a string anything after the first NULL will not be reachable! memcpy is used instead of regular string processing where needed so that the original string will contain the total result. The size returned when the string is created is the true length. A warning will be printed if a string with embedded NULLs is produced (strlen() does not match the true length). 4. Real numbers are printed with %g instead of %f. Once this new formatting code has been evaluated we should incorporate the changes/fixes into the formatting code for the other functions or the other functions could be modified to use this new code. The true string length is available so we should be able to work around the embedded NULL problem.
2007-08-14 00:56:02 +02:00
0
};
__vpiSystemTime::__vpiSystemTime()
: __vpiHandle(&vpip_system_simtime_rt)
{
scope = 0;
}
Implement the swrite* and sformat system tasks plus a few other fixes. This patch implements the swrite* and sformat system tasks. It also makes $simtime distinguishable from the other integer time tasks. This was needed to get the correct time units when $simtime was given as an argument to $swrite*. The string constant code was also modified to allow a string to be returned as a vector (0/1 bit pattern). Here are some more specifics about the swrite* changes. 1. They do not share formatting code with the other display functions, so they may/will produce different results. 2. All %{alpha} codes allow a width and justification. Others have been enhanced (%t allows the default width and precision to be overridden, time functions print with time formatting, better error checking and messages, etc.). 3. %u and %z formatting codes have been added. It is important to note that these two formats can produce embedded NULLs, since these functions are returning a string anything after the first NULL will not be reachable! memcpy is used instead of regular string processing where needed so that the original string will contain the total result. The size returned when the string is created is the true length. A warning will be printed if a string with embedded NULLs is produced (strlen() does not match the true length). 4. Real numbers are printed with %g instead of %f. Once this new formatting code has been evaluated we should incorporate the changes/fixes into the formatting code for the other functions or the other functions could be modified to use this new code. The true string length is available so we should be able to work around the embedded NULL problem.
2007-08-14 00:56:02 +02:00
int __vpiSystemTime::get_type_code(void) const
{ return vpiSysFuncCall; }
int __vpiSystemTime::vpi_get(int code)
{ return timevar_time_get(code, this); }
char* __vpiSystemTime::vpi_get_str(int code)
{ return timevar_simtime_get_str(code, this); }
void __vpiSystemTime::vpi_get_value(p_vpi_value val)
{ timevar_get_ivalue(this, val); }
vpiHandle __vpiSystemTime::vpi_put_value(p_vpi_value, int)
{ return 0; }
vpiHandle __vpiSystemTime::vpi_handle(int code)
{ return timevar_handle(code, this); }
vpiHandle __vpiSystemTime::vpi_iterate(int)
{ return 0; }
vpiHandle __vpiSystemTime::vpi_index(int)
{ return 0; }
void __vpiSystemTime::vpi_get_delays(p_vpi_delay)
{ }
void __vpiSystemTime::vpi_put_delays(p_vpi_delay)
{ }
static const struct __vpirt vpip_system_realtime_rt = {
vpiSysFuncCall,
0,
0,
0, //timevar_get_rvalue,
0,
0, //Inherit from __vpiSystemTime: timevar_handle,
0,
0,
0,
0,
0
};
__vpiScopedRealtime::__vpiScopedRealtime()
: __vpiSystemTime(&vpip_system_realtime_rt)
{
}
int __vpiScopedRealtime::vpi_get(int code)
{ return timevar_realtime_get(code, this); }
char* __vpiScopedRealtime::vpi_get_str(int code)
{ return timevar_realtime_get_str(code, this); }
void __vpiScopedRealtime::vpi_get_value(p_vpi_value val)
{ timevar_get_rvalue(this, val); }
2003-02-03 02:09:20 +01:00
/*
* Create a handle to represent a call to $time/$stime/$simtime. The
* $time and $stime system functions return a value scaled to a scope,
* and the $simtime returns the unscaled time.
*/
vpiHandle vpip_sim_time(struct __vpiScope*scope, bool is_stime)
{
2003-02-03 02:09:20 +01:00
if (scope) {
if (is_stime) {
scope->scoped_stime.scope = scope;
return &scope->scoped_stime;
} else {
scope->scoped_time.scope = scope;
return &scope->scoped_time;
}
2003-02-03 02:09:20 +01:00
} else {
return &global_simtime;
2003-02-03 02:09:20 +01:00
}
}
vpiHandle vpip_sim_realtime(struct __vpiScope*scope)
{
scope->scoped_realtime.scope = scope;
return &scope->scoped_realtime;
}
int vpip_get_time_precision(void)
{
return vpi_time_precision;
}
void vpip_set_time_precision(int pre)
{
vpi_time_precision = pre;
}