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)
|
* Copyright CERN 2013 / Stephen Williams (steve@icarus.com)
|
||||||
*
|
*
|
||||||
* This source code is free software; you can redistribute it
|
* This source code is free software; you can redistribute it
|
||||||
|
|
@ -54,7 +54,7 @@ bool PExpr::has_aa_term(Design*, NetScope*) const
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
NetNet* PExpr::elaborate_lnet(Design*, NetScope*) const
|
NetNet* PExpr::elaborate_lnet(Design*, NetScope*, bool) const
|
||||||
{
|
{
|
||||||
cerr << get_fileline() << ": error: "
|
cerr << get_fileline() << ": error: "
|
||||||
<< "expression not valid in assign l-value: "
|
<< "expression not valid in assign l-value: "
|
||||||
|
|
@ -62,7 +62,7 @@ NetNet* PExpr::elaborate_lnet(Design*, NetScope*) const
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
NetNet* PExpr::elaborate_bi_net(Design*, NetScope*) const
|
NetNet* PExpr::elaborate_bi_net(Design*, NetScope*, bool) const
|
||||||
{
|
{
|
||||||
cerr << get_fileline() << ": error: "
|
cerr << get_fileline() << ": error: "
|
||||||
<< "expression not valid as argument to inout port: "
|
<< "expression not valid as argument to inout port: "
|
||||||
|
|
|
||||||
24
PExpr.h
24
PExpr.h
|
|
@ -1,7 +1,7 @@
|
||||||
#ifndef IVL_PExpr_H
|
#ifndef IVL_PExpr_H
|
||||||
#define 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)
|
* Copyright CERN 2013 / Stephen Williams (steve@icarus.com)
|
||||||
*
|
*
|
||||||
* This source code is free software; you can redistribute it
|
* 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
|
// This method elaborates the expression as gates, but
|
||||||
// restricted for use as l-values of continuous assignments.
|
// 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
|
// This is similar to elaborate_lnet, except that the
|
||||||
// expression is evaluated to be bi-directional. This is
|
// expression is evaluated to be bi-directional. This is
|
||||||
// useful for arguments to inout ports of module instances and
|
// useful for arguments to inout ports of module instances and
|
||||||
// ports of tran primitives.
|
// 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
|
// Expressions that can be in the l-value of procedural
|
||||||
// assignments can be elaborated with this method. If the
|
// 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,
|
virtual unsigned test_width(Design*des, NetScope*scope,
|
||||||
width_mode_t&mode);
|
width_mode_t&mode);
|
||||||
|
|
||||||
virtual NetNet* elaborate_lnet(Design*des, NetScope*scope) const;
|
virtual NetNet* elaborate_lnet(Design*des, NetScope*scope,
|
||||||
virtual NetNet* elaborate_bi_net(Design*des, NetScope*scope) const;
|
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,
|
virtual NetExpr*elaborate_expr(Design*des, NetScope*scope,
|
||||||
ivl_type_t type, unsigned flags) const;
|
ivl_type_t type, unsigned flags) const;
|
||||||
|
|
@ -269,7 +273,8 @@ class PEConcat : public PExpr {
|
||||||
NetNet::PortType port_type) const;
|
NetNet::PortType port_type) const;
|
||||||
private:
|
private:
|
||||||
NetNet* elaborate_lnet_common_(Design*des, NetScope*scope,
|
NetNet* elaborate_lnet_common_(Design*des, NetScope*scope,
|
||||||
bool bidirectional_flag) const;
|
bool bidirectional_flag,
|
||||||
|
bool var_allowed_in_sv) const;
|
||||||
private:
|
private:
|
||||||
std::vector<PExpr*>parms_;
|
std::vector<PExpr*>parms_;
|
||||||
std::valarray<width_mode_t>width_modes_;
|
std::valarray<width_mode_t>width_modes_;
|
||||||
|
|
@ -355,9 +360,9 @@ class PEIdent : public PExpr {
|
||||||
width_mode_t&mode);
|
width_mode_t&mode);
|
||||||
|
|
||||||
// Identifiers are allowed (with restrictions) is assign l-values.
|
// 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.
|
// Identifiers are also allowed as procedural assignment l-values.
|
||||||
virtual NetAssign_* elaborate_lval(Design*des,
|
virtual NetAssign_* elaborate_lval(Design*des,
|
||||||
|
|
@ -545,7 +550,8 @@ class PEIdent : public PExpr {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
NetNet* elaborate_lnet_common_(Design*des, NetScope*scope,
|
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,
|
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)
|
* Copyright CERN 2012 / Stephen Williams (steve@icarus.com)
|
||||||
*
|
*
|
||||||
* This source code is free software; you can redistribute it
|
* This source code is free software; you can redistribute it
|
||||||
|
|
@ -43,7 +43,8 @@ using namespace std;
|
||||||
* make the l-value connections.
|
* make the l-value connections.
|
||||||
*/
|
*/
|
||||||
NetNet* PEConcat::elaborate_lnet_common_(Design*des, NetScope*scope,
|
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);
|
ivl_assert(*this, scope);
|
||||||
|
|
||||||
|
|
@ -76,9 +77,9 @@ NetNet* PEConcat::elaborate_lnet_common_(Design*des, NetScope*scope,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bidirectional_flag) {
|
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 {
|
} 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) {
|
if (nets[idx] == 0) {
|
||||||
|
|
@ -163,14 +164,16 @@ NetNet* PEConcat::elaborate_lnet_common_(Design*des, NetScope*scope,
|
||||||
return osig;
|
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,
|
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.
|
* so most of the work for both is done here.
|
||||||
*/
|
*/
|
||||||
NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
|
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);
|
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
|
// If this is SystemVerilog and the variable is not yet
|
||||||
// assigned by anything, then convert it to an unresolved
|
// assigned by anything, then convert it to an unresolved
|
||||||
// wire.
|
// wire.
|
||||||
if (gn_var_can_be_uwire()
|
if (gn_var_can_be_uwire() && var_allowed_in_sv
|
||||||
&& (sig->type() == NetNet::REG)
|
&& (sig->type() == NetNet::REG)
|
||||||
&& (sig->peek_lref() == 0) ) {
|
&& (sig->peek_lref() == 0) ) {
|
||||||
sig->type(NetNet::UNRESOLVED_WIRE);
|
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.
|
// Don't allow registers as assign l-values.
|
||||||
if (sig->type() == NetNet::REG) {
|
if (sig->type() == NetNet::REG) {
|
||||||
cerr << get_fileline() << ": error: reg " << sig->name()
|
cerr << get_fileline() << ": error: variable " << sig->name()
|
||||||
<< "; cannot be driven by primitives"
|
<< "; cannot be driven by a primitive or continuous assignment";
|
||||||
<< " or continuous assignment." << endl;
|
if(gn_var_can_be_uwire()) {
|
||||||
|
cerr << " with non-default strength";
|
||||||
|
}
|
||||||
|
cerr << "." << endl;
|
||||||
des->errors += 1;
|
des->errors += 1;
|
||||||
return 0;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Some parts below need the tail component. This is a convenient
|
// 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()
|
cerr << get_fileline() << ": error: Array " << path()
|
||||||
<< " needs " << sig->unpacked_dimensions() << " indices,"
|
<< " needs " << sig->unpacked_dimensions() << " indices,"
|
||||||
<< " but got only " << path_tail.index.size() << ". (net)" << endl;
|
<< " but got only " << path_tail.index.size() << ". (net)" << endl;
|
||||||
|
cerr << get_fileline() << ": : Assignment to a whole array requires SystemVerilog."
|
||||||
|
<< endl;
|
||||||
des->errors += 1;
|
des->errors += 1;
|
||||||
return 0;
|
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
|
* Identifiers in continuous assignment l-values are limited to wires
|
||||||
* and that ilk. Detect registers and memories here and report errors.
|
* 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));
|
ivl_assert(*this, pin(1));
|
||||||
|
|
||||||
/* Elaborate the l-value. */
|
/* 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) {
|
if (lval == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -771,10 +774,11 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const
|
||||||
des->errors += 1;
|
des->errors += 1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// Gates can never have variable output ports.
|
||||||
if (lval_count > gate_count)
|
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
|
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
|
// The only way this should return zero is if an error
|
||||||
// happened, so for that case just return.
|
// 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
|
Use the elaborate_bi_net method to handle all
|
||||||
the possible cases. */
|
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) {
|
if (sig == 0) {
|
||||||
cerr << pins[idx]->get_fileline() << ": error: "
|
cerr << pins[idx]->get_fileline() << ": error: "
|
||||||
<< "Inout port expression must support "
|
<< "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
|
assignment, as the port will continuous assign
|
||||||
into the port. */
|
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) {
|
if (sig == 0) {
|
||||||
cerr << pins[idx]->get_fileline() << ": error: "
|
cerr << pins[idx]->get_fileline() << ": error: "
|
||||||
<< "Output port expression must support "
|
<< "Output port expression must support "
|
||||||
|
|
@ -2196,7 +2202,8 @@ void PGModule::elaborate_udp_(Design*des, PUdp*udp, NetScope*scope) const
|
||||||
<< endl;
|
<< endl;
|
||||||
|
|
||||||
} else {
|
} 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) {
|
if (sig == 0) {
|
||||||
cerr << get_fileline() << ": error: "
|
cerr << get_fileline() << ": error: "
|
||||||
<< "Output port expression is not valid." << endl;
|
<< "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_gh800 normal,-g2009 ivltests
|
||||||
br_gh801 normal,-g2012 ivltests
|
br_gh801 normal,-g2012 ivltests
|
||||||
br_gh801b 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_ml20171017 normal,-g2009 ivltests
|
||||||
br_ml20180227 CE,-g2009 ivltests
|
br_ml20180227 CE,-g2009 ivltests
|
||||||
br_ml20180309a normal,-g2009 ivltests
|
br_ml20180309a normal,-g2009 ivltests
|
||||||
|
|
|
||||||
|
|
@ -364,9 +364,6 @@ br_gh1178a CE ivltests gold=br_gh1178a.gold
|
||||||
br_gh1178b normal ivltests
|
br_gh1178b normal ivltests
|
||||||
br_gh1178c normal ivltests
|
br_gh1178c normal ivltests
|
||||||
br_gh1182 CE ivltests gold=br_gh1182.gold
|
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_gh1225a CE ivltests gold=br_gh1225a.gold
|
||||||
br_gh1225b CE ivltests gold=br_gh1225b.gold
|
br_gh1225b CE ivltests gold=br_gh1225b.gold
|
||||||
br_gh1225c CE ivltests gold=br_gh1225c.gold
|
br_gh1225c CE ivltests gold=br_gh1225c.gold
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue