forked from github/verilator
parent
81417a2889
commit
e81abdb616
@ -12,6 +12,7 @@ Conor McCullough
|
||||
Dan Petrisko
|
||||
David Horton
|
||||
David Stanford
|
||||
David Turner
|
||||
Driss Hafdi
|
||||
Edgar E. Iglesias
|
||||
Eric Rippey
|
||||
|
@ -1747,75 +1747,98 @@ QData VL_POWSS_QQW(int obits, int, int rbits, QData lhs, WDataInP rwp, bool lsig
|
||||
|
||||
// INTERNAL: Stuff LHS bit 0++ into OUTPUT at specified offset
|
||||
// ld may be "dirty", output is clean
|
||||
static inline void _VL_INSERT_II(int, CData& lhsr, IData ld, int hbit, int lbit) VL_PURE {
|
||||
static inline void _VL_INSERT_II(int, CData& lhsr, IData ld, int hbit, int lbit,
|
||||
int rbits) VL_PURE {
|
||||
IData cleanmask = VL_MASK_I(rbits);
|
||||
IData insmask = (VL_MASK_I(hbit - lbit + 1)) << lbit;
|
||||
lhsr = (lhsr & ~insmask) | ((ld << lbit) & insmask);
|
||||
lhsr = (lhsr & ~insmask) | ((ld << lbit) & (insmask & cleanmask));
|
||||
}
|
||||
static inline void _VL_INSERT_II(int, SData& lhsr, IData ld, int hbit, int lbit) VL_PURE {
|
||||
static inline void _VL_INSERT_II(int, SData& lhsr, IData ld, int hbit, int lbit,
|
||||
int rbits) VL_PURE {
|
||||
IData cleanmask = VL_MASK_I(rbits);
|
||||
IData insmask = (VL_MASK_I(hbit - lbit + 1)) << lbit;
|
||||
lhsr = (lhsr & ~insmask) | ((ld << lbit) & insmask);
|
||||
lhsr = (lhsr & ~insmask) | ((ld << lbit) & (insmask & cleanmask));
|
||||
}
|
||||
static inline void _VL_INSERT_II(int, IData& lhsr, IData ld, int hbit, int lbit) VL_PURE {
|
||||
static inline void _VL_INSERT_II(int, IData& lhsr, IData ld, int hbit, int lbit,
|
||||
int rbits) VL_PURE {
|
||||
IData cleanmask = VL_MASK_I(rbits);
|
||||
IData insmask = (VL_MASK_I(hbit - lbit + 1)) << lbit;
|
||||
lhsr = (lhsr & ~insmask) | ((ld << lbit) & insmask);
|
||||
lhsr = (lhsr & ~insmask) | ((ld << lbit) & (insmask & cleanmask));
|
||||
}
|
||||
static inline void _VL_INSERT_QQ(int, QData& lhsr, QData ld, int hbit, int lbit) VL_PURE {
|
||||
static inline void _VL_INSERT_QQ(int, QData& lhsr, QData ld, int hbit, int lbit,
|
||||
int rbits) VL_PURE {
|
||||
QData cleanmask = VL_MASK_Q(rbits);
|
||||
QData insmask = (VL_MASK_Q(hbit - lbit + 1)) << lbit;
|
||||
lhsr = (lhsr & ~insmask) | ((ld << lbit) & insmask);
|
||||
lhsr = (lhsr & ~insmask) | ((ld << lbit) & (insmask & cleanmask));
|
||||
}
|
||||
static inline void _VL_INSERT_WI(int, WDataOutP owp, IData ld, int hbit, int lbit) VL_MT_SAFE {
|
||||
static inline void _VL_INSERT_WI(int, WDataOutP owp, IData ld, int hbit, int lbit,
|
||||
int rbits = 0) VL_MT_SAFE {
|
||||
int hoffset = VL_BITBIT_E(hbit);
|
||||
int loffset = VL_BITBIT_E(lbit);
|
||||
if (hoffset == VL_SIZEBITS_E && loffset == 0) {
|
||||
// Fast and common case, word based insertion
|
||||
owp[VL_BITWORD_E(lbit)] = ld;
|
||||
} else {
|
||||
int roffset = VL_BITBIT_E(rbits);
|
||||
int hword = VL_BITWORD_E(hbit);
|
||||
int lword = VL_BITWORD_E(lbit);
|
||||
int rword = VL_BITWORD_E(rbits);
|
||||
EData cleanmask = hword == rword ? VL_MASK_E(roffset) : VL_MASK_E(0);
|
||||
|
||||
if (hoffset == VL_SIZEBITS_E && loffset == 0) {
|
||||
// Fast and common case, word based insertion
|
||||
owp[VL_BITWORD_E(lbit)] = ld & cleanmask;
|
||||
} else {
|
||||
EData lde = static_cast<EData>(ld);
|
||||
if (hword == lword) { // know < EData bits because above checks it
|
||||
// Assignment is contained within one word of destination
|
||||
EData insmask = (VL_MASK_E(hoffset - loffset + 1)) << loffset;
|
||||
owp[lword] = (owp[lword] & ~insmask) | ((lde << loffset) & insmask);
|
||||
owp[lword] = (owp[lword] & ~insmask) | ((lde << loffset) & (insmask & cleanmask));
|
||||
} else {
|
||||
// Assignment crosses a word boundary in destination
|
||||
EData hinsmask = (VL_MASK_E(hoffset - 0 + 1)) << 0;
|
||||
EData linsmask = (VL_MASK_E((VL_EDATASIZE - 1) - loffset + 1)) << loffset;
|
||||
int nbitsonright = VL_EDATASIZE - loffset; // bits that end up in lword
|
||||
owp[lword] = (owp[lword] & ~linsmask) | ((lde << loffset) & linsmask);
|
||||
owp[hword] = (owp[hword] & ~hinsmask) | ((lde >> nbitsonright) & hinsmask);
|
||||
owp[hword]
|
||||
= (owp[hword] & ~hinsmask) | ((lde >> nbitsonright) & (hinsmask & cleanmask));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// INTERNAL: Stuff large LHS bit 0++ into OUTPUT at specified offset
|
||||
// lwp may be "dirty"
|
||||
static inline void _VL_INSERT_WW(int, WDataOutP owp, WDataInP lwp, int hbit, int lbit) VL_MT_SAFE {
|
||||
int hoffset = hbit & VL_SIZEBITS_E;
|
||||
int loffset = lbit & VL_SIZEBITS_E;
|
||||
static inline void _VL_INSERT_WW(int, WDataOutP owp, WDataInP lwp, int hbit, int lbit,
|
||||
int rbits = 0) VL_MT_SAFE {
|
||||
int hoffset = VL_BITBIT_E(hbit);
|
||||
int loffset = VL_BITBIT_E(lbit);
|
||||
int roffset = VL_BITBIT_E(rbits);
|
||||
int lword = VL_BITWORD_E(lbit);
|
||||
int hword = VL_BITWORD_E(hbit);
|
||||
int rword = VL_BITWORD_E(rbits);
|
||||
int words = VL_WORDS_I(hbit - lbit + 1);
|
||||
// Cleaning mask, only applied to top word of the assignment. Is a no-op
|
||||
// if we don't assign to the top word of the destination.
|
||||
EData cleanmask = hword == rword ? VL_MASK_E(roffset) : VL_MASK_E(0);
|
||||
|
||||
if (hoffset == VL_SIZEBITS_E && loffset == 0) {
|
||||
// Fast and common case, word based insertion
|
||||
for (int i = 0; i < words; ++i) owp[lword + i] = lwp[i];
|
||||
for (int i = 0; i < (words - 1); ++i) owp[lword + i] = lwp[i];
|
||||
owp[hword] = lwp[words - 1] & cleanmask;
|
||||
} else if (loffset == 0) {
|
||||
// Non-32bit, but nicely aligned, so stuff all but the last word
|
||||
for (int i = 0; i < (words - 1); ++i) owp[lword + i] = lwp[i];
|
||||
// Know it's not a full word as above fast case handled it
|
||||
EData hinsmask = (VL_MASK_E(hoffset - 0 + 1));
|
||||
owp[lword + words - 1]
|
||||
= (owp[words + lword - 1] & ~hinsmask) | (lwp[words - 1] & hinsmask);
|
||||
owp[hword] = (owp[hword] & ~hinsmask) | (lwp[words - 1] & (hinsmask & cleanmask));
|
||||
} else {
|
||||
EData hinsmask = (VL_MASK_E(hoffset - 0 + 1)) << 0;
|
||||
EData linsmask = (VL_MASK_E((VL_EDATASIZE - 1) - loffset + 1)) << loffset;
|
||||
int nbitsonright = VL_EDATASIZE - loffset; // bits that end up in lword (know loffset!=0)
|
||||
// Middle words
|
||||
int hword = VL_BITWORD_E(hbit);
|
||||
for (int i = 0; i < words; ++i) {
|
||||
{ // Lower word
|
||||
int oword = lword + i;
|
||||
EData d = lwp[i] << loffset;
|
||||
EData od = (owp[oword] & ~linsmask) | (d & linsmask);
|
||||
if (oword == hword) {
|
||||
owp[oword] = (owp[oword] & ~hinsmask) | (od & hinsmask);
|
||||
owp[oword] = (owp[oword] & ~hinsmask) | (od & (hinsmask & cleanmask));
|
||||
} else {
|
||||
owp[oword] = od;
|
||||
}
|
||||
@ -1826,7 +1849,7 @@ static inline void _VL_INSERT_WW(int, WDataOutP owp, WDataInP lwp, int hbit, int
|
||||
EData d = lwp[i] >> nbitsonright;
|
||||
EData od = (d & ~linsmask) | (owp[oword] & linsmask);
|
||||
if (oword == hword) {
|
||||
owp[oword] = (owp[oword] & ~hinsmask) | (od & hinsmask);
|
||||
owp[oword] = (owp[oword] & ~hinsmask) | (od & (hinsmask & cleanmask));
|
||||
} else {
|
||||
owp[oword] = od;
|
||||
}
|
||||
@ -1836,11 +1859,11 @@ static inline void _VL_INSERT_WW(int, WDataOutP owp, WDataInP lwp, int hbit, int
|
||||
}
|
||||
}
|
||||
|
||||
static inline void _VL_INSERT_WQ(int obits, WDataOutP owp, QData ld, int hbit,
|
||||
int lbit) VL_MT_SAFE {
|
||||
static inline void _VL_INSERT_WQ(int obits, WDataOutP owp, QData ld, int hbit, int lbit,
|
||||
int rbits = 0) VL_MT_SAFE {
|
||||
WData lwp[VL_WQ_WORDS_E];
|
||||
VL_SET_WQ(lwp, ld);
|
||||
_VL_INSERT_WW(obits, owp, lwp, hbit, lbit);
|
||||
_VL_INSERT_WW(obits, owp, lwp, hbit, lbit, rbits);
|
||||
}
|
||||
|
||||
// EMIT_RULE: VL_REPLICATE: oclean=clean>width32, dirty<=width32; lclean=clean; rclean==clean;
|
||||
@ -2468,34 +2491,43 @@ static inline WDataOutP VL_RTOIROUND_W_D(int obits, WDataOutP owp, double lhs) V
|
||||
// Range assignments
|
||||
|
||||
// EMIT_RULE: VL_ASSIGNRANGE: rclean=dirty;
|
||||
static inline void VL_ASSIGNSEL_IIII(int obits, int lsb, CData& lhsr, IData rhs) VL_PURE {
|
||||
_VL_INSERT_II(obits, lhsr, rhs, lsb + obits - 1, lsb);
|
||||
static inline void VL_ASSIGNSEL_IIII(int rbits, int obits, int lsb, CData& lhsr,
|
||||
IData rhs) VL_PURE {
|
||||
_VL_INSERT_II(obits, lhsr, rhs, lsb + obits - 1, lsb, rbits);
|
||||
}
|
||||
static inline void VL_ASSIGNSEL_IIII(int obits, int lsb, SData& lhsr, IData rhs) VL_PURE {
|
||||
_VL_INSERT_II(obits, lhsr, rhs, lsb + obits - 1, lsb);
|
||||
static inline void VL_ASSIGNSEL_IIII(int rbits, int obits, int lsb, SData& lhsr,
|
||||
IData rhs) VL_PURE {
|
||||
_VL_INSERT_II(obits, lhsr, rhs, lsb + obits - 1, lsb, rbits);
|
||||
}
|
||||
static inline void VL_ASSIGNSEL_IIII(int obits, int lsb, IData& lhsr, IData rhs) VL_PURE {
|
||||
_VL_INSERT_II(obits, lhsr, rhs, lsb + obits - 1, lsb);
|
||||
static inline void VL_ASSIGNSEL_IIII(int rbits, int obits, int lsb, IData& lhsr,
|
||||
IData rhs) VL_PURE {
|
||||
_VL_INSERT_II(obits, lhsr, rhs, lsb + obits - 1, lsb, rbits);
|
||||
}
|
||||
static inline void VL_ASSIGNSEL_QIII(int obits, int lsb, QData& lhsr, IData rhs) VL_PURE {
|
||||
_VL_INSERT_QQ(obits, lhsr, rhs, lsb + obits - 1, lsb);
|
||||
static inline void VL_ASSIGNSEL_QIII(int rbits, int obits, int lsb, QData& lhsr,
|
||||
IData rhs) VL_PURE {
|
||||
_VL_INSERT_QQ(obits, lhsr, rhs, lsb + obits - 1, lsb, rbits);
|
||||
}
|
||||
static inline void VL_ASSIGNSEL_QQII(int obits, int lsb, QData& lhsr, QData rhs) VL_PURE {
|
||||
_VL_INSERT_QQ(obits, lhsr, rhs, lsb + obits - 1, lsb);
|
||||
static inline void VL_ASSIGNSEL_QQII(int rbits, int obits, int lsb, QData& lhsr,
|
||||
QData rhs) VL_PURE {
|
||||
_VL_INSERT_QQ(obits, lhsr, rhs, lsb + obits - 1, lsb, rbits);
|
||||
}
|
||||
static inline void VL_ASSIGNSEL_QIIQ(int obits, int lsb, QData& lhsr, QData rhs) VL_PURE {
|
||||
_VL_INSERT_QQ(obits, lhsr, rhs, lsb + obits - 1, lsb);
|
||||
static inline void VL_ASSIGNSEL_QIIQ(int rbits, int obits, int lsb, QData& lhsr,
|
||||
QData rhs) VL_PURE {
|
||||
_VL_INSERT_QQ(obits, lhsr, rhs, lsb + obits - 1, lsb, rbits);
|
||||
}
|
||||
// static inline void VL_ASSIGNSEL_IIIW(int obits, int lsb, IData& lhsr, WDataInP rwp) VL_MT_SAFE {
|
||||
// Illegal, as lhs width >= rhs width
|
||||
static inline void VL_ASSIGNSEL_WIII(int obits, int lsb, WDataOutP owp, IData rhs) VL_MT_SAFE {
|
||||
_VL_INSERT_WI(obits, owp, rhs, lsb + obits - 1, lsb);
|
||||
static inline void VL_ASSIGNSEL_WIII(int rbits, int obits, int lsb, WDataOutP owp,
|
||||
IData rhs) VL_MT_SAFE {
|
||||
_VL_INSERT_WI(obits, owp, rhs, lsb + obits - 1, lsb, rbits);
|
||||
}
|
||||
static inline void VL_ASSIGNSEL_WIIQ(int obits, int lsb, WDataOutP owp, QData rhs) VL_MT_SAFE {
|
||||
_VL_INSERT_WQ(obits, owp, rhs, lsb + obits - 1, lsb);
|
||||
static inline void VL_ASSIGNSEL_WIIQ(int rbits, int obits, int lsb, WDataOutP owp,
|
||||
QData rhs) VL_MT_SAFE {
|
||||
_VL_INSERT_WQ(obits, owp, rhs, lsb + obits - 1, lsb, rbits);
|
||||
}
|
||||
static inline void VL_ASSIGNSEL_WIIW(int obits, int lsb, WDataOutP owp, WDataInP rwp) VL_MT_SAFE {
|
||||
_VL_INSERT_WW(obits, owp, rwp, lsb + obits - 1, lsb);
|
||||
static inline void VL_ASSIGNSEL_WIIW(int rbits, int obits, int lsb, WDataOutP owp,
|
||||
WDataInP rwp) VL_MT_SAFE {
|
||||
_VL_INSERT_WW(obits, owp, rwp, lsb + obits - 1, lsb, rbits);
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
|
@ -306,6 +306,7 @@ public:
|
||||
puts("II");
|
||||
emitIQW(nodep->rhsp());
|
||||
puts("(");
|
||||
puts(cvtToStr(selp->fromp()->widthMin()) + ",");
|
||||
puts(cvtToStr(nodep->widthMin()) + ",");
|
||||
iterateAndNextNull(selp->lsbp());
|
||||
puts(", ");
|
||||
|
@ -488,9 +488,21 @@ private:
|
||||
maskold.edataWord(w)),
|
||||
oldvalp);
|
||||
}
|
||||
addWordAssign(nodep, w, destp,
|
||||
new AstOr(lhsp->fileline(), oldvalp,
|
||||
newWordGrabShift(lhsp->fileline(), w, rhsp, lsb)));
|
||||
|
||||
// Appropriate word of new value to insert:
|
||||
AstNode* newp = newWordGrabShift(lhsp->fileline(), w, rhsp, lsb);
|
||||
|
||||
// Apply cleaning at the top word of the destination
|
||||
// (no cleaning to do if dst's width is a whole number
|
||||
// of words).
|
||||
if (w == destp->widthWords() - 1 && VL_BITBIT_E(destp->widthMin()) != 0) {
|
||||
V3Number cleanmask(nodep, VL_EDATASIZE);
|
||||
cleanmask.setMask(VL_BITBIT_E(destp->widthMin()));
|
||||
newp = new AstAnd(lhsp->fileline(), newp,
|
||||
new AstConst(lhsp->fileline(), cleanmask));
|
||||
}
|
||||
|
||||
addWordAssign(nodep, w, destp, new AstOr(lhsp->fileline(), oldvalp, newp));
|
||||
}
|
||||
}
|
||||
VL_DO_DANGLING(rhsp->deleteTree(), rhsp);
|
||||
@ -506,15 +518,22 @@ private:
|
||||
oldvalp = new AstAnd(lhsp->fileline(), new AstConst(lhsp->fileline(), maskold),
|
||||
oldvalp);
|
||||
}
|
||||
AstNode* newp = new AstOr(lhsp->fileline(), oldvalp,
|
||||
new AstShiftL(lhsp->fileline(), rhsp,
|
||||
new AstConst(lhsp->fileline(), lsb),
|
||||
destp->width()));
|
||||
|
||||
// The bit-select can refer to bits outside the width of nodep
|
||||
// which we aren't allowed to assign to. This is a mask of the
|
||||
// valid range of nodep which we apply to the new shifted RHS.
|
||||
V3Number cleanmask(nodep, destp->widthMin());
|
||||
cleanmask.setMask(destp->widthMin());
|
||||
AstNode* shifted = new AstShiftL(
|
||||
lhsp->fileline(), rhsp, new AstConst(lhsp->fileline(), lsb), destp->width());
|
||||
AstNode* cleaned = new AstAnd(lhsp->fileline(), shifted,
|
||||
new AstConst(lhsp->fileline(), cleanmask));
|
||||
AstNode* newp = new AstOr(lhsp->fileline(), oldvalp, cleaned);
|
||||
newp = new AstAssign(nodep->fileline(), destp, newp);
|
||||
insertBefore(nodep, newp);
|
||||
}
|
||||
return true;
|
||||
} else { // non-const RHS
|
||||
} else { // non-const select offset
|
||||
if (destwide && lhsp->widthConst() == 1) {
|
||||
UINFO(8, " ASSIGNSEL(varlsb,wide,1bit) " << nodep << endl);
|
||||
AstNode* rhsp = nodep->rhsp()->unlinkFrBack();
|
||||
@ -579,11 +598,21 @@ private:
|
||||
lhsp->lsbp()->cloneTree(true), destp->width())),
|
||||
oldvalp);
|
||||
}
|
||||
AstNode* newp
|
||||
= new AstOr(lhsp->fileline(), oldvalp,
|
||||
new AstShiftL(lhsp->fileline(), rhsp,
|
||||
lhsp->lsbp()->cloneTree(true), destp->width()));
|
||||
newp = new AstAssign(nodep->fileline(), destp, newp);
|
||||
AstNode* newp = new AstShiftL(lhsp->fileline(), rhsp,
|
||||
lhsp->lsbp()->cloneTree(true), destp->width());
|
||||
// Apply cleaning to the new value being inserted. Mask is
|
||||
// slightly wider than necessary to avoid an AND with all ones
|
||||
// being optimized out. No need to clean if destp is
|
||||
// quad-sized as there are no extra bits to contaminate
|
||||
if (destp->widthMin() != 64) {
|
||||
V3Number cleanmask(nodep, destp->widthMin() + 1);
|
||||
cleanmask.setMask(destp->widthMin());
|
||||
newp = new AstAnd(lhsp->fileline(), newp,
|
||||
new AstConst(lhsp->fileline(), cleanmask));
|
||||
}
|
||||
|
||||
newp = new AstAssign(nodep->fileline(), destp,
|
||||
new AstOr(lhsp->fileline(), oldvalp, newp));
|
||||
// newp->dumpTree(cout, "- new: ");
|
||||
insertBefore(nodep, newp);
|
||||
return true;
|
||||
|
21
test_regress/t/t_assign_slice_overflow.pl
Executable file
21
test_regress/t/t_assign_slice_overflow.pl
Executable file
@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2021 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;
|
179
test_regress/t/t_assign_slice_overflow.v
Normal file
179
test_regress/t/t_assign_slice_overflow.v
Normal file
@ -0,0 +1,179 @@
|
||||
// DESCRIPTION: Test that slice assignment overflows are handled correctly,
|
||||
// i.e. that if you assign to a slice such that some of the bits you assign to
|
||||
// do not actually exist, that those bits get correctly discarded.
|
||||
// Issue #2803 existed in a number number of different codepaths in
|
||||
// verilated.h and V3Expand.cpp. This test should cover all of these cases
|
||||
// when run both with and without the -Ox flag to verilator.
|
||||
// - Select offset constant, insert IData into CData
|
||||
// - Select offset constant, insert IData into SData
|
||||
// - Select offset constant, insert IData into IData
|
||||
// - Select offset constant, insert QData into QData
|
||||
// - Select offset constant, insert IData into WData within a word
|
||||
// - Select offset constant, insert IData into WData crossing a word boundary
|
||||
// - Select offset constant, insert IData into WData whole word insertion
|
||||
// - Select offset constant, insert QData into WData
|
||||
// - Select offset constant, insert WData into WData, several whole words
|
||||
// - Select offset constant, insert WData into WData, starting at word-offset
|
||||
// - Select offset constant, insert WData into WData, all other cases
|
||||
// - Select offset is non-constant, destination is wide, bit-select width == 1
|
||||
// - Select offset is non-constant, destination is wide, bit-select width != 1
|
||||
// - Select offset is non-constant, destination is narrow
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2021 by David Turner.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module t(/*AUTOARG*/
|
||||
// Inputs
|
||||
clk
|
||||
);
|
||||
input clk;
|
||||
|
||||
integer cyc=0;
|
||||
// Non-constant offsets
|
||||
reg varoffset1;
|
||||
reg [6:0] varoffset2;
|
||||
reg [6:0] varoffset3;
|
||||
|
||||
// Destinations for variable-offset assignments
|
||||
reg [69:0] dstwide1;
|
||||
reg [69:0] dstwide2;
|
||||
reg [1:0] dstnarrow;
|
||||
|
||||
// Constant offsets
|
||||
reg [6:0] constoffset;
|
||||
|
||||
// Destinations for constant-offset assignments
|
||||
reg [2:0] dst_cdata;
|
||||
reg [11:0] dst_sdata;
|
||||
reg [29:0] dst_idata;
|
||||
reg [59:0] dst_qdata;
|
||||
reg [69:0] dst_wdata1; // assign idata within word
|
||||
reg [69:0] dst_wdata2; // assign idata crossing word boundary
|
||||
reg [69:0] dst_wdata3; // assign idata corresponding to whole word
|
||||
reg [69:0] dst_wdata4; // assign qdata
|
||||
reg [69:0] dst_wdata5; // assign wdata corresponding to several whole words
|
||||
reg [69:0] dst_wdata6; // assign wdata starting at word-offset
|
||||
reg [69:0] dst_wdata7; // assign wdata unaligned
|
||||
|
||||
always @(*) begin
|
||||
// Non-constant select offset, destination narrow
|
||||
dstnarrow = 2'd0;
|
||||
dstnarrow[varoffset1 +: 2'd2] = 2'd2;
|
||||
|
||||
// Non-constant select offset, destination wide, width == 1
|
||||
dstwide1 = 70'd0;
|
||||
dstwide1[varoffset2 +: 1'd1] = 1'd1;
|
||||
|
||||
// Non-constant select offset, destination wide, width != 1
|
||||
dstwide2 = 70'd0;
|
||||
dstwide2[varoffset3 +: 2'd2] = 2'd2;
|
||||
|
||||
// Constant offset, IData into CData
|
||||
constoffset = 7'd2;
|
||||
dst_cdata = 3'd0;
|
||||
dst_cdata[constoffset[0 +: 2] +: 3'd3] = 3'd6;
|
||||
|
||||
// Constant offset, IData into SData
|
||||
constoffset = 7'd11;
|
||||
dst_sdata = 12'd0;
|
||||
dst_sdata[constoffset[0 +: 4] +: 2'd2] = 2'd2;
|
||||
|
||||
// Constant offset, IData into IData
|
||||
constoffset = 7'd29;
|
||||
dst_idata = 30'd0;
|
||||
dst_idata[constoffset[0 +: 5] +: 2'd2] = 2'd2;
|
||||
|
||||
// Constant offset, QData into QData
|
||||
constoffset = 7'd59;
|
||||
dst_qdata = 60'd0;
|
||||
dst_qdata[constoffset[0 +: 6] +: 2'd2] = 2'd2;
|
||||
|
||||
// Constant offset, IData into WData within word
|
||||
constoffset = 7'd69;
|
||||
dst_wdata1 = 70'd0;
|
||||
dst_wdata1[constoffset +: 2'd2] = 2'd2;
|
||||
|
||||
// Constant offset, IData into WData crossing word boundary
|
||||
constoffset = 7'd61;
|
||||
dst_wdata2 = 70'd0;
|
||||
dst_wdata2[constoffset +: 4'd10] = 10'd1 << 4'd9;
|
||||
|
||||
// Constant offset, IData into WData replacing a whole word
|
||||
constoffset = 7'd64;
|
||||
dst_wdata3 = 70'd0;
|
||||
dst_wdata3[constoffset +: 6'd32] = 32'd1 << 3'd6;
|
||||
|
||||
// Constant offset, QData into WData
|
||||
constoffset = 7'd31;
|
||||
dst_wdata4 = 70'd0;
|
||||
dst_wdata4[constoffset +: 7'd40] = 40'd1 << 7'd39;
|
||||
|
||||
// Constant offset, WData into WData replacing whole words
|
||||
constoffset = 7'd32;
|
||||
dst_wdata5 = 70'd0;
|
||||
dst_wdata5[constoffset +: 7'd64] = 64'd1 << 7'd38;
|
||||
|
||||
// Constant offset, WData into WData offset word aligned
|
||||
constoffset = 7'd32;
|
||||
dst_wdata6 = 70'd0;
|
||||
dst_wdata6[constoffset +: 7'd40] = 40'd1 << 7'd38;
|
||||
|
||||
// Constant offset, WData into WData unaligned
|
||||
constoffset = 7'd1;
|
||||
dst_wdata7 = 70'd0;
|
||||
dst_wdata7[constoffset +: 7'd70] = 70'd1 << 7'd69;
|
||||
end
|
||||
|
||||
// Test loop
|
||||
always @ (posedge clk) begin
|
||||
// State machine to avoid verilator constant-folding offset
|
||||
if (cyc == 0) begin
|
||||
// Initialisation
|
||||
varoffset1 <= 1'd0;
|
||||
varoffset2 <= 7'd0;
|
||||
varoffset3 <= 7'd0;
|
||||
end else if (cyc == 1) begin
|
||||
// Variable offsets set here to avoid verilator constant folding
|
||||
varoffset1 <= 1'd1;
|
||||
varoffset2 <= 7'd70;
|
||||
varoffset3 <= 7'd69;
|
||||
end else if (cyc == 2) begin
|
||||
// Check all destinations are 0
|
||||
$write("dstwide1 = %23d, downshifted = %23d\n", dstwide1, dstwide1 >> 1);
|
||||
$write("dstwide2 = %23d, downshifted = %23d\n", dstwide2, dstwide2 >> 1);
|
||||
$write("dstnarrow = %23d, downshifted = %23d\n", dstnarrow, dstnarrow >> 1);
|
||||
$write("dst_cdata = %23d, downshifted = %23d\n", dst_cdata, dst_cdata >> 1);
|
||||
$write("dst_sdata = %23d, downshifted = %23d\n", dst_sdata, dst_sdata >> 1);
|
||||
$write("dst_idata = %23d, downshifted = %23d\n", dst_idata, dst_idata >> 1);
|
||||
$write("dst_qdata = %23d, downshifted = %23d\n", dst_qdata, dst_qdata >> 1);
|
||||
$write("dst_wdata1 = %23d, downshifted = %23d\n", dst_wdata1, dst_wdata1 >> 1);
|
||||
$write("dst_wdata2 = %23d, downshifted = %23d\n", dst_wdata2, dst_wdata2 >> 1);
|
||||
$write("dst_wdata3 = %23d, downshifted = %23d\n", dst_wdata3, dst_wdata3 >> 1);
|
||||
$write("dst_wdata4 = %23d, downshifted = %23d\n", dst_wdata4, dst_wdata4 >> 1);
|
||||
$write("dst_wdata5 = %23d, downshifted = %23d\n", dst_wdata5, dst_wdata5 >> 1);
|
||||
$write("dst_wdata6 = %23d, downshifted = %23d\n", dst_wdata6, dst_wdata6 >> 1);
|
||||
$write("dst_wdata7 = %23d, downshifted = %23d\n", dst_wdata7, dst_wdata7 >> 1);
|
||||
|
||||
if (dstwide1 !== 70'd0 || (dstwide1 >> 1) !== 70'd0) $stop;
|
||||
if (dstwide2 !== 70'd0 || (dstwide2 >> 1) !== 70'd0) $stop;
|
||||
if (dstnarrow !== 2'd0 || (dstnarrow >> 1) !== 2'd0) $stop;
|
||||
if (dst_cdata !== 3'd0 || (dst_cdata >> 1) !== 3'd0) $stop;
|
||||
if (dst_sdata !== 12'd0 || (dst_sdata >> 1) !== 12'd0) $stop;
|
||||
if (dst_idata !== 30'd0 || (dst_idata >> 1) !== 30'd0) $stop;
|
||||
if (dst_qdata !== 60'd0 || (dst_qdata >> 1) !== 60'd0) $stop;
|
||||
if (dst_wdata1 !== 70'd0 || (dst_wdata1 >> 1) !== 70'd0) $stop;
|
||||
if (dst_wdata2 !== 70'd0 || (dst_wdata2 >> 1) !== 70'd0) $stop;
|
||||
if (dst_wdata3 !== 70'd0 || (dst_wdata3 >> 1) !== 70'd0) $stop;
|
||||
if (dst_wdata4 !== 70'd0 || (dst_wdata4 >> 1) !== 70'd0) $stop;
|
||||
if (dst_wdata5 !== 70'd0 || (dst_wdata5 >> 1) !== 70'd0) $stop;
|
||||
if (dst_wdata6 !== 70'd0 || (dst_wdata6 >> 1) !== 70'd0) $stop;
|
||||
if (dst_wdata7 !== 70'd0 || (dst_wdata7 >> 1) !== 70'd0) $stop;
|
||||
end else begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
cyc <= cyc + 1;
|
||||
end
|
||||
endmodule
|
24
test_regress/t/t_assign_slice_overflow_ox.pl
Executable file
24
test_regress/t/t_assign_slice_overflow_ox.pl
Executable file
@ -0,0 +1,24 @@
|
||||
#!/usr/bin/env perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2021 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);
|
||||
|
||||
top_filename("t_assign_slice_overflow.v");
|
||||
|
||||
compile(
|
||||
verilator_flags2 => ["-Ox"],
|
||||
);
|
||||
|
||||
execute(
|
||||
check_finished => 1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
Loading…
Reference in New Issue
Block a user