diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index 78384ce27..961bacde0 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -52,6 +52,7 @@ Stephen Henry Tim Snyder Tobias Rosenkranz Tobias Wölfel +Tomasz Gorochowik Todd Strader Tymoteusz Blazejczyk Vassilis Papaefstathiou diff --git a/src/Makefile_obj.in b/src/Makefile_obj.in index bff0b5b0e..ce9ccead6 100644 --- a/src/Makefile_obj.in +++ b/src/Makefile_obj.in @@ -211,6 +211,7 @@ RAW_OBJS = \ V3LinkCells.o \ V3LinkDot.o \ V3LinkJump.o \ + V3LinkInc.o \ V3LinkLValue.o \ V3LinkLevel.o \ V3LinkParse.o \ diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 996dd72ab..eb8a81f61 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -7245,6 +7245,110 @@ public: virtual int instrCount() const { return widthInstrs() * instrCountMul() * 10; } virtual bool signedFlavor() const { return true; } }; +class AstPreAdd : public AstNodeTriop { + // Pre-increment/add + // Parents: MATH + // Children: lhsp: AstConst (1) as currently support only ++ not += + // Children: rhsp: tree with AstVarRef that is value to read before operation + // Children: thsp: tree with AstVarRef LValue that is stored after operation +public: + AstPreAdd(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* thsp) + : ASTGEN_SUPER(fl, lhsp, rhsp, thsp) { + } + ASTNODE_NODE_FUNCS(PreAdd) + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, + const V3Number& ths) { + V3ERROR_NA; // Need to modify lhs + } + virtual string emitVerilog() { return "%k(++%r)"; } + virtual string emitC() { V3ERROR_NA_RETURN(""); } + virtual string emitSimpleOperator() { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const { return false; } + virtual bool cleanLhs() const { return false; } + virtual bool cleanRhs() const { return false; } + virtual bool cleanThs() const { return false; } + virtual bool sizeMattersLhs() const { return true; } + virtual bool sizeMattersRhs() const { return true; } + virtual bool sizeMattersThs() const { return true; } +}; +class AstPreSub : public AstNodeTriop { + // Pre-decrement/subtract + // Parents: MATH + // Children: lhsp: AstConst (1) as currently support only -- not -= + // Children: rhsp: tree with AstVarRef that is value to read before operation + // Children: thsp: tree with AstVarRef LValue that is stored after operation +public: + AstPreSub(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* thsp) + : ASTGEN_SUPER(fl, lhsp, rhsp, thsp) { + } + ASTNODE_NODE_FUNCS(PreSub) + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, + const V3Number& ths) { + V3ERROR_NA; // Need to modify lhs + } + virtual string emitVerilog() { return "%k(--%r)"; } + virtual string emitC() { V3ERROR_NA_RETURN(""); } + virtual string emitSimpleOperator() { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const { return false; } + virtual bool cleanLhs() const { return false; } + virtual bool cleanRhs() const { return false; } + virtual bool cleanThs() const { return false; } + virtual bool sizeMattersLhs() const { return true; } + virtual bool sizeMattersRhs() const { return true; } + virtual bool sizeMattersThs() const { return true; } +}; +class AstPostAdd : public AstNodeTriop { + // Post-increment/add + // Parents: MATH + // Children: lhsp: AstConst (1) as currently support only ++ not += + // Children: rhsp: tree with AstVarRef that is value to read before operation + // Children: thsp: tree with AstVarRef LValue that is stored after operation +public: + AstPostAdd(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* thsp) + : ASTGEN_SUPER(fl, lhsp, rhsp, thsp) { + } + ASTNODE_NODE_FUNCS(PostAdd) + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, + const V3Number& ths) { + V3ERROR_NA; // Need to modify lhs + } + virtual string emitVerilog() { return "%k(%r++)"; } + virtual string emitC() { V3ERROR_NA_RETURN(""); } + virtual string emitSimpleOperator() { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const { return false; } + virtual bool cleanLhs() const { return false; } + virtual bool cleanRhs() const { return false; } + virtual bool cleanThs() const { return false; } + virtual bool sizeMattersLhs() const { return true; } + virtual bool sizeMattersRhs() const { return true; } + virtual bool sizeMattersThs() const { return true; } +}; +class AstPostSub : public AstNodeTriop { + // Post-decrement/subtract + // Parents: MATH + // Children: lhsp: AstConst (1) as currently support only -- not -= + // Children: rhsp: tree with AstVarRef that is value to read before operation + // Children: thsp: tree with AstVarRef LValue that is stored after operation +public: + AstPostSub(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* thsp) + : ASTGEN_SUPER(fl, lhsp, rhsp, thsp) { + } + ASTNODE_NODE_FUNCS(PostSub) + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, + const V3Number& ths) { + V3ERROR_NA; // Need to modify lhs + } + virtual string emitVerilog() { return "%k(%r--)"; } + virtual string emitC() { V3ERROR_NA_RETURN(""); } + virtual string emitSimpleOperator() { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const { return false; } + virtual bool cleanLhs() const { return false; } + virtual bool cleanRhs() const { return false; } + virtual bool cleanThs() const { return false; } + virtual bool sizeMattersLhs() const { return true; } + virtual bool sizeMattersRhs() const { return true; } + virtual bool sizeMattersThs() const { return true; } +}; class AstEqCase : public AstNodeBiCom { public: AstEqCase(FileLine* fl, AstNode* lhsp, AstNode* rhsp) diff --git a/src/V3LinkInc.cpp b/src/V3LinkInc.cpp new file mode 100644 index 000000000..381f81ff8 --- /dev/null +++ b/src/V3LinkInc.cpp @@ -0,0 +1,248 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: Replace increments/decrements with new variables +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2003-2020 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 +// +//************************************************************************* +// V3LinkInc's Transformations: +// +// prepost_stmt_visit +// PREADD/PRESUB +// Create a temporary __VIncrementX variable, assign the value of +// the current variable value to it, substitute the current +// variable with the temporary one in the statement. +// Increment/decrement the original variable with by the given +// value. +// POSTADD/POSTSUB +// Increment/decrement the current variable by the given value. +// Create a temporary __VIncrementX variable, assign the value of +// of the current variable (after the operation) to it. Substitute +// The original variable with the temporary one in the statement. +// prepost_non_stmt_visit +// PREADD/PRESUB/POSTADD/POSTSUB +// Increment/decrement the current variable by the given value. +// The order (pre/post) doesn't matter outside statements thus +// the pre/post operations are treated equally and there is no +// need for a temporary variable. +// +//************************************************************************* + +#include "config_build.h" +#include "verilatedos.h" + +#include "V3Global.h" +#include "V3LinkInc.h" +#include "V3Ast.h" + +#include +#include +#include + +//###################################################################### + +class LinkIncVisitor : public AstNVisitor { +private: + // TYPES + enum InsertMode { + IM_BEFORE, // Pointing at statement ref is in, insert before this + IM_AFTER, // Pointing at last inserted stmt, insert after + IM_WHILE_PRECOND // Pointing to for loop, add to body end + }; + + // STATE + int m_modIncrementsNum; // Var name counter + InsertMode m_insMode; // How to insert + AstNode* m_insStmtp; // Where to insert statement + bool m_unsupportedHere; // Used to detect where it's not supported yet + +private: + void insertBeforeStmt(AstNode* nodep, AstNode* newp) { + // Return node that must be visited, if any + // See also AstNode::addBeforeStmt; this predates that function + if (debug() >= 9) newp->dumpTree(cout, "-newstmt:"); + UASSERT_OBJ(m_insStmtp, nodep, "Function not underneath a statement"); + if (m_insMode == IM_BEFORE) { + // Add the whole thing before insertAt + if (debug() >= 9) newp->dumpTree(cout, "-newfunc:"); + m_insStmtp->addHereThisAsNext(newp); + } else if (m_insMode == IM_AFTER) { + m_insStmtp->addNextHere(newp); + } else if (m_insMode == IM_WHILE_PRECOND) { + AstWhile* whilep = VN_CAST(m_insStmtp, While); + UASSERT_OBJ(whilep, nodep, "Insert should be under WHILE"); + whilep->addPrecondsp(newp); + } else { + nodep->v3fatalSrc("Unknown InsertMode"); + } + m_insMode = IM_AFTER; + m_insStmtp = newp; + } + + // VISITORS + virtual void visit(AstNodeModule* nodep) VL_OVERRIDE { + // Reset increments count + m_modIncrementsNum = 0; + iterateChildren(nodep); + } + virtual void visit(AstWhile* nodep) VL_OVERRIDE { + // Special, as statements need to be put in different places + // Preconditions insert first just before themselves (the normal + // rule for other statement types) + m_insStmtp = NULL; // First thing should be new statement + iterateAndNextNull(nodep->precondsp()); + // Conditions insert first at end of precondsp. + m_insMode = IM_WHILE_PRECOND; + m_insStmtp = nodep; + iterateAndNextNull(nodep->condp()); + // Body insert just before themselves + m_insStmtp = NULL; // First thing should be new statement + iterateAndNextNull(nodep->bodysp()); + iterateAndNextNull(nodep->incsp()); + // Done the loop + m_insStmtp = NULL; // Next thing should be new statement + } + virtual void visit(AstNodeFor* nodep) VL_OVERRIDE { // LCOV_EXCL_LINE + nodep->v3fatalSrc( + "For statements should have been converted to while statements in V3Begin.cpp"); + } + virtual void visit(AstNodeStmt* nodep) VL_OVERRIDE { + if (!nodep->isStatement()) { + iterateChildren(nodep); + return; + } + m_insMode = IM_BEFORE; + m_insStmtp = nodep; + iterateChildren(nodep); + m_insStmtp = NULL; // Next thing should be new statement + } + void unsupported_visit(AstNode* nodep) { + m_unsupportedHere = true; + UINFO(9, "Marking unsupported " << nodep << endl); + iterateChildren(nodep); + m_unsupportedHere = false; + } + virtual void visit(AstLogAnd* nodep) VL_OVERRIDE { unsupported_visit(nodep); } + virtual void visit(AstLogOr* nodep) VL_OVERRIDE { unsupported_visit(nodep); } + virtual void visit(AstLogEq* nodep) VL_OVERRIDE { unsupported_visit(nodep); } + virtual void visit(AstLogIf* nodep) VL_OVERRIDE { unsupported_visit(nodep); } + virtual void visit(AstCond* nodep) VL_OVERRIDE { unsupported_visit(nodep); } + virtual void visit(AstCondBound* nodep) VL_OVERRIDE { unsupported_visit(nodep); } + void prepost_visit(AstNodeTriop* nodep) { + // Check if we are underneath a statement + if (!m_insStmtp) { + prepost_non_stmt_visit(nodep); + } else { + prepost_stmt_visit(nodep); + } + } + void prepost_non_stmt_visit(AstNodeTriop* nodep) { + iterateChildren(nodep); + + AstConst* constp = VN_CAST(nodep->lhsp(), Const); + UASSERT_OBJ(nodep, constp, "Expecting CONST"); + AstConst* newconstp = constp->cloneTree(true); + + AstNode* storetop = nodep->thsp(); + AstNode* valuep = nodep->rhsp(); + + storetop->unlinkFrBack(); + valuep->unlinkFrBack(); + + AstAssign* assignp; + if (VN_IS(nodep, PreSub) || VN_IS(nodep, PostSub)) { + assignp = new AstAssign(nodep->fileline(), storetop, + new AstSub(nodep->fileline(), valuep, newconstp)); + } else { + assignp = new AstAssign(nodep->fileline(), storetop, + new AstAdd(nodep->fileline(), valuep, newconstp)); + } + nodep->replaceWith(assignp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); + } + void prepost_stmt_visit(AstNodeTriop* nodep) { + iterateChildren(nodep); + + AstNodeVarRef* varrefp; + if (m_unsupportedHere || !(varrefp = VN_CAST(nodep->rhsp(), VarRef))) { + nodep->v3error("Unsupported: Incrementation in this context."); + return; + } + + AstConst* constp = VN_CAST(nodep->lhsp(), Const); + UASSERT_OBJ(nodep, constp, "Expecting CONST"); + AstNode* backp = nodep->backp(); + AstConst* newconstp = constp->cloneTree(true); + + // Prepare a temporary variable + FileLine* fl = backp->fileline(); + string name = string("__Vincrement") + cvtToStr(++m_modIncrementsNum); + AstVar* varp = new AstVar(fl, AstVarType::BLOCKTEMP, name, varrefp->varp()->subDTypep()); + + // Declare the variable + insertBeforeStmt(nodep, varp); + + // Define what operation will we be doing + AstNode* operp; + if (VN_IS(nodep, PostSub) || VN_IS(nodep, PreSub)) { + operp = new AstSub(fl, new AstVarRef(fl, varrefp->varp(), false), newconstp); + } else { + operp = new AstAdd(fl, new AstVarRef(fl, varrefp->varp(), false), newconstp); + } + + if (VN_IS(nodep, PreAdd) || VN_IS(nodep, PreSub)) { + // PreAdd/PreSub operations + // Immediately after declaration - increment it by one + m_insStmtp->addHereThisAsNext(new AstAssign(fl, new AstVarRef(fl, varp, true), operp)); + // Immediately after incrementing - assign it to the original variable + m_insStmtp->addHereThisAsNext(new AstAssign( + fl, new AstVarRef(fl, varrefp->varp(), true), new AstVarRef(fl, varp, false))); + } else { + // PostAdd/PostSub operations + // assign the original variable to the temporary one + m_insStmtp->addHereThisAsNext(new AstAssign( + fl, new AstVarRef(fl, varp, true), new AstVarRef(fl, varrefp->varp(), false))); + // Increment the original variable by one + m_insStmtp->addHereThisAsNext( + new AstAssign(fl, new AstVarRef(fl, varrefp->varp(), true), operp)); + } + + // Replace the node with the temporary + nodep->replaceWith(new AstVarRef(varrefp->fileline(), varp, true)); + VL_DO_DANGLING(nodep->deleteTree(), nodep); + } + virtual void visit(AstPreAdd* nodep) VL_OVERRIDE { prepost_visit(nodep); } + virtual void visit(AstPostAdd* nodep) VL_OVERRIDE { prepost_visit(nodep); } + virtual void visit(AstPreSub* nodep) VL_OVERRIDE { prepost_visit(nodep); } + virtual void visit(AstPostSub* nodep) VL_OVERRIDE { prepost_visit(nodep); } + virtual void visit(AstGenFor* nodep) VL_OVERRIDE { iterateChildren(nodep); } + virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); } + +public: + // CONSTRUCTORS + explicit LinkIncVisitor(AstNetlist* nodep) { + m_modIncrementsNum = 0; + m_insMode = IM_BEFORE; + m_insStmtp = NULL; + m_unsupportedHere = false; + iterate(nodep); + } + virtual ~LinkIncVisitor() {} +}; + +//###################################################################### +// Task class functions + +void V3LinkInc::linkIncrements(AstNetlist* nodep) { + UINFO(2, __FUNCTION__ << ": " << endl); + { LinkIncVisitor bvisitor(nodep); } // Destruct before checking + V3Global::dumpCheckGlobalTree("linkInc", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); +} diff --git a/src/V3LinkInc.h b/src/V3LinkInc.h new file mode 100644 index 000000000..a1679e6d3 --- /dev/null +++ b/src/V3LinkInc.h @@ -0,0 +1,36 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: Replace increments/decrements with new variables +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2003-2020 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 +// +//************************************************************************* + +#ifndef _V3LINKINC_H_ +#define _V3LINKINC_H_ 1 + +#include "config_build.h" +#include "verilatedos.h" + +#include "V3Error.h" +#include "V3Ast.h" + +//============================================================================ + +class V3LinkInc { +public: + static void linkIncrements(AstNetlist* nodep); + +private: + void prepost_visit(AstNode* nodep); +}; + +#endif // Guard diff --git a/src/V3LinkLValue.cpp b/src/V3LinkLValue.cpp index 585c78eae..697472e49 100644 --- a/src/V3LinkLValue.cpp +++ b/src/V3LinkLValue.cpp @@ -215,6 +215,21 @@ private: } m_setRefLvalue = last_setRefLvalue; } + void prepost_visit(AstNodeTriop* nodep) { + bool last_setRefLvalue = m_setRefLvalue; + { + m_setRefLvalue = false; + iterateAndNextNull(nodep->lhsp()); + iterateAndNextNull(nodep->rhsp()); + m_setRefLvalue = true; + iterateAndNextNull(nodep->thsp()); + } + m_setRefLvalue = last_setRefLvalue; + } + virtual void visit(AstPreAdd* nodep) VL_OVERRIDE { prepost_visit(nodep); } + virtual void visit(AstPostAdd* nodep) VL_OVERRIDE { prepost_visit(nodep); } + virtual void visit(AstPreSub* nodep) VL_OVERRIDE { prepost_visit(nodep); } + virtual void visit(AstPostSub* nodep) VL_OVERRIDE { prepost_visit(nodep); } // Nodes that change LValue state virtual void visit(AstSel* nodep) VL_OVERRIDE { diff --git a/src/Verilator.cpp b/src/Verilator.cpp index c58d26c91..ed2826ffb 100644 --- a/src/Verilator.cpp +++ b/src/Verilator.cpp @@ -59,6 +59,7 @@ #include "V3LinkCells.h" #include "V3LinkDot.h" #include "V3LinkJump.h" +#include "V3LinkInc.h" #include "V3LinkLValue.h" #include "V3LinkLevel.h" #include "V3LinkParse.h" @@ -120,6 +121,8 @@ static void process() { V3LinkLValue::linkLValue(v3Global.rootp()); // Convert return/continue/disable to jumps V3LinkJump::linkJump(v3Global.rootp()); + // Convert --/++ to normal operations. Must be after LinkJump. + V3LinkInc::linkIncrements(v3Global.rootp()); V3Error::abortIfErrors(); if (v3Global.opt.stats()) V3Stats::statsStageAll(v3Global.rootp(), "Link"); diff --git a/src/verilog.y b/src/verilog.y index baa947abb..2d3bf6475 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -2929,23 +2929,17 @@ foperator_assignment: // IEEE: operator_assignment (for first part of exp //UNSUP BISONPRE_COPY(operator_assignment,{s/~f~/f/g}) // {copied} ; -//UNSUPinc_or_dec_expression: // ==IEEE: inc_or_dec_expression -//UNSUP // // Need fexprScope instead of variable_lvalue to prevent conflict -//UNSUP ~l~exprScope yP_PLUSPLUS { $$=$1; $$ = $1+$2; } -//UNSUP | ~l~exprScope yP_MINUSMINUS { $$=$1; $$ = $1+$2; } -//UNSUP // // Need expr instead of variable_lvalue to prevent conflict -//UNSUP | yP_PLUSPLUS expr { $$=$1; $$ = $1+$2; } -//UNSUP | yP_MINUSMINUS expr { $$=$1; $$ = $1+$2; } -//UNSUP ; +inc_or_dec_expression: // ==IEEE: inc_or_dec_expression + // // Need fexprScope instead of variable_lvalue to prevent conflict + ~l~exprScope yP_PLUSPLUS { $$=$1; $$ = new AstPostAdd($2, new AstConst($2, AstConst::StringToParse(), "'b1"), $1, $1->cloneTree(true)); } + | ~l~exprScope yP_MINUSMINUS { $$=$1; $$ = new AstPostSub($2, new AstConst($2, AstConst::StringToParse(), "'b1"), $1, $1->cloneTree(true)); } + // // Need expr instead of variable_lvalue to prevent conflict + | yP_PLUSPLUS expr { $$=$1; $$ = new AstPreAdd($1, new AstConst($1, AstConst::StringToParse(), "'b1"), $2, $2->cloneTree(true)); } + | yP_MINUSMINUS expr { $$=$1; $$ = new AstPreSub($1, new AstConst($1, AstConst::StringToParse(), "'b1"), $2, $2->cloneTree(true)); } + ; finc_or_dec_expression: // ==IEEE: inc_or_dec_expression - //UNSUP: Generic scopes in incrementes, remove below - fexprLvalue yP_PLUSPLUS { $$ = new AstAssign($2,$1,new AstAdd ($2,$1->cloneTree(true),new AstConst($2, AstConst::StringToParse(), "'b1"))); } - | fexprLvalue yP_MINUSMINUS { $$ = new AstAssign($2,$1,new AstSub ($2,$1->cloneTree(true),new AstConst($2, AstConst::StringToParse(), "'b1"))); } - | yP_PLUSPLUS fexprLvalue { $$ = new AstAssign($1,$2,new AstAdd ($1,$2->cloneTree(true),new AstConst($1, AstConst::StringToParse(), "'b1"))); } - | yP_MINUSMINUS fexprLvalue { $$ = new AstAssign($1,$2,new AstSub ($1,$2->cloneTree(true),new AstConst($1, AstConst::StringToParse(), "'b1"))); } - //UNSUP: Generic scopes in incrementes, remove above - //UNSUP BISONPRE_COPY(inc_or_dec_expression,{s/~l~/f/g}) // {copied} + BISONPRE_COPY(inc_or_dec_expression,{s/~l~/f/g}) // {copied} ; //UNSUPsinc_or_dec_expression: // IEEE: inc_or_dec_expression (for sequence_expression) @@ -3762,7 +3756,7 @@ expr: // IEEE: part of expression/constant_expression/primary | yP_XNOR ~r~expr %prec prREDUCTION { $$ = new AstRedXnor ($1,$2); } // // // IEEE: inc_or_dec_expression - //UNSUP ~l~inc_or_dec_expression { UNSUP } + | ~l~inc_or_dec_expression { $$=$1; $$ = $1; } // // // IEEE: '(' operator_assignment ')' // // Need exprScope of variable_lvalue to prevent conflict diff --git a/test_regress/t/t_array_index_increment.pl b/test_regress/t/t_array_index_increment.pl new file mode 100755 index 000000000..89a4e77d9 --- /dev/null +++ b/test_regress/t/t_array_index_increment.pl @@ -0,0 +1,20 @@ +#!/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. + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_array_index_increment.v b/test_regress/t/t_array_index_increment.v new file mode 100644 index 000000000..122227d93 --- /dev/null +++ b/test_regress/t/t_array_index_increment.v @@ -0,0 +1,114 @@ +module t (/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + string test_string = "abcd"; + + int array3d[2][3][4] = '{ + '{ + '{ 0, 1, 2, 3}, + '{ 4, 5, 6, 7}, + '{ 8, 9, 10, 11} + }, + '{ + '{ 12, 13, 14, 15}, + '{ 16, 17, 18, 19}, + '{ 20, 21, 22, 23} + } + }; + int pos; + int val; + int i; + byte b; + + int data[4] = '{1, 2, 3, 4}; + + generate + genvar j; + int gdata[4]; + for (j=0; j < 5; j++) begin + initial if (j >= 5) $stop; + end + + for (j=0; j < 5; ++j) begin + initial if (j >= 5) $stop; + end + + for (j=10; j >= 5; j--) begin + initial if (j < 5) $stop; + end + + for (j=10; j >= 5; --j) begin + initial if (j < 5) $stop; + end + endgenerate + + initial begin + pos = 0; + pos++; + if (pos != 1) $stop; + + array3d[0][0][0]++; + if (array3d[0][0][0] != 1) $stop; + + --array3d[0][0][0]; + if (array3d[0][0][0] != 0) $stop; + + pos = 2; + b = test_string[--pos]; + if (b !== "b") $stop; + if (pos !== 1) $stop; + + pos = 1; + b = test_string[++pos]; + if (b !== "c") $stop; + if (pos !== 2) $stop; + + pos = 3; + b = test_string[pos--]; + if (b !== "d") $stop; + if (pos !== 2) $stop; + + pos = 0; + b = test_string[pos++]; + if (b !== "a") $stop; + if (pos !== 1) $stop; + + pos = 0; + val = array3d[++pos][--pos][++pos]; + if (pos !== 1) $stop; + if (val !== 13) $stop; + + pos = 0; + val = array3d[++pos][pos--][++pos]; + if (pos !== 1) $stop; + if (val !== 17) $stop; + + for (i=0; data[++i]<4;) begin + // loop with multiple statements + pos = i; + val = data[i]; + end + + if (pos !== 2) $stop; + if (i !== 3) $stop; + if (val !== 3) $stop; + + i = 0; + while (data[i++]<4) begin + // loop with multiple statements + pos = i; + val = data[i]; + end + + if (pos !== 3) $stop; + if (i !== 4) $stop; + if (val !== 4) $stop; + + $write("*-* All Finished *-*\n"); + $finish; + + end +endmodule diff --git a/test_regress/t/t_increment_bad.out b/test_regress/t/t_increment_bad.out new file mode 100644 index 000000000..5664201ed --- /dev/null +++ b/test_regress/t/t_increment_bad.out @@ -0,0 +1,22 @@ +%Error: t/t_increment_bad.v:15:31: Unsupported: Incrementation in this context. + 15 | if (0 && test_string[pos++] != "e"); + | ^~ +%Error: t/t_increment_bad.v:16:19: Unsupported: Incrementation in this context. + 16 | if (1 || pos-- != 1); + | ^~ +%Error: t/t_increment_bad.v:18:17: Unsupported: Incrementation in this context. + 18 | if (a <-> --b); + | ^~ +%Error: t/t_increment_bad.v:19:16: Unsupported: Incrementation in this context. + 19 | if (0 -> ++b); + | ^~ +%Error: t/t_increment_bad.v:21:24: Unsupported: Incrementation in this context. + 21 | pos = (a > 0) ? a++ : --b; + | ^~ +%Error: t/t_increment_bad.v:21:29: Unsupported: Incrementation in this context. + 21 | pos = (a > 0) ? a++ : --b; + | ^~ +%Error: t/t_increment_bad.v:23:24: Unsupported: Incrementation in this context. + 23 | pos = array[0][0]++; + | ^~ +%Error: Exiting due to diff --git a/test_regress/t/t_increment_bad.pl b/test_regress/t/t_increment_bad.pl new file mode 100644 index 000000000..385b304e3 --- /dev/null +++ b/test_regress/t/t_increment_bad.pl @@ -0,0 +1,18 @@ +#!/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. + +scenarios(vlt => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_increment_bad.v b/test_regress/t/t_increment_bad.v new file mode 100644 index 000000000..7ce03d704 --- /dev/null +++ b/test_regress/t/t_increment_bad.v @@ -0,0 +1,25 @@ +module t (/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + int pos; + int a; + int b; + int array[2][2] = '{ '{0, 1}, '{2, 3}}; + + string test_string = "abcd"; + + initial begin + if (0 && test_string[pos++] != "e"); + if (1 || pos-- != 1); + + if (a <-> --b); + if (0 -> ++b); + + pos = (a > 0) ? a++ : --b; + + pos = array[0][0]++; + end +endmodule