type_t array_aggregate_type(type_t array, int from_dim) { if (type_is_unconstrained(array)) { const int nindex = type_index_constrs(array); assert(from_dim < nindex); type_t type = type_new(T_UARRAY); type_set_ident(type, type_ident(array)); type_set_elem(type, type_elem(array)); for (int i = from_dim; i < nindex; i++) type_add_index_constr(type, type_index_constr(array, i)); return type; } else { const int ndims = type_dims(array); assert(from_dim < ndims); type_t type = type_new(T_CARRAY); type_set_ident(type, type_ident(array)); type_set_elem(type, type_elem(array)); for (int i = from_dim; i < ndims; i++) type_add_dim(type, type_dim(array, i)); return type; } }
bool type_is_unconstrained(type_t t) { assert(t != NULL); if (t->kind == T_SUBTYPE) { if (type_dims(t) == 0) return type_is_unconstrained(type_base(t)); else return false; } else return (t->kind == T_UARRAY); }
void type_replace(type_t t, type_t a) { assert(t != NULL); assert(IS(t, T_INCOMPLETE)); t->kind = a->kind; t->ident = a->ident; const imask_t has = has_map[t->kind]; if (has & I_DIMS) { const int ndims = type_dims(a); for (int i = 0; i < ndims; i++) type_add_dim(t, type_dim(a, i)); } switch (a->kind) { case T_UARRAY: for (unsigned i = 0; i < type_index_constrs(a); i++) type_add_index_constr(t, type_index_constr(a, i)); // Fall-through case T_CARRAY: type_set_elem(t, type_elem(a)); break; case T_SUBTYPE: type_set_base(t, type_base(a)); break; case T_FUNC: type_set_result(t, type_result(a)); break; case T_INTEGER: case T_REAL: break; case T_ENUM: for (unsigned i = 0; i < type_enum_literals(a); i++) type_enum_add_literal(t, type_enum_literal(a, i)); break; case T_RECORD: for (unsigned i = 0; i < type_fields(a); i++) type_add_field(t, type_field(a, i)); break; default: assert(false); } }
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; }
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 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); }
unsigned array_dimension(type_t a) { return (type_is_unconstrained(a) ? type_index_constrs(type_base_recur(a)) : type_dims(a)); }
tree_t make_default_value(type_t type, const loc_t *loc) { type_t base = type_base_recur(type); switch (type_kind(base)) { case T_UARRAY: assert(type_kind(type) == T_SUBTYPE); // Fall-through case T_CARRAY: { tree_t def = NULL; const int ndims = type_dims(type); for (int i = ndims - 1; i >= 0; i--) { tree_t val = (def ? def : make_default_value(type_elem(base), loc)); def = tree_new(T_AGGREGATE); tree_set_type(def, array_aggregate_type(type, i)); tree_t a = tree_new(T_ASSOC); tree_set_subkind(a, A_OTHERS); tree_set_value(a, val); tree_add_assoc(def, a); } tree_set_type(def, type); tree_set_loc(def, loc); return def; } case T_INTEGER: case T_PHYSICAL: case T_REAL: return type_dim(type, 0).left; case T_ENUM: { int64_t val = 0; const bool folded = folded_int(type_dim(type, 0).left, &val); if (folded) return make_ref(type_enum_literal(base, (unsigned) val)); else return type_dim(type, 0).left; } case T_RECORD: { tree_t def = tree_new(T_AGGREGATE); tree_set_loc(def, loc); const int nfields = type_fields(base); for (int i = 0; i < nfields; i++) { tree_t field = type_field(base, i); tree_t a = tree_new(T_ASSOC); tree_set_subkind(a, A_POS); tree_set_value(a, make_default_value(tree_type(field), tree_loc(field))); tree_add_assoc(def, a); } tree_set_type(def, type); return def; } case T_ACCESS: { tree_t null = tree_new(T_LITERAL); tree_set_loc(null, loc); tree_set_subkind(null, L_NULL); tree_set_type(null, type); return null; } case T_UNRESOLVED: return NULL; default: fatal_trace("cannot handle type %s in %s", type_kind_str(type_kind(base)), __func__); } }
bool type_eq(type_t a, type_t b) { assert(a != NULL); assert(b != NULL); type_kind_t kind_a = type_kind(a); type_kind_t kind_b = type_kind(b); if ((kind_a == T_UNRESOLVED) || (kind_b == T_UNRESOLVED)) return false; if (a == b) return true; // Subtypes are convertible to the base type while ((kind_a = type_kind(a)) == T_SUBTYPE) a = type_base(a); while ((kind_b = type_kind(b)) == T_SUBTYPE) b = type_base(b); const bool compare_c_u_arrays = (kind_a == T_CARRAY && kind_b == T_UARRAY) || (kind_a == T_UARRAY && kind_b == T_CARRAY); if ((kind_a != kind_b) && !compare_c_u_arrays) return false; // Universal integer type is equal to any other integer type type_t universal_int = type_universal_int(); ident_t uint_i = type_ident(universal_int); if (kind_a == T_INTEGER && (type_ident(a) == uint_i || type_ident(b) == uint_i)) return true; // Universal real type is equal to any other real type type_t universal_real = type_universal_real(); ident_t ureal_i = type_ident(universal_real); if (kind_a == T_REAL && (type_ident(a) == ureal_i || type_ident(b) == ureal_i)) return true; // XXX: this is not quite right as structurally equivalent types // may be declared in different scopes with the same name but // shouldn't compare equal if (type_ident(a) != type_ident(b)) return false; // Access types are equal if the pointed to type is the same if (kind_a == T_ACCESS) return type_eq(type_access(a), type_access(b)); if (compare_c_u_arrays) return type_eq(type_elem(a), type_elem(b)); const imask_t has = has_map[a->kind]; if ((has & I_DIMS) && (type_dims(a) != type_dims(b))) return false; if (type_kind(a) == T_FUNC) { if (!type_eq(type_result(a), type_result(b))) return false; } if (has & I_PARAMS) { if (type_params(a) != type_params(b)) return false; const int nparams = type_params(a); for (int i = 0; i < nparams; i++) { if (!type_eq(type_param(a, i), type_param(b, i))) return false; } } return true; }
tree_t make_default_value(type_t type, const loc_t *loc) { type_t base = type_base_recur(type); switch (type_kind(base)) { case T_UARRAY: assert(type_kind(type) == T_SUBTYPE); // Fall-through case T_CARRAY: { tree_t def = NULL; const int ndims = type_dims(type); for (int i = ndims - 1; i >= 0; i--) { tree_t val = (def ? def : make_default_value(type_elem(base), loc)); def = tree_new(T_AGGREGATE); tree_set_type(def, array_aggregate_type(type, i)); tree_t a = tree_new(T_ASSOC); tree_set_subkind(a, A_OTHERS); tree_set_value(a, val); tree_add_assoc(def, a); } tree_set_type(def, type); tree_set_loc(def, loc); return def; } case T_INTEGER: case T_PHYSICAL: case T_REAL: return type_dim(type, 0).left; case T_ENUM: return make_ref(type_enum_literal(base, 0)); case T_RECORD: { tree_t def = tree_new(T_AGGREGATE); tree_set_loc(def, loc); const int nfields = type_fields(base); for (int i = 0; i < nfields; i++) { tree_t field = type_field(base, i); tree_t a = tree_new(T_ASSOC); tree_set_subkind(a, A_POS); tree_set_value(a, make_default_value(tree_type(field), tree_loc(field))); tree_add_assoc(def, a); } tree_set_type(def, type); return def; } case T_ACCESS: { tree_t null = tree_new(T_LITERAL); tree_set_loc(null, loc); tree_set_subkind(null, L_NULL); tree_set_type(null, type); return null; } default: assert(false); } }