From 451548ed886dea2528d25b3c81ba0ba2e56a163c Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Thu, 18 Apr 2024 21:40:22 +0100 Subject: [PATCH] Parsing for delay in Verilog procedural assignments --- lib/nvc/verilog-body.vhd | 5 +++++ lib/nvc/verilog.vhd | 1 + src/common.c | 1 + src/common.h | 1 + src/vlog/vlog-dump.c | 23 +++++++++++++++++++++++ src/vlog/vlog-lower.c | 26 ++++++++++++++++++++++++++ src/vlog/vlog-node.c | 27 ++++++++++++++++++++++++--- src/vlog/vlog-node.h | 9 +++++++++ src/vlog/vlog-number.c | 11 ++++++----- src/vlog/vlog-parse.y | 30 ++++++++++++++++++++++++++++++ src/vlog/vlog-sem.c | 29 +++++++++++++++++++++++++++++ test/dump/vlog1.v | 4 +++- test/questa.sh | 2 +- test/test_dump.c | 16 +++++++++------- test/test_vlog.c | 12 ++++++------ 15 files changed, 174 insertions(+), 23 deletions(-) diff --git a/lib/nvc/verilog-body.vhd b/lib/nvc/verilog-body.vhd index 1a06c796..eea1a1d4 100644 --- a/lib/nvc/verilog-body.vhd +++ b/lib/nvc/verilog-body.vhd @@ -370,4 +370,9 @@ package body verilog is begin return not (l = r); end function; + + impure function sys_time return time is + begin + return now; + end function; end package body; diff --git a/lib/nvc/verilog.vhd b/lib/nvc/verilog.vhd index a7c0f5bc..47a77f64 100644 --- a/lib/nvc/verilog.vhd +++ b/lib/nvc/verilog.vhd @@ -82,6 +82,7 @@ package verilog is function "/=" (l, r : t_packed_logic) return boolean; procedure sys_finish; + impure function sys_time return time; -- These procedures are called with a special variadic calling convention -- which cannot be represented in VHDL diff --git a/src/common.c b/src/common.c index 41fe9697..e840e0ba 100644 --- a/src/common.c +++ b/src/common.c @@ -1101,6 +1101,7 @@ void intern_strings(void) id_cache[W_SHAPE] = ident_new("shape"); id_cache[W_INSTANCE_NAME] = ident_new("instance_name"); id_cache[W_PATH_NAME] = ident_new("path_name"); + id_cache[W_DOLLAR_TIME] = ident_new("$time"); id_cache[W_IEEE_LOGIC_VECTOR] = ident_new("IEEE.STD_LOGIC_1164.STD_LOGIC_VECTOR"); diff --git a/src/common.h b/src/common.h index 4ad5a80b..ed6dd796 100644 --- a/src/common.h +++ b/src/common.h @@ -253,6 +253,7 @@ typedef enum { W_SHAPE, W_INSTANCE_NAME, W_PATH_NAME, + W_DOLLAR_TIME, NUM_WELL_KNOWN } well_known_t; diff --git a/src/vlog/vlog-dump.c b/src/vlog/vlog-dump.c index e8e11c76..47a992a7 100644 --- a/src/vlog/vlog-dump.c +++ b/src/vlog/vlog-dump.c @@ -171,6 +171,8 @@ static void vlog_dump_nbassign(vlog_node_t v, int indent) tab(indent); vlog_dump(vlog_target(v), 0); print_syntax(" <= "); + if (vlog_has_delay(v)) + vlog_dump(vlog_delay(v), 0); vlog_dump(vlog_value(v), 0); print_syntax(";\n"); } @@ -186,6 +188,9 @@ static void vlog_dump_bassign(vlog_node_t v, int indent) break; } + if (vlog_has_delay(v)) + vlog_dump(vlog_delay(v), 0); + vlog_dump(vlog_value(v), 0); print_syntax(";\n"); } @@ -248,6 +253,21 @@ static void vlog_dump_systask(vlog_node_t v, int indent) print_syntax(";\n"); } +static void vlog_dump_sysfunc(vlog_node_t v) +{ + print_syntax("%s", istr(vlog_ident(v))); + + const int nparams = vlog_params(v); + if (nparams > 0) { + print_syntax("("); + for (int i = 0; i < nparams; i++) { + if (i > 0) print_syntax(", "); + vlog_dump(vlog_param(v, i), 0); + } + print_syntax(")"); + } +} + static void vlog_dump_string(vlog_node_t v) { print_syntax("\"%s\"", vlog_text(v)); @@ -410,6 +430,9 @@ void vlog_dump(vlog_node_t v, int indent) case V_SYSTASK: vlog_dump_systask(v, indent); break; + case V_SYSFUNC: + vlog_dump_sysfunc(v); + break; case V_STRING: vlog_dump_string(v); break; diff --git a/src/vlog/vlog-lower.c b/src/vlog/vlog-lower.c index a9f65fc5..5f7bad33 100644 --- a/src/vlog/vlog-lower.c +++ b/src/vlog/vlog-lower.c @@ -404,6 +404,30 @@ static vcode_reg_t vlog_lower_binary(lower_unit_t *lu, vlog_binary_t op, return emit_fcall(func, rtype, rtype, args, ARRAY_LEN(args)); } +static vcode_reg_t vlog_lower_sysfunc(lower_unit_t *lu, vlog_node_t v) +{ + const v_sysfunc_kind_t kind = vlog_subkind(v); + static const char *fns[] = { + "NVC.VERILOG.SYS_TIME()T" + }; + assert(kind < ARRAY_LEN(fns)); + + vcode_reg_t context_reg = vlog_helper_package(); + + switch (kind) { + case V_SYS_TIME: + { + vcode_type_t vtime = vtype_time(); + vcode_reg_t args[] = { context_reg }; + return emit_fcall(ident_new(fns[kind]), vtime, vtime, + args, ARRAY_LEN(args)); + } + + default: + CANNOT_HANDLE(v); + } +} + static vcode_reg_t vlog_lower_rvalue(lower_unit_t *lu, vlog_node_t v) { PUSH_DEBUG_INFO(v); @@ -525,6 +549,8 @@ static vcode_reg_t vlog_lower_rvalue(lower_unit_t *lu, vlog_node_t v) vcode_type_t vnet = vlog_net_value_type(); return emit_const(vnet, map[vlog_subkind(v)]); } + case V_SYSFUNC: + return vlog_lower_sysfunc(lu, v); default: CANNOT_HANDLE(v); } diff --git a/src/vlog/vlog-node.c b/src/vlog/vlog-node.c index ccce32f5..400fcec0 100644 --- a/src/vlog/vlog-node.c +++ b/src/vlog/vlog-node.c @@ -42,7 +42,7 @@ static const imask_t has_map[V_LAST_NODE_KIND] = { (I_VALUE | I_STMTS), // V_NBASSIGN - (I_TARGET | I_VALUE), + (I_TARGET | I_VALUE | I_DELAY), // V_EVENT (I_SUBKIND | I_VALUE), @@ -87,7 +87,7 @@ static const imask_t has_map[V_LAST_NODE_KIND] = { (I_LEFT | I_RIGHT | I_SUBKIND), // V_BASSIGN - (I_TARGET | I_VALUE | I_SUBKIND), + (I_TARGET | I_VALUE | I_SUBKIND | I_DELAY), // V_UNARY (I_VALUE | I_SUBKIND), @@ -103,6 +103,9 @@ static const imask_t has_map[V_LAST_NODE_KIND] = { // V_BIT_SELECT (I_IDENT | I_REF | I_PARAMS), + + // V_SYSFUNC + (I_IDENT | I_SUBKIND | I_PARAMS), }; static const char *kind_text_map[V_LAST_NODE_KIND] = { @@ -112,7 +115,7 @@ static const char *kind_text_map[V_LAST_NODE_KIND] = { "V_NET_DECL", "V_ASSIGN", "V_DIMENSION", "V_IF", "V_COND", "V_VAR_DECL", "V_DELAY_CONTROL", "V_BINARY", "V_BASSIGN", "V_UNARY", "V_GATE_INST", "V_STRENGTH", - "V_MOD_INST", "V_BIT_SELECT", + "V_MOD_INST", "V_BIT_SELECT", "V_SYSFUNC", }; static const change_allowed_t change_allowed[] = { @@ -379,6 +382,24 @@ void vlog_set_target(vlog_node_t v, vlog_node_t e) object_write_barrier(&(v->object), &(e->object)); } +vlog_node_t vlog_delay(vlog_node_t v) +{ + item_t *item = lookup_item(&vlog_object, v, I_DELAY); + assert(item->object != NULL); + return container_of(item->object, struct _vlog_node, object); +} + +bool vlog_has_delay(vlog_node_t v) +{ + return lookup_item(&vlog_object, v, I_DELAY)->object != NULL; +} + +void vlog_set_delay(vlog_node_t v, vlog_node_t d) +{ + lookup_item(&vlog_object, v, I_DELAY)->object = &(d->object); + object_write_barrier(&(v->object), &(d->object)); +} + const char *vlog_text(vlog_node_t v) { item_t *item = lookup_item(&vlog_object, v, I_TEXT); diff --git a/src/vlog/vlog-node.h b/src/vlog/vlog-node.h index 185bbb34..5717597d 100644 --- a/src/vlog/vlog-node.h +++ b/src/vlog/vlog-node.h @@ -38,6 +38,10 @@ typedef enum { V_SYS_FINISH, } v_systask_kind_t; +typedef enum { + V_SYS_TIME, +} v_sysfunc_kind_t; + typedef enum { V_NET_WIRE, V_NET_SUPPLY0, @@ -71,6 +75,7 @@ typedef enum { V_STRENGTH, V_MOD_INST, V_BIT_SELECT, + V_SYSFUNC, V_LAST_NODE_KIND } vlog_kind_t; @@ -176,6 +181,10 @@ void vlog_set_value(vlog_node_t v, vlog_node_t e); vlog_node_t vlog_target(vlog_node_t v); void vlog_set_target(vlog_node_t v, vlog_node_t e); +vlog_node_t vlog_delay(vlog_node_t v); +bool vlog_has_delay(vlog_node_t v); +void vlog_set_delay(vlog_node_t v, vlog_node_t d); + vlog_node_t vlog_left(vlog_node_t v); void vlog_set_left(vlog_node_t v, vlog_node_t e); diff --git a/src/vlog/vlog-number.c b/src/vlog/vlog-number.c index c8f867aa..1f4e07bf 100644 --- a/src/vlog/vlog-number.c +++ b/src/vlog/vlog-number.c @@ -192,13 +192,14 @@ void number_print(number_t val, text_buf_t *tb) } break; case TAG_INTEGER: - tb_printf(tb, "%u'%s", val.intg.width, val.intg.issigned ? "s" : ""); if (val.intg.width == 1) - tb_printf(tb, "b%u", (unsigned char)val.intg.packed); - else { - const int64_t extended = val.intg.packed; - tb_printf(tb, "d%"PRIi64, extended); + tb_printf(tb, "1'b%u", (unsigned char)val.intg.packed); + else if (val.intg.width == 32 && !val.intg.issigned) { + tb_printf(tb, "%"PRIi64, (int64_t)val.intg.packed); } + else + tb_printf(tb, "%u'%sd%"PRIi64, val.intg.width, + val.intg.issigned ? "s" : "", (int64_t)val.intg.packed); break; default: DEBUG_ONLY(fatal_trace("invalid number tag %x", val.common.tag)); diff --git a/src/vlog/vlog-parse.y b/src/vlog/vlog-parse.y index 80c4de73..4454029c 100644 --- a/src/vlog/vlog-parse.y +++ b/src/vlog/vlog-parse.y @@ -139,6 +139,7 @@ static vlog_node_t make_strength(vlog_strength_t value, const loc_t *loc) %type decimal_number conditional_statement variable_type %type delay_control delay_value strength0 strength1 %type pull_gate_instance port_identifier module_instance +%type system_function_call %type identifier hierarchical_identifier %type module_item_list module_port_list_opt module_item %type list_of_port_declarations module_item_list_opt @@ -673,6 +674,17 @@ system_task_enable: } ; +system_function_call: + tSYSTASK + { + $$ = vlog_new(V_SYSFUNC); + vlog_set_loc($$, &@$); + vlog_set_ident($$, ident_new($1)); + + free($1); + } + ; + seq_block: tBEGIN list_of_statements_opt tEND { $$ = vlog_new(V_SEQ_BLOCK); @@ -702,6 +714,14 @@ nonblocking_assignment: vlog_set_target($$, $1); vlog_set_value($$, $3); } + | lvalue tLE delay_or_event_control expression + { + $$ = vlog_new(V_NBASSIGN); + vlog_set_loc($$, &@$); + vlog_set_target($$, $1); + vlog_set_delay($$, $3); + vlog_set_value($$, $4); + } ; blocking_assignment: @@ -713,6 +733,15 @@ blocking_assignment: vlog_set_target($$, $1); vlog_set_value($$, $3); } + | lvalue '=' delay_or_event_control expression + { + $$ = vlog_new(V_BASSIGN); + vlog_set_loc($$, &@$); + vlog_set_subkind($$, V_ASSIGN_EQUALS); + vlog_set_target($$, $1); + vlog_set_delay($$, $3); + vlog_set_value($$, $4); + } ; procedural_timing_control_statement: @@ -886,6 +915,7 @@ primary: hierarchical_identifier vlog_set_loc($$, &@$); } | number + | system_function_call ; number: decimal_number diff --git a/src/vlog/vlog-sem.c b/src/vlog/vlog-sem.c index 75b3db21..c679567b 100644 --- a/src/vlog/vlog-sem.c +++ b/src/vlog/vlog-sem.c @@ -173,6 +173,9 @@ static void vlog_check_nbassign(vlog_node_t stmt) vlog_node_t target = vlog_target(stmt); vlog_check(target); + if (vlog_has_delay(stmt)) + vlog_check(vlog_delay(stmt)); + vlog_node_t value = vlog_value(stmt); vlog_check(value); @@ -184,6 +187,9 @@ static void vlog_check_bassign(vlog_node_t stmt) vlog_node_t target = vlog_target(stmt); vlog_check(target); + if (vlog_has_delay(stmt)) + vlog_check(vlog_delay(stmt)); + vlog_node_t value = vlog_value(stmt); vlog_check(value); @@ -268,6 +274,26 @@ static void vlog_check_systask(vlog_node_t call) vlog_check(vlog_param(call, i)); } +static void vlog_check_sysfunc(vlog_node_t call) +{ + const well_known_t name = is_well_known(vlog_ident(call)); + + v_sysfunc_kind_t kind; + switch (name) { + case W_DOLLAR_TIME: kind = V_SYS_TIME; break; + default: + error_at(vlog_loc(call), "system function %s not recognised", + istr(vlog_ident(call))); + return; + } + + vlog_set_subkind(call, kind); + + const int nparams = vlog_params(call); + for (int i = 0; i < nparams; i++) + vlog_check(vlog_param(call, i)); +} + static void vlog_check_if(vlog_node_t stmt) { const int nconds = vlog_conds(stmt); @@ -468,6 +494,9 @@ void vlog_check(vlog_node_t v) case V_SYSTASK: vlog_check_systask(v); break; + case V_SYSFUNC: + vlog_check_sysfunc(v); + break; case V_NUMBER: vlog_check_number(v); break; diff --git a/test/dump/vlog1.v b/test/dump/vlog1.v index e9a89a05..315d6b0b 100644 --- a/test/dump/vlog1.v +++ b/test/dump/vlog1.v @@ -9,13 +9,15 @@ module mod2; wire w; reg r; initial begin - $display("hello"); + $display("hello", $time); if (bus) r <= 1 | r; $finish; r = 1; #1 r <= 0; r = ~w; + r = #1 5; + r <= #5 1; end assign bus = 3; pullup (supply1, supply0) p1 (w); diff --git a/test/questa.sh b/test/questa.sh index f39d89b3..94a8bd7b 100755 --- a/test/questa.sh +++ b/test/questa.sh @@ -28,7 +28,7 @@ if $cover; then fi cat >>/tmp/questa.do <