基于FPGA的通用读写软IP

来源:互联网 发布:vb中picturebox的属性 编辑:程序博客网 时间:2024/06/05 06:37
此IP简单易用,亲自测试可以跑到145M,读写控制信号只有wr和rd两个,其余(地址、数据、突发等)均根据个人需要配置,wr和rd一样时不操作,wr为1,rd为0时为写操作,反之为读操作,需要强调突发写时需要等待writeable为1后在时钟上升沿依此放置数据,读取时在readable为1时方可在上升沿读取数据。本人使用的sdram为HY57V641620E(L/S)T(P)-6
如有bug请一定告知,谢谢


RTL代码如下:



module  sdram_common(clk,rst,cke,cs,ba,a,ras,cas,we,udqm,ldqm,dq,wr,rd,burst_length,addr_row,addr_column,data_in,over,bank,readable,writeable);input clk;//sdram输入input rst;//sdram复位input wr;//sdram写使能inputrd;//sdram读使能,wr和rd一样时为无操作,当wr为1rd为0时为写反之为读input  [11:0]addr_row;//sdram行地址input  [7:0]addr_column;//sdram列地址input  [15:0]   data_in;//数据输入input  [2:0]    burst_length;//当为000时无突发,为001时突发为2,为010时突发为4,为011时突发为8,为100时为页突发(256)input  [1:0]    bank;//选择四片中哪一片inout  [15:0]   dq;//链接sdram的数据端口output cke;//连接sdram的时钟使能端口output cs;//连接sdram的片选端口output [1:0] ba;//连接sdram的bank端口output [11:0] a;//连接sdram的地址端口output ras;//连接sdram的行地址选择端口output cas;//连接sdram的列地址选择端口output we;//连接sdram的写使能端口output udqm;//output   ldqm;//数据掩码端口outputover;//操作结束指示信号,上升沿或高电平有效outputreadable;//可读信号,高电平有效,高电平时在时钟上升沿获取读到的数据outputwriteable;//突发写时在这个信号高电平时上升沿开始放着数据,单写时无需此信号reg [15:0]dq_r;reg [1:0]ba_r;reg cke_r;reg cs_r;reg [11:0]a_r;reg ras_r;regcas_r;reg we_r;reg [15:0]data_out_r;regover_r;regwriteable_r;//10160904assign dq = wr?dq_r:16'bzzzzzzzzzzzzzzzz;assign ba = ba_r;assign cke = cke_r;assign cs = cs_r;assign a = a_r;assign ras = ras_r;assign cas = cas_r;assign we = we_r;assign over = over_r;assign udqm = 0;assign ldqm = 0;assign readable = readable_r;assign writeable = writeable_r;//10160904reg [7:0] current_state;reg [7:0]next_state;reg [8:0] burst_length_num;wire [8:0]burst_length_num_r;parameter init = 8'b00000000;//初始化状态parameter precharge = 8'b00000010;//预充电状态parameter auto_reflash = 8'b00000100;//自动刷新状态parameter mr_confige = 8'b00001000;//配置模式寄存器parameter idel = 8'b00010000;//空闲状态parameter start_active_row= 8'b00100000;//行激活状态parameter read = 8'b01000000;//读状态parameter write = 8'b10000000;//写状态parameter done= 8'b00000001;//完成状态assign burst_length_num_r = wr?burst_length_num:(burst_length_num + 3);wire en;assign en = wr ^ rd;always@(posedge clk or negedge rst)beginif(~rst)current_state <= idel;elsecurrent_state <= next_state;endalways@(negedge clk)begincase(current_state)init:begincke_r <= 1;cs_r  <= 0;ras_r <= 1;cas_r <= 1;we_r  <= 1;over_r <= 0;writeable_r <= 0;if(init_ok)next_state <= precharge;elsenext_state <= init;endprecharge:begincke_r <= 1;cs_r  <= 0;ras_r <= 0;cas_r <= 1;we_r  <= 0;a_r[10]   <= 1;writeable_r <= 0;if(precharge_done)next_state <= auto_reflash;elsenext_state <= precharge;endauto_reflash:begincke_r <= 1;cs_r  <= 0;ras_r <= 0;cas_r <= 0;we_r  <= 1;over_r <= 0;writeable_r <= 0;if(en)next_state <= mr_confige;else next_state <= idel;endmr_confige:begincke_r <= 1;cs_r  <= 0;ras_r <= 0;cas_r <= 0;we_r  <= 0;ba_r  <= 2'b00;over_r <= 0;writeable_r <= 0;case(burst_length)//根据突发长度配着模式寄存器0:begin a_r <= 12'b000000110000; burst_length_num <= 0; end1:begin a_r <= 12'b000000110001; burst_length_num <= 1; end2:begin a_r <= 12'b000000110010; burst_length_num <= 3; end3:begin a_r <= 12'b000000110011; burst_length_num <= 7; end4:begin a_r <= 12'b000000110111; burst_length_num <= 255; enddefault:begin a_r <= 12'b000000110000; burst_length_num <= 0; endendcaseif(en & mr_confige_done)next_state <= start_active_row;else if(mr_confige_done)next_state <= idel;elsenext_state <= mr_confige;endidel:begincke_r <= 1;cs_r  <= 0;ras_r <= 1;cas_r <= 1;we_r  <= 1;over_r <= 0;writeable_r <= 0;if(en)next_state <= mr_confige;elsenext_state <= auto_reflash;endstart_active_row:begincke_r <= 1;cs_r  <= 0;ras_r <= 0;cas_r <= 1;we_r  <= 1;ba_r  <= bank;a_r   <= addr_row;over_r <= 0;writeable_r <= 0;if(addr_row_done)beginif(en)beginif(wr)beginwriteable_r <= 1;next_state <= write;endelsebeginwriteable_r <= 0;next_state <= read;endendelsebeginwriteable_r <= 0;next_state <= idel;endendelsebeginwriteable_r <= 0;next_state <= start_active_row;endendread:begincke_r <= 1;cs_r  <= 0;ras_r <= 1;cas_r <= 0;we_r  <= 1;ba_r  <= bank;a_r   <= {4'd0,addr_column};writeable_r <= 0;next_state <= done;endwrite:begincke_r <= 1;cs_r  <= 0;ras_r <= 1;cas_r <= 0;we_r  <= 0;ba_r  <= bank;a_r   <= {4'd0,addr_column};dq_r <= data_in;if(burst_length_num_r == 1'd0)beginover_r <= 1;writeable_r <= 0;next_state <= precharge;endelsenext_state <= done;enddone://完成状态,因为有突发的读和写状态,突发时要把cas和ras拉低begincke_r <= 1;cs_r  <= 0;ras_r <= 0;cas_r <= 0;if(wr)beginwe_r  <= 0;dq_r <= data_in;endelsebegindata_out_r <= dq;we_r  <= 1;endif(burst_length_done || burst_length_num_r == 1'd0)//检测突发是否完成beginover_r <= 1;writeable_r <= 0;next_state <= precharge;endelsebeginover_r <= 0;writeable_r <= writeable_r;next_state <= done;endenddefault:next_state <= idel;endcaseend      //////////////////////////初始化计数器/////////////////////////////    reg [13:0] init_counter;reg init_ok;always@(posedge clk)beginif(init_counter < 15000)begininit_counter <= init_counter + 1;init_ok <= 0;endelsebegininit_counter <= 15000;init_ok <= 1;endend////////////////////////////预充电计数器////////////////////////////reg [2:0]precharge_counter;reg precharge_done;always@(posedge clk or negedge rst)beginif(~rst)beginprecharge_counter <= 0;precharge_done <= 0;endelse if(current_state == precharge)beginprecharge_counter <= precharge_counter +1;if(precharge_counter == 7)precharge_done <= 1;elseprecharge_done <= 0;endelsebeginprecharge_counter <= 0;precharge_done <= 0;endend///////////////////////////配着模式寄存器计数器////////////////////reg [1:0] mr_confige_counter;reg mr_confige_done;always@(posedge clk or negedge rst)beginif(~rst)beginmr_confige_counter <= 0;mr_confige_done <= 0;endelse if(current_state == mr_confige)beginmr_confige_counter <= mr_confige_counter + 1;if(mr_confige_counter == 3)mr_confige_done <= 1;elsemr_confige_done <= 0;endelse beginmr_confige_counter <=0;mr_confige_done <=0;endend/////////////////////////////行激活计数器//////////////////////////////reg [1:0] addr_row_counter;reg addr_row_done;always@(posedge clk or negedge rst)beginif(~rst)beginaddr_row_counter <= 0;addr_row_done <=0;endelse if(current_state == start_active_row)beginaddr_row_counter <= addr_row_counter + 1;if(addr_row_counter == 3)addr_row_done <= 1;elseaddr_row_done <= 0;endelsebeginaddr_row_counter <= 0;addr_row_done <= 0;endend////////////////////////////突发寄存器///////////////////////////////reg [8:0] burst_length_counter;reg burst_length_done;regreadable_r;always@(posedge clk or negedge rst)beginif(~rst)beginburst_length_counter <= 0;burst_length_done <= 0;readable_r <= 0;endelse if(current_state == read || current_state == write || current_state == done)beginburst_length_counter <= burst_length_counter + 1;if(burst_length_counter > 1 && burst_length_counter < burst_length_num_r && rd)readable_r <= 1;elsereadable_r <= 0;if(burst_length_counter == burst_length_num_r - 1 || burst_length_num_r == 1'd0)//20160904burst_length_done <= 1;elseburst_length_done <= 0;endelsebeginburst_length_counter <= 0;burst_length_done <= 0;readable_r <= 0;endendendmodule