通過文件讀寫方式實現Matlab和Modelsim的聯合仿真
雖然Modelsim的功能非常強大,仿真的波形可以以多種形式進行顯示,但是當涉及到數字信號處理的算法的仿真驗證的時候,則顯得有點不足。而進行數字信號處理是Matlab的強項,不但有大量的關於數字信號處理的函數,而且圖形顯示功能也很強大,所以在做數字信號處理算法的FPGA驗證的時候借助Matlab會大大加快算法驗證的速度。
關於Matlab和Modelsim聯合仿真,我從網上看到兩種方法,一種是通過Link for Modelsim建立Matlab和Modelsim的聯合仿真接口;另一種就是通過文件讀寫的方式實現Matlab和Modelsim的聯合仿真。我沒有仔細研究過第一種方法,我大概看了一下,感覺過程比較複雜,不過功能肯定也很強大,網上有一篇關於Link for Modelsim的文章https://space.ednchina.com/Upload/2009/11/16/9e8d0364-20ed-4583-a85e-4d1fc50783a7.rar" target=_blank>,有興趣的朋友可以去看一看。關於第二種方法,隻是通過幾個文件讀寫函數就可以實現了,而且基本可以滿足當前仿真的要求,所以這裏主要討論一下我所使用的這種方法,希望能夠拋磚引玉吧,因為我也隻能算個初學者而已。
1. Matlab產生數據用作Modelsim仿真
在FPGA進行算法驗證的時候,經常需要輸入仿真數據,這些數據可以用FPGA產生,但是如果數據產生過程很複雜的話,需要耗費很大的精力,並且產生的數據的準確性也不能保證。例如,如果要驗證一個通信接收機的相關算法,那麼我們就需要先產生發送數據,也就是說得先做一個發射機,如果這個過程也由FPGA實現的話,也是一個很複雜的過程。這時候我們就可以借助Matlab,利用Matlab內部自帶的各種函數,產生需要的信號,再經過定點化,就作為FPGA接收模塊的輸入信號了。這樣做無疑會節約很多時間和精力。
下麵用一個簡單的例子說明如何用Matlab產生的數據用作Modelsim仿真。
首先利用matlab產生一個周期256點8bit的正弦波數據,然後以16進製形式寫入sin.txt文件
N = 256;
n = 1:256;
x = fix(128 + (2^7 - 1) * sin(2*pi*n/N));
fid = fopen('sin.txt','wt');
fprintf(fid,'%x\n',x);
fclose(fid);
下圖是截取的產生的數據文件的內容

然後將產生的sin.txt文件複製到Modelsim的工程下,在Verilog文件中先定義一個8bit X 256數組,然後通過$readmemh命令,將文件中的數據讀入,相關的Verilog代碼如下:
reg [7:0] data_mem[0:255]; //定義一個8bit X 256的數組
initial
begin
$readmemh("sin.txt",data_mem); //將sin.txt中的數據讀入存儲器data_mem
end
關於$readmemh的用法可以參見Verilog的參考書,這裏就不詳細說了。
後麵就可以用data_mem作為你的測試數據了。例如可以通過以下代碼,將data_mem的數據送給data_out:
always @(posedge clk)
begin
if(rst)
begin
data_out <= 8'd0;
i <= 8'd0;
end
else
begin
data_out <= data_mem[i]; //將存儲器中的數據輸出
i <= i + 8'd1;
end
end
這樣利用data_out就可以輸出一個正弦波波形,下圖是Molesim仿真產生的正弦波波形:
2. Matlab對Modelsim仿真生成的數據進行分析
Matlab對Modelsim仿真生成數據的處理也是通過文件讀寫實現的。即通過Verilog語句,將仿真過程中的某個信號寫入文件,然後在Matlab中在把這個文件的數據讀出來,就可以在Matlab中進行分析了。
下圖也通過一個簡單的例子,說明一下整個過程。
以下的Verilog語句實現將信號data_out的數據寫入data_out.txt文件
integer w_file;
initial w_file = $fopen("data_out.txt");
always @(i)
begin
$fdisplay(w_file,"%h",data_out);
if(i == 8'd255) //共寫入256個數據
$stop;
end
下圖是截取的data_out.txt的部分內容:
然後就可以編一小段Matlab的程序將data_out.txt中的數據讀取進行分析了。下麵一段Matlab的程序是將數據讀取,並通過圖形顯示出數據的波形。
fid = fopen('data_out.txt','r');
for i = 1 : 256;
num(i) = fscanf(fid, '%x', 1); %這句話的意思是從fid所指的文件以16進製方式讀出一個數據。
end
fclose(fid);
plot(num);
當利用fscanf函數時要注意兩點,
第一:保證讀取的數據格式和文件中保存的數據格式是相同的,例如這裏文件中保存的格式是十六進製,所以讀取的時候也應該以十六進製的形式讀出。
第二:要保證文件中數據的個數和設定的讀取的數目(這裏是256)保持一致。例如,要將生成文件data_out.txt中多餘的換行符去掉(一般最後會多出一行),否則Matlab會將空的行也當做一個數據,從而兩個數目不一致,導致Matlab報錯。
下圖是Matlab將data_out.txt中的數據讀出,並顯示出的波形:
當然,有了Matlab這個強大的工具,也就可以很方便的看信號的頻譜等信息了。
另外在說一點,就是關於通過Verilog將數據寫入文件有多種方法,上麵用的是$fdisplay這個係統函數,當然還有$fmonitor和$fwrite等幾個命令,下麵簡單說一下這幾個命令的不同。
-
$fdisplay
這個命令需要有觸發條件,才會把數據寫入文件,例如,上例的觸發條件就是always(i),當i變化的時候才寫入。每寫入一次數據會自動增加一個換行符。
-
$fmonitor
這個命令不需要觸發條件,隻要有變化就可以將數據寫入文件。例如可以通過以下語句:
initial $fmonitor(w_file,"%h",data_out);
這樣可以將整個仿真過程產生的data_out數據都寫入文件中。
-
$fwrite
這個命令和$fdisplay基本相同,也是需要觸發條件才會寫入,不同的是每寫入一個數據不會自動添加換行符。例如可以通過以下語句:
always @(posedge clk)
begin
$fwrite(w_file,"%h\n",data_out);
end
關於這幾個命令的詳細介紹,大家可以參考Verilog的相關數據。
簡單總結一下上麵用到的幾個函數:
-
關於Matlab的函數有:fopen, fscanf,fclose。
- 關於Modelsim的函數有:$fopen,$fclose,$readmemh,$readmemb,$fmonitor,$fdisplay,$fwrite。
上麵就是我關於Matlab和Modesim進行聯合仿真的一些心得,如果大家還有其他更好的方法,希望不吝賜教啊!
最後更新:2017-04-03 05:39:50