diff --git a/ivtest/ivltests/sv_type_identifier_net_name.v b/ivtest/ivltests/sv_type_identifier_net_name.v new file mode 100644 index 000000000..c92883ea0 --- /dev/null +++ b/ivtest/ivltests/sv_type_identifier_net_name.v @@ -0,0 +1,103 @@ +// Check that net names can shadow visible type identifiers. + +typedef logic [7:0] T; +typedef int U; +typedef logic [5:0] V; + +`define check(value, expected, error) \ + if ((value) !== (expected)) begin \ + $display("FAILED(%0d). %s", `__LINE__, error); \ + $display(" expected %0h, got %0h", expected, value); \ + failed = 1'b1; \ + end + +module net_name(output reg failed); + wire T = 1'b1; + + initial begin + failed = 1'b0; + + `check(T, 1'b1, "wire T did not declare a one-bit net"); + end +endmodule + +module net_list(output reg failed); + wire T, U; + + assign T = 1'b0; + assign U = 1'b1; + + initial begin + failed = 1'b0; + + `check(T, 1'b0, "type identifier net list first value mismatch"); + `check(U, 1'b1, "type identifier net list continuation mismatch"); + end +endmodule + +module net_array(output reg failed); + wire T [1:0]; + + assign T[0] = 1'b0; + assign T[1] = 1'b1; + + initial begin + failed = 1'b0; + + `check(T[0], 1'b0, "type identifier net array first value mismatch"); + `check(T[1], 1'b1, "type identifier net array second value mismatch"); + end +endmodule + +module net_type(output reg failed); + wire T x = 8'ha5; + wire T [1:0] y = 16'h5aa5; + wire V v0, V; + wire T T; + + assign v0 = 6'h2a; + assign V = 6'h15; + assign T = 8'h3c; + + initial begin + failed = 1'b0; + + `check($bits(x), 8, "typed net declaration width regressed"); + `check(x, 8'ha5, "typed net declaration value regressed"); + `check($bits(y), 16, "typed packed net declaration width regressed"); + `check(y, 16'h5aa5, "typed packed net declaration value regressed"); + `check($bits(v0), 6, "type identifier net declaration list first width mismatch"); + `check($bits(V), 6, "type identifier net declaration list did not allow typedef name as continuation"); + `check(V, 6'h15, "type identifier net declaration list value mismatch"); + `check($bits(T), 8, "type-name net declaration did not keep typedef type"); + `check(T, 8'h3c, "type-name net declaration value mismatch"); + end +endmodule + +module test; + reg failed; + wire f0; + wire f1; + wire f2; + wire f3; + + net_name m0(f0); + net_list m1(f1); + net_array m2(f2); + net_type m3(f3); + + initial begin + failed = 1'b0; + + #1; + + `check(f0, 1'b0, "wire T module failed"); + `check(f1, 1'b0, "wire T, U module failed"); + `check(f2, 1'b0, "wire T array module failed"); + `check(f3, 1'b0, "typed wire T module failed"); + + if (!failed) begin + $display("PASSED"); + end + end +endmodule diff --git a/ivtest/ivltests/sv_type_identifier_port_name.v b/ivtest/ivltests/sv_type_identifier_port_name.v new file mode 100644 index 000000000..b5a8f5b41 --- /dev/null +++ b/ivtest/ivltests/sv_type_identifier_port_name.v @@ -0,0 +1,236 @@ +// Check that module port names can shadow visible type identifiers. + +typedef logic [3:0] T; + +package p; + typedef logic [5:0] PT; +endpackage + +`define check(value, expected, error) \ + if ((value) !== (expected)) begin \ + $display("FAILED(%0d). %s", `__LINE__, error); \ + $display(" expected %0h, got %0h", expected, value); \ + failed = 1'b1; \ + end + +module ansi_name(input T); +endmodule + +module ansi_type(input T x); +endmodule + +module ansi_name_dim(input T [1:0]); +endmodule + +module ansi_type_dim(input T [1:0] x); +endmodule + +module ansi_name_list(input T, U); +endmodule + +module ansi_type_list(input T x, y); +endmodule + +module ansi_type_list_shadow(input T x, T); +endmodule + +module ansi_type_name(input T T, output logic ok); + initial ok = ($bits(T) == 4); +endmodule + +module ansi_type_redecl(input n, T x); +endmodule + +module ansi_type_redecl_dim(input n, T [1:0] x); +endmodule + +module ansi_name_redecl_dim(input n, T [1:0]); +endmodule + +module ansi_pkg_type_redecl(input n, p::PT x); +endmodule + +module ansi_pkg_type_redecl_dim(input n, p::PT [1:0] x); +endmodule + +module decl_name(T); + input T; +endmodule + +module decl_type(x); + input T x; +endmodule + +module decl_type_dim(x); + input T [1:0] x; +endmodule + +module decl_external(.T(x)); + input x; +endmodule + +module decl_name_list(T, U); + input T, U; +endmodule + +module decl_type_list(x, y); + input T x, y; +endmodule + +module decl_type_list_shadow(x, T); + input T x, T; +endmodule + +module decl_type_name(T, ok); + input T T; + output logic ok; + + initial ok = ($bits(T) == 4); +endmodule + +module test; + + reg failed; + logic n; + T t; + logic n_dim [1:0]; + T [1:0] t_dim; + logic n0, n1; + T t0, t1; + logic rn; + T rt; + T [1:0] rt_dim; + logic rn_dim; + logic rt_name_dim [1:0]; + logic rp_n; + logic [5:0] rp_t; + logic rp_dim_n; + logic [1:0][5:0] rp_t_dim; + logic d_n; + T d_t; + T [1:0] d_t_dim; + logic d_ext; + logic d_n0, d_n1; + T d_t0, d_t1; + T s_t0, s_t1; + T d_s_t0, d_s_t1; + T p_tn; + T d_p_tn; + logic p_tn_ok; + logic d_p_tn_ok; + + ansi_name m0(n); + ansi_type m1(t); + ansi_name_dim m2(n_dim); + ansi_type_dim m3(t_dim); + ansi_name_list m4(n0, n1); + ansi_type_list m5(t0, t1); + ansi_type_list_shadow m17(s_t0, s_t1); + ansi_type_name m19(p_tn, p_tn_ok); + ansi_type_redecl m12(rn, rt); + ansi_type_redecl_dim m13(rn, rt_dim); + ansi_name_redecl_dim m14(rn_dim, rt_name_dim); + ansi_pkg_type_redecl m15(rp_n, rp_t); + ansi_pkg_type_redecl_dim m16(rp_dim_n, rp_t_dim); + decl_name m6(d_n); + decl_type m7(d_t); + decl_type_dim m8(d_t_dim); + decl_external m9(d_ext); + decl_name_list m10(d_n0, d_n1); + decl_type_list m11(d_t0, d_t1); + decl_type_list_shadow m18(d_s_t0, d_s_t1); + decl_type_name m20(d_p_tn, d_p_tn_ok); + + initial begin + failed = 1'b0; + + n = 1'b1; + t = 4'ha; + n_dim[0] = 1'b0; + n_dim[1] = 1'b1; + t_dim[0] = 4'h3; + t_dim[1] = 4'hc; + n0 = 1'b0; + n1 = 1'b1; + t0 = 4'h5; + t1 = 4'ha; + s_t0 = 4'h6; + s_t1 = 4'h9; + p_tn = 4'h3; + rn = 1'b1; + rt = 4'hc; + rt_dim[0] = 4'h3; + rt_dim[1] = 4'ha; + rn_dim = 1'b0; + rt_name_dim[0] = 1'b1; + rt_name_dim[1] = 1'b0; + rp_n = 1'b1; + rp_t = 6'h2a; + rp_dim_n = 1'b0; + rp_t_dim[0] = 6'h15; + rp_t_dim[1] = 6'h2a; + d_n = 1'b1; + d_t = 4'h6; + d_t_dim[0] = 4'h7; + d_t_dim[1] = 4'h8; + d_ext = 1'b0; + d_n0 = 1'b1; + d_n1 = 1'b0; + d_t0 = 4'h9; + d_t1 = 4'h6; + d_s_t0 = 4'h5; + d_s_t1 = 4'ha; + d_p_tn = 4'hc; + + #1; + + `check($bits(n), 1, "input T was not parsed as a port name"); + `check($bits(t), 4, "input T x was not parsed as a typed port"); + `check($bits(n_dim), 2, "input T [1:0] was not parsed as a port array"); + `check($bits(t_dim), 8, "input T [1:0] x was not parsed as a typed port array"); + `check($bits(n0), 1, "input T, U first port did not keep implicit type"); + `check($bits(n1), 1, "input T, U continuation did not keep implicit type"); + `check($bits(t0), 4, "input T x, y first port did not keep typedef type"); + `check($bits(t1), 4, "input T x, y continuation did not keep typedef type"); + `check(t0, 4'h5, "Typed port list first value mismatch"); + `check(t1, 4'ha, "Typed port list continuation mismatch"); + `check($bits(s_t0), 4, "input T x, T first port did not keep typedef type"); + `check($bits(s_t1), 4, "input T x, T continuation did not allow typedef name as port name"); + `check(s_t1, 4'h9, "Typed port list shadowing value mismatch"); + `check($bits(p_tn), 4, "input T T did not keep typedef type"); + `check(p_tn_ok, 1'b1, "input T T was not available as a typed port"); + `check($bits(rn), 1, "input n, T x first port did not keep implicit type"); + `check($bits(rt), 4, "input n, T x second port did not keep typedef type"); + `check(rt, 4'hc, "Inherited-direction typedef port value mismatch"); + `check($bits(rt_dim), 8, "input n, T [1:0] x did not keep typedef packed dimensions"); + `check(rt_dim[0], 4'h3, "Inherited-direction typedef packed array value mismatch"); + `check(rt_dim[1], 4'ha, "Inherited-direction typedef packed array value mismatch"); + `check($bits(rn_dim), 1, "input n, T [1:0] first port did not keep implicit type"); + `check($bits(rt_name_dim), 2, "input n, T [1:0] second port was not parsed as a port array"); + `check($bits(rp_t), 6, "input n, p::PT x second port did not keep package typedef type"); + `check(rp_t, 6'h2a, "Inherited-direction package typedef port value mismatch"); + `check($bits(rp_t_dim), 12, "input n, p::PT [1:0] x did not keep package typedef packed dimensions"); + `check(rp_t_dim[0], 6'h15, "Inherited-direction package typedef packed array value mismatch"); + `check(rp_t_dim[1], 6'h2a, "Inherited-direction package typedef packed array value mismatch"); + `check($bits(d_n), 1, "input T was not parsed as a port declaration name"); + `check($bits(d_t), 4, "input T x was not parsed as a typed port declaration"); + `check($bits(d_t_dim), 8, "input T [1:0] x was not parsed as a typed port declaration array"); + `check($bits(d_ext), 1, ".T(x) was not parsed as an external port name"); + `check($bits(d_n0), 1, "input T, U first declaration did not keep implicit type"); + `check($bits(d_n1), 1, "input T, U continuation declaration did not keep implicit type"); + `check($bits(d_t0), 4, "input T x, y first declaration did not keep typedef type"); + `check($bits(d_t1), 4, "input T x, y continuation declaration did not keep typedef type"); + `check(d_t0, 4'h9, "Typed port declaration list first value mismatch"); + `check(d_t1, 4'h6, "Typed port declaration list continuation mismatch"); + `check($bits(d_s_t0), 4, "input T x, T first declaration did not keep typedef type"); + `check($bits(d_s_t1), 4, "input T x, T declaration did not allow typedef name as port name"); + `check(d_s_t1, 4'ha, "Typed port declaration list shadowing value mismatch"); + `check($bits(d_p_tn), 4, "non-ANSI input T T did not keep typedef type"); + `check(d_p_tn_ok, 1'b1, "non-ANSI input T T was not available as a typed port"); + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_type_identifier_task_function_argument_name.v b/ivtest/ivltests/sv_type_identifier_task_function_argument_name.v new file mode 100644 index 000000000..835c84b82 --- /dev/null +++ b/ivtest/ivltests/sv_type_identifier_task_function_argument_name.v @@ -0,0 +1,120 @@ +// Check that task and function argument names can shadow visible type identifiers. + +typedef int T; + +module test; + + reg failed; + + `define check(value, expected, error) \ + if ((value) !== (expected)) begin \ + $display("FAILED(%0d). %s", `__LINE__, error); \ + $display(" expected %0h, got %0h", expected, value); \ + failed = 1'b1; \ + end + + function int f_name(input T); + return ($bits(T) == 1 && T === 1'b1) ? 32'd33 : -1; + endfunction + + function int f_type(input T value); + return ($bits(value) == 32) ? value : -1; + endfunction + + function int f_type_list(input T value, T); + return $bits(value) + $bits(T); + endfunction + + function int f_type_name(input T T); + return $bits(T); + endfunction + + function int f_decl_name; + input T; + return $bits(T); + endfunction + + function int f_decl_type; + input T value; + return $bits(value); + endfunction + + function int f_decl_type_name; + input T T; + return $bits(T); + endfunction + + task t_name(input T, output int value); + value = ($bits(T) == 1 && T === 1'b1) ? 32'd44 : -1; + endtask + + task t_type(input T value, output int result); + result = ($bits(value) == 32) ? value : -1; + endtask + + task t_type_list(input T value, T, output int result); + result = $bits(value) + $bits(T); + endtask + + task t_type_name(input T T, output int value); + value = $bits(T); + endtask + + task t_decl_name; + input T; + output int value; + value = $bits(T); + endtask + + task t_decl_type; + input T value; + output int result; + result = $bits(value); + endtask + + task t_decl_type_name; + input T T; + output int value; + value = $bits(T); + endtask + + initial begin + int r0; + int r1; + int r2; + int r3; + int r4; + int r5; + int r6; + + failed = 1'b0; + + t_name(1'b1, r0); + t_type(32'd55, r1); + t_type_list(32'd11, 32'd22, r2); + t_decl_name(1'b1, r3); + t_decl_type(32'd33, r4); + t_type_name(32'd44, r5); + t_decl_type_name(32'd55, r6); + + `check(f_name(1'b1), 32'd33, "Function argument did not hide typedef"); + `check(f_type(32'd66), 32'd66, "Function typed argument regressed"); + `check(f_type_list(32'd11, 32'd22), 64, "Function typed argument list shadowing mismatch"); + `check(f_type_name(32'd33), 32, "Function type-name argument did not keep typedef type"); + `check(f_decl_name(1'b1), 1, "Function non-ANSI argument did not hide typedef"); + `check(f_decl_type(32'd66), 32, "Function non-ANSI typed argument regressed"); + `check(f_decl_type_name(32'd77), 32, "Function non-ANSI type-name argument did not keep typedef type"); + `check(r0, 32'd44, "Task argument did not hide typedef"); + `check(r1, 32'd55, "Task typed argument regressed"); + `check(r2, 64, "Task typed argument list shadowing mismatch"); + `check(r3, 1, "Task non-ANSI argument did not hide typedef"); + `check(r4, 32, "Task non-ANSI typed argument regressed"); + `check(r5, 32, "Task type-name argument did not keep typedef type"); + `check(r6, 32, "Task non-ANSI type-name argument did not keep typedef type"); + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_type_identifier_variable_name.v b/ivtest/ivltests/sv_type_identifier_variable_name.v new file mode 100644 index 000000000..c4fadae33 --- /dev/null +++ b/ivtest/ivltests/sv_type_identifier_variable_name.v @@ -0,0 +1,152 @@ +// Check that variable names can shadow visible type identifiers. + +typedef logic [7:0] T; +typedef int V; +typedef int W; +typedef logic [6:0] A; +typedef logic [5:0] B; +typedef logic [4:0] C; +typedef logic [3:0] D; +typedef logic [2:0] E; +typedef logic [1:0] F; +typedef logic [2:0] G; +typedef logic [3:0] H; +typedef logic [4:0] I; +typedef logic [2:0] P; +bit X; + +package p; + var C; + var D x, D; + var P P; +endpackage + +module test; + + reg failed; + + `define check(value, expected, error) \ + if ((value) !== (expected)) begin \ + $display("FAILED(%0d). %s", `__LINE__, error); \ + $display(" expected %0h, got %0h", expected, value); \ + failed = 1'b1; \ + end + + typedef logic [3:0] X; + + T outer; + T a, b; + A a0, A; + E E; + int T, U; + var V; + var B b0, B; + var F F; + X x; + + function int f; + int T; + + T = 32'd11; + return T; + endfunction + + function int f_type_name; + H H; + + H = 4'ha; + return $bits(H) + H; + endfunction + + task t(output int value); + int T; + + T = 32'd22; + value = T; + endtask + + task t_type_name(output int value); + I I; + + I = 5'h15; + value = $bits(I) + I; + endtask + + initial begin + int r; + int r_type_name; + int tr_type_name; + var W; + + failed = 1'b0; + + outer = 8'ha5; + a = 8'h33; + b = 8'hcc; + a0 = 7'h2a; + A = 7'h15; + E = 3'h5; + T = 32'd23; + U = 32'd41; + V = 1'b1; + b0 = 6'h2a; + B = 6'h15; + F = 2'h2; + W = 1'b0; + x = 4'hc; + t(r); + t_type_name(tr_type_name); + + begin : block_scope + int T; + + T = 32'd7; + `check(T, 32'd7, "Block declaration did not hide typedef"); + end + + begin : block_type_name + G G; + + G = 3'h3; + `check($bits(G), 3, "Block type-name declaration did not keep typedef type"); + `check(G, 3'h3, "Block type-name declaration value mismatch"); + end + + r_type_name = f_type_name(); + + `check(outer, 8'ha5, "Typedef value changed"); + `check(T, 32'd23, "Module declaration did not hide typedef"); + `check(U, 32'd41, "Declaration list continuation mismatch"); + `check($bits(V), 1, "Module var declaration did not hide typedef width"); + `check(V, 1'b1, "Module var declaration did not hide typedef value"); + `check($bits(W), 1, "Block var declaration did not hide typedef width"); + `check(W, 1'b0, "Block var declaration did not hide typedef value"); + `check(a, 8'h33, "Type declaration list first value mismatch"); + `check(b, 8'hcc, "Type declaration list continuation mismatch"); + `check($bits(a0), 7, "Type declaration list did not keep typedef type"); + `check($bits(A), 7, "Type declaration list did not allow typedef name as continuation"); + `check(A, 7'h15, "Type declaration list shadowing value mismatch"); + `check($bits(E), 3, "Type-name declaration did not keep typedef type"); + `check(E, 3'h5, "Type-name declaration value mismatch"); + `check($bits(b0), 6, "Var declaration list did not keep typedef type"); + `check($bits(B), 6, "Var declaration list did not allow typedef name as continuation"); + `check(B, 6'h15, "Var declaration list shadowing value mismatch"); + `check($bits(F), 2, "Var type-name declaration did not keep typedef type"); + `check(F, 2'h2, "Var type-name declaration value mismatch"); + `check($bits(p::C), 1, "Package var declaration did not hide typedef width"); + `check($bits(p::x), 4, "Package type declaration list first width mismatch"); + `check($bits(p::D), 4, "Package type declaration list did not allow typedef name as continuation"); + `check($bits(p::P), 3, "Package type-name declaration did not keep typedef type"); + `check(f(), 32'd11, "Function declaration did not hide typedef"); + `check(r_type_name, 14, "Function type-name declaration mismatch"); + `check(r, 32'd22, "Task declaration did not hide typedef"); + `check(tr_type_name, 26, "Task type-name declaration mismatch"); + `check($bits(x), 4, "Local typedef did not hide outer identifier"); + `check(x, 4'hc, "Local typedef value mismatch"); + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/regress-vvp.list b/ivtest/regress-vvp.list index 424ce1cc6..c25189cda 100644 --- a/ivtest/regress-vvp.list +++ b/ivtest/regress-vvp.list @@ -385,8 +385,12 @@ sv_type_identifier_foreach_name vvp_tests/sv_type_identifier_foreach_name.json sv_type_identifier_genvar_name vvp_tests/sv_type_identifier_genvar_name.json sv_type_identifier_modport_name vvp_tests/sv_type_identifier_modport_name.json sv_type_identifier_module_name vvp_tests/sv_type_identifier_module_name.json +sv_type_identifier_net_name vvp_tests/sv_type_identifier_net_name.json sv_type_identifier_package_item vvp_tests/sv_type_identifier_package_item.json +sv_type_identifier_port_name vvp_tests/sv_type_identifier_port_name.json sv_type_identifier_specparam_name vvp_tests/sv_type_identifier_specparam_name.json +sv_type_identifier_task_function_argument_name vvp_tests/sv_type_identifier_task_function_argument_name.json +sv_type_identifier_variable_name vvp_tests/sv_type_identifier_variable_name.json sv_type_param_restrict_class1 vvp_tests/sv_type_param_restrict_class1.json sv_type_param_restrict_class2 vvp_tests/sv_type_param_restrict_class2.json sv_type_param_restrict_class_fail1 vvp_tests/sv_type_param_restrict_class_fail1.json diff --git a/ivtest/vvp_tests/sv_type_identifier_net_name.json b/ivtest/vvp_tests/sv_type_identifier_net_name.json new file mode 100644 index 000000000..5b5789167 --- /dev/null +++ b/ivtest/vvp_tests/sv_type_identifier_net_name.json @@ -0,0 +1,9 @@ +{ + "type" : "normal", + "source" : "sv_type_identifier_net_name.v", + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "Typedefs and SystemVerilog net types are SystemVerilog", + "type" : "CE" + } +} diff --git a/ivtest/vvp_tests/sv_type_identifier_port_name.json b/ivtest/vvp_tests/sv_type_identifier_port_name.json new file mode 100644 index 000000000..f94594bb3 --- /dev/null +++ b/ivtest/vvp_tests/sv_type_identifier_port_name.json @@ -0,0 +1,9 @@ +{ + "type" : "normal", + "source" : "sv_type_identifier_port_name.v", + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "Typedefs and ANSI ports are SystemVerilog", + "type" : "CE" + } +} diff --git a/ivtest/vvp_tests/sv_type_identifier_task_function_argument_name.json b/ivtest/vvp_tests/sv_type_identifier_task_function_argument_name.json new file mode 100644 index 000000000..a8ed1e0fd --- /dev/null +++ b/ivtest/vvp_tests/sv_type_identifier_task_function_argument_name.json @@ -0,0 +1,9 @@ +{ + "type" : "normal", + "source" : "sv_type_identifier_task_function_argument_name.v", + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "Typedefs and task/function arguments are SystemVerilog", + "type" : "CE" + } +} diff --git a/ivtest/vvp_tests/sv_type_identifier_variable_name.json b/ivtest/vvp_tests/sv_type_identifier_variable_name.json new file mode 100644 index 000000000..fde51c2a7 --- /dev/null +++ b/ivtest/vvp_tests/sv_type_identifier_variable_name.json @@ -0,0 +1,9 @@ +{ + "type" : "normal", + "source" : "sv_type_identifier_variable_name.v", + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "Typedefs and block/task scope are SystemVerilog", + "type" : "CE" + } +} diff --git a/parse.y b/parse.y index 4b44d0358..1c9caf208 100644 --- a/parse.y +++ b/parse.y @@ -124,6 +124,41 @@ static void check_net_decl_assigns(const struct vlltype&loc, } } +static data_type_t *pform_make_parray_type(const struct vlltype&loc, + data_type_t *base, + std::list *pdims) +{ + if (!pdims) + return base; + + data_type_t *type = new parray_type_t(base, pdims); + FILE_NAME(type, loc); + + return type; +} + +template +static void set_type_id_range(T&value, data_type_t *type, char *id, + unsigned lexical_pos, + std::list *ranges) +{ + value.type = type; + value.id = id; + value.lexical_pos = lexical_pos; + value.ranges = ranges; +} + +template +static void delete_type_id_range(T&value) +{ + delete value.type; + delete[] value.id; + delete value.ranges; + value.type = nullptr; + value.id = nullptr; + value.ranges = nullptr; +} + /* The rules sometimes push attributes into a global context where sub-rules may grab them. This makes parser rules a little easier to write in some cases. */ @@ -169,25 +204,29 @@ static std::list*attributes_in_context = 0; static const struct str_pair_t pull_strength = { IVL_DR_PULL, IVL_DR_PULL }; static const struct str_pair_t str_strength = { IVL_DR_STRONG, IVL_DR_STRONG }; -static std::list* make_port_list(char*id, unsigned idn, - std::list*udims, - PExpr*expr) +static struct pform_port_list make_port_list(data_type_t *type, char*id, + unsigned idn, + std::list*udims, + PExpr*expr) { - std::list*tmp = new std::list; + struct pform_port_list list; + list.type = type; + list.ports = new std::list; pform_ident_t tmp_name = { lex_strings.make(id), idn }; - tmp->push_back(pform_port_t(tmp_name, udims, expr)); + list.ports->push_back(pform_port_t(tmp_name, udims, expr)); delete[]id; - return tmp; + return list; } -static std::list* make_port_list(list*tmp, - char*id, unsigned idn, - std::list*udims, - PExpr*expr) + +static struct pform_port_list make_port_list(struct pform_port_list list, + char*id, unsigned idn, + std::list*udims, + PExpr*expr) { pform_ident_t tmp_name = { lex_strings.make(id), idn }; - tmp->push_back(pform_port_t(tmp_name, udims, expr)); + list.ports->push_back(pform_port_t(tmp_name, udims, expr)); delete[]id; - return tmp; + return list; } static std::list* list_from_identifier(char*id, unsigned idn) @@ -206,6 +245,60 @@ static std::list* list_from_identifier(list*tmp, return tmp; } +static decl_assignment_t *pform_make_var_decl(const YYLTYPE&loc, char *id, + unsigned lexical_pos, + std::list*udims, + PExpr *init) +{ + if (init && pform_peek_scope()->var_init_needs_explicit_lifetime() && + var_lifetime == LexicalScope::INHERITED) { + cerr << loc << ": warning: Static variable initialization requires " + "explicit lifetime in this context." << endl; + warn_count += 1; + } + decl_assignment_t *decl = new decl_assignment_t; + decl->name = { lex_strings.make(id), lexical_pos }; + if (udims) { + decl->index = *udims; + delete udims; + } + decl->expr.reset(init); + delete[] id; + return decl; +} + +static decl_assignment_t *pform_make_var_decl(const YYLTYPE&loc, char *id, + std::list*udims, + PExpr *init) +{ + return pform_make_var_decl(loc, id, loc.lexical_pos, udims, init); +} + +static decl_assignment_t *pform_make_net_decl(const YYLTYPE&loc, char *id, + unsigned lexical_pos, + std::list*udims, + PExpr *init) +{ + decl_assignment_t *decl = new decl_assignment_t; + decl->name = { lex_strings.make(id), lexical_pos }; + if (udims) { + decl->index = *udims; + if (init) + pform_requires_sv(loc, "Assignment of net array during declaration"); + delete udims; + } + decl->expr.reset(init); + delete[] id; + return decl; +} + +static decl_assignment_t *pform_make_net_decl(const YYLTYPE&loc, char *id, + std::list*udims, + PExpr *init) +{ + return pform_make_net_decl(loc, id, loc.lexical_pos, udims, init); +} + template void append(vector&out, const std::vector&in) { for (size_t idx = 0 ; idx < in.size() ; idx += 1) @@ -427,14 +520,15 @@ static void port_declaration_context_init(void) } Module::port_t *module_declare_port(const YYLTYPE&loc, char *id, - NetNet::PortType port_type, + unsigned lexical_pos, + NetNet::PortType port_type, NetNet::Type net_type, data_type_t *data_type, std::list *unpacked_dims, PExpr *default_value, std::list *attributes) { - pform_ident_t name = { lex_strings.make(id), loc.lexical_pos }; + pform_ident_t name = { lex_strings.make(id), lexical_pos }; delete[] id; Module::port_t *port = pform_module_port_reference(loc, name.first); @@ -527,8 +621,7 @@ Module::port_t *module_declare_interface_port(const YYLTYPE&loc, char *type, std::list*perm_strings; std::list*identifiers; - - std::list*port_list; + struct pform_port_list port_list; std::vector* tf_ports; @@ -583,6 +676,11 @@ Module::port_t *module_declare_interface_port(const YYLTYPE&loc, char *type, decl_assignment_t*decl_assignment; std::list*decl_assignments; + struct { + data_type_t *type; + std::list *decl_assignments; + } decl_assignments_with_type; + struct_member_t*struct_member; std::list*struct_members; struct_type_t*struct_type; @@ -597,6 +695,13 @@ Module::port_t *module_declare_interface_port(const YYLTYPE&loc, char *type, typedef_t*type; } type_identifier; + struct { + data_type_t *type; + char *id; + unsigned lexical_pos; + std::list*ranges; + } type_id_range; + struct { data_type_t*type; std::list *args; @@ -807,12 +912,15 @@ Module::port_t *module_declare_interface_port(const YYLTYPE&loc, char *type, %type net_decl_assign variable_decl_assignment %type net_decl_assigns list_of_variable_decl_assignments +%type list_of_net_decl_assignments_with_type +%type list_of_variable_decl_assignments_with_type %type data_type data_type_opt data_type_or_implicit data_type_or_implicit_or_void -%type data_type_or_implicit_no_opt -%type simple_type_or_string let_formal_type -%type packed_array_data_type -%type ps_type_identifier +%type implicit_type +%type reg_prefixed_atomic_type simple_type_or_string let_formal_type +%type packed_array_data_type atomic_type + +%type ps_type_identifier ps_type_identifier_dim %type simple_packed_type %type class_scope %type struct_union_member @@ -833,7 +941,7 @@ Module::port_t *module_declare_interface_port(const YYLTYPE&loc, char *type, %type net_type net_type_opt net_type_or_var net_type_or_var_opt %type gatetype switchtype %type port_direction port_direction_opt -%type integer_vector_type +%type integer_vector_type integer_vector_type_no_reg %type parameter_value_opt %type event_expression_list @@ -877,6 +985,11 @@ Module::port_t *module_declare_interface_port(const YYLTYPE&loc, char *type, %type compressed_operator %type forward_type forward_type_without_enum +%type data_type_or_implicit_plus_id_base +%type data_type_or_implicit_plus_id_dim +%type partial_port_name_dim +%type partial_port_type_plus_id_dim +%type partial_port_typedef_plus_id_dim %token K_TAND %nonassoc K_PLUS_EQ K_MINUS_EQ K_MUL_EQ K_DIV_EQ K_MOD_EQ K_AND_EQ K_OR_EQ @@ -1332,13 +1445,13 @@ data_declaration /* IEEE1800-2005: A.2.1.3 */ $1, $2); var_lifetime = LexicalScope::INHERITED; } - | attribute_list_opt K_const_opt K_var variable_lifetime_opt data_type_or_implicit list_of_variable_decl_assignments ';' - { data_type_t *data_type = $5; + | attribute_list_opt K_const_opt K_var variable_lifetime_opt list_of_variable_decl_assignments_with_type ';' + { data_type_t*data_type = $5.type; if (!data_type) { - data_type = new vector_type_t(IVL_VT_LOGIC, false, 0); + data_type = new vector_type_t(IVL_VT_LOGIC, false, nullptr); FILE_NAME(data_type, @3); } - pform_make_var(@3, $6, data_type, $1, $2); + pform_make_var(@3, $5.decl_assignments, data_type, $1, $2); var_lifetime = LexicalScope::INHERITED; } | attribute_list_opt K_event event_variable_list ';' @@ -1354,6 +1467,7 @@ package_scope } ; + // Type identifiers with and without attached packed dimensions. ps_type_identifier /* IEEE1800-2017: A.9.3 */ : TYPE_IDENTIFIER { pform_set_type_referenced(@1, $1.text); @@ -1369,17 +1483,33 @@ ps_type_identifier /* IEEE1800-2017: A.9.3 */ } ; +ps_type_identifier_dim /* IEEE1800-2017: A.9.3 */ + : TYPE_IDENTIFIER dimensions_opt + { pform_set_type_referenced(@1, $1.text); + data_type_t*tmp = new typeref_t($1.type); + FILE_NAME(tmp, @1); + delete[]$1.text; + $$ = pform_make_parray_type(@2, tmp, $2); + } + | package_scope TYPE_IDENTIFIER dimensions_opt + { lex_in_package_scope(nullptr); + data_type_t*tmp = new typeref_t($2.type, $1); + FILE_NAME(tmp, @2); + $$ = pform_make_parray_type(@3, tmp, $3); + delete[]$2.text; + } + ; + /* Data types that can have packed dimensions directly attached to it */ packed_array_data_type /* IEEE1800-2005: A.2.2.1 */ - : enum_data_type - { $$ = $1; } - | struct_data_type + : enum_data_type dimensions_opt + { $$ = pform_make_parray_type(@2, $1, $2); } + | struct_data_type dimensions_opt { if (!$1->packed_flag && !($1->union_flag && $1->soft_flag)) { yyerror(@1, "sorry: Unpacked structs not supported."); - } - $$ = $1; + } + $$ = pform_make_parray_type(@2, $1, $2); } - | ps_type_identifier ; simple_packed_type /* Integer and vector types */ @@ -1400,7 +1530,7 @@ simple_packed_type /* Integer and vector types */ } ; -data_type /* IEEE1800-2005: A.2.2.1 */ +atomic_type : simple_packed_type { $$ = $1; } @@ -1409,14 +1539,40 @@ data_type /* IEEE1800-2005: A.2.2.1 */ FILE_NAME(tmp, @1); $$ = tmp; } - | packed_array_data_type dimensions_opt - { if ($2) { - parray_type_t*tmp = new parray_type_t($1, $2); - FILE_NAME(tmp, @1); - $$ = tmp; - } else { - $$ = $1; - } + | packed_array_data_type { $$ = $1; } + | K_string + { string_type_t*tmp = new string_type_t; + FILE_NAME(tmp, @1); + $$ = tmp; + } + ; + +/* Data types allowed after the historical iverilog extension that permits an + extra leading `reg` in block declarations. Keep `reg` itself out of this + subset so ordinary `reg` declarations continue through the normal rules. */ +reg_prefixed_atomic_type + : integer_vector_type_no_reg unsigned_signed_opt dimensions_opt + { vector_type_t*tmp = new vector_type_t($1, $2, $3); + FILE_NAME(tmp, @1); + $$ = tmp; + } + | atom_type signed_unsigned_opt + { atom_type_t*tmp = new atom_type_t($1, $2); + FILE_NAME(tmp, @1); + $$ = tmp; + } + | K_time unsigned_signed_opt + { atom_type_t*tmp = new atom_type_t(atom_type_t::TIME, $2); + FILE_NAME(tmp, @1); + $$ = tmp; + } + | non_integer_type + { real_type_t*tmp = new real_type_t($1); + FILE_NAME(tmp, @1); + $$ = tmp; + } + | packed_array_data_type + { $$ = $1; } | K_string { string_type_t*tmp = new string_type_t; @@ -1425,6 +1581,11 @@ data_type /* IEEE1800-2005: A.2.2.1 */ } ; +data_type /* IEEE1800-2005: A.2.2.1 */ + : atomic_type { $$ = $1; } + | ps_type_identifier_dim { $$ = $1; } + ; + /* Data type or nothing, but not implicit */ data_type_opt : data_type { $$ = $1; } @@ -1436,6 +1597,11 @@ data_type_opt absent. The context may need that information to decide to resort to left context. */ +data_type_or_implicit /* IEEE1800-2005: A.2.2.1 */ + : data_type_opt { $$ = $1; } + | implicit_type { $$ = $1; } + ; + scalar_vector_opt /*IEEE1800-2005: optional support for packed array */ : K_vectored { /* Ignore */ } @@ -1445,14 +1611,8 @@ scalar_vector_opt /*IEEE1800-2005: optional support for packed array */ { /* Ignore */ } ; -data_type_or_implicit /* IEEE1800-2005: A.2.2.1 */ - : data_type_or_implicit_no_opt - | { $$ = nullptr; } - -data_type_or_implicit_no_opt - : data_type - { $$ = $1; } - | signing dimensions_opt +implicit_type + : signing dimensions_opt { vector_type_t*tmp = new vector_type_t(IVL_VT_LOGIC, $1, $2); tmp->implicit_flag = true; FILE_NAME(tmp, @1); @@ -1466,7 +1626,6 @@ data_type_or_implicit_no_opt } ; - data_type_or_implicit_or_void : data_type_or_implicit { $$ = $1; } @@ -1772,7 +1931,13 @@ inside_expression /* IEEE1800-2005 A.8.3 */ integer_vector_type /* IEEE1800-2005: A.2.2.1 */ : K_reg { $$ = IVL_VT_LOGIC; } /* A synonym for logic. */ - | K_bit { $$ = IVL_VT_BOOL; } + | integer_vector_type_no_reg + { $$ = $1; + } + ; + +integer_vector_type_no_reg + : K_bit { $$ = IVL_VT_BOOL; } | K_logic { $$ = IVL_VT_LOGIC; } | K_bool { $$ = IVL_VT_BOOL; } /* Icarus Verilog xtypes extension */ ; @@ -1962,6 +2127,18 @@ loop_statement /* IEEE1800-2005: A.6.8 */ } ; +list_of_variable_decl_assignments_with_type /* IEEE1800-2005 A.2.3 */ + : data_type_or_implicit_plus_id_dim var_decl_initializer_opt + { std::list*tmp = new std::list; + tmp->push_back(pform_make_var_decl(@1, $1.id, $1.lexical_pos, $1.ranges, $2)); + $$.decl_assignments = tmp; + $$.type = $1.type; + } + | list_of_variable_decl_assignments_with_type ',' variable_decl_assignment + { $1.decl_assignments->push_back($3); + $$ = $1; + } + ; list_of_variable_decl_assignments /* IEEE1800-2005 A.2.3 */ : variable_decl_assignment @@ -1988,23 +2165,8 @@ var_decl_initializer_opt ; variable_decl_assignment /* IEEE1800-2005 A.2.3 */ - : IDENTIFIER dimensions_opt var_decl_initializer_opt - { if ($3 && pform_peek_scope()->var_init_needs_explicit_lifetime() - && (var_lifetime == LexicalScope::INHERITED)) { - cerr << @1 << ": warning: Static variable initialization requires " - "explicit lifetime in this context." << endl; - warn_count += 1; - } - - decl_assignment_t*tmp = new decl_assignment_t; - tmp->name = { lex_strings.make($1), @1.lexical_pos }; - if ($2) { - tmp->index = *$2; - delete $2; - } - tmp->expr.reset($3); - delete[]$1; - $$ = tmp; + : identifier_name dimensions_opt var_decl_initializer_opt + { $$ = pform_make_var_decl(@1, $1, $2, $3); } ; @@ -2077,7 +2239,7 @@ modport_ports_list | modport_ports_list ',' named_expression { if (last_modport_port.type == MP_SIMPLE) { pform_add_modport_port(@3, last_modport_port.direction, - $3->name, $3->parm); + $3->name, $3->parm); } else { yyerror(@3, "error: modport expression not allowed here."); } @@ -2551,11 +2713,81 @@ task_declaration /* IEEE1800-2005: A.2.7 */ tf_port_declaration /* IEEE1800-2005: A.2.7 */ - : port_direction K_var_opt data_type_or_implicit list_of_port_identifiers ';' - { $$ = pform_make_task_ports(@1, $1, $3, $4, true); + : port_direction K_var_opt list_of_port_identifiers ';' + { $$ = pform_make_task_ports(@1, $1, $3.type, $3.ports, true); } ; + // These rules only disambiguate declaration items that can be either an + // implicit declaration name or an explicit type followed by a name. Keep the + // bare `TYPE_IDENTIFIER dimensions_opt` case in the parent rule so a typedef + // name can be shadowed by an unpacked declaration name, while + // `ps_type_identifier_dim identifier_name` still parses a typedef with packed + // dimensions followed by a separate declaration name. +data_type_or_implicit_plus_id_base + : IDENTIFIER + { set_type_id_range($$, nullptr, $1, @1.lexical_pos, nullptr); + } + | atomic_type identifier_name + { set_type_id_range($$, $1, $2, @2.lexical_pos, nullptr); + } + | implicit_type identifier_name + { set_type_id_range($$, $1, $2, @2.lexical_pos, nullptr); + } + | ps_type_identifier_dim identifier_name + { set_type_id_range($$, $1, $2, @2.lexical_pos, nullptr); + } + ; + +data_type_or_implicit_plus_id_dim + : TYPE_IDENTIFIER dimensions_opt + { set_type_id_range($$, nullptr, $1.text, @1.lexical_pos, $2); + } + | data_type_or_implicit_plus_id_base dimensions_opt + { set_type_id_range($$, $1.type, $1.id, $1.lexical_pos, $2); + } + ; + + // Partial ANSI port declarations such as `input a, integer b` can redeclare + // the data type without repeating the direction. Keep this narrower than + // data_type_or_implicit_plus_id_dim so a bare identifier after a comma is + // still parsed as a continuation of the previous port declaration. +partial_port_type_plus_id_dim + : atomic_type identifier_name dimensions_opt + { set_type_id_range($$, $1, $2, @2.lexical_pos, $3); + } + | implicit_type identifier_name dimensions_opt + { set_type_id_range($$, $1, $2, @2.lexical_pos, $3); + } + ; + +partial_port_name_dim + : IDENTIFIER dimensions_opt + { set_type_id_range($$, nullptr, $1, @1.lexical_pos, $2); + } + | TYPE_IDENTIFIER dimensions_opt + { set_type_id_range($$, nullptr, $1.text, @1.lexical_pos, $2); + } + ; + +partial_port_typedef_plus_id_dim + : TYPE_IDENTIFIER dimensions_opt identifier_name dimensions_opt + { pform_set_type_referenced(@1, $1.text); + data_type_t*tmp = new typeref_t($1.type); + FILE_NAME(tmp, @1); + delete[]$1.text; + tmp = pform_make_parray_type(@2, tmp, $2); + set_type_id_range($$, tmp, $3, @3.lexical_pos, $4); + } + | package_scope TYPE_IDENTIFIER dimensions_opt identifier_name dimensions_opt + { lex_in_package_scope(nullptr); + data_type_t*tmp = new typeref_t($2.type, $1); + FILE_NAME(tmp, @2); + delete[]$2.text; + tmp = pform_make_parray_type(@3, tmp, $3); + set_type_id_range($$, tmp, $4, @4.lexical_pos, $5); + } + ; /* These rules for tf_port_item are slightly expanded from the strict rules in the LRM to help with LALR parsing. @@ -2567,61 +2799,62 @@ tf_port_declaration /* IEEE1800-2005: A.2.7 */ tf_port_item /* IEEE1800-2005: A.2.7 */ - : port_direction_opt K_var_opt data_type_or_implicit IDENTIFIER dimensions_opt initializer_opt + : port_direction_opt K_var_opt data_type_or_implicit_plus_id_dim initializer_opt { std::vector*tmp; NetNet::PortType use_port_type = $1; - if ((use_port_type == NetNet::PIMPLICIT) && (gn_system_verilog() || ($3 == 0))) + if ((use_port_type == NetNet::PIMPLICIT) && (gn_system_verilog() || !$3.type)) use_port_type = port_declaration_context.port_type; - list* port_list = make_port_list($4, @4.lexical_pos, $5, 0); + struct pform_port_list port_list = make_port_list($3.type, $3.id, + $3.lexical_pos, + $3.ranges, nullptr); if (use_port_type == NetNet::PIMPLICIT) { yyerror(@1, "error: Missing task/function port direction."); use_port_type = NetNet::PINPUT; // for error recovery } - if (($3 == 0) && ($1==NetNet::PIMPLICIT)) { + if (!$3.type && ($1==NetNet::PIMPLICIT)) { // Detect special case this is an undecorated // identifier and we need to get the declaration from // left context. - if ($5 != 0) { - yyerror(@5, "internal error: How can there be an unpacked range here?\n"); - } - tmp = pform_make_task_ports(@4, use_port_type, + tmp = pform_make_task_ports(@3, use_port_type, port_declaration_context.data_type, - port_list); + port_list.ports); } else { // Otherwise, the decorations for this identifier // indicate the type. Save the type for any right // context that may come later. port_declaration_context.port_type = use_port_type; - if ($3 == 0) { - $3 = new vector_type_t(IVL_VT_LOGIC, false, 0); - FILE_NAME($3, @4); + if (!$3.type) { + $3.type = new vector_type_t(IVL_VT_LOGIC, false, nullptr); + FILE_NAME($3.type, @3); } - port_declaration_context.data_type = $3; - tmp = pform_make_task_ports(@3, use_port_type, $3, port_list); + port_declaration_context.data_type = $3.type; + tmp = pform_make_task_ports(@3, use_port_type, $3.type, + port_list.ports); } $$ = tmp; - if ($6) { - pform_requires_sv(@6, "Task/function default argument"); + if ($4) { + pform_requires_sv(@4, "Task/function default argument"); assert(tmp->size()==1); - tmp->front().defe = $6; + tmp->front().defe = $4; } } /* Rules to match error cases... */ - | port_direction_opt K_var_opt data_type_or_implicit IDENTIFIER error - { yyerror(@3, "error: Error in task/function port item after port name %s.", $4); + | port_direction_opt K_var_opt data_type_or_implicit_plus_id_dim error + { yyerror(@3, "error: Error in task/function port item after port name %s.", $3.id); + delete_type_id_range($3); yyerrok; - $$ = 0; + $$ = nullptr; } ; tf_port_list /* IEEE1800-2005: A.2.7 */ : { port_declaration_context.port_type = gn_system_verilog() ? NetNet::PINPUT : NetNet::PIMPLICIT; - port_declaration_context.data_type = 0; + port_declaration_context.data_type = nullptr; } tf_port_item_list { $$ = $2; } @@ -2816,13 +3049,13 @@ block_item_decl /* variable declarations. Note that data_type can be 0 if we are recovering from an error. */ - : K_const_opt K_var variable_lifetime_opt data_type_or_implicit list_of_variable_decl_assignments ';' - { data_type_t *data_type = $4; + : K_const_opt K_var variable_lifetime_opt list_of_variable_decl_assignments_with_type ';' + { data_type_t*data_type = $4.type; if (!data_type) { - data_type = new vector_type_t(IVL_VT_LOGIC, false, 0); - FILE_NAME(data_type, @2); + data_type = new vector_type_t(IVL_VT_LOGIC, false, nullptr); + FILE_NAME(data_type, @2); } - pform_make_var(@2, $5, data_type, attributes_in_context, $1); + pform_make_var(@2, $4.decl_assignments, data_type, attributes_in_context, $1); var_lifetime = LexicalScope::INHERITED; } @@ -2831,8 +3064,8 @@ block_item_decl var_lifetime = LexicalScope::INHERITED; } - /* The extra `reg` is not valid (System)Verilog, this is a iverilog extension. */ - | K_const_opt variable_lifetime_opt K_reg data_type list_of_variable_decl_assignments ';' + /* The extra `reg` is not valid (System)Verilog, this is an iverilog extension. */ + | K_const_opt variable_lifetime_opt K_reg reg_prefixed_atomic_type list_of_variable_decl_assignments ';' { if ($4) pform_make_var(@4, $5, $4, attributes_in_context, $1); var_lifetime = LexicalScope::INHERITED; } @@ -2853,11 +3086,6 @@ block_item_decl /* Recover from errors that happen within variable lists. Use the trailing semi-colon to resync the parser. */ - - | K_const_opt K_var variable_lifetime_opt data_type_or_implicit error ';' - { yyerror(@1, "error: Syntax error in variable list."); - yyerrok; - } | K_const_opt variable_lifetime_opt data_type error ';' { yyerror(@1, "error: Syntax error in variable list."); yyerrok; @@ -2945,13 +3173,8 @@ enum_base_type /* IEEE 1800-2012 A.2.2.1 */ : simple_packed_type { $$ = $1; } - | ps_type_identifier dimensions_opt - { if ($2) { - $$ = new parray_type_t($1, $2); - FILE_NAME($$, @1); - } else { - $$ = $1; - } + | ps_type_identifier_dim + { $$ = $1; } | { $$ = new atom_type_t(atom_type_t::INT, true); @@ -4602,16 +4825,16 @@ genvar_identifier_list ; list_of_port_identifiers - : IDENTIFIER dimensions_opt - { $$ = make_port_list($1, @1.lexical_pos, $2, 0); } - | list_of_port_identifiers ',' IDENTIFIER dimensions_opt - { $$ = make_port_list($1, $3, @3.lexical_pos, $4, 0); } + : data_type_or_implicit_plus_id_dim + { $$ = make_port_list($1.type, $1.id, $1.lexical_pos, $1.ranges, nullptr); } + | list_of_port_identifiers ',' identifier_name dimensions_opt + { $$ = make_port_list($1, $3, @3.lexical_pos, $4, nullptr); } ; list_of_variable_port_identifiers - : IDENTIFIER dimensions_opt initializer_opt - { $$ = make_port_list($1, @1.lexical_pos, $2, $3); } - | list_of_variable_port_identifiers ',' IDENTIFIER dimensions_opt initializer_opt + : data_type_or_implicit_plus_id_dim initializer_opt + { $$ = make_port_list($1.type, $1.id, $1.lexical_pos, $1.ranges, $2); } + | list_of_variable_port_identifiers ',' identifier_name dimensions_opt initializer_opt { $$ = make_port_list($1, $3, @3.lexical_pos, $4, $5); } ; @@ -4656,23 +4879,41 @@ list_of_port_declarations tmp->push_back($3); $$ = tmp; } - | list_of_port_declarations ',' attribute_list_opt IDENTIFIER dimensions_opt initializer_opt + | list_of_port_declarations ',' attribute_list_opt partial_port_name_dim initializer_opt { std::vector *ports = $1; Module::port_t* port; if (port_declaration_context.port_type == NetNet::NOT_A_PORT) { yyerror(@4, "error: Incomplete interface port declaration."); - delete[]$4; + delete_type_id_range($4); delete $5; - delete $6; delete $3; port = 0; } else { - port = module_declare_port(@4, $4, + port = module_declare_port(@4, $4.id, $4.lexical_pos, port_declaration_context.port_type, port_declaration_context.port_net_type, port_declaration_context.data_type, - $5, $6, $3); + $4.ranges, $5, $3); + } + ports->push_back(port); + $$ = ports; + } + | list_of_port_declarations ',' attribute_list_opt partial_port_typedef_plus_id_dim initializer_opt + { std::vector *ports = $1; + + Module::port_t* port; + if (port_declaration_context.port_type == NetNet::NOT_A_PORT) { + yyerror(@4, "error: Incomplete interface port declaration."); + delete_type_id_range($4); + delete $5; + delete $3; + port = 0; + } else { + port = module_declare_port(@4, $4.id, $4.lexical_pos, + port_declaration_context.port_type, + NetNet::IMPLICIT, $4.type, + $4.ranges, $5, $3); } ports->push_back(port); $$ = ports; @@ -4686,29 +4927,32 @@ list_of_port_declarations // All of port direction, port kind and data type are optional, but at least // one has to be specified, so we need multiple rules. port_declaration - : attribute_list_opt port_direction net_type_or_var_opt data_type_or_implicit IDENTIFIER dimensions_opt initializer_opt - { $$ = module_declare_port(@5, $5, $2, $3, $4, $6, $7, $1); + : attribute_list_opt port_direction net_type_or_var_opt data_type_or_implicit_plus_id_dim initializer_opt + { $$ = module_declare_port(@4, $4.id, $4.lexical_pos, + $2, $3, $4.type, $4.ranges, $5, $1); } - | attribute_list_opt INTERFACE_IDENTIFIER '.' IDENTIFIER IDENTIFIER dimensions_opt + | attribute_list_opt INTERFACE_IDENTIFIER '.' identifier_name identifier_name dimensions_opt { $$ = module_declare_interface_port(@5, $2, $4, $5, $6, $1); } - | attribute_list_opt INTERFACE_IDENTIFIER IDENTIFIER dimensions_opt + | attribute_list_opt INTERFACE_IDENTIFIER identifier_name dimensions_opt { $$ = module_declare_interface_port(@3, $2, 0, $3, $4, $1); } - | attribute_list_opt net_type_or_var data_type_or_implicit IDENTIFIER dimensions_opt initializer_opt - { pform_requires_sv(@4, "Partial ANSI port declaration"); - $$ = module_declare_port(@4, $4, port_declaration_context.port_type, - $2, $3, $5, $6, $1); - } - | attribute_list_opt data_type_or_implicit_no_opt IDENTIFIER dimensions_opt initializer_opt + | attribute_list_opt net_type_or_var data_type_or_implicit_plus_id_dim initializer_opt { pform_requires_sv(@3, "Partial ANSI port declaration"); - $$ = module_declare_port(@3, $3, port_declaration_context.port_type, - NetNet::IMPLICIT, $2, $4, $5, $1); + $$ = module_declare_port(@3, $3.id, $3.lexical_pos, + port_declaration_context.port_type, + $2, $3.type, $3.ranges, $4, $1); } - | attribute_list_opt port_direction K_wreal IDENTIFIER + | attribute_list_opt partial_port_type_plus_id_dim initializer_opt + { pform_requires_sv(@2, "Partial ANSI port declaration"); + $$ = module_declare_port(@2, $2.id, $2.lexical_pos, + port_declaration_context.port_type, + NetNet::IMPLICIT, $2.type, $2.ranges, $3, $1); + } + | attribute_list_opt port_direction K_wreal identifier_name { real_type_t*real_type = new real_type_t(real_type_t::REAL); FILE_NAME(real_type, @3); - $$ = module_declare_port(@4, $4, $2, NetNet::WIRE, + $$ = module_declare_port(@4, $4, @4.lexical_pos, $2, NetNet::WIRE, real_type, nullptr, nullptr, $1); } ; @@ -5007,7 +5251,19 @@ module_item net_decl_assigns, which are = assignment declarations. */ - | attribute_list_opt net_type drive_strength_opt data_type_or_implicit delay3_opt net_decl_assigns ';' + | attribute_list_opt net_type drive_strength_opt list_of_net_decl_assignments_with_type ';' + { data_type_t*data_type = $4.type; + pform_check_net_data_type(@2, $2, data_type); + check_net_decl_assigns(@4, $4.decl_assignments); + if (!data_type) { + data_type = new vector_type_t(IVL_VT_LOGIC, false, nullptr); + FILE_NAME(data_type, @2); + } + pform_makewire(@2, nullptr, $3, $4.decl_assignments, $2, data_type, $1); + delete $1; + } + + | attribute_list_opt net_type drive_strength_opt data_type_or_implicit delay3 net_decl_assigns ';' { data_type_t*data_type = $4; pform_check_net_data_type(@2, $2, $4); check_net_decl_assigns(@6, $6); @@ -5041,12 +5297,12 @@ module_item input wire signed [h:l] ; This creates the wire and sets the port type all at once. */ - | attribute_list_opt port_direction net_type_or_var data_type_or_implicit list_of_port_identifiers ';' - { pform_module_define_port(@2, $5, $2, $3, $4, $1); } + | attribute_list_opt port_direction net_type_or_var list_of_port_identifiers ';' + { pform_module_define_port(@2, $4.ports, $2, $3, $4.type, $1); } | attribute_list_opt port_direction K_wreal list_of_port_identifiers ';' { real_type_t*real_type = new real_type_t(real_type_t::REAL); - pform_module_define_port(@2, $4, $2, NetNet::WIRE, real_type, $1); + pform_module_define_port(@2, $4.ports, $2, NetNet::WIRE, real_type, $1); } /* The next three rules handle port declarations that include a variable @@ -5055,33 +5311,33 @@ module_item and also handle incomplete port declarations, e.g. input signed [h:l] ; */ - | attribute_list_opt K_inout data_type_or_implicit list_of_port_identifiers ';' - { NetNet::Type use_type = $3 ? NetNet::IMPLICIT : NetNet::NONE; - if (const vector_type_t*dtype = dynamic_cast ($3)) { + | attribute_list_opt K_inout list_of_port_identifiers ';' + { NetNet::Type use_type = $3.type ? NetNet::IMPLICIT : NetNet::NONE; + if (vector_type_t*dtype = dynamic_cast ($3.type)) { if (dtype->implicit_flag) use_type = NetNet::NONE; } if (use_type == NetNet::NONE) - pform_set_port_type(@2, $4, NetNet::PINOUT, $3, $1); + pform_set_port_type(@2, $3.ports, NetNet::PINOUT, $3.type, $1); else - pform_module_define_port(@2, $4, NetNet::PINOUT, use_type, $3, $1); + pform_module_define_port(@2, $3.ports, NetNet::PINOUT, use_type, $3.type, $1); } - | attribute_list_opt K_input data_type_or_implicit list_of_port_identifiers ';' - { NetNet::Type use_type = $3 ? NetNet::IMPLICIT : NetNet::NONE; - if (const vector_type_t*dtype = dynamic_cast ($3)) { + | attribute_list_opt K_input list_of_port_identifiers ';' + { NetNet::Type use_type = $3.type ? NetNet::IMPLICIT : NetNet::NONE; + if (vector_type_t*dtype = dynamic_cast ($3.type)) { if (dtype->implicit_flag) use_type = NetNet::NONE; } if (use_type == NetNet::NONE) - pform_set_port_type(@2, $4, NetNet::PINPUT, $3, $1); + pform_set_port_type(@2, $3.ports, NetNet::PINPUT, $3.type, $1); else - pform_module_define_port(@2, $4, NetNet::PINPUT, use_type, $3, $1); + pform_module_define_port(@2, $3.ports, NetNet::PINPUT, use_type, $3.type, $1); } - | attribute_list_opt K_output data_type_or_implicit list_of_variable_port_identifiers ';' - { NetNet::Type use_type = $3 ? NetNet::IMPLICIT : NetNet::NONE; - if (const vector_type_t*dtype = dynamic_cast ($3)) { + | attribute_list_opt K_output list_of_variable_port_identifiers ';' + { NetNet::Type use_type = $3.type ? NetNet::IMPLICIT : NetNet::NONE; + if (vector_type_t*dtype = dynamic_cast ($3.type)) { if (dtype->implicit_flag) use_type = NetNet::NONE; else @@ -5091,40 +5347,36 @@ module_item // output ports are implicitly (on the inside) // variables because "reg" is not valid syntax // here. - } else if ($3) { + } else if ($3.type) { use_type = NetNet::IMPLICIT_REG; } if (use_type == NetNet::NONE) - pform_set_port_type(@2, $4, NetNet::POUTPUT, $3, $1); + pform_set_port_type(@2, $3.ports, NetNet::POUTPUT, $3.type, $1); else - pform_module_define_port(@2, $4, NetNet::POUTPUT, use_type, $3, $1); + pform_module_define_port(@2, $3.ports, NetNet::POUTPUT, use_type, $3.type, $1); } - | attribute_list_opt port_direction net_type_or_var data_type_or_implicit error ';' + | attribute_list_opt port_direction net_type_or_var error ';' { yyerror(@2, "error: Invalid variable list in port declaration."); if ($1) delete $1; - if ($4) delete $4; yyerrok; } - | attribute_list_opt K_inout data_type_or_implicit error ';' + | attribute_list_opt K_inout error ';' { yyerror(@2, "error: Invalid variable list in port declaration."); if ($1) delete $1; - if ($3) delete $3; yyerrok; } - | attribute_list_opt K_input data_type_or_implicit error ';' + | attribute_list_opt K_input error ';' { yyerror(@2, "error: Invalid variable list in port declaration."); if ($1) delete $1; - if ($3) delete $3; yyerrok; } - | attribute_list_opt K_output data_type_or_implicit error ';' + | attribute_list_opt K_output error ';' { yyerror(@2, "error: Invalid variable list in port declaration."); if ($1) delete $1; - if ($3) delete $3; yyerrok; } @@ -5535,19 +5787,22 @@ net_decl_initializer_opt | { $$ = 0; } ; +list_of_net_decl_assignments_with_type /* IEEE1800-2005 A.2.5 */ + : data_type_or_implicit_plus_id_dim net_decl_initializer_opt + { std::list*tmp = new std::list; + tmp->push_back(pform_make_net_decl(@1, $1.id, $1.lexical_pos, $1.ranges, $2)); + $$.decl_assignments = tmp; + $$.type = $1.type; + } + | list_of_net_decl_assignments_with_type ',' net_decl_assign + { $1.decl_assignments->push_back($3); + $$ = $1; + } + ; + net_decl_assign - : IDENTIFIER dimensions_opt net_decl_initializer_opt - { decl_assignment_t*tmp = new decl_assignment_t; - tmp->name = { lex_strings.make($1), @1.lexical_pos }; - if ($2) { - tmp->index = *$2; - if ($3) - pform_requires_sv(@$, "Assignment of net array during declaration"); - delete $2; - } - tmp->expr.reset($3); - delete[]$1; - $$ = tmp; + : identifier_name dimensions_opt net_decl_initializer_opt + { $$ = pform_make_net_decl(@1, $1, $2, $3); } ; @@ -5798,7 +6053,7 @@ port references. The port_t object gets its PWire from the port_reference, but its name from the IDENTIFIER. */ - | '.' IDENTIFIER '(' port_reference ')' + | '.' identifier_name '(' port_reference ')' { Module::port_t*tmp = $4; tmp->name = lex_strings.make($2); delete[]$2; @@ -5818,7 +6073,7 @@ port /* This attaches a name to a port reference concatenation list so that parameter passing be name is possible. */ - | '.' IDENTIFIER '(' '{' port_reference_list '}' ')' + | '.' identifier_name '(' '{' port_reference_list '}' ')' { Module::port_t*tmp = $5; tmp->name = lex_strings.make($2); delete[]$2; @@ -5921,14 +6176,14 @@ port_conn_expression_list_with_nuls port_t object to pass it up to the module declaration code. */ port_reference - : IDENTIFIER + : identifier_name { Module::port_t*ptmp; perm_string name = lex_strings.make($1); ptmp = pform_module_port_reference(@1, name); delete[]$1; $$ = ptmp; } - | IDENTIFIER '[' expression ':' expression ']' + | identifier_name '[' expression ':' expression ']' { index_component_t itmp; itmp.sel = index_component_t::SEL_PART; itmp.msb = $3; @@ -5951,7 +6206,7 @@ port_reference delete[]$1; $$ = ptmp; } - | IDENTIFIER '[' expression ']' + | identifier_name '[' expression ']' { index_component_t itmp; itmp.sel = index_component_t::SEL_BIT; itmp.msb = $3; @@ -5973,7 +6228,7 @@ port_reference delete[]$1; $$ = ptmp; } - | IDENTIFIER '[' error ']' + | identifier_name '[' error ']' { yyerror(@1, "error: Invalid port bit select"); Module::port_t*ptmp = new Module::port_t; PEIdent*wtmp = new PEIdent(lex_strings.make($1), @1.lexical_pos); diff --git a/pform_types.h b/pform_types.h index e16273cf6..021229e53 100644 --- a/pform_types.h +++ b/pform_types.h @@ -510,4 +510,9 @@ extern std::ostream& operator<< (std::ostream&out, const name_component_t&that); extern std::ostream& operator<< (std::ostream&out, const index_component_t&that); extern std::ostream& operator<< (std::ostream&out, const type_restrict_t& type); +struct pform_port_list { + std::list *ports; + data_type_t *type; +}; + #endif /* IVL_pform_types_H */