当前位置: 首页 > news >正文

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.xdnf.cn/news/1481977.html

相关文章:

  • 【LLM】Openai分析大模型出现幻觉的原因
  • 检查权限与申请权限
  • 为什么LIO-SAM的残差项使用对数映射
  • 动态规划题目
  • MotionSound-简单易用的文本转语音工具
  • Linux--命名管道
  • 【大语言模型 44】创造力评估:开放域生成质量测试
  • 【C++/STL】优先级队列,仿函数和反向迭代器
  • 阿喀琉斯之踵:从神话传说到现代隐喻的致命弱点
  • 【Kubernetes】知识点总结6
  • 2025高教社国赛数学建模竞赛B题完整参考论文(含模型和代码)
  • MQTT 与 Java 框架集成:Spring Boot 实战(二)
  • 自注意力机制解析
  • 我用Claude Code 开发了一个浏览器插件
  • Storybook:多框架兼容的前端组件开发工具,高效解决组件隔离开发与文档管理问题
  • ElasticSearch 基础内容深度解析
  • 网站管理后台
  • cifar10下载太慢,解决使用第三方链接或迅雷下载
  • VSCode下载安装与汉化
  • NAND Flash块擦除与数据状态解析
  • 【视网膜分割】一种基于结构自适应模型的空洞残差网络
  • 基于大数据+python的肾脏疾病风险教育与数据可视化系统源码 基于数据挖掘的肾脏疾病风险分析与决策支持系统(调试、开题、LW、PPT)
  • 芯片ATE测试PAT(Part Average Testing)学习总结-20250916
  • 提示词工程知识积累及分析
  • C++ 并发编程指南 实现无锁队列
  • Sentinel服务治理:服务降级、熔断与线程隔离
  • 新后端漏洞(上)- Weblogic SSRF漏洞
  • 「数据获取」《中国服务业统计与服务业发展(2014)》
  • 详解flink性能优化
  • docker使用nginxWebUI配置