本文相对简单,只供自己看看就行。从其它的博客找了个代码,然后记录下仿真波形。
直接使用quartus生成的DDR2 IP核,然后实现循环 -->写入burst长度的数据后读出。
代码数据的传输是32位,实际使用了两片IC。因此IP核也是32位交互。
burst=4,是IC固有的=预取值。而代码中LEN为用户一次想要读取数据的长度的。与local_size和burst_length无关。
分为4个状态: IDLE、WRITER、WRITING、READR、READING。WRITER和READR状态下,开始读写burst的第一个数据,其余的在WRITING和READING状态读写。
local_ready:很重要的一个指示信号。要进行读写操作,必须在IP核(ddr2)准备好的情况下进行。因此,需要一直对此信号进行检测判断。
写入地址(mem_local_addr),一开始为1,当读到的数据长度rdatalen=5时(初始值=1),mem_local_addr <= mem_local_addr + 4;
命令
连续写
连续读
读完写
如下图所示:每次先写入连续4个数据,(例如1,2,3,4),然后再依次读出。
读过程及下一次写
顶层代码:
- module ddr2wrtest (
- input clk , // Clock
- input global_reset_n , // Asynchronous reset active low
-
-
- output [ 12: 0] mem_addr ,
- output [ 2: 0] mem_ba ,
- output mem_cas_n ,
- output mem_cke ,
- inout mem_clk ,
- inout mem_clk_n ,
- output mem_cs_n ,
- output [ 1: 0] mem_dm ,
- inout [ 15: 0] mem_dq ,
- inout [ 1: 0] mem_dqs ,
- output mem_odt ,
- output mem_ras_n ,
- output mem_we_n
-
- );
-
-
- parameter LEN = 8; // 突发长度 4
-
- parameter IDEL = 5'b00001; // 空闲态
- parameter WRITER = 5'b00010; // 准备写
- parameter WRITING = 5'b00100; // 写状态
- parameter READR = 5'b01000; // 准备读
- parameter READING = 5'b10000; // 读状态
- reg [ 5: 0] state;
- //**********************与IP相连部分********************//
- reg [ 24: 0] mem_local_addr =1 ;
- wire mem_local_init_done ;
- wire local_burstbegin_sig ;
- wire [ 31: 0] mem_local_rdata ;
- wire mem_local_rdata_valid ;
- wire mem_local_read_req ;
- wire mem_local_ready ;
- wire [ 3: 0] mem_local_size ;
- reg [ 31: 0] mem_local_wdata ;
- wire mem_local_write_req ;
- wire phy_clk ;
- wire reset_phy_clk_n ;
- //*****************************************************//
- wire rst_n ;
- reg [ 3: 0] rdatalen ; // 读突发长度计数器
- reg [ 3: 0] wdatalen ; // 写突发长度计数器
- reg [100: 0] state_name ; // 状态名
- assign rst_n = reset_phy_clk_n&&mem_local_init_done;
- assign mem_local_size = LEN;
- assign local_burstbegin_sig = ((state == WRITER&&mem_local_ready) || (state == READR&&mem_local_ready))?1:0;
- assign mem_local_write_req = (state == WRITING)?1:0;
- assign mem_local_read_req = (state == READR&&mem_local_ready)?1:0;
-
- ddr2 ddr2_inst
- (
- //==============================《 》===============================
- .aux_full_rate_clk ( ), //全速率时钟
- .aux_half_rate_clk ( ), //半速率时钟
- //==============================《 用户操作信号 》===============================
- .global_reset_n (global_reset_n ), //全局复位
- .local_address (mem_local_addr ), //当前操作地址
- .local_be (8'hff ), //数据掩码
- .local_burstbegin (local_burstbegin_sig ), //突发起始信号
- .local_init_done (mem_local_init_done ), //初始化完成信号
- .local_rdata (mem_local_rdata ), //读数据总线
- .local_rdata_valid (mem_local_rdata_valid ), //读有效标志
- .local_read_req (mem_local_read_req ), //读请求,保持一个时钟周期
- .local_ready (mem_local_ready ), //接受到请求
- .local_refresh_ack ( ), //自动刷新
- .local_size (mem_local_size ), //突发长度
- .local_wdata (mem_local_wdata ), //写数据总线
- .local_write_req (mem_local_write_req ), //写请求
- //==============================《 与DDR2相连的信号 》===============================
- .mem_addr (mem_addr ), //地址总线
- .mem_ba (mem_ba ), //bank地址
- .mem_cas_n (mem_cas_n ), //行选通
- .mem_cke (mem_cke ), //时钟使能
- .mem_clk (mem_clk ), //操作时钟
- .mem_clk_n (mem_clk_n ), //反向时钟
- .mem_cs_n (mem_cs_n ), //片选信号
- .mem_dm (mem_dm ), //DDR2数据屏蔽信号
- .mem_dq (mem_dq ), //数据总线
- .mem_dqs (mem_dqs ), //数据选取脉冲信号
- .mem_odt (mem_odt ), //片内终结信号
- .mem_ras_n (mem_ras_n ), //行选通
- .mem_we_n (mem_we_n ), //使能
- //==============================《 用户操作信号 》===============================
- .phy_clk (phy_clk ), //提供给用户的操作时钟
- .pll_ref_clk (clk ), //给ddr2的输入时钟
- .reset_phy_clk_n (reset_phy_clk_n ), //提供给用户的复位信号
- .reset_request_n ( ), //当PLL锁定后为低电平
- .soft_reset_n (1'b1 ) //软复位,不包括PLL的复位
- );
- always@(*)
- case (state)
- IDEL : state_name = "IDEL";
- WRITER : state_name = "WRITER" ;
- WRITING : state_name = "WRITING" ;
- READR : state_name = "READR" ;
- READING : state_name = "READING";
-
- default : /* default */;
- endcase
- always@(posedge phy_clk or negedge rst_n)begin
- if(!rst_n)
- state <= IDEL;
- else
- case (state)
- IDEL : state <= WRITER;
- WRITER : if(mem_local_ready)
- state <= WRITING;
- else
- state <= WRITER;
- WRITING : if(wdatalen == LEN)
- state <= READR;
- else
- state <= state;
- READR : if(mem_local_ready)
- state <= READING;
- else
- state <= READR;
- READING : if(rdatalen == LEN)
- state <= IDEL;
- else
- state <= state;
- default : state <= state;
- endcase
- end
- // 写的数据自加1
- always@(posedge phy_clk or negedge rst_n)begin
- if(!rst_n)
- mem_local_wdata <= 1;
- else if(state == WRITING && mem_local_ready)
- mem_local_wdata <= mem_local_wdata + 1;
- else
- mem_local_wdata <= mem_local_wdata;
- end
- // 当前写的数据突发长度
- always@(posedge phy_clk or negedge rst_n)begin
- if(!rst_n)
- wdatalen <= 1;
- else if(state == WRITING && mem_local_ready)
- wdatalen <= wdatalen + 1;
- else if(state == WRITING && !mem_local_ready)
- wdatalen <= wdatalen ;
- else
- wdatalen <= 1;
- end
- // 当前读的数据突发长度
- always@(posedge phy_clk or negedge rst_n)begin
- if(!rst_n)
- rdatalen <= 1;
- else if(state == READING && mem_local_rdata_valid)
- rdatalen <= rdatalen + 1;
- else
- rdatalen <= 1;
- end
- // 操作地址自加
- always@(posedge phy_clk or negedge rst_n)begin
- if(!rst_n)
- mem_local_addr <= 1;
- else if(rdatalen == LEN)
- mem_local_addr <= mem_local_addr + LEN;
- end
- endmodule
测试代码
- `timescale 1ns/1ps
- module test_tb ();
-
- reg clk ;
- reg global_reset_n;
-
- wire [ 12: 0] mem_addr ;
- wire [ 2: 0] mem_ba ;
- wire mem_cas_n ;
- wire mem_cke ;
- wire mem_clk ;
- wire mem_clk_n ;
- wire mem_cs_n ;
- wire [ 1: 0] mem_dm ;
- wire [ 15: 0] mem_dq ;
- wire [ 1: 0] mem_dqs ;
- wire mem_odt ;
- wire mem_ras_n ;
- wire mem_we_n ;
-
-
- ddr2wrtest u1 (
- .clk (clk ), // Clock
- .global_reset_n (global_reset_n ) , // Asynchronous reset active low
- .mem_addr (mem_addr ),
- .mem_ba (mem_ba ),
- .mem_cas_n (mem_cas_n ),
- .mem_cke (mem_cke ),
- .mem_clk (mem_clk ),
- .mem_clk_n (mem_clk_n ),
- .mem_cs_n (mem_cs_n ),
- .mem_dm (mem_dm ),
- .mem_dq (mem_dq ),
- .mem_dqs (mem_dqs ),
- .mem_odt (mem_odt ),
- .mem_ras_n (mem_ras_n ),
- .mem_we_n (mem_we_n )
-
- );
-
- ddr2_mem_model mem (
- .mem_dq (mem_dq),
- .mem_dqs (mem_dqs),
- .mem_dqs_n (mem_dqs_n),
- .mem_addr (mem_addr),
- .mem_ba (mem_ba),
- .mem_clk (mem_clk),
- .mem_clk_n (mem_clk_n),
- .mem_cke (mem_cke),
- .mem_cs_n (mem_cs_n),
- .mem_ras_n (mem_ras_n),
- .mem_cas_n (mem_cas_n),
- .mem_we_n (mem_we_n),
- .mem_dm (mem_dm),
- .mem_odt (mem_odt)
- );
- always #10 clk = ~clk;
- initial begin
- clk = 0;
- global_reset_n = 0;
- @(posedge clk);
- @(posedge clk);
- @(posedge clk);
- @(posedge clk);
- @(posedge clk);
- @(posedge clk);
- @(posedge clk);
- @(posedge clk);
- @(posedge clk);
- global_reset_n = 1;
- end
- endmodule