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 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 get_bool_lit(tree_t t, bool v) { tree_t fdecl = tree_ref(t); assert(tree_kind(fdecl) == T_FUNC_DECL); static type_t bool_type = NULL; if (bool_type == NULL) { lib_t std = lib_find("std", true, true); assert(std != NULL); tree_t standard = lib_get(std, ident_new("STD.STANDARD")); assert(standard != NULL); const int ndecls = tree_decls(standard); for (int i = 0; (i < ndecls) && (bool_type == NULL); i++) { tree_t d = tree_decl(standard, i); if (tree_ident(d) == std_bool_i) bool_type = tree_type(d); } assert(bool_type != NULL); } tree_t lit = type_enum_literal(bool_type, v ? 1 : 0); tree_t b = tree_new(T_REF); tree_set_loc(b, tree_loc(t)); tree_set_ref(b, lit); tree_set_type(b, bool_type); tree_set_ident(b, tree_ident(lit)); return b; }
tree_t make_ref(tree_t to) { tree_t t = tree_new(T_REF); tree_set_ident(t, tree_ident(to)); tree_set_ref(t, to); tree_set_type(t, tree_type(to)); return t; }
tree_t get_bool_lit(tree_t t, bool v) { type_t bool_type = tree_type(t); tree_t lit = type_enum_literal(bool_type, v ? 1 : 0); tree_t b = tree_new(T_REF); tree_set_loc(b, tree_loc(t)); tree_set_ref(b, lit); tree_set_type(b, bool_type); tree_set_ident(b, tree_ident(lit)); return b; }
static void elab_context_walk_fn(ident_t name, int kind, void *context) { if (kind == T_PACKAGE) { const elab_ctx_t *ctx = (elab_ctx_t *)context; if (!elab_have_context(ctx->out, name)) { tree_t c = tree_new(T_USE); tree_set_ident(c, name); tree_set_ident2(c, all_i); elab_add_context(c, ctx); } } }
tree_t str_to_literal(const char *start, const char *end, type_t type) { tree_t t = tree_new(T_LITERAL); tree_set_subkind(t, L_STRING); type_t elem = NULL; if (type != NULL) { tree_set_type(t, type); elem = type_elem(type); } char last = '\0'; for (const char *p = start; *p != '\0' && p != end; p++) { if (*p == -127) continue; else if (*p == '"' && last == '"') { last = '\0'; continue; } else last = *p; const char ch[] = { '\'', *p, '\'', '\0' }; ident_t id = ident_new(ch); tree_t ref = tree_new(T_REF); tree_set_ident(ref, id); tree_add_char(t, ref); if (elem != NULL) { const int nlit = type_enum_literals(elem); for (int i = 0; i < nlit; i++) { tree_t lit = type_enum_literal(elem, i); if (tree_ident(lit) == id) { tree_set_ref(ref, lit); break; } } } } return t; }
static void elab_pseudo_context(tree_t out, tree_t src) { // Add a pseudo use clause for an entity or architecture so the // makefile generator can find the dependencies ident_t name = tree_ident(src); const int nctx = tree_contexts(out); for (int i = 0; i < nctx; i++) { tree_t c = tree_context(out, i); if (tree_kind(c) != T_USE) continue; else if (tree_ident(c) == name) return; } tree_t c = tree_new(T_USE); tree_set_ident(c, name); tree_add_context(out, c); }
static tree_t str_to_agg(const char *p, const char *end) { tree_t t = tree_new(T_AGGREGATE); unsigned len = 0; while (*p != '\0' && p != end) { const char ch[] = { '\'', *p++, '\'', '\0' }; tree_t ref = tree_new(T_REF); tree_set_ident(ref, ident_new(ch)); tree_t a = tree_new(T_ASSOC); tree_set_subkind(a, A_POS); tree_set_value(a, ref); tree_add_assoc(t, a); ++len; } tree_t left = tree_new(T_LITERAL); tree_set_subkind(left, L_INT); tree_set_ival(left, 0); tree_t right = tree_new(T_LITERAL); tree_set_subkind(right, L_INT); tree_set_ival(right, len - 1); type_t type = type_new(T_CARRAY); type_set_ident(type, ident_new("string")); type_set_elem(type, type_universal_int()); range_t r = { .kind = RANGE_DOWNTO, .left = left, .right = right }; type_add_dim(type, r); tree_set_type(t, type); return t; }
END_TEST START_TEST(test_lib_save) { { tree_t ent = tree_new(T_ENTITY); tree_set_ident(ent, ident_new("name")); tree_add_attr_str(ent, ident_new("attr"), ident_new("test string")); type_t e = type_new(T_ENUM); type_set_ident(e, ident_new("myenum")); tree_t a = tree_new(T_ENUM_LIT); tree_set_ident(a, ident_new("a")); tree_set_type(a, e); tree_set_pos(a, 55); type_enum_add_literal(e, a); tree_t b = tree_new(T_ENUM_LIT); tree_set_ident(b, ident_new("b")); tree_set_type(b, e); type_enum_add_literal(e, b); tree_t p1 = tree_new(T_PORT_DECL); tree_set_ident(p1, ident_new("foo")); tree_set_subkind(p1, PORT_OUT); tree_set_type(p1, type_universal_int()); tree_add_port(ent, p1); tree_t p2 = tree_new(T_PORT_DECL); tree_set_ident(p2, ident_new("bar")); tree_set_subkind(p2, PORT_IN); tree_set_type(p2, e); tree_add_port(ent, p2); tree_t ar = tree_new(T_ARCH); tree_set_ident(ar, ident_new("arch")); tree_set_ident2(ar, ident_new("foo")); tree_t pr = tree_new(T_PROCESS); tree_set_ident(pr, ident_new("proc")); tree_add_stmt(ar, pr); tree_t v1 = tree_new(T_VAR_DECL); tree_set_ident(v1, ident_new("v1")); tree_set_type(v1, e); tree_t r = tree_new(T_REF); tree_set_ident(r, ident_new("v1")); tree_set_ref(r, v1); tree_t s = tree_new(T_VAR_ASSIGN); tree_set_ident(s, ident_new("var_assign")); tree_set_target(s, r); tree_set_value(s, r); tree_add_stmt(pr, s); tree_t c = tree_new(T_LITERAL); tree_set_subkind(c, L_INT); tree_set_ival(c, 53); tree_t s2 = tree_new(T_VAR_ASSIGN); tree_set_ident(s2, ident_new("var_assign")); tree_set_target(s2, r); tree_set_value(s2, c); tree_add_stmt(pr, s2); tree_t s3 = tree_new(T_VAR_ASSIGN); tree_set_ident(s3, ident_new("var_assign")); tree_set_target(s3, r); tree_set_value(s3, str_to_agg("foobar", NULL)); tree_add_stmt(pr, s3); tree_t s4 = tree_new(T_ASSERT); tree_set_ident(s4, ident_new("assert")); tree_set_value(s4, c); tree_set_severity(s4, c); tree_set_message(s4, str_to_agg("message", NULL)); tree_add_stmt(pr, s4); lib_put(work, ar); lib_put(work, ent); } tree_gc(); lib_save(work); lib_free(work); lib_add_search_path("/tmp"); work = lib_find(ident_new("test_lib"), false); fail_if(work == NULL); { tree_t ent = lib_get(work, ident_new("name")); fail_if(ent == NULL); fail_unless(tree_kind(ent) == T_ENTITY); fail_unless(tree_ident(ent) == ident_new("name")); fail_unless(tree_ports(ent) == 2); ident_t attr = tree_attr_str(ent, ident_new("attr")); fail_if(attr == NULL); fail_unless(icmp(attr, "test string")); tree_t p1 = tree_port(ent, 0); fail_unless(tree_kind(p1) == T_PORT_DECL); fail_unless(tree_subkind(p1) == PORT_OUT); fail_unless(type_kind(tree_type(p1)) == T_INTEGER); tree_t p2 = tree_port(ent, 1); fail_unless(tree_kind(p2) == T_PORT_DECL); fail_unless(tree_subkind(p2) == PORT_IN); type_t e = tree_type(p2); fail_unless(type_kind(e) == T_ENUM); fail_unless(type_enum_literals(e) == 2); tree_t a = type_enum_literal(e, 0); fail_unless(tree_kind(a) == T_ENUM_LIT); fail_unless(tree_ident(a) == ident_new("a")); fail_unless(tree_type(a) == e); fail_unless(tree_pos(a) == 55); tree_t b = type_enum_literal(e, 1); fail_unless(tree_kind(b) == T_ENUM_LIT); fail_unless(tree_ident(b) == ident_new("b")); fail_unless(tree_type(b) == e); tree_t ar = lib_get(work, ident_new("arch")); fail_if(ar == NULL); fail_unless(tree_ident(ar) == ident_new("arch")); fail_unless(tree_ident2(ar) == ident_new("foo")); tree_t pr = tree_stmt(ar, 0); fail_unless(tree_kind(pr) == T_PROCESS); fail_unless(tree_ident(pr) == ident_new("proc")); tree_t s = tree_stmt(pr, 0); fail_unless(tree_kind(s) == T_VAR_ASSIGN); tree_t r = tree_target(s); fail_unless(tree_kind(r) == T_REF); fail_unless(tree_value(s) == r); tree_t s2 = tree_stmt(pr, 1); fail_unless(tree_kind(s2) == T_VAR_ASSIGN); fail_unless(tree_target(s2) == r); tree_t s3 = tree_stmt(pr, 2); fail_unless(tree_kind(s3) == T_VAR_ASSIGN); fail_unless(tree_target(s3) == r); fail_unless(tree_kind(tree_value(s3)) == T_AGGREGATE); tree_t s4 = tree_stmt(pr, 3); fail_unless(tree_kind(s4) == T_ASSERT); fail_unless(tree_ident(s4) == ident_new("assert")); tree_t c = tree_value(s2); fail_unless(tree_kind(c) == T_LITERAL); fail_unless(tree_subkind(c) == L_INT); fail_unless(tree_ival(c) == 53); // Type declaration and reference written to different units // so two copies of the type declaration will be read back // hence can't check for pointer equality here fail_unless(type_eq(tree_type(tree_ref(r)), e)); } }
tree_t call_builtin(const char *builtin, type_t type, ...) { struct decl_cache { struct decl_cache *next; ident_t bname; tree_t decl; }; char *name = xasprintf("NVC.BUILTIN.%s", builtin); for (char *p = name; *p != '\0'; p++) *p = toupper((int)*p); static struct decl_cache *cache = NULL; ident_t bname = ident_new(builtin); ident_t name_i = ident_new(name); free(name); struct decl_cache *it; tree_t decl = NULL; for (it = cache; it != NULL; it = it->next) { if (it->bname == bname) { decl = it->decl; break; } } if (decl == NULL) { decl = tree_new(T_FUNC_DECL); tree_set_ident(decl, name_i); tree_add_attr_str(decl, builtin_i, ident_new(builtin)); } struct decl_cache *c = xmalloc(sizeof(struct decl_cache)); c->next = cache; c->bname = bname; c->decl = decl; cache = c; tree_t call = tree_new(T_FCALL); tree_set_ident(call, name_i); tree_set_ref(call, decl); if (type != NULL) tree_set_type(call, type); va_list ap; va_start(ap, type); tree_t arg; while ((arg = va_arg(ap, tree_t))) { tree_t p = tree_new(T_PARAM); tree_set_value(p, arg); tree_set_loc(p, tree_loc(arg)); tree_set_subkind(p, P_POS); tree_add_param(call, p); } va_end(ap); return call; }