FPGA學習筆記——SDR SDRAM的讀寫(調用IP核版)

目錄

一、任務

二、需求分析

三、Visio圖

四、具體分析

1.需要注意的問題

(1)器件SDRAM需要的時鐘

(2)跨時鐘域(異步FIFO)

2.模塊分析和調用

(1)SDR SDRAM IP核調用

(2)串口收發模塊

(3)調用PLL IP核

(4)調用異步FIFO IP核

讀FIFO

寫FIFO

(5)讀寫控制模塊

五、代碼

(1)top.v

(2)uart_tx.v

(3)uart_rx.v

(4)key_filter.v

(5)sdram_ctrl.v

(6)rw_ctrl.v

六、實驗現象


一、任務

調用SDR SDRAM IP核對SDR SDRAM進行讀寫操作,按鍵按下從SDRAM中讀出10個數據,并在串口助手顯示,用串口助手每發送10個字節數據,就將數據寫入SDRAM中,與SDRAM通信的時鐘為100MHz。


二、需求分析

分析任務,需要調用SDR SDRAM IP核來完成任務,然后還需要按鍵模塊來進行讀操作,還需要串口收發模塊來發送和接收數據,每接收到10個數據就進行寫操作,說明需要FIFO來進行緩存,讀操作也是一樣的,而且這里要注意,SDRAM通信的時鐘是100MHz,就需要PLL IP核來產生時鐘,最后就是需要讀寫操作模塊。(具體看具體分析)


三、Visio圖


四、具體分析

1.需要注意的問題

(1)器件SDRAM需要的時鐘

????????器件SDRAM需要的100MHz時鐘需要進行相位偏移,Slave需要的100MHz時鐘不需要相位偏移,為什么器件SDRAM需要偏移時鐘,就是讓SDRAM在數據的中間采集的數據是穩定的。

(2)跨時鐘域(異步FIFO)

跨時鐘域常用的方法就是:異步FIFO

????????這里涉及50MHz和100MHz,從串口接收模塊是50MHz時鐘,發送給Slave是需要100MHz時鐘,所以必須要使用異步FIFO

2.模塊分析和調用

(1)SDR SDRAM IP核調用

調用SDR SDRAM IP核

(2)串口收發模塊

串口收發模塊

(3)調用PLL IP核

(4)調用異步FIFO IP核

這里異步FIFO IP要調用兩個一個讀FIFO和一個寫FIFO:

讀FIFO

寫FIFO

(5)讀寫控制模塊

調用的SDR SDRAM IP核的突發長度固定是1,所以這里的連續讀或寫10個數據,就發10個讀指令或寫指令,是一個偽突發。(指令都是由SDR SDRAM IP核內部發送的)

當串口助手發送10個字節數據,狀態由IDLE狀態跳到WRITE狀態,由于這里的寫FIFO是16bit寬度,所以讓這個數據{2{data}},在讀出來的時候截取低8位,當10個數據傳輸完成,進入DONE狀態,再進入IDLE狀態,等待下一次觸發。

當按鍵按下,狀態由IDLE狀態跳到READ狀態,每接收一個數據就發送,當發送10個數據,狀態由READ狀態進入DONE狀態,再進入IDLE狀態,等待下一次觸發。(更具體的可以看rw_ctrl.v)


五、代碼

(1)top.v

module top( input               clk      ,input               rst_n    ,//keyinput               key_in   ,//uart_txinput               rx       ,//uart_rxoutput              tx       ,//sdram_ctrloutput              clk_100s   ,output      [12:0]  sdram_addr ,//行列地址 output      [1:0]   sdram_bank ,//bank地址   []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 
);
//key_filter
wire                key_down;
//uart_rx
wire                uart_rxd   ;
wire        [7:0]   rx_data    ;
wire                rx_data_vld;
//uart_tx
wire        [7:0]   tx_data    ;
wire                tx_data_vld;
wire                uart_txd   ;
wire                ready      ;
//pll
wire    clk_in ;
wire    clk_out;
wire    locked ;key_filter u_key_filter(.clk      (clk      ),.rst_n    (rst_n    ),.key_in   (key_in   ),.key_down (key_down )
);uart_rx #( .CLOCK_FRQ(50_000_000),.BAUD(115200),.DATA_LENTH(8)     ,.CHECKBIT_SELECT(0),.CHECK_TYPE(0)   //偶校驗:0  奇校驗:1
)uart_rx_inst( /*input               */.clk      (clk        ),/*input               */.rst_n    (rst_n      ),/*input               */.uart_rxd (rx         ),/*output  reg [7:0]   */.dout     (rx_data    ),/*output              */.dout_vld (rx_data_vld)
);uart_tx #(  .CLOCK_FRQ(50_000_000),.BAUD(115200),.DATA_LENTH(8)     ,.CHECKBIT_SELECT(0),.CHECK_TYPE(0)   //偶校驗:0  奇校驗:1)uart_tx_inst( /*input                           */.clk      (clk        ),/*input                           */.rst_n    (rst_n      ),/*input       [DATA_LENTH-1:0]    */.tx_din   (tx_data    ),/*input                           */.tx_enable(tx_data_vld),/*output  reg                     */.uart_txd (tx         ),/*output  reg                     */.ready    (ready      ) //忙閑指示信號
);sdram_ctrl u_sdram_ctrl(.clk         (clk_in      ),.clk_in      (clk         ),.clk_out     (clk         ),.rst_n       (rst_n       ),.rx_data     (rx_data     ),.rx_data_vld (rx_data_vld ),.ready       (ready       ),.tx_data     (tx_data     ),.tx_data_vld (tx_data_vld ),.key_down    (key_down    ),.sdram_addr  (sdram_addr  ),.sdram_bank  (sdram_bank  ),.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  )
);pll_0 u_pll_0(.areset (~rst_n ),.inclk0 (clk    ),.c0     (clk_in ),.c1     (clk_out),.locked (locked )
);assign  clk_100s = clk_out;endmodule

(2)uart_tx.v

module uart_tx #(parameter CLOCK_FRQ  = 50_000_000,BAUD       = 9600      ,DATA_LENTH = 8         ,CHECKBIT_SELECT = 0    ,CHECK_TYPE = 0           //偶校驗:0  奇校驗:1
)( input                           clk      ,input                           rst_n    ,input       [DATA_LENTH-1:0]    tx_din   ,input                           tx_enable,output  reg                     uart_txd ,output  reg                     ready     //忙閑指示信號
);
//---------<參數定義>------------------------------------------------//狀態機參數定義localparam  IDLE  = 5'b00001,START = 5'b00010,DATA  = 5'b00100,CHECK = 5'b01000,STOP  = 5'b10000;localparam  BUAD_MAX = CLOCK_FRQ/BAUD;//---------<內部信號定義>--------------------------------------------reg     [4:0]   state_c     ;reg     [4:0]   state_n     ;reg		[15:0]	cnt_baud	;//波特率計數器wire			add_cnt_baud;wire			end_cnt_baud;reg		[2:0]	cnt_bit	    ;//數據傳輸的比特計數器wire			add_cnt_bit ;wire			end_cnt_bit ;reg     [7:0]   tx_din_r    ;//狀態轉移條件定義wire            idle2start  ;wire            start2data  ;wire            data2check  ;wire            data2stop   ;wire            check2stop  ;wire            stop2idle   ;//*******************************************************************
//--tx_din_r
//*******************************************************************always @(posedge clk or negedge rst_n)begin if(!rst_n)begintx_din_r <= 'd0;end else if(tx_enable)begin tx_din_r <= tx_din;end end//*******************************************************************
//--狀態機
//*******************************************************************//第一段:同步時序描述狀態轉移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(idle2start)state_n = START; else state_n = state_c;endSTART : beginif(start2data)state_n = DATA;else state_n = state_c;endDATA  : beginif(data2check)state_n = CHECK;else if(data2stop)state_n = STOP;else state_n = state_c;endCHECK : beginif(check2stop)state_n = STOP;else state_n = state_c;endSTOP  : beginif(stop2idle)state_n = IDLE; else state_n = state_c;enddefault : state_n = IDLE;endcaseendassign  idle2start = (state_c == IDLE ) && tx_enable; assign  start2data = (state_c == START) && end_cnt_baud;assign  data2check = (state_c == DATA ) && end_cnt_bit && CHECKBIT_SELECT;assign  data2stop  = (state_c == DATA ) && end_cnt_bit && !CHECKBIT_SELECT;assign  check2stop = (state_c == CHECK) && end_cnt_baud;assign  stop2idle  = (state_c == STOP ) && end_cnt_baud;//*******************************************************************
//--cnt_baud
//*******************************************************************always @(posedge clk or negedge rst_n)begin if(!rst_n)begincnt_baud <= 'd0;end else if(add_cnt_baud)begin if(end_cnt_baud)begin cnt_baud <= 'd0;endelse begin cnt_baud <= cnt_baud + 1'b1;end endend assign add_cnt_baud = state_c != IDLE;assign end_cnt_baud = add_cnt_baud && cnt_baud == ((state_c == STOP) ? ((BUAD_MAX>>1)+(BUAD_MAX>>2)) : (BUAD_MAX - 1));//*******************************************************************
//--cnt_bit
//*******************************************************************always @(posedge clk or negedge rst_n)begin if(!rst_n)begincnt_bit <= 'd0;end else if(add_cnt_bit)begin if(end_cnt_bit)begin cnt_bit <= 'd0;endelse begin cnt_bit <= cnt_bit + 1'b1;end endend assign add_cnt_bit = state_c == DATA && end_cnt_baud;assign end_cnt_bit = add_cnt_bit && cnt_bit == DATA_LENTH - 1;//*******************************************************************
//--uart_txd
//*******************************************************************always @(posedge clk or negedge rst_n)begin if(!rst_n)beginuart_txd <= 1'b1;end else begin case (state_c)IDLE  : uart_txd <= 1'b1;START : uart_txd <= 1'b0;DATA  : uart_txd <= tx_din_r[cnt_bit];//并轉串,LSB// CHECK : uart_txd <= ^tx_din_r + CHECK_TYPE;CHECK : uart_txd <= CHECK_TYPE ? (^tx_din_r + 1'b1) : (^tx_din_r); STOP  : uart_txd <= 1'b1;default: uart_txd <= 1'b1;endcaseend end//*******************************************************************
//--ready
//*******************************************************************always @(posedge clk or negedge rst_n)begin if(!rst_n)beginready <= 'd0;end else begin ready <= state_n == IDLE;end endendmodule

(3)uart_rx.v

module uart_rx #(parameter CLOCK_FRQ  = 50_000_000,BAUD       = 9600      ,DATA_LENTH = 8         ,CHECKBIT_SELECT = 0    ,CHECK_TYPE = 0           //偶校驗:0  奇校驗:1
)( input               clk      ,input               rst_n    ,input               uart_rxd ,output  reg [7:0]   dout     ,output              dout_vld 
);
//---------<參數定義>------------------------------------------------//狀態機參數定義localparam  IDLE  = 5'b00001,START = 5'b00010,DATA  = 5'b00100,CHECK = 5'b01000,STOP  = 5'b10000;localparam  BUAD_MAX = CLOCK_FRQ/BAUD;//---------<內部信號定義>--------------------------------------------reg     [4:0]   state_c     ;reg     [4:0]   state_n     ;reg		[15:0]	cnt_baud	;//波特率計數器wire			add_cnt_baud;wire			end_cnt_baud;reg		[2:0]	cnt_bit	   ;//接收bit數量的計數器wire			add_cnt_bit;wire			end_cnt_bit;reg     [2:0]   uart_rxd_r  ;wire            rxd_n_edge  ;//狀態轉移條件定義wire            idle2start  ;wire            start2data  ;wire            data2check  ;wire            data2stop   ;wire            check2stop  ;wire            stop2idle   ;//*******************************************************************
//--打三拍(前兩拍同步,后一拍獲得邊沿)
//*******************************************************************//uart_rxd_ralways @(posedge clk or negedge rst_n)begin if(!rst_n)beginuart_rxd_r <= 3'b111;end else begin uart_rxd_r <= {uart_rxd_r[1:0],uart_rxd};end end//rxd_n_edgeassign  rxd_n_edge = ~uart_rxd_r[1] & uart_rxd_r[2];//*******************************************************************
//--狀態機
//*******************************************************************//第一段:同步時序描述狀態轉移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(idle2start)state_n = START; else state_n = state_c;endSTART : beginif(start2data)state_n = DATA;else state_n = state_c;endDATA  : beginif(data2check)state_n = CHECK;else if(data2stop)state_n = STOP;else state_n = state_c;endCHECK : beginif(check2stop)state_n = STOP;else state_n = state_c;endSTOP  : beginif(stop2idle)state_n = IDLE; else state_n = state_c;enddefault : state_n = IDLE;endcaseendassign  idle2start = (state_c == IDLE ) && rxd_n_edge;assign  start2data = (state_c == START) && end_cnt_baud;assign  data2check = (state_c == DATA ) && end_cnt_bit && CHECKBIT_SELECT;assign  data2stop  = (state_c == DATA ) && end_cnt_bit && !CHECKBIT_SELECT;assign  check2stop = (state_c == CHECK) && end_cnt_baud;assign  stop2idle  = (state_c == STOP ) && end_cnt_baud;//*******************************************************************
//--cnt_baud
//*******************************************************************always @(posedge clk or negedge rst_n)begin if(!rst_n)begincnt_baud <= 'd0;end else if(add_cnt_baud)begin if(end_cnt_baud)begin cnt_baud <= 'd0;endelse begin cnt_baud <= cnt_baud + 1'b1;end endend assign add_cnt_baud = state_c != IDLE;assign end_cnt_baud = add_cnt_baud && cnt_baud == ((state_c == STOP) ? ((BUAD_MAX>>1)+(BUAD_MAX>>2)) : (BUAD_MAX - 1));//*******************************************************************
//--cnt_bit
//*******************************************************************always @(posedge clk or negedge rst_n)begin if(!rst_n)begincnt_bit <= 'd0;end else if(add_cnt_bit)begin if(end_cnt_bit)begin cnt_bit <= 'd0;endelse begin cnt_bit <= cnt_bit + 1'b1;end endend assign add_cnt_bit = state_c == DATA && end_cnt_baud;assign end_cnt_bit = add_cnt_bit && cnt_bit == DATA_LENTH - 1;//*******************************************************************
//--dout
//*******************************************************************always @(posedge clk or negedge rst_n)begin if(!rst_n)begindout <= 'd0;end else if(state_c == DATA && cnt_baud == (BUAD_MAX>>1) - 1)begin dout[cnt_bit] <= uart_rxd_r[2];// dout <= {uart_rxd_r[2],dout[7:1]};end end//*******************************************************************
//--dout_vld
//*******************************************************************assign  dout_vld = stop2idle;endmodule

(4)key_filter.v

module key_filter#(parameter WIDTH = 1,TIME_20MS = 1000_000)( input				    clk		,input				    rst_n	,input       [WIDTH-1:0]	key_in	,output  reg [WIDTH-1:0] key_down
);								 
//---------<參數定義>--------------------------------------------------------- //狀態機參數        獨熱碼編碼localparam  IDLE        = 4'b0001,//空閑狀態FILTER_DOWN = 4'b0010,//按鍵按下抖動狀態HOLD        = 4'b0100,//按鍵穩定按下狀態FILTER_UP   = 4'b1000;//按鍵釋放抖動狀態//---------<內部信號定義>-----------------------------------------------------reg     [3:0]       state_c         ;//現態reg     [3:0]       state_n         ;//次態reg     [WIDTH-1:0] key_r0          ;//同步打拍reg     [WIDTH-1:0] key_r1          ;reg     [WIDTH-1:0] key_r2          ;wire    [WIDTH-1:0] n_edge          ;//下降沿wire    [WIDTH-1:0] p_edge          ;//上升沿   reg	    [19:0]	    cnt_20ms	   	;//延時計數器(20ms)wire				add_cnt_20ms	;wire				end_cnt_20ms	;  //狀態轉移條件信號wire                idle2filter_down    ;wire                filter_down2idle    ;wire                filter_down2hold    ;wire                hold2filter_up      ;wire                filter_up2hold      ;wire                filter_up2idle      ;  //****************************************************************
//--狀態機
//****************************************************************//第一段:時序邏輯描述狀態轉移always @(posedge clk or negedge rst_n)begin if(!rst_n)beginstate_c <= IDLE;end else begin state_c <= state_n;end end//第二段:組合邏輯描述狀態轉移規律和狀態轉移條件always @(*)begin case (state_c)IDLE        : begin if(idle2filter_down)begin state_n = FILTER_DOWN;endelse begin // state_n = IDLE;state_n = state_c;endendFILTER_DOWN : begin if(filter_down2idle)begin state_n = IDLE;endelse if(filter_down2hold)begin state_n = HOLD;endelse begin state_n = state_c;endendHOLD        : begin if(hold2filter_up)begin state_n = FILTER_UP;endelse begin state_n = state_c;endendFILTER_UP   : begin if(filter_up2hold)begin state_n = HOLD;endelse if(filter_up2idle)begin state_n = IDLE;endelse begin state_n = state_c;endenddefault: state_n = IDLE;endcaseendassign idle2filter_down = (state_c == IDLE) && n_edge;assign filter_down2idle = (state_c == FILTER_DOWN) && p_edge;assign filter_down2hold = (state_c == FILTER_DOWN) && end_cnt_20ms && !p_edge;assign hold2filter_up   = (state_c == HOLD) && p_edge;assign filter_up2hold   = (state_c == FILTER_UP) && n_edge;assign filter_up2idle   = (state_c == FILTER_UP) && end_cnt_20ms;//****************************************************************
//--n_edge、p_edge 
//****************************************************************             always @(posedge clk or negedge rst_n)begin if(!rst_n)beginkey_r0 <= {WIDTH{1'b1}};key_r1 <= {WIDTH{1'b1}};key_r2 <= {WIDTH{1'b1}};end else begin key_r0 <= key_in;key_r1 <= key_r0;key_r2 <= key_r1; end endassign n_edge = ~key_r1 & key_r2;//下降沿assign p_edge = ~key_r2 & key_r1;//上升沿//****************************************************************
//--cnt_20ms
//****************************************************************always @(posedge clk or negedge rst_n)begin if(!rst_n)begincnt_20ms <= 'd0;end else if(add_cnt_20ms)begin if(end_cnt_20ms || filter_down2idle || filter_up2hold)begin cnt_20ms <= 'd0;endelse begin cnt_20ms <= cnt_20ms + 1'b1;end endend assign add_cnt_20ms = (state_c == FILTER_DOWN) || (state_c == FILTER_UP);assign end_cnt_20ms = add_cnt_20ms && cnt_20ms == TIME_20MS - 1;//****************************************************************
//--key_down
//****************************************************************always @(posedge clk or negedge rst_n)begin if(!rst_n)beginkey_down <= 'd0;end else begin key_down <= filter_down2hold ? ~key_r2 : 1'b0;endendendmodule

(5)sdram_ctrl.v

module sdram_ctrl( input               clk        ,//100Mhzinput               clk_in     ,//50Mhzinput               clk_out    ,//50Mhzinput               rst_n      ,//uart_rxinput       [7:0]   rx_data    ,input               rx_data_vld,//uart_txinput               ready      ,output      [7:0]   tx_data    ,output              tx_data_vld,//key_filterinput               key_down   ,//sdram memoryoutput      [12:0]  sdram_addr ,//行列地址 output      [1:0]   sdram_bank ,//bank地址   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_wrdata     ;
wire            avm_read_n     ;
wire            avm_write_n    ;
wire    [15:0]  avm_rddata     ;
wire            avm_rddata_vld ;
wire            avm_waitrequest;rw_sdram u_rw_sdram(.clk             (clk             ),.clk_in          (clk_in          ),.clk_out         (clk_out         ),.rst_n           (rst_n           ),.rx_data         (rx_data         ),.rx_data_vld     (rx_data_vld     ),.ready           (ready           ),.tx_data         (tx_data         ),.tx_data_vld     (tx_data_vld     ),.key_down        (key_down        ),.avm_address     (avm_address     ),.avm_wrdata      (avm_wrdata      ),.avm_read_n      (avm_read_n      ),.avm_write_n     (avm_write_n     ),.avm_rddata      (avm_rddata      ),.avm_rddata_vld  (avm_rddata_vld  ),.avm_waitrequest (avm_waitrequest )
);sdram_intf u_sdram_intf(.avs_address       (avm_address    ),.avs_byteenable_n  (2'b00          ),.avs_chipselect    (1'b1           ),.avs_writedata     (avm_wrdata     ),.avs_read_n        (avm_read_n     ),.avs_write_n       (avm_write_n    ),.avs_readdata      (avm_rddata     ),.avs_readdatavalid (avm_rddata_vld ),.avs_waitrequest   (avm_waitrequest),.clk_clk           (clk            ),.reset_reset_n     (rst_n          ),.sdram_addr        (sdram_addr     ),.sdram_ba          (sdram_bank     ),.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

(6)rw_ctrl.v

module rw_sdram#(parameter BURST_LENTH = 10)( input               clk            ,//100Mhzinput               clk_in         ,//50Mhzinput               clk_out        ,//50Mhzinput               rst_n          ,//uart_rxinput       [7:0]   rx_data        ,input               rx_data_vld    ,//uart_txinput               ready          ,output      [7:0]   tx_data        ,output              tx_data_vld    ,//key_filterinput               key_down       ,//sdram ip: Avalon-MM Master Interface output      [23:0]  avm_address    ,//{bank[1],row[12:0],bank[0],colum[8:0]}   output      [15:0]  avm_wrdata     ,   output              avm_read_n     ,      output              avm_write_n    ,      input       [15:0]  avm_rddata     ,     input               avm_rddata_vld ,input               avm_waitrequest  
);localparam IDLE  = 4'b0001,WRITE = 4'b0010,READ  = 4'b0100,DONE  = 4'b1000;reg     [3:0]   state_c ;
reg     [3:0]   state_n ;    reg		[3:0]	cnt_burst	 ;//突發讀/寫長度計數器
wire			add_cnt_burst;
wire			end_cnt_burst;
reg     [23:0]  wr_addr    ;//{bank[1:0],rwo[12:0],colum[8:0]}
wire			add_wr_addr;
wire			end_wr_addr;
reg		[23:0]	rd_addr	   ;//{bank[1:0],rwo[12:0],colum[8:0]}
wire			add_rd_addr;
wire			end_rd_addr;wire            idle2write;
wire            idle2read ;
wire            write2done;
wire            read2done ;wire            wrfifo_wrreq;
wire            wrfifo_rdempty;
wire    [3:0]   wrfifo_rdusedw;
wire            wrfifo_wrfull ;        
wire            wrfifo_rdreq  ;
wire    [15:0]  wrfifo_q      ;wire            rdfifo_wrreq  ;
wire            rdfifo_rdempty;
wire            rdfifo_wrfull ;
wire            rdfifo_rdreq  ;
wire    [15:0]  rdfifo_q      ;//---------<FIFO例化>------------------------------------------------- 
wr_fifo u_wr_fifo(.aclr    (~rst_n        ),.data    ({2{rx_data} } ),.rdclk   (clk           ),.rdreq   (wrfifo_rdreq  ),.wrclk   (clk_in        ),.wrreq   (wrfifo_wrreq  ),.q       (wrfifo_q      ),.rdempty (wrfifo_rdempty),.rdusedw (wrfifo_rdusedw),.wrfull  (wrfifo_wrfull )
);assign wrfifo_wrreq = ~wrfifo_wrfull && rx_data_vld;
assign wrfifo_rdreq = ~wrfifo_rdempty && state_c == WRITE && ~avm_waitrequest;rd_fifo u_rd_fifo(.aclr    (~rst_n        ),.data    (avm_rddata    ),.rdclk   (clk_out       ),.rdreq   (rdfifo_rdreq  ),.wrclk   (clk           ),.wrreq   (rdfifo_wrreq  ),.q       (rdfifo_q      ),.rdempty (rdfifo_rdempty),.wrfull  (rdfifo_wrfull )
);assign rdfifo_wrreq = ~rdfifo_wrfull && avm_rddata_vld;
assign rdfifo_rdreq = ~rdfifo_rdempty && ready;//---------<State Machine>------------------------------------------------- 
always @(posedge clk or negedge rst_n)begin if(!rst_n)beginstate_c <= IDLE;end else begin state_c <= state_n;end 
endalways @(*) begincase(state_c)IDLE  : beginif(idle2write)state_n = WRITE;else if(idle2read)state_n = READ;elsestate_n = state_c;endWRITE : beginif(write2done)state_n = DONE;elsestate_n = state_c;endREAD  : beginif(read2done)state_n = DONE;elsestate_n = state_c;endDONE  : state_n = IDLE;default : ;endcase
endassign idle2write = (state_c == IDLE) && wrfifo_rdusedw >= BURST_LENTH;
assign idle2read  = (state_c == IDLE) && key_down;
assign write2done = (state_c == WRITE) && end_cnt_burst; 
assign read2done  = (state_c == READ) && end_cnt_burst;//---------<cnt_burst>------------------------------------------------- 
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 == WRITE | state_c == READ) && ~avm_waitrequest;
assign end_cnt_burst = add_cnt_burst && cnt_burst == BURST_LENTH - 1;//---------<寫地址>------------------------------------------------- 
// always @(posedge clk or negedge rst_n)begin 
//     if(!rst_n)
//         wr_addr <= 24'd0;
//     else if(state_c == WRITE && ~avm_waitrequest)
//         wr_addr <= wr_addr + 1'b1;
// endalways @(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;//---------<rd_addr>------------------------------------------------- 
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;//---------<輸出>------------------------------------------------- 
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_wrdata = wrfifo_q; 
assign avm_read_n = ~(state_c == READ) ;
assign avm_write_n = ~(state_c ==WRITE);assign tx_data = rdfifo_q[7:0];   
assign tx_data_vld = rdfifo_rdreq;endmodule

六、實驗現象


以上就是SDR SDRAM的讀寫。(如果有錯誤的地方,還請大家指出來,謝謝!)

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

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

相關文章

離散數學學習指導與習題解析

《離散數學學習指導與習題解析&#xff08;第2版&#xff09;》是屈婉玲、耿素云、張立昂編著的《離散數學&#xff08;第2版&#xff09;》的配套參考書&#xff0c;旨在為學生提供系統的學習指導和豐富的習題解析。本書內容全面&#xff0c;涵蓋數理邏輯、集合論、代數結構、…

Qt網絡通信服務端與客戶端學習

Qt網絡通信服務端與客戶端學習 一、項目概述 本項目基于Qt框架實現了TCP服務端與客戶端的基本通信&#xff0c;涵蓋連接、消息收發、斷開管理等功能&#xff0c;適合初學者系統學習Qt網絡模塊的實際用法。 二、項目結構 52/ 服務端&#xff1a;main.cpp、widget.cpp、widget.h5…

神馬 M60S++ 238T礦機參數解析:高效SHA-256算法比拼

1. 算法與適用幣種神馬 M60S 238T采用SHA-256算法&#xff0c;適用于挖掘主流的加密貨幣&#xff0c;包括比特幣&#xff08;BTC&#xff09;和比特幣現金&#xff08;BCH&#xff09;。SHA-256&#xff08;安全哈希算法256位&#xff09;是一種廣泛應用于比特幣等加密貨幣挖礦…

[特殊字符] 深入理解操作系統核心特性:從并發到分布式,從單核到多核的全面解析

&#x1f680; 深入理解操作系統核心特性&#xff1a;從并發到分布式&#xff0c;從單核到多核的全面解析&#x1f4a1; 前言&#xff1a;操作系統是計算機的靈魂&#xff0c;它就像一個優秀的管家&#xff0c;協調著硬件和軟件之間的關系。今天&#xff0c;我們將深入探討操作…

人工智能機器學習——聚類

一、無監督學習(Unsupervised Learning)機器學習的一種方法&#xff0c;沒有給定事先標記過的訓練示例&#xff0c;自動對輸入的數據進行分類或分群。優點&#xff1a; 算法不受監督信息&#xff08;偏見&#xff09;的約束&#xff0c;可能考慮到新的信息不需要標簽數據&#…

優化MySQL分區表備份流程詳解

在大型數據驅動應用中&#xff0c;MySQL分區表是優化查詢和維護歷史的常見選擇。但隨之而來的數據備份問題卻讓許多開發者頭疼&#xff1a;如何確保分散在不同分區的數據能完整、一致地被備份&#xff0c;并在需要時快速恢復&#xff1f;手動處理不僅繁瑣&#xff0c;而且極易出…

用 Go + HTML 實現 OpenHarmony 投屏(hdckit-go + WebSocket + Canvas 實戰)

本文帶你用 Go HTML/WebSocket 從零實現一個 OpenHarmony 設備投屏 Demo&#xff1a;Go 側用 hdckit-go 連接設備并抓取屏幕幀&#xff08;UiDriver&#xff09;&#xff0c;通過 WebSocket 二進制實時推送到瀏覽器&#xff0c;前端用 Canvas 渲染&#xff0c;并根據設備分辨率…

運籌學——求解線性規劃的單純形法

單純形法的原理 先來舉個例子&#xff1a; 用單純形法求解下面線性規劃問題的最優解&#xff1a;注釋&#xff1a;解的過程是反復迭代的過程&#xff0c;如果第一次迭代沒有理解也沒關系&#xff0c;再繼續看第二次迭代&#xff0c;和第三次迭代&#xff0c;每次迭代的流程都是…

Python GUI 框架 -- DearPyGui 簡易入門

DearPyGui 關于 DPG 是一個簡單且功能強大的 Python 圖形用戶界面框架。 與其他Python圖形用戶界面庫相比&#xff0c;DPG具有以下獨特之處&#xff1a; GPU 渲染多線程高度可定制內置開發人員工具&#xff1a;主題檢查、資源檢查、運行時指標帶有數百種小部件組合的 70 多…

gcloud cli 使用 impersonate模擬 服務帳號

什么是模擬服務帳號 眾所周知&#xff0c; gcloud 登陸的方式有兩種 使用個人帳號&#xff0c; 通常是1個郵箱地址使用一個service account 通常是1個 json key 文件 所謂模式服務帳號意思就是&#xff0c; 讓操作人員用個人帳號登陸&#xff0c; 但是登陸后所有的操作都是基于…

idf--esp32的看門狗menuconfig

1.Interrupt Watchdog Timeout (ms)&#xff1a;意思是中斷看門狗&#xff0c;也就是專門監管中斷響應時間的看門狗&#xff0c;如果某個中斷服務程序超過了這個運行時間&#xff0c;就會導致程序重啟。2.紅框是任務看門狗的最大看門時間&#xff0c;超過時間就會警告&#xff…

git在Linux中的使用

git-Linux中的使用一、下載git二、https方式上傳三、ssh秘鑰方式上傳一、下載git 版本信息 [rootrocky ~]# cat /etc/rocky-release Rocky Linux release 9.4 (Blue Onyx) [rootrocky ~]# cat /etc/rocky-release-upstream Derived from Red Hat Enterprise Linux 9.4 [rootro…

HMI(人機界面)

新晉碼農一枚&#xff0c;小編定期整理一些寫的比較好的代碼&#xff0c;作為自己的學習筆記&#xff0c;會試著做一下批注和補充&#xff0c;轉載或者參考他人文獻會標明出處&#xff0c;非商用&#xff0c;如有侵權會刪改&#xff01;歡迎大家斧正和討論&#xff01;一、核心…

嵌入式解謎日志—多路I/O復用

多路 I/O復用&#xff08;Multiplexed I/O&#xff09;&#xff1a;1.定義&#xff1a;系統提供的I/O事件通知機制2.應用&#xff1a;是一種 I/O 編程模型&#xff0c;用于在單線程中同時處理多個&#xff08;阻塞&#xff09; I/O 操作&#xff0c;避免因等待某個 I/O 操作完成…

關于嵌入式學習——單片機4

ds18b20溫度傳感器的使用一、傳感器分類&#xff1a;數字溫度傳感器&#xff0c;實現簡單&#xff0c;不需要額外轉換電路&#xff0c;采集過來的就是數字溫度值模擬溫度傳感器->熱敏電阻->AD轉換電路->數字值二、傳感器接口&#xff1a;GPIO接口&#xff1a;&#xf…

Kali搭建sqli-labs靶場

1.輸入apt-get install docker.io即可下載靶場鏡像。 下載好后&#xff0c;我們輸入docker search sqli-labs搜索sqli-labs靶場。2.我們選擇第一個&#xff0c;輸入docker pull acgpiano/sqli-labs&#xff0c;將該靶場裝到本地。此時輸入docker images&#xff0c;發現本地有s…

電腦外接顯示屏字體和圖標過大

當外接顯示屏的分辨率過高時&#xff0c;可以調整顯示器設置來解決字體和圖標過大的問題。具體操作包括在桌面右擊選擇顯示設置&#xff0c;切換到外接顯示器&#xff0c;將分辨率調至推薦的1920x1080&#xff0c;或根據個人偏好進行適當調節&#xff0c;然后保存更改。 原因&a…

Linux 網絡流量監控 Shell 腳本詳解(支持郵件告警)

前言 一、腳本功能 二、實現原理 三、Shell 腳本實現 四、關鍵知識點解析 1. Bash 關聯數組 2. 命令組 { } 與子 Shell ( ) 3. 字符串拼接換行 4. 流量計算邏輯 五、測試方法 六、優化建議 七、總結 前言 在生產環境中&#xff0c;監控服務器的 網絡流量 非常重要…

【牛客刷題-劍指Offer】BM18 二維數組中的查找:一題四解,從暴力到最優

文章目錄 一、題目介紹 1.1 描述 1.2 示例1 1.3 示例2 1.4 給的部分代碼 二、題解 方法一:暴力遍歷 方法二:二分查找(逐行) 方法三:Z字形查找(最優解) 方法四:遞歸分治(拓展思路) 三、總結 心得體會 一、題目介紹 原題鏈接:https://www.nowcoder.com/practice/abc3…

使用pyspark對上百億行的hive表生成稀疏向量

背景&#xff1a;一張上百億行的hive表&#xff0c;只有id和app兩列&#xff0c;其中app的去重量是8w多個&#xff08;原app有上百萬枚舉值&#xff0c;此處已經用id數量進行過篩選&#xff0c;只留下有一定規模的app&#xff09;&#xff0c;id的去重量大概有八九億&#xff0…