Finish $clog2 function.

This patch fixes problems in the initial $clog2 implementation
and adds correct functionality to the runtime.
This commit is contained in:
Cary R 2008-08-15 19:28:11 -07:00 committed by Stephen Williams
parent c032d28aaa
commit 5e512e6570
7 changed files with 113 additions and 35 deletions

View File

@ -1621,6 +1621,15 @@ NetExpr* evaluate_clog2(NetExpr*arg)
} else { } else {
arg = verinum(tmpr->value().as_double(), true); arg = verinum(tmpr->value().as_double(), true);
} }
/* If we have an x in the verinum we return 32'bx. */
if (!arg.is_defined()) {
verinum tmp (verinum::Vx, 32);
tmp.has_sign(true);
NetEConst*rtn = new NetEConst(tmp);
return rtn;
}
uint64_t res = 0; uint64_t res = 0;
if (arg.is_negative()) is_neg = true; if (arg.is_negative()) is_neg = true;
arg.has_sign(false); // $unsigned() arg.has_sign(false); // $unsigned()
@ -1632,7 +1641,9 @@ NetExpr* evaluate_clog2(NetExpr*arg)
} }
} }
if (is_neg && res < 32) res = 32; if (is_neg && res < 32) res = 32;
NetEConst*rtn = new NetEConst(verinum(res, 32)); verinum tmp (res, 32);
tmp.has_sign(true);
NetEConst*rtn = new NetEConst(tmp);
return rtn; return rtn;
} }

View File

@ -76,31 +76,18 @@ static PLI_INT32 sys_clog2_calltf(PLI_BYTE8 *name)
vpiHandle argv = vpi_iterate(vpiArgument, callh); vpiHandle argv = vpi_iterate(vpiArgument, callh);
vpiHandle arg; vpiHandle arg;
s_vpi_value val; s_vpi_value val;
s_vpi_vecval vec;
(void) name; // Not used!/ (void) name; // Not used!/
/* Get the argument. */ /* Get the argument. */
arg = vpi_scan(argv); arg = vpi_scan(argv);
val.format = vpiRealVal;
vpi_get_value(arg, &val);
vpi_free_object(argv); vpi_free_object(argv);
/* For now we don't support a negative value! */ vec = vpip_calc_clog2(arg);
if (val.value.real < 0.0) {
vpi_printf("SORRY: %s line %d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("$clog2 does not currently support negative values.\n");
vpi_control(vpiFinish, 1);
return 0;
}
/* Return the value to the system. */ val.format = vpiVectorVal;
val.format = vpiIntVal; val.value.vector = &vec;
if (val.value.real == 0.0)
val.value.integer = 0;
else
val.value.integer = ceil(log(floor(val.value.real+0.5))/M_LN2);
vpi_put_value(callh, &val, 0, vpiNoDelay); vpi_put_value(callh, &val, 0, vpiNoDelay);
return 0; return 0;
} }

View File

@ -566,6 +566,7 @@ extern DLLEXPORT void (*vlog_startup_routines[])();
buffer. The value must be a vpiStrengthVal. */ buffer. The value must be a vpiStrengthVal. */
extern void vpip_format_strength(char*str, s_vpi_value*value, unsigned bit); extern void vpip_format_strength(char*str, s_vpi_value*value, unsigned bit);
extern void vpip_set_return_value(int value); extern void vpip_set_return_value(int value);
extern s_vpi_vecval vpip_calc_clog2(vpiHandle arg);
EXTERN_C_END EXTERN_C_END

View File

@ -456,6 +456,10 @@ void vpip_vec4_get_value(const vvp_vector4_t&word_val, unsigned width,
vp->format); vp->format);
assert(0 && "format not implemented"); assert(0 && "format not implemented");
case vpiObjTypeVal:
vp->format = vpiVectorVal;
break;
case vpiSuppressVal: case vpiSuppressVal:
break; break;
@ -1033,3 +1037,63 @@ extern "C" void vpi_control(PLI_INT32 operation, ...)
vpi_sim_vcontrol(operation, ap); vpi_sim_vcontrol(operation, ap);
va_end(ap); va_end(ap);
} }
/*
* This routine calculated the return value for $clog2.
* It is easier to do it here vs trying to to use the VPI interface.
*/
extern "C" s_vpi_vecval vpip_calc_clog2(vpiHandle arg)
{
s_vpi_vecval rtn;
s_vpi_value val;
vvp_vector4_t vec4;
bool is_neg = false; // At this point only a real can be negative.
/* Get the value as a vvp_vector4_t. */
val.format = vpiObjTypeVal;
vpi_get_value(arg, &val);
if (val.format == vpiRealVal) {
vpi_get_value(arg, &val);
/* All double values can be represented in 1024 bits. */
vec4 = vvp_vector4_t(1024, val.value.real);
if (val.value.real < 0) is_neg = true;
} else {
val.format = vpiVectorVal;
vpi_get_value(arg, &val);
unsigned wid = vpi_get(vpiSize, arg);
vec4 = vvp_vector4_t(wid, BIT4_0);
for (unsigned idx=0; idx < wid; idx += 1) {
PLI_INT32 aval = val.value.vector[idx/32].aval;
PLI_INT32 bval = val.value.vector[idx/32].bval;
aval >>= idx % 32;
bval >>= idx % 32;
int bitmask = (aval&1) | ((bval<<1)&2);
vvp_bit4_t bit = scalar_to_bit4(bitmask);
vec4.set_bit(idx, bit);
}
}
if (vec4.has_xz()) {
rtn.aval = rtn.bval = 0xFFFFFFFFU; /* Set to 'bx. */
return rtn;
}
vvp_vector2_t vec2(vec4);
if (is_neg) vec2.trim_neg(); /* This is a special trim! */
else vec2.trim(); /* This makes less work shifting. */
/* Calculate the clog2 result. */
PLI_INT32 res = 0;
if (!vec2.is_zero()) {
vec2 -= vvp_vector2_t(1, vec2.size());
while(!vec2.is_zero()) {
res += 1;
vec2 >>= 1;
}
}
rtn.aval = res;
rtn.bval = 0;
return rtn;
}

View File

@ -728,23 +728,6 @@ static vvp_vector4_t from_stringval(const char*str, unsigned wid)
return val; return val;
} }
static vvp_bit4_t scalar_to_bit4(PLI_INT32 scalar)
{
switch(scalar) {
case vpi0:
return BIT4_0;
case vpi1:
return BIT4_1;
case vpiX:
return BIT4_X;
case vpiZ:
return BIT4_Z;
default:
fprintf(stderr, "Unsupported scalar value %d.\n", scalar);
assert(0);
}
}
static vpiHandle signal_put_value(vpiHandle ref, s_vpi_value*vp, int flags) static vpiHandle signal_put_value(vpiHandle ref, s_vpi_value*vp, int flags)
{ {
unsigned wid; unsigned wid;

View File

@ -130,6 +130,23 @@ vvp_bit4_t add_with_carry(vvp_bit4_t a, vvp_bit4_t b, vvp_bit4_t&c)
} }
} }
vvp_bit4_t scalar_to_bit4(PLI_INT32 scalar)
{
switch(scalar) {
case vpi0:
return BIT4_0;
case vpi1:
return BIT4_1;
case vpiX:
return BIT4_X;
case vpiZ:
return BIT4_Z;
default:
fprintf(stderr, "Unsupported scalar value %d.\n", scalar);
assert(0);
}
}
vvp_bit4_t operator ^ (vvp_bit4_t a, vvp_bit4_t b) vvp_bit4_t operator ^ (vvp_bit4_t a, vvp_bit4_t b)
{ {
if (bit4_is_xz(a)) if (bit4_is_xz(a))
@ -1611,6 +1628,15 @@ void vvp_vector2_t::trim()
while (value(wid_-1) == 0 && wid_ > 1) wid_ -= 1; while (value(wid_-1) == 0 && wid_ > 1) wid_ -= 1;
} }
/* This is a special trim that is used on numbers we know represent a
* negative signed value (they came from a negative real value). */
void vvp_vector2_t::trim_neg()
{
if (value(wid_-1) == 1 && wid_ > 32) {
while (value(wid_-2) == 1 && wid_ > 32) wid_ -= 1;
}
}
int vvp_vector2_t::value(unsigned idx) const int vvp_vector2_t::value(unsigned idx) const
{ {
if (idx >= wid_) if (idx >= wid_)

View File

@ -20,6 +20,7 @@
*/ */
# include "config.h" # include "config.h"
# include "vpi_user.h"
# include <stddef.h> # include <stddef.h>
# include <string.h> # include <string.h>
# include <new> # include <new>
@ -67,6 +68,8 @@ inline char vvp_bit4_to_ascii(vvp_bit4_t a) { return "01zx"[a]; }
extern vvp_bit4_t add_with_carry(vvp_bit4_t a, vvp_bit4_t b, vvp_bit4_t&c); extern vvp_bit4_t add_with_carry(vvp_bit4_t a, vvp_bit4_t b, vvp_bit4_t&c);
extern vvp_bit4_t scalar_to_bit4(PLI_INT32 scalar);
/* Return TRUE if the bit is BIT4_X or BIT4_Z. The fast /* Return TRUE if the bit is BIT4_X or BIT4_Z. The fast
implementation here relies on the encoding of vvp_bit4_t values. */ implementation here relies on the encoding of vvp_bit4_t values. */
inline bool bit4_is_xz(vvp_bit4_t a) { return a >= 2; } inline bool bit4_is_xz(vvp_bit4_t a) { return a >= 2; }
@ -470,6 +473,9 @@ class vvp_vector2_t {
void set_bit(unsigned idx, int bit); void set_bit(unsigned idx, int bit);
// Make the size just big enough to hold the first 1 bit. // Make the size just big enough to hold the first 1 bit.
void trim(); void trim();
// Trim off extra 1 bit since this is representing a negative value.
// Always keep at least 32 bits.
void trim_neg();
private: private:
enum { BITS_PER_WORD = 8 * sizeof(unsigned long) }; enum { BITS_PER_WORD = 8 * sizeof(unsigned long) };