module string_literal_test; initial begin $display("今日は天気がよいので\ 外で泳ぎましょう。"); $display("今日は天気がよいので\n\ 外で泳ぎましょう。"); end endmodule
***** Veritak SV Engine Version 0.423 Build Jul.7.2011 ***** 今日は天気がよいので外で泳ぎましょう。 今日は天気がよいので 外で泳ぎましょう。 ---------- シミュレーションを終了します。time=0ns
module string_literal_test; byte c = "A"; // assigns to c "A" integer c1 = "A"; bit [5:0][7:0] d="ABCD"; logic [2:0][7:0] e="ABCDE"; initial begin $display("c=%s",c); $display("c=%s",c1); $display("d=%s %x",d,d); $display("e=%s %x",e,e); end endmodule
***** Veritak SV Engine Version 0.423 Build Jul.7.2011 ***** c=A c= A d= ABCD 000041424344 e=CDE 434445 ---------- シミュレーションを終了します。time=0ns
module string_test; logic [8*14:1] stringvar; initial begin stringvar = "Hello world"; $display("%s is stored as %h", stringvar, stringvar); stringvar = {stringvar,"!!!"}; $display("%s is stored as %h", stringvar, stringvar); end endmodule
***** Veritak SV Engine Version 0.423 Build Jul.7.2011 ***** Hello world is stored as 00000048656c6c6f20776f726c64 Hello world!!! is stored as 48656c6c6f20776f726c64212121 ---------- シミュレーションを終了します。time=0ns
次のコードでは、結果は、等しくなりません。
module string_literal_concat; bit [8*10:1] s1, s2; initial begin s1 = "Hello"; s2 = " world!"; if ({s1,s2} == "Hello world!") $display("strings are equal"); else $display("strings are not equal because s1=%x s2=%x {s1,s2}=%x",s1,s2,{s1,s2}); end endmodule
***** Veritak SV Engine Version 0.423 Build Jul.7.2011 ***** strings are not equal because s1=000000000048656c6c6f s2=00000020776f726c6421 {s1,s2}=000000000048656c6c6f00000020776f726c6421 ---------- シミュレーションを終了します。time=0ns
これは、ゼロパッドしているが故です。bit 幅は、コンパイル時に決定され固定していることに起因する問題です。このような場合は、string変数を使うとよいでしょう。
4)ストリングリテラルの16進直接指定
バックスラッシュxYY (YYは、16進二桁)で直接ASCIIコードを指定できます
module string_literal_test; byte c = "A"; // assigns to c "A" byte c1 = "\x41"; bit [7:0][7:0] d="ABC\x00DEFG"; string s1; initial begin $display("c=%s",c); $display("c=%s",c1); $display("d=%x",d); s1=string'(d); $display("s1=%s",s1); end endmodule
***** Veritak SV Engine Version 0.423 Build Jul.7.2011 ***** c=A c=A d=4142430044454647 s1=ABCDEFG ---------- シミュレーションを終了します。time=0ns
string タイプ
1)stringは、regと違い、ゼロパッドされることはないので、直感的に自然な結果になります
module string_literal_concat; string s1, s2; initial begin s1 = "Hello"; s2 = " world!"; if ({s1,s2} == "Hello world!") $display("strings are equal %s",{s1,s2}); end endmodule
***** Veritak SV Engine Version 0.423 Build Jul.7.2011 *****
strings are equal Hello world!
---------- シミュレーションを終了します。time=0ns
2)string 代入前初期値は、""空(長さ0の)のストリング,0の書き込みは、常に無視されます。
言語の内部実装には、Cのchar* になっていると思います。(DPIでのインターフェース仕様からの類推) しかし、Cのポインタの生存管理は、言語内でクローズしており,ユーザは意識する必要はありません。
module string_literal_test; byte c = "A"; // assigns to c "A" byte c1 = "\x41"; bit [7:0][7:0] d="ABC\x00DEFG"; string s1; initial begin $display("c=%s",c); $display("c=%s",c1); $display("d=%x",d); s1=string'(d); $display("s1=%s",s1); end endmodule
3) string以外の変数->string変換では、キャストが必要です
ストリングリテラル -> string キャスト不要
string -> string キャスト不要
を除いて、キャストが必要となります。ストリングへのキャストは、string'( ) です。
ストリングへのキャスト操作は、次のようになります。
module cast_test; bit [7:0] a; byte b; shortint c; int d; integer e; longint f; shortreal g; real h; realtime i; time j; logic [131:0] l; string s="abcdefghijk"; initial begin a=s; $display("a=%s",a); b=s; $display("b=%s",b); c=s; $display("c=%s",c); d=s; $display("d=%s",d); e=s; $display("e=%s",e); f=s; $display("f=%s",f); j=s; $display("j=%s",j); l=s; $display("l=%s",l); // g=s;//Compile Error// h=s;//Compile Error// i=s;//Compile Error $display(""); s=string'(a); $display("s=%s",s); s=string'(b); $display("s=%s",s); s=string'(c); $display("s=%s",s); s=string'(d); $display("s=%s",s); s=string'(e); $display("s=%s",s); s=string'(f); $display("s=%s",s); s=string'(j); $display("s=%s",s); s=string'(l); $display("s=%s",s); end endmodule
***** Veritak SV Engine Version 0.423 Build Jul.7.2011 ***** a=k b=k c=jk d=hijk e=hijk f=defghijk j=defghijk l= abcdefghijk s=k s=k s=jk s=hijk s=hijk s=defghijk s=defghijk s=abcdefghijk ---------- シミュレーションを終了します。time=0ns
3) stringに関するオペレータ
使用可能なオペレータは、それほど多くありません。以下に限定されます。
オペレータ | 意味 |
Str1 == Str2 | 二つのstringが一致するなら1、一致しないなら0を返します。オペランドのどちらかがストリング変数ならば、比較は、ストリングタイプとして、行われます。どちらもストリングリテラルであるなら、reg variable変数同士の比較と同じように行われます。 |
Str1 != Str2 | 不一致のときに1、一致のとき0が返ります。 |
Str1 < Str2 Str1 <= Str2 Str1 > Str2 Str1 >= Str2 |
c言語のstrcmpに同じです。条件が成立して==のときは、0が返ります。==でない条件成立のときは、正数が返ります。 不成立のときは、負数が返ります。 正数、負数は、かならずしも+1、-1ではありません。 |
{Str1,Str2,...,Strn} | オペランドのどれかひとつでも、stringタイプなら stringに変換されて演算が行われます。 |
{multiplier{Str}} | multiplierが定数でないか、Strがstringタイプであるときは、stringに変換されて演算が行われます。 |
Str[index] | string は、内部的にインデクスが振られ0からNが振られています。(Nは、Str.len()-1) str[0]は、最初の文字、 str[N]は最後の文字になります。 |
Str.method(...) | string メンバー関数です。 |
module string_compare_and_concat_test; bit [7:0] a; byte b; shortint c; int d; integer e; longint f; shortreal g; real h; realtime i; time j; logic [131:0] l; string s="abcdefghijk"; initial begin a=s; if (a==s) $display("Equal %s %s",a,s); else $display("Not equal %s %s",a,s); if (a <s) $display("a<s"); else if (a<=s) $display("a<=s"); else if (a>s) $display("a>s"); else if (a>=s) $display("a>=s"); b=s; if (b==s)$display("Equal %s %s",b,s); else $display("Not equal %s %s",b,s); c=s; if (c==s)$display("Equal %s %s",c,s); else $display("Not equal %s %s",c,s); d=s; if (d==s)$display("Equal %s %s",d,s); else $display("Not equal %s %s",d,s); e=s; if (e==s)$display("Equal %s %s",e,s); else $display("Not equal %s %s",e,s); f=s; if (f==s)$display("Equal %s %s",f,s); else $display("Not equal %s %s",f,s); j=s; if (j==s)$display("Equal %s %s",j,s); else $display("Not equal %s %s",j,s); l=s; if (l==s)$display("Equal %s %s",l,s); else $display("Not equal %s %s",l,s); if (l <s) $display("l<s"); else if (l<=s) $display("l<=s"); else if (l>s) $display("l>s"); else if (l>=s) $display("l>=s"); s="AB"; $display("{s,a}=%s",{s,a}); $display("{s,b}=%s",{s,b}); $display("{s,c}=%s",{s,c}); $display("{s,d}=%s",{s,d}); $display("{s,e}=%s",{s,e}); $display("{s,f}=%s",{s,f}); $display("{s,j}=%s",{s,j}); $display("{s,l}=%s",{s,l}); repeat_f(0); end function automatic void repeat_f(int c); if (c==4) return; $display("%1d{s,a}=%s",c,{c{s,a}}); repeat_f(c+1); endfunction endmodule
上のベンチの結果です。
***** Veritak SV Engine Version 0.423 Build Jul.7.2011 ***** Not equal k abcdefghijk a>s Not equal k abcdefghijk Not equal jk abcdefghijk Not equal hijk abcdefghijk Not equal hijk abcdefghijk Not equal defghijk abcdefghijk Not equal defghijk abcdefghijk Equal abcdefghijk abcdefghijk l<=s {s,a}=ABk {s,b}=ABk {s,c}=ABjk {s,d}=ABhijk {s,e}=ABhijk {s,f}=ABdefghijk {s,j}=ABdefghijk {s,l}=ABabcdefghijk 0{s,a}= 1{s,a}=ABk 2{s,a}=ABkABk 3{s,a}=ABkABkABk ---------- シミュレーションを終了します。time=0ns
少し、注意する点を挙げます。
module cast_test; string a,b; reg [31:0] r; int i=3; initial begin b = {2{"H"}}; // OK $display("b=%s",b); a = {i{"H"}}; // OK (non-constant replication) $display("a=%s",a); //r = {i{"Hi"}}; // Compile Error a = {i{b}}; // OK $display("{i{b}}=%s",a); a = {a,b}; // OK $display("a=%s",a); a = {"ABC",b}; $display("a=%s",a); r = {"H",""}; // ""は、8'b0に変換される。 $display("r=%h",r); b = {"H",""}; // "" は、空ストリング $display("b=%s",b); a[0] = "i"; $display("a=%s",a); a[0] =byte'(b); // キャストが必要 $display("a=%s",a); a[1] = "\0"; // バイナリゼロの書き込みは、無視される。 $display("a=%s",a); end endmodule
string に代入する場合は、
a = {i{"H"}};
のように、変数repeatが可能になります。これに対して、regに代入する場合は、コンパイル時にビット幅が確定しないので、コンパイルエラーとなります。
r = {i{"Hi"}}; // Compile Error
***** Veritak SV Engine Version 0.423 Build Jul.7.2011 *****
b=HH
a=HHH
{i{b}}=HHHHHH
a=HHHHHHHH
a=ABCHH
r=00004800
b=H
a=iBCHH
a=HBCHH
a=HBCHH
---------- シミュレーションを終了します。time=0ns
4)stringのメンバー関数
メソッド | 意味 |
function int len(); | 長さを返します。stringが空(="")のときは、0が返ります。 |
function void putc(int i, byte c); | str[i]=c;を実行します。 i < 0 または、 i >= str.len()のときは、strは、書き込まれません。. また、c==0のときも、書き込まれません。 |
function byte getc(int i); | str[i] を返します。 i < 0 または、 i >= str.len(),のときは、 0が返ります。 |
function string toupper(); | 大文字に変換します。 |
function string tolower(); | 小文字に変換します。 |
function int compare(string s); | C言語のstrcmpに同じです。 |
function int icompare(string s); | 大文字、小文字を無視したcompareです。 |
function string substr(int i, int j); | str.substr(i, j) は、str[i:j]を返します。 i < 0, j < i, or j >= str.len(), のときは、""空stringが返ります。 |
function integer atoi(); function integer atohex(); function integer atooct(); function integer atobin(); |
atoi:ASCIIデシマルストリングをintegerl型に変換した結果を返します。 atohex:ASCIIHexストリングをintegerl型に変換した結果を返します。 atooct:ASCIIHexストリングをintegerl型に変換した結果を返します。 atobin:ASCIIBinaryストリングをintegerl型に変換した結果を返します。 これらの関数は、32ビットで打ち切りになります。32ビットより大きいときは、$sscanfを使ってください。 |
function real atoreal(); | ASCIIデシマルストリングをreal型に変換した結果を返します。 |
function void itoa(integer i); | integer型iをDecimalストリング(0-9)に変換します。 |
function void hextoa(integer i); | integer型iをHexストリング(0-f)に変換します。 |
function void octtoa(integer i); | integer型iをOctalストリング(0-7)に変換します。 |
function void bintoa(integer i); | integer型iを0/1ストリングに変換します。 |
function void realtoa(real r); | real型rをストリングに変換します。 |
上記のビルトイン関数を使って、パターンマッチングする例2種です。下記を参照しました。
http://www.testbench.in/SV_04_STRINGS.html
http://hitorilife.com/match.php
C言語並に手軽に書けることが分かります。
module string_match; string str1,str2; initial begin //include pattern matching str1 = "今日は、晴れ です。"; str2 = "今日"; if(match(str1,str2)) $display(" str2 : %s : found in :%s:",str2,str1); str1 = "今日は、晴れ です。"; str2 = "晴れ"; if(match(str1,str2)) $display(" str2 : %s : found in :%s:",str2,str1); str1 = "今日は、晴れ です。"; str2 = "です。"; if(match(str1,str2)) $display(" str2 : %s : found in :%s:",str2,str1); str1 = "今日は、晴れ です。"; str2 = "今日は、"; if(match(str1,str2)) $display(" str2 : %s : found in :%s:",str2,str1); str1 = "今日は、晴れ です。"; str2 = "晴れ です。"; if(match(str1,str2)) $display(" str2 : %s : found in :%s:",str2,str1); //*? pattern matching $display(""); str1="abcde.tx"; str2="abcde.txt"; match_check(str1,str2); str1="*"; str2="abcde.txt"; match_check(str1,str2); str1="*.*"; str2="abcde.txt"; match_check(str1,str2); str1="abcde.??"; str2="abcde.txt"; match_check(str1,str2); str1="abcde.???"; str2="abcde.txt"; match_check(str1,str2); end function automatic bit match(string s1,s2); int l1,l2; l1 = s1.len(); l2 = s2.len(); match = 0 ; if( l2 > l1 ) return 0; for(int i = 0;i < l1 - l2 + 1; i ++) if( s1.substr(i,i+l2 -1) == s2) return 1; endfunction function automatic void match_check( ref string s1,s2); if (match2(str1,str2)) $display(" マッチしました。 str1=%s : str2=%s:",str1,str2); else $display("マッチしません。 str1=%s : str2=%s",str1,str2); endfunction function automatic bit match2(string s1,s2); //For Debug $display("%s %s",s1,s2); if (!s1.len() &&!s2.len()) return 1; //? if (s1.getc(0)=="?") if (!s2.len()) return 0; else begin return match2(s1.substr(1,s1.len()-1),s2.substr(1,s2.len()-1)); end //* if (s1.getc(0)=="*") begin if (!s2.len()) return match2(s1.substr(1,s1.len()-1),s2); else begin if (match2(s1.substr(1,s1.len()-1), s2)) return 1; else return match2(s1,s2.substr(1,s2.len()-1)); endend if (s1.getc(0)==s2.getc(0 )) return match2(s1.substr(1,s1.len()-1),s2.substr(1,s2.len()-1)); return 0; endfunction endmodule
***** Veritak SV Engine Version 0.423 Build Jul.7.2011 ***** str2 : 今日 : found in :今日は、晴れ です。: str2 : 晴れ : found in :今日は、晴れ です。: str2 : です。 : found in :今日は、晴れ です。: str2 : 今日は、 : found in :今日は、晴れ です。: str2 : 晴れ です。 : found in :今日は、晴れ です。: マッチしません。 str1=abcde.tx : str2=abcde.txt マッチしました。 str1=* : str2=abcde.txt: マッチしました。 str1=*.* : str2=abcde.txt: マッチしません。 str1=abcde.?? : str2=abcde.txt マッチしました。 str1=abcde.??? : str2=abcde.txt: ---------- シミュレーションを終了します。time=0ns
5)システムタスク
システムタスク名 | task/function | 意味 |
$swrite(output_str, list_of_arguments ); $swriteb(output_str, list_of_arguments ); $swriteo(output_str, list_of_arguments ); $swriteh(output_str, list_of_arguments ); |
task | output_strに指定フォーマットで読み取ります。フォーマット指定は、どこにあってもよいのですが、"%d %s"等の定数フォーマットでなければなりません。 |
$sformat ( output_str , format_string , list_of_arguments ) ; | task | output_strにformat_string(2ndパラメータに限定されます。)で指定されるフォーマットで書き込みます。format_strは、"%d
%s"等の定数に限定されず、stringも使用することが出来ます。 |
$sformatf ( format_string , list_of_arguments ) ; | function | $sformatのfunction版で戻り値がstring になります。 $psprintfは、LRM(P1800-2009)では定義されておらずvendor uniqueです。$sformatfを使ってください。 |
$sscanf ( str , format , args ) | function | format指定で、strをスキャンします。読み込みに成功した個数が戻り値として返ります。 |
module string_literal_test; logic [79:0] a; parameter pformat="S/N%h %b %3d %s"; string format=pformat; string str,result; logic [8*13:1] r1; byte b; int c; string comment; initial begin str="S/Nbeafdeadabcd1234 01001010 100 コメントなし"; $sscanf(str,"S/N%h %b %3d %s",a,b,c,comment); $display( "S/N%h %b %3d %s",a,b,c,comment); $sscanf(str,format,a,b,c,comment); $display("S/N%h %b %3d %s",a,b,c,comment); $sformat(result,format,a,b,c,comment); $display("%s",result); $swrite(result,pformat,a,b,c,comment); $display("%s",result); my_log($sformatf(format,a,b,c,comment)); my_log( convert2string(c,c+1)); end function void my_log( inputstring s); $display("time=%0t %s",$time,s); endfunction function automatic string convert2string( inputint address, int data); return $sformatf("%3d :%3d",address,data); endfunction endmodule
***** Veritak SV Engine Version 0.423 Build Jul.7.2011 ***** S/N0000beafdeadabcd1234 01001010 100 コメントなし S/N0000beafdeadabcd1234 01001010 100 コメントなし S/N0000beafdeadabcd1234 01001010 100 コメントなし S/N0000beafdeadabcd1234 01001010 100 コメントなし time=0 S/N0000beafdeadabcd1234 01001010 100 コメントなし time=0 100 :101 ---------- シミュレーションを終了します。time=0ns