學會使用Hdlbits網頁版Verilog代碼仿真驗證平臺

原文鏈接:https://blog.csdn.net/qq_18239447/article/details/89359081

學會使用Hdlbits網頁版Verilog代碼仿真驗證平臺

給大家推薦一款網頁版的 Verilog代碼編輯仿真驗證平臺,這個平臺是國外的一家開源FPGA學習網站,通過“https://hdlbits.01xz.net/wiki/Main_Page”地址鏈接進入網頁,在該網頁上可以進行Verilog代碼的編寫、綜合,而且最後還能夠仿真出波形來驗證設計代碼的正確性,該驗證平臺是基於Icarus Verilog(簡稱iVerilog,比較著名的開源HDL仿真工具,也有對應的安裝版本)的,讓你隨時隨地只需登錄網頁就能夠享受Verilog編程仿真的樂趣!

一、官方模板演示

1、首先打開“https://hdlbits.01xz.net/wiki/Main_Page”,打開後的界面如下圖所示,全英文顯示。如果感覺自己的英文水平欠佳,可以使用谷歌瀏覽器打開該網頁,並選擇在線翻譯功能,翻譯的正確率還是很高的。
在這裏插入圖片描述
2、點擊Simulation下的 ”Run a Simulation(lcarus Verilog)“。
在這裏插入圖片描述
3、打開後的界面如下圖所示,代碼編輯框中給出了一個簡單的例子。
在這裏插入圖片描述
4、點擊下面的“Submit(new window)“在新界面中進行仿真。
在這裏插入圖片描述
5、在新打開的界面中我們可以看到編譯的信息和仿真波形圖。
在這裏插入圖片描述

二、實例演示

雖然看完了官方的模板演示,但我們要想立刻仿真驗證自己設計的代碼並不是那麼容易,需要進行一番摸索。下面就是大家進行一個呼吸燈的設計實例演示。
1、學習過FPGA的朋友都知道要想對FPGA邏輯進行仿真一定要具備兩個文件,一個是RTL代碼文件,用來綜合生成硬件電路的部分;第二個就是Testbench文件,用來驗證RTL代碼功能的仿真文件,這兩者缺一不可。
2、根據觀察發現官方模板中的代碼編輯部分有兩個module,大家也都知道一個.v 文件中只能有一個模塊,也就是只能有一個module,而這裏面有兩個,那肯定就不對了。再仔細觀察會發現代碼編輯區域中的上半部分就是Testbench,而下半部分則是RTL代碼,再結合仿真出的波形來更看驗證了這個想法。原來 RTL 代碼和Testbench都寫在了一個編輯框裏。
3、但是我們在提供的模板中發現一些我們平時幾乎沒有見過的新語法,如第4行的”initial probe_start“、第6行的”probe(clk)“、第26行的”`probe(in)“,通過模板的註釋和多次實驗發現這是官方定義的一個”宏“,也就是通過這個”宏“調用“probe”探針的功能,我們不用管這個”宏“是如何定義的,我們只需要會調用就可以了。
4、下面我們通過該網頁來仿真驗證一下自己設計的呼吸燈的例子。詳細代碼如下(呼吸燈邏輯和Testbench代碼的編寫方法這裏我們不做講解,會在以後的文章中再進行詳細說明),標紅處的註釋是需要特別強調的(代碼可以全部直接複製使用)。

`timescale	1ns/1ns

//-------------------Tesebench--------------------
module	top_module;		//仿真文件名必須是“top_module”

reg		sclk;
reg		rst_n;

wire	led;
  
initial `probe_start;   	// Start the timing diagram

  `probe(sclk);       	// Probe signal "clk",這是加載的系統時鐘,只能在Tesebench中加載    
  
//初始化
initial	begin
  sclk   = 1'b0;
  rst_n <= 1'b0;
  #200
  rst_n <= 1'b1;
  #5000					//一定要設置仿真停止時間,如果仿真結束時間太久會提示
  $finish; 
end

//產生20ns的時鐘
always	#10	sclk =	~sclk;

//爲了減少仿真時間我們在仿真中重定義參數,不影響RTL代碼中參數的值
defparam	breath_led_inst.CNT_1US_MAX	 = 1;
defparam	breath_led_inst.CNT_1MS_MAX  = 2;
defparam	breath_led_inst.CNT_1S_MAX   = 2;

//-------------------breath_led--------------------
breath_led	breath_led_inst(
  .sclk	(sclk	),	//input	sclk	
  .rst_n	(rst_n	),	//input	rst_n	
                        
  .led    (led  	)	//output	led
);

endmodule	
//--------------------------------------------------	


//-----------------------RTL------------------------
module	breath_led
#(
  parameter	CNT_1US_MAX =	6'd49,
  parameter	CNT_1MS_MAX =	10'd999,
  parameter	CNT_1S_MAX	  =	10'd999
)
(
  input	wire	sclk	,
  input	wire	rst_n	,
  
  output	reg		led
);

reg	[5:0]	cnt_1us;	
reg	[9:0]	cnt_1ms;	
reg	[9:0]	cnt_1s;		
reg			cnt_1us_flag;
reg			cnt_1ms_flag;
reg			cnt_1s_flag;

//cnt_1us:1us計數器
always@(posedge sclk or negedge	rst_n)
  if(rst_n == 1'b0)	
  	cnt_1us <=	6'b0;	
  else	if(cnt_1us	== CNT_1US_MAX)	
  	cnt_1us <=	6'b0;
  else
  	cnt_1us <=	cnt_1us + 1'b1;

//cnt_1us_flag:1us計數器標誌信號
always@(posedge sclk or negedge	rst_n)
  if(rst_n == 1'b0)	
  	cnt_1us_flag <= 1'b0;	
  else	if(cnt_1us	==	CNT_1US_MAX)	
  	cnt_1us_flag <= 1'b1;
  else
  	cnt_1us_flag <= 1'b0;

//cnt_1ms:1ms計數器
always@(posedge sclk or negedge	rst_n)
  if(rst_n == 1'b0)	
  	cnt_1ms <=	10'b0;	
  else	if(cnt_1ms	==	CNT_1MS_MAX && cnt_1us_flag == 1'b1)	
  	cnt_1ms <=	10'b0;
  else	if(cnt_1us_flag == 1'b1)
  	cnt_1ms <=	cnt_1ms + 1'b1;
  	
//cnt_1ms_flag:1ms計數器標誌信號
always@(posedge sclk or negedge	rst_n)
  if(rst_n == 1'b0)	
  	cnt_1ms_flag	<=	1'b0;	
  else	if(cnt_1ms	==	CNT_1MS_MAX && cnt_1us_flag == 1'b1)	
  	cnt_1ms_flag <= 1'b1;
  else	
  	cnt_1ms_flag <= 1'b0;

//cnt_1s:1s計數器
always@(posedge sclk or negedge	rst_n)
  if(rst_n == 1'b0)	
  	cnt_1s	<=	10'b0;	
  else	if(cnt_1s == CNT_1S_MAX && cnt_1ms_flag == 1'b1)	
  	cnt_1s	<=	10'b0;
  else	if(cnt_1ms_flag == 1'b1)
  	cnt_1s	<=	cnt_1s	+ 1'b1;

//cnt_1s_flag:1s計數器標誌信號
always@(posedge sclk or negedge	rst_n)
  if(rst_n == 1'b0)	
  	cnt_1s_flag <= 1'b0;	
  else	if(cnt_1s == CNT_1S_MAX && cnt_1ms_flag == 1'b1)	
  	cnt_1s_flag <= ~cnt_1s_flag;	
  
//led:一個LED燈
always@(posedge sclk or negedge	rst_n)
  if(rst_n == 1'b0)
  	led	<= 1'b0;	
  else	if((cnt_1s_flag == 1'b1 && cnt_1ms <= cnt_1s)	|| (cnt_1s_flag	== 1'b0 && cnt_1ms > cnt_1s))
  	led	<= 1'b1;
  else	
  	led	<= 1'b0;
  
//添加要觀察的信號名
  `probe(rst_n			);	// Sub-modules can also have `probe()
  `probe(cnt_1us			);	// Sub-modules can also have `probe()
  `probe(cnt_1us_flag	);	// Sub-modules can also have `probe()
  `probe(cnt_1ms		);	// Sub-modules can also have `probe()
  `probe(cnt_1ms_flag	);	// Sub-modules can also have `probe()
  `probe(cnt_1s			);	// Sub-modules can also have `probe()
  `probe(cnt_1s_flag	);	// Sub-modules can also have `probe()
  `probe(led				);	// Sub-modules can also have `probe()

endmodule 

5、將上面編寫好的Testbench代碼和RTL代碼放到一個文件中(Testbench在上面,RTL代碼在下面,僅在該平臺仿真時可以將兩種文件放在一起,在其他平臺仿真時要獨立放到兩個.v文件中),然後複製粘貼到代碼編輯框中,點擊“Submit(new window)“執行仿真。
在這裏插入圖片描述
6、也可以將寫好的Testbench代碼和RTL代碼放到同一個.v文件中,然後點擊下面的代碼編輯框下面的“Upload a source file…”,在展開的界面中選擇添加.v文件後,再點擊”Upload and simulate”啓動仿真。

在這裏插入圖片描述
在這裏插入圖片描述

7、仿真波形如下所示,因爲界面空間有限,拖動波形顯示框下面的滾動條,可以看到後面的波形顯示。

在這裏插入圖片描述

8、在波形顯示框中右擊鼠標可以選擇保存爲PNG格式或SVG格式,將完整的波形信息保存下來。

在這裏插入圖片描述

9、保存爲SVG格式後的完整波形圖如下所示。

在這裏插入圖片描述
10、如果我們在第58行處代碼設置一個錯誤後,再點擊執行仿真,此時在仿真窗口中不會顯示波形,而是提示錯誤的內容,將錯誤修改後再執行仿真即可。

在這裏插入圖片描述

在這裏插入圖片描述
11、該網頁還有其他更多有趣的功能,如組合邏輯代碼編寫訓練、時序邏輯代碼編寫訓練、單片機嵌入式仿真等等,有興趣的朋友可以自己探索,這裏不再一一演示。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章