Support pre/postifx incrementation/decrementation in array index (#2223)

This commit is contained in:
Maciej Sobkowski 2020-05-29 00:08:15 +02:00 committed by GitHub
parent c4aab57c62
commit 9d48ff7745
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 617 additions and 16 deletions

View File

@ -52,6 +52,7 @@ Stephen Henry
Tim Snyder
Tobias Rosenkranz
Tobias Wölfel
Tomasz Gorochowik
Todd Strader
Tymoteusz Blazejczyk
Vassilis Papaefstathiou

View File

@ -211,6 +211,7 @@ RAW_OBJS = \
V3LinkCells.o \
V3LinkDot.o \
V3LinkJump.o \
V3LinkInc.o \
V3LinkLValue.o \
V3LinkLevel.o \
V3LinkParse.o \

View File

@ -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)

248
src/V3LinkInc.cpp Normal file
View File

@ -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 <algorithm>
#include <cstdarg>
#include <vector>
//######################################################################
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);
}

36
src/V3LinkInc.h Normal file
View File

@ -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

View File

@ -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 {

View File

@ -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");

View File

@ -2929,23 +2929,17 @@ foperator_assignment<nodep>: // IEEE: operator_assignment (for first part of exp
//UNSUP BISONPRE_COPY(operator_assignment,{s/~f~/f/g}) // {copied}
;
//UNSUPinc_or_dec_expression<nodep>: // ==IEEE: inc_or_dec_expression
//UNSUP // // Need fexprScope instead of variable_lvalue to prevent conflict
//UNSUP ~l~exprScope yP_PLUSPLUS { $<fl>$=$<fl>1; $$ = $1+$2; }
//UNSUP | ~l~exprScope yP_MINUSMINUS { $<fl>$=$<fl>1; $$ = $1+$2; }
//UNSUP // // Need expr instead of variable_lvalue to prevent conflict
//UNSUP | yP_PLUSPLUS expr { $<fl>$=$<fl>1; $$ = $1+$2; }
//UNSUP | yP_MINUSMINUS expr { $<fl>$=$<fl>1; $$ = $1+$2; }
//UNSUP ;
inc_or_dec_expression<nodep>: // ==IEEE: inc_or_dec_expression
// // Need fexprScope instead of variable_lvalue to prevent conflict
~l~exprScope yP_PLUSPLUS { $<fl>$=$<fl>1; $$ = new AstPostAdd($2, new AstConst($2, AstConst::StringToParse(), "'b1"), $1, $1->cloneTree(true)); }
| ~l~exprScope yP_MINUSMINUS { $<fl>$=$<fl>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 { $<fl>$=$<fl>1; $$ = new AstPreAdd($1, new AstConst($1, AstConst::StringToParse(), "'b1"), $2, $2->cloneTree(true)); }
| yP_MINUSMINUS expr { $<fl>$=$<fl>1; $$ = new AstPreSub($1, new AstConst($1, AstConst::StringToParse(), "'b1"), $2, $2->cloneTree(true)); }
;
finc_or_dec_expression<nodep>: // ==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<nodep>: // IEEE: inc_or_dec_expression (for sequence_expression)
@ -3762,7 +3756,7 @@ expr<nodep>: // 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 { $<fl>$=$<fl>1; $$ = $1; }
//
// // IEEE: '(' operator_assignment ')'
// // Need exprScope of variable_lvalue to prevent conflict

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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