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;
|
||||
}
|
||||
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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} },
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue