對一些數據處理的模塊進行調試仿真,模塊需要特定的數據輸入,比如單一頻率的正弦波;為了解決這個問題,我們可以用matlab,python等工具生成文本數據,然后使用Verilog將數據讀取進來;Testbench可以使用2種方法進行文本數據操作
readmemb, readmemh, writememb, writememh操作
從字面意思理解,readmem是讀取數據到memory,后綴的b, h代表了數據的進制;同理,writemem是將memory的數據寫入到文件中;
所以,在使用這一類系統自帶函數時,首先要有一個memory類型的變量。定義方法如下:
reg [M-1:0] mem [N:1];
mem”變量“(應該叫寄存器組)有N個”一維“變量,每個”一維“變量的bit寬度為M;你可以將mem理解為C語言中的二維數組,里面包含了N個一維數組,每個一維數組有M個元素,元素為bit。
事實上,我們稱M為mem的數據寬度,N為mem的數據深度。
以readmemb為例,進行數據讀取操作
initial
begin
$readmemb("data.txt", mem);
end
readmemb的第一個參數為文件名,第二個參數為memory變量名;至此,data.txt內部的N行數據存入了mem里。readmemh操作類似,不同的是data.txt的數據要求為16進制。
那么可能有人會有疑問了,假如有以下問題,mem存入的數據會是啥樣:
- data.txt每行的數據位寬小于M或者大于M
圖1 數據位寬小于M波形
圖2 數據位寬小于M存儲
圖3 數據位寬大于M
圖4 數據位寬大于M,VCS警告
經過試驗,M大于數據位寬,數據可以正常讀取,高位補0;小于數據位寬,數據無法正常讀取。
- data.txt的數據不是二進制,或者不是純數字
與M小于數據位寬的情況一致,無法正常讀取數據。
- 如果data.txt的行數小于N或大于N
圖5 行數小于N
圖6 行數大于N
經過試驗,行數大于N,仿真器會出警告,但數據可以正常讀取。小于N時,多余的部分memory的值為不定狀態。
數據存入mem但還沒有進入到模塊的輸入,接下來的操作可以參考下列代碼:
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操作;整個過程不斷循環;這里設置了index計數到N返回1的計數保護,防止出現無效數據。
再將data_in與被測模塊的數據輸入端口相連,數據就送入進去了。
圖7 送入的數據波形
writememb的操作與readmemb反過來,將mem的數據存儲為文本操作如下:
initial
begin
$writememb("new_data_b.txt", mem);
$writememh("new_data_h.txt", mem);
end
存儲之后的
圖8 writememh
圖9 writememb
fscanf, fwrite等操作
Verilog本身的語法與C類似,其自身也有文本操作的函數,也與C類似。使用Verilog對文本操作,首先需要進行如下操作:
integer fid;
initial
begin
fid = $fopen("data.txt", "r");
//fid = $fopen("data.txt", "w"); //write
if (!fid)
$display("file open error");
end
如同C語言中的fopen一樣,第一個參數為文件名,第二個參數為操作模式,包括讀(r, rb),寫(w, wb)等操作;根據返回值判斷文件操作是否有錯誤。
然后,根據文本文件的數據格式,進行數據讀取操作。
reg [M-1:0] data_in;
always @ (posedge clk)
$fscanf(fid, "%d %d %d", data_in, mem[0], mem[1]);
fscanf用法與C語言類似,文件句柄為第一個參數,第二個參數為格式參數,第三個為數據保存變量,但不需要加&了。讀取文件的時候第二個參數與第三個參數需要對應,否則數據讀取可能會出錯。(親身經歷)
數據存儲操作如下,在前面fopen使用w模式下:
always @ (posegde clk)
$fwrite(fid, "%d, %d, %d\\n", $signed(data_in), $signed(data_in)+1, $signed(data_in)+2);
數據可以按照第二個參數的格式存儲進文本文件。還有一系列如fdisplay, 相對于fwrite, 它的文件寫入數據之后會自動到下一行,所以第二個參數不需要加入“\\n”;ftell等函數。
注意,想要存儲十進制的負數,除了第二個參數用%d,第三個參數的寄存器變量還要使用$signed轉換為有符號數形式
圖10 正常情況文本操作讀取后存儲的數據
圖11 寄存器位寬小于數據位寬時,文本操作讀取后存儲的數據
注意,當存儲的寄存器位寬小于數據位寬時,數據會被自動截去高位保留低位。
之前使用文件操作存儲被測模塊的輸出時,每次文件的數據量(行數)都與理想中的數目對不上,找各種原因,最后才發現自己犯了一個低級錯誤,沒有使用fclose關閉文件句柄。
initial
begin
#1000;
$fclose(fid);
$finish;
end
停止仿真前,一定要用fclose關閉文件句柄,否則數據存取會出現不可預知的問題。
歡迎使用本文使用的Testbench做實驗,注意,在windows下使用modelsim做實驗時,文件名必須是絕對路徑;tb中,使用"READMEM_ON"宏定義決定運行readmem或文件操作,可以嘗試修改宏定義的值改變文件操作的函數類型;本文使用資源在公眾號回復116獲取;
兩種方法差異對比
- readmem,writemem方法只能存取二進制或十六進制數據,數據格式固定,對多維其他格式數據讀取不支持,沒有文件操作靈活;文本操作方便其他的工具,如matlab,python處理數據
- readmem是可綜合語句,所以可以用于對模塊內的memory變量進行賦值,但其他語句是不可綜合語句,只能用于仿真測試中
- 文件操作雖然支持各種格式的文本存取,但是操作上沒有readmem, writemem簡單;假如數據需要循環使用,readmem讀取進memory之后,通過復位index就可以循環使用數據,而文本操作就麻煩一些。
-
matlab
+關注
關注
185文章
2977瀏覽量
230622 -
寄存器
+關注
關注
31文章
5357瀏覽量
120600 -
正弦波
+關注
關注
11文章
645瀏覽量
55445 -
仿真器
+關注
關注
14文章
1018瀏覽量
83797 -
C語言
+關注
關注
180文章
7607瀏覽量
137071
發布評論請先 登錄
相關推薦
評論