對(duì)一些數(shù)據(jù)處理的模塊進(jìn)行調(diào)試仿真,模塊需要特定的數(shù)據(jù)輸入,比如單一頻率的正弦波;為了解決這個(gè)問題,我們可以用matlab,python等工具生成文本數(shù)據(jù),然后使用Verilog將數(shù)據(jù)讀取進(jìn)來;Testbench可以使用2種方法進(jìn)行文本數(shù)據(jù)操作
readmemb, readmemh, writememb, writememh操作
從字面意思理解,readmem是讀取數(shù)據(jù)到memory,后綴的b, h代表了數(shù)據(jù)的進(jìn)制;同理,writemem是將memory的數(shù)據(jù)寫入到文件中;
所以,在使用這一類系統(tǒng)自帶函數(shù)時(shí),首先要有一個(gè)memory類型的變量。定義方法如下:
reg [M-1:0] mem [N:1];
mem”變量“(應(yīng)該叫寄存器組)有N個(gè)”一維“變量,每個(gè)”一維“變量的bit寬度為M;你可以將mem理解為C語言中的二維數(shù)組,里面包含了N個(gè)一維數(shù)組,每個(gè)一維數(shù)組有M個(gè)元素,元素為bit。
事實(shí)上,我們稱M為mem的數(shù)據(jù)寬度,N為mem的數(shù)據(jù)深度。
以readmemb為例,進(jìn)行數(shù)據(jù)讀取操作
initial
begin
$readmemb("data.txt", mem);
end
readmemb的第一個(gè)參數(shù)為文件名,第二個(gè)參數(shù)為memory變量名;至此,data.txt內(nèi)部的N行數(shù)據(jù)存入了mem里。readmemh操作類似,不同的是data.txt的數(shù)據(jù)要求為16進(jìn)制。
那么可能有人會(huì)有疑問了,假如有以下問題,mem存入的數(shù)據(jù)會(huì)是啥樣:
- data.txt每行的數(shù)據(jù)位寬小于M或者大于M
圖1 數(shù)據(jù)位寬小于M波形
圖2 數(shù)據(jù)位寬小于M存儲(chǔ)
圖3 數(shù)據(jù)位寬大于M
圖4 數(shù)據(jù)位寬大于M,VCS警告
經(jīng)過試驗(yàn),M大于數(shù)據(jù)位寬,數(shù)據(jù)可以正常讀取,高位補(bǔ)0;小于數(shù)據(jù)位寬,數(shù)據(jù)無法正常讀取。
- data.txt的數(shù)據(jù)不是二進(jìn)制,或者不是純數(shù)字
與M小于數(shù)據(jù)位寬的情況一致,無法正常讀取數(shù)據(jù)。
- 如果data.txt的行數(shù)小于N或大于N
圖5 行數(shù)小于N
圖6 行數(shù)大于N
經(jīng)過試驗(yàn),行數(shù)大于N,仿真器會(huì)出警告,但數(shù)據(jù)可以正常讀取。小于N時(shí),多余的部分memory的值為不定狀態(tài)。
數(shù)據(jù)存入mem但還沒有進(jìn)入到模塊的輸入,接下來的操作可以參考下列代碼:
reg [M-1:0] data_in;
integer index = 1;
initial
begin
forever
begin
@(posegde clk);
data_in = mem[index];
index = (index >= N) ? 1 : index + 1;
end
end
代碼里面,等待clk的上升沿,然后將mem的index元素賦值給data_in,然后index完成加1操作;整個(gè)過程不斷循環(huán);這里設(shè)置了index計(jì)數(shù)到N返回1的計(jì)數(shù)保護(hù),防止出現(xiàn)無效數(shù)據(jù)。
再將data_in與被測(cè)模塊的數(shù)據(jù)輸入端口相連,數(shù)據(jù)就送入進(jìn)去了。
圖7 送入的數(shù)據(jù)波形
writememb的操作與readmemb反過來,將mem的數(shù)據(jù)存儲(chǔ)為文本操作如下:
initial
begin
$writememb("new_data_b.txt", mem);
$writememh("new_data_h.txt", mem);
end
存儲(chǔ)之后的
圖8 writememh
圖9 writememb
fscanf, fwrite等操作
Verilog本身的語法與C類似,其自身也有文本操作的函數(shù),也與C類似。使用Verilog對(duì)文本操作,首先需要進(jìn)行如下操作:
integer fid;
initial
begin
fid = $fopen("data.txt", "r");
//fid = $fopen("data.txt", "w"); //write
if (!fid)
$display("file open error");
end
如同C語言中的fopen一樣,第一個(gè)參數(shù)為文件名,第二個(gè)參數(shù)為操作模式,包括讀(r, rb),寫(w, wb)等操作;根據(jù)返回值判斷文件操作是否有錯(cuò)誤。
然后,根據(jù)文本文件的數(shù)據(jù)格式,進(jìn)行數(shù)據(jù)讀取操作。
reg [M-1:0] data_in;
always @ (posedge clk)
$fscanf(fid, "%d %d %d", data_in, mem[0], mem[1]);
fscanf用法與C語言類似,文件句柄為第一個(gè)參數(shù),第二個(gè)參數(shù)為格式參數(shù),第三個(gè)為數(shù)據(jù)保存變量,但不需要加&了。讀取文件的時(shí)候第二個(gè)參數(shù)與第三個(gè)參數(shù)需要對(duì)應(yīng),否則數(shù)據(jù)讀取可能會(huì)出錯(cuò)。(親身經(jīng)歷)
數(shù)據(jù)存儲(chǔ)操作如下,在前面fopen使用w模式下:
always @ (posegde clk)
$fwrite(fid, "%d, %d, %d\\n", $signed(data_in), $signed(data_in)+1, $signed(data_in)+2);
數(shù)據(jù)可以按照第二個(gè)參數(shù)的格式存儲(chǔ)進(jìn)文本文件。還有一系列如fdisplay, 相對(duì)于fwrite, 它的文件寫入數(shù)據(jù)之后會(huì)自動(dòng)到下一行,所以第二個(gè)參數(shù)不需要加入“\\n”;ftell等函數(shù)。
注意,想要存儲(chǔ)十進(jìn)制的負(fù)數(shù),除了第二個(gè)參數(shù)用%d,第三個(gè)參數(shù)的寄存器變量還要使用$signed轉(zhuǎn)換為有符號(hào)數(shù)形式
圖10 正常情況文本操作讀取后存儲(chǔ)的數(shù)據(jù)
圖11 寄存器位寬小于數(shù)據(jù)位寬時(shí),文本操作讀取后存儲(chǔ)的數(shù)據(jù)
注意,當(dāng)存儲(chǔ)的寄存器位寬小于數(shù)據(jù)位寬時(shí),數(shù)據(jù)會(huì)被自動(dòng)截去高位保留低位。
之前使用文件操作存儲(chǔ)被測(cè)模塊的輸出時(shí),每次文件的數(shù)據(jù)量(行數(shù))都與理想中的數(shù)目對(duì)不上,找各種原因,最后才發(fā)現(xiàn)自己犯了一個(gè)低級(jí)錯(cuò)誤,沒有使用fclose關(guān)閉文件句柄。
initial
begin
#1000;
$fclose(fid);
$finish;
end
停止仿真前,一定要用fclose關(guān)閉文件句柄,否則數(shù)據(jù)存取會(huì)出現(xiàn)不可預(yù)知的問題。
歡迎使用本文使用的Testbench做實(shí)驗(yàn),注意,在windows下使用modelsim做實(shí)驗(yàn)時(shí),文件名必須是絕對(duì)路徑;tb中,使用"READMEM_ON"宏定義決定運(yùn)行readmem或文件操作,可以嘗試修改宏定義的值改變文件操作的函數(shù)類型;本文使用資源在公眾號(hào)回復(fù)116獲取;
兩種方法差異對(duì)比
- readmem,writemem方法只能存取二進(jìn)制或十六進(jìn)制數(shù)據(jù),數(shù)據(jù)格式固定,對(duì)多維其他格式數(shù)據(jù)讀取不支持,沒有文件操作靈活;文本操作方便其他的工具,如matlab,python處理數(shù)據(jù)
- readmem是可綜合語句,所以可以用于對(duì)模塊內(nèi)的memory變量進(jìn)行賦值,但其他語句是不可綜合語句,只能用于仿真測(cè)試中
- 文件操作雖然支持各種格式的文本存取,但是操作上沒有readmem, writemem簡(jiǎn)單;假如數(shù)據(jù)需要循環(huán)使用,readmem讀取進(jìn)memory之后,通過復(fù)位index就可以循環(huán)使用數(shù)據(jù),而文本操作就麻煩一些。
-
matlab
+關(guān)注
關(guān)注
188文章
2998瀏覽量
233447 -
寄存器
+關(guān)注
關(guān)注
31文章
5425瀏覽量
123606 -
正弦波
+關(guān)注
關(guān)注
11文章
652瀏覽量
56356 -
仿真器
+關(guān)注
關(guān)注
14文章
1034瀏覽量
85076 -
C語言
+關(guān)注
關(guān)注
180文章
7630瀏覽量
140644
發(fā)布評(píng)論請(qǐng)先 登錄
如何在Go中操作文本文件
求助,為什么在CAN數(shù)據(jù)庫(.dbc文本文件)中找不到報(bào)文?
如何把文本文件里面的數(shù)據(jù)讀取到波形圖表中
matlab讀取文本文件然后再計(jì)算
問一個(gè)文本文件讀取的問題
labview中怎么將文本文件中的數(shù)據(jù)按奇,偶行分別進(jìn)讀取。
TCP通信時(shí)用到while循環(huán),將讀取的TCP數(shù)據(jù)寫入文本文件,程序結(jié)束后打開那個(gè)文本文件里面怎么沒有數(shù)據(jù)
CVI中文本文件的格式問題
labview如何讀取6400個(gè)超聲數(shù)據(jù)文本文件,并用波形圖逐一顯示出來
C語言入門教程-文本文件
C語言入門教程-讀取文本文件
Arduino之如何逐行讀取SD卡文本文件

評(píng)論