目录
一、任务
二、需求分析
三、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的读写。(如果有错误的地方,还请大家指出来,谢谢!)