/* * Check to see if the real expression is of the form (expr) * <scale> */ static unsigned check_scaled_real_expr(ivl_expr_t expr, double scale) { double scale_val; if ((ivl_expr_type(expr) != IVL_EX_BINARY) || (ivl_expr_opcode(expr) != '*') || (ivl_expr_type(ivl_expr_oper2(expr)) != IVL_EX_REALNUM)) { fprintf(stderr, "%s:%u: vlog95 error: Variable real time unit " " expression/value cannot be scaled.\n ", ivl_expr_file(expr), ivl_expr_lineno(expr)); vlog_errors += 1; return 0; } scale_val = ivl_expr_dvalue(ivl_expr_oper2(expr)); if (scale != scale_val) { fprintf(stderr, "%s:%u: vlog95 error: Variable real time unit " "expression/value scale coefficient did not " "match expected value (%g != %g).\n", ivl_expr_file(expr), ivl_expr_lineno(expr), scale, scale_val); vlog_errors += 1; return 0; } /* Yes, this expression is of the correct form. */ return 1; }
// HERE: Probably need to pass in a msg string to make this work with // indexed part selects. static unsigned is_scaled_expr(ivl_expr_t expr, int msb, int lsb) { int64_t scale_val; int rtype; /* This is as easy as removing the addition/subtraction that was * added to scale the value to be zero based, but we need to verify * that the scaling value is correct first. */ if (msb > lsb) { if ((ivl_expr_type(expr) != IVL_EX_BINARY) || ((ivl_expr_opcode(expr) != '+') && (ivl_expr_opcode(expr) != '-')) || (ivl_expr_type(ivl_expr_oper2(expr)) != IVL_EX_NUMBER)) { fprintf(vlog_out, "<invalid>"); fprintf(stderr, "%s:%u: vlog95 error: Scaled " "expression value cannot be scaled.\n", ivl_expr_file(expr), ivl_expr_lineno(expr)); vlog_errors += 1; return 0; } scale_val = get_valid_int64_from_number( ivl_expr_oper2(expr), &rtype, "expression value scale coefficient"); } else { if ((ivl_expr_type(expr) != IVL_EX_BINARY) || ((ivl_expr_opcode(expr) != '+') && (ivl_expr_opcode(expr) != '-')) || (ivl_expr_type(ivl_expr_oper1(expr)) != IVL_EX_NUMBER)) { fprintf(vlog_out, "<invalid>"); fprintf(stderr, "%s:%u: vlog95 error: Scaled " "expression value cannot be scaled.\n", ivl_expr_file(expr), ivl_expr_lineno(expr)); vlog_errors += 1; return 0; } scale_val = get_valid_int64_from_number( ivl_expr_oper1(expr), &rtype, "expression value scale coefficient"); } if (rtype) return 0; if (ivl_expr_opcode(expr) == '+') scale_val *= -1; if (lsb != scale_val) { fprintf(vlog_out, "<invalid>"); fprintf(stderr, "%s:%u: vlog95 error: Scaled expression value " "scaling coefficient did not match expected " "value (%d != %"PRIu64").\n", ivl_expr_file(expr), ivl_expr_lineno(expr), lsb, scale_val); vlog_errors += 1; return 0; } return 1; }
static void draw_sfunc_vec4(ivl_expr_t expr) { unsigned parm_count = ivl_expr_parms(expr); /* Special case: If there are no arguments to print, then the %vpi_call statement is easy to draw. */ if (parm_count == 0) { assert(ivl_expr_value(expr)==IVL_VT_LOGIC || ivl_expr_value(expr)==IVL_VT_BOOL); fprintf(vvp_out, " %%vpi_func %u %u \"%s\" %u {0 0 0};\n", ivl_file_table_index(ivl_expr_file(expr)), ivl_expr_lineno(expr), ivl_expr_name(expr), ivl_expr_width(expr)); return; } if (strcmp(ivl_expr_name(expr), "$ivl_darray_method$pop_back")==0) { draw_darray_pop(expr); return; } if (strcmp(ivl_expr_name(expr),"$ivl_darray_method$pop_front")==0) { draw_darray_pop(expr); return; } draw_vpi_func_call(expr); }
/* * Check to see if the bit based expression is of the form (expr) * <scale> */ static unsigned check_scaled_expr(ivl_expr_t expr, uint64_t scale, const char *msg, unsigned must_match) { uint64_t scale_val; int rtype; if ((ivl_expr_type(expr) != IVL_EX_BINARY) || (ivl_expr_opcode(expr) != '*') || (ivl_expr_type(ivl_expr_oper2(expr)) != IVL_EX_NUMBER)) { fprintf(stderr, "%s:%u: vlog95 error: %s expression/value " "cannot be scaled.\n ", ivl_expr_file(expr), ivl_expr_lineno(expr), msg); vlog_errors += 1; return 0; } scale_val = get_uint64_from_number(ivl_expr_oper2(expr), &rtype); if (rtype > 0) { fprintf(stderr, "%s:%u: vlog95 error: %s expression/value " "scale coefficient was greater than 64 bits " "(%d).\n", ivl_expr_file(expr), ivl_expr_lineno(expr), msg, rtype); vlog_errors += 1; return 0; } if (rtype < 0) { fprintf(stderr, "%s:%u: vlog95 error: %s expression/value " "scale coefficient has an undefined bit.\n", ivl_expr_file(expr), ivl_expr_lineno(expr), msg); vlog_errors += 1; return 0; } if (scale != scale_val) { if (must_match) { fprintf(stderr, "%s:%u: vlog95 error: %s expression/value " "scale coefficient did not match expected " "value (%"PRIu64" != %"PRIu64").\n", ivl_expr_file(expr), ivl_expr_lineno(expr), msg, scale, scale_val); vlog_errors += 1; return 0; } return 2; } /* Yes, this expression is of the correct form. */ return 1; }
static int64_t get_valid_int64_from_number(ivl_expr_t expr, int *rtype, const char *msg) { int64_t value = get_int64_from_number(expr, rtype); if (*rtype > 0) { fprintf(vlog_out, "<invalid>"); fprintf(stderr, "%s:%u: vlog95 error: Scaled %s is greater than " "64 bits (%d) and cannot be safely represented.\n", ivl_expr_file(expr), ivl_expr_lineno(expr), msg, *rtype); vlog_errors += 1; return 0; } else if (*rtype < 0) { fprintf(vlog_out, "<invalid>"); fprintf(stderr, "%s:%u: vlog95 error: Scaled %s has an undefined " "bit and cannot be represented.\n", ivl_expr_file(expr), ivl_expr_lineno(expr), msg); vlog_errors += 1; return 0; } return value; }
int draw_vpi_rfunc_call(ivl_expr_t fnet) { char call_string[1024]; int res = allocate_word(); sprintf(call_string, " %%vpi_func/r %u %u \"%s\", %d", ivl_file_table_index(ivl_expr_file(fnet)), ivl_expr_lineno(fnet), ivl_expr_name(fnet), res); draw_vpi_taskfunc_args(call_string, 0, fnet); return res; }
struct vector_info draw_vpi_func_call(ivl_expr_t fnet, unsigned wid) { char call_string[1024]; struct vector_info res; res.base = allocate_vector(wid); res.wid = wid; if (res.base == 0) { fprintf(stderr, "%s:%u: vvp.tgt error: " "Unable to allocate %u thread bits for system function result.\n", ivl_expr_file(fnet), ivl_expr_lineno(fnet), wid); vvp_errors += 1; } sprintf(call_string, " %%vpi_func %u %u \"%s\", %u, %u", ivl_file_table_index(ivl_expr_file(fnet)), ivl_expr_lineno(fnet), ivl_expr_name(fnet), res.base, res.wid); draw_vpi_taskfunc_args(call_string, 0, fnet); return res; }
static unsigned emit_param_name_in_scope(ivl_scope_t scope, ivl_expr_t expr) { unsigned idx, count, lineno; const char *file; count = ivl_scope_params(scope); file = ivl_expr_file(expr); lineno = ivl_expr_lineno(expr); for (idx = 0; idx < count; idx += 1) { ivl_parameter_t par = ivl_scope_param(scope, idx); if (lineno != ivl_parameter_lineno(par)) continue; if (strcmp(file, ivl_parameter_file(par)) == 0) { /* Check that the appropriate expression bits match the * original parameter bits. */ ivl_expr_t pex = ivl_parameter_expr(par); unsigned wid = ivl_expr_width(expr); unsigned param_wid = ivl_expr_width(pex); const char *my_bits = ivl_expr_bits(expr); const char *param_bits = ivl_expr_bits(pex); unsigned bit; if (param_wid < wid) wid = param_wid; for (bit = 0; bit < wid; bit += 1) { if (my_bits[bit] != param_bits[bit]) { fprintf(stderr, "%s:%u: vlog95 error: Constant " "expression bits do not match " "parameter bits.\n", ivl_expr_file(expr), ivl_expr_lineno(expr)); break; } } // HERE: Does this work with an out of scope parameter reference? // What about real parameters? emit_id(ivl_parameter_basename(par)); return 1; } } return 0; }
struct vector_info draw_ufunc_expr(ivl_expr_t expr, unsigned wid) { unsigned swid = ivl_expr_width(expr); ivl_scope_t def = ivl_expr_def(expr); ivl_signal_t retval = ivl_scope_port(def, 0); struct vector_info res; unsigned load_wid; /* Take in arguments to function and call function code. */ draw_ufunc_preamble(expr); /* Fresh basic block starts after the join. */ clear_expression_lookaside(); /* The return value is in a signal that has the name of the expression. Load that into the thread and return the vector result. */ res.base = allocate_vector(wid); res.wid = wid; if (res.base == 0) { fprintf(stderr, "%s:%u: vvp.tgt error: " "Unable to allocate %u thread bits for function result.\n", ivl_expr_file(expr), ivl_expr_lineno(expr), wid); vvp_errors += 1; return res; } assert(res.base != 0); load_wid = swid; if (load_wid > ivl_signal_width(retval)) load_wid = ivl_signal_width(retval); assert(ivl_signal_dimensions(retval) == 0); fprintf(vvp_out, " %%load/v %u, v%p_0, %u;\n", res.base, retval, load_wid); /* Pad the signal value with zeros. */ if (load_wid < wid) pad_expr_in_place(expr, res, swid); draw_ufunc_epilogue(expr); return res; }
static void emit_expr_unary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid) { char *oper = "invalid"; switch (ivl_expr_opcode(expr)) { case '-': oper = "-"; break; case '~': oper = "~"; break; case '&': oper = "&"; break; case '|': oper = "|"; break; case '^': oper = "^"; break; case 'A': oper = "~&"; break; case 'N': oper = "~|"; break; case 'X': oper = "~^"; break; case '!': oper = "!"; break; } switch (ivl_expr_opcode(expr)) { case '-': case '~': case '&': case '|': case '^': case 'A': case 'N': case 'X': case '!': fprintf(vlog_out, "(%s", oper); emit_expr(scope, ivl_expr_oper1(expr), wid); fprintf(vlog_out, ")"); break; case '2': case 'i': case 'r': /* A cast is a noop. */ emit_expr(scope, ivl_expr_oper1(expr), wid); break; default: fprintf(vlog_out, "<unknown>"); emit_expr(scope, ivl_expr_oper1(expr), wid); fprintf(stderr, "%s:%u: vlog95 error: Unknown unary " "operator (%c).\n", ivl_expr_file(expr), ivl_expr_lineno(expr), ivl_expr_opcode(expr)); break; } }
static void emit_select_name(ivl_scope_t scope, ivl_expr_t expr, unsigned wid) { /* A select of a number is really a parameter select. */ if (ivl_expr_type(expr) == IVL_EX_NUMBER) { /* Look in the current scope. */ if (emit_param_name_in_scope(scope, expr)) return; /* Now look in the enclosing module scope if this is not a * module scope. */ if (ivl_scope_type(scope) != IVL_SCT_MODULE) { if (emit_param_name_in_scope(get_module_scope(scope), expr)) return; } // HERE: For now we only look in the current and module scope for the // parameter that is being selected. We need to also look in other // scopes, but that involves a big search. fprintf(vlog_out, "<missing>"); fprintf(stderr, "%s:%u: vlog95 error: Unable to find parameter " "for select expression \n", ivl_expr_file(expr), ivl_expr_lineno(expr)); vlog_errors += 1; } else { emit_expr(scope, expr, wid); } }
static void draw_unary_vec4(ivl_expr_t expr) { ivl_expr_t sub = ivl_expr_oper1(expr); if (debug_draw) { fprintf(vvp_out, " ; %s:%u:draw_unary_vec4: opcode=%c\n", ivl_expr_file(expr), ivl_expr_lineno(expr), ivl_expr_opcode(expr)); } switch (ivl_expr_opcode(expr)) { case '&': draw_eval_vec4(sub); fprintf(vvp_out, " %%and/r;\n"); break; case '|': draw_eval_vec4(sub); fprintf(vvp_out, " %%or/r;\n"); break; case '^': draw_eval_vec4(sub); fprintf(vvp_out, " %%xor/r;\n"); break; case '~': draw_eval_vec4(sub); fprintf(vvp_out, " %%inv;\n"); break; case '!': draw_eval_vec4(sub); fprintf(vvp_out, " %%nor/r;\n"); break; case '-': draw_eval_vec4(sub); fprintf(vvp_out, " %%inv;\n"); fprintf(vvp_out, " %%pushi/vec4 1, 0, %u;\n", ivl_expr_width(sub)); fprintf(vvp_out, " %%add;\n"); break; case 'A': /* nand (~&) */ draw_eval_vec4(sub); fprintf(vvp_out, " %%nand/r;\n"); break; case 'D': /* pre-decrement (--x) */ draw_unary_inc_dec(sub, false, true); break; case 'd': /* post_decrement (x--) */ draw_unary_inc_dec(sub, false, false); break; case 'I': /* pre-increment (++x) */ draw_unary_inc_dec(sub, true, true); break; case 'i': /* post-increment (x++) */ draw_unary_inc_dec(sub, true, false); break; case 'N': /* nor (~|) */ draw_eval_vec4(sub); fprintf(vvp_out, " %%nor/r;\n"); break; case 'X': /* xnor (~^) */ draw_eval_vec4(sub); fprintf(vvp_out, " %%xnor/r;\n"); break; case 'm': /* abs(m) */ draw_eval_vec4(sub); if (! ivl_expr_signed(sub)) break; /* Test if (m) < 0 */ fprintf(vvp_out, " %%dup/vec4;\n"); fprintf(vvp_out, " %%pushi/vec4 0, 0, %u;\n", ivl_expr_width(sub)); fprintf(vvp_out, " %%cmp/s;\n"); fprintf(vvp_out, " %%jmp/0xz T_%u.%u, 5;\n", thread_count, local_count); /* If so, calculate -(m) */ fprintf(vvp_out, " %%inv;\n"); fprintf(vvp_out, " %%pushi/vec4 1, 0, %u;\n", ivl_expr_width(sub)); fprintf(vvp_out, " %%add;\n"); fprintf(vvp_out, "T_%u.%u ;\n", thread_count, local_count); local_count += 1; break; case 'v': /* Cast real to vec4 */ assert(ivl_expr_value(sub) == IVL_VT_REAL); draw_eval_real(sub); fprintf(vvp_out, " %%cvt/vr %u;\n", ivl_expr_width(expr)); break; case '2': /* Cast expression to bool */ switch (ivl_expr_value(sub)) { case IVL_VT_LOGIC: draw_eval_vec4(sub); fprintf(vvp_out, " %%cast2;\n"); resize_vec4_wid(sub, ivl_expr_width(expr)); break; case IVL_VT_BOOL: draw_eval_vec4(sub); resize_vec4_wid(sub, ivl_expr_width(expr)); break; case IVL_VT_REAL: draw_eval_real(sub); fprintf(vvp_out, " %%cvt/vr %u;\n", ivl_expr_width(expr)); break; default: assert(0); break; } break; default: fprintf(stderr, "XXXX Unary operator %c not implemented\n", ivl_expr_opcode(expr)); break; } }
struct vector_info draw_ufunc_expr(ivl_expr_t expr, unsigned wid) { unsigned idx; unsigned swid = ivl_expr_width(expr); ivl_scope_t def = ivl_expr_def(expr); ivl_signal_t retval = ivl_scope_port(def, 0); struct vector_info res; unsigned load_wid; /* If this is an automatic function, allocate the local storage. */ if (ivl_scope_is_auto(def)) { fprintf(vvp_out, " %%alloc S_%p;\n", def); } /* evaluate the expressions and send the results to the function ports. */ assert(ivl_expr_parms(expr) == (ivl_scope_ports(def)-1)); for (idx = 0 ; idx < ivl_expr_parms(expr) ; idx += 1) { ivl_signal_t port = ivl_scope_port(def, idx+1); draw_function_argument(port, ivl_expr_parm(expr, idx)); } /* Call the function */ fprintf(vvp_out, " %%fork TD_%s", vvp_mangle_id(ivl_scope_name(def))); fprintf(vvp_out, ", S_%p;\n", def); fprintf(vvp_out, " %%join;\n"); /* Fresh basic block starts after the join. */ clear_expression_lookaside(); /* The return value is in a signal that has the name of the expression. Load that into the thread and return the vector result. */ res.base = allocate_vector(wid); res.wid = wid; if (res.base == 0) { fprintf(stderr, "%s:%u: vvp.tgt error: " "Unable to allocate %u thread bits for function result.\n", ivl_expr_file(expr), ivl_expr_lineno(expr), wid); vvp_errors += 1; return res; } assert(res.base != 0); load_wid = swid; if (load_wid > ivl_signal_width(retval)) load_wid = ivl_signal_width(retval); assert(ivl_signal_dimensions(retval) == 0); fprintf(vvp_out, " %%load/v %u, v%p_0, %u;\n", res.base, retval, load_wid); /* Pad the signal value with zeros. */ if (load_wid < wid) pad_expr_in_place(expr, res, swid); /* If this is an automatic function, free the local storage. */ if (ivl_scope_is_auto(def)) { fprintf(vvp_out, " %%free S_%p;\n", def); } return res; }
static void emit_expr_unary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid) { char *oper = "invalid"; switch (ivl_expr_opcode(expr)) { case '-': oper = "-"; break; case '~': oper = "~"; break; case '&': oper = "&"; break; case '|': oper = "|"; break; case '^': oper = "^"; break; case 'A': oper = "~&"; break; case 'N': oper = "~|"; break; case 'X': oper = "~^"; break; case '!': oper = "!"; break; } switch (ivl_expr_opcode(expr)) { case '-': case '~': case '&': case '|': case '^': case 'A': case 'N': case 'X': case '!': fprintf(vlog_out, "(%s", oper); emit_expr(scope, ivl_expr_oper1(expr), wid); fprintf(vlog_out, ")"); break; case '2': case 'v': case 'r': /* A cast is a noop. */ emit_expr(scope, ivl_expr_oper1(expr), wid); break; case 'I': fprintf(vlog_out, "(++"); emit_expr(scope, ivl_expr_oper1(expr), wid); fprintf(vlog_out, ")"); fprintf(stderr, "%s:%u: vlog95 sorry: Pre-increment " "operator is not currently translated.\n", ivl_expr_file(expr), ivl_expr_lineno(expr)); vlog_errors += 1; break; case 'i': fprintf(vlog_out, "("); emit_expr(scope, ivl_expr_oper1(expr), wid); fprintf(vlog_out, "++)"); fprintf(stderr, "%s:%u: vlog95 sorry: Pre-increment " "operator is not currently translated.\n", ivl_expr_file(expr), ivl_expr_lineno(expr)); vlog_errors += 1; break; case 'D': fprintf(vlog_out, "(--"); emit_expr(scope, ivl_expr_oper1(expr), wid); fprintf(vlog_out, ")"); fprintf(stderr, "%s:%u: vlog95 sorry: Pre-decrement " "operator is not currently translated.\n", ivl_expr_file(expr), ivl_expr_lineno(expr)); vlog_errors += 1; break; case 'd': fprintf(vlog_out, "("); emit_expr(scope, ivl_expr_oper1(expr), wid); fprintf(vlog_out, "--)"); fprintf(stderr, "%s:%u: vlog95 sorry: Pre-decrement " "operator is not currently translated.\n", ivl_expr_file(expr), ivl_expr_lineno(expr)); vlog_errors += 1; break; default: fprintf(vlog_out, "<unknown>"); emit_expr(scope, ivl_expr_oper1(expr), wid); fprintf(stderr, "%s:%u: vlog95 error: Unknown unary " "operator (%c).\n", ivl_expr_file(expr), ivl_expr_lineno(expr), ivl_expr_opcode(expr)); vlog_errors += 1; break; } }
/* * Emit a constant or variable delay that has been rescaled to the given * scopes timescale. */ void emit_scaled_delayx(ivl_scope_t scope, ivl_expr_t expr, unsigned is_stmt) { ivl_expr_type_t type = ivl_expr_type(expr); if (type == IVL_EX_DELAY) { emit_scaled_delay(scope, ivl_expr_delay_val(expr)); } else if (type == IVL_EX_NUMBER) { assert(! ivl_expr_signed(expr)); int rtype; uint64_t value = get_uint64_from_number(expr, &rtype); if (rtype > 0) { fprintf(vlog_out, "<invalid>"); fprintf(stderr, "%s:%u: vlog95 error: Time value is " "greater than 64 bits (%u) and cannot be " "safely represented.\n", ivl_expr_file(expr), ivl_expr_lineno(expr), rtype); vlog_errors += 1; return; } if (rtype < 0) { fprintf(vlog_out, "<invalid>"); fprintf(stderr, "%s:%u: vlog95 error: Time value has an " "undefined bit and cannot be represented.\n", ivl_expr_file(expr), ivl_expr_lineno(expr)); vlog_errors += 1; return; } emit_scaled_delay(scope, value); } else { int exponent = ivl_scope_time_units(scope) - sim_precision; assert(exponent >= 0); if ((exponent == 0) && (type == IVL_EX_SIGNAL)) { emit_delay(scope, expr, is_stmt); /* A real delay variable is not scaled by the compiler. */ } else if (type == IVL_EX_SIGNAL) { if (is_stmt) { fprintf(vlog_out, "<invalid>"); fprintf(stderr, "%s:%u: vlog95 error: Only continuous " "assignment delay variables are scaled " "at run time.\n", ivl_expr_file(expr), ivl_expr_lineno(expr)); vlog_errors += 1; return; } emit_delay(scope, expr, is_stmt); } else { uint64_t iscale = 1; unsigned rtn; assert(! ivl_expr_signed(expr)); /* Calculate the integer time scaling coefficient. */ while (exponent > 0) { iscale *= 10; exponent -= 1; } /* Check to see if this is an integer time value. */ rtn = check_scaled_expr(expr, iscale, "Variable time", 0); /* This may be a scaled real value. */ if (rtn == 2){ ivl_expr_t tmp_expr; uint64_t rprec = 1; /* This could be a scaled real time so calculate * the real time scaling coefficients and check * that the expression matches (statements only). */ exponent = ivl_scope_time_precision(scope) - sim_precision; assert(exponent >= 0); while (exponent > 0) { rprec *= 10; exponent -= 1; } /* Verify that the precision scaling is correct. */ if (! check_scaled_expr(expr, rprec, "Variable real time prec.", 1)) { fprintf(vlog_out, "<invalid>"); return; } /* Verify that the left operator is a real to * integer cast. */ tmp_expr = ivl_expr_oper1(expr); if ((ivl_expr_type(tmp_expr) != IVL_EX_UNARY) || (ivl_expr_opcode(tmp_expr) != 'v')) { fprintf(vlog_out, "<invalid>"); fprintf(stderr, "%s:%u: vlog95 error: Real time " "value does not have a cast to " "integer.\n", ivl_expr_file(expr), ivl_expr_lineno(expr)); vlog_errors += 1; return; } /* Check that the cast value is scaled correctly. */ assert(iscale >= rprec); tmp_expr = ivl_expr_oper1(tmp_expr); assert(ivl_expr_value(tmp_expr) == IVL_VT_REAL); if (! check_scaled_real_expr(tmp_expr, iscale/rprec)) { fprintf(vlog_out, "<invalid>"); return; } assert(is_stmt); emit_delay(scope, ivl_expr_oper1(tmp_expr), is_stmt); return; } else if (rtn == 1) { emit_delay(scope, ivl_expr_oper1(expr), is_stmt); return; } fprintf(vlog_out, "<invalid>"); } } }
void emit_expr(ivl_scope_t scope, ivl_expr_t expr, unsigned wid) { switch (ivl_expr_type(expr)) { case IVL_EX_ARRAY: emit_expr_array(scope, expr, wid); break; case IVL_EX_BINARY: emit_expr_binary(scope, expr, wid); break; case IVL_EX_CONCAT: emit_expr_concat(scope, expr, wid); break; case IVL_EX_DELAY: emit_expr_delay(scope, expr, wid); break; case IVL_EX_ENUMTYPE: fprintf(vlog_out, "<enum>"); fprintf(stderr, "%s:%u: vlog95 error: Enum expressions " "are not supported.\n", ivl_expr_file(expr), ivl_expr_lineno(expr)); vlog_errors += 1; break; case IVL_EX_EVENT: emit_expr_event(scope, expr, wid); break; case IVL_EX_NUMBER: emit_number(ivl_expr_bits(expr), ivl_expr_width(expr), ivl_expr_signed(expr), ivl_expr_file(expr), ivl_expr_lineno(expr)); break; case IVL_EX_REALNUM: emit_real_number(ivl_expr_dvalue(expr)); break; case IVL_EX_SCOPE: emit_expr_scope(scope, expr, wid); break; case IVL_EX_SELECT: emit_expr_select(scope, expr, wid); break; case IVL_EX_SFUNC: fprintf(vlog_out, "%s", ivl_expr_name(expr)); emit_expr_func(scope, expr, wid); break; case IVL_EX_SIGNAL: emit_expr_signal(scope, expr, wid); break; case IVL_EX_STRING: emit_string(ivl_expr_string(expr)); break; case IVL_EX_TERNARY: emit_expr_ternary(scope, expr, wid); break; case IVL_EX_UFUNC: emit_scope_path(scope, ivl_expr_def(expr)); emit_expr_func(scope, expr, wid); break; case IVL_EX_UNARY: emit_expr_unary(scope, expr, wid); break; default: fprintf(vlog_out, "<unknown>"); fprintf(stderr, "%s:%u: vlog95 error: Unknown expression " "type (%d).\n", ivl_expr_file(expr), ivl_expr_lineno(expr), (int)ivl_expr_type(expr)); vlog_errors += 1; break; } }
void show_expression(ivl_expr_t net, unsigned ind) { assert(net); unsigned idx; ivl_parameter_t par = ivl_expr_parameter(net); const ivl_expr_type_t code = ivl_expr_type(net); unsigned width = ivl_expr_width(net); const char*sign = ivl_expr_signed(net)? "signed" : "unsigned"; const char*sized = ivl_expr_sized(net)? "sized" : "unsized"; const char*vt = vt_type_string(net); switch (code) { case IVL_EX_ARRAY: show_array_expression(net, ind); break; case IVL_EX_ARRAY_PATTERN: show_array_pattern_expression(net, ind); break; case IVL_EX_BACCESS: show_branch_access_expression(net, ind); break; case IVL_EX_BINARY: show_binary_expression(net, ind); break; case IVL_EX_CONCAT: fprintf(out, "%*s<concat repeat=%u, width=%u, %s, type=%s>\n", ind, "", ivl_expr_repeat(net), width, sign, vt); for (idx = 0 ; idx < ivl_expr_parms(net) ; idx += 1) show_expression(ivl_expr_parm(net, idx), ind+3); break; case IVL_EX_ENUMTYPE: show_enumtype_expression(net, ind); break; case IVL_EX_MEMORY: show_memory_expression(net, ind); break; case IVL_EX_NEW: show_new_expression(net, ind); break; case IVL_EX_NULL: show_null_expression(net, ind); break; case IVL_EX_PROPERTY: show_property_expression(net, ind); break; case IVL_EX_NUMBER: { const char*bits = ivl_expr_bits(net); fprintf(out, "%*s<number=%u'b", ind, "", width); for (idx = width ; idx > 0 ; idx -= 1) fprintf(out, "%c", bits[idx-1]); fprintf(out, ", %s %s %s", sign, sized, vt); if (par != 0) fprintf(out, ", parameter=%s", ivl_parameter_basename(par)); fprintf(out, ">\n"); break; } case IVL_EX_SELECT: show_select_expression(net, ind); break; case IVL_EX_STRING: fprintf(out, "%*s<string=\"%s\", width=%u", ind, "", ivl_expr_string(net), ivl_expr_width(net)); if (par != 0) fprintf(out, ", parameter=%s", ivl_parameter_basename(par)); fprintf(out, ", type=%s>\n", vt); break; case IVL_EX_SFUNC: fprintf(out, "%*s<function=\"%s\", width=%u, %s, type=%s file=%s:%u>\n", ind, "", ivl_expr_name(net), width, sign, vt, ivl_expr_file(net), ivl_expr_lineno(net)); { unsigned cnt = ivl_expr_parms(net); unsigned jdx; for (jdx = 0 ; jdx < cnt ; jdx += 1) show_expression(ivl_expr_parm(net, jdx), ind+3); } break; case IVL_EX_SIGNAL: show_signal_expression(net, ind); break; case IVL_EX_TERNARY: show_ternary_expression(net, ind); break; case IVL_EX_UNARY: show_unary_expression(net, ind); break; case IVL_EX_UFUNC: show_function_call(net, ind); break; case IVL_EX_REALNUM: { int jdx; union foo { double rv; unsigned char bv[sizeof(double)]; } tmp; tmp.rv = ivl_expr_dvalue(net); fprintf(out, "%*s<realnum=%f (", ind, "", tmp.rv); for (jdx = sizeof(double) ; jdx > 0 ; jdx -= 1) fprintf(out, "%02x", tmp.bv[jdx-1]); fprintf(out, ")"); if (par != 0) fprintf(out, ", parameter=%s", ivl_parameter_basename(par)); fprintf(out, ">\n"); } break; case IVL_EX_SHALLOWCOPY: show_shallowcopy(net, ind); break; default: fprintf(out, "%*s<expr_type=%d>\n", ind, "", code); break; } }
static void emit_expr_binary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid) { char *oper = "<invalid>"; switch (ivl_expr_opcode(expr)) { case '+': oper = "+"; break; case '-': oper = "-"; break; case '*': oper = "*"; break; case '/': oper = "/"; break; case '%': oper = "%"; break; case 'p': oper = "**"; break; case 'E': oper = "==="; break; case 'e': oper = "=="; break; case 'N': oper = "!=="; break; case 'n': oper = "!="; break; case '<': oper = "<"; break; case 'L': oper = "<="; break; case '>': oper = ">"; break; case 'G': oper = ">="; break; case '&': oper = "&"; break; case '|': oper = "|"; break; case '^': oper = "^"; break; case 'A': oper = "&"; break; case 'O': oper = "|"; break; case 'X': oper = "~^"; break; case 'a': oper = "&&"; break; case 'o': oper = "||"; break; case 'l': oper = "<<"; break; case 'r': oper = ">>"; break; case 'R': oper = ">>>"; break; } fprintf(vlog_out, "("); switch (ivl_expr_opcode(expr)) { case '%': if (ivl_expr_value(expr) == IVL_VT_REAL) { fprintf(stderr, "%s:%u: vlog95 error: Real modulus operator " "is not supported.\n", ivl_expr_file(expr), ivl_expr_lineno(expr)); vlog_errors += 1; } case '+': case '-': case '*': case '/': case 'E': case 'e': case 'N': case 'n': case '<': case 'L': case '>': case 'G': case '&': case '|': case '^': case 'X': emit_expr(scope, ivl_expr_oper1(expr), wid); fprintf(vlog_out, " %s ", oper); emit_expr(scope, ivl_expr_oper2(expr), wid); break; case 'a': case 'o': emit_expr(scope, ivl_expr_oper1(expr), 0); fprintf(vlog_out, " %s ", oper); emit_expr(scope, ivl_expr_oper2(expr), 0); break; case 'R': if (! allow_signed) { fprintf(stderr, "%s:%u: vlog95 error: >>> operator is not " "supported.\n", ivl_expr_file(expr), ivl_expr_lineno(expr)); vlog_errors += 1; } case 'l': case 'r': emit_expr(scope, ivl_expr_oper1(expr), wid); fprintf(vlog_out, " %s ", oper); emit_expr(scope, ivl_expr_oper2(expr), 0); break; case 'A': case 'O': fprintf(vlog_out, "~("); emit_expr(scope, ivl_expr_oper1(expr), wid); fprintf(vlog_out, " %s ", oper); emit_expr(scope, ivl_expr_oper2(expr), wid); fprintf(vlog_out, ")"); break; case 'p': if (! emit_power_as_shift(scope, expr, wid)) { emit_expr(scope, ivl_expr_oper1(expr), wid); fprintf(vlog_out, " ** "); emit_expr(scope, ivl_expr_oper2(expr), 0); fprintf(stderr, "%s:%u: vlog95 error: Power operator is not " "supported.\n", ivl_expr_file(expr), ivl_expr_lineno(expr)); vlog_errors += 1; } break; default: emit_expr(scope, ivl_expr_oper1(expr), wid); fprintf(vlog_out, "<unknown>"); emit_expr(scope, ivl_expr_oper2(expr), wid); fprintf(stderr, "%s:%u: vlog95 error: Unknown expression " "operator (%c).\n", ivl_expr_file(expr), ivl_expr_lineno(expr), ivl_expr_opcode(expr)); vlog_errors += 1; break; } fprintf(vlog_out, ")"); }
static int show_stmt_assign_vector(ivl_statement_t net) { ivl_expr_t rval = ivl_stmt_rval(net); struct vector_info res; struct vector_info lres = {0, 0}; struct vec_slice_info*slices = 0; /* If this is a compressed assignment, then get the contents of the l-value. We need these values as part of the r-value calculation. */ if (ivl_stmt_opcode(net) != 0) { slices = calloc(ivl_stmt_lvals(net), sizeof(struct vec_slice_info)); lres = get_vec_from_lval(net, slices); } /* Handle the special case that the expression is a real value. Evaluate the real expression, then convert the result to a vector. Then store that vector into the l-value. */ if (ivl_expr_value(rval) == IVL_VT_REAL) { draw_eval_real(rval); /* This is the accumulated with of the l-value of the assignment. */ unsigned wid = ivl_stmt_lwidth(net); res.base = allocate_vector(wid); res.wid = wid; if (res.base == 0) { fprintf(stderr, "%s:%u: vvp.tgt error: " "Unable to allocate %u thread bits for " "r-value expression.\n", ivl_expr_file(rval), ivl_expr_lineno(rval), wid); vvp_errors += 1; } fprintf(vvp_out, " %%cvt/vr %u, %u;\n", res.base, res.wid); } else { res = draw_eval_expr(rval, 0); } switch (ivl_stmt_opcode(net)) { case 0: set_vec_to_lval(net, res); break; case '+': if (res.base > 3) { fprintf(vvp_out, " %%add %u, %u, %u;\n", res.base, lres.base, res.wid); clr_vector(lres); } else { fprintf(vvp_out, " %%add %u, %u, %u;\n", lres.base, res.base, res.wid); res.base = lres.base; } put_vec_to_lval(net, slices, res); break; case '-': fprintf(vvp_out, " %%sub %u, %u, %u;\n", lres.base, res.base, res.wid); fprintf(vvp_out, " %%mov %u, %u, %u;\n", res.base, lres.base, res.wid); clr_vector(lres); put_vec_to_lval(net, slices, res); break; case '*': if (res.base > 3) { fprintf(vvp_out, " %%mul %u, %u, %u;\n", res.base, lres.base, res.wid); clr_vector(lres); } else { fprintf(vvp_out, " %%mul %u, %u, %u;\n", lres.base, res.base, res.wid); res.base = lres.base; } put_vec_to_lval(net, slices, res); break; case '/': fprintf(vvp_out, " %%div%s %u, %u, %u;\n", ivl_expr_signed(rval)? "/s" : "", lres.base, res.base, res.wid); fprintf(vvp_out, " %%mov %u, %u, %u;\n", res.base, lres.base, res.wid); clr_vector(lres); put_vec_to_lval(net, slices, res); break; case '%': fprintf(vvp_out, " %%mod%s %u, %u, %u;\n", ivl_expr_signed(rval)? "/s" : "", lres.base, res.base, res.wid); fprintf(vvp_out, " %%mov %u, %u, %u;\n", res.base, lres.base, res.wid); clr_vector(lres); put_vec_to_lval(net, slices, res); break; case '&': if (res.base > 3) { fprintf(vvp_out, " %%and %u, %u, %u;\n", res.base, lres.base, res.wid); clr_vector(lres); } else { fprintf(vvp_out, " %%and %u, %u, %u;\n", lres.base, res.base, res.wid); res.base = lres.base; } put_vec_to_lval(net, slices, res); break; case '|': if (res.base > 3) { fprintf(vvp_out, " %%or %u, %u, %u;\n", res.base, lres.base, res.wid); clr_vector(lres); } else { fprintf(vvp_out, " %%or %u, %u, %u;\n", lres.base, res.base, res.wid); res.base = lres.base; } put_vec_to_lval(net, slices, res); break; case '^': if (res.base > 3) { fprintf(vvp_out, " %%xor %u, %u, %u;\n", res.base, lres.base, res.wid); clr_vector(lres); } else { fprintf(vvp_out, " %%xor %u, %u, %u;\n", lres.base, res.base, res.wid); res.base = lres.base; } put_vec_to_lval(net, slices, res); break; case 'l': /* lres <<= res */ fprintf(vvp_out, " %%ix/get 0, %u, %u;\n", res.base, res.wid); fprintf(vvp_out, " %%shiftl/i0 %u, %u;\n", lres.base, res.wid); fprintf(vvp_out, " %%mov %u, %u, %u;\n", res.base, lres.base, res.wid); break; case 'r': /* lres >>= res */ fprintf(vvp_out, " %%ix/get 0, %u, %u;\n", res.base, res.wid); fprintf(vvp_out, " %%shiftr/i0 %u, %u;\n", lres.base, res.wid); fprintf(vvp_out, " %%mov %u, %u, %u;\n", res.base, lres.base, res.wid); break; case 'R': /* lres >>>= res */ fprintf(vvp_out, " %%ix/get 0, %u, %u;\n", res.base, res.wid); fprintf(vvp_out, " %%shiftr/s/i0 %u, %u;\n", lres.base, res.wid); fprintf(vvp_out, " %%mov %u, %u, %u;\n", res.base, lres.base, res.wid); break; default: fprintf(vvp_out, "; UNSUPPORTED ASSIGNMENT OPCODE: %c\n", ivl_stmt_opcode(net)); assert(0); break; } if (slices) free(slices); if (res.base > 3) clr_vector(res); return 0; }
void draw_eval_vec4(ivl_expr_t expr) { if (debug_draw) { fprintf(vvp_out, " ; %s:%u:draw_eval_vec4: expr_type=%d\n", ivl_expr_file(expr), ivl_expr_lineno(expr), ivl_expr_type(expr)); } switch (ivl_expr_type(expr)) { case IVL_EX_BINARY: draw_binary_vec4(expr); return; case IVL_EX_CONCAT: draw_concat_vec4(expr); return; case IVL_EX_NUMBER: draw_number_vec4(expr); return; case IVL_EX_SELECT: if (ivl_expr_oper2(expr)==0) draw_select_pad_vec4(expr); else draw_select_vec4(expr); return; case IVL_EX_SFUNC: draw_sfunc_vec4(expr); return; case IVL_EX_SIGNAL: draw_signal_vec4(expr); return; case IVL_EX_STRING: draw_string_vec4(expr); return; case IVL_EX_TERNARY: draw_ternary_vec4(expr); return; case IVL_EX_UFUNC: draw_ufunc_vec4(expr); return; case IVL_EX_UNARY: draw_unary_vec4(expr); return; case IVL_EX_PROPERTY: draw_property_vec4(expr); return; default: break; } fprintf(stderr, "XXXX Evaluate VEC4 expression (%d)\n", ivl_expr_type(expr)); fprintf(vvp_out, "; XXXX Evaluate VEC4 expression (%d)\n", ivl_expr_type(expr)); }
void show_expression(ivl_expr_t net, unsigned ind) { unsigned idx; const ivl_expr_type_t code = ivl_expr_type(net); ivl_parameter_t par = ivl_expr_parameter(net); unsigned width = ivl_expr_width(net); const char*sign = ivl_expr_signed(net)? "signed" : "unsigned"; const char*sized = ivl_expr_sized(net)? "sized" : "unsized"; const char*vt = vt_type_string(net); switch (code) { case IVL_EX_ARRAY: show_array_expression(net, ind); break; case IVL_EX_BACCESS: show_branch_access_expression(net, ind); break; case IVL_EX_BINARY: show_binary_expression(net, ind); break; case IVL_EX_CONCAT: fprintf(out, "%*s<concat repeat=%u, width=%u, %s, type=%s>\n", ind, "", ivl_expr_repeat(net), width, sign, vt); for (idx = 0 ; idx < ivl_expr_parms(net) ; idx += 1) show_expression(ivl_expr_parm(net, idx), ind+3); break; case IVL_EX_MEMORY: show_memory_expression(net, ind); break; case IVL_EX_NUMBER: { const char*bits = ivl_expr_bits(net); fprintf(out, "%*s<number=%u'b", ind, "", width); for (idx = width ; idx > 0 ; idx -= 1) fprintf(out, "%c", bits[idx-1]); fprintf(out, ", %s %s %s", sign, sized, vt); if (par != 0) fprintf(out, ", parameter=%s", ivl_parameter_basename(par)); fprintf(out, ">\n"); break; } case IVL_EX_SELECT: /* The SELECT expression can be used to express part select, or if the base is null vector extension. */ if (ivl_expr_oper2(net)) { fprintf(out, "%*s<select: width=%u, %s>\n", ind, "", width, sign); show_expression(ivl_expr_oper1(net), ind+3); show_expression(ivl_expr_oper2(net), ind+3); } else { fprintf(out, "%*s<expr pad: width=%u, %s>\n", ind, "", width, sign); show_expression(ivl_expr_oper1(net), ind+3); } break; case IVL_EX_STRING: fprintf(out, "%*s<string=\"%s\", width=%u", ind, "", ivl_expr_string(net), ivl_expr_width(net)); if (par != 0) fprintf(out, ", parameter=%s", ivl_parameter_basename(par)); fprintf(out, ", type=%s>\n", vt); break; case IVL_EX_SFUNC: fprintf(out, "%*s<function=\"%s\", width=%u, %s, type=%s file=%s:%u>\n", ind, "", ivl_expr_name(net), width, sign, vt, ivl_expr_file(net), ivl_expr_lineno(net)); { unsigned cnt = ivl_expr_parms(net); unsigned jdx; for (jdx = 0 ; jdx < cnt ; jdx += 1) show_expression(ivl_expr_parm(net, jdx), ind+3); } break; case IVL_EX_SIGNAL: show_signal_expression(net, ind); break; case IVL_EX_TERNARY: show_ternary_expression(net, ind); break; case IVL_EX_UNARY: show_unary_expression(net, ind); break; case IVL_EX_UFUNC: show_function_call(net, ind); break; case IVL_EX_REALNUM: { int jdx; union foo { double rv; unsigned char bv[sizeof(double)]; } tmp; tmp.rv = ivl_expr_dvalue(net); fprintf(out, "%*s<realnum=%f (", ind, "", tmp.rv); for (jdx = sizeof(double) ; jdx > 0 ; jdx -= 1) fprintf(out, "%02x", tmp.bv[jdx-1]); fprintf(out, ")"); if (par != 0) fprintf(out, ", parameter=%s", ivl_parameter_basename(par)); fprintf(out, ">\n"); } break; default: fprintf(out, "%*s<expr_type=%u>\n", ind, "", code); break; } }