diff --git a/PExpr.h b/PExpr.h index b91e9bdcf..8958ed62a 100644 --- a/PExpr.h +++ b/PExpr.h @@ -172,7 +172,8 @@ class PExpr : public LineInfo { virtual NetAssign_* elaborate_lval(Design*des, NetScope*scope, bool is_cassign, - bool is_force) const; + bool is_force, + bool is_init = false) const; // This method returns true if the expression represents a // structural net that can have multiple drivers. This is @@ -262,7 +263,8 @@ class PEConcat : public PExpr { virtual NetAssign_* elaborate_lval(Design*des, NetScope*scope, bool is_cassign, - bool is_force) const; + bool is_force, + bool is_init = false) const; virtual bool is_collapsible_net(Design*des, NetScope*scope, NetNet::PortType port_type) const; private: @@ -361,7 +363,8 @@ class PEIdent : public PExpr { virtual NetAssign_* elaborate_lval(Design*des, NetScope*scope, bool is_cassign, - bool is_force) const; + bool is_force, + bool is_init = false) const; virtual NetExpr*elaborate_expr(Design*des, NetScope*scope, ivl_type_t type, unsigned flags) const; @@ -647,7 +650,8 @@ class PENumber : public PExpr { virtual NetAssign_* elaborate_lval(Design*des, NetScope*scope, bool is_cassign, - bool is_force) const; + bool is_force, + bool is_init = false) const; private: verinum*const value_; diff --git a/PWire.h b/PWire.h index 4d8820eee..8b47fc214 100644 --- a/PWire.h +++ b/PWire.h @@ -68,6 +68,9 @@ class PWire : public PNamedItem { NetNet::PortType get_port_type() const; bool set_port_type(NetNet::PortType); + void set_const(bool is_const) { is_const_ = is_const; }; + bool get_const() const { return is_const_; }; + void set_signed(bool flag); bool get_signed() const; @@ -100,6 +103,9 @@ class PWire : public PNamedItem { NetNet::PortType port_type_; bool signed_; + // Whether the wire is variable declared with the const keyword. + bool is_const_ = false; + // These members hold expressions for the bit width of the // wire. If they do not exist, the wire is 1 bit wide. If they // do exist, they represent the packed dimensions of the diff --git a/Statement.cc b/Statement.cc index d75b802da..7799eca73 100644 --- a/Statement.cc +++ b/Statement.cc @@ -29,8 +29,9 @@ Statement::~Statement() { } -PAssign_::PAssign_(PExpr*lval__, PExpr*ex, bool is_constant) -: event_(0), count_(0), lval_(lval__), rval_(ex), is_constant_(is_constant) +PAssign_::PAssign_(PExpr*lval__, PExpr*ex, bool is_constant, bool is_init) +: event_(0), count_(0), lval_(lval__), rval_(ex), is_constant_(is_constant), + is_init_(is_init) { delay_ = 0; } @@ -73,8 +74,8 @@ PAssign::PAssign(PExpr*lval__, PExpr*cnt, PEventStatement*d, PExpr*ex) { } -PAssign::PAssign(PExpr*lval__, PExpr*ex, bool is_constant) -: PAssign_(lval__, ex, is_constant), op_(0) +PAssign::PAssign(PExpr*lval__, PExpr*ex, bool is_constant, bool is_init) +: PAssign_(lval__, ex, is_constant, is_init), op_(0) { } diff --git a/Statement.h b/Statement.h index 7d8efa6bf..d9b7f0faf 100644 --- a/Statement.h +++ b/Statement.h @@ -95,7 +95,8 @@ class Statement : virtual public LineInfo { */ class PAssign_ : public Statement { public: - explicit PAssign_(PExpr*lval, PExpr*ex, bool is_constant); + explicit PAssign_(PExpr*lval, PExpr*ex, bool is_constant, + bool is_init = false); explicit PAssign_(PExpr*lval, PExpr*de, PExpr*ex); explicit PAssign_(PExpr*lval, PExpr*cnt, PEventStatement*de, PExpr*ex); virtual ~PAssign_() =0; @@ -122,6 +123,8 @@ class PAssign_ : public Statement { PExpr* lval_; PExpr* rval_; bool is_constant_; + // Whether the assignment is a variable initializer expression + bool is_init_ = false; }; class PAssign : public PAssign_ { @@ -135,7 +138,7 @@ class PAssign : public PAssign_ { explicit PAssign(PExpr*lval, char op, PExpr*ex); explicit PAssign(PExpr*lval, PExpr*de, PExpr*ex); explicit PAssign(PExpr*lval, PExpr*cnt, PEventStatement*de, PExpr*ex); - explicit PAssign(PExpr*lval, PExpr*ex, bool is_constant); + explicit PAssign(PExpr*lval, PExpr*ex, bool is_constant, bool is_init); ~PAssign(); virtual void dump(std::ostream&out, unsigned ind) const; diff --git a/elab_lval.cc b/elab_lval.cc index 1ac35d916..10d24a1e0 100644 --- a/elab_lval.cc +++ b/elab_lval.cc @@ -76,7 +76,7 @@ using namespace std; * is to try to make a net elaboration, and see if the result is * suitable for assignment. */ -NetAssign_* PExpr::elaborate_lval(Design*, NetScope*, bool, bool) const +NetAssign_* PExpr::elaborate_lval(Design*, NetScope*, bool, bool, bool) const { cerr << get_fileline() << ": Assignment l-value too complex." << endl; return 0; @@ -98,7 +98,8 @@ NetAssign_* PExpr::elaborate_lval(Design*, NetScope*, bool, bool) const NetAssign_* PEConcat::elaborate_lval(Design*des, NetScope*scope, bool is_cassign, - bool is_force) const + bool is_force, + bool is_init) const { if (repeat_) { cerr << get_fileline() << ": error: Repeat concatenations make " @@ -119,7 +120,7 @@ NetAssign_* PEConcat::elaborate_lval(Design*des, } NetAssign_*tmp = parms_[idx]->elaborate_lval(des, scope, - is_cassign, is_force); + is_cassign, is_force, is_init); /* If the l-value doesn't elaborate, the error was already detected and printed. We just skip it and let @@ -157,7 +158,8 @@ NetAssign_* PEConcat::elaborate_lval(Design*des, NetAssign_* PEIdent::elaborate_lval(Design*des, NetScope*scope, bool is_cassign, - bool is_force) const + bool is_force, + bool is_init) const { if (debug_elaborate) { @@ -213,6 +215,13 @@ NetAssign_* PEIdent::elaborate_lval(Design*des, << endl; } + if (reg->get_const() && !is_init) { + cerr << get_fileline() << ": error: Assignment to const signal `" + << reg->name() << "` is not allowed." << endl; + des->errors++; + return nullptr; + } + return elaborate_lval_var_(des, scope, is_force, is_cassign, reg, sr.type, member_path); } @@ -1535,7 +1544,7 @@ bool PEIdent::elaborate_lval_net_packed_member_(Design*des, NetScope*scope, return false; } -NetAssign_* PENumber::elaborate_lval(Design*des, NetScope*, bool, bool) const +NetAssign_* PENumber::elaborate_lval(Design*des, NetScope*, bool, bool, bool) const { cerr << get_fileline() << ": error: Constant values not allowed " << "in l-value expressions." << endl; diff --git a/elab_net.cc b/elab_net.cc index 9d30e5642..9635bf0e8 100644 --- a/elab_net.cc +++ b/elab_net.cc @@ -556,6 +556,12 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope, << endl; } + if (sig->get_const()) { + cerr << get_fileline() << ": error: Continuous assignment to const" + << " signal `" << sig->name() << "` is not allowed." << endl; + des->errors++; + return nullptr; + } // If this is SystemVerilog and the variable is not yet // assigned by anything, then convert it to an unresolved diff --git a/elab_sig.cc b/elab_sig.cc index 7337250c4..a855d9948 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -1204,5 +1204,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const for (unsigned idx = 0 ; idx < nattrib ; idx += 1) sig->attribute(attrib_list[idx].key, attrib_list[idx].val); + sig->set_const(is_const_); + return sig; } diff --git a/elaborate.cc b/elaborate.cc index b99ba90c7..1e387f8e9 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -2378,7 +2378,7 @@ NetAssign_* PAssign_::elaborate_lval(Design*des, NetScope*scope) const << "lval_ expr type = " << typeid(*lval_).name() << endl; } - return lval_->elaborate_lval(des, scope, false, false); + return lval_->elaborate_lval(des, scope, false, false, is_init_); } NetExpr* PAssign_::elaborate_rval_(Design*des, NetScope*scope, diff --git a/ivtest/ivltests/sv_const1.v b/ivtest/ivltests/sv_const1.v new file mode 100644 index 000000000..085e5672a --- /dev/null +++ b/ivtest/ivltests/sv_const1.v @@ -0,0 +1,18 @@ +// Check that const variables in module scope are supported. + +module test; + + const integer x = 10; + + // The initializer expression is allowed to reference other const variables. + const integer y = 20 + x; + + initial begin + if (x === 10 && y === 30) begin + $display("PASSED"); + end else begin + $display("FAILED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_const2.v b/ivtest/ivltests/sv_const2.v new file mode 100644 index 000000000..ac668b909 --- /dev/null +++ b/ivtest/ivltests/sv_const2.v @@ -0,0 +1,29 @@ +// Check that const variables are supported in function and task scope. + +module test; + + function automatic integer f(integer x); + // Automatic const variables can have a non-const initializer epxression + const integer y = 2 * x; + return y; + endfunction + + task automatic t(input integer x, output integer y); + // Automatic const variables can have a non-const initializer epxression + const integer z = 2 * x; + y = z; + endtask + + initial begin + integer y; + + t(15, y); + + if (f(10) === 20 && y === 30) begin + $display("PASSED"); + end else begin + $display("FAILED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_const3.v b/ivtest/ivltests/sv_const3.v new file mode 100644 index 000000000..1f0a6a82b --- /dev/null +++ b/ivtest/ivltests/sv_const3.v @@ -0,0 +1,17 @@ +// Check that const variables in block scope are supported. + +module test; + + initial begin + const static integer x = 10; + // The initializer expression is allowed to reference other const variables. + const static integer y = 20 + x; + + if (x === 10 && y === 30) begin + $display("PASSED"); + end else begin + $display("FAILED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_const4.v b/ivtest/ivltests/sv_const4.v new file mode 100644 index 000000000..3d0af2291 --- /dev/null +++ b/ivtest/ivltests/sv_const4.v @@ -0,0 +1,18 @@ +// Check that const variables are supported in the unit scope. + +const integer x = 10; + +// The initializer expression is allowed to reference other const variables. +const integer y = 20 + x; + +module test; + + initial begin + if (x === 10 && y === 30) begin + $display("PASSED"); + end else begin + $display("FAILED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_const5.v b/ivtest/ivltests/sv_const5.v new file mode 100644 index 000000000..e08bdfbc1 --- /dev/null +++ b/ivtest/ivltests/sv_const5.v @@ -0,0 +1,20 @@ +// Check that const variables are supported in a package scope. + +package P; + const integer x = 10; + + // The initializer expression is allowed to reference other const variables. + const integer y = 20 + x; +endpackage + +module test; + + initial begin + if (P::x === 10 && P::y === 30) begin + $display("PASSED"); + end else begin + $display("FAILED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_const_fail1.v b/ivtest/ivltests/sv_const_fail1.v new file mode 100644 index 000000000..f65427272 --- /dev/null +++ b/ivtest/ivltests/sv_const_fail1.v @@ -0,0 +1,13 @@ +// Check that continuous assignment to a const variable fails. + +module test; + + const integer x = 10; + + assign x = 20; // Error: Assignment to const variable + + initial begin + $display("FAILED"); + end + +endmodule diff --git a/ivtest/ivltests/sv_const_fail2.v b/ivtest/ivltests/sv_const_fail2.v new file mode 100644 index 000000000..2d0b2d638 --- /dev/null +++ b/ivtest/ivltests/sv_const_fail2.v @@ -0,0 +1,12 @@ +// Check that blocking assignment to a const variable fails. + +module test; + + const integer x = 10; + + initial begin + x = 20; // Error: Assignment to const variable + $display("FAILED"); + end + +endmodule diff --git a/ivtest/ivltests/sv_const_fail3.v b/ivtest/ivltests/sv_const_fail3.v new file mode 100644 index 000000000..41546994f --- /dev/null +++ b/ivtest/ivltests/sv_const_fail3.v @@ -0,0 +1,12 @@ +// Check that non-blocking assignment to a const variable fails. + +module test; + + const integer x = 10; + + initial begin + x <= 20; // Error: Assignment to const variable + $display("FAILED"); + end + +endmodule diff --git a/ivtest/ivltests/sv_const_fail4.v b/ivtest/ivltests/sv_const_fail4.v new file mode 100644 index 000000000..56b24a874 --- /dev/null +++ b/ivtest/ivltests/sv_const_fail4.v @@ -0,0 +1,12 @@ +// Check that force assignment to a const variable fails. + +module test; + + const integer x = 10; + + initial begin + force x = 20; // Error: Assignment to const variable + $display("FAILED"); + end + +endmodule diff --git a/ivtest/ivltests/sv_const_fail5.v b/ivtest/ivltests/sv_const_fail5.v new file mode 100644 index 000000000..58a856ea1 --- /dev/null +++ b/ivtest/ivltests/sv_const_fail5.v @@ -0,0 +1,12 @@ +// Check that procedural continuous assignment to a const variable fails. + +module test; + + const integer x = 10; + + initial begin + assign x = 20; // Error: Assignment to const variable + $display("FAILED"); + end + +endmodule diff --git a/ivtest/ivltests/sv_const_fail6.v b/ivtest/ivltests/sv_const_fail6.v new file mode 100644 index 000000000..34dd551e2 --- /dev/null +++ b/ivtest/ivltests/sv_const_fail6.v @@ -0,0 +1,16 @@ +// Check that binding a const variable to a task output port fails. + +module test; + + const integer x = 10; + + task t(output integer x); + x = 20; + endtask + + initial begin + t(x); + $display("FAILED"); + end + +endmodule diff --git a/ivtest/ivltests/sv_const_fail7.v b/ivtest/ivltests/sv_const_fail7.v new file mode 100644 index 000000000..8cad8fa79 --- /dev/null +++ b/ivtest/ivltests/sv_const_fail7.v @@ -0,0 +1,21 @@ +// Check that binding a const variable to a module output port fails. + +module M( + output integer x +); + assign x = 20; +endmodule + +module test; + + const integer x = 10; + + M i_m ( + .x (x) + ); + + initial begin + $display("FAILED"); + end + +endmodule diff --git a/ivtest/ivltests/sv_const_fail8.v b/ivtest/ivltests/sv_const_fail8.v new file mode 100644 index 000000000..af9cfa3e6 --- /dev/null +++ b/ivtest/ivltests/sv_const_fail8.v @@ -0,0 +1,21 @@ +// Check that binding a const variable to a module inout port fails. + +module M( + inout integer x +); + assign x = 20; +endmodule + +module test; + + const integer x = 10; + + M i_m ( + .x (x) + ); + + initial begin + $display("FAILED"); + end + +endmodule diff --git a/ivtest/regress-vvp.list b/ivtest/regress-vvp.list index 05fd8b6d4..11f9dc682 100644 --- a/ivtest/regress-vvp.list +++ b/ivtest/regress-vvp.list @@ -60,6 +60,19 @@ sv_array_assign_fail1 vvp_tests/sv_array_assign_fail1.json sv_array_assign_fail2 vvp_tests/sv_array_assign_fail2.json sv_array_cassign6 vvp_tests/sv_array_cassign6.json sv_array_cassign7 vvp_tests/sv_array_cassign7.json +sv_const1 vvp_tests/sv_const1.json +sv_const2 vvp_tests/sv_const2.json +sv_const3 vvp_tests/sv_const3.json +sv_const4 vvp_tests/sv_const4.json +sv_const5 vvp_tests/sv_const5.json +sv_const_fail1 vvp_tests/sv_const_fail1.json +sv_const_fail2 vvp_tests/sv_const_fail2.json +sv_const_fail3 vvp_tests/sv_const_fail3.json +sv_const_fail4 vvp_tests/sv_const_fail4.json +sv_const_fail5 vvp_tests/sv_const_fail5.json +sv_const_fail6 vvp_tests/sv_const_fail6.json +sv_const_fail7 vvp_tests/sv_const_fail7.json +sv_const_fail8 vvp_tests/sv_const_fail8.json sv_foreach9 vvp_tests/sv_foreach9.json sv_foreach10 vvp_tests/sv_foreach10.json sv_module_port1 vvp_tests/sv_module_port1.json diff --git a/ivtest/vvp_tests/sv_const1.json b/ivtest/vvp_tests/sv_const1.json new file mode 100644 index 000000000..80a6a307b --- /dev/null +++ b/ivtest/vvp_tests/sv_const1.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_const1.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_const2.json b/ivtest/vvp_tests/sv_const2.json new file mode 100644 index 000000000..39efe3073 --- /dev/null +++ b/ivtest/vvp_tests/sv_const2.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_const2.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_const3.json b/ivtest/vvp_tests/sv_const3.json new file mode 100644 index 000000000..c151c363b --- /dev/null +++ b/ivtest/vvp_tests/sv_const3.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_const3.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_const4.json b/ivtest/vvp_tests/sv_const4.json new file mode 100644 index 000000000..7cc53be8b --- /dev/null +++ b/ivtest/vvp_tests/sv_const4.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_const4.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_const5.json b/ivtest/vvp_tests/sv_const5.json new file mode 100644 index 000000000..d3da84c81 --- /dev/null +++ b/ivtest/vvp_tests/sv_const5.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_const5.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_const_fail1.json b/ivtest/vvp_tests/sv_const_fail1.json new file mode 100644 index 000000000..5fb0d364a --- /dev/null +++ b/ivtest/vvp_tests/sv_const_fail1.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_const_fail1.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_const_fail2.json b/ivtest/vvp_tests/sv_const_fail2.json new file mode 100644 index 000000000..39c51cc42 --- /dev/null +++ b/ivtest/vvp_tests/sv_const_fail2.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_const_fail2.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_const_fail3.json b/ivtest/vvp_tests/sv_const_fail3.json new file mode 100644 index 000000000..19353d4ed --- /dev/null +++ b/ivtest/vvp_tests/sv_const_fail3.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_const_fail3.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_const_fail4.json b/ivtest/vvp_tests/sv_const_fail4.json new file mode 100644 index 000000000..50c209472 --- /dev/null +++ b/ivtest/vvp_tests/sv_const_fail4.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_const_fail4.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_const_fail5.json b/ivtest/vvp_tests/sv_const_fail5.json new file mode 100644 index 000000000..1278627cd --- /dev/null +++ b/ivtest/vvp_tests/sv_const_fail5.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_const_fail5.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_const_fail6.json b/ivtest/vvp_tests/sv_const_fail6.json new file mode 100644 index 000000000..f8eaa2d35 --- /dev/null +++ b/ivtest/vvp_tests/sv_const_fail6.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_const_fail6.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_const_fail7.json b/ivtest/vvp_tests/sv_const_fail7.json new file mode 100644 index 000000000..542ae9d9a --- /dev/null +++ b/ivtest/vvp_tests/sv_const_fail7.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_const_fail7.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_const_fail8.json b/ivtest/vvp_tests/sv_const_fail8.json new file mode 100644 index 000000000..3835ef9f9 --- /dev/null +++ b/ivtest/vvp_tests/sv_const_fail8.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_const_fail8.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/netlist.h b/netlist.h index 4efd478d8..8ea80ddf8 100644 --- a/netlist.h +++ b/netlist.h @@ -702,6 +702,9 @@ class NetNet : public NetObj, public PortType { signed. Otherwise, it is unsigned. */ bool get_signed() const; + void set_const(bool is_const) { is_const_ = is_const; } + bool get_const() const { return is_const_; } + bool get_scalar() const; inline const ivl_type_s* net_type(void) const { return net_type_; } @@ -808,6 +811,9 @@ class NetNet : public NetObj, public PortType { netuarray_t *array_type_ = nullptr; ivl_discipline_t discipline_; + // Whether the net is variable declared with the const keyword. + bool is_const_ = false; + std::vector unpacked_dims_; // These are the widths of the various slice depths. There is diff --git a/parse.y b/parse.y index c0d4fc32f..92e8c73ef 100644 --- a/parse.y +++ b/parse.y @@ -639,7 +639,7 @@ Module::port_t *module_declare_port(const YYLTYPE&loc, char *id, %type number pos_neg_number %type signing unsigned_signed_opt signed_unsigned_opt %type import_export -%type K_genvar_opt K_static_opt K_virtual_opt +%type K_genvar_opt K_static_opt K_virtual_opt K_const_opt %type udp_reg_opt edge_operator %type drive_strength drive_strength_opt dr_strength0 dr_strength1 %type udp_input_sym udp_output_sym @@ -1231,21 +1231,22 @@ constraint_set /* IEEE1800-2005 A.1.9 */ ; data_declaration /* IEEE1800-2005: A.2.1.3 */ - : attribute_list_opt data_type list_of_variable_decl_assignments ';' - { data_type_t*data_type = $2; - if (data_type == 0) { + : attribute_list_opt K_const_opt data_type list_of_variable_decl_assignments ';' + { data_type_t *data_type = $3; + if (!data_type) { data_type = new vector_type_t(IVL_VT_LOGIC, false, 0); - FILE_NAME(data_type, @2); + FILE_NAME(data_type, @3); } - pform_makewire(@2, 0, str_strength, $3, NetNet::IMPLICIT_REG, data_type, $1); + pform_makewire(@3, 0, str_strength, $4, NetNet::IMPLICIT_REG, data_type, + $1, $2); } - | attribute_list_opt K_var data_type_or_implicit list_of_variable_decl_assignments ';' - { data_type_t*data_type = $3; - if (data_type == 0) { + | attribute_list_opt K_const_opt K_var data_type_or_implicit list_of_variable_decl_assignments ';' + { data_type_t *data_type = $4; + if (!data_type) { data_type = new vector_type_t(IVL_VT_LOGIC, false, 0); - FILE_NAME(data_type, @2); + FILE_NAME(data_type, @3); } - pform_make_var(@2, $4, data_type, $1); + pform_make_var(@3, $5, data_type, $1, $2); } | attribute_list_opt K_event event_variable_list ';' { if ($3) pform_make_events(@2, $3); @@ -2731,24 +2732,24 @@ block_item_decl /* variable declarations. Note that data_type can be 0 if we are recovering from an error. */ - : K_var variable_lifetime_opt data_type_or_implicit list_of_variable_decl_assignments ';' - { data_type_t*data_type = $3; - if (data_type == 0) { + : K_const_opt K_var variable_lifetime_opt data_type_or_implicit list_of_variable_decl_assignments ';' + { data_type_t *data_type = $4; + if (!data_type) { data_type = new vector_type_t(IVL_VT_LOGIC, false, 0); - FILE_NAME(data_type, @1); + FILE_NAME(data_type, @2); } - pform_make_var(@1, $4, data_type, attributes_in_context); + pform_make_var(@2, $5, data_type, attributes_in_context); var_lifetime = LexicalScope::INHERITED; } - | variable_lifetime_opt data_type list_of_variable_decl_assignments ';' - { if ($2) pform_make_var(@2, $3, $2, attributes_in_context); + | K_const_opt variable_lifetime_opt data_type list_of_variable_decl_assignments ';' + { if ($3) pform_make_var(@3, $4, $3, attributes_in_context, $1); var_lifetime = LexicalScope::INHERITED; } /* The extra `reg` is not valid (System)Verilog, this is a iverilog extension. */ - | variable_lifetime_opt K_reg data_type list_of_variable_decl_assignments ';' - { if ($3) pform_make_var(@3, $4, $3, attributes_in_context); + | K_const_opt variable_lifetime_opt K_reg data_type list_of_variable_decl_assignments ';' + { if ($4) pform_make_var(@4, $5, $4, attributes_in_context, $1); var_lifetime = LexicalScope::INHERITED; } @@ -2769,11 +2770,11 @@ block_item_decl /* Recover from errors that happen within variable lists. Use the trailing semi-colon to resync the parser. */ - | K_var variable_lifetime_opt data_type_or_implicit error ';' + | K_const_opt K_var variable_lifetime_opt data_type_or_implicit error ';' { yyerror(@1, "error: Syntax error in variable list."); yyerrok; } - | variable_lifetime_opt data_type error ';' + | K_const_opt variable_lifetime_opt data_type error ';' { yyerror(@1, "error: Syntax error in variable list."); yyerrok; } @@ -7308,6 +7309,11 @@ unique_priority presence is significant. This is a fairly common pattern so collect those rules here. */ +K_const_opt + : K_const { $$ = true; } + | { $$ = false; } + ; + K_genvar_opt : K_genvar { $$ = true; } | { $$ = false; } diff --git a/pform.cc b/pform.cc index 3957019ed..61da7ad75 100644 --- a/pform.cc +++ b/pform.cc @@ -951,11 +951,13 @@ PCallTask* pform_make_call_task(const struct vlltype&loc, void pform_make_var(const struct vlltype&loc, std::list*assign_list, - data_type_t*data_type, std::list*attr) + data_type_t*data_type, std::list*attr, + bool is_const) { static const struct str_pair_t str = { IVL_DR_STRONG, IVL_DR_STRONG }; - pform_makewire(loc, 0, str, assign_list, NetNet::REG, data_type, attr); + pform_makewire(loc, 0, str, assign_list, NetNet::REG, data_type, attr, + is_const); } void pform_make_foreach_declarations(const struct vlltype&loc, @@ -2494,7 +2496,7 @@ void pform_make_var_init(const struct vlltype&li, PEIdent*lval = new PEIdent(name); FILE_NAME(lval, li); - PAssign*ass = new PAssign(lval, expr, !gn_system_verilog()); + PAssign*ass = new PAssign(lval, expr, !gn_system_verilog(), true); FILE_NAME(ass, li); lexical_scope->var_inits.push_back(ass); @@ -2646,7 +2648,8 @@ void pform_makewire(const struct vlltype&li, std::list*assign_list, NetNet::Type type, data_type_t*data_type, - list*attr) + list*attr, + bool is_const) { if (is_compilation_unit(lexical_scope) && !gn_system_verilog()) { VLerror(li, "error: Variable declarations must be contained within a module."); @@ -2662,7 +2665,7 @@ void pform_makewire(const struct vlltype&li, wires->push_back(wire); } - pform_set_data_type(li, data_type, wires, type, attr); + pform_set_data_type(li, data_type, wires, type, attr, is_const); while (! assign_list->empty()) { decl_assignment_t*first = assign_list->front(); @@ -3224,7 +3227,7 @@ void pform_set_port_type(const struct vlltype&li, */ void pform_set_data_type(const struct vlltype&li, data_type_t*data_type, std::vector *wires, NetNet::Type net_type, - list*attr) + list*attr, bool is_const) { if (data_type == 0) { VLerror(li, "internal error: data_type==0."); @@ -3245,6 +3248,7 @@ void pform_set_data_type(const struct vlltype&li, data_type_t*data_type, ivl_assert(li, rc); wire->set_data_type(data_type); + wire->set_const(is_const); pform_bind_attributes(wire->attributes, attr, true); } diff --git a/pform.h b/pform.h index 7eeb93621..92d3edfb2 100644 --- a/pform.h +++ b/pform.h @@ -350,12 +350,14 @@ extern void pform_makewire(const struct vlltype&li, std::list*assign_list, NetNet::Type type, data_type_t*data_type, - std::list*attr = 0); + std::list*attr = 0, + bool is_const = false); extern void pform_make_var(const struct vlltype&loc, std::list*assign_list, data_type_t*data_type, - std::list*attr = 0); + std::list*attr = 0, + bool is_const = false); extern void pform_make_var_init(const struct vlltype&li, perm_string name, PExpr*expr); @@ -374,7 +376,8 @@ extern void pform_set_data_type(const struct vlltype&li, data_type_t *data_type, std::vector *wires, NetNet::Type net_type, - std::list*attr); + std::list*attr, + bool is_const = false); extern void pform_set_string_type(const struct vlltype&li, const string_type_t*string_type, std::list*names, NetNet::Type net_type, std::list*attr);