Support `unconnected_drive

This commit is contained in:
Wilson Snyder 2020-04-09 23:26:03 -04:00
parent 343db78c03
commit 15b40a97d9
13 changed files with 140 additions and 9 deletions

View File

@ -2420,6 +2420,7 @@ private:
int m_level; // 1=top module, 2=cell off top module, ...
int m_varNum; // Incrementing variable number
int m_typeNum; // Incrementing implicit type number
VOptionBool m_unconnectedDrive; // State of `unconnected_drive
public:
AstNodeModule(AstType t, FileLine* fl, const string& name)
: AstNode(t, fl)
@ -2461,6 +2462,8 @@ public:
bool recursive() const { return m_recursive; }
void recursiveClone(bool flag) { m_recursiveClone = flag; }
bool recursiveClone() const { return m_recursiveClone; }
void unconnectedDrive(const VOptionBool flag) { m_unconnectedDrive = flag; }
VOptionBool unconnectedDrive() const { return m_unconnectedDrive; }
};
class AstNodeRange : public AstNode {

View File

@ -547,7 +547,6 @@ private:
// we'll save work, and we can't call pinReconnectSimple in
// this loop as it clone()s itself.
for (AstPin* pinp = nodep->pinsp(); pinp; pinp = VN_CAST(pinp->nextp(), Pin)) {
if (!pinp->exprp()) continue;
V3Inst::pinReconnectSimple(pinp, nodep, false);
}

View File

@ -62,13 +62,15 @@ private:
// PIN(p,expr) -> ASSIGNW(VARXREF(p),expr) (if sub's input)
// or ASSIGNW(expr,VARXREF(p)) (if sub's output)
UINFO(4," PIN "<<nodep<<endl);
if (!nodep->user1()) {
// Simplify it
V3Inst::pinReconnectSimple(nodep, m_cellp, false);
}
if (!nodep->exprp()) return; // No-connect
if (debug()>=9) nodep->dumpTree(cout, " Pin_oldb: ");
V3Inst::checkOutputShort(nodep);
// Use user1p on the PIN to indicate we created an assign for this pin
if (!nodep->user1SetOnce()) {
// Simplify it
V3Inst::pinReconnectSimple(nodep, m_cellp, false);
// Make an ASSIGNW (expr, pin)
AstNode* exprp = nodep->exprp()->cloneTree(false);
UASSERT_OBJ(exprp->width() == nodep->modVarp()->width(), nodep,
@ -481,8 +483,20 @@ public:
// Else create a intermediate wire to perform the interconnect
// Return the new assignment, if one was made
// Note this module calles cloneTree() via new AstVar
AstVar* pinVarp = pinp->modVarp();
if (!pinp->exprp()) {
// No-connect, perhaps promote based on `unconnected_drive,
// otherwise done
if (pinVarp->direction() == VDirection::INPUT
&& cellp->modp()->unconnectedDrive().isSetTrue()) {
pinp->exprp(new AstConst(pinp->fileline(), AstConst::StringToParse(), "'1"));
} else if (pinVarp->direction() == VDirection::INPUT
&& cellp->modp()->unconnectedDrive().isSetFalse()) {
pinp->exprp(new AstConst(pinp->fileline(), AstConst::StringToParse(), "'0"));
} else {
return NULL;
}
}
AstVarRef* connectRefp = VN_CAST(pinp->exprp(), VarRef);
AstVarXRef* connectXRefp = VN_CAST(pinp->exprp(), VarXRef);
AstBasicDType* pinBasicp = VN_CAST(pinVarp->dtypep(), BasicDType); // Maybe NULL

View File

@ -53,6 +53,8 @@ public:
bool isDefault() const { return m_e == OPT_DEFAULT_FALSE || m_e == OPT_DEFAULT_TRUE; }
bool isTrue() const { return m_e == OPT_TRUE || m_e == OPT_DEFAULT_TRUE; }
bool isFalse() const { return m_e == OPT_FALSE || m_e == OPT_DEFAULT_FALSE; }
bool isSetTrue() const { return m_e == OPT_TRUE; }
bool isSetFalse() const { return m_e == OPT_FALSE; }
void setTrueOrFalse(bool flag) { m_e = flag ? OPT_TRUE : OPT_FALSE; }
const char* ascii() const {
static const char* const names[] = {

View File

@ -109,6 +109,7 @@ class V3ParseImp {
bool m_inLibrary; // Currently reading a library vs. regular file
int m_inBeginKwd; // Inside a `begin_keywords
int m_lastVerilogState; // Last LEX state in `begin_keywords
VOptionBool m_unconnectedDrive; // Last unconnected drive
int m_prevLexToken; // previous parsed token (for lexer)
bool m_ahead; // aheadval is valid
@ -199,6 +200,8 @@ public:
bool inCellDefine() const { return m_inCellDefine; }
void inCellDefine(bool flag) { m_inCellDefine = flag; }
bool inLibrary() const { return m_inLibrary; }
VOptionBool unconnectedDrive() const { return m_unconnectedDrive; }
void unconnectedDrive(const VOptionBool flag) { m_unconnectedDrive = flag; }
// Interactions with parser
int bisonParse();

View File

@ -1087,10 +1087,8 @@ class TristateVisitor : public TristateBaseVisitor {
// Find child module's new variables.
AstVar* enModVarp = static_cast<AstVar*>(nodep->modVarp()->user1p());
if (!enModVarp) {
if (nodep->exprp()) {
// May have an output only that later connects to a tristate, so simplify now.
V3Inst::pinReconnectSimple(nodep, m_cellp, false);
}
// May have an output only that later connects to a tristate, so simplify now.
V3Inst::pinReconnectSimple(nodep, m_cellp, false);
iteratePinGuts(nodep);
return; // No __en signals on this pin
}

View File

@ -966,7 +966,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
"`noremove_gatenames" { FL_FWD; FL_BRK; } // Verilog-XL compatibility
"`noremove_netnames" { FL_FWD; FL_BRK; } // Verilog-XL compatibility
"`nosuppress_faults" { FL_FWD; FL_BRK; } // Verilog-XL compatibility
"`nounconnected_drive" { FL_FWD; FL_BRK; } // Verilog-XL compatibility
"`nounconnected_drive" { FL_FWD; PARSEP->unconnectedDrive(VOptionBool::OPT_DEFAULT_FALSE); FL_BRK; }
"`portcoerce" { FL_FWD; FL_BRK; }
"`pragma"{ws}*[^\n\r]* { FL_FWD; FL_BRK; } // Verilog 2005
"`protect" { FL_FWD; FL_BRK; }
@ -976,6 +976,9 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
return yaT_RESETALL; } // Rest handled by preproc
"`suppress_faults" { FL_FWD; FL_BRK; } // Verilog-XL compatibility
"`timescale"{ws}+[^\n\r]* { FL_FWD; FL_BRK; } // Verilog spec - not supported
"`unconnected_drive"{ws}+"pull0" { FL_FWD; PARSEP->unconnectedDrive(VOptionBool::OPT_FALSE); FL_BRK; }
"`unconnected_drive"{ws}+"pull1" { FL_FWD; PARSEP->unconnectedDrive(VOptionBool::OPT_TRUE); FL_BRK; }
"`unconnected_drive" { FL_FWD; yyerrorf("Bad `unconnected_drive syntax"); FL_BRK; }
"`uselib"{ws}+[^\n\r]* { FL_FWD; FL_BRK; } // Verilog-XL compatibility
/* See also setLanguage below */

View File

@ -953,6 +953,7 @@ modFront<modulep>:
{ $$ = new AstModule($<fl>3,*$3);
$$->inLibrary(PARSEP->inLibrary() || PARSEP->inCellDefine());
$$->modTrace(GRAMMARP->allTracingOn($$->fileline()));
$$->unconnectedDrive(PARSEP->unconnectedDrive());
PARSEP->rootp()->addModulep($$);
SYMP->pushNew($$); }
;

21
test_regress/t/t_unconnected.pl Executable file
View File

@ -0,0 +1,21 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2004 by Wilson Snyder. This program is free software; you
# can redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
scenarios(simulator => 1);
compile(
);
execute(
check_finished => 1,
);
ok(1);
1;

View File

@ -0,0 +1,46 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2020 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
module t(/*AUTOARG*/
// Inputs
clk
);
input clk;
wire o_n;
wire o_0;
wire o_1;
// verilator lint_off PINMISSING
sub_0 sub_0(.o_0);
sub_1 sub_1(.o_1);
sub_n sub_n(.o_n);
// verilator lint_on PINMISSING
always @ (posedge clk) begin
if (o_0 !== 1'b0) $stop;
if (o_1 !== 1'b1) $stop;
//4-state if (o_n !== 1'bz) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule
`unconnected_drive pull0
module sub_0 (input i, output wire o_0);
assign o_0 = i;
endmodule
`unconnected_drive pull1
module sub_1 (input i, output wire o_1);
assign o_1 = i;
endmodule
`nounconnected_drive
module sub_n (input i, output wire o_n);
assign o_n = i;
endmodule

View File

@ -0,0 +1,10 @@
%Error: t/t_unconnected_bad.v:7:1: Bad `unconnected_drive syntax
7 | `unconnected_drive
| ^~~~~~~~~~~~~~~~~~
%Error: t/t_unconnected_bad.v:9:1: Bad `unconnected_drive syntax
9 | `unconnected_drive pull2
| ^~~~~~~~~~~~~~~~~~
%Error: t/t_unconnected_bad.v:9:20: syntax error, unexpected IDENTIFIER
9 | `unconnected_drive pull2
| ^~~~~
%Error: Exiting due to

View File

@ -0,0 +1,19 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 by Wilson Snyder. This program is free software; you
# can redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
scenarios(linter => 1);
lint(
fails => 1,
expect_filename => $Self->{golden_filename},
);
ok(1);
1;

View File

@ -0,0 +1,12 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2018 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
`unconnected_drive
`unconnected_drive pull2
module t;
endmodule