雙口 RAM IP 核簡介
雙口 RAM IP 核有兩個端口,它又分為偽雙端口 RAM 和真雙端口 RAM,偽雙端口 RAM 一個端口只能讀,另一個端口只能
寫,真雙端口 RAM 兩個端口都可以進行讀寫操作。同時對存儲器進行讀寫操作時就會用到雙端口 RAM,例如有一個 FIFO 存儲器,需要同時對其進行數據的寫入和讀出,這時候就需要一個寫端口和一個讀端口。
偽雙端口 RAM
BMG IP 核配置成簡單雙端口 RAM 的框圖如下圖所示:
它有兩組獨立的端口 A 和 B,其中 A 端口只能提供了 DINA 數據總線,只能進行寫操作,B 端口只提供了 DOUTB 數據總線,只能進行讀操作,此外它相當于單口 RAM 還多出了以下信號線(在常規使用中一般不會關注這些信號線):
- IINJECTSBITERR:Inject Single-Bit Error 的簡寫,即注入單 bit 錯誤,僅適用于 Xilinx Zynq-7000 和 7系列芯片的 ECC 配置。
- IINJECTDBITERR:Inject Double-Bit Error 的簡寫,即注入雙 bit 錯誤,同樣僅適用于 Xilinx Zynq-7000和 7 系列芯片的 ECC 配置。
- SBITERR:Single-Bit Error 的簡寫,即單 bit 錯誤,標記內存中存在的單 bit 錯誤,該錯誤已在輸出總線上自動更正。
- DBITERR:Double-Bit Error 的簡寫,即雙 bit 錯誤,標記內存中存在雙 bit 錯誤,需要注意的是內置的ECC 解碼模塊不能自動糾正雙 bit 錯誤。
- RDADDRECC:Read Address for ECC Error output 的簡寫,即讀地址 ECC 錯誤輸出,同樣僅適用于Xilinx Zynq-7000 和 7 系列芯片的 ECC 配置。
真雙口 RAM
BMG IP 核配置成真雙端口RAM 的框圖如下圖所示:
它有兩組獨立的端口 A 和 B,且每組端口都可進行讀寫操作。
不同 RAM 端口對比
通過對比可以發現無論是哪種雙端口 RAM,其地址線、時鐘線、使能線都有兩組,所以雙端口 RAM 可以實現在不同時鐘域下的讀/寫,且可以同時對不同的地址進行讀/寫,這便大大提高了我們數據處理的靈活性。
讀寫沖突和寫寫沖突
寫-寫沖突:當兩個端口都試圖向同一個地址寫數據(即兩個端口寫使能同時有效且寫地址相同)時則會產生寫-寫沖突,發生寫-寫沖突后對應內存地址的數據為未知。
讀-寫沖突:一個端口進行讀取數據操作,另一個端口進行寫入數據操作,當同時操作到同一地址時就會發生讀-寫沖突,此時如果:
- 寫端口為 READ_FIRST 模式,則讀端口讀出的數據為寫入操作前存儲在RAM中的數據。
- 寫端口為 WRITE_FIRST 或 NO_CHANGE 模式,則讀端口讀出的數據為無效。
雙口 RAM 配置核生成
打開 BMG IP 核的“Customize IP”窗口
- Vivado 工程左側“Flow Navigator”欄中的“IP Catalog”
- 在“IP Catalog”窗口的搜索欄中輸入“Block Memory”關鍵字后,出現唯一匹配的“Block Memory Generator”
- 雙擊“Block Memory Generator”后彈出 IP 核的配置界面
BMG IP 核有關偽雙口 RAM 的配置
Block Memory Generator IP核的 IP Catalog 窗口如下,主要包括一個IP名稱輸入框核5個選項卡,下面依次進行介紹。
- 在“Component Name”一欄可以設置該 IP 元件的名稱
- “Basic”選項卡
(1)“lnterface Type(接口模式)”:有兩種接口模式可選,分別為 Native(常規)接口和 AXI4 接口。AXI4 模式一般是在處理器中的數據需要和 BRAM 交互時才會使用,當不需要與處理器數據進行交互時一般采用 Native 模式。
(2) “Generate address interface with 32 bits”選項為是否生成位寬為 32 的地址接口,勾選后內存的數據位寬也必須設置成 32 的整數倍,一般不做勾選。
(3) “Memory Type(存儲類型)”:有五種類型可選,分別為“Single Port RAM(單端口RAM)”、“Simple Dual Port RAM(偽雙端口 RAM)”、“True Dual Port RAM(真雙端口 RAM)”、“Single Port ROM(單端口 ROM)”和“Dual Port ROM(雙端口 ROM)”,這里以單端口 RAM 為例。
(4) “Common Clock”選項:是否啟用同步時鐘,Port A 和 Port B 在同一個時鐘域時可以勾選也可以不勾選,在不同時鐘域時不能勾選,否則跨時鐘域會出問題。
(5) “ECC Options(ECC 選項)”:ECC糾錯碼選項只有在偽雙端口 RAM 類型下才可以進行配置。
(6) “Write Enable(寫使能)”:可以選擇是否使用字節寫使能功能,啟用后可設置字節大小為 8 位或 9 位,需要注意的是啟用后內存的數據位寬必須設置為所選字節大小的整數倍。
(7) “Algorithm Options(算法選項)”:算法選項主要用于決定 BRAM 的拼接的方式,一般在BRAM 深度、寬度較大的時候起作用,有三種算法可選,分別為“Minimum Area(最小面積算法)”、“Low Power(低功耗算法)”和“Fixed Primitives(固定單元算法)” - “Port A Options選項卡,Port A實現數據寫入操作。
(1)“Memory Size(內存大小)”:用于指定端口寬度和深度、運行模式和使能端口類型。
- Port A Width;數據位寬,單位 bit,本次實驗我們設置成 8,可設置的位寬范圍為 1~4608。
- Port A Depth;深度,即 RAM 所能訪問的地址范圍。這里有一點需要注意,那就是寫深度和寫位寬的乘積不要超過器件本身的 ram 資源的大小。
- Operating Mode;RAM 運作模式,有三種模式可選,分別是Write First(寫優先模式)、 Read First(讀優先模式)、No Change(不變模式),單口 RAM 一般選 No Change(不變模式)。
- Enable Port Type;使能端口類型。有兩種可選,分別為 Use ENA pin(添加使能端口 A 的信號)和 Always Enabled(取消使能信號,端口 A 一直處于使能狀態)。
(2)“Port A Optional Output Register”:用于為 RAM 的輸出端添加寄存器,Port A 不支持。
(3)“Port A Output Reset Options”:用于配置端口的復位信號。,Port A 不支持
(4)“READ Address Change A”:用于更改端口的讀地址,這個功能只在 UltraScale 設備上使用。
- “Port B Options”選項卡,Port B 只支持讀操作。
(1)“Memory Size(內存大小)”:用于指定端口寬度和深度、運行模式和使能端口類型。
- Port B Width;數據位寬,其位寬設置必須與 Port A 數據位寬存在倍數關系,通常情況下保持一致。
- Port B Depth;深度,當 Port B 數據位寬、Port A 數據位寬和深度的值確定后,Port B 深度的值就會自動確定。
- Operating Mode;RAM 運作模式,Port B 不可配置。
- Enable Port Type;使能端口類型。有兩種可選,分別為 Use ENA pin(添加使能端口 A 的信號)和 Always Enabled(取消使能信號,端口 B 一直處于使能狀態)。
(2)“Port B Optional Output Register”:用于為 RAM 的輸出端添加寄存器。其作用是提高 BRAM 的運行頻率和改善時序,當然為此付出的代價就是每勾選一個寄存器,輸出就會延遲一拍。 - Primitives Output Register 使用 BRAM 內部的寄存器打拍輸出。
- Core Output Register 使用 SLICE 的寄存器打拍輸出。
- SoftECC Input Register 當使用軟 ECC 的時候,用 SLICE 的寄存器打拍。
- REGCEA,當使用 Primitives Output Register 或者 Core Output Register 時,可以用 REGCEA 來使能相應的輸出。
(3)“Port B Output Reset Options”:用于配置端口的復位信號。可以添加一個復位信號(RSTA Pin)、配置復位時 RAM 輸出總線上的數據值(Output Reset Value)、配置是否復位內置鎖存器(Reset Memory Latch)、配置復位信號與時鐘使能之間的優先級(Reset Priority)。
(4)“READ Address Change B”:用于更改端口的讀地址,這個功能只在 UltraScale 設備上使用。
- “Other Options”選項卡
(1)“Pipeline Stages within Mux”:輸出端 Mux 選擇器的流水線級數。在大位寬、大深度的 BRAM 拼接場景中會用 MUX 來選擇輸出地址所對應的數據,勾選該選項后可以使輸出數據具有更好的時序。
(2)“Memory Initialization(初始化文件)”:選擇是否使用本地初始化文件(.coe 文件)來對存儲空間進行初始化。
(3)“Structural/UniSim Simulation Model Options”:用于選擇結構仿真模型發生碰撞時生成的警告消息和輸出的類型。
(4)“Behavioral Simulation Model Options”:用于關閉仿真時的沖突告警和超出范圍告警。 - “Summary”選項卡
該界面顯示了配置的存儲器的類型,消耗的 BRAM 資源等信息,檢查沒問題可以直接點擊“OK”按鈕生成 RAM IP 核。
在彈出的“Generate Output Products”窗口直接點擊“Generate”即可。
模塊設計
本次實驗的用 Xilinx BMG IP 核配置成一個偽裝雙口 RAM 并對其進行讀寫操作,系統框圖如下:
編寫代碼
大多數情況下偽雙口 RAM 都已經滿足使用需求,入跨時鐘域傳輸數據、存儲數據、FIFO等,所以這里以偽雙口 RAM 為例。
生成偽雙口 RAM IP 核
偽雙口 RAM IP 核的配置如下:
偽雙口 RAM IP讀寫代碼編寫
在偽雙口 RAM IP讀寫代碼先例化一個偽雙口 RAM IP核,在復位完成后開始通過 Port A 周期寫入數據,當第一次寫入到一半時啟動 Port B 進行周期讀數據,波形圖如下:
module ram_ip_rw(input sys_clk,input sys_rst_n
);//端口 A 時鐘
wire clka;
//端口 A 使能,高電平使能
reg ena;
//端口 A 寫使能,高電平寫入
reg wea;
//端口 A 地址
reg [5:0]addra;
//寫入端口 A 的數據
wire [7:0]dina;//端口 B 時鐘
wire clkb;
//端口 B 使能,高電平使能
reg enb;
//端口 B 地址
reg [5:0]addrb;
//端口 B 讀出的數據
wire [7:0]doutb;//端口 A 時鐘
assign clka = sys_clk;//端口 A 使能
always @(posedge sys_clk) beginif(!sys_rst_n)ena <= 0;elseena <= 1;
end//端口 A 寫使能
always @(posedge sys_clk) beginif(!sys_rst_n)wea <= 0;elsewea <= 1;
end//端口 A 地址,0~63
always @(posedge sys_clk) beginif(!sys_rst_n)addra <= 0;else if((addra < 63) && (wea == 1))addra <= addra + 1;elseaddra <= 0;
end//端口 A 寫入數據,從地址0~63依次寫入如0~63
assign dina = (wea == 1) ? addra : 0;//端口 B 時鐘
assign clkb = sys_clk;//端口 B 使能
always @(posedge sys_clk) beginif(!sys_rst_n)enb <= 0;else if(addra == 31)enb <= 1;
end//端口 B 地址,0~63
always @(posedge sys_clk) beginif(!sys_rst_n)addrb <= 0;else if((addrb < 63) && (enb == 1))addrb <= addrb + 1;elseaddrb <= 0;
end//例化偽雙口RAM IP核
blk_mem_gen_0 u_blk_mem_gen_0_inst0(.clka(clka),.ena(ena),.wea(wea),.addra(addra),.dina(dina),.clkb(clkb),.enb(enb),.addrb(addrb),.doutb(doutb)
);endmodule
仿真激勵代碼編寫
仿真激勵代碼非常簡單,只需要例化 單口 RAM IP讀寫模塊 ,然后產生一個周期時鐘即可,完整的代碼如下:
module tb_ram_ip_rw(
);reg sys_clk; //系統時鐘
reg sys_rst_n; //系統復位,低電平有效//信號初始化
initial beginsys_clk = 1'b0;sys_rst_n = 1'b0;#200sys_rst_n = 1'b1;
end//產生時鐘
always #20 sys_clk = ~sys_clk;//例化需要仿真的IP核
ram_ip_rw tb_u_ram_ip_rw_inst0(.sys_clk(sys_clk), //系統時鐘.sys_rst_n(sys_rst_n) //系統復位,低電平有效
);endmodule