目录
一、任务
调用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核调用
(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 ,
//key
input key_in ,
//uart_tx
input rx ,
//uart_rx
output tx ,
//sdram_ctrl
output 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)begin
tx_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)begin
state_c <= IDLE;
end
else begin
state_c <= state_n;
end
end
//第二段:组合逻辑判断状态转移条件,描述状态转移规律
always @(*) begin
case(state_c)
IDLE : begin
if(idle2start)
state_n = START;
else
state_n = state_c;
end
START : begin
if(start2data)
state_n = DATA;
else
state_n = state_c;
end
DATA : begin
if(data2check)
state_n = CHECK;
else if(data2stop)
state_n = STOP;
else
state_n = state_c;
end
CHECK : begin
if(check2stop)
state_n = STOP;
else
state_n = state_c;
end
STOP : begin
if(stop2idle)
state_n = IDLE;
else
state_n = state_c;
end
default : state_n = IDLE;
endcase
end
assign 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)begin
cnt_baud <= 'd0;
end
else if(add_cnt_baud)begin
if(end_cnt_baud)begin
cnt_baud <= 'd0;
end
else begin
cnt_baud <= cnt_baud + 1'b1;
end
end
end
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)begin
cnt_bit <= 'd0;
end
else if(add_cnt_bit)begin
if(end_cnt_bit)begin
cnt_bit <= 'd0;
end
else begin
cnt_bit <= cnt_bit + 1'b1;
end
end
end
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)begin
uart_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;
endcase
end
end
//*******************************************************************
//--ready
//*******************************************************************
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
ready <= 'd0;
end
else begin
ready <= state_n == IDLE;
end
end
endmodule
(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_r
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
uart_rxd_r <= 3'b111;
end
else begin
uart_rxd_r <= {uart_rxd_r[1:0],uart_rxd};
end
end
//rxd_n_edge
assign rxd_n_edge = ~uart_rxd_r[1] & uart_rxd_r[2];
//*******************************************************************
//--状态机
//*******************************************************************
//第一段:同步时序描述状态转移
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
state_c <= IDLE;
end
else begin
state_c <= state_n;
end
end
//第二段:组合逻辑判断状态转移条件,描述状态转移规律
always @(*) begin
case(state_c)
IDLE : begin
if(idle2start)
state_n = START;
else
state_n = state_c;
end
START : begin
if(start2data)
state_n = DATA;
else
state_n = state_c;
end
DATA : begin
if(data2check)
state_n = CHECK;
else if(data2stop)
state_n = STOP;
else
state_n = state_c;
end
CHECK : begin
if(check2stop)
state_n = STOP;
else
state_n = state_c;
end
STOP : begin
if(stop2idle)
state_n = IDLE;
else
state_n = state_c;
end
default : state_n = IDLE;
endcase
end
assign 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)begin
cnt_baud <= 'd0;
end
else if(add_cnt_baud)begin
if(end_cnt_baud)begin
cnt_baud <= 'd0;
end
else begin
cnt_baud <= cnt_baud + 1'b1;
end
end
end
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)begin
cnt_bit <= 'd0;
end
else if(add_cnt_bit)begin
if(end_cnt_bit)begin
cnt_bit <= 'd0;
end
else begin
cnt_bit <= cnt_bit + 1'b1;
end
end
end
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)begin
dout <= '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)begin
state_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;
end
else begin
// state_n = IDLE;
state_n = state_c;
end
end
FILTER_DOWN : begin
if(filter_down2idle)begin
state_n = IDLE;
end
else if(filter_down2hold)begin
state_n = HOLD;
end
else begin
state_n = state_c;
end
end
HOLD : begin
if(hold2filter_up)begin
state_n = FILTER_UP;
end
else begin
state_n = state_c;
end
end
FILTER_UP : begin
if(filter_up2hold)begin
state_n = HOLD;
end
else if(filter_up2idle)begin
state_n = IDLE;
end
else begin
state_n = state_c;
end
end
default: state_n = IDLE;
endcase
end
assign 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)begin
key_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
end
assign 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)begin
cnt_20ms <= 'd0;
end
else if(add_cnt_20ms)begin
if(end_cnt_20ms || filter_down2idle || filter_up2hold)begin
cnt_20ms <= 'd0;
end
else begin
cnt_20ms <= cnt_20ms + 1'b1;
end
end
end
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)begin
key_down <= 'd0;
end
else begin
key_down <= filter_down2hold ? ~key_r2 : 1'b0;
end
end
endmodule
(5)sdram_ctrl.v
module sdram_ctrl(
input clk ,//100Mhz
input clk_in ,//50Mhz
input clk_out ,//50Mhz
input rst_n ,
//uart_rx
input [7:0] rx_data ,
input rx_data_vld,
//uart_tx
input ready ,
output [7:0] tx_data ,
output tx_data_vld,
//key_filter
input key_down ,
//sdram memory
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
);
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 ,//100Mhz
input clk_in ,//50Mhz
input clk_out ,//50Mhz
input rst_n ,
//uart_rx
input [7:0] rx_data ,
input rx_data_vld ,
//uart_tx
input ready ,
output [7:0] tx_data ,
output tx_data_vld ,
//key_filter
input 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)begin
state_c <= IDLE;
end
else begin
state_c <= state_n;
end
end
always @(*) begin
case(state_c)
IDLE : begin
if(idle2write)
state_n = WRITE;
else if(idle2read)
state_n = READ;
else
state_n = state_c;
end
WRITE : begin
if(write2done)
state_n = DONE;
else
state_n = state_c;
end
READ : begin
if(read2done)
state_n = DONE;
else
state_n = state_c;
end
DONE : state_n = IDLE;
default : ;
endcase
end
assign 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)begin
cnt_burst <= 'd0;
end
else if(add_cnt_burst)begin
if(end_cnt_burst)begin
cnt_burst <= 'd0;
end
else 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;
// end
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
wr_addr <= 'd0;
end
else if(add_wr_addr)begin
if(end_wr_addr)begin
wr_addr <= 'd0;
end
else 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)begin
rd_addr <= 'd0;
end
else if(add_rd_addr)begin
if(end_rd_addr)begin
rd_addr <= 'd0;
end
else 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的读写。(如果有错误的地方,还请大家指出来,谢谢!)