static void group_decl(tree_t decl, group_nets_ctx_t *ctx, int start, int n) { netid_t first = NETID_INVALID; unsigned len = 0; type_t type = tree_type(decl); const int nnets = tree_nets(decl); const bool record = group_contains_record(type); int ffield = -1; assert((n == -1) | (start + n <= nnets)); for (int i = start; i < (n == -1 ? nnets : start + n); i++) { netid_t nid = tree_net(decl, i); if (first == NETID_INVALID) { first = nid; len = 1; ffield = record ? group_net_to_field(type, i) : -1; } else if (nid == first + len && (!record || group_net_to_field(type, i) == ffield)) ++len; else { group_add(ctx, first, len); first = nid; len = 1; ffield = record ? group_net_to_field(type, i) : -1; } } if (first != NETID_INVALID) group_add(ctx, first, len); else { // Array signal with null range tree_add_attr_int(decl, null_range_i, 1); } }
static tree_t elab_port_to_signal(tree_t arch, tree_t port, tree_t actual) { assert(tree_kind(port) == T_PORT_DECL); ident_t name = tree_ident(port); const int ndecls = tree_decls(arch); for (int i = 0; i < ndecls; i++) { tree_t d = tree_decl(arch, i); if (tree_ident(d) == name) return d; } type_t port_type = tree_type(port); type_t actual_type = tree_type(actual); type_t type = (type_is_unconstrained(port_type)) ? actual_type : port_type; port_mode_t mode = tree_subkind(port); tree_t s = tree_new(T_SIGNAL_DECL); tree_set_ident(s, tree_ident(port)); tree_set_type(s, type); tree_add_attr_int(s, fst_dir_i, mode); tree_set_loc(s, tree_loc(port)); tree_set_flag(s, tree_flags(port) & TREE_F_LAST_VALUE); if ((mode == PORT_OUT) || (mode == PORT_INOUT) || (mode == PORT_BUFFER)) { if (tree_has_value(port)) tree_add_attr_tree(s, driver_init_i, tree_value(port)); } tree_add_decl(arch, s); return s; }
static void opt_elide_array_ref_bounds(tree_t t) { tree_t value = tree_value(t); if (tree_kind(value) != T_REF) return; tree_t decl = tree_ref(value); const int nparams = tree_params(t); for (int i = 0; i < nparams; i++) { tree_t index = tree_value(tree_param(t, i)); if (tree_kind(index) != T_REF) return; tree_t index_decl = tree_ref(index); tree_t range_var = tree_attr_tree(index_decl, range_var_i); if (range_var == NULL) return; if (range_var != decl) return; } tree_add_attr_int(t, elide_bounds_i, 1); }
static void opt_tag_last_value_fcall(tree_t t) { tree_t decl = tree_ref(t); if (tree_attr_str(decl, builtin_i) != NULL) return; // A regular subprogram call may pass parameters as class signal which // could access 'LAST_VALUE in the body const int nports = tree_ports(decl); for (int i = 0; i < nports; i++) { tree_t port = tree_port(decl, i); if (tree_class(port) != C_SIGNAL) continue; tree_t value = tree_value(tree_param(t, i)); tree_kind_t kind; while ((kind = tree_kind(value)) != T_REF) { assert((kind == T_ARRAY_REF) || (kind == T_ARRAY_SLICE)); value = tree_value(value); } tree_add_attr_int(tree_ref(value), last_value_i, 1); } }
void cover_tag(tree_t top) { stmt_tag_i = ident_new("stmt_tag"); int line_tags = 0; tree_visit(top, cover_tag_stmts_fn, &line_tags); tree_add_attr_int(top, ident_new("stmt_tags"), line_tags); }
static void opt_tag_last_value_attr_ref(tree_t t) { static ident_t last_value_attr_i = NULL; if (last_value_attr_i == NULL) last_value_attr_i = ident_new("LAST_VALUE"); if (tree_ident(t) == last_value_attr_i) { tree_t signal = tree_ref(tree_name(t)); if (tree_kind(signal) != T_SIGNAL_DECL) return; // A signal in a package will not have nets assigned yet so we cannot // optimise out 'LAST_VALUE if (tree_nets(signal) > 0) tree_add_attr_int(signal, last_value_i, 1); } }
static void cover_tag_stmts_fn(tree_t t, void *context) { int *next = context; switch (tree_kind(t)) { case T_SIGNAL_ASSIGN: case T_ASSERT: case T_VAR_ASSIGN: case T_IF: case T_WHILE: case T_WAIT: case T_RETURN: case T_NEXT: case T_EXIT: tree_add_attr_int(t, stmt_tag_i, (*next)++); break; default: break; } }
static tree_t elab_signal_port(tree_t arch, tree_t formal, tree_t param, map_list_t **maps) { assert(tree_kind(param) == T_PARAM); tree_t actual = tree_value(param); // NULL name means associate the whole port tree_t name = NULL; if (tree_subkind(param) == P_NAMED) { tree_t n = tree_name(param); if (tree_kind(n) != T_REF) name = n; } const bool partial_map = name != NULL; switch (tree_kind(actual)) { case T_REF: case T_ARRAY_REF: case T_ARRAY_SLICE: case T_RECORD_REF: { // Replace the formal port with a signal and connect its nets to // those of the actual tree_t ref = actual; tree_kind_t ref_kind; while ((ref_kind = tree_kind(ref)) != T_REF) { if ((ref_kind == T_AGGREGATE) || (ref_kind == T_LITERAL)) return actual; else ref = tree_value(ref); } tree_t decl = tree_ref(ref); tree_kind_t decl_kind = tree_kind(decl); if (decl_kind == T_SIGNAL_DECL) { tree_t s = elab_port_to_signal(arch, formal, actual); if (partial_map) tree_add_attr_int(s, partial_map_i, 1); map_list_t *m = xmalloc(sizeof(map_list_t)); m->next = *maps; m->formal = formal; m->actual = actual; m->signal = s; m->name = name; *maps = m; return s; } else if (decl_kind == T_PORT_DECL) return NULL; // Port was OPEN at a higher level else return actual; } case T_LITERAL: case T_AGGREGATE: { type_t formal_type = tree_type(formal); if (!type_is_unconstrained(formal_type)) tree_set_type(actual, formal_type); return actual; } case T_OPEN: return NULL; case T_TYPE_CONV: // Only allow simple array type conversions for now { type_t to_type = tree_type(actual); type_t from_type = tree_type(tree_value(tree_param(actual, 0))); if (type_is_array(to_type) && type_is_array(from_type)) return actual; else fatal_at(tree_loc(actual), "sorry, this form of type conversion " "is not supported as an actual"); } default: fatal_at(tree_loc(actual), "tree %s not supported as actual", tree_kind_str(tree_kind(actual))); } }