您的位置:首页 > 其它

关于利用verilog 编写ssram的读写时序时遇到的问题

2014-09-16 21:30 281 查看
此次使用的 ssram型号为 CY7C1462AV33



ssram的读和写都在两个时钟周期内完成,即写时钟周期内,第一个clk上升沿时采集 addr ,w_n等有效信号,第三个clk上升沿时将要写的数据采样进去。

ssram主要用在存储ccd的图像,40MHz的速度。

一开始采用的想法是状态机来实现一个读和写的周期,及完成一个读和写需要两个时钟周期。按照这个想法写了一下verilog代码。

后来发现这个速度跟不上,而其对于官方给的ssram的读写时序就是一个流水线的操作。这样可以利用每个时钟周期。给出verilog代码:

module line_ssram(

clk,
addr,
w_data,
r_data,
cs_n,
w_n,
r_n,

ssram_clk,

ssram_data,
ssram_addr,
ssram_be_n,

ssram_ce1_n,
ssram_ce2,
ssram_ce3_n,
ssram_we_n,
ssram_oe_n,
ssram_cen_n,
ssram_adv_ld_n,
ssram_mode,
ssram_zz
);

input 				clk;
input		[20:0] 	addr;
input		[15:0]	w_data;
output   [15:0]   r_data;
input 				cs_n;
input             w_n;
input             r_n;

output 				ssram_clk;

inout		[15:0]	ssram_data;
output	[20:0]	ssram_addr;
output	[1:0]	   ssram_be_n;

output				ssram_ce1_n;
output				ssram_ce2;
output				ssram_ce3_n;
output				ssram_we_n;
output				ssram_oe_n;
output				ssram_cen_n;
output				ssram_adv_ld_n;
output				ssram_mode;
output				ssram_zz;

reg 			      ce3_n_temp;
reg					we_n_temp;
reg					oe_n_temp;
reg     [1:0]     be_n_temp;

reg read_bus_d1;
reg read_bus_d2;
reg read_bus;
reg write_bus_d1;
reg write_bus_d2;
reg write_bus;
reg [15:0] write_data_d1;
reg [15:0] write_data_d2;
reg [15:0] write_data;

assign 	ssram_cen_n     = 1'b0;
assign 	ssram_adv_ld_n  = 1'b0;
assign 	ssram_mode      = 1'b0;
assign 	ssram_ce1_n     = 1'b0;
assign	ssram_ce2       = 1'b1;
assign 	ssram_zz        = 1'b0;

assign   ssram_clk       = clk;

assign   ssram_addr      =(!cs_n)         ?  addr          : 21'bz;
assign   ssram_data      =(write_bus_d2)  ?  write_data_d2 : 16'bz;
assign   r_data          =(read_bus_d2)	?  ssram_data    : 16'bz;

assign ssram_ce3_n = ce3_n_temp;
assign ssram_we_n  = we_n_temp;
assign ssram_oe_n  = oe_n_temp;
assign ssram_be_n  = be_n_temp;

always@(negedge clk)
begin
if(cs_n)
begin
ce3_n_temp <= 1'b1;
we_n_temp  <= 1'bz;
oe_n_temp  <= 1'bz;
be_n_temp  <= 2'b11;

read_bus<=1'b0;
write_bus<=1'b0;
end
else if((w_n)&&(!r_n)) //read
begin
ce3_n_temp <= 1'b0;
we_n_temp  <= 1'b1;
oe_n_temp  <= 1'b0;
read_bus   <= 1'b1;
write_bus  <= 1'b0;
end
else if((!w_n)&&(r_n))  //write
begin
ce3_n_temp <= 1'b0;
we_n_temp  <= 1'b0;
oe_n_temp  <= 1'b1;
be_n_temp  <= 2'd0;
write_bus  <= 1'b1;
read_bus   <= 1'b0;
write_data <= w_data;
end
end

always@(negedge clk)
begin
if(cs_n)
begin
read_bus_d1<=1'b0;
read_bus_d2<=1'b0;
end
else
begin
read_bus_d1<=read_bus;
read_bus_d2<=read_bus_d1;
end
end

always@(negedge clk)
begin
if(cs_n)
begin
write_bus_d1<=1'b0;
write_bus_d2<=1'b0;
end
else
begin
write_bus_d1<=write_bus;
write_bus_d2<=write_bus_d1;
end
end

always@(negedge clk)
begin
write_data_d1<=write_data;
write_data_d2<=write_data_d1;
end

endmodule


这里将数据延迟两个时钟周期来完成对ssram对读写时序的要求,这里为了提高效率,我采用了时钟下降沿完成外部数据以及控制信号的采样,上升沿为ssram的数据采样。

下图为modelsim的功能仿真:



为检测实际的读写功能我写了一个测试模块:

module rw_test(
rest_n,
clkin,
clk,
addr,
cs_n,
w_n,
r_n,
w_data,
r_data,
seg,
cnt_out
);
input 	clkin;
input 	rest_n;
output  [20:0] addr;
output  [15:0] w_data;
input   [15:0] r_data;
output  [13:0] seg;
output  cs_n;
output  w_n;
output  r_n;
output  clk;
output  [7:0] cnt_out;

reg [20:0] addr_temp;

reg [13:0] seg_temp;
reg cs_n_temp;
reg w_n_temp;
reg r_n_temp;
reg [15:0] w_data_temp;

reg [20:0] cnt;
initial cnt = 0;

reg r_data_en;
initial r_data_en=0;

assign addr = addr_temp;
assign w_data = w_data_temp;

assign cs_n = cs_n_temp;
assign w_n  = w_n_temp;
assign r_n  = r_n_temp;
assign clk  = clkin;

assign cnt_out =cnt;

always@(posedge clkin)
begin
if(cnt == 21'd40)
cnt <= 21'd0;
else
cnt <= cnt + 1'b1;
end

always@(posedge clkin)
begin
if(cnt==21'd20)  //read
begin
cs_n_temp <= 1'b0;
w_n_temp  <= 1'b1;
r_n_temp  <= 1'b0;
addr_temp <= 21'd1;
end
else if(cnt == 21'd 30)
begin
cs_n_temp <= 1'b1;
w_n_temp  <= 1'b1;
r_n_temp  <= 1'b1;

end

else if(cnt==21'd1)  //w
begin
cs_n_temp <= 1'b0;
w_n_temp  <= 1'b0;
r_n_temp  <= 1'b1;
addr_temp <= 21'd1;
w_data_temp <= 16'd1;
end
else if(cnt==21'd3)  //w
begin
cs_n_temp <= 1'b0;
w_n_temp  <= 1'b0;
r_n_temp  <= 1'b1;
addr_temp <= 21'd2;
w_data_temp <= 16'd2;
end
else if(cnt == 21'd8)
begin
cs_n_temp <= 1'b1;
w_n_temp  <= 1'b1;
r_n_temp  <= 1'b1;

end
end

always@(clkin)
begin
if(r_data == 16'd2)
r_data_en <= 1'b1;
else
r_data_en <= 1'b0;
end

assign seg =(r_data_en==1'b1) ? 14'd2 :14'd1;
//assign seg = 14'd6;
endmodule


采用一个循环计数,完成两次写,一次读。

下图为用signaltap的逻辑分析的实测结果。为了有对比性,第一张图将ssram的clk断了,第二张图为正常。可以观察在ssram_we_n分别为高电平和低电平时ssram_data的读数情况。

1.



2.

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: