Add %ix/getv instruction

The %ix/getv instruction loads an integer register directly from
a signal vector. This is an optimization that an index register
is loaded from an expression is only a signal. It avoids the thread
vector space.
This commit is contained in:
Stephen Williams 2007-12-07 13:12:19 -08:00
parent 937397b24c
commit 64936d07e5
5 changed files with 98 additions and 43 deletions

View File

@ -107,23 +107,71 @@ unsigned long get_number_immediate(ivl_expr_t ex)
return imm;
}
static void eval_logic_into_integer(ivl_expr_t expr, unsigned ix)
{
switch (ivl_expr_type(expr)) {
case IVL_EX_NUMBER: {
unsigned value = 0;
unsigned idx, nbits = ivl_expr_width(expr);
const char*bits = ivl_expr_bits(expr);
for (idx = 0 ; idx < nbits ; idx += 1) switch (bits[idx]) {
case '0':
break;
case '1':
assert(idx < (8*sizeof value));
value |= 1 << idx;
break;
default:
assert(0);
}
fprintf(vvp_out, " %%ix/load %u, %u;\n", ix, value);
break;
}
case IVL_EX_ULONG:
fprintf(vvp_out, " %%ix/load %u, %lu;\n", ix, ivl_expr_uvalue(expr));
break;
case IVL_EX_SIGNAL: {
ivl_signal_t sig = ivl_expr_signal(expr);
unsigned word = 0;
if (ivl_signal_array_count(sig) > 1) {
ivl_expr_t ixe = ivl_expr_oper1(expr);
assert(number_is_immediate(ixe, 8*sizeof(unsigned long)));
word = get_number_immediate(ixe);
}
fprintf(vvp_out, " %%ix/getv %u, v%p_%u;\n", ix, sig, word);
break;
}
default: {
struct vector_info rv;
rv = draw_eval_expr(expr, 0);
fprintf(vvp_out, " %%ix/get %u, %u, %u;\n",
ix, rv.base, rv.wid);
clr_vector(rv);
break;
}
}
}
/*
* This function, in addition to setting the value into index 0, sets
* bit 4 to 1 if the value is unknown.
*/
void draw_eval_expr_into_integer(ivl_expr_t expr, unsigned ix)
{
struct vector_info vec;
int word;
switch (ivl_expr_value(expr)) {
case IVL_VT_BOOL:
case IVL_VT_LOGIC:
vec = draw_eval_expr(expr, 0);
fprintf(vvp_out, " %%ix/get %u, %u, %u;\n",
ix, vec.base, vec.wid);
clr_vector(vec);
eval_logic_into_integer(expr, ix);
break;
case IVL_VT_REAL:
@ -954,43 +1002,7 @@ static struct vector_info draw_binary_expr_lrs(ivl_expr_t exp, unsigned wid)
/* Figure out the shift amount and load that into the index
register. The value may be a constant, or may need to be
evaluated at run time. */
switch (ivl_expr_type(re)) {
case IVL_EX_NUMBER: {
unsigned shift = 0;
unsigned idx, nbits = ivl_expr_width(re);
const char*bits = ivl_expr_bits(re);
for (idx = 0 ; idx < nbits ; idx += 1) switch (bits[idx]) {
case '0':
break;
case '1':
assert(idx < (8*sizeof shift));
shift |= 1 << idx;
break;
default:
assert(0);
}
fprintf(vvp_out, " %%ix/load 0, %u;\n", shift);
break;
}
case IVL_EX_ULONG:
fprintf(vvp_out, " %%ix/load 0, %lu;\n", ivl_expr_uvalue(re));
break;
default: {
struct vector_info rv;
rv = draw_eval_expr(re, 0);
fprintf(vvp_out, " %%ix/get 0, %u, %u;\n",
rv.base, rv.wid);
clr_vector(rv);
break;
}
}
eval_logic_into_integer(re,0);
fprintf(vvp_out, " %s/i0 %u, %u;\n", opcode, lv.base, lv.wid);
@ -1850,11 +1862,14 @@ static struct vector_info draw_select_signal(ivl_expr_t sube,
use_word = get_number_immediate(ix);
}
#if 0
shiv = draw_eval_expr(bit_idx, STUFF_OK_XZ|STUFF_OK_RO);
fprintf(vvp_out, " %%ix/get 0, %u, %u;\n", shiv.base, shiv.wid);
if (shiv.base >= 8)
clr_vector(shiv);
#else
draw_eval_expr_into_integer(bit_idx, 0);
#endif
/* Try the special case that the base is 0 and the width
exactly matches the signal. Just load the signal in one

View File

@ -81,6 +81,7 @@ extern bool of_FORK(vthread_t thr, vvp_code_t code);
extern bool of_INV(vthread_t thr, vvp_code_t code);
extern bool of_IX_ADD(vthread_t thr, vvp_code_t code);
extern bool of_IX_GET(vthread_t thr, vvp_code_t code);
extern bool of_IX_GETV(vthread_t thr, vvp_code_t code);
extern bool of_IX_GET_S(vthread_t thr, vvp_code_t code);
extern bool of_IX_LOAD(vthread_t thr, vvp_code_t code);
extern bool of_IX_MUL(vthread_t thr, vvp_code_t code);

View File

@ -127,6 +127,7 @@ const static struct opcode_table_s opcode_table[] = {
{ "%inv", of_INV, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
{ "%ix/add", of_IX_ADD, 2, {OA_BIT1, OA_NUMBER, OA_NONE} },
{ "%ix/get", of_IX_GET, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%ix/getv",of_IX_GETV,2, {OA_BIT1, OA_FUNC_PTR, OA_NONE} },
{ "%ix/get/s",of_IX_GET_S,3,{OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%ix/load",of_IX_LOAD,2, {OA_BIT1, OA_NUMBER, OA_NONE} },
{ "%ix/mul", of_IX_MUL, 2, {OA_BIT1, OA_NUMBER, OA_NONE} },

View File

@ -333,6 +333,11 @@ bits.
5: (reserved)
6: (reserved)
* %ix/getv <functor-label>, <bit>
This instruction is like the %ix/get instruction, except that is reads
directly from a functor label instead of from thread bits. It sets
bits 4/5/6 just line %ix/get.
* %ix/load <idx>, <value>
@ -416,6 +421,13 @@ from the least significant up to <wid> bits, is loaded starting at
thread bit <bit>. It is an error for the width to not match the vector
width at the functor.
* %load/vp0 <bit>, <functor-label>, <wid>
This instruction is the same as %load/v above, except that it also
adds the integer value is index register 0 into the loaded value. The
addition is a verilog-style add, which means that if any of the input
bits are X or Z, the entire result is turned into a vector of X bits.
* %load/wr <bit>, <vpi-label>
This instruction reads a real value from the vpi-like object to a word

View File

@ -1947,6 +1947,32 @@ bool of_IX_GET_S(vthread_t thr, vvp_code_t cp)
return true;
}
bool of_IX_GETV(vthread_t thr, vvp_code_t cp)
{
unsigned index = cp->bit_idx[0];
vvp_net_t*net = cp->net;
vvp_fun_signal_vec*sig = dynamic_cast<vvp_fun_signal_vec*>(net->fun);
if (sig == 0) {
cerr << "%%ix/getv error: Net arg not a vector signal? "
<< typeid(*net->fun).name() << endl;
}
assert(sig);
vvp_vector4_t vec = sig->vec4_value();
unsigned long val;
bool known_flag = vector4_to_value(vec, val);
if (known_flag)
thr->words[index].w_int = val;
else
thr->words[index].w_int = 0;
/* Set bit 4 as a flag if the input is unknown. */
thr_put_bit(thr, 4, known_flag? BIT4_0 : BIT4_1);
return true;
}
/*
* The various JMP instruction work simply by pulling the new program