Check what can drive a variable in SystemVerilog
This commit is contained in:
parent
a05da1ca08
commit
66d57628bf
6
PExpr.cc
6
PExpr.cc
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1998-2024 Stephen Williams <steve@icarus.com>
|
||||
* Copyright (c) 1998-2025 Stephen Williams <steve@icarus.com>
|
||||
* Copyright CERN 2013 / Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
|
|
@ -54,7 +54,7 @@ bool PExpr::has_aa_term(Design*, NetScope*) const
|
|||
return false;
|
||||
}
|
||||
|
||||
NetNet* PExpr::elaborate_lnet(Design*, NetScope*) const
|
||||
NetNet* PExpr::elaborate_lnet(Design*, NetScope*, bool) const
|
||||
{
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< "expression not valid in assign l-value: "
|
||||
|
|
@ -62,7 +62,7 @@ NetNet* PExpr::elaborate_lnet(Design*, NetScope*) const
|
|||
return 0;
|
||||
}
|
||||
|
||||
NetNet* PExpr::elaborate_bi_net(Design*, NetScope*) const
|
||||
NetNet* PExpr::elaborate_bi_net(Design*, NetScope*, bool) const
|
||||
{
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< "expression not valid as argument to inout port: "
|
||||
|
|
|
|||
24
PExpr.h
24
PExpr.h
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef IVL_PExpr_H
|
||||
#define IVL_PExpr_H
|
||||
/*
|
||||
* Copyright (c) 1998-2024 Stephen Williams <steve@icarus.com>
|
||||
* Copyright (c) 1998-2025 Stephen Williams <steve@icarus.com>
|
||||
* Copyright CERN 2013 / Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
|
|
@ -156,13 +156,15 @@ class PExpr : public LineInfo {
|
|||
|
||||
// This method elaborates the expression as gates, but
|
||||
// restricted for use as l-values of continuous assignments.
|
||||
virtual NetNet* elaborate_lnet(Design*des, NetScope*scope) const;
|
||||
virtual NetNet* elaborate_lnet(Design*des, NetScope*scope,
|
||||
bool var_allowed_in_sv) const;
|
||||
|
||||
// This is similar to elaborate_lnet, except that the
|
||||
// expression is evaluated to be bi-directional. This is
|
||||
// useful for arguments to inout ports of module instances and
|
||||
// ports of tran primitives.
|
||||
virtual NetNet* elaborate_bi_net(Design*des, NetScope*scope) const;
|
||||
virtual NetNet* elaborate_bi_net(Design*des, NetScope*scope,
|
||||
bool var_allowed_in_sv) const;
|
||||
|
||||
// Expressions that can be in the l-value of procedural
|
||||
// assignments can be elaborated with this method. If the
|
||||
|
|
@ -251,8 +253,10 @@ class PEConcat : public PExpr {
|
|||
virtual unsigned test_width(Design*des, NetScope*scope,
|
||||
width_mode_t&mode);
|
||||
|
||||
virtual NetNet* elaborate_lnet(Design*des, NetScope*scope) const;
|
||||
virtual NetNet* elaborate_bi_net(Design*des, NetScope*scope) const;
|
||||
virtual NetNet* elaborate_lnet(Design*des, NetScope*scope,
|
||||
bool var_allowed_in_sv) const;
|
||||
virtual NetNet* elaborate_bi_net(Design*des, NetScope*scope,
|
||||
bool var_allowed_in_sv) const;
|
||||
|
||||
virtual NetExpr*elaborate_expr(Design*des, NetScope*scope,
|
||||
ivl_type_t type, unsigned flags) const;
|
||||
|
|
@ -269,7 +273,8 @@ class PEConcat : public PExpr {
|
|||
NetNet::PortType port_type) const;
|
||||
private:
|
||||
NetNet* elaborate_lnet_common_(Design*des, NetScope*scope,
|
||||
bool bidirectional_flag) const;
|
||||
bool bidirectional_flag,
|
||||
bool var_allowed_in_sv) const;
|
||||
private:
|
||||
std::vector<PExpr*>parms_;
|
||||
std::valarray<width_mode_t>width_modes_;
|
||||
|
|
@ -355,9 +360,9 @@ class PEIdent : public PExpr {
|
|||
width_mode_t&mode);
|
||||
|
||||
// Identifiers are allowed (with restrictions) is assign l-values.
|
||||
virtual NetNet* elaborate_lnet(Design*des, NetScope*scope) const;
|
||||
virtual NetNet* elaborate_lnet(Design*des, NetScope*scope, bool var_allowed_in_sv) const;
|
||||
|
||||
virtual NetNet* elaborate_bi_net(Design*des, NetScope*scope) const;
|
||||
virtual NetNet* elaborate_bi_net(Design*des, NetScope*scope, bool var_allowed_in_sv) const;
|
||||
|
||||
// Identifiers are also allowed as procedural assignment l-values.
|
||||
virtual NetAssign_* elaborate_lval(Design*des,
|
||||
|
|
@ -545,7 +550,8 @@ class PEIdent : public PExpr {
|
|||
|
||||
private:
|
||||
NetNet* elaborate_lnet_common_(Design*des, NetScope*scope,
|
||||
bool bidirectional_flag) const;
|
||||
bool bidirectional_flag,
|
||||
bool var_allowed_in_sv) const;
|
||||
|
||||
|
||||
bool eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
|
||||
|
|
|
|||
47
elab_net.cc
47
elab_net.cc
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1999-2024 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1999-2025 Stephen Williams (steve@icarus.com)
|
||||
* Copyright CERN 2012 / Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
|
|
@ -43,7 +43,8 @@ using namespace std;
|
|||
* make the l-value connections.
|
||||
*/
|
||||
NetNet* PEConcat::elaborate_lnet_common_(Design*des, NetScope*scope,
|
||||
bool bidirectional_flag) const
|
||||
bool bidirectional_flag,
|
||||
bool var_allowed_in_sv) const
|
||||
{
|
||||
ivl_assert(*this, scope);
|
||||
|
||||
|
|
@ -76,9 +77,9 @@ NetNet* PEConcat::elaborate_lnet_common_(Design*des, NetScope*scope,
|
|||
}
|
||||
|
||||
if (bidirectional_flag) {
|
||||
nets[idx] = parms_[idx]->elaborate_bi_net(des, scope);
|
||||
nets[idx] = parms_[idx]->elaborate_bi_net(des, scope, var_allowed_in_sv);
|
||||
} else {
|
||||
nets[idx] = parms_[idx]->elaborate_lnet(des, scope);
|
||||
nets[idx] = parms_[idx]->elaborate_lnet(des, scope, var_allowed_in_sv);
|
||||
}
|
||||
|
||||
if (nets[idx] == 0) {
|
||||
|
|
@ -163,14 +164,16 @@ NetNet* PEConcat::elaborate_lnet_common_(Design*des, NetScope*scope,
|
|||
return osig;
|
||||
}
|
||||
|
||||
NetNet* PEConcat::elaborate_lnet(Design*des, NetScope*scope) const
|
||||
NetNet* PEConcat::elaborate_lnet(Design*des, NetScope*scope,
|
||||
bool var_allowed_in_sv) const
|
||||
{
|
||||
return elaborate_lnet_common_(des, scope, false);
|
||||
return elaborate_lnet_common_(des, scope, false, var_allowed_in_sv);
|
||||
}
|
||||
|
||||
NetNet* PEConcat::elaborate_bi_net(Design*des, NetScope*scope) const
|
||||
NetNet* PEConcat::elaborate_bi_net(Design*des, NetScope*scope,
|
||||
bool var_allowed_in_sv) const
|
||||
{
|
||||
return elaborate_lnet_common_(des, scope, true);
|
||||
return elaborate_lnet_common_(des, scope, true, var_allowed_in_sv);
|
||||
}
|
||||
|
||||
bool PEConcat::is_collapsible_net(Design*des, NetScope*scope,
|
||||
|
|
@ -518,7 +521,8 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
|
|||
* so most of the work for both is done here.
|
||||
*/
|
||||
NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
|
||||
bool bidirectional_flag) const
|
||||
bool bidirectional_flag,
|
||||
bool var_allowed_in_sv) const
|
||||
{
|
||||
ivl_assert(*this, scope);
|
||||
|
||||
|
|
@ -569,7 +573,7 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
|
|||
// If this is SystemVerilog and the variable is not yet
|
||||
// assigned by anything, then convert it to an unresolved
|
||||
// wire.
|
||||
if (gn_var_can_be_uwire()
|
||||
if (gn_var_can_be_uwire() && var_allowed_in_sv
|
||||
&& (sig->type() == NetNet::REG)
|
||||
&& (sig->peek_lref() == 0) ) {
|
||||
sig->type(NetNet::UNRESOLVED_WIRE);
|
||||
|
|
@ -577,11 +581,14 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
|
|||
|
||||
// Don't allow registers as assign l-values.
|
||||
if (sig->type() == NetNet::REG) {
|
||||
cerr << get_fileline() << ": error: reg " << sig->name()
|
||||
<< "; cannot be driven by primitives"
|
||||
<< " or continuous assignment." << endl;
|
||||
cerr << get_fileline() << ": error: variable " << sig->name()
|
||||
<< "; cannot be driven by a primitive or continuous assignment";
|
||||
if(gn_var_can_be_uwire()) {
|
||||
cerr << " with non-default strength";
|
||||
}
|
||||
cerr << "." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Some parts below need the tail component. This is a convenient
|
||||
|
|
@ -758,6 +765,8 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
|
|||
cerr << get_fileline() << ": error: Array " << path()
|
||||
<< " needs " << sig->unpacked_dimensions() << " indices,"
|
||||
<< " but got only " << path_tail.index.size() << ". (net)" << endl;
|
||||
cerr << get_fileline() << ": : Assignment to a whole array requires SystemVerilog."
|
||||
<< endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -982,14 +991,16 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
|
|||
* Identifiers in continuous assignment l-values are limited to wires
|
||||
* and that ilk. Detect registers and memories here and report errors.
|
||||
*/
|
||||
NetNet* PEIdent::elaborate_lnet(Design*des, NetScope*scope) const
|
||||
NetNet* PEIdent::elaborate_lnet(Design*des, NetScope*scope,
|
||||
bool var_allowed_in_sv) const
|
||||
{
|
||||
return elaborate_lnet_common_(des, scope, false);
|
||||
return elaborate_lnet_common_(des, scope, false, var_allowed_in_sv);
|
||||
}
|
||||
|
||||
NetNet* PEIdent::elaborate_bi_net(Design*des, NetScope*scope) const
|
||||
NetNet* PEIdent::elaborate_bi_net(Design*des, NetScope*scope,
|
||||
bool var_allowed_in_sv) const
|
||||
{
|
||||
return elaborate_lnet_common_(des, scope, true);
|
||||
return elaborate_lnet_common_(des, scope, true, var_allowed_in_sv);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
19
elaborate.cc
19
elaborate.cc
|
|
@ -124,7 +124,10 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const
|
|||
ivl_assert(*this, pin(1));
|
||||
|
||||
/* Elaborate the l-value. */
|
||||
NetNet*lval = pin(0)->elaborate_lnet(des, scope);
|
||||
// A continuous assignment can drive a variable if the default strength is used.
|
||||
bool var_allowed_in_sv = (drive0 == IVL_DR_STRONG &&
|
||||
drive1 == IVL_DR_STRONG) ? true : false;
|
||||
NetNet*lval = pin(0)->elaborate_lnet(des, scope, var_allowed_in_sv);
|
||||
if (lval == 0) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -771,10 +774,11 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const
|
|||
des->errors += 1;
|
||||
return;
|
||||
}
|
||||
// Gates can never have variable output ports.
|
||||
if (lval_count > gate_count)
|
||||
lval_sigs[idx] = pin(idx)->elaborate_bi_net(des, scope);
|
||||
lval_sigs[idx] = pin(idx)->elaborate_bi_net(des, scope, false);
|
||||
else
|
||||
lval_sigs[idx] = pin(idx)->elaborate_lnet(des, scope);
|
||||
lval_sigs[idx] = pin(idx)->elaborate_lnet(des, scope, false);
|
||||
|
||||
// The only way this should return zero is if an error
|
||||
// happened, so for that case just return.
|
||||
|
|
@ -1677,7 +1681,8 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
|
|||
Use the elaborate_bi_net method to handle all
|
||||
the possible cases. */
|
||||
|
||||
sig = pins[idx]->elaborate_bi_net(des, scope);
|
||||
// A module inout port cannot drive a variable.
|
||||
sig = pins[idx]->elaborate_bi_net(des, scope, false);
|
||||
if (sig == 0) {
|
||||
cerr << pins[idx]->get_fileline() << ": error: "
|
||||
<< "Inout port expression must support "
|
||||
|
|
@ -1739,7 +1744,8 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
|
|||
assignment, as the port will continuous assign
|
||||
into the port. */
|
||||
|
||||
sig = pins[idx]->elaborate_lnet(des, scope);
|
||||
// A module output port can drive a variable.
|
||||
sig = pins[idx]->elaborate_lnet(des, scope, true);
|
||||
if (sig == 0) {
|
||||
cerr << pins[idx]->get_fileline() << ": error: "
|
||||
<< "Output port expression must support "
|
||||
|
|
@ -2196,7 +2202,8 @@ void PGModule::elaborate_udp_(Design*des, PUdp*udp, NetScope*scope) const
|
|||
<< endl;
|
||||
|
||||
} else {
|
||||
NetNet*sig = pins[0]->elaborate_lnet(des, scope);
|
||||
// A UDP can drive a variable.
|
||||
NetNet*sig = pins[0]->elaborate_lnet(des, scope, true);
|
||||
if (sig == 0) {
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< "Output port expression is not valid." << endl;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,27 @@
|
|||
module top;
|
||||
real rout_ca1, rout_ca2, rout_valid, rout_gt, rout_udp;
|
||||
logic lout_ca1, lout_ca2, lout_valid1, lout_valid2, lout_gt, lout_udp;
|
||||
reg in;
|
||||
|
||||
assign (weak1, weak0) {rout_ca1, rout_ca2} = in; // Non-default strength so invalid
|
||||
assign (weak1, weak0) {lout_ca1, lout_ca2} = in; // Non-default strength so invalid
|
||||
|
||||
assign (strong1, strong0) rout_valid = in; // Ok, real cannot be in a concatenation
|
||||
assign (strong1, strong0) {lout_valid1, lout_valid2} = in; // Ok, default strength
|
||||
|
||||
and (rout_gt, in, in); // Gates must drive a net
|
||||
and (lout_gt, in, in); // Gates must drive a net
|
||||
|
||||
// When strength is added it should only be for the default strength!
|
||||
udp_inv (rout_udp, in); // A UDP is like a module and can drive a variable
|
||||
udp_inv (lout_udp, in); // A UDP is like a module and can drive a variable
|
||||
|
||||
initial $display("FAILED: There should be compile errors!");
|
||||
endmodule
|
||||
|
||||
primitive udp_inv (output y, input a);
|
||||
table
|
||||
0 : 1;
|
||||
1 : 0;
|
||||
endtable
|
||||
endprimitive
|
||||
|
|
@ -228,6 +228,10 @@ br_gh782b normal,-g2009 ivltests gold=br_gh782b.gold
|
|||
br_gh800 normal,-g2009 ivltests
|
||||
br_gh801 normal,-g2012 ivltests
|
||||
br_gh801b normal,-g2012 ivltests
|
||||
br_gh1222 CE,-g2009 ivltests gold=br_gh1222.gold
|
||||
br_gh1223a normal,-g2009 ivltests
|
||||
br_gh1223b normal,-g2009 ivltests
|
||||
br_gh1223c normal,-g2009 ivltests
|
||||
br_ml20171017 normal,-g2009 ivltests
|
||||
br_ml20180227 CE,-g2009 ivltests
|
||||
br_ml20180309a normal,-g2009 ivltests
|
||||
|
|
|
|||
|
|
@ -364,9 +364,6 @@ br_gh1178a CE ivltests gold=br_gh1178a.gold
|
|||
br_gh1178b normal ivltests
|
||||
br_gh1178c normal ivltests
|
||||
br_gh1182 CE ivltests gold=br_gh1182.gold
|
||||
br_gh1223a normal,-g2009 ivltests
|
||||
br_gh1223b normal,-g2009 ivltests
|
||||
br_gh1223c normal,-g2009 ivltests
|
||||
br_gh1225a CE ivltests gold=br_gh1225a.gold
|
||||
br_gh1225b CE ivltests gold=br_gh1225b.gold
|
||||
br_gh1225c CE ivltests gold=br_gh1225c.gold
|
||||
|
|
|
|||
Loading…
Reference in New Issue