日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

跨时钟域问题(三)异步FIFO的Verilog实现(格雷码)

發布時間:2023/12/20 编程问答 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 跨时钟域问题(三)异步FIFO的Verilog实现(格雷码) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

🏡 博客首頁:安靜到無聲

?? 歡迎關注 ?? 點贊 🎒 收藏 ?? 留言

目錄

  • 異步FIFO概述
  • 格雷碼(gray code)的使用
    • 2.1 格雷碼編碼的verilog的實現
  • 格雷碼下的 fifo空滿判斷
  • 異步FIFO代碼及仿真實現
  • 參考

異步FIFO概述

異步FIFO是用來在兩個異步時鐘域間傳輸數據。

圖1 用異步FIFO進行數據傳輸

System X利用xclk時鐘將數據寫入FIFO,并利用System X利用yclk時鐘進行輸出。

其中fifo_full和fifo_empty分別是滿標志和空標志,用于說明數據狀態,當fifo_full時,不再進行數據的寫入,當fifo_empty時不再進行數據的讀取。

格雷碼(gray code)的使用

在產生FIFO滿信號時,要將寫指針和讀指針進行比較,由于兩個指針分別在各自的時鐘域,彼此之間是異步的,在使用二進制進行計數器實現指針時,就會導致用于比較的指針取樣錯誤。

使用自然二進制碼計數時,相鄰數據之間可能會產生多bit的變化。這會產生較大的尖峰電流以及其他問題。

比如,二進制計數器的值會從FFF變為000。這時所有位會同時改變。雖然能通過同步計數器避免亞穩態,但是仍然能得到極不相關的取樣值,所以同步計數器不是最終的解決方案。

從FFF 到000可能的轉換:

  • FFF→000
  • FFF→001
  • FFF→010
  • FFF→011
  • FFF→100
  • FFF→101
  • FFF→110
  • FFF→111

如果同步時鐘邊沿在FFF向000轉換的中間位置到來,就可能將三位二進制數的任何值取樣并同步到新的時鐘域中。鑒于以上情況,強烈建議避免使用二進制計數器實現讀、寫指針。

格雷碼是一種相鄰數據只有1bit變化的碼制。因此可以使用格雷碼去取代二進制計數器,并且用打拍的方式去同步(跨時鐘域問題(二)(單bit信號跨時鐘域 1. 電平同步器 2. 邊沿同步器 3. 脈沖檢測器))(只有深度為2的n次方才能用格雷碼的方式去同步,這樣才能保證最大值和最小值只有一位的變化)。我們可以將指針轉為格雷碼同步到另一個時鐘域再進行比較。如果同步時鐘在計數值轉換期間到來,這種編碼能夠消除絕大部分的錯誤。

圖2 格雷碼編碼計數器

2.1 格雷碼編碼的verilog的實現

自然二進制編碼轉換為格雷碼如下:

圖3 二進制轉化為格雷碼

gray_code=binary_code⊕(binary_code>>1)gray\_code = binary\_code \oplus (binary\_code > > 1)gray_code=binary_code(binary_code>>1)

格雷碼轉化為自然二進制

圖4 格雷碼轉化為自然二進制


我們以??途WVL47 格雷碼計數器為例!


代碼

`timescale 1ns/1nsmodule gray_counter(input clk ,input rst_n ,output reg [ 3:0] gray_out );reg [ 3:0] binary_cnt ; reg flag ;always @(posedge clk or negedge rst_n) beginif (!rst_n) beginflag <= 1'd0;endelse beginflag <= ~flag;end end always @(posedge clk or negedge rst_n) beginif (!rst_n) beginbinary_cnt <= 1'd0;end else beginif (flag == 1'd1) beginbinary_cnt <= binary_cnt + 1'd1;end else beginbinary_cnt <= binary_cnt;endend endalways @(*) begingray_out <= binary_cnt ^ (binary_cnt >> 1); endendmodule

格雷碼下的 fifo空滿判斷

在判斷寫滿時,要將讀地址指針同步到寫地址指針的時鐘域;在判讀讀空是,要將寫地址指針同步到讀地址指針的時鐘域。

對于“空”的判斷依然依據二者完全相等(包括MSB);

而對于“滿”的判斷,如下圖,由于gray碼除了MSB外,具有鏡像對稱的特點,當讀指針指向7,寫指針指向8時,除了MSB,其余位皆相同,不能說它為滿。因此不能單純的只檢測最高位了,在gray碼上判斷為滿必須同時滿足以下3條:

  • wr_adr_gray和同步過來的rd_adr_gray的MSB不相等,因為wptr必須比rptr多折回一次。
  • wr_adr_gray與rd_adr_gray的次高位不相等(如下圖位置7和位置15,轉化為二進制對應的是0111和1111,MSB不同說明多折回一次,111相同代表同一位置,而對應的格雷碼是最高位相反同時次高位也相反)
  • 剩下的其余位完全相等。
  • 圖5 空滿信號的判斷

    異步FIFO代碼及仿真實現

    module asyn_fifo#(parameter data_width = 16 ,//數據的寬度parameter data_depth = 8 ,//數據的深度parameter ram_depth = 256 //定義ram)(//復位時鐘input rst_n ,//復位時鐘//寫時鐘域input wr_clk ,//寫時鐘域時鐘input wr_en ,//寫使能input [data_width-1:0] data_in ,//寫入數據output full ,//滿標志//讀時鐘域input rd_clk ,//讀時鐘域時鐘input rd_en ,//讀使能output reg [data_width-1:0] data_out ,//讀出數據output empty //滿標志 );//定義雙端口ram的讀寫地址 wire [data_depth-1:0] wr_adr ;//雙端口ram的寫地址 wire [data_depth-1:0] rd_adr ;//雙端口ram的讀地址//定義雙端口ram的讀寫指針!為什么比讀寫地址多一位,在博客中講解! reg [data_depth:0] wr_adr_ptr ;//寫指針 reg [data_depth:0] rd_adr_ptr ;//讀指針//轉換為格雷碼進行打拍操作 wire [data_depth:0] wr_adr_gray ;//寫地址指針二進制轉化為格雷碼 reg [data_depth:0] wr_adr_gray1 ;//打一拍緩存 reg [data_depth:0] wr_adr_gray2 ;//打兩拍緩存wire [data_depth:0] rd_adr_gray ;//讀地址指針二進制轉化為格雷碼 reg [data_depth:0] rd_adr_gray1 ;//打一拍緩存 reg [data_depth:0] rd_adr_gray2 ;//打兩拍緩存//讀寫地址比控制指針少一位 assign wr_adr = wr_adr_ptr[data_depth-1:0]; assign rd_adr = rd_adr_ptr[data_depth-1:0];//開辟一段內存空間 reg [data_width-1:0] ram_fifo [ram_depth-1:0] ;//data_width*ram_depth//寫數據 integer i; always @(posedge wr_clk or negedge rst_n) beginif (!rst_n) beginfor (i = 0; i < ram_depth; i = i + 1) beginram_fifo[i] <= 'd0;endend else beginif(wr_en && (~full)) begin //如果寫使能開啟,且未滿ram_fifo[wr_adr] <= data_in;end else beginram_fifo[wr_adr] <= ram_fifo[wr_adr];endend end//讀數據 always @(posedge rd_clk or negedge rst_n) beginif (!rst_n) begindata_out <= 'd0;end else beginif(rd_en && (~empty)) begin //如果讀使能開啟,且未空data_out <= ram_fifo [rd_adr];end else begindata_out <= 'd0; //否則讀出為0endend end//寫地址指針控制 always @(posedge wr_clk or negedge rst_n) beginif (!rst_n) beginwr_adr_ptr <= 'd0;end else beginif(wr_en && (~full)) beginwr_adr_ptr <= wr_adr_ptr + 1'b1;end else beginwr_adr_ptr <= wr_adr_ptr;endend end//讀地址指針控制 always @(posedge rd_clk or negedge rst_n) beginif (!rst_n) beginrd_adr_ptr <= 'd0;end else beginif(rd_en && (~empty)) beginrd_adr_ptr <= rd_adr_ptr + 1'b1;end else beginrd_adr_ptr <= rd_adr_ptr;endend end//二進制指針轉化為格雷碼 assign wr_adr_gray = (wr_adr_ptr >> 1) ^ wr_adr_ptr; assign rd_adr_gray = (rd_adr_ptr >> 1) ^ rd_adr_ptr;//格雷碼的同步 讀時鐘域同步到寫時鐘域 always @(posedge wr_clk or negedge rst_n) beginif (!rst_n) beginrd_adr_gray1 <= 'd0;rd_adr_gray2 <= 'd0;end else beginrd_adr_gray1 <= rd_adr_gray;rd_adr_gray2 <= rd_adr_gray1;end end//格雷碼的同步 寫時鐘域同步到讀時鐘域 always @(posedge rd_clk or negedge rst_n) beginif (!rst_n) beginwr_adr_gray1 <= 'd0;wr_adr_gray2 <= 'd0;end else beginwr_adr_gray1 <= wr_adr_gray;wr_adr_gray2 <= wr_adr_gray1;end end//空標志---->表示讀空---->同步到讀時鐘域的寫地址指針和讀地址指針相同 assign empty = (rd_adr_gray == wr_adr_gray2) ? 1'b1 : 1'b0; assign full = (wr_adr_gray[data_depth] != rd_adr_gray2[data_depth]) && (wr_adr_gray[data_depth-1] != rd_adr_gray2[data_depth-1]) && (wr_adr_gray[data_depth-2:0] == rd_adr_gray2[data_depth-2:0]);endmodule

    仿真

    `timescale 1ns / 1psmodule asyn_fifo_tb;reg rst_n ;reg wr_clk ; reg wr_en ; reg [ 15:0] data_in ; wire full ;reg rd_clk ; reg rd_en ; wire [ 15:0] data_out ; wire empty ;asyn_fifo asyn_fifo_inst(.rst_n (rst_n ),.wr_clk (wr_clk ),.wr_en (wr_en ),.data_in (data_in ),.full (full ),.rd_clk (rd_clk ),.rd_en (rd_en ),.data_out (data_out ),.empty (empty ) );initial wr_clk = 0;always#10 wr_clk = ~wr_clk;initial rd_clk = 0;always#30 rd_clk = ~rd_clk;always@(posedge wr_clk or negedge rst_n)beginif(!rst_n)data_in <= 'd0;else if(wr_en)data_in <= data_in + 1'b1;elsedata_in <= data_in;endinitial beginrst_n = 0;wr_en = 0;rd_en = 0;#200;rst_n = 1;wr_en = 1;#6000;wr_en = 0;rd_en = 1;#18000;rd_en = 0;$stop;endendmodule

    仿真結果

    vivado的工程已將經傳至地址

    參考

  • 硬件架構的藝術——數字電路設計方法與藝術
  • ??途W——格雷碼計數器
  • https://blog.csdn.net/weixin_41458037/article/details/96499750
  • https://www.bilibili.com/video/BV1Wf4y1N7h4?spm_id_from=333.337.search-card.all.click&vd_source=e3e56f2c8b99f0309ca6937cefb13991
  • 總結

    以上是生活随笔為你收集整理的跨时钟域问题(三)异步FIFO的Verilog实现(格雷码)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。