文章目录
- 第50讲:SDRAM读写控制器的设计与验证
- 理论部分
- 设计与实现
- 1. sdram_ctrl
- sdram_init
- sdram_a_ref
- sdram_write
- sdram_read
- sdram_arbit
- sdram_ctrl
- 2. sdram_top
- fifo_ctrl
- sdram_top
- 3. uart_sdram
- uart_rx
- uart_tx
- fifo_read
- uart_sdram
第50讲:SDRAM读写控制器的设计与验证
理论部分
SDRAM全称“Synchronous Dynamic Random Access Memory”,译为“同步动态随机存取内存”或“同步动态随机存储器”,是动态随机存储器(Dynamic Random Access Memory,DRAM)家族的一份子。
设计与实现
1. sdram_ctrl
sdram_init
`timescale 1ns/1ns
module sdram_init
(
input wire sys_clk , //系统时钟,频率100MHz
input wire sys_rst_n , //复位信号,低电平有效
output reg [3:0] init_cmd , //初始化阶段写入sdram的指令,{cs_n,ras_n,cas_n,we_n}
output reg [1:0] init_ba , //初始化阶段Bank地址
output reg [12:0] init_addr , //初始化阶段地址数据,辅助预充电操作
//和配置模式寄存器操作,A12-A0,共13位
output wire init_end //初始化结束信号
);
// parameter define
parameter T_POWER = 15'd20_000 ; //上电后等待时钟数(200us)
//SDRAM初始化用到的控制信号命令
parameter P_CHARGE = 4'b0010 , //预充电指令
AUTO_REF = 4'b0001 , //自动刷新指令
NOP = 4'b0111 , //空操作指令
M_REG_SET = 4'b0000 ; //模式寄存器设置指令
//SDRAM初始化过程各个状态
parameter INIT_IDLE = 3'b000 , //初始状态
INIT_PRE = 3'b001 , //预充电状态
INIT_TRP = 3'b011 , //预充电等待 tRP
INIT_AR = 3'b010 , //自动刷新
INIT_TRF = 3'b100 , //自动刷新等待 tRC
INIT_MRS = 3'b101 , //模式寄存器设置
INIT_TMRD = 3'b111 , //模式寄存器设置等待 tMRD
INIT_END = 3'b110 ; //初始化完成
parameter TRP_CLK = 3'd2 , //预充电等待周期,20ns
TRC_CLK = 3'd7 , //自动刷新等待,70ns
TMRD_CLK = 3'd3 ; //模式寄存器设置等待周期,30ns
// wire define
wire wait_end ; //上电后200us等待结束标志
wire trp_end ; //预充电等待结束标志
wire trc_end ; //自动刷新等待结束标志
wire tmrd_end ; //模式寄存器设置等待结束标志
// reg define
reg [14:0] cnt_200us ; //SDRAM上电后200us稳定期计数器
reg [2:0] init_state ; //SDRAM初始化状态
reg [2:0] cnt_clk ; //时钟周期计数,记录初始化各状态等待周期数
reg cnt_clk_rst ; //时钟周期计数复位标志
reg [3:0] cnt_init_aref ; //初始化过程自动刷新次数计数器
//cnt_200us:SDRAM上电后200us稳定期计数器
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_200us <= 15'd0;
else if(cnt_200us == T_POWER)
cnt_200us <= T_POWER;
else
cnt_200us <= cnt_200us + 1'b1;
//wait_end:上电后200us等待结束标志
assign wait_end = (cnt_200us == (T_POWER - 1'b1)) ? 1'b1 : 1'b0;
//init_end:SDRAM初始化完毕信号
assign init_end = (init_state == INIT_END) ? 1'b1 : 1'b0;
//cnt_clk:时钟周期计数,记录初始化各状态等待时间
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_clk <= 3'd0;
else if(cnt_clk_rst == 1'b1)
cnt_clk <= 3'd0;
else
cnt_clk <= cnt_clk + 1'b1;
//cnt_init_aref:初始化过程自动刷新次数计数器
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_init_aref <= 4'd0;
else if(init_state == INIT_IDLE)
cnt_init_aref <= 4'd0;
else if(init_state == INIT_AR)
cnt_init_aref <= cnt_init_aref + 1'b1;
else
cnt_init_aref <= cnt_init_aref;
//trp_end,trc_end,tmrd_end:等待结束标志
assign trp_end = ((init_state == INIT_TRP ) && (cnt_clk == TRP_CLK )) ? 1'b1 : 1'b0;
assign trc_end = ((init_state == INIT_TRF ) && (cnt_clk == TRC_CLK )) ? 1'b1 : 1'b0;
assign tmrd_end = ((init_state == INIT_TMRD) && (cnt_clk == TMRD_CLK)) ? 1'b1 : 1'b0;
//SDRAM的初始化状态机
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
init_state <= INIT_IDLE;
else
case(init_state)
INIT_IDLE: //系统上电后,在初始状态等待200us跳转到预充电状态
if(wait_end == 1'b1)
init_state <= INIT_PRE;
else
init_state <= init_state;
INIT_PRE: //预充电状态,直接跳转到预充电等待状态
init_state <= INIT_TRP;
INIT_TRP: //预充电等待状态,等待结束,跳转到自动刷新状态
if(trp_end == 1'b1)
init_state <= INIT_AR;
else
init_state <= init_state;
INIT_AR : //自动刷新状态,直接跳转到自动刷新等待状态
init_state <= INIT_TRF;
INIT_TRF: //自动刷新等待状态,等待结束,自动跳转到模式寄存器设置状态
if(trc_end == 1'b1)
if(cnt_init_aref == 4'd8)
init_state <= INIT_MRS;
else
init_state <= INIT_AR;
else
init_state <= init_state;
INIT_MRS: //模式寄存器设置状态,直接跳转到模式寄存器设置等待状态
init_state <= INIT_TMRD;
INIT_TMRD: //模式寄存器设置等待状态,等待结束,跳到初始化完成状态
if(tmrd_end == 1'b1)
init_state <= INIT_END;
else
init_state <= init_state;
INIT_END: //初始化完成状态,保持此状态
init_state <= INIT_END;
default: init_state <= INIT_IDLE;
endcase
//cnt_clk_rst:时钟周期计数复位标志
always@(*)
begin
case (init_state)
INIT_IDLE: cnt_clk_rst <= 1'b1; //时钟周期计数复位信号,高有效,时钟周期计数清零
INIT_TRP: cnt_clk_rst <= (trp_end == 1'b1) ? 1'b1 : 1'b0;
//等待结束标志有效,计数器清零
INIT_TRF: cnt_clk_rst <= (trc_end == 1'b1) ? 1'b1 : 1'b0;
//等待结束标志有效,计数器清零
INIT_TMRD: cnt_clk_rst <= (tmrd_end == 1'b1) ? 1'b1 : 1'b0;
//等待结束标志有效,计数器清零
INIT_END: cnt_clk_rst <= 1'b1; //初始化完成,计数器清零
default: cnt_clk_rst <= 1'b0;
endcase
end
//SDRAM操作指令控制
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
begin
init_cmd <= NOP;
init_ba <= 2'b11;
init_addr <= 13'h1fff;
end
else
case(init_state)
INIT_IDLE,INIT_TRP,INIT_TRF,INIT_TMRD: //执行空操作指令
begin
init_cmd <= NOP;
init_ba <= 2'b11;
init_addr <= 13'h1fff;
end
INIT_PRE: //预充电指令
begin
init_cmd <= P_CHARGE;
init_ba <= 2'b11;
init_addr <= 13'h1fff;
end
INIT_AR: //自动刷新指令
begin
init_cmd <= AUTO_REF;
init_ba <= 2'b11;
init_addr <= 13'h1fff;
end
INIT_MRS: //模式寄存器设置指令
begin
init_cmd <= M_REG_SET;
init_ba <= 2'b00;
init_addr <=
{ //地址辅助配置模式寄存器,参数不同,配置的模式不同
3'b000, //A12-A10:预留
1'b0, //A9=0:读写方式,0:突发读&突发写,1:突发读&单写
2'b00, //{A8,A7}=00:标准模式,默认
3'b011, //{A6,A5,A4}=011:CAS潜伏期,010:2,011:3,其他:保留
1'b0, //A3=0:突发传输方式,0:顺序,1:隔行
3'b111 //{A2,A1,A0}=111:突发长度,000:单字节,001:2字节
//010:4字节,011:8字节,111:整页,其他:保留
};
end
INIT_END: //SDRAM初始化完成
begin
init_cmd <= NOP;
init_ba <= 2'b11;
init_addr <= 13'h1fff;
end
default:
begin
init_cmd <= NOP;
init_ba <= 2'b11;
init_addr <= 13'h1fff;
end
endcase
endmodule
sdram_a_ref
`timescale 1ns/1ns
module sdram_a_ref
(
input wire sys_clk , //系统时钟,频率100MHz
input wire sys_rst_n , //复位信号,低电平有效
input wire init_end , //初始化结束信号
input wire aref_en , //自动刷新使能
output reg aref_req , //自动刷新请求
output reg [3:0] aref_cmd , //自动刷新阶段写入sdram的指令,{cs_n,ras_n,cas_n,we_n}
output reg [1:0] aref_ba , //自动刷新阶段Bank地址
output reg [12:0] aref_addr , //地址数据,辅助预充电操作,A12-A0,13位地址
output wire aref_end //自动刷新结束标志
);
//parameter define
parameter CNT_REF_MAX = 10'd749 ; //自动刷新等待时钟数(7.5us)
parameter TRP_CLK = 3'd2 , //预充电等待周期
TRC_CLK = 3'd7 ; //自动刷新等待周期
parameter P_CHARGE = 4'b0010 , //预充电指令
A_REF = 4'b0001 , //自动刷新指令
NOP = 4'b0111 ; //空操作指令
parameter AREF_IDLE = 3'b000 , //初始状态,等待自动刷新使能
AREF_PCHA = 3'b001 , //预充电状态
AREF_TRP = 3'b011 , //预充电等待 tRP
AUTO_REF = 3'b010 , //自动刷新状态
AREF_TRF = 3'b100 , //自动刷新等待 tRC
AREF_END = 3'b101 ; //自动刷新结束
//wire define
wire trp_end ; //预充电等待结束标志
wire trc_end ; //自动刷新等待结束标志
wire aref_ack ; //自动刷新应答信号
//reg define
reg [9:0] cnt_aref ; //自动刷新计数器
reg [2:0] aref_state ; //SDRAM自动刷新状态
reg [2:0] cnt_clk ; //时钟周期计数,记录自刷新阶段各状态等待时间
reg cnt_clk_rst ; //时钟周期计数复位标志
reg [1:0] cnt_aref_aref ; //自动刷新次数计数器
//cnt_ref:刷新计数器
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_aref <= 10'd0;
else if(cnt_aref >= CNT_REF_MAX)
cnt_aref <= 10'd0;
else if(init_end == 1'b1)
cnt_aref <= cnt_aref + 1'b1;
else
cnt_aref <= cnt_aref;
//aref_req:自动刷新请求
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
aref_req <= 1'b0;
else if(cnt_aref == CNT_REF_MAX - 1'b1)
aref_req <= 1'b1;
else if(aref_ack == 1'b1)
aref_req <= 1'b0;
//aref_ack:自动刷新应答信号
assign aref_ack = (aref_state == AREF_PCHA ) ? 1'b1 : 1'b0;
//aref_end:自动刷新结束标志
assign aref_end = (aref_state == AREF_END ) ? 1'b1 : 1'b0;
//cnt_clk:时钟周期计数,记录初始化各状态等待时间
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_clk <= 3'd0;
else if(cnt_clk_rst == 1'b1)
cnt_clk <= 3'd0;
else
cnt_clk <= cnt_clk + 1'b1;
//trp_end,trc_end,tmrd_end:等待结束标志
assign trp_end = ((aref_state == AREF_TRP) && (cnt_clk == TRP_CLK )) ? 1'b1 : 1'b0;
assign trc_end = ((aref_state == AREF_TRF) && (cnt_clk == TRC_CLK )) ? 1'b1 : 1'b0;
//cnt_aref_aref:初始化过程自动刷新次数计数器
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_aref_aref <= 2'd0;
else if(aref_state == AREF_IDLE)
cnt_aref_aref <= 2'd0;
else if(aref_state == AUTO_REF)
cnt_aref_aref <= cnt_aref_aref + 1'b1;
else
cnt_aref_aref <= cnt_aref_aref;
//SDRAM自动刷新状态机
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
aref_state <= AREF_IDLE;
else
case(aref_state)
AREF_IDLE:
if((aref_en == 1'b1) && (init_end == 1'b1))
aref_state <= AREF_PCHA;
else
aref_state <= aref_state;
AREF_PCHA:
aref_state <= AREF_TRP;
AREF_TRP:
if(trp_end == 1'b1)
aref_state <= AUTO_REF;
else
aref_state <= aref_state;
AUTO_REF:
aref_state <= AREF_TRF;
AREF_TRF:
if(trc_end == 1'b1)
if(cnt_aref_aref == 2'd2)
aref_state <= AREF_END;
else
aref_state <= AUTO_REF;
else
aref_state <= aref_state;
AREF_END:
aref_state <= AREF_IDLE;
default:
aref_state <= AREF_IDLE;
endcase
//cnt_clk_rst:时钟周期计数复位标志
always@(*)
begin
case (aref_state)
AREF_IDLE: cnt_clk_rst <= 1'b1; //时钟周期计数器清零
AREF_TRP: cnt_clk_rst <= (trp_end == 1'b1) ? 1'b1 : 1'b0;
//等待结束标志有效,计数器清零
AREF_TRF: cnt_clk_rst <= (trc_end == 1'b1) ? 1'b1 : 1'b0;
//等待结束标志有效,计数器清零
AREF_END: cnt_clk_rst <= 1'b1;
default: cnt_clk_rst <= 1'b0;
endcase
end
//SDRAM操作指令控制
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
begin
aref_cmd <= NOP;
aref_ba <= 2'b11;
aref_addr <= 13'h1fff;
end
else
case(aref_state)
AREF_IDLE,AREF_TRP,AREF_TRF: //执行空操作指令
begin
aref_cmd <= NOP;
aref_ba <= 2'b11;
aref_addr <= 13'h1fff;
end
AREF_PCHA: //预充电指令
begin
aref_cmd <= P_CHARGE;
aref_ba <= 2'b11;
aref_addr <= 13'h1fff;
end
AUTO_REF: //自动刷新指令
begin
aref_cmd <= A_REF;
aref_ba <= 2'b11;
aref_addr <= 13'h1fff;
end
AREF_END: //一次自动刷新完成
begin
aref_cmd <= NOP;
aref_ba <= 2'b11;
aref_addr <= 13'h1fff;
end
default:
begin
aref_cmd <= NOP;
aref_ba <= 2'b11;
aref_addr <= 13'h1fff;
end
endcase
endmodule
sdram_write
`timescale 1ns/1ns
module sdram_write
(
input wire sys_clk , //系统时钟,频率100MHz
input wire sys_rst_n , //复位信号,低电平有效
input wire init_end , //初始化结束信号
input wire wr_en , //写使能
input wire [23:0] wr_addr , //写SDRAM地址
input wire [15:0] wr_data , //待写入SDRAM的数据(写FIFO传入)
input wire [9:0] wr_burst_len , //写突发SDRAM字节数
output wire wr_ack , //写SDRAM响应信号
output wire wr_end , //一次突发写结束
output reg [3:0] write_cmd , //写数据阶段写入sdram的指令,{cs_n,ras_n,cas_n,we_n}
output reg [1:0] write_ba , //写数据阶段Bank地址
output reg [12:0] write_addr , //地址数据,辅助预充电操作,行、列地址,A12-A0,13位地址
output reg wr_sdram_en , //数据总线输出使能
output wire [15:0] wr_sdram_data //写入SDRAM的数据
);
//parameter define
parameter TRCD_CLK = 10'd2 , //激活周期
TRP_CLK = 10'd2 ; //预充电周期
parameter WR_IDLE = 4'b0000 , //初始状态
WR_ACTIVE = 4'b0001 , //激活
WR_TRCD = 4'b0011 , //激活等待
WR_WRITE = 4'b0010 , //写操作
WR_DATA = 4'b0100 , //写数据
WR_PRE = 4'b0101 , //预充电
WR_TRP = 4'b0111 , //预充电等待
WR_END = 4'b0110 ; //一次突发写结束
parameter NOP = 4'b0111 , //空操作指令
ACTIVE = 4'b0011 , //激活指令
WRITE = 4'b0100 , //数据写指令
B_STOP = 4'b0110 , //突发停止指令
P_CHARGE = 4'b0010 ; //预充电指令
//wire define
wire trcd_end ; //激活等待周期结束
wire twrite_end ; //突发写结束
wire trp_end ; //预充电有效周期结束
//reg define
reg [3:0] write_state ; //SDRAM写状态
reg [9:0] cnt_clk ; //时钟周期计数,记录写数据阶段各状态等待时间
reg cnt_clk_rst ; //时钟周期计数复位标志
//wr_end:一次突发写结束
assign wr_end = (write_state == WR_END) ? 1'b1 : 1'b0;
//wr_ack:写SDRAM响应信号
assign wr_ack = ( write_state == WR_WRITE) || ((write_state == WR_DATA) && (cnt_clk <= wr_burst_len - 2'd2));
//cnt_clk:时钟周期计数,记录初始化各状态等待时间
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_clk <= 10'd0;
else if(cnt_clk_rst == 1'b1)
cnt_clk <= 10'd0;
else
cnt_clk <= cnt_clk + 1'b1;
//trcd_end,twrite_end,trp_end:等待结束标志
assign trcd_end = ((write_state == WR_TRCD)
&&(cnt_clk == TRCD_CLK )) ? 1'b1 : 1'b0; //激活周期结束
assign twrite_end = ((write_state == WR_DATA)
&&(cnt_clk == wr_burst_len - 1)) ? 1'b1 : 1'b0; //突发写结束
assign trp_end = ((write_state == WR_TRP )
&&(cnt_clk == TRP_CLK )) ? 1'b1 : 1'b0; //预充电等待周期结束
//write_state:SDRAM的工作状态机
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
write_state <= WR_IDLE;
else
case(write_state)
WR_IDLE:
if((wr_en ==1'b1) && (init_end == 1'b1))
write_state <= WR_ACTIVE;
else
write_state <= write_state;
WR_ACTIVE:
write_state <= WR_TRCD;
WR_TRCD:
if(trcd_end == 1'b1)
write_state <= WR_WRITE;
else
write_state <= write_state;
WR_WRITE:
write_state <= WR_DATA;
WR_DATA:
if(twrite_end == 1'b1)
write_state <= WR_PRE;
else
write_state <= write_state;
WR_PRE:
write_state <= WR_TRP;
WR_TRP:
if(trp_end == 1'b1)
write_state <= WR_END;
else
write_state <= write_state;
WR_END:
write_state <= WR_IDLE;
default:
write_state <= WR_IDLE;
endcase
//计数器控制逻辑
always@(*)
begin
case(write_state)
WR_IDLE: cnt_clk_rst <= 1'b1;
WR_TRCD: cnt_clk_rst <= (trcd_end == 1'b1) ? 1'b1 : 1'b0;
WR_WRITE: cnt_clk_rst <= 1'b1;
WR_DATA: cnt_clk_rst <= (twrite_end == 1'b1) ? 1'b1 : 1'b0;
WR_TRP: cnt_clk_rst <= (trp_end == 1'b1) ? 1'b1 : 1'b0;
WR_END: cnt_clk_rst <= 1'b1;
default: cnt_clk_rst <= 1'b0;
endcase
end
//SDRAM操作指令控制
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
begin
write_cmd <= NOP;
write_ba <= 2'b11;
write_addr <= 13'h1fff;
end
else
case(write_state)
WR_IDLE,WR_TRCD,WR_TRP:
begin
write_cmd <= NOP;
write_ba <= 2'b11;
write_addr <= 13'h1fff;
end
WR_ACTIVE: //激活指令
begin
write_cmd <= ACTIVE;
write_ba <= wr_addr[23:22];
write_addr <= wr_addr[21:9];
end
WR_WRITE: //写操作指令
begin
write_cmd <= WRITE;
write_ba <= wr_addr[23:22];
write_addr <= {4'b0000,wr_addr[8:0]};
end
WR_DATA: //突发传输终止指令
begin
if(twrite_end == 1'b1)
write_cmd <= B_STOP;
else
begin
write_cmd <= NOP;
write_ba <= 2'b11;
write_addr <= 13'h1fff;
end
end
WR_PRE: //预充电指令
begin
write_cmd <= P_CHARGE;
write_ba <= wr_addr[23:22];
write_addr <= 13'h0400;
end
WR_END:
begin
write_cmd <= NOP;
write_ba <= 2'b11;
write_addr <= 13'h1fff;
end
default:
begin
write_cmd <= NOP;
write_ba <= 2'b11;
write_addr <= 13'h1fff;
end
endcase
//wr_sdram_en:数据总线输出使能
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
wr_sdram_en <= 1'b0;
else
wr_sdram_en <= wr_ack;
//wr_sdram_data:写入SDRAM的数据
assign wr_sdram_data = (wr_sdram_en == 1'b1) ? wr_data : 16'd0;
endmodule
sdram_read
`timescale 1ns/1ns
module sdram_read
(
input wire sys_clk , //系统时钟,频率100MHz
input wire sys_rst_n , //复位信号,低电平有效
input wire init_end , //初始化结束信号
input wire rd_en , //读使能
input wire [23:0] rd_addr , //读SDRAM地址
input wire [15:0] rd_data , //自SDRAM中读出的数据
input wire [9:0] rd_burst_len , //读突发SDRAM字节数
output wire rd_ack , //读SDRAM响应信号
output wire rd_end , //一次突发读结束
output reg [3:0] read_cmd , //读数据阶段写入sdram的指令,{cs_n,ras_n,cas_n,we_n}
output reg [1:0] read_ba , //读数据阶段Bank地址
output reg [12:0] read_addr , //地址数据,辅助预充电操作,行、列地址,A12-A0,13位地址
output wire [15:0] rd_sdram_data //SDRAM读出的数据
);
//parameter define
parameter TRCD_CLK = 10'd2 , //激活等待周期
TCL_CLK = 10'd3 , //潜伏期
TRP_CLK = 10'd2 ; //预充电等待周期
parameter RD_IDLE = 4'b0000 , //空闲
RD_ACTIVE = 4'b0001 , //激活
RD_TRCD = 4'b0011 , //激活等待
RD_READ = 4'b0010 , //读操作
RD_CL = 4'b0100 , //潜伏期
RD_DATA = 4'b0101 , //读数据
RD_PRE = 4'b0111 , //预充电
RD_TRP = 4'b0110 , //预充电等待
RD_END = 4'b1100 ; //一次突发读结束
parameter NOP = 4'b0111 , //空操作指令
ACTIVE = 4'b0011 , //激活指令
READ = 4'b0101 , //数据读指令
B_STOP = 4'b0110 , //突发停止指令
P_CHARGE = 4'b0010 ; //预充电指令
//wire define
wire trcd_end ; //激活等待周期结束
wire trp_end ; //预充电等待周期结束
wire tcl_end ; //潜伏期结束标志
wire tread_end ; //突发读结束
wire rdburst_end ; //读突发终止
//reg define
reg [3:0] read_state ; //SDRAM写状态
reg [9:0] cnt_clk ; //时钟周期计数,记录初始化各状态等待时间
reg cnt_clk_rst ; //时钟周期计数复位标志
reg [15:0] rd_data_reg ;
//rd_data_reg
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
rd_data_reg <= 16'd0;
else
rd_data_reg <= rd_data;
//rd_end:一次突发读结束
assign rd_end = (read_state == RD_END) ? 1'b1 : 1'b0;
//rd_ack:读SDRAM响应信号
assign rd_ack = (read_state == RD_DATA) && (cnt_clk >= 10'd1) && (cnt_clk < (rd_burst_len + 2'd1));
//cnt_clk:时钟周期计数,记录初始化各状态等待时间
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_clk <= 10'd0;
else if(cnt_clk_rst == 1'b1)
cnt_clk <= 10'd0;
else
cnt_clk <= cnt_clk + 1'b1;
//trcd_end,trp_end,tcl_end,tread_end,rdburst_end:等待结束标志
assign trcd_end = ((read_state == RD_TRCD) && (cnt_clk == TRCD_CLK)) ? 1'b1 : 1'b0; //行选通周期结束
assign trp_end = ((read_state == RD_TRP ) && (cnt_clk == TRP_CLK)) ? 1'b1 : 1'b0; //预充电有效周期结束
assign tcl_end = ((read_state == RD_CL ) && (cnt_clk == TCL_CLK - 1)) ? 1'b1 : 1'b0; //潜伏期结束
assign tread_end = ((read_state == RD_DATA) && (cnt_clk == rd_burst_len + 2)) ? 1'b1 : 1'b0; //突发读结束
assign rdburst_end = ((read_state == RD_DATA) && (cnt_clk == rd_burst_len - 4)) ? 1'b1 : 1'b0; //读突发终止
//read_state:SDRAM的工作状态机
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
read_state <= RD_IDLE;
else
case(read_state)
RD_IDLE:
if((rd_en ==1'b1) && (init_end == 1'b1))
read_state <= RD_ACTIVE;
else
read_state <= RD_IDLE;
RD_ACTIVE:
read_state <= RD_TRCD;
RD_TRCD:
if(trcd_end == 1'b1)
read_state <= RD_READ;
else
read_state <= RD_TRCD;
RD_READ:
read_state <= RD_CL;
RD_CL:
read_state <= (tcl_end == 1'b1) ? RD_DATA : RD_CL;
RD_DATA:
read_state <= (tread_end == 1'b1) ? RD_PRE : RD_DATA;
RD_PRE:
read_state <= RD_TRP;
RD_TRP:
read_state <= (trp_end == 1'b1) ? RD_END : RD_TRP;
RD_END:
read_state <= RD_IDLE;
default:
read_state <= RD_IDLE;
endcase
//计数器控制逻辑
always@(*)
begin
case(read_state)
RD_IDLE: cnt_clk_rst <= 1'b1;
RD_TRCD: cnt_clk_rst <= (trcd_end == 1'b1) ? 1'b1 : 1'b0;
RD_READ: cnt_clk_rst <= 1'b1;
RD_CL: cnt_clk_rst <= (tcl_end == 1'b1) ? 1'b1 : 1'b0;
RD_DATA: cnt_clk_rst <= (tread_end == 1'b1) ? 1'b1 : 1'b0;
RD_TRP: cnt_clk_rst <= (trp_end == 1'b1) ? 1'b1 : 1'b0;
RD_END: cnt_clk_rst <= 1'b1;
default: cnt_clk_rst <= 1'b0;
endcase
end
//SDRAM操作指令控制
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
begin
read_cmd <= NOP;
read_ba <= 2'b11;
read_addr <= 13'h1fff;
end
else
case(read_state)
RD_IDLE,RD_TRCD,RD_TRP:
begin
read_cmd <= NOP;
read_ba <= 2'b11;
read_addr <= 13'h1fff;
end
RD_ACTIVE: //激活指令
begin
read_cmd <= ACTIVE;
read_ba <= rd_addr[23:22];
read_addr <= rd_addr[21:9];
end
RD_READ: //读操作指令
begin
read_cmd <= READ;
read_ba <= rd_addr[23:22];
read_addr <= {4'b0000,rd_addr[8:0]};
end
RD_DATA: //突发传输终止指令
begin
if(rdburst_end == 1'b1)
read_cmd <= B_STOP;
else
begin
read_cmd <= NOP;
read_ba <= 2'b11;
read_addr <= 13'h1fff;
end
end
RD_PRE: //预充电指令
begin
read_cmd <= P_CHARGE;
read_ba <= rd_addr[23:22];
read_addr <= 13'h0400;
end
RD_END:
begin
read_cmd <= NOP;
read_ba <= 2'b11;
read_addr <= 13'h1fff;
end
default:
begin
read_cmd <= NOP;
read_ba <= 2'b11;
read_addr <= 13'h1fff;
end
endcase
//rd_sdram_data:SDRAM读出的数据
assign rd_sdram_data = (rd_ack == 1'b1) ? rd_data_reg : 16'b0;
endmodule
sdram_arbit
`timescale 1ns/1ns
module sdram_arbit
(
input wire sys_clk , //系统时钟
input wire sys_rst_n , //复位信号
//sdram_init
input wire [3:0] init_cmd , //初始化阶段命令
input wire init_end , //初始化结束标志
input wire [1:0] init_ba , //初始化阶段Bank地址
input wire [12:0] init_addr , //初始化阶段数据地址
//sdram_auto_ref
input wire aref_req , //自刷新请求
input wire aref_end , //自刷新结束
input wire [3:0] aref_cmd , //自刷新阶段命令
input wire [1:0] aref_ba , //自动刷新阶段Bank地址
input wire [12:0] aref_addr , //自刷新阶段数据地址
//sdram_write
input wire wr_req , //写数据请求
input wire [1:0] wr_ba , //写阶段Bank地址
input wire [15:0] wr_data , //写入SDRAM的数据
input wire wr_end , //一次写结束信号
input wire [3:0] wr_cmd , //写阶段命令
input wire [12:0] wr_addr , //写阶段数据地址
input wire wr_sdram_en ,
//sdram_read
input wire rd_req , //读数据请求
input wire rd_end , //一次读结束
input wire [3:0] rd_cmd , //读阶段命令
input wire [12:0] rd_addr , //读阶段数据地址
input wire [1:0] rd_ba , //读阶段Bank地址
output reg aref_en , //自刷新使能
output reg wr_en , //写数据使能
output reg rd_en , //读数据使能
output wire sdram_cke , //SDRAM时钟使能
output wire sdram_cs_n , //SDRAM片选信号
output wire sdram_ras_n , //SDRAM行地址选通
output wire sdram_cas_n , //SDRAM列地址选通
output wire sdram_we_n , //SDRAM写使能
output reg [1:0] sdram_ba , //SDRAM Bank地址
output reg [12:0] sdram_addr , //SDRAM地址总线
inout wire [15:0] sdram_dq //SDRAM数据总线
);
//parameter define
parameter IDLE = 5'b0_0001 , //初始状态
ARBIT = 5'b0_0010 , //仲裁状态
AREF = 5'b0_0100 , //自动刷新状态
WRITE = 5'b0_1000 , //写状态
READ = 5'b1_0000 ; //读状态
parameter CMD_NOP = 4'b0111 ; //空操作指令
//reg define
reg [3:0] sdram_cmd ; //写入SDRAM命令
reg [4:0] state ; //状态机状态
//state:状态机状态
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
state <= IDLE;
else case(state)
IDLE: if(init_end == 1'b1)
state <= ARBIT;
else
state <= IDLE;
ARBIT: if(aref_req == 1'b1)
state <= AREF;
else if(wr_req == 1'b1)
state <= WRITE;
else if(rd_req == 1'b1)
state <= READ;
else
state <= ARBIT;
AREF: if(aref_end == 1'b1)
state <= ARBIT;
else
state <= AREF;
WRITE: if(wr_end == 1'b1)
state <= ARBIT;
else
state <= WRITE;
READ: if(rd_end == 1'b1)
state <= ARBIT;
else
state <= READ;
default:state <= IDLE;
endcase
//aref_en:自动刷新使能
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
aref_en <= 1'b0;
else if((state == ARBIT) && (aref_req == 1'b1))
aref_en <= 1'b1;
else if(aref_end == 1'b1)
aref_en <= 1'b0;
//wr_en:写数据使能
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
wr_en <= 1'b0;
else if((state == ARBIT) && (aref_req == 1'b0) && (wr_req == 1'b1))
wr_en <= 1'b1;
else if(wr_end == 1'b1)
wr_en <= 1'b0;
//rd_en:读数据使能
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
rd_en <= 1'b0;
else if((state == ARBIT) && (aref_req == 1'b0) && (rd_req == 1'b1))
rd_en <= 1'b1;
else if(rd_end == 1'b1)
rd_en <= 1'b0;
//sdram_cmd:写入SDRAM命令;sdram_ba:SDRAM Bank地址;sdram_addr:SDRAM地址总线
always@(*)
case(state)
IDLE: begin
sdram_cmd <= init_cmd;
sdram_ba <= init_ba;
sdram_addr <= init_addr;
end
AREF: begin
sdram_cmd <= aref_cmd;
sdram_ba <= aref_ba;
sdram_addr <= aref_addr;
end
WRITE: begin
sdram_cmd <= wr_cmd;
sdram_ba <= wr_ba;
sdram_addr <= wr_addr;
end
READ: begin
sdram_cmd <= rd_cmd;
sdram_ba <= rd_ba;
sdram_addr <= rd_addr;
end
default: begin
sdram_cmd <= CMD_NOP;
sdram_ba <= 2'b11;
sdram_addr <= 13'h1fff;
end
endcase
//SDRAM时钟使能
assign sdram_cke = 1'b1;
//SDRAM数据总线
assign sdram_dq = (wr_sdram_en == 1'b1) ? wr_data : 16'bz;
//片选信号,行地址选通信号,列地址选通信号,写使能信号
assign {sdram_cs_n, sdram_ras_n, sdram_cas_n, sdram_we_n} = sdram_cmd;
endmodule
sdram_ctrl
`timescale 1ns/1ns
module sdram_ctrl
(
input wire sys_clk , //系统时钟
input wire sys_rst_n , //复位信号,低电平有效
//SDRAM写端口
input wire sdram_wr_req , //写SDRAM请求信号
input wire [23:0] sdram_wr_addr , //SDRAM写操作的地址
input wire [9:0] wr_burst_len , //写sdram时数据突发长度
input wire [15:0] sdram_data_in , //写入SDRAM的数据
output wire sdram_wr_ack , //写SDRAM响应信号
//SDRAM读端口
input wire sdram_rd_req , //读SDRAM请求信号
input wire [23:0] sdram_rd_addr , //SDRAM读操作的地址
input wire [9:0] rd_burst_len , //读sdram时数据突发长度
output wire [15:0] sdram_data_out , //从SDRAM读出的数据
output wire init_end , //SDRAM 初始化完成标志
output wire sdram_rd_ack , //读SDRAM响应信号
//FPGA与SDRAM硬件接口
output wire sdram_cke , // SDRAM 时钟有效信号
output wire sdram_cs_n , // SDRAM 片选信号
output wire sdram_ras_n , // SDRAM 行地址选通
output wire sdram_cas_n , // SDRAM 列地址选通
output wire sdram_we_n , // SDRAM 写使能
output wire [1:0] sdram_ba , // SDRAM Bank地址
output wire [12:0] sdram_addr , // SDRAM 地址总线
inout wire [15:0] sdram_dq // SDRAM 数据总线
);
//wire define
//sdram_init
wire [3:0] init_cmd ; //初始化阶段写入sdram的指令
wire [1:0] init_ba ; //初始化阶段Bank地址
wire [12:0] init_addr ; //初始化阶段地址数据,辅助预充电操作
//sdram_a_ref
wire aref_req ; //自动刷新请求
wire aref_end ; //自动刷新结束标志
wire [3:0] aref_cmd ; //自动刷新阶段写入sdram的指令
wire [1:0] aref_ba ; //自动刷新阶段Bank地址
wire [12:0] aref_addr ; //地址数据,辅助预充电操作
wire aref_en ; //自动刷新使能
//sdram_write
wire wr_en ; //写使能
wire wr_end ; //一次写结束信号
wire [3:0] write_cmd ; //写阶段命令
wire [1:0] write_ba ; //写数据阶段Bank地址
wire [12:0] write_addr ; //写阶段数据地址
wire wr_sdram_en ; //SDRAM写使能
wire [15:0] wr_sdram_data; //写入SDRAM的数据
//sdram_read
wire rd_en ; //读使能
wire rd_end ; //一次突发读结束
wire [3:0] read_cmd ; //读数据阶段写入sdram的指令
wire [1:0] read_ba ; //读阶段Bank地址
wire [12:0] read_addr ; //读阶段数据地址
//------------- sdram_init_inst -------------
sdram_init sdram_init_inst
(
.sys_clk (sys_clk ), //系统时钟,频率100MHz
.sys_rst_n (sys_rst_n ), //复位信号,低电平有效
.init_cmd (init_cmd ), //初始化阶段写入sdram的指令
.init_ba (init_ba ), //初始化阶段Bank地址
.init_addr (init_addr ), //初始化阶段地址数据,辅助预充电操作
.init_end (init_end ) //初始化结束信号
);
//------------- sdram_arbit_inst -------------
sdram_arbit sdram_arbit_inst
(
.sys_clk (sys_clk ), //系统时钟
.sys_rst_n (sys_rst_n ), //复位信号
//sdram_init
.init_cmd (init_cmd ), //初始化阶段命令
.init_end (init_end ), //初始化结束标志
.init_ba (init_ba ), //初始化阶段Bank地址
.init_addr (init_addr ), //初始化阶段数据地址
//sdram_auto_ref
.aref_req (aref_req ), //自刷新请求
.aref_end (aref_end ), //自刷新结束
.aref_cmd (aref_cmd ), //自刷新阶段命令
.aref_ba (aref_ba ), //自动刷新阶段Bank地址
.aref_addr (aref_addr ), //自刷新阶段数据地址
//sdram_write
.wr_req (sdram_wr_req ), //写数据请求
.wr_end (wr_end ), //一次写结束信号
.wr_cmd (write_cmd ), //写阶段命令
.wr_ba (write_ba ), //写阶段Bank地址
.wr_addr (write_addr ), //写阶段数据地址
.wr_sdram_en(wr_sdram_en ), //SDRAM写使能
.wr_data (wr_sdram_data ), //写入SDRAM的数据
//sdram_read
.rd_req (sdram_rd_req ), //读数据请求
.rd_end (rd_end ), //一次读结束
.rd_cmd (read_cmd ), //读阶段命令
.rd_addr (read_addr ), //读阶段数据地址
.rd_ba (read_ba ), //读阶段Bank地址
.aref_en (aref_en ), //自刷新使能
.wr_en (wr_en ), //写数据使能
.rd_en (rd_en ), //读数据使能
.sdram_cke (sdram_cke ), //SDRAM时钟使能
.sdram_cs_n (sdram_cs_n ), //SDRAM片选信号
.sdram_ras_n(sdram_ras_n ), //SDRAM行地址选通
.sdram_cas_n(sdram_cas_n ), //SDRAM列地址选通
.sdram_we_n (sdram_we_n ), //SDRAM写使能
.sdram_ba (sdram_ba ), //SDRAM Bank地址
.sdram_addr (sdram_addr ), //SDRAM地址总线
.sdram_dq (sdram_dq ) //SDRAM数据总线
);
//------------- sdram_a_ref_inst -------------
sdram_a_ref sdram_a_ref_inst
(
.sys_clk (sys_clk ), //系统时钟,频率100MHz
.sys_rst_n (sys_rst_n ), //复位信号,低电平有效
.init_end (init_end ), //初始化结束信号
.aref_en (aref_en ), //自动刷新使能
.aref_req (aref_req ), //自动刷新请求
.aref_cmd (aref_cmd ), //自动刷新阶段写入sdram的指令
.aref_ba (aref_ba ), //自动刷新阶段Bank地址
.aref_addr (aref_addr ), //地址数据,辅助预充电操作
.aref_end (aref_end ) //自动刷新结束标志
);
//------------- sdram_write_inst -------------
sdram_write sdram_write_inst
(
.sys_clk (sys_clk ), //系统时钟,频率100MHz
.sys_rst_n (sys_rst_n ), //复位信号,低电平有效
.init_end (init_end ), //初始化结束信号
.wr_en (wr_en ), //写使能
.wr_addr (sdram_wr_addr ), //写SDRAM地址
.wr_data (sdram_data_in ), //待写入SDRAM的数据(写FIFO传入)
.wr_burst_len (wr_burst_len ), //写突发SDRAM字节数
.wr_ack (sdram_wr_ack ), //写SDRAM响应信号
.wr_end (wr_end ), //一次突发写结束
.write_cmd (write_cmd ), //写数据阶段写入sdram的指令
.write_ba (write_ba ), //写数据阶段Bank地址
.write_addr (write_addr ), //地址数据,辅助预充电操作
.wr_sdram_en (wr_sdram_en ), //数据总线输出使能
.wr_sdram_data (wr_sdram_data ) //写入SDRAM的数据
);
//------------- sdram_read_inst -------------
sdram_read sdram_read_inst
(
.sys_clk (sys_clk ), //系统时钟,频率100MHz
.sys_rst_n (sys_rst_n ), //复位信号,低电平有效
.init_end (init_end ), //初始化结束信号
.rd_en (rd_en ), //读使能
.rd_addr (sdram_rd_addr ), //读SDRAM地址
.rd_data (sdram_dq ), //自SDRAM中读出的数据
.rd_burst_len (rd_burst_len ), //读突发SDRAM字节数
.rd_ack (sdram_rd_ack ), //读SDRAM响应信号
.rd_end (rd_end ), //一次突发读结束
.read_cmd (read_cmd ), //读数据阶段写入sdram的指令
.read_ba (read_ba ), //读数据阶段Bank地址
.read_addr (read_addr ), //地址数据,辅助预充电操作
.rd_sdram_data (sdram_data_out ) //SDRAM读出的数据
);
endmodule
2. sdram_top
fifo_ctrl
`timescale 1ns/1ns
module fifo_ctrl
(
input wire sys_clk , //系统时钟
input wire sys_rst_n , //复位信号
//写fifo信号
input wire wr_fifo_wr_clk , //写FIFO写时钟
input wire wr_fifo_wr_req , //写FIFO写请求
input wire [15:0] wr_fifo_wr_data , //写FIFO写数据
input wire [23:0] sdram_wr_b_addr , //写SDRAM首地址
input wire [23:0] sdram_wr_e_addr , //写SDRAM末地址
input wire [9:0] wr_burst_len , //写SDRAM数据突发长度
input wire wr_rst , //写复位信号
//读fifo信号
input wire rd_fifo_rd_clk , //读FIFO读时钟
input wire rd_fifo_rd_req , //读FIFO读请求
input wire [23:0] sdram_rd_b_addr , //读SDRAM首地址
input wire [23:0] sdram_rd_e_addr , //读SDRAM末地址
input wire [9:0] rd_burst_len , //读SDRAM数据突发长度
input wire rd_rst , //读复位信号
output wire [15:0] rd_fifo_rd_data , //读FIFO读数据
output wire [9:0] rd_fifo_num , //读fifo中的数据量
input wire read_valid , //SDRAM读使能
input wire init_end , //SDRAM初始化完成标志
//SDRAM写信号
input wire sdram_wr_ack , //SDRAM写响应
output reg sdram_wr_req , //SDRAM写请求
output reg [23:0] sdram_wr_addr , //SDRAM写地址
output wire [15:0] sdram_data_in , //写入SDRAM的数据
//SDRAM读信号
input wire sdram_rd_ack , //SDRAM读相应
input wire [15:0] sdram_data_out , //读出SDRAM数据
output reg sdram_rd_req , //SDRAM读请求
output reg [23:0] sdram_rd_addr //SDRAM读地址
);
//wire define
wire wr_ack_fall ; //写响应信号下降沿
wire rd_ack_fall ; //读相应信号下降沿
wire [9:0] wr_fifo_num ; //写fifo中的数据量
//reg define
reg wr_ack_dly ; //写响应打拍
reg rd_ack_dly ; //读响应打拍
//wr_ack_dly:写响应信号打拍
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
wr_ack_dly <= 1'b0;
else
wr_ack_dly <= sdram_wr_ack;
//rd_ack_dly:读响应信号打拍
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
rd_ack_dly <= 1'b0;
else
rd_ack_dly <= sdram_rd_ack;
//wr_ack_fall,rd_ack_fall:检测读写响应信号下降沿
assign wr_ack_fall = (wr_ack_dly & ~sdram_wr_ack);
assign rd_ack_fall = (rd_ack_dly & ~sdram_rd_ack);
//sdram_wr_addr:sdram写地址
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
sdram_wr_addr <= 24'd0;
else if(wr_rst == 1'b1)
sdram_wr_addr <= sdram_wr_b_addr;
else if(wr_ack_fall == 1'b1) //一次突发写结束,更改写地址
begin
if(sdram_wr_addr < (sdram_wr_e_addr - wr_burst_len))
//不使用乒乓操作,一次突发写结束,更改写地址,未达到末地址,写地址累加
sdram_wr_addr <= sdram_wr_addr + wr_burst_len;
else //不使用乒乓操作,到达末地址,回到写起始地址
sdram_wr_addr <= sdram_wr_b_addr;
end
//sdram_rd_addr:sdram读地址
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
sdram_rd_addr <= 24'd0;
else if(rd_rst == 1'b1)
sdram_rd_addr <= sdram_rd_b_addr;
else if(rd_ack_fall == 1'b1) //一次突发读结束,更改读地址
begin
if(sdram_rd_addr < (sdram_rd_e_addr - rd_burst_len))
//读地址未达到末地址,读地址累加
sdram_rd_addr <= sdram_rd_addr + rd_burst_len;
else //到达末地址,回到首地址
sdram_rd_addr <= sdram_rd_b_addr;
end
//sdram_wr_req,sdram_rd_req:读写请求信号
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
begin
sdram_wr_req <= 1'b0;
sdram_rd_req <= 1'b0;
end
else if(init_end == 1'b1) //初始化完成后响应读写请求
begin //优先执行写操作,防止写入SDRAM中的数据丢失
if(wr_fifo_num >= wr_burst_len)
begin //写FIFO中的数据量达到写突发长度
sdram_wr_req <= 1'b1; //写请求有效
sdram_rd_req <= 1'b0;
end
else if((rd_fifo_num < rd_burst_len) && (read_valid == 1'b1))
begin //读FIFO中的数据量小于读突发长度,且读使能信号有效
sdram_wr_req <= 1'b0;
sdram_rd_req <= 1'b1; //读请求有效
end
else
begin
sdram_wr_req <= 1'b0;
sdram_rd_req <= 1'b0;
end
end
else
begin
sdram_wr_req <= 1'b0;
sdram_rd_req <= 1'b0;
end
//------------- wr_fifo_data -------------
fifo_data wr_fifo_data(
//用户接口
.wrclk (wr_fifo_wr_clk ), //写时钟
.wrreq (wr_fifo_wr_req ), //写请求
.data (wr_fifo_wr_data), //写数据
//SDRAM接口
.rdclk (sys_clk ), //读时钟
.rdreq (sdram_wr_ack ), //读请求
.q (sdram_data_in ), //读数据
.rdusedw (wr_fifo_num ), //FIFO中的数据量
.wrusedw ( ),
.aclr (~sys_rst_n || wr_rst) //清零信号
);
//------------- rd_fifo_data -------------
fifo_data rd_fifo_data(
//sdram接口
.wrclk (sys_clk ), //写时钟
.wrreq (sdram_rd_ack ), //写请求
.data (sdram_data_out ), //写数据
//用户接口
.rdclk (rd_fifo_rd_clk ), //读时钟
.rdreq (rd_fifo_rd_req ), //读请求
.q (rd_fifo_rd_data), //读数据
.rdusedw ( ),
.wrusedw (rd_fifo_num ), //FIFO中的数据量
.aclr (~sys_rst_n || rd_rst) //清零信号
);
endmodule
sdram_top
`timescale 1ns/1ns
module sdram_top
(
input wire sys_clk , //系统时钟
input wire clk_out , //相位偏移时钟
input wire sys_rst_n , //复位信号,低有效
//写FIFO信号
input wire wr_fifo_wr_clk , //写FIFO写时钟
input wire wr_fifo_wr_req , //写FIFO写请求
input wire [15:0] wr_fifo_wr_data , //写FIFO写数据
input wire [23:0] sdram_wr_b_addr , //写SDRAM首地址
input wire [23:0] sdram_wr_e_addr , //写SDRAM末地址
input wire [9:0] wr_burst_len , //写SDRAM数据突发长度
input wire wr_rst , //写复位信号
//读FIFO信号
input wire rd_fifo_rd_clk , //读FIFO读时钟
input wire rd_fifo_rd_req , //读FIFO读请求
input wire [23:0] sdram_rd_b_addr , //读SDRAM首地址
input wire [23:0] sdram_rd_e_addr , //读SDRAM末地址
input wire [9:0] rd_burst_len , //读SDRAM数据突发长度
input wire rd_rst , //读复位信号
output wire [15:0] rd_fifo_rd_data , //读FIFO读数据
output wire [9:0] rd_fifo_num , //读fifo中的数据量
input wire read_valid , //SDRAM读使能
output wire init_end , //SDRAM初始化完成标志
//SDRAM接口信号
output wire sdram_clk , //SDRAM芯片时钟
output wire sdram_cke , //SDRAM时钟有效信号
output wire sdram_cs_n , //SDRAM片选信号
output wire sdram_ras_n , //SDRAM行地址选通脉冲
output wire sdram_cas_n , //SDRAM列地址选通脉冲
output wire sdram_we_n , //SDRAM写允许位
output wire [1:0] sdram_ba , //SDRAM的L-Bank地址线
output wire [12:0] sdram_addr , //SDRAM地址总线
output wire [1:0] sdram_dqm , //SDRAM数据掩码
inout wire [15:0] sdram_dq //SDRAM数据总线
);
//wire define
wire sdram_wr_req ; //sdram 写请求
wire sdram_wr_ack ; //sdram 写响应
wire [23:0] sdram_wr_addr ; //sdram 写地址
wire [15:0] sdram_data_in ; //写入sdram中的数据
wire sdram_rd_req ; //sdram 读请求
wire sdram_rd_ack ; //sdram 读响应
wire [23:0] sdram_rd_addr ; //sdram 读地址
wire [15:0] sdram_data_out ; //从sdram中读出的数据
//sdram_clk:SDRAM芯片时钟
assign sdram_clk = clk_out;
//sdram_dqm:SDRAM数据掩码
assign sdram_dqm = 2'b00;
//------------- fifo_ctrl_inst -------------
fifo_ctrl fifo_ctrl_inst(
//system signal
.sys_clk (sys_clk ), //SDRAM控制时钟
.sys_rst_n (sys_rst_n ), //复位信号
//write fifo signal
.wr_fifo_wr_clk (wr_fifo_wr_clk ), //写FIFO写时钟
.wr_fifo_wr_req (wr_fifo_wr_req ), //写FIFO写请求
.wr_fifo_wr_data(wr_fifo_wr_data), //写FIFO写数据
.sdram_wr_b_addr(sdram_wr_b_addr), //写SDRAM首地址
.sdram_wr_e_addr(sdram_wr_e_addr), //写SDRAM末地址
.wr_burst_len (wr_burst_len ), //写SDRAM数据突发长度
.wr_rst (wr_rst ), //写清零信号
//read fifo signal
.rd_fifo_rd_clk (rd_fifo_rd_clk ), //读FIFO读时钟
.rd_fifo_rd_req (rd_fifo_rd_req ), //读FIFO读请求
.rd_fifo_rd_data(rd_fifo_rd_data), //读FIFO读数据
.rd_fifo_num (rd_fifo_num ), //读FIFO中的数据量
.sdram_rd_b_addr(sdram_rd_b_addr), //读SDRAM首地址
.sdram_rd_e_addr(sdram_rd_e_addr), //读SDRAM末地址
.rd_burst_len (rd_burst_len ), //读SDRAM数据突发长度
.rd_rst (rd_rst ), //读清零信号
//USER ctrl signal
.read_valid (read_valid ), //SDRAM读使能
.init_end (init_end ), //SDRAM初始化完成标志
//SDRAM ctrl of write
.sdram_wr_ack (sdram_wr_ack ), //SDRAM写响应
.sdram_wr_req (sdram_wr_req ), //SDRAM写请求
.sdram_wr_addr (sdram_wr_addr ), //SDRAM写地址
.sdram_data_in (sdram_data_in ), //写入SDRAM的数据
//SDRAM ctrl of read
.sdram_rd_ack (sdram_rd_ack ), //SDRAM读请求
.sdram_data_out (sdram_data_out ), //SDRAM读响应
.sdram_rd_req (sdram_rd_req ), //SDRAM读地址
.sdram_rd_addr (sdram_rd_addr ) //读出SDRAM数据
);
//------------- sdram_ctrl_inst -------------
sdram_ctrl sdram_ctrl_inst(
.sys_clk (sys_clk ), //系统时钟
.sys_rst_n (sys_rst_n ), //复位信号,低电平有效
//SDRAM 控制器写端口
.sdram_wr_req (sdram_wr_req ), //写SDRAM请求信号
.sdram_wr_addr (sdram_wr_addr ), //SDRAM写操作的地址
.wr_burst_len (wr_burst_len ), //写sdram时数据突发长度
.sdram_data_in (sdram_data_in ), //写入SDRAM的数据
.sdram_wr_ack (sdram_wr_ack ), //写SDRAM响应信号
//SDRAM 控制器读端口
.sdram_rd_req (sdram_rd_req ), //读SDRAM请求信号
.sdram_rd_addr (sdram_rd_addr ), //SDRAM写操作的地址
.rd_burst_len (rd_burst_len ), //读sdram时数据突发长度
.sdram_data_out (sdram_data_out ), //从SDRAM读出的数据
.init_end (init_end ), //SDRAM 初始化完成标志
.sdram_rd_ack (sdram_rd_ack ), //读SDRAM响应信号
//FPGA与SDRAM硬件接口
.sdram_cke (sdram_cke ), // SDRAM 时钟有效信号
.sdram_cs_n (sdram_cs_n ), // SDRAM 片选信号
.sdram_ras_n (sdram_ras_n ), // SDRAM 行地址选通脉冲
.sdram_cas_n (sdram_cas_n ), // SDRAM 列地址选通脉冲
.sdram_we_n (sdram_we_n ), // SDRAM 写允许位
.sdram_ba (sdram_ba ), // SDRAM L-Bank地址线
.sdram_addr (sdram_addr ), // SDRAM 地址总线
.sdram_dq (sdram_dq ) // SDRAM 数据总线
);
endmodule
3. uart_sdram
uart_rx
`timescale 1ns/1ns
module uart_rx
#(
parameter UART_BPS = 'd9600, //串口波特率
parameter CLK_FREQ = 'd50_000_000 //时钟频率
)
(
input wire sys_clk , //系统时钟50MHz
input wire sys_rst_n , //全局复位
input wire rx , //串口接收数据
output reg [7:0] po_data , //串转并后的8bit数据
output reg po_flag //串转并后的数据有效标志信号
);
//localparam define
localparam BAUD_CNT_MAX = CLK_FREQ/UART_BPS ;
//reg define
reg rx_reg1 ;
reg rx_reg2 ;
reg rx_reg3 ;
reg start_nedge ;
reg work_en ;
reg [12:0] baud_cnt ;
reg bit_flag ;
reg [3:0] bit_cnt ;
reg [7:0] rx_data ;
reg rx_flag ;
//插入两级寄存器进行数据同步,用来消除亚稳态
//rx_reg1:第一级寄存器,寄存器空闲状态复位为1
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
rx_reg1 <= 1'b1;
else
rx_reg1 <= rx;
//rx_reg2:第二级寄存器,寄存器空闲状态复位为1
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
rx_reg2 <= 1'b1;
else
rx_reg2 <= rx_reg1;
//rx_reg3:第三级寄存器和第二级寄存器共同构成下降沿检测
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
rx_reg3 <= 1'b1;
else
rx_reg3 <= rx_reg2;
//start_nedge:检测到下降沿时start_nedge产生一个时钟的高电平
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
start_nedge <= 1'b0;
else if((~rx_reg2) && (rx_reg3))
start_nedge <= 1'b1;
else
start_nedge <= 1'b0;
//work_en:接收数据工作使能信号
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
work_en <= 1'b0;
else if(start_nedge == 1'b1)
work_en <= 1'b1;
else if((bit_cnt == 4'd8) && (bit_flag == 1'b1))
work_en <= 1'b0;
//baud_cnt:波特率计数器计数,从0计数到BAUD_CNT_MAX - 1
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
baud_cnt <= 13'b0;
else if((baud_cnt == BAUD_CNT_MAX - 1) || (work_en == 1'b0))
baud_cnt <= 13'b0;
else if(work_en == 1'b1)
baud_cnt <= baud_cnt + 1'b1;
//bit_flag:当baud_cnt计数器计数到中间数时采样的数据最稳定,
//此时拉高一个标志信号表示数据可以被取走
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
bit_flag <= 1'b0;
else if(baud_cnt == BAUD_CNT_MAX/2 - 1)
bit_flag <= 1'b1;
else
bit_flag <= 1'b0;
//bit_cnt:有效数据个数计数器,当8个有效数据(不含起始位和停止位)
//都接收完成后计数器清零
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
bit_cnt <= 4'b0;
else if((bit_cnt == 4'd8) && (bit_flag == 1'b1))
bit_cnt <= 4'b0;
else if(bit_flag ==1'b1)
bit_cnt <= bit_cnt + 1'b1;
//rx_data:输入数据进行移位
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
rx_data <= 8'b0;
else if((bit_cnt >= 4'd1)&&(bit_cnt <= 4'd8)&&(bit_flag == 1'b1))
rx_data <= {rx_reg3, rx_data[7:1]};
//rx_flag:输入数据移位完成时rx_flag拉高一个时钟的高电平
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
rx_flag <= 1'b0;
else if((bit_cnt == 4'd8) && (bit_flag == 1'b1))
rx_flag <= 1'b1;
else
rx_flag <= 1'b0;
//po_data:输出完整的8位有效数据
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
po_data <= 8'b0;
else if(rx_flag == 1'b1)
po_data <= rx_data;
//po_flag:输出数据有效标志(比rx_flag延后一个时钟周期,为了和po_data同步)
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
po_flag <= 1'b0;
else
po_flag <= rx_flag;
endmodule
uart_tx
`timescale 1ns/1ns
module uart_tx
#(
parameter UART_BPS = 'd9600, //串口波特率
parameter CLK_FREQ = 'd50_000_000 //时钟频率
)
(
input wire sys_clk , //系统时钟50MHz
input wire sys_rst_n , //全局复位
input wire [7:0] pi_data , //模块输入的8bit数据
input wire pi_flag , //并行数据有效标志信号
output reg tx //串转并后的1bit数据
);
//localparam define
localparam BAUD_CNT_MAX = CLK_FREQ/UART_BPS ;
//reg define
reg [12:0] baud_cnt;
reg bit_flag;
reg [3:0] bit_cnt ;
reg work_en ;
//work_en:接收数据工作使能信号
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
work_en <= 1'b0;
else if(pi_flag == 1'b1)
work_en <= 1'b1;
else if((bit_flag == 1'b1) && (bit_cnt == 4'd9))
work_en <= 1'b0;
//baud_cnt:波特率计数器计数,从0计数到BAUD_CNT_MAX - 1
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
baud_cnt <= 13'b0;
else if((baud_cnt == BAUD_CNT_MAX - 1) || (work_en == 1'b0))
baud_cnt <= 13'b0;
else if(work_en == 1'b1)
baud_cnt <= baud_cnt + 1'b1;
//bit_flag:当baud_cnt计数器计数到1时让bit_flag拉高一个时钟的高电平
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
bit_flag <= 1'b0;
else if(baud_cnt == 13'd1)
bit_flag <= 1'b1;
else
bit_flag <= 1'b0;
//bit_cnt:数据位数个数计数,10个有效数据(含起始位和停止位)到来后计数器清零
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
bit_cnt <= 4'b0;
else if((bit_flag == 1'b1) && (bit_cnt == 4'd9))
bit_cnt <= 4'b0;
else if((bit_flag == 1'b1) && (work_en == 1'b1))
bit_cnt <= bit_cnt + 1'b1;
//tx:输出数据在满足rs232协议(起始位为0,停止位为1)的情况下一位一位输出
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
tx <= 1'b1; //空闲状态时为高电平
else if(bit_flag == 1'b1)
case(bit_cnt)
0 : tx <= 1'b0;
1 : tx <= pi_data[0];
2 : tx <= pi_data[1];
3 : tx <= pi_data[2];
4 : tx <= pi_data[3];
5 : tx <= pi_data[4];
6 : tx <= pi_data[5];
7 : tx <= pi_data[6];
8 : tx <= pi_data[7];
9 : tx <= 1'b1;
default : tx <= 1'b1;
endcase
endmodule
fifo_read
`timescale 1ns/1ns
module fifo_read
(
input wire sys_clk , //系统时钟,频率50MHz
input wire sys_rst_n , //复位信号,低电平有效
input wire [9:0] rd_fifo_num , //SDRAM中读fifo中数据个数
input wire [7:0] pi_data , //读出数据
input wire [9:0] burst_num , //一次突发数据个数
output reg read_en , //SDRAM中读fifo的读使能
output wire [7:0] tx_data , //输出数据
output reg tx_flag //输出数据标志信号
);
//parameter define
parameter BAUD_CNT_END = 13'd5207 ,
BAUD_CNT_END_HALF = 13'd2603 ;
parameter CNT_WAIT_MAX = 24'd4_999_999 ;
//wire define
wire [9:0] data_num ; //fifo中数据个数
//reg define
reg read_en_dly ;
reg [12:0] baud_cnt ;
reg rd_en ;
reg rd_flag ;
reg [9:0] cnt_read ;
reg [3:0] bit_cnt ;
reg bit_flag ;
//read_en:SDRAM中读fifo的读使能
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
read_en <= 1'b0;
else if(rd_fifo_num == burst_num)
read_en <= 1'b1;
else if(data_num == burst_num - 2)
read_en <= 1'b0;
//read_en_dly:SDRAM中读fifo的读使能打拍
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
read_en_dly <= 1'b0;
else
read_en_dly <= read_en;
//rd_flag:向tx模块发送数据使能
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
rd_flag <= 1'b0;
else if(cnt_read == burst_num)
rd_flag <= 1'b0;
else if(data_num == burst_num)
rd_flag <= 1'b1;
//baud_cnt:波特率计数器计数从0计数到BAUD_CNT_END
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
baud_cnt <= 13'd0;
else if(baud_cnt == BAUD_CNT_END)
baud_cnt <= 13'd0;
else if(rd_flag == 1'b1)
baud_cnt <= baud_cnt + 1'b1;
//bit_flag:bit计数器计数使能
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
bit_flag <= 1'b0;
else if(baud_cnt == BAUD_CNT_END_HALF)
bit_flag <= 1'b1;
else
bit_flag <= 1'b0;
//bit_cnt:bit计数器
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
bit_cnt <= 4'b0;
else if((bit_cnt == 4'd9) && (bit_flag == 1'b1))
bit_cnt <= 4'b0;
else if(bit_flag == 1'b1)
bit_cnt <= bit_cnt + 1'b1;
//rd_en:读fifo的读使能
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
rd_en <= 1'b0;
else if(bit_cnt == 4'd9 && bit_flag == 1'b1)
rd_en <= 1'b1;
else
rd_en <= 1'b0;
//cnt_read:读出数据计数
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_read <= 10'd0;
else if(cnt_read == burst_num)
cnt_read <= 10'b0;
else if(rd_en == 1'b1)
cnt_read <= cnt_read + 1'b1;
else
cnt_read <= cnt_read;
//tx_flag:读出数据标志信号
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
tx_flag <= 1'b0;
else
tx_flag <= rd_en;
//-------------fifo_read_inst--------------
read_fifo read_fifo_inst(
.clock (sys_clk ), //input clk
.data (pi_data ), //input [7 : 0] din
.wrreq (read_en_dly ), //input wr_en
.rdreq (rd_en ), //input rd_en
.q (tx_data ), //output [7 : 0] dout
.usedw (data_num )
);
endmodule
uart_sdram
`timescale 1ns/1ns
module uart_sdram
(
input wire sys_clk , //时钟信号
input wire sys_rst_n , //复位信号
input wire rx , //串口接收数据
output wire tx , //串口发送数据
output wire sdram_clk , //SDRAM 芯片时钟
output wire sdram_cke , //SDRAM 时钟有效
output wire sdram_cs_n , //SDRAM 片选
output wire sdram_cas_n , //SDRAM 行有效
output wire sdram_ras_n , //SDRAM 列有效
output wire sdram_we_n , //SDRAM 写有效
output wire [1:0] sdram_ba , //SDRAM Bank地址
output wire [12:0] sdram_addr , //SDRAM 行/列地址
output wire [1:0] sdram_dqm , //SDRAM 数据掩码
inout wire [15:0] sdram_dq //SDRAM 数据
);
//parameter define
parameter DATA_NUM = 24'd10 ; //写入SDRAM数据个数
parameter WAIT_MAX = 16'd750 ; //等待计数最大值
parameter UART_BPS = 14'd9600 , //比特率
CLK_FREQ = 26'd50_000_000 ; //时钟频率
// wire define
//uart_rx
wire [ 7:0] rx_data ; //串口接收模块拼接后的8位数据
wire rx_flag ; //数据标志信号
//fifo_read
wire [ 7:0] rfifo_wr_data ; //读fifo发热写入数据
wire rfifo_wr_en ; //读fifo的写使能
wire [ 7:0] rfifo_rd_data ; //读fifo的读数据
wire rfifo_rd_en ; //读fifo的读使能
wire [9:0] rd_fifo_num ; //读fifo中的数据量
//clk_gen
wire clk_50m ;
wire clk_100m ;
wire clk_100m_shift ; //pll产生时钟
wire locked ; //pll锁定信号
wire rst_n ; //复位信号
//sdram_top_inst
reg [23:0] data_num ; //写入SDRAM数据个数计数
reg read_valid ; //数据读使能
reg [15:0] cnt_wait ; //等待计数器
//rst_n:复位信号
assign rst_n = sys_rst_n & locked;
//data_num:写入SDRAM数据个数计数
always@(posedge clk_50m or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
data_num <= 24'd0;
else if(read_valid == 1'b1)
data_num <= 24'd0;
else if(rx_flag == 1'b1)
data_num <= data_num + 1'b1;
else
data_num <= data_num;
//cnt_wait:等待计数器
always@(posedge clk_50m or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_wait <= 16'd0;
else if(cnt_wait == WAIT_MAX)
cnt_wait <= 16'd0;
else if(data_num == DATA_NUM)
cnt_wait <= cnt_wait + 1'b1;
//read_valid:数据读使能
always@(posedge clk_50m or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
read_valid <= 1'b0;
else if(cnt_wait == WAIT_MAX)
read_valid <= 1'b1;
else if(rd_fifo_num == DATA_NUM)
read_valid <= 1'b0;
//------------- clk_gen_inst -------------
clk_gen clk_gen_inst (
.inclk0 (sys_clk ),
.areset (~sys_rst_n ),
.c0 (clk_50m ),
.c1 (clk_100m ),
.c2 (clk_100m_shift ),
.locked (locked )
);
//-------------uart_rx_inst-------------
uart_rx
#(
.UART_BPS (UART_BPS ), //串口波特率
.CLK_FREQ (CLK_FREQ ) //时钟频率
)
uart_rx_inst
(
.sys_clk (clk_50m ), //input sys_clk
.sys_rst_n (rst_n ), //input sys_rst_n
.rx (rx ), //input rx
.po_data (rx_data ), //output [7:0] rx_data
.po_flag (rx_flag ) //output rx_flag
);
//------------- sdram_top_inst -------------
sdram_top sdram_top_inst
(
.sys_clk (clk_100m ), //sdram 控制器参考时钟
.clk_out (clk_100m_shift ), //用于输出的相位偏移时钟
.sys_rst_n (rst_n ), //系统复位
//用户写端口
.wr_fifo_wr_clk (clk_50m ), //写端口FIFO: 写时钟
.wr_fifo_wr_req (rx_flag ), //写端口FIFO: 写使能
.wr_fifo_wr_data ({8'b0,rx_data} ), //写端口FIFO: 写数据
.sdram_wr_b_addr (24'd0 ), //写SDRAM的起始地址
.sdram_wr_e_addr (DATA_NUM ), //写SDRAM的结束地址
.wr_burst_len (DATA_NUM ), //写SDRAM时的数据突发长度
.wr_rst ( ), //写复位
//用户读端口
.rd_fifo_rd_clk (clk_50m ), //读端口FIFO: 读时钟
.rd_fifo_rd_req (rfifo_wr_en ), //读端口FIFO: 读使能
.rd_fifo_rd_data (rfifo_wr_data ), //读端口FIFO: 读数据
.sdram_rd_b_addr (24'd0 ), //读SDRAM的起始地址
.sdram_rd_e_addr (DATA_NUM ), //读SDRAM的结束地址
.rd_burst_len (DATA_NUM ), //从SDRAM中读数据时的突发长度
.rd_rst ( ), //读复位
.rd_fifo_num (rd_fifo_num ), //读fifo中的数据量
//用户控制端口
.read_valid (read_valid ), //SDRAM 读使能
.init_end ( ), //SDRAM 初始化完成标志
//SDRAM 芯片接口
.sdram_clk (sdram_clk ), //SDRAM 芯片时钟
.sdram_cke (sdram_cke ), //SDRAM 时钟有效
.sdram_cs_n (sdram_cs_n ), //SDRAM 片选
.sdram_ras_n (sdram_ras_n ), //SDRAM 行有效
.sdram_cas_n (sdram_cas_n ), //SDRAM 列有效
.sdram_we_n (sdram_we_n ), //SDRAM 写有效
.sdram_ba (sdram_ba ), //SDRAM Bank地址
.sdram_addr (sdram_addr ), //SDRAM 行/列地址
.sdram_dq (sdram_dq ), //SDRAM 数据
.sdram_dqm (sdram_dqm ) //SDRAM 数据掩码
);
//------------- fifo_read_inst --------------
fifo_read fifo_read_inst
(
.sys_clk (clk_50m ), //input sys_clk
.sys_rst_n (sys_rst_n ), //input sys_rst_n
.rd_fifo_num (rd_fifo_num ),
.pi_data (rfifo_wr_data ), //input [7:0] pi_data
.burst_num (DATA_NUM ),
.read_en (rfifo_wr_en ), //input pi_flag
.tx_data (rfifo_rd_data ), //output [7:0] tx_data
.tx_flag (rfifo_rd_en ) //output tx_flag
);
//-------------uart_tx_inst-------------
uart_tx
#(
.UART_BPS (UART_BPS ), //串口波特率
.CLK_FREQ (CLK_FREQ ) //时钟频率
)
uart_tx_inst
(
.sys_clk (sys_clk ), //input sys_clk
.sys_rst_n (sys_rst_n ), //input sys_rst_n
.pi_data (rfifo_rd_data ), //input [7:0] pi_data
.pi_flag (rfifo_rd_en ), //input pi_flag
.tx (tx ) //output tx
);
endmodule