From 688c85bb4b91c6332981009c27307915a7553570 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Fri, 26 Jan 2024 20:37:25 +0000 Subject: [PATCH] Add support for inertial keyword in port maps. Issue #843 --- NEWS.md | 1 + src/common.c | 2 ++ src/dump.c | 5 +++++ src/jit/jit-core.c | 2 +- src/lower.c | 12 ++++++------ src/names.c | 9 +++++++++ src/nvc.c | 4 ++-- src/parse.c | 25 ++++++++++++++++++++++--- src/sem.c | 24 ++++++++++++++++++------ src/tree.c | 5 ++++- src/tree.h | 1 + test/dump/vhdl2.vhd | 2 ++ test/parse/vhdl2008.vhd | 13 +++++++++++++ test/regress/signal35.vhd | 30 ++++++++++++++++++++++++++++++ test/regress/testlist.txt | 1 + test/test_dump.c | 4 +++- test/test_parse.c | 4 +++- test/test_simp.c | 4 ++-- 18 files changed, 125 insertions(+), 23 deletions(-) create mode 100644 test/regress/signal35.vhd diff --git a/NEWS.md b/NEWS.md index 2721b035..69a14f56 100644 --- a/NEWS.md +++ b/NEWS.md @@ -10,6 +10,7 @@ function call, as required by the LRM (#835). - The implementation of conversions in port maps has been reworked and fixes a number of long-standing issues (#843). +- Added support for `inertial` keyword in port maps (#843). ## Version 1.11.2 - 2024-01-04 - Fixed an incorrect length check in the equivalent process for diff --git a/src/common.c b/src/common.c index 4699fdb7..ba3ae56a 100644 --- a/src/common.c +++ b/src/common.c @@ -1873,6 +1873,7 @@ type_t get_type_or_null(tree_t t) case T_USE: case T_CONTEXT: case T_PSL: + case T_WAVEFORM: return NULL; default: if (tree_has_type(t)) @@ -2051,6 +2052,7 @@ void build_wait(tree_t expr, build_wait_fn_t fn, void *ctx) case T_QUALIFIED: case T_TYPE_CONV: case T_ASSERT: + case T_INERTIAL: if (tree_has_value(expr)) build_wait(tree_value(expr), fn, ctx); break; diff --git a/src/dump.c b/src/dump.c index a040bbad..9ff903ca 100644 --- a/src/dump.c +++ b/src/dump.c @@ -407,6 +407,11 @@ static void dump_expr(tree_t t) } break; + case T_INERTIAL: + print_syntax("#inertial "); + dump_expr(tree_value(t)); + break; + default: cannot_dump(t, "expr"); } diff --git a/src/jit/jit-core.c b/src/jit/jit-core.c index 9b09ff1c..53cc754d 100644 --- a/src/jit/jit-core.c +++ b/src/jit/jit-core.c @@ -554,7 +554,7 @@ static void jit_emit_trace(diag_t *d, const loc_t *loc, object_t *enclosing, case T_PACK_INST: diag_trace(d, loc, "Package$$ %s", istr(tree_ident(tree))); break; - case T_WAVEFORM: + case T_INERTIAL: diag_trace(d, loc, "Equivalent process"); break; case T_TYPE_CONV: diff --git a/src/lower.c b/src/lower.c index bbf35b73..90add050 100644 --- a/src/lower.c +++ b/src/lower.c @@ -11500,9 +11500,9 @@ static void lower_convert_signal(lower_unit_t *lu, vcode_reg_t src_reg, } } -static void lower_non_static_actual(lower_unit_t *parent, tree_t port, - tree_t target, type_t type, - vcode_reg_t port_reg, tree_t wave) +static void lower_inertial_actual(lower_unit_t *parent, tree_t port, + tree_t target, type_t type, + vcode_reg_t port_reg, tree_t wave) { // Construct the equivalent process according the procedure in LRM 08 // section 6.5.6.3 @@ -11715,9 +11715,9 @@ static void lower_port_map(lower_unit_t *lu, tree_t block, tree_t map, else lower_map_signal(lu, src_reg, dst_reg, src_type, dst_type, map); } - else if (tree_kind(value) == T_WAVEFORM) { + else if (tree_kind(value) == T_INERTIAL) { tree_t name = tree_subkind(map) == P_NAMED ? tree_name(map) : port; - lower_non_static_actual(lu, port, name, name_type, port_reg, value); + lower_inertial_actual(lu, port, name, name_type, port_reg, value); } else if (value_reg != VCODE_INVALID_REG) { type_t value_type = tree_type(value); @@ -12052,7 +12052,7 @@ static void lower_ports(lower_unit_t *lu, driver_set_t *ds, tree_t block) tree_t value = tree_value(p); const tree_kind_t kind = tree_kind(value); - if (kind == T_TYPE_CONV || kind == T_CONV_FUNC || kind == T_WAVEFORM) + if (kind == T_TYPE_CONV || kind == T_CONV_FUNC || kind == T_INERTIAL) map_regs[i] = VCODE_INVALID_REG; else if (lower_is_signal_ref(value)) map_regs[i] = lower_lvalue(lu, value); diff --git a/src/names.c b/src/names.c index c0e924b3..cdf6527d 100644 --- a/src/names.c +++ b/src/names.c @@ -4617,6 +4617,13 @@ static type_t solve_view_element(nametab_t *tab, tree_t elem) } } +static type_t solve_inertial(nametab_t *tab, tree_t expr) +{ + type_t type = _solve_types(tab, tree_value(expr)); + tree_set_type(expr, type); + return type; +} + static type_t solve_range(nametab_t *tab, tree_t r) { if (tree_has_type(r)) @@ -4746,6 +4753,8 @@ static type_t _solve_types(nametab_t *tab, tree_t expr) return solve_cond_expr(tab, expr); case T_VIEW_ELEMENT: return solve_view_element(tab, expr); + case T_INERTIAL: + return solve_inertial(tab, expr); default: fatal_trace("cannot solve types for %s", tree_kind_str(tree_kind(expr))); } diff --git a/src/nvc.c b/src/nvc.c index 84954365..00aab530 100644 --- a/src/nvc.c +++ b/src/nvc.c @@ -1,5 +1,5 @@ // -// Copyright (C) 2011-2023 Nick Gasson +// Copyright (C) 2011-2024 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 @@ -62,7 +62,7 @@ typedef struct { } cmd_state_t; const char copy_string[] = - "Copyright (C) 2011-2023 Nick Gasson\n" + "Copyright (C) 2011-2024 Nick Gasson\n" "This program comes with ABSOLUTELY NO WARRANTY. This is free software, " "and\nyou are welcome to redistribute it under certain conditions. See " "the GNU\nGeneral Public Licence for details."; diff --git a/src/parse.c b/src/parse.c index 8bee3c00..64009b87 100644 --- a/src/parse.c +++ b/src/parse.c @@ -1,5 +1,5 @@ // -// Copyright (C) 2014-2023 Nick Gasson +// Copyright (C) 2014-2024 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 @@ -2893,7 +2893,7 @@ static tree_t p_formal_part(void) return name; } -static tree_t p_actual_part(class_t class) +static tree_t p_actual_part(class_t class, formal_kind_t kind) { // actual_designator // | name ( actual_designator ) @@ -2919,6 +2919,25 @@ static tree_t p_actual_part(class_t class) return ref; } + if (optional(tINERTIAL)) { + require_std(STD_08, "inertial in actual designator"); + + tree_t expr = p_expression(); + + if (kind == F_PORT_MAP) { + tree_t w = tree_new(T_INERTIAL); + tree_set_loc(w, CURRENT_LOC); + tree_set_value(w, expr); + + return w; + } + else { + parse_error(CURRENT_LOC, "the reserved word INERTIAL can only be " + "used in port map association elements"); + return expr; + } + } + // If the actual part takes either the second or third form above then the // argument to the function call is the actual designator but only if the // call is to a named function rather than an operator. @@ -3009,7 +3028,7 @@ static void p_association_element(tree_t map, int pos, tree_t unit, type = tree_type(formal); } - tree_t value = p_actual_part(class); + tree_t value = p_actual_part(class, kind); if (kind == F_PORT_MAP) solve_types(nametab, value, type); diff --git a/src/sem.c b/src/sem.c index 9cc86aaa..29e49dde 100644 --- a/src/sem.c +++ b/src/sem.c @@ -1,5 +1,5 @@ // -// Copyright (C) 2011-2023 Nick Gasson +// Copyright (C) 2011-2024 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 @@ -4409,9 +4409,12 @@ static bool sem_check_port_actual(formal_map_t *formals, int nformals, if (!sem_check(value, tab)) return false; - type_t value_type = tree_type(value); + const tree_kind_t kind = tree_kind(value); + tree_t expr = kind == T_INERTIAL ? tree_value(value) : value; - if (!sem_check_type(value, type, tab)) + type_t value_type = tree_type(expr); + + if (!sem_check_type(expr, type, tab)) sem_error(value, "type of actual %s does not match type %s of formal " "port %s", type_pp(value_type), type_pp(type), istr(tree_ident(decl))); @@ -4432,7 +4435,6 @@ static bool sem_check_port_actual(formal_map_t *formals, int nformals, // These only apply if the class of the formal is not constant tree_t actual = NULL; - const tree_kind_t kind = tree_kind(value); if (kind == T_TYPE_CONV || kind == T_CONV_FUNC) { // Conversion functions are in LRM 93 section 4.3.2.2 actual = tree_value(value); @@ -4452,7 +4454,7 @@ static bool sem_check_port_actual(formal_map_t *formals, int nformals, else actual = value; // No conversion - if (mode == PORT_IN) { + if (mode == PORT_IN && kind != T_INERTIAL) { tree_t ref = name_to_ref(actual); bool is_static = true; if (ref != NULL && class_of(ref) == C_SIGNAL) @@ -4478,7 +4480,7 @@ static bool sem_check_port_actual(formal_map_t *formals, int nformals, return false; } - tree_t w = tree_new(T_WAVEFORM); + tree_t w = tree_new(T_INERTIAL); tree_set_loc(w, tree_loc(value)); tree_set_value(w, value); @@ -6622,6 +6624,14 @@ static bool sem_check_prot_decl(tree_t t, nametab_t *tab) return true; } +static bool sem_check_inertial(tree_t t, nametab_t *tab) +{ + if (!sem_check(tree_value(t), tab)) + return false; + + return true; +} + bool sem_check(tree_t t, nametab_t *tab) { switch (tree_kind(t)) { @@ -6798,6 +6808,8 @@ bool sem_check(tree_t t, nametab_t *tab) return sem_check_sequence(t, tab); case T_PROT_DECL: return sem_check_prot_decl(t, tab); + case T_INERTIAL: + return sem_check_inertial(t, tab); default: sem_error(t, "cannot check %s", tree_kind_str(tree_kind(t))); } diff --git a/src/tree.c b/src/tree.c index 803bc7f3..26672529 100644 --- a/src/tree.c +++ b/src/tree.c @@ -365,6 +365,9 @@ static const imask_t has_map[T_LAST_TREE_KIND] = { // T_GUARD (I_REF | I_SPEC | I_TYPE), + + // T_INERTIAL + (I_VALUE | I_TYPE), }; static const char *kind_text_map[T_LAST_TREE_KIND] = { @@ -405,7 +408,7 @@ static const char *kind_text_map[T_LAST_TREE_KIND] = { "T_VIEW_DECL", "T_PACKAGE_MAP", "T_COND_EXPR", "T_COND_VALUE", "T_COND_RETURN", "T_VIEW_ELEMENT", "T_MATCH_SELECT", "T_PROT_DECL", "T_DUMMY_DRIVER", - "T_GUARD", + "T_GUARD", "T_INERTIAL", }; static const change_allowed_t change_allowed[] = { diff --git a/src/tree.h b/src/tree.h index d42e268e..382355b1 100644 --- a/src/tree.h +++ b/src/tree.h @@ -367,6 +367,7 @@ typedef enum tree_kind { T_PROT_DECL, T_DUMMY_DRIVER, T_GUARD, + T_INERTIAL, T_LAST_TREE_KIND } tree_kind_t; diff --git a/test/dump/vhdl2.vhd b/test/dump/vhdl2.vhd index a843619a..0a0fd894 100644 --- a/test/dump/vhdl2.vhd +++ b/test/dump/vhdl2.vhd @@ -35,6 +35,8 @@ architecture test of vhdl2 is begin b1: block is + port ( p : integer ); + port map ( p => inertial 1 ); begin end block; diff --git a/test/parse/vhdl2008.vhd b/test/parse/vhdl2008.vhd index 120b08f5..5b785c31 100644 --- a/test/parse/vhdl2008.vhd +++ b/test/parse/vhdl2008.vhd @@ -276,4 +276,17 @@ begin constant c2 : c1'subtype := c1; -- OK begin end block; + + b11: block is + generic ( g : in integer ); + generic map ( g => inertial 5 + 1 ); -- Error + port ( x : in integer ); + port map ( x => inertial 3 + 4 ); -- OK + + procedure proc ( signal x : integer ) is + begin + end procedure; + begin + proc(x => inertial x); -- Error + end block; end architecture; diff --git a/test/regress/signal35.vhd b/test/regress/signal35.vhd new file mode 100644 index 00000000..ac713cdb --- /dev/null +++ b/test/regress/signal35.vhd @@ -0,0 +1,30 @@ +entity signal35 is +end entity; + +architecture test of signal35 is + signal s : integer := 1000; +begin + s <= 1 after 1 ns, 5 after 2 ns; + + b: block is + port ( p : in integer := 0); + port map ( p => inertial s ); + begin + + check: process is + begin + assert p = 0; + wait for 1 ns; + assert p = 1000; + wait for 0 ns; + assert p = 1; + wait for 1 ns; + assert p = 1; + wait for 0 ns; + assert p = 5; + wait; + end process; + + end block; + +end architecture; diff --git a/test/regress/testlist.txt b/test/regress/testlist.txt index 8f297c65..5e9cfcdf 100644 --- a/test/regress/testlist.txt +++ b/test/regress/testlist.txt @@ -931,3 +931,4 @@ conv11 normal conv12 normal issue843 normal,2008 bounds43 fail,gold +signal35 normal,2008 diff --git a/test/test_dump.c b/test/test_dump.c index 8737e502..d3fb9762 100644 --- a/test/test_dump.c +++ b/test/test_dump.c @@ -1,5 +1,5 @@ // -// Copyright (C) 2023 Nick Gasson +// Copyright (C) 2023-2024 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 @@ -163,6 +163,8 @@ START_TEST(test_vhdl2) const char *stmt_cases[][2] = { { "B1", "B1: block is\n" + " port ( signal P : in INTEGER );\n" + " port map (P => inertial 1);\n" "begin\n" "end block;\n" }, { "U1", diff --git a/test/test_parse.c b/test/test_parse.c index 8cc9f972..6193e385 100644 --- a/test/test_parse.c +++ b/test/test_parse.c @@ -1,5 +1,5 @@ // -// Copyright (C) 2011-2022 Nick Gasson +// Copyright (C) 2011-2024 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 @@ -3631,6 +3631,8 @@ START_TEST(test_vhdl2008) { 232, "expected trailing generate statement body label to match FOO" }, { 249, "expected trailing case generate statement label to match G3" }, { 264, "signed bit string literal cannot be an empty string" }, + { 282, "the reserved word INERTIAL can only be used in port map " }, + { 290, "the reserved word INERTIAL can only be used in port map " }, { -1, NULL } }; expect_errors(expect); diff --git a/test/test_simp.c b/test/test_simp.c index 1a2e48c0..d3467906 100644 --- a/test/test_simp.c +++ b/test/test_simp.c @@ -1202,8 +1202,8 @@ START_TEST(test_ports2008) tree_t inst = tree_stmt(b, 0); fail_unless(tree_kind(inst) == T_INSTANCE); - fail_unless(tree_kind(tree_value(tree_param(inst, 0))) == T_WAVEFORM); - fail_unless(tree_kind(tree_value(tree_param(inst, 1))) == T_WAVEFORM); + fail_unless(tree_kind(tree_value(tree_param(inst, 0))) == T_INERTIAL); + fail_unless(tree_kind(tree_value(tree_param(inst, 1))) == T_INERTIAL); } END_TEST -- 2.39.2