forked from github/verilator
Support string len() method.
This commit is contained in:
parent
6b6e8dc83e
commit
662ebece71
2
Changes
2
Changes
@ -6,6 +6,8 @@ The contributors that suggested a given feature are shown in []. Thanks!
|
||||
|
||||
**** Support > 64 bit decimal $display.
|
||||
|
||||
**** Support string len() method. [Victor Besyakov]
|
||||
|
||||
**** Fix modport outputs being treated as inputs, bug1246. [Jeff Bush]
|
||||
|
||||
**** Fix false ALWCOMBORDER on interface references, bug1247. [Josh Redford]
|
||||
|
@ -60,6 +60,8 @@ inline std::string VL_REPLICATEN_NNI(int obits,int lbits,int rbits, const std::s
|
||||
return VL_REPLICATEN_NNQ(obits,lbits,rbits,lhs,rep);
|
||||
}
|
||||
|
||||
inline IData VL_LEN_IN(const std::string& ld) { return ld.length(); }
|
||||
|
||||
extern IData VL_FOPEN_NI(const std::string& filename, IData mode) VL_MT_SAFE;
|
||||
extern void VL_READMEM_N(bool hex, int width, int depth, int array_lsb, int fnwords,
|
||||
const std::string& ofilename, void* memp, IData start, IData end) VL_MT_SAFE;
|
||||
|
@ -3545,6 +3545,18 @@ public:
|
||||
virtual int instrCount() const { return 1+V3Number::log2b(width()); }
|
||||
};
|
||||
|
||||
class AstLenN : public AstNodeUniop {
|
||||
// Length of a string
|
||||
public:
|
||||
AstLenN(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {
|
||||
dtypeSetSigned32(); }
|
||||
ASTNODE_NODE_FUNCS(LenN)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opLenN(lhs); }
|
||||
virtual string emitVerilog() { return "%f(%l)"; }
|
||||
virtual string emitC() { return "VL_LEN_IN(%li)"; }
|
||||
virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return true;}
|
||||
virtual bool sizeMattersLhs() {return false;}
|
||||
};
|
||||
class AstLogNot : public AstNodeUniop {
|
||||
public:
|
||||
AstLogNot(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {
|
||||
|
@ -1035,6 +1035,11 @@ V3Number& V3Number::opConcat (const V3Number& lhs, const V3Number& rhs) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
V3Number& V3Number::opLenN (const V3Number& lhs) {
|
||||
setQuad(lhs.toString().length());
|
||||
return *this;
|
||||
}
|
||||
|
||||
V3Number& V3Number::opRepl (const V3Number& lhs, const V3Number& rhs) { // rhs is # of times to replicate
|
||||
// Hopefully the using routine has a error check too.
|
||||
// See also error in V3Width
|
||||
|
@ -242,6 +242,7 @@ public:
|
||||
V3Number& opCLog2 (const V3Number& lhs);
|
||||
V3Number& opClean (const V3Number& lhs, uint32_t bits);
|
||||
V3Number& opConcat (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opLenN (const V3Number& lhs);
|
||||
V3Number& opRepl (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opRepl (const V3Number& lhs, uint32_t rhs);
|
||||
V3Number& opStreamL (const V3Number& lhs, const V3Number& rhs);
|
||||
|
@ -330,6 +330,9 @@ private:
|
||||
// Widths: Output integer unsigned, input real
|
||||
virtual void visit(AstRealToBits* nodep) { visit_Ou64_Lr(nodep); }
|
||||
|
||||
// Output integer, input string
|
||||
virtual void visit(AstLenN* nodep) { visit_Os32_string(nodep); }
|
||||
|
||||
// Widths: Constant, terminal
|
||||
virtual void visit(AstTime* nodep) { nodep->dtypeSetUInt64(); }
|
||||
virtual void visit(AstTimeD* nodep) { nodep->dtypeSetDouble(); }
|
||||
@ -1497,6 +1500,7 @@ private:
|
||||
// Find the fromp dtype - should be a class
|
||||
if (!nodep->fromp() || !nodep->fromp()->dtypep()) nodep->v3fatalSrc("Unsized expression");
|
||||
AstNodeDType* fromDtp = nodep->fromp()->dtypep()->skipRefToEnump();
|
||||
AstBasicDType* basicp = fromDtp ? fromDtp->basicp() : NULL;
|
||||
UINFO(9," from dt "<<fromDtp<<endl);
|
||||
if (AstEnumDType* adtypep = fromDtp->castEnumDType()) {
|
||||
// Method call on enum without following parenthesis, e.g. "ENUM.next"
|
||||
@ -1613,6 +1617,17 @@ private:
|
||||
nodep->v3error("Unknown built-in array method '"<<nodep->fromp()->prettyTypeName()<<"'");
|
||||
}
|
||||
}
|
||||
else if (basicp && basicp->isString()) {
|
||||
// Method call on string
|
||||
if (nodep->name() == "len") {
|
||||
// Constant value
|
||||
AstNode* newp = new AstLenN(nodep->fileline(), nodep->fromp()->unlinkFrBack());
|
||||
nodep->replaceWith(newp);
|
||||
pushDeletep(nodep); VL_DANGLING(nodep);
|
||||
} else {
|
||||
nodep->v3error("Unsupported: built-in string method '"<<nodep->fromp()->prettyTypeName()<<"'");
|
||||
}
|
||||
}
|
||||
else {
|
||||
nodep->v3error("Unsupported: Member call on non-enum object '"
|
||||
<<nodep->fromp()->prettyTypeName()<<"' which is a '"<<nodep->fromp()->dtypep()->prettyTypeName()<<"'");
|
||||
@ -2646,6 +2661,16 @@ private:
|
||||
nodep->dtypeSetLogicBool();
|
||||
}
|
||||
}
|
||||
void visit_Os32_string(AstNodeUniop* nodep) {
|
||||
// CALLER: LenN
|
||||
// Widths: 32 bit out
|
||||
if (!nodep->lhsp()) nodep->v3fatalSrc("For unary ops only!");
|
||||
if (m_vup->prelim()) {
|
||||
// See similar handling in visit_cmp_eq_gt where created
|
||||
iterateCheckString(nodep,"LHS",nodep->lhsp(),BOTH);
|
||||
nodep->dtypeSetSigned32();
|
||||
}
|
||||
}
|
||||
|
||||
void visit_negate_not(AstNodeUniop* nodep, bool real_ok) {
|
||||
// CALLER: (real_ok=false) Not
|
||||
|
18
test_regress/t/t_string_type_methods.pl
Executable file
18
test_regress/t/t_string_type_methods.pl
Executable 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.
|
||||
|
||||
compile (
|
||||
);
|
||||
|
||||
execute (
|
||||
check_finished=>1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
115
test_regress/t/t_string_type_methods.v
Normal file
115
test_regress/t/t_string_type_methods.v
Normal file
@ -0,0 +1,115 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// 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 checkg(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='%g' exp='%g'\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0);
|
||||
|
||||
module t (/*AUTOARG*/
|
||||
// Inputs
|
||||
clk
|
||||
);
|
||||
input clk;
|
||||
|
||||
string s;
|
||||
|
||||
integer cyc=0;
|
||||
|
||||
// Check constification
|
||||
initial begin
|
||||
s="1234"; `checkh(s.len(),4);
|
||||
`ifndef VERILATOR
|
||||
s="1234"; s.putc(2, "z"); `checks(s, "12z4");
|
||||
s="1234"; `checkh(s.getc(2), "3");
|
||||
s="abCD"; `checks(s.toupper(), "ABCD");
|
||||
s="abCD"; `checks(s.tolower(), "abcd");
|
||||
s="b"; if (s.compare("a") <= 0) $stop;
|
||||
s="b"; if (s.compare("b") != 0) $stop;
|
||||
s="b"; if (s.compare("c") >= 0) $stop;
|
||||
s="b"; if (s.icompare("A") < 0) $stop;
|
||||
s="b"; if (s.icompare("B") != 0) $stop;
|
||||
s="b"; if (s.icompare("C") >= 0) $stop;
|
||||
s="101"; `checkh(s.atoi(), 'd101);
|
||||
s="101"; `checkh(s.atohex(), 'h101);
|
||||
s="101"; `checkh(s.atooct(), 'o101);
|
||||
s="101"; `checkh(s.atobin(), 'b101);
|
||||
s="1.23"; `checkg(s.atoreal(), 1.23);
|
||||
s.itoa(123); `checks(s, "123");
|
||||
s.hextoa(123); `checks(s, "7b");
|
||||
s.octtoa(123); `checks(s, "173");
|
||||
s.bintoa(123); `checks(s, "1111011");
|
||||
s.realtoa(1.23); `checks(s, "1.23");
|
||||
`endif
|
||||
end
|
||||
|
||||
// Check runtime
|
||||
always @ (posedge clk) begin
|
||||
cyc <= cyc + 1;
|
||||
if (cyc==0) begin
|
||||
// Setup
|
||||
s = "1234";
|
||||
end
|
||||
else if (cyc==1) begin
|
||||
`checkh(s.len(),4);
|
||||
`ifndef VERILATOR
|
||||
s.putc(2, "z");
|
||||
end
|
||||
else if (cyc==2) begin
|
||||
`checks(s, "12z4");
|
||||
`checkh(s.getc(2), "z");
|
||||
s="abCD";
|
||||
end
|
||||
else if (cyc==3) begin
|
||||
`checks(s.toupper(), "ABCD");
|
||||
`checks(s.tolower(), "abcd");
|
||||
s="b";
|
||||
end
|
||||
else if (cyc==5) begin
|
||||
if (s.compare("a") <= 0) $stop;
|
||||
if (s.compare("b") != 0) $stop;
|
||||
if (s.compare("c") >= 0) $stop;
|
||||
if (s.icompare("A") < 0) $stop;
|
||||
if (s.icompare("B") != 0) $stop;
|
||||
if (s.icompare("C") >= 0) $stop;
|
||||
s="101";
|
||||
end
|
||||
else if (cyc==7) begin
|
||||
`checkh(s.atoi(), 'd101);
|
||||
`checkh(s.atohex(), 'h101);
|
||||
`checkh(s.atooct(), 'o101);
|
||||
`checkh(s.atobin(), 'b101);
|
||||
s="1.23";
|
||||
end
|
||||
else if (cyc==8) begin
|
||||
`checkg(s.atoreal(), 1.23);
|
||||
s.itoa(123);
|
||||
end
|
||||
else if (cyc==10) begin
|
||||
`checks(s, "123");
|
||||
s.hextoa(123);
|
||||
end
|
||||
else if (cyc==11) begin
|
||||
`checks(s, "7b");
|
||||
s.octtoa(123);
|
||||
end
|
||||
else if (cyc==12) begin
|
||||
`checks(s, "173");
|
||||
s.bintoa(123);
|
||||
end
|
||||
else if (cyc==13) begin
|
||||
`checks(s, "1111011");
|
||||
s.realtoa(1.23);
|
||||
end
|
||||
else if (cyc==14) begin
|
||||
`checks(s, "1.23");
|
||||
`endif
|
||||
end
|
||||
else if (cyc==99) begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
Loading…
Reference in New Issue
Block a user