From c15de4ad52a1703f149cb2cab99157b42ee87c7c Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sun, 5 Feb 2023 11:18:00 +0000 Subject: [PATCH] Refactor translation of 'DELAYED implicit signal. Issue #603 --- src/common.c | 14 +++++ src/common.h | 1 + src/dump.c | 27 ++++++---- src/jit/jit-dump.c | 2 +- src/jit/jit-exits.c | 9 ++++ src/jit/jit-exits.h | 1 + src/jit/jit-irgen.c | 15 ++++++ src/jit/jit-priv.h | 1 + src/lower.c | 101 +++++++++++++++++++++++++++++++------ src/names.c | 4 +- src/names.h | 3 +- src/parse.c | 75 ++++++++++++++++++++++++++- src/rt/model.c | 52 +++++++++++++++---- src/sem.c | 3 ++ src/simp.c | 17 ------- src/tree.h | 1 + src/vcode.c | 59 ++++++++++++++-------- src/vcode.h | 4 +- test/regress/implicit5.vhd | 38 ++++++++++++++ test/regress/issue603.vhd | 9 ++++ test/regress/testlist.txt | 1 + 21 files changed, 361 insertions(+), 76 deletions(-) create mode 100644 test/regress/implicit5.vhd diff --git a/src/common.c b/src/common.c index a6789c0b..3460b21c 100644 --- a/src/common.c +++ b/src/common.c @@ -611,6 +611,20 @@ bool is_container(tree_t t) } } +bool is_concurrent_block(tree_t t) +{ + switch (tree_kind(t)) { + case T_ARCH: + case T_ENTITY: + case T_BLOCK: + case T_IF_GENERATE: + case T_FOR_GENERATE: + return true; + default: + return false; + } +} + bool is_package(tree_t t) { switch (tree_kind(t)) { diff --git a/src/common.h b/src/common.h index 4b0470d2..054d9597 100644 --- a/src/common.h +++ b/src/common.h @@ -56,6 +56,7 @@ bool unit_needs_cgen(tree_t t); bool package_needs_body(tree_t pack); bool is_subprogram(tree_t t); bool is_container(tree_t t); +bool is_concurrent_block(tree_t t); bool is_package(tree_t t); bool is_guarded_signal(tree_t decl); bool is_type_decl(tree_t t); diff --git a/src/dump.c b/src/dump.c index 062168db..35087a65 100644 --- a/src/dump.c +++ b/src/dump.c @@ -193,6 +193,19 @@ static void dump_address(tree_t t) #endif } +static void dump_waveform(tree_t w) +{ + if (tree_has_value(w)) + dump_expr(tree_value(w)); + else + syntax("#null"); + + if (tree_has_delay(w)) { + syntax(" #after "); + dump_expr(tree_delay(w)); + } +} + static void dump_expr(tree_t t) { switch (tree_kind(t)) { @@ -401,6 +414,10 @@ static void dump_expr(tree_t t) printf("<>"); break; + case T_WAVEFORM: + dump_waveform(t); + break; + default: cannot_dump(t, "expr"); } @@ -929,15 +946,7 @@ static void dump_waveforms(tree_t t) const int nwaves = tree_waveforms(t); for (int i = 0; i < nwaves; i++) { if (i > 0) printf(", "); - tree_t w = tree_waveform(t, i); - if (tree_has_value(w)) - dump_expr(tree_value(w)); - else - syntax("#null"); - if (tree_has_delay(w)) { - syntax(" #after "); - dump_expr(tree_delay(w)); - } + dump_waveform(tree_waveform(t, i)); } } diff --git a/src/jit/jit-dump.c b/src/jit/jit-dump.c index 497fe219..ca963f25 100644 --- a/src/jit/jit-dump.c +++ b/src/jit/jit-dump.c @@ -73,7 +73,7 @@ const char *jit_exit_name(jit_exit_t exit) "MAP_CONST", "RESOLVE_SIGNAL", "LAST_EVENT", "LAST_ACTIVE", "DISCONNECT", "ELAB_ORDER_FAIL", "FORCE", "RELEASE", "PUSH_SCOPE", "POP_SCOPE", "IMPLICIT_SIGNAL", "DRIVING", "DRIVING_VALUE", - "CLAIM_TLAB", "COVER_TOGGLE", + "CLAIM_TLAB", "COVER_TOGGLE", "PROCESS INIT", }; assert(exit < ARRAY_LEN(names)); return names[exit]; diff --git a/src/jit/jit-exits.c b/src/jit/jit-exits.c index a8a412b0..796c1689 100644 --- a/src/jit/jit-exits.c +++ b/src/jit/jit-exits.c @@ -1060,6 +1060,15 @@ void __nvc_do_exit(jit_exit_t which, jit_anchor_t *anchor, jit_scalar_t *args, } break; + case JIT_EXIT_PROCESS_INIT: + { + jit_handle_t handle = args[0].integer; + tree_t where = args[1].pointer; + + x_process_init(handle, where); + } + break; + default: fatal_trace("unhandled exit %s", jit_exit_name(which)); } diff --git a/src/jit/jit-exits.h b/src/jit/jit-exits.h index 8ca09f6d..e7d25ec7 100644 --- a/src/jit/jit-exits.h +++ b/src/jit/jit-exits.h @@ -93,5 +93,6 @@ void x_elab_order_fail(tree_t where); void x_unreachable(tree_t where); void *x_mspace_alloc(size_t size); void x_cover_setup_toggle_cb(sig_shared_t *ss, int32_t *toggle_mask); +void x_process_init(jit_handle_t handle, tree_t where); #endif // _JIT_EXITS_H diff --git a/src/jit/jit-irgen.c b/src/jit/jit-irgen.c index 5b4307e3..bd6fbbb7 100644 --- a/src/jit/jit-irgen.c +++ b/src/jit/jit-irgen.c @@ -2242,6 +2242,18 @@ static void irgen_op_protected_free(jit_irgen_t *g, int op) // TODO: files allowed in protected types } +static void irgen_op_process_init(jit_irgen_t *g, int op) +{ + jit_value_t locus = irgen_get_arg(g, op, 0); + ident_t func = vcode_get_func(op); + + jit_handle_t handle = jit_lazy_compile(g->func->jit, func); + + j_send(g, 0, jit_value_from_handle(handle)); + j_send(g, 1, locus); + macro_exit(g, JIT_EXIT_PROCESS_INIT); +} + static void irgen_op_index_check(jit_irgen_t *g, int op) { jit_value_t value = irgen_get_arg(g, op, 0); @@ -3530,6 +3542,9 @@ static void irgen_block(jit_irgen_t *g, vcode_block_t block) case VCODE_OP_PROTECTED_FREE: irgen_op_protected_free(g, i); break; + case VCODE_OP_PROCESS_INIT: + irgen_op_process_init(g, i); + break; case VCODE_OP_FILE_OPEN: irgen_op_file_open(g, i); break; diff --git a/src/jit/jit-priv.h b/src/jit/jit-priv.h index c22adba8..fb0db241 100644 --- a/src/jit/jit-priv.h +++ b/src/jit/jit-priv.h @@ -155,6 +155,7 @@ typedef enum { JIT_EXIT_DRIVING_VALUE, JIT_EXIT_CLAIM_TLAB, JIT_EXIT_COVER_TOGGLE, + JIT_EXIT_PROCESS_INIT, } jit_exit_t; typedef uint16_t jit_reg_t; diff --git a/src/lower.c b/src/lower.c index 1f7170af..0723f50a 100644 --- a/src/lower.c +++ b/src/lower.c @@ -7222,27 +7222,96 @@ static void lower_implicit_decl(tree_t decl) vcode_var_t var = emit_var(signal_type, vbounds, name, VAR_SIGNAL); lower_put_vcode_obj(decl, var, top_scope); - ident_t func = NULL; switch (tree_subkind(decl)) { case IMPLICIT_GUARD: - func = lower_guard_func(tree_ident(decl), tree_value(decl)); + { + ident_t func = lower_guard_func(tree_ident(decl), tree_value(decl)); + vcode_reg_t one_reg = emit_const(vtype_offset(), 1); + vcode_reg_t locus = lower_debug_locus(decl); + vcode_reg_t context_reg = lower_context_for_call(func); + vcode_reg_t closure = + emit_closure(func, context_reg, VCODE_INVALID_TYPE, vtype); + vcode_reg_t kind_reg = emit_const(vtype_offset(), IMPLICIT_GUARD); + vcode_reg_t sig = emit_implicit_signal(vtype, one_reg, one_reg, locus, + kind_reg, closure); + emit_store(sig, var); + + tree_visit_only(tree_value(decl), lower_guard_refs_cb, + (void *)(uintptr_t)sig, T_REF); + } break; - } - vcode_reg_t one_reg = emit_const(vtype_offset(), 1); - vcode_reg_t locus = lower_debug_locus(decl); - vcode_reg_t context_reg = lower_context_for_call(func); - vcode_reg_t closure = - emit_closure(func, context_reg, VCODE_INVALID_TYPE, vtype); - vcode_reg_t kind_reg = emit_const(vtype_offset(), IMPLICIT_GUARD); - vcode_reg_t sig = emit_implicit_signal(vtype, one_reg, one_reg, locus, - kind_reg, closure); - emit_store(sig, var); + case IMPLICIT_DELAYED: + { + tree_t wave = tree_value(decl); + assert(tree_kind(wave) == T_WAVEFORM); - switch (tree_subkind(decl)) { - case IMPLICIT_GUARD: - tree_visit_only(tree_value(decl), lower_guard_refs_cb, - (void *)(uintptr_t)sig, T_REF); + tree_t expr = tree_value(wave); + type_t type = tree_type(expr); + + vcode_reg_t init_reg = lower_rvalue(expr); + lower_sub_signals(type, decl, NULL, 0, type, var, + VCODE_INVALID_REG, init_reg, VCODE_INVALID_REG, + VCODE_INVALID_REG, 0); + + vcode_state_t state; + vcode_state_save(&state); + + ident_t name = ident_prefix(vcode_unit_name(), tree_ident(decl), '.'); + emit_process(name, tree_to_object(decl), vcode_active_unit()); + + lower_push_scope(NULL); + + { + vcode_reg_t nets_reg = lower_signal_ref(decl); + vcode_reg_t count_reg = lower_type_width(type, nets_reg); + vcode_reg_t data_reg = lower_array_data(nets_reg); + + emit_drive_signal(data_reg, count_reg); + } + + { + tree_t prefix = longest_static_prefix(expr); + vcode_reg_t nets_reg = lower_lvalue(prefix); + vcode_reg_t count_reg = lower_type_width(type, nets_reg); + vcode_reg_t data_reg = lower_array_data(nets_reg); + + emit_sched_static(data_reg, count_reg, VCODE_INVALID_REG); + } + + emit_return(VCODE_INVALID_REG); + + vcode_block_t main_bb = emit_block(); + vcode_select_block(main_bb); + + vcode_reg_t delay_reg = lower_rvalue(tree_delay(wave)); + vcode_reg_t reject_reg = emit_const(vtype_time(), 0); + vcode_reg_t value_reg = lower_rvalue(expr); + + target_part_t parts[] = { + { .kind = PART_ALL, + .reg = lower_signal_ref(decl), + .off = VCODE_INVALID_REG, + .target = decl }, + { .kind = PART_POP, + .reg = VCODE_INVALID_REG, + .off = VCODE_INVALID_REG, + } + }; + + target_part_t *ptr = parts; + lower_signal_assign_target(&ptr, decl, value_reg, type, + reject_reg, delay_reg); + + emit_return(VCODE_INVALID_REG); + + lower_finished(); + lower_pop_scope(); + + vcode_state_restore(&state); + + emit_process_init(name, lower_debug_locus(decl)); + } break; } } diff --git a/src/names.c b/src/names.c index 6ff1f786..4798470a 100644 --- a/src/names.c +++ b/src/names.c @@ -1,5 +1,5 @@ // -// Copyright (C) 2020-2022 Nick Gasson +// Copyright (C) 2020-2023 Nick Gasson // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -498,6 +498,8 @@ static tree_t scope_find_enclosing(scope_t *s, scope_kind_t what) return s->container; else if (what == S_PROTECTED && tree_kind(s->container) == T_PROT_BODY) return s->container; + else if (what == S_CONCURRENT_BLOCK && is_concurrent_block(s->container)) + return s->container; } return NULL; diff --git a/src/names.h b/src/names.h index 448cee37..939494bb 100644 --- a/src/names.h +++ b/src/names.h @@ -1,5 +1,5 @@ // -// Copyright (C) 2020-2022 Nick Gasson +// Copyright (C) 2020-2023 Nick Gasson // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -35,6 +35,7 @@ typedef enum { S_SUBPROGRAM, S_PROCESS, S_PROTECTED, + S_CONCURRENT_BLOCK, } scope_kind_t; typedef enum { diff --git a/src/parse.c b/src/parse.c index 863d90db..bc5dd861 100644 --- a/src/parse.c +++ b/src/parse.c @@ -37,6 +37,7 @@ #include #include #include +#include typedef struct { token_t token; @@ -1685,6 +1686,7 @@ static void make_universal_real(tree_t container) static void make_implicit_guard_signal(tree_t block, tree_t expr) { tree_t guard = tree_new(T_IMPLICIT_SIGNAL); + tree_set_subkind(guard, IMPLICIT_GUARD); tree_set_ident(guard, ident_new("GUARD")); tree_set_loc(guard, tree_loc(expr)); tree_set_type(guard, std_type(NULL, STD_BOOLEAN)); @@ -2192,6 +2194,71 @@ static type_t apply_type_attribute(tree_t aref) } } +static void implicit_signal_attribute(tree_t aref) +{ + if (find_enclosing(nametab, S_SUBPROGRAM) != NULL) { + parse_error(tree_loc(aref), "implicit signal %s cannot be used in a " + "subprogram body", istr(tree_ident(aref))); + return; + } + + tree_t b = find_enclosing(nametab, S_CONCURRENT_BLOCK); + if (b == NULL) { + parse_error(tree_loc(aref), "implicit signal %s cannot be used in " + "this context", istr(tree_ident(aref))); + return; + } + + tree_t prefix = tree_name(aref); + + tree_t delay = NULL; + bool const_delay = false; + if (tree_params(aref) > 0) { + delay = tree_value(tree_param(aref, 0)); + const_delay = (tree_kind(delay) == T_LITERAL); + } + + LOCAL_TEXT_BUF tb = tb_new(); + tree_t ref = name_to_ref(prefix); + if (ref != NULL) + tb_istr(tb, tree_ident(ref)); + tb_cat(tb, "$delayed"); + if (const_delay) { + tb_printf(tb, "_%"PRIi64, tree_ival(delay)); + if (tree_has_ident(delay)) + tb_printf(tb, "_%s", istr(tree_ident(delay))); + } + + ident_t id; + if (ref == prefix && (delay == NULL || const_delay)) { + id = ident_new(tb_get(tb)); + + tree_t exist = search_decls(b, id, 0); + if (exist != NULL) { + tree_set_value(aref, make_ref(exist)); + return; + } + } + else + id = ident_uniq(tb_get(tb)); + + tree_t w = tree_new(T_WAVEFORM); + tree_set_loc(w, CURRENT_LOC); + tree_set_value(w, prefix); + tree_set_delay(w, delay ?: get_time(0, CURRENT_LOC)); + + tree_t imp = tree_new(T_IMPLICIT_SIGNAL); + tree_set_subkind(imp, IMPLICIT_DELAYED); + tree_set_ident(imp, id); + tree_set_loc(imp, CURRENT_LOC); + tree_set_value(imp, w); + tree_set_type(imp, tree_type(aref)); + + tree_add_decl(b, imp); + + tree_set_value(aref, make_ref(imp)); +} + //////////////////////////////////////////////////////////////////////////////// // Parser rules @@ -3097,6 +3164,9 @@ static tree_t p_attribute_name(tree_t prefix) else solve_types(nametab, t, NULL); + if (kind == ATTR_DELAYED) + implicit_signal_attribute(t); + return t; } @@ -9477,10 +9547,10 @@ static tree_t p_block_statement(ident_t label) else { tree_set_loc(b, CURRENT_LOC); insert_name(nametab, b, NULL); - scope_set_prefix(nametab, label); } push_scope(nametab); + scope_set_prefix(nametab, label ?: error_marker()); scope_set_container(nametab, b); if (peek() == tLPAREN) { @@ -9551,6 +9621,8 @@ static tree_t p_for_generate_statement(ident_t label) tree_t g = tree_new(T_FOR_GENERATE); tree_set_ident(g, label); + scope_set_container(nametab, g); + p_parameter_specification(g, T_GENERIC_DECL); consume(tGENERATE); @@ -9596,6 +9668,7 @@ static tree_t p_if_generate_statement(ident_t label) } push_scope(nametab); + scope_set_container(nametab, g); scope_set_prefix(nametab, alt_label ?: label); tree_t c0 = tree_new(T_COND); diff --git a/src/rt/model.c b/src/rt/model.c index b5fb792a..30e5b30f 100644 --- a/src/rt/model.c +++ b/src/rt/model.c @@ -370,17 +370,23 @@ static rt_scope_t *scope_for_block(rt_model_t *m, tree_t block, ident_t prefix) const int ndecls = tree_decls(block); for (int i = 0; i < ndecls; i++) { tree_t d = tree_decl(block, i); - if (tree_kind(d) == T_PACK_INST) { - rt_scope_t *p = xcalloc(sizeof(rt_scope_t)); - p->where = d; - p->name = ident_prefix(s->name, tree_ident(d), '.'); - p->kind = SCOPE_PACKAGE; - p->privdata = mptr_new(m->mspace, "pack inst privdata"); + switch (tree_kind(d)) { + case T_PACK_INST: + { + rt_scope_t *p = xcalloc(sizeof(rt_scope_t)); + p->where = d; + p->name = ident_prefix(s->name, tree_ident(d), '.'); + p->kind = SCOPE_PACKAGE; + p->privdata = mptr_new(m->mspace, "pack inst privdata"); + + hash_put(m->scopes, d, p); - hash_put(m->scopes, d, p); + *childp = p; + childp = &(p->chain); + } - *childp = p; - childp = &(p->chain); + default: + break; } } @@ -3523,3 +3529,31 @@ void x_resolve_signal(sig_shared_t *ss, jit_handle_t handle, void *context, n->flags |= NET_F_R_IDENT; } } + +void x_process_init(jit_handle_t handle, tree_t where) +{ + rt_model_t *m = get_model(); + ident_t name = jit_get_name(m->jit, handle); + + TRACE("init process %s", istr(name)); + + rt_scope_t *s = active_scope; + assert(s != NULL); + assert(s->kind == SCOPE_INSTANCE); + + rt_proc_t *p = xcalloc(sizeof(rt_proc_t)); + p->where = where; + p->name = name; + p->handle = handle; + p->scope = s; + p->privdata = mptr_new(m->mspace, "process privdata"); + p->chain = s->procs; + + p->wakeable.kind = W_PROC; + p->wakeable.wakeup_gen = 0; + p->wakeable.pending = false; + p->wakeable.postponed = false; + p->wakeable.delayed = false; + + s->procs = p; +} diff --git a/src/sem.c b/src/sem.c index 47bb7a49..b035ca8c 100644 --- a/src/sem.c +++ b/src/sem.c @@ -3323,6 +3323,9 @@ static bool sem_check_valid_implicit_signal(tree_t t, nametab_t *tab) // Certain attributes are illegal inside a subprogram according to LRM // 93 section 2.1.1.2 + if (tree_subkind(t) == ATTR_DELAYED) + return true; // XXX: now checked by parser + if (find_enclosing(tab, S_SUBPROGRAM) != NULL) sem_error(t, "implicit signal %s cannot be used in a " "subprogram body", istr(tree_ident(t))); diff --git a/src/simp.c b/src/simp.c index 2a8ef732..f78a8a9e 100644 --- a/src/simp.c +++ b/src/simp.c @@ -397,7 +397,6 @@ static tree_t simp_signal_attribute(tree_t t, attr_kind_t which, tb_istr(tb, tree_ident(ref)); switch (which) { case ATTR_TRANSACTION: tb_cat(tb, "$transaction"); break; - case ATTR_DELAYED: tb_printf(tb, "$delayed_%"PRIi64, iparam); break; default: break; } @@ -429,21 +428,6 @@ static tree_t simp_signal_attribute(tree_t t, attr_kind_t which, tree_set_target(a, r); switch (which) { - case ATTR_DELAYED: - { - if (tree_has_value(decl)) - tree_set_value(s, tree_value(decl)); - - tree_t delay = tree_value(tree_param(t, 0)); - - tree_t wave = tree_new(T_WAVEFORM); - tree_set_value(wave, name); - tree_set_delay(wave, delay); - - tree_add_waveform(a, wave); - } - break; - case ATTR_TRANSACTION: { tree_t not_decl = std_func(ident_new("STD.STANDARD.\"not\"(B)B")); @@ -525,7 +509,6 @@ static tree_t simp_attr_ref(tree_t t, simp_ctx_t *ctx) const attr_kind_t predef = tree_subkind(t); switch (predef) { - case ATTR_DELAYED: case ATTR_TRANSACTION: return simp_signal_attribute(t, predef, ctx); diff --git a/src/tree.h b/src/tree.h index 31726fcb..d5dca4eb 100644 --- a/src/tree.h +++ b/src/tree.h @@ -222,6 +222,7 @@ typedef enum { typedef enum { IMPLICIT_GUARD, + IMPLICIT_DELAYED, } implicit_kind_t; typedef enum { diff --git a/src/vcode.c b/src/vcode.c index 89e05259..bb16bed8 100644 --- a/src/vcode.c +++ b/src/vcode.c @@ -47,11 +47,12 @@ DECLARE_AND_DEFINE_ARRAY(vcode_type); (x == VCODE_OP_PCALL \ || x == VCODE_OP_FCALL || x == VCODE_OP_RESOLUTION_WRAPPER \ || x == VCODE_OP_CLOSURE || x == VCODE_OP_PROTECTED_INIT \ - || x == VCODE_OP_PACKAGE_INIT || x == VCODE_OP_COVER_BRANCH) + || x == VCODE_OP_PACKAGE_INIT || x == VCODE_OP_COVER_BRANCH \ + || x == VCODE_OP_PROCESS_INIT) #define OP_HAS_FUNC(x) \ (x == VCODE_OP_FCALL || x == VCODE_OP_PCALL || x == VCODE_OP_RESUME \ || x == VCODE_OP_CLOSURE || x == VCODE_OP_PROTECTED_INIT \ - || x == VCODE_OP_PACKAGE_INIT) + || x == VCODE_OP_PACKAGE_INIT || x == VCODE_OP_PROCESS_INIT) #define OP_HAS_IDENT(x) \ (x == VCODE_OP_LINK_VAR || x == VCODE_OP_LINK_PACKAGE \ || x == VCODE_OP_DEBUG_LOCUS || x == VCODE_OP_LINK_INSTANCE) @@ -914,28 +915,27 @@ const char *vcode_op_string(vcode_op_t op) { static const char *strs[] = { "cmp", "fcall", "wait", "const", "assert", "jump", "load", "store", - "mul", "add", "comment", "const array", "index", "sub", - "cast", "load indirect", "store indirect", "return", - "sched waveform", "cond", "report", "div", "neg", "exp", "abs", "mod", - "rem", "alloc", "select", "or", "wrap", "uarray left", - "uarray right", "uarray dir", "unwrap", "not", "and", - "event", "active", "const record", "record ref", "copy", "sched event", - "pcall", "resume", "xor", "xnor", "nand", "nor", "memset", - "case", "endfile", "file open", "file write", "file close", + "mul", "add", "comment", "const array", "index", "sub", "cast", + "load indirect", "store indirect", "return", "sched waveform", + "cond", "report", "div", "neg", "exp", "abs", "mod", "rem", "alloc", + "select", "or", "wrap", "uarray left", "uarray right", "uarray dir", + "unwrap", "not", "and", "event", "active", "const record", "record ref", + "copy", "sched event", "pcall", "resume", "xor", "xnor", "nand", "nor", + "memset", "case", "endfile", "file open", "file write", "file close", "file read", "null", "new", "null check", "deallocate", "all", "const real", "last event", "debug out", "cover stmt", "cover branch", - "cover toggle", "cover expression", "uarray len", "undefined", "range null", - "var upref", "resolved", "last value", "init signal", "map signal", - "drive signal", "link var", "resolution wrapper", "last active", "driving", - "driving value", "address of", "closure", "protected init", - "context upref", "const rep", "protected free", "sched static", - "implicit signal", "disconnect", "link package", "index check", - "debug locus", "length check", "range check", "array ref", "range length", - "exponent check", "zero check", "map const", "resolve signal", - "push scope", "pop scope", "alias signal", "trap add", + "cover toggle", "cover expression", "uarray len", "undefined", + "range null", "var upref", "resolved", "last value", "init signal", + "map signal", "drive signal", "link var", "resolution wrapper", + "last active", "driving", "driving value", "address of", "closure", + "protected init", "context upref", "const rep", "protected free", + "sched static", "implicit signal", "disconnect", "link package", + "index check", "debug locus", "length check", "range check", "array ref", + "range length", "exponent check", "zero check", "map const", + "resolve signal", "push scope", "pop scope", "alias signal", "trap add", "trap sub", "trap mul", "force", "release", "link instance", "unreachable", "package init", "strconv", "canon value", "convstr", - "trap neg" + "trap neg", "process init", }; if ((unsigned)op >= ARRAY_LEN(strs)) return "???"; @@ -1436,6 +1436,14 @@ void vcode_dump_with_mark(int mark_op, vcode_dump_fn_t callback, void *arg) } break; + case VCODE_OP_PROCESS_INIT: + { + color_printf("%s $magenta$%s$$ locus ", + vcode_op_string(op->kind), istr(op->func)); + vcode_dump_reg(op->args.items[0]); + } + break; + case VCODE_OP_PROTECTED_FREE: { printf("%s ", vcode_op_string(op->kind)); @@ -4779,6 +4787,17 @@ vcode_reg_t emit_protected_init(vcode_type_t type, vcode_reg_t context) return (op->result = vcode_add_reg(type)); } +void emit_process_init(ident_t name, vcode_reg_t locus) +{ + op_t *op = vcode_add_op(VCODE_OP_PROCESS_INIT); + vcode_add_arg(op, locus); + op->func = name; + op->subkind = VCODE_CC_VHDL; + + VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS, + "locus argument to process init must be a debug locus"); +} + void emit_protected_free(vcode_reg_t obj) { op_t *op = vcode_add_op(VCODE_OP_PROTECTED_FREE); diff --git a/src/vcode.h b/src/vcode.h index 83d2d9f8..ba5633ed 100644 --- a/src/vcode.h +++ b/src/vcode.h @@ -1,5 +1,5 @@ // -// Copyright (C) 2014-2022 Nick Gasson +// Copyright (C) 2014-2023 Nick Gasson // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -155,6 +155,7 @@ typedef enum { VCODE_OP_CANON_VALUE, VCODE_OP_CONVSTR, VCODE_OP_TRAP_NEG, + VCODE_OP_PROCESS_INIT, } vcode_op_t; typedef enum { @@ -493,6 +494,7 @@ vcode_reg_t emit_resolution_wrapper(vcode_type_t type, vcode_reg_t closure, vcode_reg_t emit_closure(ident_t func, vcode_reg_t context, vcode_type_t atype, vcode_type_t rtype); vcode_reg_t emit_protected_init(vcode_type_t type, vcode_reg_t context); +void emit_process_init(ident_t name, vcode_reg_t locus); vcode_reg_t emit_package_init(ident_t name, vcode_reg_t context); void emit_protected_free(vcode_reg_t obj); vcode_reg_t emit_context_upref(int hops); diff --git a/test/regress/implicit5.vhd b/test/regress/implicit5.vhd new file mode 100644 index 00000000..0002de1f --- /dev/null +++ b/test/regress/implicit5.vhd @@ -0,0 +1,38 @@ +entity implicit5 is +end entity; + +architecture test of implicit5 is + signal x : bit_vector(1 to 3); +begin + + p1: process is + begin + x <= "101"; + assert x'delayed = "000"; + wait for 0 ns; + assert x'delayed = "000"; + wait for 0 ns; + assert x'delayed = "101"; + x(2) <= '1'; + wait for 0 ns; + assert x'delayed = "101"; + wait for 0 ns; + assert x'delayed = "111"; + wait for 1 ns; + + x <= "000" after 1 ns, "111" after 2 ns, "101" after 3 ns; + + assert x'delayed(5 ns) = "000"; + wait for 5 ns; + assert x'delayed(5 ns) = "111"; + wait for 1 ns; + assert x'delayed(5 ns) = "000"; + wait for 1 ns; + assert x'delayed(5 ns) = "111"; + wait for 1 ns; + assert x'delayed(5 ns) = "101"; + + wait; + end process; + +end architecture; diff --git a/test/regress/issue603.vhd b/test/regress/issue603.vhd index febe4757..9079310a 100644 --- a/test/regress/issue603.vhd +++ b/test/regress/issue603.vhd @@ -26,4 +26,13 @@ begin wait; end process; + g1: for i in 1 to 3 generate + begin + p2: process is + begin + assert x(i)'delayed = '0'; + wait; + end process; + end generate; + end architecture; diff --git a/test/regress/testlist.txt b/test/regress/testlist.txt index 6fdb57ab..103af6d8 100644 --- a/test/regress/testlist.txt +++ b/test/regress/testlist.txt @@ -716,3 +716,4 @@ stdenv3 normal,2019 issue603 normal cover11 cover,shell issue609 normal +implicit5 normal -- 2.39.2