diff --git a/Changes b/Changes index 484c74fd1..81ffcd1bd 100644 --- a/Changes +++ b/Changes @@ -19,6 +19,8 @@ The contributors that suggested a given feature are shown in []. Thanks! **** Support left justified $display, #2101. [Pieter Kapsenberg] +**** Support string character access via indexing. + **** Add parameter values in XML. #2110. [Pieter Kapsenberg] **** Add loc column location in XML (replaces fl), #2122. [Pieter Kapsenberg] diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 31ff34e37..37947da07 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -6188,6 +6188,29 @@ public: virtual bool sizeMattersRhs() const { return false; } }; +class AstGetcRefN : public AstNodeBiop { + // Verilog string[#] on the left-hand-side of assignment + // Spec says is of type byte (not string of single character) +public: + AstGetcRefN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER(fl, lhsp, rhsp) { dtypeSetBitSized(8, AstNumeric::UNSIGNED); } + ASTNODE_NODE_FUNCS(GetcRefN) + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstGetcRefN(this->fileline(), lhsp, rhsp); + } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + V3ERROR_NA; + } + virtual string emitVerilog() { return "%k%l[%r]"; } + virtual string emitC() { V3ERROR_NA; } + virtual string emitSimpleOperator() { return ""; } + virtual bool cleanOut() const { return true; } + virtual bool cleanLhs() const { return true; } + virtual bool cleanRhs() const { return true; } + virtual bool sizeMattersLhs() const { return false; } + virtual bool sizeMattersRhs() const { return false; } +}; + class AstSubstrN : public AstNodeTriop { // Verilog string.substr() public: diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index 4d34f891e..4986c4a45 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -229,6 +229,14 @@ public: iterateAndNextNull(selp->lsbp()); puts(", "); iterateAndNextNull(selp->fromp()); puts(", "); } + } else if (AstGetcRefN* selp = VN_CAST(nodep->lhsp(), GetcRefN)) { + iterateAndNextNull(selp->lhsp()); + puts(" = "); + putbs("VL_PUTC_N("); + iterateAndNextNull(selp->lhsp()); + puts(", "); + iterateAndNextNull(selp->rhsp()); + puts(", "); } else if (AstVar* varp = AstVar::scVarRecurse(nodep->lhsp())) { putbs("VL_ASSIGN_"); // Set a systemC variable emitScIQW(varp); diff --git a/src/V3EmitCInlines.cpp b/src/V3EmitCInlines.cpp index 47a268840..0090b880a 100644 --- a/src/V3EmitCInlines.cpp +++ b/src/V3EmitCInlines.cpp @@ -74,6 +74,10 @@ class EmitCInlines : EmitCBaseVisitor { v3Global.needHeavy(true); iterateChildren(nodep); } + virtual void visit(AstGetcRefN* nodep) VL_OVERRIDE { + v3Global.needHeavy(true); + iterateChildren(nodep); + } virtual void visit(AstSubstrN* nodep) VL_OVERRIDE { v3Global.needHeavy(true); iterateChildren(nodep); diff --git a/src/V3Width.cpp b/src/V3Width.cpp index bb8602c57..54b57fd1b 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -355,6 +355,16 @@ private: nodep->dtypeSetBitSized(8, AstNumeric::UNSIGNED); } } + virtual void visit(AstGetcRefN* nodep) VL_OVERRIDE { + // CALLER: str.getc() + UASSERT_OBJ(nodep->rhsp(), nodep, "For binary ops only!"); + if (m_vup && m_vup->prelim()) { + // See similar handling in visit_cmp_eq_gt where created + iterateCheckString(nodep, "LHS", nodep->lhsp(), BOTH); + iterateCheckSigned32(nodep, "RHS", nodep->rhsp(), BOTH); + nodep->dtypeSetBitSized(8, AstNumeric::UNSIGNED); + } + } virtual void visit(AstSubstrN* nodep) VL_OVERRIDE { // CALLER: str.substr() UASSERT_OBJ(nodep->rhsp() && nodep->thsp(), nodep, "For ternary ops only!"); diff --git a/src/V3WidthSel.cpp b/src/V3WidthSel.cpp index de74c01b7..d6e866185 100644 --- a/src/V3WidthSel.cpp +++ b/src/V3WidthSel.cpp @@ -99,7 +99,8 @@ private: fromRange = adtypep->declRange(); } else if (AstBasicDType* adtypep = VN_CAST(ddtypep, BasicDType)) { - if (adtypep->isRanged()) { + if (adtypep->isString() && VN_IS(nodep, SelBit)) { + } else if (adtypep->isRanged()) { UASSERT_OBJ(!(adtypep->rangep() && (!VN_IS(adtypep->rangep()->msbp(), Const) || !VN_IS(adtypep->rangep()->lsbp(), Const))), @@ -268,7 +269,20 @@ private: if (debug()>=9) newp->dumpTree(cout, "--SELBTq: "); nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); } - else if (VN_IS(ddtypep, BasicDType)) { + else if (VN_IS(ddtypep, BasicDType) && ddtypep->isString()) { + // SELBIT(string, index) -> GETC(string, index) + AstNodeVarRef* varrefp = VN_CAST(fromp, NodeVarRef); + if (!varrefp) nodep->v3error("Unsupported: String array operation on non-variable"); + AstNode* newp; + if (varrefp && varrefp->lvalue()) { + newp = new AstGetcRefN(nodep->fileline(), fromp, rhsp); + } else { + newp = new AstGetcN(nodep->fileline(), fromp, rhsp); + } + UINFO(6, " new " << newp << endl); + nodep->replaceWith(newp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + } else if (VN_IS(ddtypep, BasicDType)) { // SELBIT(range, index) -> SEL(array, index, 1) AstSel* newp = new AstSel(nodep->fileline(), fromp, diff --git a/test_regress/t/t_string.v b/test_regress/t/t_string.v index 3dbd39130..e06cb2a2e 100644 --- a/test_regress/t/t_string.v +++ b/test_regress/t/t_string.v @@ -4,7 +4,7 @@ // without warranty, 2014 by Wilson Snyder. `define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0); -`define checks(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=\"%s\" exp=\"%s\"\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0); +`define checks(gotv,expv) do if ((gotv) != (expv)) begin $write("%%Error: %s:%0d: got=\"%s\" exp=\"%s\"\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0); module t (/*AUTOARG*/ // Inputs @@ -98,6 +98,19 @@ module t (/*AUTOARG*/ `checkh(s <= " ", 1'b0); `checkh(s <= "a", 1'b1); end + // String character references + else if (cyc==10) begin + s2 = "astring"; + end + else if (cyc==11) begin + `checks(s2, "astring"); + `checkh(s2.len(), 7); + `checkh(s2[1], "s"); + s2[0] = "0"; + s2[3] = "3"; + `checks(s2, "0st3ing"); + end + // else if (cyc==99) begin $write("*-* All Finished *-*\n"); $finish;