根据上一篇生成的IP核,例化之后如上图,Local开头的数据是用户侧数据,其他数据暂时不用纠结,不用管。
这些是需要关注的信号,但是初学阶段很难对这些信号形成具体的概念,这里参考明德扬的代码进行二次封装。
- module ddr2_intf(
- clk_in ,
- clk_out ,
- rst_n ,
- local_address ,
- local_write_req ,
- local_read_req ,
- local_wdata ,
- local_ready ,
- local_rdata ,
- local_rdata_valid,
- local_init_done ,
- local_burstbegin ,
- user_wdata ,
- user_wdata_en ,
- user_waddr ,
- user_raddr ,
- user_rdata_en ,
- user_rdata ,
- user_rdata_vld ,
- user_wdata_rdy ,
- user_rdata_rdy
- );
- parameter ADDR_W = 23 ;
- parameter DDR_DATA_W = 32 ;
- parameter BURST = 2 ;
- parameter USE_DATA_W = DDR_DATA_W * BURST;
- parameter FIFO_W = USE_DATA_W + ADDR_W;
- input clk_in ;
- input rst_n ;
- input clk_out ;
- input local_ready ;
- input [DDR_DATA_W-1:0] local_rdata ;
- input local_rdata_valid;
- input local_init_done ;
- input [USE_DATA_W-1:0] user_wdata ;
- input user_wdata_en ;
- input [ADDR_W-1:0] user_waddr ;
- input [ADDR_W-1:0] user_raddr ;
- input user_rdata_en ;
- output [ADDR_W-1:0] local_address ;
- output local_write_req ;
- output local_read_req ;
- output [DDR_DATA_W-1:0] local_wdata ;
- output local_burstbegin ;
- output [USE_DATA_W-1:0] user_rdata ;
- output user_rdata_vld ;
- output user_wdata_rdy ;
- output user_rdata_rdy ;
- reg [USE_DATA_W-1:0] user_rdata ;
- reg user_rdata_vld ;
- reg user_wdata_rdy ;
- reg user_rdata_rdy ;
- wire [ADDR_W-1:0] local_address ;
- wire local_write_req ;
- wire local_read_req ;
- wire [DDR_DATA_W-1:0] local_wdata ;
- wire local_burstbegin ;
- wire [FIFO_W-1:0] wfifo_wdata ;
- wire wfifo_wrreq ;
- wire wfifo_empty ;
- wire wfifo_rdreq ;
- wire [FIFO_W-1:0] wfifo_q ;
- wire [ 5:0] wfifo_usedw ;
- wire [ADDR_W-1:0] rfifo_wdata ;
- wire rfifo_wrreq ;
- wire rfifo_empty ;
- wire rfifo_rdreq ;
- wire [ADDR_W-1:0] rfifo_q ;
- wire [ 5:0] rfifo_usedw ;
- reg [FIFO_W :0] ififo_wdata ;
- reg ififo_wrreq ;
- wire ififo_empty ;
- wire ififo_rdreq ;
- wire [FIFO_W :0] ififo_q ;
- wire [ 5:0] ififo_usedw ;
- wire ififo_rdy ;
- reg [USE_DATA_W-1:0] gfifo_wdata ;
- reg gfifo_wrreq ;
- wire gfifo_empty ;
- wire gfifo_rdreq ;
- wire [USE_DATA_W-1:0] gfifo_q ;
- wire [ 5:0] gfifo_usedw ;
- reg [ 1:0] cnt0 ;
- wire add_cnt0 ;
- wire end_cnt0 ;
- reg [ 2:0] x ;
- reg [ 3:0] cnt1 ;
- wire add_cnt1 ;
- wire end_cnt1 ;
- fifo_ahead_sys #(.DATA_W(FIFO_W),.DEPT_W(64)) u_wfifo(
- .aclr (~rst_n ),
- .clock (clk_in ),
- .data (wfifo_wdata ),
- .rdreq (wfifo_rdreq ),
- .wrreq (wfifo_wrreq ),
- .empty (wfifo_empty ),
- .q (wfifo_q ),
- .usedw (wfifo_usedw )
- );
- fifo_ahead_sys #(.DATA_W(ADDR_W),.DEPT_W(64)) u_rfifo(
- .aclr (~rst_n ),
- .clock (clk_in ),
- .data (rfifo_wdata ),
- .rdreq (rfifo_rdreq ),
- .wrreq (rfifo_wrreq ),
- .empty (rfifo_empty ),
- .q (rfifo_q ),
- .usedw (rfifo_usedw )
- );
- fifo_ahead_asy #(.DATA_W(FIFO_W+1),.DEPT_W(64)) u_ififo(
- .aclr (~rst_n ),
- .data (ififo_wdata ),
- .rdclk (clk_out ),
- .rdreq (ififo_rdreq ),
- .wrclk (clk_in ),
- .wrreq (ififo_wrreq ),
- .q (ififo_q ),
- .rdempty (ififo_empty ),
- .wrusedw (ififo_usedw )
- );
- assign wfifo_wdata = {user_waddr,user_wdata};
- assign wfifo_wrreq = user_wdata_en ;
- assign wfifo_rdreq = ififo_rdy && wfifo_empty==0 && rfifo_empty==1;
- assign rfifo_wdata = user_raddr ;
- assign rfifo_wrreq = user_rdata_en ;
- assign rfifo_rdreq = ififo_rdy && rfifo_empty==0;
- always @(posedge clk_in or negedge rst_n)begin
- if(rst_n==1'b0)begin
- ififo_wdata <= 0;
- end
- else if(wfifo_rdreq) begin
- ififo_wdata <= {1'b1,wfifo_q};
- end
- else if(rfifo_rdreq)begin
- ififo_wdata <= {1'b0,rfifo_q,{USE_DATA_W{1'b0}}};
- end
- end
- always @(posedge clk_in or negedge rst_n)begin
- if(rst_n==1'b0)begin
- ififo_wrreq <= 0;
- end
- else begin
- ififo_wrreq <= wfifo_rdreq || rfifo_rdreq;
- end
- end
- assign ififo_rdy = ififo_usedw<40;
- always @(posedge clk_in or negedge rst_n)begin
- if(rst_n==1'b0)begin
- user_wdata_rdy <= 0;
- end
- else begin
- user_wdata_rdy <= wfifo_usedw<40;
- end
- end
- always @(posedge clk_in or negedge rst_n)begin
- if(rst_n==1'b0)begin
- user_rdata_rdy <= 0;
- end
- else begin
- user_rdata_rdy <= rfifo_usedw<40;
- end
- end
- wire local_read_req_tmp;
- assign local_wdata = ififo_q[USE_DATA_W-DDR_DATA_W*cnt0-1 -:DDR_DATA_W];
- assign local_address = ififo_q[FIFO_W-1 -:ADDR_W];
- assign local_write_req = ififo_q[FIFO_W] && ififo_empty==0 && local_init_done;
- assign local_read_req_tmp = ififo_q[FIFO_W]==0 && ififo_empty==0 && local_init_done;
- assign local_read_req = local_read_req_tmp && cnt0==1-1;
- assign local_burstbegin= add_cnt0 && cnt0==1-1;
- assign ififo_rdreq = end_cnt0;
- reg ififo_q_ff0;
- always @(posedge clk_out or negedge rst_n)begin
- if(rst_n==1'b0)begin
- ififo_q_ff0<=0;
- end
- else begin
- ififo_q_ff0<=ififo_q[FIFO_W];
- end
- end
- always @(posedge clk_out or negedge rst_n)begin
- if(!rst_n)begin
- cnt0 <= 0;
- end
- else if(add_cnt0)begin
- if(end_cnt0)
- cnt0 <= 0;
- else
- cnt0 <= cnt0 + 1;
- end
- end
- assign add_cnt0 = (local_write_req||local_read_req_tmp)&&local_ready;
- assign end_cnt0 = add_cnt0 && cnt0==2-1;
- always @(posedge clk_out or negedge rst_n)begin
- if(!rst_n)begin
- cnt1 <= 0;
- end
- else if(add_cnt1)begin
- if(end_cnt1)
- cnt1 <= 0;
- else
- cnt1 <= cnt1 + 1;
- end
- end
- assign add_cnt1 = local_rdata_valid;
- assign end_cnt1 = add_cnt1 && cnt1==BURST-1 ;
- always @(posedge clk_out or negedge rst_n)begin
- if(rst_n==1'b0)begin
- gfifo_wrreq <= 0;
- end
- else begin
- gfifo_wrreq <= end_cnt1;
- end
- end
- always @(posedge clk_out or negedge rst_n)begin
- if(rst_n==1'b0)begin
- gfifo_wdata <= 0;
- end
- else if(add_cnt1)begin
- gfifo_wdata[USE_DATA_W - DDR_DATA_W*cnt1 -1 -:DDR_DATA_W] <= local_rdata;
- end
- end
- fifo_ahead_asy #(.DATA_W(USE_DATA_W),.DEPT_W(64)) u_gfifo(
- .aclr (~rst_n ),
- .data (gfifo_wdata ),
- .rdclk (clk_in ),
- .rdreq (gfifo_rdreq ),
- .wrclk (clk_out ),
- .wrreq (gfifo_wrreq ),
- .q (gfifo_q ),
- .rdempty (gfifo_empty ),
- .wrusedw (gfifo_usedw )
- );
- assign gfifo_rdreq = gfifo_empty==0;
- always @(posedge clk_in or negedge rst_n)begin
- if(rst_n==1'b0)begin
- user_rdata <= 0;
- end
- else begin
- user_rdata <= gfifo_q;
- end
- end
- always @(posedge clk_in or negedge rst_n)begin
- if(rst_n==1'b0)begin
- user_rdata_vld <= 0;
- end
- else begin
- user_rdata_vld <= gfifo_rdreq;
- end
- end
- endmodule
- ddr2_intf u8(
- .clk_in ( clk ),
- .clk_out ( phy_clk ),
- .rst_n ( rst_n_ff1 ),
- .local_address ( local_address ),
- .local_write_req ( local_write_req ),
- .local_read_req ( local_read_req ),
- .local_wdata ( local_wdata ),
- .local_ready ( local_ready ),
- .local_rdata ( local_rdata ),
- .local_rdata_valid( local_rdata_valid ),
- .local_init_done ( local_init_done ),
- .local_burstbegin ( local_burstbegin ),
- .user_wdata ( user_wdata ),
- .user_wdata_en ( user_wdata_en ),
- .user_waddr ( user_waddr ),
- .user_raddr ( user_raddr ),
- .user_rdata_en ( user_rdata_en ),
- .user_rdata ( user_rdata ),
- .user_rdata_vld ( user_rdata_vld ),
- .user_wdata_rdy ( user_wdata_rdy ),
- .user_rdata_rdy ( user_rdata_rdy )
- );
封装之后只需要关注
- .user_wdata ( user_wdata ),
- .user_wdata_en ( user_wdata_en ),
- .user_waddr ( user_waddr ),
- .user_raddr ( user_raddr ),
- .user_rdata_en ( user_rdata_en ),
- .user_rdata ( user_rdata ),
- .user_rdata_vld ( user_rdata_vld ),
- .user_wdata_rdy ( user_wdata_rdy ),
- .user_rdata_rdy ( user_rdata_rdy )
上面这9个信号,当user_wdata_rdy为高电平的时候可以写入数据,user_rdata_rdy ( user_rdata_rdy ) 可以读出数据,
写了一个简单的测试程序
- always @(posedge clk or negedge rst_n)begin
- if(!rst_n)begin
- cnt0 <= 0;
- end
- else if(add_cnt0)begin
- if(end_cnt0)
- cnt0 <= 0;
- else
- cnt0 <= cnt0 + 1;
- end
- end
- assign add_cnt0 = user_wdata_en ;
- assign end_cnt0 = add_cnt0 && cnt0==100 ;
- assign user_wdata_en = user_wdata_rdy && flag_add==0;
- always @(posedge clk or negedge rst_n)begin
- if(!rst_n)begin
- cnt1 <= 0;
- end
- else if(add_cnt1)begin
- if(end_cnt1)
- cnt1 <= 0;
- else
- cnt1 <= cnt1 + 1;
- end
- end
- assign add_cnt1 = user_rdata_en ;
- assign end_cnt1 = add_cnt1 && cnt1==100 ;
- assign user_rdata_en = user_rdata_rdy && flag_add==1;
- always @(posedge clk)begin
- if(!rst_n)
- flag_add <= 0;
- else if(end_cnt0)
- flag_add <= 1;
- else if(end_cnt1)
- flag_add <= 0;
- end
- always @(posedge clk or negedge rst_n)begin
- if(rst_n==1'b0)begin
- user_wdata <= 0;
- user_waddr <= 0;
- user_raddr <= 0;
- end
- else begin
- user_wdata <= cnt0 ;
- user_waddr <= cnt0*2 ;
- user_raddr <= cnt1*2 ;
- end
- end
当flag_add为低电平的时候往DDR2中写入数据,flag_add为高电平的时候读出数据。一共写入一百个数据。
使用signaltapII抓到的波形为
local_init_done为高电平说明DDR2芯片初始化完成,user_wdata_en为高电平时写入数据,放大了看则是
写入的数据为地址的二分之一
然后看一下读出来的数据
这里很清楚的可以看出来user_rdata_en跟user_rdata_vld并不能对齐
放大了看
当user_rdata_vld为高电平的时候输出的数据有效,
测量一下得知user_rdata_en跟user_rdata_vld的偏差是21个数据,从Altera DDR2 IP核学习总结1中得知DRAM数据输出有延迟,结构相同的DDR2自然有相同的特性,大神称为首字惩罚特性(当时纠结这个问题半天,怎么也解决不了,多谢群里的大神)。
观察写入数据和读取数据一致,DDR2驱动成功。
Altera DDR2 IP核学习总结3-----------DDR2 IP核的使用的更多相关文章
-
关于AXI4-Stream to Video Out 和 Video Timing Controller IP核学习
关于AXI4-Stream to Video Out 和 Video Timing Controller IP核学习 1.AXI4‐Stream to Video Out Top‐Level Sign ...
-
xilinx AXI相关IP核学习
xilinx AXI相关IP核学习 1.阅读PG044 (1)AXI4‐Stream to Video Out Top‐Level Signaling Interface (2)AXI4‐Stream ...
-
TCP/IP协议学习(五) 基于C# Socket的C/S模型
TCP/IP协议作为现代网络通讯的基石,内容包罗万象,直接去理解理论是比较困难的:然而通过实践先理解网络通讯的理解,在反过来理解学习TCP/IP协议栈就相对简单很多.C#通过提供的Socket API ...
-
linux 学习 设置固定网Ip
本人使用CentOs6.5 最近在学习linux操作系统,单在使用shell连接前都要使用ifconfig eth0 设置一个临时IP让我不胜其烦.决定学习设置一个固定IP 步骤: 1.登录计算机后使 ...
-
Lattice 的 Framebuffer IP核使用调试笔记之IP核生成与参数设置
本文由远航路上ing 原创,转载请标明出处. 这节笔记记录IP核的生成以及参数设置. 先再IP库里下载安装Framebuffer 的ipcore 并安装完毕. 一.IP核的生成: 1.先点击IP核则右 ...
-
TCP/IP协议学习笔记
计算机网络基础知识复习汇总:计算机网络基础知识复习 HTTP协议的解析:剖析 HTTP 协议 一个系列的解析文章: TCP/IP详解学习笔记(1)-- 概述 TCP/IP详解学习笔记(2)-- 数据链 ...
-
TCP/IP协议学习之实例ping命令学习笔记
TCP/IP协议学习之实例ping命令学习笔记(一) 一. 目的为了让网络协议学习更有效果,在真实网络上进行ping命令前相关知识的学习,暂时不管DNS,在内网中,进行2台主机间的ping命令的整个详 ...
-
IP地址和子网划分学习笔记之《IP地址详解》
2018-05-03 18:47:37 在学习IP地址和子网划分前,必须对进制计数有一定了解,尤其是二进制和十进制之间的相互转换,对于我们掌握IP地址和子网的划分非常有帮助,可参看如下目录详文. ...
-
【计算机网络】网络层学习笔记:总结IP,NAT和DHCP
前言:这篇文章是学习网络层协议时候总结的笔记,前面的主要部分介绍的都是IP协议, 后半部分介绍NAT协议和DHCP协议 参考书籍 <计算机网络-自顶向下> 作者 James F ...
随机推荐
-
centos6.5升级python为2.7
今天线上服务器全部升级python环境为python-2.7.6的环境,我采用的方法是ansible+shell,代码如下,友提,Python-2.7.6.tgz.setuptools-14.3.1. ...
-
Android 手机卫士16--手机杀毒
1.指定动画一直旋转 rotateAnimation.setRepeatCount(RotateAnimation.INFINITE); android:repeatCount 重复的次数,默认为0, ...
-
windows系统下Tomcat与Apache服务器集成
说明:此文是看书真实试验成功的,书中提到了不同版本不兼容的问题,但是很荣幸我没碰到,此例可供参考. 本文假设你已经有了java环境和tomcat,你已经熟悉tomcat的应用. Jdk 1.7.0_5 ...
-
关于Aazure 使用以前保留的vhd创建虚拟机的基本步骤
1. 删除vm保留vhd(只删除虚拟机记录,不删除磁盘)2. 拷贝vhd以及status文件到指定的存储账号3. 使用拷贝的VHD创建disk4. 从disk创建vm,指定指定vnet以及cloud ...
-
Java中的那些名词术语(不断更新中)
在工作和学习中,总会遇到各种术语.岁月不饶人,记忆力越来越下降.在这里记录下那些曾经关注过学习过的东西. POJO: Plain Old Java Object DI: Dependency Inje ...
-
AppCan 双击返回按钮退出应用
使用AppCan开发手机应用,拦截返回键实现自定义2秒内双击退出应用的操作 var c1c = 0; window.uexOnload = function(type){ uexWindow.setR ...
-
H5 canvas圆形的时钟
今天用H5中的canvas标签做一个时钟,H5中有很多好用的新增标签,真的很不错. 1.canvas标签介绍 <canvas> 标签定义图形,比如图表和其他图像,你必须使用脚本来绘制图形. ...
-
453. Minimum Moves to Equal Array Elements
Given anon-emptyinteger array of sizen, find the minimum number of moves required to make all array ...
-
【Scala篇】--Scala中Trait、模式匹配、样例类、Actor模型
一.前述 Scala Trait(特征) 相当于 Java 的接口,实际上它比接口还功能强大. 模式匹配机制相当于java中的switch-case. 使用了case关键字的类定义就是样例类(case ...
-
golang:吐槽multipart的设计
最近在做邮件解析的工作,因此接触到multipart库,用了之后才发现golang的multipart有一点设计很诡异. 红线标出来的话意思是:当Content-Transfer-Encoding的值 ...