[RTLLM-p020] Memory/FIFO (First-In, First-Out)/asyn_fifo


提交解答


分數: 5
時間限制: 2.0s
記憶體限制: 256M

作者:
題目代碼
題目類型
允許的語言
Verilog

參數化非同步 FIFO

題目說明

請設計一個名為 asyn_fifo 的參數化非同步 FIFO,用於在兩個不同時脈域之間安全地傳輸資料。

FIFO 的寫入端使用 wclk,讀取端使用 rclk。由於兩個時脈彼此獨立,讀寫指標不可直接跨時脈域傳遞,必須先轉換為 Gray code,再使用兩級正反器同步器傳遞至另一個時脈域。

FIFO 必須包含以下部分:

  1. 雙埠 RAM
  2. 寫入指標與 Full 控制邏輯
  3. 讀取指標與 Empty 控制邏輯
  4. 讀指標到寫時脈域的兩級同步器
  5. 寫指標到讀時脈域的兩級同步器

模組參數

參數 預設值 說明
WIDTH 8 每筆資料的位元寬度
DEPTH 16 FIFO 可儲存的資料筆數

本題要求 DEPTH 必須是 2 的冪次,例如:

2, 4, 8, 16, 32, 64, ...

FIFO 的位址寬度為:

ADDR_WIDTH = $clog2(DEPTH)

讀寫指標比 RAM 位址多一個位元:

PTR_WIDTH = ADDR_WIDTH + 1

例如,當:

DEPTH = 8

則:

ADDR_WIDTH = 3
PTR_WIDTH  = 4

因此使用 4 位元 Gray code 指標,低 3 位元對應 RAM 位址。


模組介面

方向 位元寬度 說明
wclk input 1 寫入端時脈
rclk input 1 讀取端時脈
wrstn input 1 寫入端低電位有效非同步重置
rrstn input 1 讀取端低電位有效非同步重置
winc input 1 寫入請求
rinc input 1 讀取請求
wdata input WIDTH 寫入資料
wfull output 1 FIFO 已滿
rempty output 1 FIFO 為空
rdata output WIDTH 讀出資料

雙埠 RAM

請建立一個名為 dual_port_RAM 的子模組。

模組介面如下:

module dual_port_RAM #(
    parameter DEPTH = 16,
    parameter WIDTH = 8
) (
    input                              wclk,
    input                              wenc,
    input      [$clog2(DEPTH)-1:0]     waddr,
    input      [WIDTH-1:0]             wdata,

    input                              rclk,
    input                              renc,
    input      [$clog2(DEPTH)-1:0]     raddr,
    output reg [WIDTH-1:0]             rdata
);

RAM 必須具有:

  • 獨立寫入時脈
  • 獨立讀取時脈
  • 同步寫入
  • 同步讀取
  • 可參數化深度與資料寬度

只有在:

wenc = 1

時才可寫入 RAM。

只有在:

renc = 1

時才更新 rdata


寫入操作

真正的 RAM 寫入使能為:

wenc = winc AND NOT wfull

因此,當 FIFO 已滿時,即使 winc1,寫入指標與 RAM 內容也不可改變。

寫入二進位指標的下一個值為:

wbin_next = wbin + wenc

再將二進位指標轉換為 Gray code:

wgray_next = (wbin_next >> 1) XOR wbin_next

RAM 寫入位址使用二進位指標的低 ADDR_WIDTH 位元:

waddr = wbin[ADDR_WIDTH-1:0]

讀取操作

真正的 RAM 讀取使能為:

renc = rinc AND NOT rempty

因此,當 FIFO 為空時,即使 rinc1,讀取指標也不可改變。

讀取二進位指標的下一個值為:

rbin_next = rbin + renc

再轉換為 Gray code:

rgray_next = (rbin_next >> 1) XOR rbin_next

RAM 讀取位址使用二進位指標的低 ADDR_WIDTH 位元:

raddr = rbin[ADDR_WIDTH-1:0]

Gray Code

二進位轉 Gray code 的公式為:

gray = binary XOR (binary >> 1)

Gray code 在每次指標增加時通常只有一個位元發生變化,因此適合用於跨時脈域同步。

不可直接將多位元二進位指標跨時脈域同步,因為多個位元可能同時變化,接收端可能取得不一致的指標值。


指標同步器

讀指標同步至寫時脈域

讀取 Gray code 指標必須經過兩級 wclk 正反器同步後,才能送至 Full 判斷邏輯。

rptr
  │
  ▼
第一級同步器
  │
  ▼
第二級同步器
  │
  ▼
rptr_sync_wclk
寫指標同步至讀時脈域

寫入 Gray code 指標必須經過兩級 rclk 正反器同步後,才能送至 Empty 判斷邏輯。

wptr
  │
  ▼
第一級同步器
  │
  ▼
第二級同步器
  │
  ▼
wptr_sync_rclk

Empty 判斷

當下一個讀取 Gray code 指標等於同步後的寫入 Gray code 指標時,FIFO 為空:

rempty_next = (rgray_next == wgray_sync)

Full 判斷

當下一個寫入指標比讀取指標多繞行一圈時,FIFO 為滿。

對標準 Gray code FIFO 而言,Full 判斷方式是:

  • 將同步後讀指標的最高兩個位元反相。
  • 其餘位元保持不變。
  • 與下一個寫入 Gray code 指標比較。
wfull_next =
    wgray_next ==
    {NOT rgray_sync[MSB:MSB-1],
     rgray_sync[MSB-2:0]}

例如,當 DEPTH = 8 時,指標寬度為 4:

wgray_next[3:0] ==
{
    ~rgray_sync[3:2],
     rgray_sync[1:0]
}

重置行為

wrstnrrstn 都是低電位有效非同步重置。

wrstn = 0 時:

  • 寫入二進位指標歸零
  • 寫入 Gray code 指標歸零
  • 讀指標同步器歸零
  • wfull 歸零

rrstn = 0 時:

  • 讀取二進位指標歸零
  • 讀取 Gray code 指標歸零
  • 寫指標同步器歸零
  • rempty 設為 1

設計要求

  • 模組名稱必須為 asyn_fifo
  • 必須支援參數 WIDTHDEPTH
  • DEPTH 必須是 2 的冪次。
  • 必須實例化 dual_port_RAM 子模組。
  • 讀寫時脈必須彼此獨立。
  • 跨時脈域只能同步 Gray code 指標。
  • 每個跨時脈域指標必須使用兩級正反器同步。
  • FIFO 為滿時不可寫入。
  • FIFO 為空時不可讀取。
  • wfull 必須在寫時脈域產生。
  • rempty 必須在讀時脈域產生。

程式設計模板

module dual_port_RAM #(
    parameter DEPTH = 16,
    parameter WIDTH = 8
) (
    input                          wclk,
    input                          wenc,
    input      [$clog2(DEPTH)-1:0] waddr,
    input      [WIDTH-1:0]         wdata,

    input                          rclk,
    input                          renc,
    input      [$clog2(DEPTH)-1:0] raddr,
    output reg [WIDTH-1:0]         rdata
);

    // Write your code here

endmodule


module asyn_fifo #(
    parameter WIDTH = 8,
    parameter DEPTH = 16
) (
    input                  wclk,
    input                  rclk,
    input                  wrstn,
    input                  rrstn,
    input                  winc,
    input                  rinc,
    input      [WIDTH-1:0] wdata,

    output                 wfull,
    output                 rempty,
    output     [WIDTH-1:0] rdata
);

    // Write your code here

endmodule

評論

目前沒有評論。