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:
parent
937397b24c
commit
64936d07e5
|
|
@ -107,23 +107,71 @@ unsigned long get_number_immediate(ivl_expr_t ex)
|
||||||
return imm;
|
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
|
* This function, in addition to setting the value into index 0, sets
|
||||||
* bit 4 to 1 if the value is unknown.
|
* bit 4 to 1 if the value is unknown.
|
||||||
*/
|
*/
|
||||||
void draw_eval_expr_into_integer(ivl_expr_t expr, unsigned ix)
|
void draw_eval_expr_into_integer(ivl_expr_t expr, unsigned ix)
|
||||||
{
|
{
|
||||||
struct vector_info vec;
|
|
||||||
int word;
|
int word;
|
||||||
|
|
||||||
switch (ivl_expr_value(expr)) {
|
switch (ivl_expr_value(expr)) {
|
||||||
|
|
||||||
case IVL_VT_BOOL:
|
case IVL_VT_BOOL:
|
||||||
case IVL_VT_LOGIC:
|
case IVL_VT_LOGIC:
|
||||||
vec = draw_eval_expr(expr, 0);
|
eval_logic_into_integer(expr, ix);
|
||||||
fprintf(vvp_out, " %%ix/get %u, %u, %u;\n",
|
|
||||||
ix, vec.base, vec.wid);
|
|
||||||
clr_vector(vec);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IVL_VT_REAL:
|
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
|
/* Figure out the shift amount and load that into the index
|
||||||
register. The value may be a constant, or may need to be
|
register. The value may be a constant, or may need to be
|
||||||
evaluated at run time. */
|
evaluated at run time. */
|
||||||
switch (ivl_expr_type(re)) {
|
eval_logic_into_integer(re,0);
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fprintf(vvp_out, " %s/i0 %u, %u;\n", opcode, lv.base, lv.wid);
|
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);
|
use_word = get_number_immediate(ix);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
shiv = draw_eval_expr(bit_idx, STUFF_OK_XZ|STUFF_OK_RO);
|
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);
|
fprintf(vvp_out, " %%ix/get 0, %u, %u;\n", shiv.base, shiv.wid);
|
||||||
if (shiv.base >= 8)
|
if (shiv.base >= 8)
|
||||||
clr_vector(shiv);
|
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
|
/* Try the special case that the base is 0 and the width
|
||||||
exactly matches the signal. Just load the signal in one
|
exactly matches the signal. Just load the signal in one
|
||||||
|
|
|
||||||
|
|
@ -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_INV(vthread_t thr, vvp_code_t code);
|
||||||
extern bool of_IX_ADD(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_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_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_LOAD(vthread_t thr, vvp_code_t code);
|
||||||
extern bool of_IX_MUL(vthread_t thr, vvp_code_t code);
|
extern bool of_IX_MUL(vthread_t thr, vvp_code_t code);
|
||||||
|
|
|
||||||
|
|
@ -127,6 +127,7 @@ const static struct opcode_table_s opcode_table[] = {
|
||||||
{ "%inv", of_INV, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
|
{ "%inv", of_INV, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
|
||||||
{ "%ix/add", of_IX_ADD, 2, {OA_BIT1, OA_NUMBER, 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/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/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/load",of_IX_LOAD,2, {OA_BIT1, OA_NUMBER, OA_NONE} },
|
||||||
{ "%ix/mul", of_IX_MUL, 2, {OA_BIT1, OA_NUMBER, OA_NONE} },
|
{ "%ix/mul", of_IX_MUL, 2, {OA_BIT1, OA_NUMBER, OA_NONE} },
|
||||||
|
|
|
||||||
|
|
@ -333,6 +333,11 @@ bits.
|
||||||
5: (reserved)
|
5: (reserved)
|
||||||
6: (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>
|
* %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
|
thread bit <bit>. It is an error for the width to not match the vector
|
||||||
width at the functor.
|
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>
|
* %load/wr <bit>, <vpi-label>
|
||||||
|
|
||||||
This instruction reads a real value from the vpi-like object to a word
|
This instruction reads a real value from the vpi-like object to a word
|
||||||
|
|
|
||||||
|
|
@ -1947,6 +1947,32 @@ bool of_IX_GET_S(vthread_t thr, vvp_code_t cp)
|
||||||
return true;
|
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
|
* The various JMP instruction work simply by pulling the new program
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue