static void elab_add_context(tree_t t, const elab_ctx_t *ctx) { ident_t cname = tree_ident(t); ident_t lname = ident_until(cname, '.'); lib_t lib = elab_find_lib(lname, ctx); tree_t unit = lib_get(lib, cname); if (unit == NULL) fatal_at(tree_loc(t), "cannot find unit %s", istr(cname)); else if (tree_kind(unit) == T_PACKAGE) { elab_copy_context(unit, ctx); ident_t name = tree_ident(unit); ident_t body_i = ident_prefix(name, ident_new("body"), '-'); tree_t body = lib_get(lib, body_i); if (body != NULL) elab_copy_context(unit, ctx); } // Always use real library name rather than WORK alias tree_set_ident(t, tree_ident(unit)); tree_add_context(ctx->out, t); }
static tree_t rewrite_refs(tree_t t, void *context) { rewrite_params_t *params = context; if (tree_kind(t) != T_REF) return t; tree_t decl = tree_ref(t); for (int i = 0; i < params->count; i++) { if (decl != params->formals[i]) continue; // Do not rewrite references if they appear as formal names if (tree_attr_int(t, formal_i, 0)) continue; // Skip assignments to OPEN ports if (params->actuals[i] == NULL) continue; switch (tree_kind(params->actuals[i])) { case T_SIGNAL_DECL: case T_ENUM_LIT: tree_set_ref(t, params->actuals[i]); tree_set_type(t, tree_type(params->actuals[i])); return t; case T_LITERAL: case T_AGGREGATE: case T_REF: case T_ARRAY_SLICE: case T_ARRAY_REF: case T_FCALL: case T_CONCAT: return params->actuals[i]; case T_TYPE_CONV: // XXX: this only works in trivial cases return tree_value(tree_param(params->actuals[i], 0)); default: fatal_at(tree_loc(params->actuals[i]), "cannot handle tree kind %s " "in rewrite_refs", tree_kind_str(tree_kind(params->actuals[i]))); } } return t; }
static ident_t elab_formal_name(tree_t t) { tree_kind_t kind; while ((kind = tree_kind(t)) != T_REF) { switch (kind) { case T_ARRAY_REF: case T_ARRAY_SLICE: t = tree_value(t); break; default: fatal_at(tree_loc(t), "sorry, this kind of formal is not supported %s", tree_kind_str(kind)); } } return tree_ident(t); }
int64_t assume_int(tree_t t) { switch (tree_kind(t)) { case T_LITERAL: assert(tree_subkind(t) == L_INT); return tree_ival(t); case T_REF: { tree_t ref = tree_ref(t); assert(tree_kind(ref) == T_ENUM_LIT); return tree_pos(ref); } default: fatal_at(tree_loc(t), "expression cannot be folded to " "an integer constant"); } }
static tree_t pick_arch(const loc_t *loc, ident_t name, lib_t *new_lib, const elab_ctx_t *ctx) { // When an explicit architecture name is not given select the most // recently analysed architecture of this entity lib_t lib = elab_find_lib(name, ctx); tree_t arch = lib_get_check_stale(lib, name); if ((arch == NULL) || (tree_kind(arch) != T_ARCH)) { arch = NULL; lib_search_params_t params = { lib, name, &arch }; lib_walk_index(lib, find_arch, ¶ms); if (arch == NULL) fatal_at(loc, "no suitable architecture for %s", istr(name)); } if (new_lib != NULL) *new_lib = lib; return arch; }
static bool group_name(tree_t target, group_nets_ctx_t *ctx, int start, int n) { switch (tree_kind(target)) { case T_REF: group_ref(target, ctx, start, n); return true; case T_ARRAY_REF: { tree_t value = tree_value(target); type_t type = tree_type(value); if (type_is_unconstrained(type)) return false; int offset = 0; const int nparams = tree_params(target); for (int i = 0; i < nparams; i++) { tree_t index = tree_value(tree_param(target, i)); const int stride = type_width(type_elem(type)); if (tree_kind(index) != T_LITERAL) { if (i > 0) return false; const int twidth = type_width(type); for (int j = 0; j < twidth; j += stride) group_name(value, ctx, start + j, n); return true; } else { if (i > 0) { range_t type_r = range_of(type, i); int64_t low, high; range_bounds(type_r, &low, &high); offset *= high - low + 1; } offset += stride * rebase_index(type, i, assume_int(index)); } } return group_name(value, ctx, start + offset, n); } case T_ARRAY_SLICE: { tree_t value = tree_value(target); type_t type = tree_type(value); if (type_is_unconstrained(type)) return false; // Only in procedure range_t slice = tree_range(target, 0 ); if (tree_kind(slice.left) != T_LITERAL || tree_kind(slice.right) != T_LITERAL) return false; int64_t low, high; range_bounds(slice, &low, &high); const int64_t low0 = rebase_index(type, 0, assume_int(slice.left)); const int stride = type_width(type_elem(type)); return group_name(value, ctx, start + low0 * stride, n); } case T_RECORD_REF: { tree_t value = tree_value(target); type_t rec = tree_type(value); const int offset = record_field_to_net(rec, tree_ident(target)); return group_name(value, ctx, start + offset, n); } case T_AGGREGATE: case T_LITERAL: // This can appear due to assignments to open ports with a // default value return true; default: fatal_at(tree_loc(target), "tree kind %s not yet supported for offset " "calculation", tree_kind_str(tree_kind(target))); } }
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))); } }