static int group_net_to_field(type_t type, netid_t nid) { int count = 0; if (type_is_record(type)) { const int nfields = type_fields(type); netid_t first = 0; for (int i = 0; i < nfields; i++) { tree_t field = type_field(type, i); type_t ftype = tree_type(field); const netid_t next = first + type_width(tree_type(field)); if (nid >= first && nid < next) { if (type_is_array(ftype) || type_is_record(ftype)) return count + group_net_to_field(ftype, nid - first); else return count; } first = next; count += type_width(ftype); } fatal_trace("group_net_to_field failed to find field for nid=%d type=%s", nid, type_pp(type)); } else if (type_is_array(type)) { type_t elem = type_elem(type); const int width = type_width(elem); if (type_is_record(elem)) return (nid / width) * width + group_net_to_field(elem, nid % width); else return group_net_to_field(elem, nid % width); } else return 0; }
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 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 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; }
static void lxt_fmt_enum(tree_t decl, watch_t *w, lxt_data_t *data) { uint64_t val; rt_watch_value(w, &val, 1, false); tree_t lit = type_enum_literal(tree_type(decl), val); lt_emit_value_string(trace, data->sym, 0, (char *)istr(tree_ident(lit))); }
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; }
static int shell_cmd_watch(ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { const char *help = "watch - Trace changes to a signal\n" "\n" "Usage: watch SIGNALS...\n" "\n" "Prints a message every time an update occurs to a signal listed." "\n" "Examples:\n" " watch [signals {clk}] Trace updates to all signals named clk\n"; if (show_help(objc, objv, help)) return TCL_OK; if (objc == 1) { warnf("nothing to watch (try -help for usage)"); return TCL_OK; } hash_t *decl_hash = (hash_t *)cd; for (int i = 1; i < objc; i++) { int length; if (Tcl_ListObjLength(interp, objv[i], &length) != TCL_OK) return TCL_ERROR; for (int j = 0; j < length; j++) { Tcl_Obj *obj; if (Tcl_ListObjIndex(interp, objv[i], j, &obj) != TCL_OK) return TCL_ERROR; const char *str = Tcl_GetString(obj); tree_t t = hash_get(decl_hash, ident_new(str)); if (t == NULL) return tcl_error(interp, "object not found: %s", str); if (t == NULL) return tcl_error(interp, "object not found: %s", str); else if (tree_kind(t) != T_SIGNAL_DECL) return tcl_error(interp, "not a signal: %s", str); else if (type_is_array(tree_type(t))) return tcl_error(interp, "only scalar signals may be watched"); // TODO: make this work for arrays slave_watch_msg_t msg = { .index = tree_index(t) }; slave_post_msg(SLAVE_WATCH, &msg, sizeof(msg)); } } return TCL_OK; }
tree_t get_real_lit(tree_t t, double r) { tree_t f = tree_new(T_LITERAL); tree_set_loc(f, tree_loc(t)); tree_set_subkind(f, L_REAL); tree_set_dval(f, r); tree_set_type(f, tree_type(t)); return f; }
tree_t get_int_lit(tree_t t, int64_t i) { tree_t f = tree_new(T_LITERAL); tree_set_subkind(f, L_INT); tree_set_ival(f, i); tree_set_loc(f, tree_loc(t)); tree_set_type(f, tree_type(t)); return f; }
static void fst_fmt_enum(tree_t decl, watch_t *w, fst_data_t *data) { uint64_t val; rt_watch_value(w, &val, 1, false); tree_t lit = type_enum_literal(tree_type(decl), val); const char *str = istr(tree_ident(lit)); fstWriterEmitVariableLengthValueChange( fst_ctx, data->handle, str, strlen(str)); }
/// Is the block b readable by the grid readers? inline bool is_readable(io::json const& b) { string type_str = io::read_field(b, "type", HM3_AT_); if (type_str == tree_type()) { return true; // } else if (type_str == single_type()) { // return true; } else if (type_str == multi_type()) { return true; } else { return false; } }
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; }
bool folded_bool(tree_t t, bool *b) { if (tree_kind(t) == T_REF) { tree_t decl = tree_ref(t); if (tree_kind(decl) == T_ENUM_LIT && type_ident(tree_type(decl)) == std_bool_i) { *b = (tree_pos(decl) == 1); return true; } } return false; }
type_t index_type_of(type_t type, int dim) { if (type_is_unconstrained(type)) return type_index_constr(type_base_recur(type), dim); else if (type_kind(type) == T_ENUM) return type; else { tree_t left = type_dim(type, dim).left; // If the left bound has not been assigned a type then there is some // error with it so just return a dummy type here return tree_has_type(left) ? tree_type(left) : type; } }
tree_t find_record_field(tree_t rref) { ident_t fname = tree_ident(rref); type_t value_type = tree_type(tree_value(rref)); const int nfields = type_fields(value_type); for (int i = 0; i < nfields; i++) { tree_t field = type_field(value_type, i); if (tree_ident(field) == fname) return field; } return NULL; }
bool folded_bool(tree_t t, bool *b) { ident_t std_bool_i = ident_new("STD.STANDARD.BOOLEAN"); if (tree_kind(t) == T_REF) { tree_t decl = tree_ref(t); if (tree_kind(decl) == T_ENUM_LIT && type_ident(tree_type(decl)) == std_bool_i) { *b = (tree_pos(decl) == 1); return true; } } return false; }
int record_field_to_net(type_t type, ident_t name) { int offset = 0; const int nfields = type_fields(type); for (int i = 0; i < nfields; i++) { tree_t field = type_field(type, i); if (tree_ident(field) == name) return offset; else offset += type_width(tree_type(field)); } assert(false); }
static STATEMENT *reduce_statement(MODULE *module, FUNCTION *func, BLOCK *block, STATEMENT *stmt) { if (stmt == NULL) return stmt; if (tree_is_type(stmt, STMT_ASSIGN)) { EXPRESSION *expr = tree_get_child(stmt, 1); expr = simplify_expression(module, func, block, expr, stmt); tree_get_child(stmt, 1) = expr; } else if (tree_is_type(stmt, STMT_IF)) { EXPRESSION *cond = tree_get_child(stmt, 0); cond = simplify_expression(module, func, block, cond, stmt); tree_get_child(stmt, 0) = cond; reduce_block(module, func, tree_get_child(stmt, 1)); reduce_block(module, func, tree_get_child(stmt, 2)); } else if (tree_is_type(stmt, STMT_WHILE)) { EXPRESSION *cond = tree_get_child(stmt, 0); BLOCK *body = tree_get_child(stmt, 1); if (!is_atomic(cond)) { EXPRESSION *old_cond = cond; cond = atomise_expression(module, func, block, cond, stmt); tree_get_child(stmt, 0) = cond; STATEMENT *new_assign = make_assignment(cond, CAST_TO_EXPRESSION(tree_copy(old_cond)), CAST_TO_AST(cond)->source_line); tree_add_child(body, new_assign); } reduce_block(module, func, body); } else if (tree_is_type(stmt, STMT_RETURN)) { EXPRESSION *expr = tree_get_child(stmt, 0); expr = atomise_expression(module, func, block, expr, stmt); tree_get_child(stmt, 0) = expr; } else if (tree_is_type(stmt, STMT_RESTART)) { /* Do nothing. */ } else error("Not sure how to reduce statement of type %d\n", tree_type(stmt)); return stmt; }
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; }
char *get_escaped_op_symbol(EXPRESSION *expr) { switch (tree_type(expr)) { case EXPR_LEQ: return "<="; case EXPR_GEQ: return ">="; case EXPR_LT: return "<"; case EXPR_GT: return ">"; case EXPR_AND: return "&&"; default: return get_op_symbol(expr); } }
static void group_target(tree_t t, group_nets_ctx_t *ctx) { switch (tree_kind(t)) { case T_REF: group_ref(t, ctx, 0, -1); break; case T_ARRAY_REF: case T_ARRAY_SLICE: case T_RECORD_REF: { type_t type = tree_type(t); if (!type_known_width(type)) ungroup_name(t, ctx); else if (!group_name(t, ctx, 0, type_width(type))) ungroup_name(t, ctx); } break; case T_LITERAL: case T_OPEN: // Constant folding can cause this to appear break; case T_AGGREGATE: { const int nassocs = tree_assocs(t); for (int i = 0; i < nassocs; i++) group_target(tree_value(tree_assoc(t, i)), ctx); } break; default: fmt_loc(stdout, tree_loc(t)); fatal_trace("Cannot handle tree kind %s in group_target", tree_kind_str(tree_kind(t))); } }
unsigned type_width(type_t type) { if (type_is_array(type)) { const unsigned elem_w = type_width(type_elem(type)); unsigned w = 1; const int ndims = type_dims(type); for (int i = 0; i < ndims; i++) { int64_t low, high; range_bounds(type_dim(type, i), &low, &high); w *= MAX(high - low + 1, 0) * elem_w; } return w; } else if (type_is_record(type)) { type_t base = type_base_recur(type); unsigned w = 0; const int nfields = type_fields(base); for (int i = 0; i < nfields; i++) w += type_width(tree_type(type_field(base, i))); return w; } else return 1; }
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)); } }
static void vcd_process_signal(tree_t d, int *next_key) { type_t type = tree_type(d); type_t base = type_base_recur(type); vcd_data_t *data = xmalloc(sizeof(vcd_data_t)); memset(data, '\0', sizeof(vcd_data_t)); int msb = 0, lsb = 0; if (type_is_array(type)) { if (type_dims(type) > 1) { warn_at(tree_loc(d), "cannot represent multidimensional arrays " "in VCD format"); free(data); return; } range_t r = type_dim(type, 0); int64_t low, high; range_bounds(r, &low, &high); data->dir = r.kind; data->size = high - low + 1; msb = assume_int(r.left); lsb = assume_int(r.right); type_t elem = type_elem(type); if (!vcd_can_fmt_chars(elem, data)) { warn_at(tree_loc(d), "cannot represent arrays of type %s " "in VCD format", type_pp(elem)); free(data); return; } } else { switch (type_kind(base)) { case T_INTEGER: { int64_t low, high; range_bounds(type_dim(type, 0), &low, &high); data->size = ilog2(high - low + 1); data->fmt = vcd_fmt_int; } break; case T_ENUM: if (vcd_can_fmt_chars(type, data)) { data->size = 1; break; } // Fall-through default: warn_at(tree_loc(d), "cannot represent type %s in VCD format", type_pp(type)); free(data); return; } } const char *name_base = strrchr(istr(tree_ident(d)), ':') + 1; const size_t base_len = strlen(name_base); char name[base_len + 64]; strncpy(name, name_base, base_len + 64); if (type_is_array(type)) snprintf(name + base_len, 64, "[%d:%d]\n", msb, lsb); tree_add_attr_ptr(d, vcd_data_i, data); data->watch = rt_set_event_cb(d, vcd_event_cb, data, true); vcd_key_fmt(*next_key, data->key); fprintf(vcd_file, "$var reg %d %s %s $end\n", (int)data->size, data->key, name); ++(*next_key); }
void lxt_restart(void) { if (trace == NULL) return; lt_set_timescale(trace, -15); lt_symbol_bracket_stripping(trace, 0); lt_set_clock_compress(trace); const int ndecls = tree_decls(lxt_top); for (int i = 0; i < ndecls; i++) { tree_t d = tree_decl(lxt_top, i); if (tree_kind(d) != T_SIGNAL_DECL) continue; else if (!wave_should_dump(d)) continue; type_t type = tree_type(d); int rows, msb, lsb; if (type_is_array(type)) { rows = type_dims(type) - 1; if ((rows > 0) || type_is_array(type_elem(type))) { warn_at(tree_loc(d), "cannot emit arrays of greater than one " "dimension or arrays of arrays in LXT yet"); continue; } range_t r = type_dim(type, 0); msb = assume_int(r.left); lsb = assume_int(r.right); } else { rows = 0; msb = lsb = -1; } lxt_data_t *data = xmalloc(sizeof(lxt_data_t)); memset(data, '\0', sizeof(lxt_data_t)); int flags = 0; if (type_is_array(type)) { // Only arrays of CHARACTER, BIT, STD_ULOGIC are supported type_t elem = type_base_recur(type_elem(type)); if ((type_kind(elem) != T_ENUM) || !lxt_can_fmt_enum_chars(elem, data, &flags)) { warn_at(tree_loc(d), "cannot represent arrays of type %s " "in LXT format", type_pp(elem)); free(data); continue; } data->dir = type_dim(type, 0).kind; } else { type_t base = type_base_recur(type); switch (type_kind(base)) { case T_INTEGER: data->fmt = lxt_fmt_int; flags = LT_SYM_F_INTEGER; break; case T_ENUM: if (!lxt_can_fmt_enum_chars(base, data, &flags)) { data->fmt = lxt_fmt_enum; flags = LT_SYM_F_STRING; } break; default: warn_at(tree_loc(d), "cannot represent type %s in LXT format", type_pp(type)); free(data); continue; } } char *name = lxt_fmt_name(d); data->sym = lt_symbol_add(trace, name, rows, msb, lsb, flags); free(name); tree_add_attr_ptr(d, lxt_data_i, data); watch_t *w = rt_set_event_cb(d, lxt_event_cb, data, true); (*data->fmt)(d, w, data); } last_time = (lxttime_t)-1; }
static int shell_cmd_show(ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { const char *help = "show - Display simulation objects\n" "\n" "Usage: show LIST...\n" "\n" "Prints a representation of each simulation object in LIST. Typically\n" "this will be a list of signal names and the output will show their\n" "current value.\n" "\n" "Examples:\n" " show {:top:foo} Print value of signal :top_foo\n" " show [signals] Print value of all signals\n"; if (show_help(objc, objv, help)) return TCL_OK; if (objc == 1) { warnf("nothing to show (try -help for usage)"); return TCL_OK; } hash_t *decl_hash = (hash_t *)cd; for (int i = 1; i < objc; i++) { int length; if (Tcl_ListObjLength(interp, objv[i], &length) != TCL_OK) return TCL_ERROR; for (int j = 0; j < length; j++) { Tcl_Obj *obj; if (Tcl_ListObjIndex(interp, objv[i], j, &obj) != TCL_OK) return TCL_ERROR; const char *str = Tcl_GetString(obj); tree_t t = hash_get(decl_hash, ident_new(str)); if (t == NULL) return tcl_error(interp, "object not found: %s", str); tree_kind_t kind = tree_kind(t); switch (kind) { case T_SIGNAL_DECL: { const size_t len = tree_nets(t); uint64_t *values LOCAL = xmalloc(len * sizeof(uint64_t)); rt_signal_value(t, values, len); const char *type_str = type_pp(tree_type(t)); const char *short_name = strrchr(type_str, '.'); LOCAL_TEXT_BUF values_tb = pprint(t, values, len); printf("%-30s%-20s%s\n", str, (short_name != NULL ? short_name + 1 : type_str), tb_get(values_tb)); } break; default: return tcl_error(interp, "cannot show tree kind %s", tree_kind_str(kind)); } } } return TCL_OK; }
static void fst_process_signal(tree_t d) { type_t type = tree_type(d); type_t base = type_base_recur(type); fst_data_t *data = xmalloc(sizeof(fst_data_t)); memset(data, '\0', sizeof(fst_data_t)); int msb = 0, lsb = 0; enum fstVarType vt; enum fstSupplementalDataType sdt; if (type_is_array(type)) { if (type_dims(type) > 1) { warn_at(tree_loc(d), "cannot represent multidimensional arrays " "in FST format"); free(data); return; } range_t r = type_dim(type, 0); int64_t low, high; range_bounds(r, &low, &high); data->dir = r.kind; data->size = high - low + 1; msb = assume_int(r.left); lsb = assume_int(r.right); type_t elem = type_elem(type); if (!fst_can_fmt_chars(elem, data, &vt, &sdt)) { warn_at(tree_loc(d), "cannot represent arrays of type %s " "in FST format", type_pp(elem)); free(data); return; } else { ident_t ident = type_ident(base); if (ident == unsigned_i) sdt = FST_SDT_VHDL_UNSIGNED; else if (ident == signed_i) sdt = FST_SDT_VHDL_SIGNED; } } else { switch (type_kind(base)) { case T_INTEGER: { ident_t ident = type_ident(type); if (ident == natural_i) sdt = FST_SDT_VHDL_NATURAL; else if (ident == positive_i) sdt = FST_SDT_VHDL_POSITIVE; else sdt = FST_SDT_VHDL_INTEGER; int64_t low, high; range_bounds(type_dim(type, 0), &low, &high); vt = FST_VT_VCD_INTEGER; data->size = ilog2(high - low + 1); data->fmt = fst_fmt_int; } break; case T_ENUM: if (!fst_can_fmt_chars(type, data, &vt, &sdt)) { ident_t ident = type_ident(base); if (ident == std_bool_i) sdt = FST_SDT_VHDL_BOOLEAN; else if (ident == std_char_i) sdt = FST_SDT_VHDL_CHARACTER; else sdt = FST_SDT_NONE; vt = FST_VT_GEN_STRING; data->size = 0; data->fmt = fst_fmt_enum; } else data->size = 1; break; case T_PHYSICAL: { sdt = FST_SDT_NONE; vt = FST_VT_GEN_STRING; data->size = 0; data->type.units = fst_make_unit_map(type); data->fmt = fst_fmt_physical; } break; default: warn_at(tree_loc(d), "cannot represent type %s in FST format", type_pp(type)); free(data); return; } } enum fstVarDir dir = FST_VD_IMPLICIT; switch (tree_attr_int(d, fst_dir_i, -1)) { case PORT_IN: dir = FST_VD_INPUT; break; case PORT_OUT: dir = FST_VD_OUTPUT; break; case PORT_INOUT: dir = FST_VD_INOUT; break; case PORT_BUFFER: dir = FST_VD_BUFFER; break; } const char *name_base = strrchr(istr(tree_ident(d)), ':') + 1; const size_t base_len = strlen(name_base); char name[base_len + 64]; strncpy(name, name_base, base_len + 64); if (type_is_array(type)) snprintf(name + base_len, 64, "[%d:%d]\n", msb, lsb); data->handle = fstWriterCreateVar2( fst_ctx, vt, dir, data->size, name, 0, type_pp(type), FST_SVT_VHDL_SIGNAL, sdt); tree_add_attr_ptr(d, fst_data_i, data); data->watch = rt_set_event_cb(d, fst_event_cb, data, true); }
static int shell_cmd_show(ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { const char *help = "show - Display simulation objects\n" "\n" "Usage: show LIST...\n" "\n" "Prints a representation of each simulation object in LIST. Typically\n" "this will be a list of signal names and the output will show their\n" "current value.\n" "\n" "Examples:\n" " show {:top:foo} Print value of signal :top_foo\n" " show [signals] Print value of all signals\n"; if (show_help(objc, objv, help)) return TCL_OK; if (objc == 1) { warnf("nothing to show (try -help for usage)"); return TCL_OK; } hash_t *decl_hash = (hash_t *)cd; for (int i = 1; i < objc; i++) { int length; if (Tcl_ListObjLength(interp, objv[i], &length) != TCL_OK) return TCL_ERROR; for (int j = 0; j < length; j++) { Tcl_Obj *obj; if (Tcl_ListObjIndex(interp, objv[i], j, &obj) != TCL_OK) return TCL_ERROR; const char *str = Tcl_GetString(obj); tree_t t = hash_get(decl_hash, ident_new(str)); if (t == NULL) return tcl_error(interp, "object not found: %s", str); tree_kind_t kind = tree_kind(t); switch (kind) { case T_SIGNAL_DECL: { size_t len = 1; type_t type = tree_type(t); while (type_is_array(type)) { int64_t low = 0, high = 0; range_bounds(type_dim(type, 0), &low, &high); len *= (high - low + 1); type = type_elem(type); } slave_read_signal_msg_t msg = { .index = tree_index(t), .len = len }; slave_post_msg(SLAVE_READ_SIGNAL, &msg, sizeof(msg)); const size_t rsz = sizeof(reply_read_signal_msg_t) + (msg.len * sizeof(uint64_t)); reply_read_signal_msg_t *reply = xmalloc(rsz); slave_get_reply(REPLY_READ_SIGNAL, reply, rsz); const char *type_str = type_pp(type); const char *short_name = strrchr(type_str, '.'); printf("%-30s%-20s%s\n", str, (short_name != NULL ? short_name + 1 : type_str), pprint(t, reply->values, msg.len)); free(reply); } break; default: return tcl_error(interp, "cannot show tree kind %s", tree_kind_str(kind)); } } } return TCL_OK; }
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))); } }