一. SDRAM基础特性
1.内部存储(Memory)
- bank-row-column
- 一共有4个bank,每个bank有213行,每一行有29列,每一个为16bit
2.刷新周期
8192refresh cycles/64ms,平均每 7.8us 刷新一行
3.数据读写和命令发送介绍
- SDRAM提供可编程突发长度的可编程读或写突发长度:1、2、4、8个位置或整页。(一页表示一行)
- 数据读写和命令发送都同步于sdram时钟上升沿
- 数据断电丢失
- 半双工并行通信,一次传输16bit
4.预充电和刷新的区别
- precharge all bank :一次刷新所有行(不定期)
- auto refresh:一次刷新某一行(定期)
二. 引脚描述
行地址13个,列地址9个,所以每个Bank=2^13 行*2^9 ,一页突发表示一行的突发
- CLK:SDRAM工作的时钟,这款芯片最高支持133M,所以要设定为133M以下
- CKE:时钟使能信号
- CS#:SDRAM片选信号(#表示低电平有效)
- CAS#,RAS#,WE#:这三个信号构成了对SDRAM的命令信号
- DQM:数据输入/输出掩码
- BA[1:0]:Bank地址,
- A[12:0]:地址线,当我们选择SDRAM某个Bank的Row(行)址的时候,需要到13根地址线(A0~A12);当选择Col(列)的时候,只用A0~A8这9根线;A10这个信号可以用来控制Auto-precharge
DQ [15:0]:双向数据总线(三态门)
三. AC特性表(需要的延时)
CAS:Column Address Select列选地址
RAS:Row Address Select 行选地址
latency:延迟
一些在代码中需要的延时时间
四. 模式寄存器设置
write model,burst type,CAS latency,Burst Length
- OP_MODE (写模式控制):突发写读/突发写单个读
- CAS_LATENCY (列选址延时):2/3(单位:clk)
- BURST_TYPE (突发类型 ):1时不能全页读写
- BURST_LENTH (突发长度 ):1/2/4/8/512 (每个数据:16bit)
五. 命令真值表,掩码
H: 高电平, L: 低电平, X: 不关心
在代码中需要用到的命令
- PRE_ALL_BANK (预充电所有bank)
- AUTO_REFRSH (自动刷新)
- MODE_REGISTER_SET(模式寄存器设置)
- ROW_ACTIVE(行激活)
- READ
- WRITE
- BURST_STOP(读写都可以终止)
- NO_OPREATION(无操作):该命令不会影响前一个命令执行的操作,该命令主要是为了保护当前的操作不会受到影响
六. 需要用到的时序图
1.写入NO_OPERATION,ROW_ACTIVE命令的时序图
2.读数据的时序图
- 读操作命令后根据设置的cas_latency(2/3clk)决定采样数据时间
- 发送完写(READ)命令后,下一个上升沿以后发送无操作(NOP)命令
- 在每一个时钟上升沿读取数据
3.写数据的时序图
- 发送完写(WRITE)命令后,下一个上升沿以后发送无操作(NOP)命令
- 在每一个时钟上升沿写入数据
4.写到预充电的时序图
写完数据后有一个T_DPL的延时
七. 代码、状态图、整体框架
1.整体框架
2.状态转换图
3 .代码
(1) sdram_interface(sdram接口代码)
module sdram_interface (
input clk ,//100sdram时钟
input rst_n ,
input [15:0] write_data ,//写入的数据
input [1:0] req ,//读写请求
input [14:0] mode_set ,//模式选择:bank+A0-A10
input [23:0] addr ,//bank+行地址+列地址(2+13+9)
output [15:0] read_data ,//读取的数据
output write_data_vld,
output read_data_vld,
output cke ,//时钟使能
output cs_n ,//片选,低电平有效
output [1:0] bank ,//块地址
output [12:0] rc_addr ,//行列地址设置
output ras_n ,//行选址,低电平有效
output cas_n ,//列选址,低电平有效
output we_n ,//低电平有效
output [1:0] dqm ,//掩码
inout [15:0] dq //数据输入输出
);
/* 参数定义 */
//状态参数
localparam POWER_ON = 10'b00000_00001,
PRE_ALL1 = 10'b00000_00010,
AUTO_REF1 = 10'b00000_00100,
MODE_SET = 10'b00000_01000,
IDLE = 10'b00000_10000,
AUTO_REF2 = 10'b00001_00000,
ROW_ACTIVE = 10'b00010_00000,
READ = 10'b00100_00000,
WRITE = 10'b01000_00000,
PRE_ALL2 = 10'b10000_00000;
//延时参数
localparam T_START = 20000 ,// 上电后等待200us
TRP = 2 ,// 行预充电30ns
TRRC = 8 ,// 自刷新80ns
TMRD = 2 ,// 模式设置后与新命令之间的间隔时间
TRCD = 2 ,// 行激活与列激活间隔时间
T_FRESH = 700 ,// 一行数据读写完的刷新时间
TDPL = 2 ;// 写完后与预充电命令的间隔时间
//命令参数
localparam PRE_ALL_CMD = 4'b0010,
AUTO_REF_CMD = 4'b0001,
MODE_SET_CMD = 4'b0000,
ROW_ACTIVE_CMD = 4'b0011,
READ_CMD = 4'b0101,
WRITE_CMD = 4'b0100,
BURST_STOP_CMD = 4'b0110,
NOP_CMD = 4'b0111;
//突发参数
localparam BURST_LENTH_1 = 1 ,
BURST_LENTH_2 = 2 ,
BURST_LENTH_4 = 4 ,
BURST_LENTH_8 = 8 ,
BURST_LENTH_FULL = 512;//全页突发模式,自定义读写字节数(<=512)
/* 信号定义 */
wire [15:0] dq_in;
wire [15:0] dq_out;
wire dq_out_enable;
reg [3:0] command ; //cs_n+cas_n+ras_n+we_n
reg cke_r ;
reg [1:0] bank_r ;
reg [12:0] rc_addr_r ;
reg [1:0] dqm_r ;
reg read_req ;
reg write_req ;
reg [11:0] burst_num;//突发长度
//计数器
reg [9:0] fresh_cnt; //行刷新计数器
wire add_fresh_cnt;
wire end_fresh_cnt;
reg fresh_flag; //刷新标志
reg fresh_cnt_flag;//刷新计时开始标志
reg [14:0] delay_cnt; //延时计数器
wire add_delay_cnt;
wire end_delay_cnt;
reg [14:0] delay_cnt_sel;//延时选择
reg delay_cnt_falg;//延时开始标志
reg [11:0] byte_cnt; //字节计数器
wire add_byte_cnt;
wire end_byte_cnt;
reg read_end_flag;//读写结束到需要延时的标志
reg write_end_flag;//读写结束到需要延时的标志
//状态跳转条件
wire power_preall1 ;
wire preall1_atref1;
wire atref1_modeset;
wire modeset_idle ;
wire idle_atref2 ;
wire idle_rowact ;
wire atref2_idle ;
wire rowact_read ;
wire rowact_write ;
wire read_preall2 ;
wire write_preall2 ;
wire preall2_idle ;
reg [9:0] state_c;
reg [9:0] state_n;
/* 代码编写 */
//状态转换
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
state_c <= POWER_ON;
end
else begin
state_c <= state_n;
end
end
//转换规律
always @(*) begin
case(state_c)
POWER_ON :
if (power_preall1) begin
state_n = PRE_ALL1;
end
else begin
state_n = state_c;
end
PRE_ALL1 :
if (preall1_atref1) begin
state_n = AUTO_REF1;
end
else begin
state_n = state_c;
end
AUTO_REF1 :
if (atref1_modeset) begin
state_n = MODE_SET;
end
else begin
state_n = state_c;
end
MODE_SET :
if (modeset_idle) begin
state_n = IDLE;
end
else begin
state_n = state_c;
end
IDLE :
if (idle_atref2) begin
state_n = AUTO_REF2;
end
else if (idle_rowact) begin
state_n = ROW_ACTIVE;
end
else begin
state_n = state_c;
end
AUTO_REF2 :
if (atref2_idle) begin
state_n = IDLE;
end
else begin
state_n = state_c;
end
ROW_ACTIVE :
if (rowact_read) begin
state_n = READ;
end
else if (rowact_write) begin
state_n = WRITE;
end
else begin
state_n = state_c;
end
READ :
if (read_preall2) begin
state_n = PRE_ALL2;
end
else begin
state_n = state_c;
end
WRITE :
if (write_preall2) begin
state_n = PRE_ALL2;
end
else begin
state_n = state_c;
end
PRE_ALL2 :
if (preall2_idle) begin
state_n = IDLE;
end
else begin
state_n = state_c;
end
default : state_n <= state_c ;
endcase
end
//转换条件
assign power_preall1 = state_c == POWER_ON && end_delay_cnt;
assign preall1_atref1 = state_c == PRE_ALL1 && end_delay_cnt;
assign atref1_modeset = state_c == AUTO_REF1 && end_delay_cnt;
assign modeset_idle = state_c == MODE_SET && end_delay_cnt;
assign idle_atref2 = state_c == IDLE && fresh_flag;
assign idle_rowact = state_c == IDLE && (read_req || write_req);
assign atref2_idle = state_c == AUTO_REF2 && end_delay_cnt;
assign rowact_read = state_c == ROW_ACTIVE && end_delay_cnt && read_req;
assign rowact_write = state_c == ROW_ACTIVE && end_delay_cnt && write_req;
assign read_preall2 = state_c == READ && end_delay_cnt;
assign write_preall2 = state_c == WRITE && end_delay_cnt;
assign preall2_idle = state_c == PRE_ALL2 && end_delay_cnt;
//fresh计数器
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
fresh_cnt <= 0;
end
else if (atref2_idle) begin
fresh_cnt <= 0;//行刷新完计数回归0
end
else if(add_fresh_cnt)begin
if(end_fresh_cnt)begin
fresh_cnt <= 0;
end
else begin
fresh_cnt <= fresh_cnt + 1;
end
end
else begin
fresh_cnt <= fresh_cnt;
end
end
assign add_fresh_cnt = fresh_cnt_flag;
assign end_fresh_cnt = add_fresh_cnt && fresh_cnt == T_FRESH - 1;
//fresh_flag
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
fresh_flag <= 0;
end
else if(end_fresh_cnt)begin
fresh_flag <= 1'b1;
end
else if (idle_atref2) begin
fresh_flag <= 1'b0;
end
end
//fresh_cnt_flag
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
fresh_cnt_flag <= 0;
end
else if(modeset_idle)begin
fresh_cnt_flag <= 1'b1;
end
end
//delay计数器
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
delay_cnt <= 0;
end
else if(add_delay_cnt)begin
if(end_delay_cnt)begin
delay_cnt <= 0;
end
else begin
delay_cnt <= delay_cnt + 1;
end
end
else begin
delay_cnt <= delay_cnt;
end
end
assign add_delay_cnt = delay_cnt_falg;
assign end_delay_cnt = add_delay_cnt && delay_cnt ==delay_cnt_sel - 1 ;
//delay_cnt_sel延时时间选择
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
delay_cnt_sel <= 0;
end
else if(state_c == POWER_ON )begin
delay_cnt_sel <= T_START;
end
else begin
case(state_c)
PRE_ALL1 : delay_cnt_sel <= TRP ;
AUTO_REF1 : delay_cnt_sel <= TRRC ;
MODE_SET : delay_cnt_sel <= TMRD ;
AUTO_REF2 : delay_cnt_sel <= TRRC ;
ROW_ACTIVE : delay_cnt_sel <= TRCD ;
READ : delay_cnt_sel <= TRP ;
WRITE : delay_cnt_sel <= TDPL ;
PRE_ALL2 : delay_cnt_sel <= TRP ;
default : delay_cnt_sel <= TRP ;
endcase
end
end
//delay_cnt_falg延时开始标志
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
delay_cnt_falg <= 0;
end
else if(state_n == POWER_ON || state_n == PRE_ALL1 || state_n ==AUTO_REF1 || state_n == MODE_SET)begin
delay_cnt_falg <= 1'b1;
end
else if (state_n == ROW_ACTIVE) begin
delay_cnt_falg <= 1'b1;
end
else if(state_n == PRE_ALL2 )begin
delay_cnt_falg <= 1'b1;
end
else if (state_n == READ && read_end_flag) begin
delay_cnt_falg <= 1'b1;
end
else if (state_n == WRITE && write_end_flag) begin
delay_cnt_falg <= 1'b1;
end
else if (state_n ==AUTO_REF2 ) begin
delay_cnt_falg <= 1'b1;
end
else begin
delay_cnt_falg <= 1'b0;
end
end
//cas_latency,byte_cnt,字节数=读写字节数+cas_lastency
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
byte_cnt <= 0;
end
else if (preall2_idle) begin
byte_cnt <= 0;
end
else if(add_byte_cnt)begin
if(end_byte_cnt)begin
byte_cnt <= 0;
end
else begin
byte_cnt <= byte_cnt + 1;
end
end
else begin
byte_cnt <= byte_cnt;
end
end
assign add_byte_cnt = state_c == READ || state_c == WRITE;
assign end_byte_cnt = add_byte_cnt && byte_cnt == 525;
//read_end_flag.write_end_flag
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
read_end_flag <= 0;
write_end_flag <= 0;
end
else if(state_c == READ && byte_cnt == burst_num - 1+2 )begin
read_end_flag <= 1'b1;
end
else if(state_c == WRITE && byte_cnt == burst_num - 1)begin
write_end_flag <= 1'b1;
end
else if (write_preall2) begin
write_end_flag <= 1'b0;
end
else if(read_preall2 )begin
read_end_flag <= 1'b0;
end
end
//burst_num
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
burst_num <= 1;
end
else begin
case (mode_set[2:0])
3'b000 : burst_num = BURST_LENTH_1 ;
3'b001 : burst_num = BURST_LENTH_2 ;
3'b010 : burst_num = BURST_LENTH_4 ;
3'b011 : burst_num = BURST_LENTH_8 ;
3'b111 : burst_num = BURST_LENTH_FULL;
default : burst_num = 1;
endcase
end
end
//command
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
command <= NOP_CMD;
end
else if (atref1_modeset) begin
command <= MODE_SET_CMD;
end
else if(power_preall1 || read_preall2 || write_preall2)begin
command <= PRE_ALL_CMD;
end
else if((state_c == WRITE && byte_cnt == burst_num - 1))begin
command <= BURST_STOP_CMD;
end
else if(idle_atref2 ||preall1_atref1)begin
command <= AUTO_REF_CMD;
end
else if (idle_rowact) begin
command <= ROW_ACTIVE_CMD;
end
else if (rowact_read ) begin
command <= READ_CMD;
end
else if (rowact_write ) begin
command <= WRITE_CMD;
end
else begin
command <= NOP_CMD;
end
end
//read_data,从sdram读取的数据
assign read_data = (state_c == READ && byte_cnt >= 2 && byte_cnt <= burst_num - 1 +2)?dq_in:1'b0;
assign read_data_vld = (state_c == READ && byte_cnt >= 2 && byte_cnt <= burst_num - 1+2 )?1'b1:1'b0;
assign write_data_vld = (state_c == WRITE && byte_cnt <= burst_num - 1)?1'b1:1'b0;
assign dq_out = (state_c == WRITE && byte_cnt <= burst_num - 1)?write_data:1'b0;
assign dq_out_enable = (state_c == WRITE && byte_cnt <= burst_num - 1)?1'b1:1'b0;
//read_req,write_req
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
read_req <= 0;
write_req <= 0;
end
else if(req[1])begin
read_req<=1'b1;
end
else if(req[0])begin
write_req<=1'b1;
end
else if (read_preall2 || write_preall2)begin
read_req <= 0;
write_req <= 0;
end
end
//bank_r,rc_addr_r
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
bank_r <= 0;
rc_addr_r <=0;
end
else if (atref1_modeset) begin
bank_r <= mode_set[14:13];
rc_addr_r <= mode_set[12:0];
end
else if(idle_rowact)begin
bank_r <= addr[23:22];
rc_addr_r <= addr[21:9];
end
else if (rowact_read || rowact_write) begin
rc_addr_r <= {4'b0,addr[8:0]};
end
end
//dq
assign dq_in = dq;
assign dq = dq_out_enable?dq_out:1'bz;
//与sdram的接口
assign cke = 1'b1;
assign cs_n = command[3] ;
assign bank = bank_r ;
assign rc_addr = rc_addr_r ;
assign ras_n = command[2] ;
assign cas_n = command[1] ;
assign we_n = command[0] ;
assign dqm = 2'b00;//不需要隐藏数据
endmodule //sdram_interface
(2). sdram_ctrl(sdram控制模块代码)
module sdram_ctrl (
input clk ,
input rst_n ,
input [1:0] key_down ,//按键
output [15:0] write_data ,//输出:接口模块的信号
output reg [1:0] req ,
output reg [14:0] mode_set ,
output reg [23:0] addr ,
output clk_100m ,
input [15:0] read_data ,//输入:接口模块的信号
input write_data_vld,
input read_data_vld,
//UART_TX信号
input busy ,
output [7:0] tx_data ,//传入uart_tx的数据
output tx_data_vld ,
//UART_RX信号
input [7:0] rx_data ,//输入的数据
input rx_data_vld
);
/* 参数定义 */
//MODE_SET模式设置参数
localparam OP_MODE = 1'b0 ,//写模式控制
CAS_LATENCY = 3'b010,//列选址延时
BURST_TYPE = 1'b0 ,//突发类型
BURST_LENTH = 3'b111;//突发长度
//读写地址
localparam RW_ADDR = 16'h0;
pll_100m pll_100m_inst (
.areset ( ~rst_n ),
.inclk0 ( clk),
.c0 ( clk_100m )
);
//req
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
req <= 2'b0;
end
else if(key_down[1])begin
req[1] =1'b1;
end
else if(key_down[0])begin
req[0] =1'b1;
end
else begin
req <= 2'b0;
end
end
//mode_set
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
mode_set <= 0;
end
else begin
mode_set <= {5'b0,OP_MODE,2'b0,CAS_LATENCY,BURST_TYPE,BURST_LENTH};
end
end
//addr
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
addr <= 16'h0;
end
else begin
addr <= RW_ADDR;
end
end
/* fifo */
//write_fifo 从UART_RX接受到数据写入sdram
write_fifo write_fifo_inst (
.aclr ( ~rst_n ),
.data ( wfifo_data_in ),
.rdclk ( clk_100m ),
.rdreq ( wfifo_rdreq ),
.wrclk ( clk ),
.wrreq ( wfifo_wrreq ),
.q ( wfifo_data_out),
.rdempty ( wfifo_rdempty ),
.rdfull ( wfifo_rdfull ),
.rdusedw ( wfifo_rdusedw ),
.wrempty ( wfifo_wrempty ),
.wrfull ( wfifo_wrfull ),
.wrusedw ( wfifo_wrusedw )
);
//wfifo读的信号
wire wfifo_rdreq ;
wire [15:0] wfifo_data_out ;
wire wfifo_rdempty ;
wire wfifo_rdfull ;
wire [11:0] wfifo_rdusedw ;
//wfifo写的信号
wire [15:0] wfifo_data_in ;
wire wfifo_wrreq ;
wire wfifo_wrempty ;
wire wfifo_wrfull ;
wire [11:0] wfifo_wrusedw ;
//写入wfifo
assign wfifo_wrreq = rx_data_vld && ~wfifo_wrfull;
assign wfifo_data_in = rx_data;
//读取fifo数据给sdram
assign wfifo_rdreq = ~wfifo_rdempty && write_data_vld;
assign write_data = wfifo_data_out ;
//read_fifo 从sdram中读取数据传入给UART_TX
read_fifo read_fifo_inst (
.aclr ( ~rst_n ),
.data ( rfifo_data_in ),
.rdclk ( clk ),
.rdreq ( rfifo_rdreq ),
.wrclk ( clk_100m ),
.wrreq ( rfifo_wrreq ),
.q ( rfifo_data_out),
.rdempty ( rfifo_rdempty ),
.rdfull ( rfifo_rdfull ),
.rdusedw ( rfifo_rdusedw ),
.wrempty ( rfifo_wrempty ),
.wrfull ( rfifo_wrfull ),
.wrusedw ( rfifo_wrusedw )
);
//rfifo读的信号
wire rfifo_rdreq ;
wire [15:0] rfifo_data_out ;
wire rfifo_rdempty ;
wire rfifo_rdfull ;
wire [11:0] rfifo_rdusedw ;
//rfifo写的信号
wire [15:0] rfifo_data_in ;
wire rfifo_wrreq ;
wire rfifo_wrempty ;
wire rfifo_wrfull ;
wire [11:0] rfifo_wrusedw ;
//写入fifo
assign rfifo_wrreq = read_data_vld && ~wfifo_wrfull ;
assign rfifo_data_in =read_data;
//读取rfifo数据给uart_tx
assign rfifo_rdreq = ~busy && ~rfifo_rdempty;
assign tx_data_vld = rfifo_rdreq;
assign tx_data = rfifo_data_out;
endmodule //sdram_ctrl
(3). TOP(顶层代码)
module top (
input clk ,
input rst_n ,
input [1:0] key_in ,
//串口接口
input uart_rxd ,
output uart_txd ,
//sdram接口
output clk_100m ,
output cke ,
output cs_n ,
output [1:0] bank ,
output [12:0] rc_addr ,
output ras_n ,
output cas_n ,
output we_n ,
output [1:0] dqm ,
inout [15:0] dq
);
//sdram_ctrl与sdram_interface连接的信号
wire [15:0] write_data;//写入sdram的数据
wire [1:0] req ;//读写请求
wire [14:0] mode_set ;//sdram模式设置
wire [23:0] addr ;//bank+行+列地址
//sdram_interface与sdram_ctrl连接的信号
wire [15:0] read_data ;//从sdram读取的数据
wire [1:0] key_down ;//按键检测
(* keep *) wire write_data_vld;
(* keep *) wire read_data_vld ;
//串口与sdram连接的信号
wire busy ;//串口正在传数据
wire [7:0] rx_data ;//串口接受到的数据
wire rx_data_vld;//接收数据有效
wire [7:0] tx_data ;//串口传输数据
wire tx_data_vld;//串口传输数据有效
uart_rx u_uart_rx(
/* input */ .clk (clk ) ,
/* input */ .rst_n (rst_n ) ,
/* input */ .uart_rxd (uart_rxd ) ,
/* */
/* output [7:0] */ .rx_data (rx_data ) ,
/* output */ .rx_data_vld(rx_data_vld)
);
uart_tx u_uart_tx(
/* input */ .clk (clk ) ,
/* input */ .rst_n (rst_n ) ,
/* input [7:0] */ .tx_data (tx_data ) ,
/* input */ .tx_data_vld(tx_data_vld) ,
/* output */ .busy (busy ) ,
.uart_txd (uart_txd )
);
//sdram_ctrl
sdram_ctrl u_sdram_ctrl(
/* input */ .clk (clk ) ,
/* input */ .rst_n (rst_n ) ,
/* input [1:0] */ .key_down (key_down ) ,//按键
/* output reg [15:0] */ .write_data(write_data) ,//输出:接口模块的信号
/* output reg [1:0] */ .req (req ) ,
/* output reg [14:0] */ .mode_set (mode_set ) ,
/* output reg [23:0] */ .addr (addr ) ,
/* output */ .clk_100m (clk_100m ) ,
/* input [15:0] */ .read_data (read_data ) ,//输入:接口模块的信号
.write_data_vld(write_data_vld) ,
.read_data_vld(read_data_vld) ,
/* */
/* */
/* //UART_TX信号 */
/* input */ .busy (busy ) ,
/* output [7:0] */ .tx_data (tx_data ) ,//传入uart_tx的数据
/* output */ .tx_data_vld(tx_data_vld) ,
/* //UART_RX信号 */
/* input [7:0] */ .rx_data (rx_data ) ,//输入的数据
/* input */ .rx_data_vld(rx_data_vld)
);
//sdram_interface
sdram_interface u_sdram_interface(
/* input */ .clk (clk_100m ) ,//100sdram时钟
/* input */ .rst_n (rst_n ) ,
/* input [15:0] */ .write_data(write_data) ,//写入的数据
/* input [1:0] */ .req (req ) ,//读写请求
/* input [14:0] */ .mode_set (mode_set ) ,//模式选择:bank+A0-A10
/* input [23:0] */ .addr (addr ) ,//bank+行地址+列地址(2+13+9)
/* output [15:0] */ .read_data (read_data ) ,//读取的数据
.write_data_vld(write_data_vld),
.read_data_vld(read_data_vld) ,
/* output */ .cke (cke ) ,//时钟使能
/* output */ .cs_n (cs_n ) ,//片选,低电平有效
/* output [1:0] */ .bank (bank ) ,//块地址
/* output [12:0] */ .rc_addr (rc_addr ) ,//行列地址设置
/* output */ .ras_n (ras_n ) ,//行选址,低电平有效
/* output */ .cas_n (cas_n ) ,//列选址,低电平有效
/* output */ .we_n (we_n ) ,//低电平有效
/* output [1:0] */ .dqm (dqm ) ,//掩码
/* inout [15:0] */ .dq (dq ) //数据输入输出
);
key_debounce u_key_debounce (
/* input */.clk (clk ),
/* input */.rst_n (rst_n ),
/* input [KEY_W-1:0] */ .key_in (key_in ),
/* */
/* output reg [KEY_W-1:0] */ .key_out (key_down) //检测到按下,输出一个周期的高脉冲,其他时刻为0
);
endmodule //top