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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈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…