Finish $clog2 function.
This patch fixes problems in the initial $clog2 implementation and adds correct functionality to the runtime.
This commit is contained in:
parent
c032d28aaa
commit
5e512e6570
13
eval_tree.cc
13
eval_tree.cc
|
|
@ -1621,6 +1621,15 @@ NetExpr* evaluate_clog2(NetExpr*arg)
|
|||
} else {
|
||||
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;
|
||||
if (arg.is_negative()) is_neg = true;
|
||||
arg.has_sign(false); // $unsigned()
|
||||
|
|
@ -1632,7 +1641,9 @@ NetExpr* evaluate_clog2(NetExpr*arg)
|
|||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -76,31 +76,18 @@ static PLI_INT32 sys_clog2_calltf(PLI_BYTE8 *name)
|
|||
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||
vpiHandle arg;
|
||||
s_vpi_value val;
|
||||
s_vpi_vecval vec;
|
||||
(void) name; // Not used!/
|
||||
|
||||
/* Get the argument. */
|
||||
arg = vpi_scan(argv);
|
||||
val.format = vpiRealVal;
|
||||
vpi_get_value(arg, &val);
|
||||
vpi_free_object(argv);
|
||||
|
||||
/* For now we don't support a negative value! */
|
||||
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;
|
||||
}
|
||||
vec = vpip_calc_clog2(arg);
|
||||
|
||||
/* Return the value to the system. */
|
||||
val.format = vpiIntVal;
|
||||
if (val.value.real == 0.0)
|
||||
val.value.integer = 0;
|
||||
else
|
||||
val.value.integer = ceil(log(floor(val.value.real+0.5))/M_LN2);
|
||||
val.format = vpiVectorVal;
|
||||
val.value.vector = &vec;
|
||||
vpi_put_value(callh, &val, 0, vpiNoDelay);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -566,6 +566,7 @@ extern DLLEXPORT void (*vlog_startup_routines[])();
|
|||
buffer. The value must be a vpiStrengthVal. */
|
||||
extern void vpip_format_strength(char*str, s_vpi_value*value, unsigned bit);
|
||||
extern void vpip_set_return_value(int value);
|
||||
extern s_vpi_vecval vpip_calc_clog2(vpiHandle arg);
|
||||
|
||||
EXTERN_C_END
|
||||
|
||||
|
|
|
|||
|
|
@ -456,6 +456,10 @@ void vpip_vec4_get_value(const vvp_vector4_t&word_val, unsigned width,
|
|||
vp->format);
|
||||
assert(0 && "format not implemented");
|
||||
|
||||
case vpiObjTypeVal:
|
||||
vp->format = vpiVectorVal;
|
||||
break;
|
||||
|
||||
case vpiSuppressVal:
|
||||
break;
|
||||
|
||||
|
|
@ -1033,3 +1037,63 @@ extern "C" void vpi_control(PLI_INT32 operation, ...)
|
|||
vpi_sim_vcontrol(operation, 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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -728,23 +728,6 @@ static vvp_vector4_t from_stringval(const char*str, unsigned wid)
|
|||
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)
|
||||
{
|
||||
unsigned wid;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
if (bit4_is_xz(a))
|
||||
|
|
@ -1611,6 +1628,15 @@ void vvp_vector2_t::trim()
|
|||
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
|
||||
{
|
||||
if (idx >= wid_)
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
*/
|
||||
|
||||
# include "config.h"
|
||||
# include "vpi_user.h"
|
||||
# include <stddef.h>
|
||||
# include <string.h>
|
||||
# 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 scalar_to_bit4(PLI_INT32 scalar);
|
||||
|
||||
/* Return TRUE if the bit is BIT4_X or BIT4_Z. The fast
|
||||
implementation here relies on the encoding of vvp_bit4_t values. */
|
||||
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);
|
||||
// Make the size just big enough to hold the first 1 bit.
|
||||
void trim();
|
||||
// Trim off extra 1 bit since this is representing a negative value.
|
||||
// Always keep at least 32 bits.
|
||||
void trim_neg();
|
||||
|
||||
private:
|
||||
enum { BITS_PER_WORD = 8 * sizeof(unsigned long) };
|
||||
|
|
|
|||
Loading…
Reference in New Issue