Altera DDR2 IP核学习总结3-----------DDR2 IP核的使用
根据上一篇生成的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 ...
随机推荐
- 简单了解Oracle的回滚段
因为上一次研究了Oracle的事务一致性,中间查阅资料的时候,看到这个地方与回滚段有关.所以就罗列了以下简单的知识.更为深层次的就不再深挖了,个人感觉对于事务的一致性和隔离级别是开发经理应该了解的,但 ...
- JavaEE体系架构
转载于:https://www.cnblogs.com/reverseAC/p/8512379.html JavaEE知识体系结构图 JavaEE体系结构图: 认识JavaEE完整体系架构(转载):作 ...
- [Linux系统] (3)应用安装方式详解(编译安装、rpm包安装、yum安装)
软件的安装方式: 编译安装 RPM包安装 yum安装 一.编译安装 1.下载一个源码安装包:tengine-2.3.0.tar.gz.这是淘宝二次开发过的nginx.将其解压. .tar.gz 2.查 ...
- Cobbler自动装机
preface 我们之前批量安装操作系统的时候都是采用pxe来安装,pxe也是通过网络安装操作系统的,但是PXE依赖于DHCP,HTTP/TFTP,kicstart等支持.安装流程如下所示: 对于上面 ...
- 【java工具类】上传文件
/**上传文件 * @param file 文件 * @param filePath 上传文件路径,不包含文件名 * @param fileName 新的文件名 * @return 返回一个路径名 * ...
- java支持断点续传文件上传和下载组件
java两台服务器之间,大文件上传(续传),采用了Socket通信机制以及JavaIO流两个技术点,具体思路如下: 实现思路: 1.服:利用ServerSocket搭建服务器,开启相应端口,进行长连接 ...
- 015 pip的使用
目录 一.配置pip环境变量 二.Cmd终端使用pip 三.Pycharm使用pip 四.Jupyter使用pip 如果把python假想成一部手机,那么pip就是这部手机上的应用管家/APP,他可以 ...
- Vue组件使用
一.组件概念 有html模板,有css样式,有js逻辑的集合体 每一个组件都是一个vue实例 每个组件均具有自身的模板template,根组件的模板就是挂载点 每个组件模板只能拥有一个根标签 子组件的 ...
- The 10 Statistical Techniques Data Scientists Need to Master
原文 就我个人所知有太多的软件工程师尝试转行到数据科学家而盲目地使用机器学习框架来处理数据,例如,TensorFlow或者Apache Spark,但是对于这些框架背后的统计理论没有完全的理解.所以提 ...
- 分布式-网络通信-IO-基础(1)
IO整体图架构 一.IO流概述 概述: IO流简单来说就是Input和Output流,IO流主要是用来处理设备之间的数据传输,Java对于数据的操作都是通过流实现,而java用于操作流的对象都在IO ...