基于FPGA的實時圖像處理系統(1)——SDRAM回環測試

SDRAM回環設計

文章目錄

  • SDRAM回環設計
    • 一、SDRAM簡介
      • 1、引腳
      • 2、內部結構框圖
      • 3、操作指令
    • 二、系統設計
    • 三、實現流程
      • 1、SDRAM接口
      • 2、FIFO設置
      • 3、內部SDRAM的控制模塊
      • 4、其他
    • 四、實現效果
    • 五、總結
    • 六、代碼
      • 1、top
      • 2、sdram_top
      • 3、sdram_ctrl

一、SDRAM簡介

SDRAM英文全稱“Synchronous Dynamic Random Access Memory”,譯為“同步動態隨機存取內存”或“同步動態隨機存儲器”,是動態隨機存儲器(Dynamic Random Access Memory,簡稱DRAM)家族的一份子。同步、動態、隨機是其性能特點的外在說明,也是其區別其他存儲器的特色標簽。這三個概念性的標簽,我們要好好理解掌握。

同步(Synchronous):與通常的異步DRAM不同, SDRAM存在一個同步接口,其工作時鐘的時鐘頻率與對應控制器(CPU/FPGA)的時鐘頻率相同,并且SDRAM內部的命令發送與數據傳輸均以此時鐘為基準,實現指令或數據的同步操作;

動態(Dynamic): SDRAM需要不斷的刷新來保證存儲陣列內數據不丟失;

隨機(Random):數據在SDRAM中并不是按照線性依次存儲,而是可以自由指定地址進行數據的讀寫。

空間存儲量大、讀寫速度快以及價格相對便宜等優點使其在存儲界屹立不倒、經久不衰,廣泛應用在計算機中。隨著時代的不斷發展、技術的不斷更新,SDRAM使用至今已過數十載,產品更新歷經五代,分別是:第一代SDR SDRAM,第二代DDR SDRAM,第三代DDR2 SDRAM,第四代DDR3 SDRAM,第五代,DDR4 SDRAM。

第一代SDR SDRAM采用單端時鐘信號,SDRAM只在時鐘的上升沿進行數據采樣;而后面的四代SDRAM由于工作頻率比較快,所以采用可降低干擾的差分時鐘信號作為同步時鐘,雙沿采樣,速度更快,且功耗更低。同時技術的不斷發展、制造工藝的不斷提高,使得五代SDRAM的更新過程中,集成度越來越高、內核電壓越來越低(SDR:3.3V 、DDR:2.5V、DDR2:1.8V、DDR3:1.5V、DDR4:1.2V),這也是SDRAM速度提高、功耗降低的重要原因。

本次運用的SDRAM為海力士公司的H57V2562GTR-75C,內存大小為256Mbit,有4個bank,每個bank有4M(8192行*512列)存儲單元,每個單元可存16bit數據

1、引腳

信號類型描述
clkin時鐘,所有其他輸入在CLK的上升沿被寄存到SDRAM
ckein時鐘使能,控制內部時鐘信號,當禁用時,SDRAM將處于電源關閉、暫停或自刷新狀態之一
cs_nin片選,啟用或禁用除CLK、CKE和DQM之外的所有輸入
BA0,BA1inbank地址線
A0-A12in行列地址線,行地址:RA0 ~ RA12,列地址:CA0 ~ CA8自動預充電標志:A10
RAS_n,CAS_n,WE_Nin行地址選通,列地址選通,寫使能
LDQM,UDQMI/O數據掩碼,16位高低字節,可控制讀寫數據
DQ0-DQ15I/O數據輸入輸出

2、內部結構框圖

在這里插入圖片描述
由圖可知,SDRAM內部包含一個狀態機左上角state machine),外部通過控制CS_N、RAS_N、CAS_N、WE_N、A0-A12數據地址線以及BA0、BA1 BANK地址線來發送命令,命令經過解碼器進行譯碼后,將控制參數保存到模式寄存器中,邏輯控制單元進而控制邏輯運行。

外部通過地址總線輸入地址信息,地址信息在邏輯控制單元進行邏輯控制時起到輔助作用,除此之外,復用的地址總線與Bank控制邏輯、行地址復用器、列地址計數鎖存器、列地址解碼器等內部器件共同作用,精確選定存儲陣列中與行列地址相對應的存儲單元,進而進行數據存取操作。

DQM數據掩碼線控制這數據是否有效,其又L低位與U高位兩條線,每條控制著8bit數據。

DQ0-DQ15為數據線,其為雙向,讀寫共用一條線。

3、操作指令

在這里插入圖片描述

1、預充電(precharge)

預充電命令:關閉特定bank中激活的行,或關閉所有bank中激活的行。

A10決定預充電模式:

當預充電命令中的地址A10為高時,預充電所有bank;當預充電命令中A10為低時,預充電特定bank。

當write/read命令中的A10為高時,自動預充電(auto-precharge)被使能;反之。

預充電命令發送之后,這些bank等待tRP才能接收命令

2、自動預充電(auto-precharge)

自動預充電是非顯示命令,即使能自動預充電是需要發送write/read命令時將地址中A10拉高,在讀寫

突發結束后,立即預充電那個bank/row。

3、NOP

NOP 指令用以表明對 sdram 芯片(CS# == 0)進行空操作。NOP 指令的目的是在 sdram 在空閑

或者等待狀態下,避免去執行一些潛在的不需要的指令。已經在執行過程中的指令不受影響。

4、自動刷新(auto-refresh)與自刷新(self-refresh)

為使數據不丟失,電容的兩次刷新時間不能超過64ms,刷新都是針對行的。共性:都不需要外部提供地址信息,SDRAM內部有一個行地址生成器(刷新計數器)。刷新都是針對

一行的,不需要對列地址尋址,但也不需要對行進行尋址,因為內部有刷新計數器

自動刷新:SDRAM正常工作模式中為了數據不丟失進行的操作,需要外部時鐘參與,刷新的行地址也

是由內部刷新計算器控制

自刷新:休眠模式低功耗狀態下存儲數據,不需要外部時鐘參與,刷新的行地址內部刷新計算器控

制。

發送自動刷新命令需要的時間為tRRC(自動刷新周期),由于是對行操作,等效于行選通時間(RAS)

SDRAM中每次刷新操作所需要的時間為自動刷新周期(tRC),在自動刷新指令發出后需要等待tRC才能發

送其他指令。

5、行激活

行激活命令也叫做bank激活命令,作用是在指定bank中激活一行;

行激活后會一直處于激活狀態(即列尋址處于激活狀態),直到預充電命令被發送到這個bank;

行激活命令之后,需要延時tRCD(即發出行地址到發出列地址的時間間隔),才能發送READ/WRITE命令(讀寫操作必須先激活對應bank)

6、讀操作

讀數據命令用來開啟數據的突發讀,bank,row都可選,注意A10的值決定是否執行自動預充電操作,若執行自動預充電,突發讀結束后就進行預充電,此行關閉,若不執行自動預充電,該行保持激活,仍能被訪問。

CAS latency :讀延遲(讀潛伏周期,CL)Burst length:突發長度(BL)

讀命令發出后,輸出buffer(理解為SDRAM的dq_out)會在(CL-1)個時鐘后期后變為低阻,然后會在突發讀結束后重新變為高阻態,

7、寫操作

DM(數據掩碼)高有效,當為低時,數據能正確被寫入DM;當為高時,數據將被忽略。

寫突發時,第一個數據與寫命令同步;

突發寫–>預充電中間需要間隔tDPL。

二、系統設計

在這里插入圖片描述
所實現功能 :pc發送數據,存入fifo的數據達到所設閾值,進行突發寫操作(此處用的ip核不支持多bit突發讀寫操作,故在控制模塊中實現突發讀寫操作),當按鍵(經過消抖)按下,進行突發讀操作,將讀取的數據發送回pc顯示出來。

三、實現流程

1、SDRAM接口

在這里插入圖片描述

SDRAM接口部分由ip核實現
1) 選擇Platform Designer
在這里插入圖片描述
2) 在左上角處搜索sdram,在下方雙擊選中ip添加
在這里插入圖片描述
3) 配置各個參數
在這里插入圖片描述
本次運用的SDRAM的數據寬度為16bit,有4個bank,每個bank有13行9列

在這里插入圖片描述

參數含義典型值意義
CAS latency cycles讀命令發出后,到第一個有效數據出現在總線上的時鐘周期數設為 3 → 3 個時鐘
Initialization refresh cycles上電后、正式初始化前,控制器自動發出的 Auto-Refresh 命令次數8 次
Issue one refresh command every兩次刷新命令之間的間隔時間7.8 μs(SDRAM 要求 64 ms 內刷完所有行,因此 7.8 μs/行≈8192 行)
Delay after powerup, before initialization芯片上電穩定后再開始初始化的等待時間200 μs(JEDEC 規范建議 ≥100 μs)
Duration of refresh command (t_rfc)單個 Auto-Refresh 命令占用總線的最短時間70 ns
Duration of precharge command (t_rp)關閉當前行(Precharge)所需時間20 ns
ACTIVE to READ or WRITE delay (t_rcd)行激活到列讀/寫命令之間的最小間隔20 ns
Access time (t_ac)時鐘沿到數據有效輸出的延遲(器件參數,非用戶設)5 ns
Write recovery time (t_wr)寫命令結束后到允許 Precharge 的最小間隔20 ns

配置完如下

在這里插入圖片描述
4) 點擊右下角finish左邊按鈕出現以下界面

在這里插入圖片描述
改為生成verilog代碼,路徑自行選擇,更改完成點擊生成,等待完成,等待時間因電腦配置有差異

在這里插入圖片描述

生成完成,依次點擊close、finish

5) finish后出現以下界面提示添加文件

在這里插入圖片描述
添加完成在ip查看界面才會有顯示

在這里插入圖片描述

生成的例化模板:

	sdram_ip u0 (.clk_clk           (), //   clk.clk.reset_reset_n     (), // reset.reset_n.sdram_addr        (), // sdram.addr.sdram_ba          (), //      .ba.sdram_cas_n       (), //      .cas_n.sdram_cke         (), //      .cke.sdram_cs_n        (), //      .cs_n.sdram_dq          (), //      .dq.sdram_dqm         (), //      .dqm.sdram_ras_n       (), //      .ras_n.sdram_we_n        (), //      .we_n.avs_address       (), //   avs.address.avs_byteenable_n  (), //      .byteenable_n.avs_chipselect    (), //      .chipselect.avs_writedata     (), //      .writedata.avs_read_n        (), //      .read_n.avs_write_n       (), //      .write_n.avs_readdata      (), //      .readdata.avs_readdatavalid (), //      .readdatavalid.avs_waitrequest   () //      .waitrequest);
端口名稱方向位寬含義說明
clk_clkinput1全局系統時鐘,用于 SDRAM 控制器內部邏輯以及 SDRAM 芯片。
reset_reset_ninput1全局異步復位,低有效。
sdram_addr[12:0]output13SDRAM 地址總線,行列地址復用。
sdram_ba[1:0]output2Bank 地址,選擇 SDRAM 的 4 個 bank。
sdram_cas_noutput1列地址選通,低有效。
sdram_ckeoutput1時鐘使能,高時 SDRAM 響應時鐘。
sdram_cs_noutput1片選,低有效。
sdram_dq[15:0]inout16雙向數據總線。
sdram_dqm[1:0]output2數據掩碼/字節使能,對應 16bit 數據的高低字節。
sdram_ras_noutput1行地址選通,低有效。
sdram_we_noutput1寫使能,低有效。
avs_address[21:0]input22Avalon-MM 總線地址(字節地址)。
avs_byteenable_n[1:0]input2字節使能,低有效,對應 16bit 數據高低字節。
avs_chipselectinput1Avalon-MM 片選,高有效。
avs_writedata[15:0]input16寫數據。
avs_read_ninput1讀請求,低有效。
avs_write_ninput1寫請求,低有效。
avs_readdata[15:0]output16讀回數據。
avs_readdatavalidoutput1讀數據有效指示,高有效。
avs_waitrequestoutput1控制器忙,拉低時表示需要等待。

sdram前綴為輸出給sdram芯片的接口,avs前綴為內部的控制的Avalon協議接口。

2、FIFO設置

//---------<寫FIFO例化>------------------------------------------------- wr_fifo	wr_fifo_inst (.aclr       ( ~rst_n        ),.data       ( {2{rx_data}}  ),.rdclk      ( clk           ),.rdreq      ( wr_rden       ),.wrclk      ( clk_in        ),.wrreq      ( wr_wren       ),.q          ( wr_q          ),.rdempty    ( wr_rdempty    ),.rdusedw    ( wr_rdusedw    ),.wrfull     ( wr_wrfull     ));assign  wr_wren = ~wr_wrfull && rx_vld;
assign  wr_rden = ~wr_rdempty && (state_c == WRITE) && ~avm_waitrequest;

由于所設置SDRAM寬度為16,但uart_rx傳入為8bit,所以拼兩個傳入的數據存入SDRAM。

寫使能(wr_wren):fifo未滿且rx傳入的數據有效,就將數據寫入fifo
讀使能(wr_rden):fifo不空且處于寫狀態,且sdram處于不忙狀態(waitrequest為低)將數據傳給sdram

//---------<讀FIFO例化>------------------------------------------------- rd_fifo	rd_fifo_inst (.aclr       ( ~rst_n        ),.data       ( avm_readdata  ),.rdclk      ( clk_out       ),.rdreq      ( rd_rden       ),.wrclk      ( clk           ),.wrreq      ( rd_wren       ),.q          ( rd_q          ),.rdempty    ( rd_rdempty    ),.wrfull     ( rd_wrfull     )
);assign  rd_wren = ~rd_wrfull && avm_readdatavalid;
assign  rd_rden = ~rd_rdempty && tx_done;

寫使能(rd_wren):fifo未滿且sdram處于不忙狀態(waitrequest為低)將數據傳給讀fifo
讀使能(rd_rden):fifo不空且tx發送模塊不忙,將數據傳給tx發送到pc

3、內部SDRAM的控制模塊

在這里插入圖片描述
由于uart時鐘與sdram的時鐘不同,這里用了兩個異步fifo,一個用于寫,一個用于讀;wrfifo寫側為uart_rx輸入的系統時鐘,即為clk_in,讀側為輸出到sdram的時鐘,為clk_100m;rdfifo寫側為sdram傳出的數據,時鐘為clk_100m,讀側為通過uart_tx傳回pc的數據接口,時鐘為系統時鐘。

在此設置一個簡單的狀態機實現讀寫操作,此處的burst_lenth為 10。

//---------<突發計數器>------------------------------------------------- always @(posedge clk or negedge rst_n)begin if(!rst_n)begincnt_burst <= 'd0;end else if(add_cnt_burst)begin if(end_cnt_burst)begin cnt_burst <= 'd0;endelse begin cnt_burst <= cnt_burst + 1'b1;end end
end assign add_cnt_burst = ((state_c == READ) || (state_c == WRITE)) && ~avm_waitrequest;
assign end_cnt_burst = add_cnt_burst && cnt_burst == (BURST_LENTH-1);

在這里插入圖片描述
當按鍵按下進入讀數據狀態,開始從sdram讀取數據,當讀fifo中讀了10個數據時跳出。
當寫fifo的數據大于所設突發操作的閾值,就進行寫入操作,跳轉到write狀態,將10個數據寫入sdram,寫完10個后跳到空閑狀態。

讀寫地址通過計數器實現

//---------<讀寫地址>------------------------------------------------- 
//寫地址計數
always @(posedge clk or negedge rst_n)begin if(!rst_n)beginwr_addr <= 'd0;end else if(add_wr_addr)begin if(end_wr_addr)begin wr_addr <= 'd0;endelse begin wr_addr <= wr_addr + 1'b1;end end
end assign add_wr_addr = (state_c == WRITE) && ~avm_waitrequest;
assign end_wr_addr = add_wr_addr && wr_addr == 24'hff_ff_ff-1;//讀地址計數
always @(posedge clk or negedge rst_n)begin if(!rst_n)beginrd_addr <= 'd0;end else if(add_rd_addr)begin if(end_rd_addr)begin rd_addr <= 'd0;endelse begin rd_addr <= rd_addr + 1'b1;end end
end assign add_rd_addr = (state_c == READ) && ~avm_waitrequest;
assign end_rd_addr = add_rd_addr && rd_addr == 24'hff_ff_ff-1;

由于地址線共用,所以要判斷現在是讀狀態還是寫狀態

//---------<狀態判斷>------------------------------------------------- 
assign  avm_address = (state_c == WRITE) ?  {wr_addr[23],wr_addr[21:9],wr_addr[22],wr_addr[8:0]} : {rd_addr[23],rd_addr[21:9],rd_addr[22],rd_addr[8:0]} ;

其他輸出

assign  tx_data = rd_q [7:0];
assign  tx_vld  = rd_rden;
assign  avm_writedata = wr_q;
assign  avm_read_n = ~(state_c == READ);
assign  avm_write_n = ~(state_c == WRITE);

4、其他

其他模塊復用之前的。

四、實現效果

在這里插入圖片描述
直接按下按鍵讀出錯亂的數據,按下復位,發送數據,將數據寫入sdram

在這里插入圖片描述
按下兩次按鍵讀出數據

在這里插入圖片描述
讀出的20個數據與發送的前20個相同,驗證成功。

五、總結

相較于之前的幾個存儲器來說,sdram是并行的,且有其他的各種信號,端口較多比較復雜,且內部要用avalon協議傳輸數據,連線和數據之間的傳輸較為復雜,需要認真理解,本實驗主要目的為理解sdram的操作和工作原理。

六、代碼

1、top

/*******************************************************************
Engineer: Turing_kun
Create Date: 2025-07-30 14:03:14
Description: 項目頂層
********************************************************************/module top (input               clk             ,input               rst_n           ,input    [1:0]      sw              ,
//---------<sdram>------------------------------------------------- output   [12:0]     sdram_addr      ,output   [1:0]      sdram_ba        ,output              sdram_cas_n     ,output              sdram_cke       ,output              sdram_cs_n      ,inout    [15:0]     sdram_dq        ,output   [1:0]      sdram_dqm       ,output              sdram_ras_n     ,output              sdram_we_n      ,output              sdram_clk       ,
//---------<uart>------------------------------------------------- input               rx              ,output              tx              ,
//---------<key>------------------------------------------------- input    [0:0]      key_in
);wire            clk_100ms;
wire            clk_100ms_s;
wire            locked;//---------<uart_rx>------------------------------------------------- 
wire    [7:0]   rx_data;
wire            rx_vld;
//---------<uart_tx>------------------------------------------------- 
wire    [7:0]   tx_data;
wire            tx_vld;
wire            tx_done;
//---------<key>-------------------------------------------------
wire            key_down; assign sdram_clk = clk_100ms_s;
sdram_top   inst_sdram_top(.clk        (clk_100ms  ),.clk_in     (clk        ),.clk_out    (clk        ),.rst_n      (rst_n      ),.rx_data    (rx_data    ),.rx_vld     (rx_vld     ),.tx_done    (tx_done    ),.tx_data    (tx_data    ),.tx_vld     (tx_vld     ),.key_down   (key_down   ),.sdram_addr (sdram_addr ),.sdram_ba   (sdram_ba   ),.sdram_cas_n(sdram_cas_n),.sdram_cke  (sdram_cke  ),.sdram_cs_n (sdram_cs_n ),.sdram_dq   (sdram_dq   ),.sdram_dqm  (sdram_dqm  ),.sdram_ras_n(sdram_ras_n),.sdram_we_n (sdram_we_n )
);sdram_pll	sdram_pll_inst (.areset ( ~rst_n ),.inclk0 ( clk ),.c0     ( clk_100ms    ),.c1     ( clk_100ms_s   ),.locked ( locked ));uart_rx     inst_uart_rx(.clk     (clk     ),.rst_n   (rst_n   ),.rx      (rx      ),.sw      (sw      ),.rx_data (rx_data ),.rx_done (rx_vld  )
);uart_tx     inst_uart_tx(.clk     (clk     ),.rst_n   (rst_n   ),.tx_data (tx_data ),.tx_start(tx_vld  ),.sw      (sw      ),.tx      (tx      ),.tx_done (tx_done )
);fsm_key     inst_fsm_key(.clk		(clk    ),.rst_n	    (rst_n	),.key_in	    (key_in	),.key_down   (key_down)
);
endmodule

2、sdram_top

/*******************************************************************
Engineer: Turing_kun
Create Date: 2025-07-30 14:02:40
Description: SDRAM子頂層
********************************************************************/module sdram_top( input               clk             ,   //100mHzinput               clk_in          ,   //50mHzinput               clk_out         ,   //50mHzinput               rst_n           ,
//---------<uart_rx>------------------------------------------------- input    [7:0]      rx_data         ,input               rx_vld          ,
//---------<uart_tx>------------------------------------------------- input               tx_done         ,output   [7:0]      tx_data         ,output              tx_vld          ,
//---------<key>------------------------------------------------- input               key_down        ,
//---------<sdram_ip>-------------------------------------------------      output   [12:0]     sdram_addr      ,output   [1:0]      sdram_ba        ,output              sdram_cas_n     ,output              sdram_cke       ,output              sdram_cs_n      ,inout    [15:0]     sdram_dq        ,output   [1:0]      sdram_dqm       ,output              sdram_ras_n     ,output              sdram_we_n      
);wire    [23:0]    avm_address           ;
wire    [15:0]    avm_writedata         ;
wire              avm_read_n            ;
wire              avm_write_n           ;
wire    [15:0]    avm_readdata          ;
wire              avm_readdatavalid     ;
wire              avm_waitrequest       ;sdram_ctrl      inst_sdram_ctrl(.clk              (clk              ),.clk_in           (clk_in           ),.clk_out          (clk_out          ),.rst_n            (rst_n            ),.rx_data          (rx_data          ),.rx_vld           (rx_vld           ),.tx_done          (tx_done          ),.tx_data          (tx_data          ),.tx_vld           (tx_vld           ),.key_down         (key_down         ),.avm_address      (avm_address      ),.avm_writedata    (avm_writedata    ),.avm_read_n       (avm_read_n       ),.avm_write_n      (avm_write_n      ),.avm_readdata     (avm_readdata     ),.avm_readdatavalid(avm_readdatavalid),.avm_waitrequest  (avm_waitrequest  )
);sdram_ip        inst_sdram_ip(.avs_address      (avm_address      ),      .avs_byteenable_n (2'b00            ), .avs_chipselect   (1'b1             ),   .avs_writedata    (avm_writedata    ),    .avs_read_n       (avm_read_n       ),       .avs_write_n      (avm_write_n      ),      .avs_readdata     (avm_readdata     ),     .avs_readdatavalid(avm_readdatavalid),.avs_waitrequest  (avm_waitrequest  ),  .clk_clk          (clk              ),          .reset_reset_n    (rst_n            ),    .sdram_addr       (sdram_addr       ),       .sdram_ba         (sdram_ba         ),         .sdram_cas_n      (sdram_cas_n      ),      .sdram_cke        (sdram_cke        ),        .sdram_cs_n       (sdram_cs_n       ),       .sdram_dq         (sdram_dq         ),         .sdram_dqm        (sdram_dqm        ),        .sdram_ras_n      (sdram_ras_n      ),      .sdram_we_n       (sdram_we_n       ) 
);    endmodule

3、sdram_ctrl

/*******************************************************************
Engineer: Turing_kun
Create Date: 2025-07-30 14:05:40
Description: SDRAM控制模塊
********************************************************************/module sdram_ctrl #(parameter BURST_LENTH = 10)(input               clk                 ,   //100mHzinput               clk_in              ,   //50mHzinput               clk_out             ,   //50mHzinput               rst_n               ,
//---------<uart_rx>---------------------------------input    [7:0]      rx_data             ,input               rx_vld              ,
//---------<uart_tx>---------------------------------input               tx_done             ,output   [7:0]      tx_data             ,output              tx_vld              ,
//---------<key>-------------------------------------input               key_down            ,
//---------<sdram_ip>------------------------------------------------- output    [23:0]    avm_address         ,      output    [15:0]    avm_writedata       ,    output              avm_read_n          ,output              avm_write_n         ,input     [15:0]    avm_readdata        ,input               avm_readdatavalid   ,input               avm_waitrequest     
);//rd_fifo
wire                    rd_rden     ;
wire                    rd_wren     ;
wire        [15:0]      rd_q        ;
wire                    rd_rdempty  ;
wire                    rd_wrfull   ;//wr_fifo
wire                    wr_rden     ;
wire                    wr_wren     ;
wire        [15:0]      wr_q        ;
wire                    wr_rdempty  ;
wire                    wr_wrfull   ;
wire        [8:0]       wr_rdusedw  ;//---------<狀態參數>------------------------------------------------- reg     [1:0]   state_c ;
reg     [1:0]   state_n ;localparam              IDLE    =       2'd0,READ    =       2'd1,WRITE   =       2'd2,DONE    =       2'd3;wire                    IDLE_2_READ;
wire                    READ_2_DONE;
wire                    IDLE_2_WRITE;
wire                    WRITE_2_DONE;reg		[8:0]	cnt_burst	    ;
wire			add_cnt_burst   ;
wire			end_cnt_burst   ;//寫地址
reg		[23:0]	wr_addr	   ;
wire			add_wr_addr;
wire			end_wr_addr;
//讀地址
reg		[23:0]	rd_addr	   ;
wire			add_rd_addr;
wire			end_rd_addr;//---------<讀FIFO例化>------------------------------------------------- rd_fifo	rd_fifo_inst (.aclr       ( ~rst_n        ),.data       ( avm_readdata  ),.rdclk      ( clk_out       ),.rdreq      ( rd_rden       ),.wrclk      ( clk           ),.wrreq      ( rd_wren       ),.q          ( rd_q          ),.rdempty    ( rd_rdempty    ),.wrfull     ( rd_wrfull     )
);assign  rd_wren = ~rd_wrfull && avm_readdatavalid;
assign  rd_rden = ~rd_rdempty && tx_done;//---------<寫FIFO例化>------------------------------------------------- wr_fifo	wr_fifo_inst (.aclr       ( ~rst_n        ),.data       ( {2{rx_data}}  ),.rdclk      ( clk           ),.rdreq      ( wr_rden       ),.wrclk      ( clk_in        ),.wrreq      ( wr_wren       ),.q          ( wr_q          ),.rdempty    ( wr_rdempty    ),.rdusedw    ( wr_rdusedw    ),.wrfull     ( wr_wrfull     ));assign  wr_wren = ~wr_wrfull && rx_vld;
assign  wr_rden = ~wr_rdempty && (state_c == WRITE) && ~avm_waitrequest;//---------<突發計數器>------------------------------------------------- always @(posedge clk or negedge rst_n)begin if(!rst_n)begincnt_burst <= 'd0;end else if(add_cnt_burst)begin if(end_cnt_burst)begin cnt_burst <= 'd0;endelse begin cnt_burst <= cnt_burst + 1'b1;end end
end assign add_cnt_burst = ((state_c == READ) || (state_c == WRITE)) && ~avm_waitrequest;
assign end_cnt_burst = add_cnt_burst && cnt_burst == (BURST_LENTH-1);//---------<state>------------------------------------------------- //第一段:同步時序描述狀態轉移
always @(posedge clk or negedge rst_n)begin if(!rst_n)beginstate_c <= IDLE;end else begin state_c <= state_n;end 
end//第二段:組合邏輯判斷狀態轉移條件,描述狀態轉移規律
always @(*) begincase(state_c)IDLE  : beginif(IDLE_2_READ)state_n = READ;else if(IDLE_2_WRITE)state_n = WRITE;else state_n = state_c;endREAD  : state_n = (READ_2_DONE ) ? DONE : state_c;WRITE : state_n = (WRITE_2_DONE) ? DONE : state_c;DONE  : state_n = IDLE;default : state_n = IDLE;endcase
endassign      IDLE_2_READ     =   (state_c == IDLE ) && key_down;
assign      READ_2_DONE     =   (state_c == READ ) && end_cnt_burst;
assign      IDLE_2_WRITE    =   (state_c == IDLE ) && wr_rdusedw >= BURST_LENTH;
assign      WRITE_2_DONE    =   (state_c == WRITE) && end_cnt_burst;//---------<讀寫地址>------------------------------------------------- 
//寫地址計數
always @(posedge clk or negedge rst_n)begin if(!rst_n)beginwr_addr <= 'd0;end else if(add_wr_addr)begin if(end_wr_addr)begin wr_addr <= 'd0;endelse begin wr_addr <= wr_addr + 1'b1;end end
end assign add_wr_addr = (state_c == WRITE) && ~avm_waitrequest;
assign end_wr_addr = add_wr_addr && wr_addr == 24'hff_ff_ff-1;//讀地址計數
always @(posedge clk or negedge rst_n)begin if(!rst_n)beginrd_addr <= 'd0;end else if(add_rd_addr)begin if(end_rd_addr)begin rd_addr <= 'd0;endelse begin rd_addr <= rd_addr + 1'b1;end end
end assign add_rd_addr = (state_c == READ) && ~avm_waitrequest;
assign end_rd_addr = add_rd_addr && rd_addr == 24'hff_ff_ff-1;//---------<tx_data tx_vld>------------------------------------------------- 
assign  tx_data = rd_q [7:0];
assign  tx_vld  = rd_rden;//---------<狀態判斷>------------------------------------------------- 
assign  avm_address = (state_c == WRITE) ?  {wr_addr[23],wr_addr[21:9],wr_addr[22],wr_addr[8:0]} : {rd_addr[23],rd_addr[21:9],rd_addr[22],rd_addr[8:0]} ;assign  avm_writedata = wr_q;
assign  avm_read_n = ~(state_c == READ);
assign  avm_write_n = ~(state_c == WRITE);
endmodule

其他復用之前的項目

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/919046.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/919046.shtml
英文地址,請注明出處:http://en.pswp.cn/news/919046.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

一鍵檢測接口是否存活:用 Python/Shell 寫個輕量級監控腳本

網羅開發&#xff08;小紅書、快手、視頻號同名&#xff09;大家好&#xff0c;我是 展菲&#xff0c;目前在上市企業從事人工智能項目研發管理工作&#xff0c;平時熱衷于分享各種編程領域的軟硬技能知識以及前沿技術&#xff0c;包括iOS、前端、Harmony OS、Java、Python等方…

優秀工具包-Hutool工具詳解

優秀工具包-Hutool工具詳解 課程概述 Hutool簡介 定位&#xff1a; 小而全的Java工具庫&#xff0c;簡化開發流程。對文件、流、加密解密、轉碼、正則、線程、XML等JDK方法進行封裝。 核心優勢&#xff1a;零依賴、高性能、中文網頁完善。 應用場景&#xff1a;Web開發、數…

《深度解構:構建瀏覽器端Redis控制臺的WebSocket協議核心技術》

Redis作為高性能的內存數據庫,其原生客戶端多依賴命令行或桌面應用,而瀏覽器端控制臺的缺失,成為制約Web化管理的關鍵瓶頸,WebSocket協議的出現,打破了HTTP協議單向通信的局限,為瀏覽器與Redis服務之間建立持久、雙向的實時連接提供了可能。本文將從協議本質、交互邏輯、…

Pushgateway安裝和部署,以及對應Prometheus調整

目錄Pushgateway簡介安裝驗證Prometheus的配置&#xff1a;其它命令Pushgateway簡介 Pushgateway 是 Prometheus 生態系統中的一個組件。主要特點是推送而非拉取&#xff1a;Prometheus 默認采用拉取&#xff08;pull&#xff09;模式收集指標&#xff0c;但 Pushgateway 允許…

JAVA面試匯總(四)JVM(一)

久違的重新寫了一篇面試匯總的&#xff0c;關于JVM的一篇&#xff0c;一共三篇&#xff0c;今天寫了第一篇&#xff0c;繼續重新學習&#xff0c;重新卷起來&#xff0c;come on baby 1.什么情況下會觸發類的初始化&#xff1f; &#xff08;1&#xff09;首先是類未被初始化時…

Agent中的memory

rag系列文章目錄 文章目錄rag系列文章目錄前言一、Memory機制作用二、memory分類三、langgraph實踐總結前言 眾所周知&#xff0c;大模型是無狀態的。但是基于大模型的agent一般是有狀態的&#xff0c;也就是它有記憶功能。在AI Agent框架中&#xff0c;Memory機制是核心組件之…

AI與IT從業者的未來:替代焦慮還是協作革命?

??引言&#xff1a;技術滲透與核心命題??2025年&#xff0c;人工智能技術已從實驗室走向產業核心。國務院《關于深入實施“人工智能”行動的意見》推動AI在醫療、制造、金融等領域的規模化落地&#xff0c;全球AI應用用戶規模突破2.3億&#xff0c;生成式AI工具滲透率達16.…

手機版碰一碰發視頻系統批量剪輯功能開發,支持OEM貼牌

引言在當今短視頻盛行的時代&#xff0c;視頻內容的快速生產與分享變得愈發重要。手機版碰一碰發視頻系統&#xff0c;借助 NFC 等近場通信技術&#xff0c;實現了便捷的數據交互與視頻分享&#xff0c;而在此基礎上集成的批量剪輯功能&#xff0c;更是為內容創作者和商家帶來了…

Spring AMQP如何通過配置文件避免硬編碼實現解耦

在使用Spring AMQP基于注解聲明監聽者時&#xff0c;可通過抽取常量來避免硬編碼&#xff1a;RabbitListener(bindings QueueBinding(exchange Exchange(MQConstant.USER_EXCHANGE),value Queue(MQConstant.USER_QUEUE),key MQConstant.USER_REDIS_BINDING))public void de…

解決zabbix圖片中文亂碼

要把 Zabbix 前端字體替換為 simkai.ttf&#xff08;楷體&#xff0c;解決亂碼常用&#xff09;&#xff0c;按以下步驟操作&#xff1a;1. 確認 simkai.ttf 路徑 先找到系統里 simkai.ttf 字體文件&#xff0c;若沒有&#xff0c;可從 Windows 系統&#xff08;C:\Windows\Fon…

實例分割-動手學計算機視覺13

介紹 實例分割(instance segmentation)的目的是從圖像中分割出每個目標實例的掩模(mask)。與語義分割相比&#xff0c;實例分割不但要區分不同的類別&#xff0c;還要區分出同一種類別下的不同目標實例。如圖13-1所示 語義分割的結果中&#xff0c;不同的羊對應的標簽是一樣的…

水環境遙感分析!R語言編程+多源遙感數據預處理;水體指數計算、水深回歸分析、水溫SVM預測、水質神經網絡建模及科研級可視化制圖

系統性地整合R語言編程、遙感數據處理及機器學習建模&#xff0c;涵蓋水線提取&#xff08;水體指數與閾值法&#xff09;、水深反演&#xff08;多元回歸&#xff09;、水溫預測&#xff08;支持向量機&#xff09;、水質評估&#xff08;神經網絡&#xff09;等核心內容&…

微信公眾號/小程序百萬級OpenID自動化獲取工具

摘要 本報告詳細闡述了微信用戶列表數據獲取與處理工具的設計思路,包括分頁處理機制、頻率控制策略、斷點續傳功能和分布式存儲方案。針對微信API調用限制和用戶數據規模特點,該工具旨在高效、安全地獲取和存儲微信用戶列表數據,同時嚴格遵守微信API調用頻率限制,確保系統…

物聯網系統中傳感器到網關到物聯網平臺的傳輸路徑、協議、原理、用途與架構詳解

摘要物聯網&#xff08;IoT&#xff09;系統通過傳感器、網關和物聯網平臺實現數據的采集、傳輸、處理和應用。本文詳細分析了傳感器到網關再到物聯網平臺的傳輸路徑&#xff0c;涵蓋直接連接、網關中繼、邊緣計算、多級網關和混合路徑五種方式&#xff1b;介紹了短距離&#x…

SpringBoot自動注入配置類初步實現

一.SpringBoot自動裝配SpringBoot 的 自動裝配&#xff08;Auto-Configuration&#xff09; 是它的核心特性之一&#xff0c;它讓開發者可以 "開箱即用"&#xff0c;避免手動配置大量的 XML 或 Java Config。它的核心思想是&#xff1a;"約定優于配置"&…

直播預告|鴻蒙生態中的AI新玩法

想知道鴻蒙生態里 AI 能玩出啥新花樣&#xff1f; 8 月 14 日&#xff08;周四&#xff09;20:00 &#xff0c;「開發者?面對面 堅果派特輯 —— 鴻蒙生態中的 AI 新玩法」直播來襲&#xff01; &#x1f50d; 直播亮點搶先看 AI賦能鴻蒙產品開發&#xff1a;將分享如何利用AI…

智能合約:區塊鏈時代的“數字契約革命”

一、技術原理與核心特征1. 定義與本質智能合約是運行在區塊鏈上的自動化程序&#xff0c;通過代碼定義業務規則&#xff0c;在預設條件滿足時自動執行操作&#xff08;如資金轉移、信息更新&#xff09;&#xff0c;無需人工干預。其核心特性包括&#xff1a;自動執行&#xff…

【數據分析】比較SparCC、Pearson和Spearman相關性估計方法在合成組學數據上的表現

禁止商業或二改轉載,僅供自學使用,侵權必究,如需截取部分內容請后臺聯系作者! 文章目錄 介紹 加載R包 模擬數據 構建網絡 RMSE指數計算 畫圖 總結 系統信息 介紹 在生物信息學和生態學研究中,組學數據的分析越來越依賴于對微生物群落或基因表達數據中物種或基因間相關性的…

Google C++ 風格指南

文章目錄背景介紹風格指南的目標C 版本頭文件自包含頭文件#define 防護包含所需內容前置聲明在頭文件中定義函數頭文件包含順序與命名規范作用域命名空間內部鏈接非成員函數、靜態成員函數與全局函數局部變量靜態與全局變量關于析構的決策關于初始化的決策常見模式thread_local…

安裝部署_WVP流媒體

文章目錄一、DEV_WVP流媒體開發手冊1、搭建流媒體服務clone代碼&#xff1a;安裝編譯器cmake構建和編譯項目修改配置文件啟動項目2、搭建GB28181協議視頻平臺安裝 jdk, nodejs, maven, git安裝redis安裝postgresqlclone代碼編譯前端代碼編譯后端代碼配置文件修改3、設備接入測測…