Skip to content

Commit

Permalink
Parse Verilog concatenation
Browse files Browse the repository at this point in the history
  • Loading branch information
nickg committed Dec 19, 2024
1 parent 1bd7243 commit 69e5210
Show file tree
Hide file tree
Showing 12 changed files with 157 additions and 17 deletions.
16 changes: 16 additions & 0 deletions src/vlog/vlog-dump.c
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,19 @@ static void vlog_dump_cond_expr(vlog_node_t v, int indent)
vlog_dump(vlog_right(v), 0);
}

static void vlog_dump_concat(vlog_node_t v, int indent)
{
print_syntax("{");

const int nparams = vlog_params(v);
for (int i = 0; i < nparams; i++) {
if (i > 0) print_syntax(", ");
vlog_dump(vlog_param(v, i), 0);
}

print_syntax("}");
}

void vlog_dump(vlog_node_t v, int indent)
{
switch (vlog_kind(v)) {
Expand Down Expand Up @@ -631,6 +644,9 @@ void vlog_dump(vlog_node_t v, int indent)
case V_COND_EXPR:
vlog_dump_cond_expr(v, indent);
break;
case V_CONCAT:
vlog_dump_concat(v, indent);
break;
default:
print_syntax("\n");
fflush(stdout);
Expand Down
5 changes: 4 additions & 1 deletion src/vlog/vlog-node.c
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,9 @@ static const imask_t has_map[V_LAST_NODE_KIND] = {

// V_REAL
(I_DVAL),

// V_CONCAT
(I_PARAMS),
};

static const char *kind_text_map[V_LAST_NODE_KIND] = {
Expand All @@ -186,7 +189,7 @@ static const char *kind_text_map[V_LAST_NODE_KIND] = {
"V_UNION_DECL", "V_STRUCT_DECL", "V_EVENT_CONTROL", "V_EMPTY",
"V_REPEAT", "V_WHILE", "V_DO_WHILE", "V_TASK_DECL",
"V_FUNC_DECL", "V_WAIT", "V_PARAM_DECL", "V_COND_EXPR",
"V_REAL",
"V_REAL", "V_CONCAT",
};

static const change_allowed_t change_allowed[] = {
Expand Down
1 change: 1 addition & 0 deletions src/vlog/vlog-node.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ typedef enum {
V_PARAM_DECL,
V_COND_EXPR,
V_REAL,
V_CONCAT,

V_LAST_NODE_KIND
} vlog_kind_t;
Expand Down
53 changes: 46 additions & 7 deletions src/vlog/vlog-parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -1156,6 +1156,26 @@ static vlog_node_t p_mintypmax_expression(void)
return p_expression();
}

static vlog_node_t p_concatenation(void)
{
// { expression { , expression } }

BEGIN("concatenation");

consume(tLBRACE);

vlog_node_t v = vlog_new(V_CONCAT);

do {
vlog_add_param(v, p_expression());
} while (optional(tCOMMA));

consume(tRBRACE);

vlog_set_loc(v, CURRENT_LOC);
return v;
}

static vlog_node_t p_primary(void)
{
// primary_literal | empty_queue
Expand Down Expand Up @@ -1186,8 +1206,11 @@ static vlog_node_t p_primary(void)
consume(tRPAREN);
return expr;
}
case tLBRACE:
return p_concatenation();
default:
one_of(tID, tSTRING, tNUMBER, tUNSIGNED, tREAL, tSYSTASK, tLPAREN);
one_of(tID, tSTRING, tNUMBER, tUNSIGNED, tREAL, tSYSTASK, tLPAREN,
tLBRACE);
return p_select(error_marker());
}
}
Expand Down Expand Up @@ -1255,9 +1278,10 @@ static vlog_node_t p_nonbinary_expression(void)
case tSTRING:
case tNUMBER:
case tUNSIGNED:
case tREAL:
case tSYSTASK:
case tLPAREN:
case tREAL:
case tLBRACE:
return p_primary();
case tMINUS:
case tTILDE:
Expand All @@ -1270,7 +1294,8 @@ static vlog_node_t p_nonbinary_expression(void)
return v;
}
default:
one_of(tID, tSTRING, tNUMBER, tUNSIGNED, tMINUS, tTILDE, tBANG, tSYSTASK);
one_of(tID, tSTRING, tNUMBER, tUNSIGNED, tREAL, tSYSTASK, tLPAREN,
tLBRACE, tMINUS, tTILDE, tBANG);
return p_select(error_marker());
}
}
Expand Down Expand Up @@ -1493,11 +1518,25 @@ static vlog_node_t p_net_lvalue(void)

BEGIN("net lvalue");

ident_t id = p_identifier();
vlog_node_t v = p_constant_select(id);
if (optional(tLBRACE)) {
vlog_node_t v = vlog_new(V_CONCAT);

vlog_set_loc(v, CURRENT_LOC);
return v;
do {
vlog_add_param(v, p_net_lvalue());
} while (optional(tCOMMA));

consume(tRBRACE);

vlog_set_loc(v, CURRENT_LOC);
return v;
}
else {
ident_t id = p_identifier();
vlog_node_t v = p_constant_select(id);

vlog_set_loc(v, CURRENT_LOC);
return v;
}
}

static vlog_node_t p_operator_assignment(vlog_node_t lhs)
Expand Down
2 changes: 2 additions & 0 deletions src/vlog/vlog-pp.l
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ ID [a-zA-Z_]([a-zA-Z0-9_$])*
`timescale |
`resetall |
`pragma |
`begin_keywords |
`end_keywords |
`celldefine |
`endcelldefine { tb_cat(output, vlogpp_text); }

Expand Down
54 changes: 47 additions & 7 deletions src/vlog/vlog-sem.c
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,40 @@ static void vlog_check_bassign(vlog_node_t stmt)
vlog_check_variable_target(target);
}

static void vlog_check_net_lvalue(vlog_node_t v, vlog_node_t where)
{
switch (vlog_kind(v)) {
case V_NET_DECL:
break;
case V_PORT_DECL:
if (vlog_has_ref(v))
vlog_check_net_lvalue(vlog_ref(v), where);
break;
case V_BIT_SELECT:
case V_REF:
if (vlog_has_ref(v))
vlog_check_net_lvalue(vlog_ref(v), v);
break;
case V_CONCAT:
{
const int nparams = vlog_params(v);
for (int i = 0; i < nparams; i++) {
vlog_node_t p = vlog_param(v, i);
vlog_check_net_lvalue(p, p);
}
}
break;
default:
{
diag_t *d = diag_new(DIAG_ERROR, vlog_loc(where));
name_for_diag(d, where, "target");
diag_suppress(d, has_error(where));
diag_printf(d, " cannot be driven by continuous assignment");
diag_emit(d);
}
}
}

static void vlog_check_assign(vlog_node_t stmt)
{
vlog_node_t target = vlog_target(stmt);
Expand All @@ -252,13 +286,7 @@ static void vlog_check_assign(vlog_node_t stmt)
vlog_node_t value = vlog_value(stmt);
vlog_check(value);

if (!vlog_is_net(target)) {
diag_t *d = diag_new(DIAG_ERROR, vlog_loc(target));
name_for_diag(d, target, "target");
diag_suppress(d, has_error(target));
diag_printf(d, " cannot be driven by continuous assignment");
diag_emit(d);
}
vlog_check_net_lvalue(target, target);
}

static void vlog_check_timing(vlog_node_t timing)
Expand Down Expand Up @@ -613,6 +641,15 @@ static void vlog_check_cond_expr(vlog_node_t expr)
vlog_check(vlog_right(expr));
}

static void vlog_check_concat(vlog_node_t expr)
{
const int nparams = vlog_params(expr);
for (int i = 0; i < nparams; i++) {
vlog_node_t p = vlog_param(expr, i);
vlog_check(p);
}
}

void vlog_check(vlog_node_t v)
{
switch (vlog_kind(v)) {
Expand Down Expand Up @@ -729,6 +766,9 @@ void vlog_check(vlog_node_t v)
case V_COND_EXPR:
vlog_check_cond_expr(v);
break;
case V_CONCAT:
vlog_check_concat(v);
break;
default:
fatal_at(vlog_loc(v), "cannot check verilog node %s",
vlog_kind_str(vlog_kind(v)));
Expand Down
1 change: 1 addition & 0 deletions test/dump/vlog1.v
Original file line number Diff line number Diff line change
Expand Up @@ -50,5 +50,6 @@ module mod3; // Check operator precedence
end
real v1 = 1.5;
integer v2 = x ? 1 : 2;
assign z = {x, y};
endmodule // mod3

2 changes: 1 addition & 1 deletion test/run_ivtest.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
IvtestDir = Pathname.new(ARGV[0]).realpath
GitRev = IO::popen("git rev-parse --short HEAD").read.chomp
Tool = ENV['NVC'] || 'nvc'
ExpectFails = 1324
ExpectFails = 1280

ENV['NVC_COLORS'] = 'always'

Expand Down
1 change: 1 addition & 0 deletions test/test_dump.c
Original file line number Diff line number Diff line change
Expand Up @@ -564,6 +564,7 @@ START_TEST(test_vlog1)
" if ((x == y) || (y == z));\n"
" if ((x & y) == z);\n"
" end\n"
" assign z = {x, y};\n"
"endmodule // mod3\n\n");
tb_rewind(tb);

Expand Down
25 changes: 24 additions & 1 deletion test/test_vlog.c
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ START_TEST(test_parse1)
vlog_node_t m = vlog_parse();
fail_if(m == NULL);
fail_unless(vlog_kind(m) == V_MODULE);
fail_unless(vlog_stmts(m) == 12);
fail_unless(vlog_stmts(m) == 14);
fail_unless(vlog_ports(m) == 0);
fail_unless(vlog_decls(m) == 14);

Expand Down Expand Up @@ -632,6 +632,28 @@ START_TEST(test_pp3)
}
END_TEST

START_TEST(test_concat1)
{
input_from_file(TESTDIR "/vlog/concat1.v");

const error_t expect[] = {
{ 10, "'q' cannot be driven by continuous assignment" },
{ -1, NULL }
};
expect_errors(expect);

vlog_node_t m = vlog_parse();
fail_if(m == NULL);
fail_unless(vlog_kind(m) == V_MODULE);

vlog_check(m);

fail_unless(vlog_parse() == NULL);

check_expected_errors();
}
END_TEST

Suite *get_vlog_tests(void)
{
Suite *s = suite_create("vlog");
Expand All @@ -656,6 +678,7 @@ Suite *get_vlog_tests(void)
tcase_add_test(tc, test_union1);
tcase_add_test(tc, test_param1);
tcase_add_test(tc, test_pp3);
tcase_add_test(tc, test_concat1);
suite_add_tcase(s, tc);

return s;
Expand Down
12 changes: 12 additions & 0 deletions test/vlog/concat1.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
module concat1;
wire x, y;
wire [7:0] z;
real r1;
reg q;

assign a1 = {x, y}; // OK
assign a2 = {r1, x}; // Error
assign {z[0], z[4]} = {x, y}; // OK
assign {x, q} = 2'b11; // Error

endmodule // concat1
2 changes: 2 additions & 0 deletions test/vlog/parse1.v
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,6 @@ module parse1;
real r3 = 1.0;
shortreal r4 = 6.7;
realtime r5 = 1.0;
assign r2 = {x, y};
assign {r1, r2} = {x, y};
endmodule // parse1

0 comments on commit 69e5210

Please sign in to comment.