精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

FPGA學習筆記:ROM IP核的使用方法

CHANBAEK ? 來源:小小研究生 ? 作者:xxyjs2020 ? 2023-08-22 15:06 ? 次閱讀

理論學習

上一篇介紹了常用的鎖相環IP,這一節將介紹一種較為常用的 存儲類IP核 ——ROM的使用方法。ROM是 只讀存儲器 (Read-Only Memory),顧名思義,我們只能讀出事先存放在固態中的數據,一旦寫入不能再修改或刪除,斷電不丟失。我們知道FPGA只有RAM,因此事實上在 FPGA 中通過 IP 核生成的 ROM 或 RAM掉電內容都會丟失。用 IP 核生成的 ROM 模塊只是提前添加了數據文件(.mif 或.hex 格式),在 FPGA 運行時通過數據文件給 ROM 模塊初始化,才使得 ROM 模塊 “真正”的掉電非易失存儲器;也正是這個原因,ROM 模塊的內容必須提前在數據文件中寫死,無法在電路中修改。

Altera推出的ROM IP核分為兩種類型:單端口ROM和雙端口ROM。對于單端口ROM提供一個讀地址端口和一個讀數據端口,只能進行讀操作;雙端口ROM提供兩個讀地址端口和兩個讀數據端口。其中不是每個端口都要用到,調用完IP核后,是可以生成其例化模塊的,到時候就可以看到我們需要控制的信號了。

圖片

ROM IP核配置

ROM要事先寫進去.mif 或.hex 格式,因此我們需要先建一個.mif文件,寫入我們想要存儲的數據。

File→New→在Memory Files下找到Memory Initialization File-選擇容量為256,位寬為8bit→選中表格的行或列右鍵可以更改進制,默認地址是十進制,存儲器是無符號十進制→手動輸入數據/復制、粘貼/利用軟件自帶的功能,直接推譯出所有數據。

軟件自帶的填充功能用法

右鍵點擊任意單元格→Custom Fill Cells→容量為256,如果起始地址為0,結束地址就為255→可以看到表格中從0-255自動填充好,由于位寬8bit,255也不會超→保存為.mif格式

圖片

創建好工程之后,還是和上一篇中一樣創建IP核,先試單端口

圖片

圖片

圖片

使用寫好的數據,瀏覽文件夾,選擇.mif格式,找到剛才保存的.mif文件導入。

圖片

和上一篇一樣,顯示了我們在仿真ROM IP核時需要的Altera仿真庫,提示我們單獨使用第三方仿真工具時需要添加altera_mf的庫

圖片

和上一篇一樣,選擇inst.v實例化文件

圖片

雙端口有少許不同

圖片

1、可以看出有兩條地址線和兩條數據線了

2、設置定義ROM存儲器大小的方式,按字數確定或按比特數確定,用默認就好

3、選擇ROM的容量,還是選擇256個數據(注意:選擇的容量需大于我們需要寫入的數據文件的數據量)

4、設置不同端口的位寬是否相同,默認是關閉,即使用相同位寬

5、設置數據位寬,這里的數據位寬設置8bit

6、存儲單元類型的選擇,按默認選擇自動

圖片

1、選擇單時鐘/雙時鐘:單時鐘是用一個時鐘控制所有寄存器,雙時鐘是輸入和輸出時鐘分別控制存儲塊的數據輸入和輸出的相關寄存器:時鐘A控制端口A的所有寄存器,時鐘B控制端口B的所有寄存器。每個端口也支持獨立的時鐘使能

2、選擇是否創建‘rden_a’和‘rden_b’讀使能信號

圖片

1、選擇是否輸出‘q_a’和‘q_b’寄存器,選擇的話就會使輸出延遲一拍

2、選擇是否為時鐘信號創建使能信號

3、選擇是否創建“aclr”異步復位信號

后面的步驟都一樣。我們以單端口為例進行設計調用,還是將生成的,qip文件添加到Files下。

設計規劃

首先我們ROM的初始化數據是0~255,每隔0.2s從0地址開始往下讀取數據顯示在數碼管上,再利用兩個按鍵信號來讀取指定地址的數據(例如按下按鍵1顯示地址為99時的數據,按下按鍵2顯示地址為199時的數據,0-255隨意指定)。每按一個按鍵就讀取一個地址的數據顯示在數碼管上。再次按下按鍵后,以當前地址繼續以0.2s的時間間隔往下讀取數據并顯示出來。

圖片

一共有5個模塊:按鍵消抖模塊(使用兩次),ROM控制模塊,IP核,數碼管動態顯示模塊,頂層模塊。實際需要做的是ROM控制模塊,頂層只是實現實例化,其他模塊可以直接調用以前的,可能要做一些修改。

剛才建立rom的ip后生成了inst.v實例化文件,由內容可以看出這個模塊出輸入輸出信號名稱,頂層模塊中關于rom的ip模塊的實例化可以直接復制這個

圖片

編寫代碼

ROM 控制模塊

讀操作是在時鐘的上升沿觸發的,而我們在調用ROM時是沒有生成讀使能的,所以在讀時鐘上升沿只要給相應的地址就能在時鐘的上升沿讀出該地址內的數據了。我們只需要控制生成讀地址即可。現在自定義的ROM IP的用法就是給從地址線輸入一個地址,ROM模塊從數據線輸出地址對應的數據。

圖片輸入有時鐘、復位、兩個按鍵標志信號,中間信號有兩個地址標志信號,200ms計數器,輸出是8位地址。某一個按鍵按下時對應的按鍵標志信號會拉高,當檢測到某一個按鍵標志信號拉高時,對應的地址標志信號會拉高,直至下一個按鍵被按下。按一次按鍵是顯示規定地址存放的數據,再按同一個按鍵會在該地址基礎上繼續顯示下一個地址的數據,而按不同的按鍵就是顯示另一個按鍵規定的地址存放的數據。

module rom_ctrl
(
input wire sys_clk , //系統時鐘,頻率50MHz
input wire sys_rst_n , //復位信號,低有效
input wire key1_flag , //按鍵1消抖后有效信號
input wire key2_flag , //按鍵2消抖后有效信號
output reg [7:0] addr //輸出讀ROM地址
 );


 //parameter define
 parameter CNT_MAX = 9_999_999; //0.2s計數器最大值


 //reg define
 reg addr_flag1 ; //特定地址1標志信號
 reg addr_flag2 ; //特定地址2標志信號
 reg [23:0] cnt_200ms ; //0.2s計數器


 //產生特定地址1標志信號
 always@(posedge sys_clk or negedge sys_rst_n)
 if(sys_rst_n == 1'b0)
 addr_flag1 <= 1'b0;
 else if(key2_flag == 1'b1)
 addr_flag1 <= 1'b0;
 else if(key1_flag == 1'b1)
 addr_flag1 <= ~addr_flag1;


 //產生特定地址2標志信號
 always@(posedge sys_clk or negedge sys_rst_n)
 if(sys_rst_n == 1'b0)
 addr_flag2 <= 1'b0;
 else if(key1_flag == 1'b1)
 addr_flag2 <= 1'b0;
 else if(key2_flag == 1'b1)
 addr_flag2 <= ~addr_flag2;


 //0.2s循環計數
 always@(posedge sys_clk or negedge sys_rst_n)
 if(sys_rst_n == 1'b0)
 cnt_200ms <= 24'd0;
 else if(cnt_200ms == CNT_MAX)
 cnt_200ms <= 24'd0;
 else
 cnt_200ms <= cnt_200ms + 1'b1;


 //讓地址從0~255循環,其中兩個按鍵控制兩個特定地址的跳轉
 always@(posedge sys_clk or negedge sys_rst_n)
 if(sys_rst_n == 1'b0)
 addr <= 8'd0;
 else if(addr == 8'd255 && cnt_200ms == CNT_MAX)
 addr <= 8'd0;
 else if(addr_flag1 == 1'b1)
 addr <= 8'd99;
 else if(addr_flag2 == 1'b1)
 addr <= 8'd199;
 else if(cnt_200ms == CNT_MAX)
 addr <= addr + 1'b1;


 endmodule

產生addr_flag1:復位有效時addr_flag歸0;key2_flag拉高時addr_flag1歸0(因為key1與key2是互斥的,同一時間只能亮一個,所以不管key1現在是否按下去,key2一旦按下去就要以key2的地址為準了);key_flag1拉高時addr_flag1取反(因為可能存在連按兩次的情況,第一次按addr_flag1從第變高,第二次按就從高變低)。產生addr_flag1同理

200ms計數器:復位有效時歸0;計數到最大值時歸0;否則自加1

地址輸出:復位有效時addr為0;當addr為255且cnt200ms計數為最大值CNT_MAX時,addr為0(因為地址指向255后0.2ms要循環顯示地址0對應的數據);當addr_flag1拉高時addr為99;當addr_flag2拉高時addr為199;當計數器計到最大值時addr自加1

頂層模塊

實質是幾個模塊的實例化,需要注意的是key模塊使用了兩次,要實例化兩次,兩次實例化的模塊名字不能相同

之前的數碼管動態顯示的模塊框圖做一下修正

圖片

對比一下現在的模塊

圖片

1、之前的給數碼管模塊的輸入數據是data_gen這個模塊的輸出產生的,現在的data是rom的IP模塊產生的。且這個IP的輸出只有8位,而我們之前的設置的數碼管模塊data是27位,因此要補19個0能保證位數一致且對顯示沒有影響。還需要修改一處是top_seg_595模塊中實例化了data_gen,現在不需要了

2、之前的data_gen的輸出信號seg_en與seg_595_dynamic模塊的輸入信號seg_en相連,用于給數碼管顯示使能?,F在的rom_256x8模塊的實例化是系統IP自動生成的,沒有提供seg_en信號接口,需要自行設置這個信號為高電平讓他使能

頂層模塊代碼

module rom
(
input wire sys_clk , 
input wire sys_rst_n , 
input wire [1:0] key , 
output wire stcp , 
output wire shcp , 
output wire ds 
);


 //wire define
 wire [7:0] addr ; //地址線
 wire [7:0] rom_data ; //讀出ROM數據
 wire key1_flag ; //按鍵1消抖信號
 wire key2_flag ; //按鍵2消抖信號


 rom_ctrl rom_ctrl_inst
 (
 .sys_clk (sys_clk ),
 .sys_rst_n (sys_rst_n ), 
 .key1_flag (key1_flag ),
 .key2_flag (key2_flag ),
 .addr (addr )
 );


 key_filter key1_filter_inst
 (
 .sys_clk (sys_clk ), 
 .sys_rst_n (sys_rst_n ), 
 .key_in (key[0] ), 
 .key_flag (key1_flag ) 
 );


 key_filter key2_filter_inst
 (
 .sys_clk (sys_clk ), 
 .sys_rst_n (sys_rst_n ), 
 .key_in (key[1] ), 
 .key_flag (key2_flag ) 
 );


 seg_595_dynamic seg_595_dynamic_inst
 (
 .sys_clk (sys_clk ), 
 .sys_rst_n (sys_rst_n ), 
 .data ({19'd0,rom_data}), 
 .seg_en (1'b1 ), //數碼管使能信號,高電平有效
 .stcp (stcp ), //輸出數據存儲寄時鐘
 .shcp (shcp ), //移位寄存器的時鐘輸入
 .ds (ds )//串行數據輸入
 );


 rom_256x8 rom_256x8_inst
 (
 .address (addr ),
 .clock (sys_clk ),
 .q (rom_data )
 );


 endmodule

rom_ctrl模塊的實例化沒有什么需要特別注意的

key_filter模塊需要注意的是這兩個模塊名不能一樣,模塊都用的是key_filter,實例化后一個叫key1_filter_inst,一個叫key2_filter_inst。rom頂層模塊中定義的Key是一個2位的變量,兩個模塊中的Key_in就分別接key的高位和低位

數碼管動態顯示模塊:這個模塊是第三次使用了,因為之前的data是27位,現在只用了data的其中8位,剩下19位置0

rom_256x8模塊的實例化就是rom的ip核生成的inst.v實例化文件

圖片

Testbench

`timescale 1ns/1ns
module tb_rom();


//wire define
wire stcp;
wire shcp;
wire ds ;
//reg define
reg sys_clk ;
reg sys_rst_n ;
reg [1:0] key ;


//對sys_clk,sys_rst賦初值,并模擬按鍵抖動
initial
begin
sys_clk = 1'b1 ;
sys_rst_n <= 1'b0 ;
key <= 2'b11;
#200 sys_rst_n <= 1'b1 ;
//按下按鍵key[0]
#2000 key[0] <= 1'b0;//按下按鍵
#20 key[0] <= 1'b1;//模擬抖動
#20 key[0] <= 1'b0;//模擬抖動
#20 key[0] <= 1'b1;//模擬抖動
#20 key[0] <= 1'b0;//模擬抖動
#200 key[0] <= 1'b1;//松開按鍵
#20 key[0] <= 1'b0;//模擬抖動
#20 key[0] <= 1'b1;//模擬抖動
#20 key[0] <= 1'b0;//模擬抖動
#20 key[0] <= 1'b1;//模擬抖動
//按下按鍵key[1]
#2000 key[1] <= 1'b0;//按下按鍵
#20 key[1] <= 1'b1;//模擬抖動
#20 key[1] <= 1'b0;//模擬抖動
#20 key[1] <= 1'b1;//模擬抖動
#20 key[1] <= 1'b0;//模擬抖動
#200 key[1] <= 1'b1;//松開按鍵
#20 key[1] <= 1'b0;//模擬抖動
#20 key[1] <= 1'b1;//模擬抖動
#20 key[1] <= 1'b0;//模擬抖動
#20 key[1] <= 1'b1;//模擬抖動
//按下按鍵key[1]
#2000 key[1] <= 1'b0;//按下按鍵
#20 key[1] <= 1'b1;//模擬抖動
#20 key[1] <= 1'b0;//模擬抖動
#20 key[1] <= 1'b1;//模擬抖動
#20 key[1] <= 1'b0;//模擬抖動
#200 key[1] <= 1'b1;//松開按鍵
#20 key[1] <= 1'b0;//模擬抖動
#20 key[1] <= 1'b1;//模擬抖動
#20 key[1] <= 1'b0;//模擬抖動
#20 key[1] <= 1'b1;//模擬抖動
//按下按鍵key[1]
#2000 key[1] <= 1'b0;//按下按鍵
#20 key[1] <= 1'b1;//模擬抖動
#20 key[1] <= 1'b0;//模擬抖動
#20 key[1] <= 1'b1;//模擬抖動
#20 key[1] <= 1'b0;//模擬抖動
#200 key[1] <= 1'b1;//松開按鍵
#20 key[1] <= 1'b0;//模擬抖動
#20 key[1] <= 1'b1;//模擬抖動
#20 key[1] <= 1'b0;//模擬抖動
#20 key[1] <= 1'b1;//模擬抖動
//按下按鍵key[0]
#2000 key[0] <= 1'b0;//按下按鍵
#20 key[0] <= 1'b1;//模擬抖動
#20 key[0] <= 1'b0;//模擬抖動
#20 key[0] <= 1'b1;//模擬抖動
#20 key[0] <= 1'b0;//模擬抖動
#200 key[0] <= 1'b1;//松開按鍵
#20 key[0] <= 1'b0;//模擬抖動
#20 key[0] <= 1'b1;//模擬抖動
#20 key[0] <= 1'b0;//模擬抖動
#20 key[0] <= 1'b1;//模擬抖動
//按下按鍵key[0]
#2000 key[0] <= 1'b0;//按下按鍵
#20 key[0] <= 1'b1;//模擬抖動
#20 key[0] <= 1'b0;//模擬抖動
#20 key[0] <= 1'b1;//模擬抖動
#20 key[0] <= 1'b0;//模擬抖動
#200 key[0] <= 1'b1;//松開按鍵
#20 key[0] <= 1'b0;//模擬抖動
#20 key[0] <= 1'b1;//模擬抖動
#20 key[0] <= 1'b0;//模擬抖動
#20 key[0] <= 1'b1;//模擬抖動
end
//sys_clk:模擬系統時鐘,每10ns電平取反一次,周期為20ns,頻率為50MHz
always #10 sys_clk = ~sys_clk;


 //重新定義參數值,縮短仿真時間仿真
 defparam rom_inst.key1_filter_inst.CNT_MAX = 5 ;
 defparam rom_inst.key2_filter_inst.CNT_MAX = 5 ;
 defparam rom_inst.rom_ctrl_inst.CNT_MAX = 99;


 //---------------rom_inst--------------
 rom rom_inst
 (
 .sys_clk (sys_clk ), //系統時鐘,頻率50MHz
 .sys_rst_n (sys_rst_n ), //復位信號,低電平有效
 .key (key ), //輸入按鍵信號
 .stcp (stcp ), //輸出數據存儲寄時鐘
 .shcp (shcp ), //移位寄存器的時鐘輸入
 .ds (ds ) //串行數據輸入
 );


 endmodule

初始化:時鐘為高電平,復位為低電平,按鍵都為高電平表示未按下

延遲200ns后復位釋放

延遲2000ns后按下按鍵1但是模擬抖動,抖動中有200ns的按鍵是按下狀態以便識別并拉高flag

再重復模擬按下按鍵2,2,2,1,1

重新定義參數,縮短仿真時間

rom模塊實例化

波形變化

圖片

圖片

管腳分配

圖片

圖片

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • FPGA
    +關注

    關注

    1626

    文章

    21678

    瀏覽量

    602037
  • 鎖相環
    +關注

    關注

    35

    文章

    583

    瀏覽量

    87699
  • 存儲器
    +關注

    關注

    38

    文章

    7455

    瀏覽量

    163623
  • ROM
    ROM
    +關注

    關注

    4

    文章

    562

    瀏覽量

    85679
  • IP核
    +關注

    關注

    4

    文章

    326

    瀏覽量

    49434
收藏 人收藏

    評論

    相關推薦

    關于FPGA IP

    對于深入學習使用FPGA的小伙伴們,特別是一些復雜的、大規模的設計應用,適宜的IP核對開發能起到事半功倍的作用。IP的概念與我們sdk里庫
    發表于 04-29 21:01

    FPGAIP使用技巧

    的工作原理、使用方法和限制條件。 參數化配置 : 如果IP提供了參數化配置選項,可以根據項目需求進行配置。例如,對于RAM IP
    發表于 05-27 16:13

    FPGA IP的相關問題

    我用的是xinlinx spartan6 FPGA,我想知道它的IPRAM是與FPGA獨立的,只是集成在了一起呢,還是占用了FPGA的資源
    發表于 01-10 17:19

    關于ip生成的rom

    用quartus ii 中自帶的ip創建了一個rom,并加載了初始的hex數據。當我從rom中讀出數據的時候,發現前面兩個地址(0000,0001)的輸出數據不正確,0002輸出數據
    發表于 05-14 14:38

    【鋯石A4 FPGA試用體驗】IPROM(二)創建ROM IP

    前面建好了mif文件,下面就要創建ROM IP了。首先,我們新建一個工程。菜單欄:Tools --> MegaWizardPlug-InManager ,點擊“Next”選擇ROM
    發表于 09-25 09:38

    xilinx FPGA的FFT IP的調用

    有沒有大神可以提供xilinx FPGA的FFT IP的調用的verilog 的參考程序,最近在學習FFT的IP
    發表于 12-25 17:05

    LabVIEW FPGA CORDIC IP的arctan使用方法

    使用LabVIEW FPGA模塊中的CORDIC IP,配置arctan(X/Y)算法,配置完成之后,IP只有一個輸入。我參考網上VHD
    發表于 09-10 20:07

    【夢翼師兄今日分享】 只讀儲存器ROM IP的調取及應用

    和大家一起學習FPGA只讀存儲器IP-ROM的設計。項目需求設計一個ROM控制器,該控制器負責
    發表于 12-16 17:18

    使用Vivado調用ROM IP

      本例程主要使用Vivado 調用ROM IP,用含有正弦曲線的.coe文件初始化ROM,最終通過仿真實現波形的顯示  一、首先建立工程      二、選擇芯片的型號  我
    發表于 01-08 17:16

    基于IPFPGA設計方法是什么?

    的分類和特點是什么?基于IPFPGA設計方法是什么?
    發表于 05-08 07:07

    FPGA零基礎學習IP CORE 之 ROM設計

    學習FPGA設計方法及設計思想的同時,實操結合各類操作軟件,會讓你在技術學習道路上無比的順暢,告別技術學習小BUG卡破腦殼,告別目前忽悠性
    發表于 03-13 15:46

    FPGAIP的生成

    FPGAIP的生成,簡單介紹Quartus II生成IP的基本操作,簡單實用挺不錯的資料
    發表于 11-30 17:36 ?11次下載

    FPGA學習:使用matlab和ISE 創建并仿真ROM IP

    大家好,又到了每日學習的時間了,今天我們來聊一聊使用matlab和ISE 創建并仿真ROM IP。本人想使用簡單的中值濾波進行verilog相關算法的硬件實現,由于HDL設計軟件不能
    的頭像 發表于 10-25 20:20 ?3790次閱讀
    <b class='flag-5'>FPGA</b><b class='flag-5'>學習</b>:使用matlab和ISE 創建并仿真<b class='flag-5'>ROM</b> <b class='flag-5'>IP</b><b class='flag-5'>核</b>

    FPGA學習筆記:PLL IP使用方法

    IP(Intellectual Property)是知識產權的意思,半導體行業的IP是“用于ASIC或FPGA中的預先設計好的電路功能模塊”。一些常用的復雜的功能模塊(如FIFO、RAM、FIR
    的頭像 發表于 08-22 15:04 ?4552次閱讀
    <b class='flag-5'>FPGA</b><b class='flag-5'>學習</b><b class='flag-5'>筆記</b>:PLL <b class='flag-5'>IP</b><b class='flag-5'>核</b>的<b class='flag-5'>使用方法</b>

    FPGA學習筆記:RAM IP使用方法

    我們知道除了只讀存儲器外還有隨機存取存儲器,這一篇將介紹另一種 存儲類IP ——RAM的使用方法。RAM是 隨機存取存儲器 (Random Access Memory),是一個易失性存儲器,斷電丟失。RAM工作時可以隨時從任何
    的頭像 發表于 08-29 16:46 ?3481次閱讀
    <b class='flag-5'>FPGA</b><b class='flag-5'>學習</b><b class='flag-5'>筆記</b>:RAM <b class='flag-5'>IP</b><b class='flag-5'>核</b>的<b class='flag-5'>使用方法</b>