不带自动预充电的 页突发数据读模式:
读取6个数据 发送页突发停止指令。 第六个周期就写入页突发停止指令。
读指令后会有潜伏期之后,才会读数据。 A4-A6为潜伏期。 011 为三个潜伏期。
潜伏期之后读数据,突发长度为 潜伏期+读数据长度 13个周期
cnt_clk cnt_clk_rst 信号也需要。
激活信号等待结束信号trcd_end 潜伏期等待结束信号tcl_end 读状态的等待结束信号trd_end 预充电等待结束信号trp_end
同步数据到当前时钟频率下 跨时钟域信号处理
输入数据通过寄存器打一拍,rd_data_reg
bank 地址和地址总线 开始为全1,激活后地址为全0 表示对第0个bank第0行,数据读取时写入数据列地址。 潜伏期等待全为1,写入突发终止指令在读指令开始的下个周期写入,开始计数,第n个周期开始写入。对所有bank进行预充电 地址总线写入13'h400. A10 为高电平,表示对所有bank进行操作。
程序
(
input wire sys_clk,
input wire sys_rst_n,
input wire init_end,
input wire [23:0]rd_addr, //两位宽bank地址 13位宽行地址 9位宽列地址
input wire [15:0]rd_data, //sdram 芯片位宽为16位
input wire [9:0]rd_burst_len, //我们使用页突发,我们使用512,表示512需要10位
input wire rd_en,
output reg [3:0]rd_cmd,
output reg [1:0]rd_ba,
output reg [12:0]rd_sdram_addr,
output reg rd_sdram_en,
output wire rd_end,
output wire [15:0]rd_sdram_data,
output wire rd_ack
);
reg [15:0]rd_data_reg;
wire rd_b_end;
reg [3:0]rd_state;
reg [9:0]cnt_clk;
reg cnt_clk_rst;
wire trcd_end;
wire tcl_end;
wire trd_end;
wire trp_end;
//指令
parameter NOP = 4'b0111,
ACTIVE = 4'b0011,
WR_CMD = 4'b0100,
RD_CMD = 4'B0101,
B_STOP = 4'b0110,
P_CHARGE =4'b0010;
//格雷码表示状态 读状态九个状态,
parameter RD_IDLE = 4'b0000,
RD_ACTIVE = 4'b0001,
RD_TRCD = 4'b0011,
READ= 4'b0010,
RD_CL = 4'b0110,
RD_DATA = 4'b0111,
RD_PCH = 4'b0101,
RD_TRP = 4'b0100,
RD_END = 4'b1100;
//等待的参数
parameter TRCD = 3'd2,
TCL = 3'd3,
TRP = 3'd7;
// 读数据 数据寄存
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;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
rd_state <= RD_IDLE;
else
case(rd_state)
RD_IDLE:
if(init_end == 1'b1 && rd_en == 1'b1)
rd_state <= RD_ACTIVE;
else
rd_state <= rd_state;
RD_ACTIVE:
rd_state <= RD_TRCD;
RD_TRCD:
if(trcd_end == 1'b1 )
rd_state <= READ;
else
rd_state <= rd_state;
READ:
rd_state <= RD_CL;
RD_CL:
rd_state <= (tcl_end == 1'b1 )?RD_DATA:RD_CL;
RD_DATA:
rd_state <= (trd_end == 1'b1 )?RD_PCH:RD_DATA;
RD_PCH:
rd_state <= RD_TRP;
RD_TRP:
rd_state <= (trp_end == 1'b1 )?RD_END:RD_TRP;
RD_END:
rd_state <= RD_IDLE;
default:
rd_state <= RD_IDLE;
endcase
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;
//复位信号的赋值
always@(*)
begin
case(rd_state)
RD_IDLE: cnt_clk_rst <= 1'b1;
RD_TRCD: cnt_clk_rst <= (trcd_end == 1'b1) ? 1'b1:1'b0;
READ :cnt_clk_rst <= 1'b1;
RD_CL: cnt_clk_rst <= (tcl_end == 1'b1) ? 1'b1:1'b0;
RD_DATA:cnt_clk_rst <= (trd_end==1'b1)?1'b1:1'b0;
RD_PCH: 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
//等待结束信号的赋值
assign trcd_end = ((rd_state <= RD_TRCD)&&(cnt_clk == TRCD))? 1'b1:1'b0;
assign tcl_end = ((rd_state <= RD_CL)&&(cnt_clk == TCL))? 1'b1:1'b0;
assign trd_end = ((rd_state <= RD_DATA)&&(cnt_clk == (rd_burst_len-1+TCL)))? 1'b1:1'b0;
assign trp_end =((rd_state <= RD_TRP)&& (cnt_clk == TRP))? 1'b1:1'b0;
//用来确定突发终止指令的写入位置
assign rd_b_end =(cnt_clk == (rd_burst_len-1'b1-TCL))? 1'b1:1'b0;
//读响应信号赋值
assign rd_ack = ((rd_state==RD_DATA)&&(cnt_clk <= rd_burst_len)&&(cnt_clk>=1'b1))? 1'b1:1'b0;
//结束信号
assign rd_end = (rd_state == RD_END)?1'b1:1'b0;
//地址的赋值
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
begin
rd_cmd <= NOP;
rd_ba <= 2'b11;
rd_sdram_addr <= 13'h1fff;
end
//结合状态机进行赋值
else
case(rd_state)
RD_IDLE,RD_TRCD,RD_TRP:
begin
rd_cmd <= NOP;
rd_ba <= 2'b11;
rd_sdram_addr <= 13'h1fff;
end
RD_ACTIVE:
begin
rd_cmd <= ACTIVE;
rd_ba <= rd_addr[23:24];
rd_sdram_addr <= rd_addr[21:9];
end
READ:
begin
rd_cmd <= RD_CMD;
rd_ba <= rd_addr[23:22];
//列地址 分时复用 所以需要拼接
rd_sdram_addr <= {4'b0000,rd_addr[8:0]};
end
RD_DATA:
if(rd_b_end == 1'b1)
rd_cmd <= B_STOP;
else
begin
rd_cmd <= NOP;
rd_ba <= 2'b11;
rd_sdram_addr <= 13'h1fff;
end
RD_PCH:
begin
rd_cmd <= P_CHARGE;
rd_ba <= rd_addr[23:22];
//对所有bank进行预充电 A10置为1
rd_sdram_addr <= 13'h0400;
end
RD_END:
begin
rd_cmd <= NOP;
rd_ba <= 2'b11;
rd_sdram_addr <= 13'h1fff;
end
// 潜伏情况也在默认情况中
default:
begin
rd_cmd <= NOP;
rd_ba <= 2'b11;
rd_sdram_addr <= 13'h1fff;
end
endcase
// 读出数据赋值
assign rd_sdram_data = (rd_ack == 1'b1)?rd_data_reg:16'd0;
endmodule