SerDes介绍以及原语使用介绍(4)ISERDESE2原语仿真

文章目录

  • 前言
  • 一、iserdese2_module模块
  • 二、oserdese2_module模块
  • 三、顶层模块
  • 四、仿真结果分析

前言

上文详细介绍了ISERDESE2原语的使用,本文根据仿真对ISERDESE2原语的使用进一步加深印象。在仿真时,与OSERDESE进行回环。

一、iserdese2_module模块

模块设计思路如下:

  1. 发送端在上电后会一直发送64个连续读8’bBC和8’b50,接受端需要一直检测接收到的并行数据是否为这俩个数据
  2. 发现数据错误则需要滑动串并转换窗口,在滑动窗口后,至少需要3个CLKDIV周期才可以检测到滑动后的数据,这里统一等待4个时钟周期进行检测,如果正确则关闭滑动窗口锁r_slip_lock,在下一个周期进行滑动,即拉高r_bitslip
  3. 如若接收到的数据正确,则不需要滑动,但是为了排除误判的可能,需要继续观察一段时间,当连续接收到正确的P_MAX_RIGHT_NUM个数据后,拉高信号r_byte_align信号表示对齐,此时即可一直打开滑动窗口锁r_slip_lock,不在进行窗口滑动。

代码如下:

module iserdese2_module(
	input          	i_clk       	,
	input          	i_div_clk   	,
	input          	i_rst       	,
	input          	i_OFB     		,
	output [7 :0]	o_par_data		,
	output  		o_data_valid 	
);

localparam P_MAX_RIGHT_NUM = 10;

reg   		r_bitslip		;
reg  [2 :0]	r_gap_cnt		;
reg   		r_byte_align	;
reg   		r_slip_lock		;
reg  [5 :0]	r_right_cnt 	;

wire [7 :0] w_par_data		;

assign o_par_data = w_par_data	;
assign o_data_valid = r_byte_align	;


always @(posedge i_div_clk or posedge i_rst) begin
	if(i_rst)
		r_gap_cnt <= 'd0;
	else if(r_byte_align || r_bitslip)
		r_gap_cnt <= 'd0;
	else if(r_slip_lock)
		r_gap_cnt <= r_gap_cnt + 'd1;
	else
		r_gap_cnt <= 'd0;
end


always @(posedge i_div_clk or posedge i_rst) begin
	if(i_rst)
		r_slip_lock <= 'd1;
	else if(r_byte_align || (r_gap_cnt == 5 && !r_slip_lock))
		r_slip_lock <= 'd1;
	else if(w_par_data != 8'hBC && w_par_data != 8'h50 && (r_gap_cnt == 4))
		r_slip_lock <= 'd0;
	else
		r_slip_lock <= 'd1;
end

always @(posedge i_div_clk or posedge i_rst) begin
	if(i_rst)
		r_bitslip <= 'd0;
	else if((r_gap_cnt == 5) && !r_slip_lock)
		r_bitslip <= 'd1;
	else
		r_bitslip <= 'd0;
end

always @(posedge i_div_clk or posedge i_rst) begin
	if(i_rst)
		r_right_cnt <= 'd0;
	else if(r_bitslip)
		r_right_cnt <= 'd0;
	else if(r_right_cnt == P_MAX_RIGHT_NUM)
		r_right_cnt <= r_right_cnt;
	else if(r_slip_lock && (w_par_data == 8'hBC || w_par_data == 8'h50))
		r_right_cnt <= r_right_cnt + 1;
	else
		r_right_cnt <= r_right_cnt;
end


always @(posedge i_div_clk or posedge i_rst) begin
	if(i_rst)
		r_byte_align <= 'd0;
	else if(r_right_cnt == P_MAX_RIGHT_NUM)
		r_byte_align <= 'd1;
	else
		r_byte_align <= 'd0;
end


ISERDESE2 #(
      .DATA_RATE		("DDR"),           // DDR, SDR
      .DATA_WIDTH		(8),              // Parallel data width (2-8,10,14)
      .DYN_CLKDIV_INV_EN("FALSE"), // Enable DYNCLKDIVINVSEL inversion (FALSE, TRUE)
      .DYN_CLK_INV_EN	("FALSE"),    // Enable DYNCLKINVSEL inversion (FALSE, TRUE)
      // INIT_Q1 - INIT_Q4: Initial value on the Q outputs (0/1)
      .INIT_Q1			(1'b0),
      .INIT_Q2			(1'b0),
      .INIT_Q3			(1'b0),
      .INIT_Q4			(1'b0),
      .INTERFACE_TYPE	("NETWORKING"),   // MEMORY, MEMORY_DDR3, MEMORY_QDR, NETWORKING, OVERSAMPLE
      .IOBDELAY			("NONE"),           // NONE, BOTH, IBUF, IFD
      .NUM_CE			(2),                  // Number of clock enables (1,2)
      .OFB_USED			("TRUE"),          // Select OFB path (FALSE, TRUE)
      .SERDES_MODE		("MASTER"),      // MASTER, SLAVE
      // SRVAL_Q1 - SRVAL_Q4: Q output values when SR is used (0/1)
      .SRVAL_Q1			(1'b0),
      .SRVAL_Q2			(1'b0),
      .SRVAL_Q3			(1'b0),
      .SRVAL_Q4			(1'b0)
   )
   ISERDESE2_inst (
      .O(				),                       // 1-bit output: Combinatorial output
      // Q1 - Q8: 1-bit (each) output: Registered data outputs
      .Q1(w_par_data[7]	),
      .Q2(w_par_data[6]	),
      .Q3(w_par_data[5]	),
      .Q4(w_par_data[4]	),
      .Q5(w_par_data[3]	),
      .Q6(w_par_data[2]	),
      .Q7(w_par_data[1]	),
      .Q8(w_par_data[0]	),
      // SHIFTOUT1, SHIFTOUT2: 1-bit (each) output: Data width expansion output ports
      .SHIFTOUT1(),
      .SHIFTOUT2(),
      .BITSLIP(r_bitslip),           // 1-bit input: The BITSLIP pin performs a Bitslip operation synchronous to
                                   // CLKDIV when asserted (active High). Subsequently, the data seen on the Q1
                                   // to Q8 output ports will shift, as in a barrel-shifter operation, one
                                   // position every time Bitslip is invoked (DDR operation is different from
                                   // SDR).

      // CE1, CE2: 1-bit (each) input: Data register clock enable inputs
      .CE1(1'b1),
      .CE2(1'b1),
      .CLKDIVP(1'b0),           // 1-bit input: TBD
      // Clocks: 1-bit (each) input: ISERDESE2 clock input ports
      .CLK(i_clk),                   // 1-bit input: High-speed clock
      .CLKB(~i_clk),                 // 1-bit input: High-speed secondary clock
      .CLKDIV(i_div_clk),             // 1-bit input: Divided clock
      .OCLK(1'b0),                 // 1-bit input: High speed output clock used when INTERFACE_TYPE="MEMORY" 
      // Dynamic Clock Inversions: 1-bit (each) input: Dynamic clock inversion pins to switch clock polarity
      .DYNCLKDIVSEL(1'b0), // 1-bit input: Dynamic CLKDIV inversion
      .DYNCLKSEL(1'b0),       // 1-bit input: Dynamic CLK/CLKB inversion
      // Input Data: 1-bit (each) input: ISERDESE2 data input ports
      .D(1'b0),                       // 1-bit input: Data input
      .DDLY(1'b0),                 // 1-bit input: Serial data from IDELAYE2
      .OFB(i_OFB),                   // 1-bit input: Data feedback from OSERDESE2
      .OCLKB(),               // 1-bit input: High speed negative edge output clock
      .RST(i_rst),                   // 1-bit input: Active high asynchronous reset
      // SHIFTIN1, SHIFTIN2: 1-bit (each) input: Data width expansion input ports
      .SHIFTIN1(),
      .SHIFTIN2()
   );
   
   
endmodule

二、oserdese2_module模块

  1. 模块上电后连续发送P_INIT_CNT个连续的8’bBC和8’b50
  2. 随后开始产生自增数据,观察接收端情况

代码如下:

module oserdese2_module(
    input          i_clk       ,
    input          i_div_clk   ,
    input          i_rst       ,
    output         o_OFB         
);

localparam  P_INIT_CNT = 64;
 
reg  [7 :0] r_par_data  ;
reg  [15:0] r_init_cnt  ;
reg         r_init_flag ;


always @(posedge i_div_clk or posedge i_rst)begin
    if(i_rst)
		r_init_cnt <= 'd0;
    else if(r_init_cnt == P_INIT_CNT)
        r_init_cnt <= P_INIT_CNT + 1;
    else
        r_init_cnt <= r_init_cnt + 1;
end

always @(posedge i_div_clk or posedge i_rst)begin
    if(i_rst)
        r_init_flag <= 'd0;
    else if(r_init_cnt < P_INIT_CNT)
        r_init_flag <= ~r_init_flag;
    else
        r_init_flag <= r_init_flag;
end

always @(posedge i_div_clk or posedge i_rst)begin
    if(i_rst)
        r_par_data <= 'd0;
    else if(r_init_cnt < P_INIT_CNT)
        r_par_data <= r_init_flag ? 8'hBC : 8'h50;
    else if(r_init_cnt == P_INIT_CNT)
        r_par_data <= 'd0;
    else
        r_par_data <= r_par_data + 'd1;
end


     
OSERDESE2 #(
   .DATA_RATE_OQ     ("DDR"         ), // DDR, SDR
   .DATA_RATE_TQ     ("DDR"         ), // DDR, BUF, SDR
   .DATA_WIDTH       (8             ), // Parallel data width (2-8,10,14)
   .INIT_OQ          (1'b0          ), // Initial value of OQ output (1'b0,1'b1)
   .INIT_TQ          (1'b0          ), // Initial value of TQ output (1'b0,1'b1)
   .SERDES_MODE      ("MASTER"      ), // MASTER, SLAVE
   .SRVAL_OQ         (1'b0          ), // OQ output value when SR is used (1'b0,1'b1)
   .SRVAL_TQ         (1'b0          ), // TQ output value when SR is used (1'b0,1'b1)
   .TBYTE_CTL        ("FALSE"       ), // Enable tristate byte operation (FALSE, TRUE)
   .TBYTE_SRC        ("FALSE"       ), // Tristate byte source (FALSE, TRUE)
   .TRISTATE_WIDTH   (1             )  // 3-state converter width (1,4)
)
OSERDESE2_inst (
   .OFB              (o_OFB         ), // 1-bit output: Feedback path for data
   .OQ               (              ), // 1-bit output: Data path output
   // SHIFTOUT1 / SHIFTOUT2: 1-bit (each) output: Data output expansion (1-bit each)
   .SHIFTOUT1        (              ),
   .SHIFTOUT2        (              ),
   .TBYTEOUT         (              ), // 1-bit output: Byte group tristate
   .TFB              (              ), // 1-bit output: 3-state control
   .TQ               (              ), // 1-bit output: 3-state control
   .CLK              (i_clk         ), // 1-bit input: High speed clock
   .CLKDIV           (i_div_clk     ), // 1-bit input: Divided clock
   // D1 - D8: 1-bit (each) input: Parallel data inputs (1-bit each)
   .D1               (r_par_data[0] ),
   .D2               (r_par_data[1] ),
   .D3               (r_par_data[2] ),
   .D4               (r_par_data[3] ),
   .D5               (r_par_data[4] ),
   .D6               (r_par_data[5] ),
   .D7               (r_par_data[6] ),
   .D8               (r_par_data[7] ),
   .OCE              (1'b1          ), // 1-bit input: Output data clock enable
   .RST              (i_rst         ), // 1-bit input: Reset
   // SHIFTIN1 / SHIFTIN2: 1-bit (each) input: Data input expansion (1-bit each)
   .SHIFTIN1         (              ),
   .SHIFTIN2         (              ),
   // T1 - T4: 1-bit (each) input: Parallel 3-state inputs
   .T1               (1'b0          ),
   .T2               (1'b0          ),
   .T3               (1'b0          ),
   .T4               (1'b0          ),
   .TBYTEIN          (1'b0          ), // 1-bit input: Byte group tristate
   .TCE              (1'b0          )  // 1-bit input: 3-state clock enable
);
 
endmodule

三、顶层模块

例化clk_wiz_100M_400M模块,产生100Mhz时钟和400Mhz时钟信号,分别对应CLKDIV和CLK,这也是最常用的方法。

module serdes_top(
	input          i_clk_p       ,
	input          i_clk_n       
);

wire 		w_clk_100mhz	;
wire 		w_clk_400mhz	;
wire   		w_locked		;

wire   		w_OFB			;
wire [7 :0]	w_par_data		;
wire  		w_data_valid	;

clk_wiz_100M_400M clk_wiz_100M_400M_u0
(
	.clk_out1		(w_clk_100mhz	),  
	.clk_out2		(w_clk_400mhz	),  
	.locked			(w_locked		),    
	.clk_in1_p		(i_clk_p		), 
	.clk_in1_n		(i_clk_n		)  
);

oserdese2_module oserdese2_module_u0(
	.i_clk       	(w_clk_400mhz	),
	.i_div_clk   	(w_clk_100mhz	),
	.i_rst       	(!w_locked		),
	.o_OFB       	(w_OFB			)  
);

iserdese2_module iserdese2_module_u0(
	.i_clk       	(w_clk_400mhz	),
	.i_div_clk   	(w_clk_100mhz	),
	.i_rst       	(!w_locked		),
	.i_OFB     		(w_OFB			),
	.o_par_data		(w_par_data		),
	.o_data_valid	(w_data_valid	)
);


endmodule

四、仿真结果分析

如下图所示,黄色刻度线和蓝色刻度线之间的过程是在进行不断对齐,蓝色刻度线之后串并转换对齐,开始正常接收数据。
在这里插入图片描述
正常数据如下,结果比对,仿真结果正确:成功将自增数据进行恢复。
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/758559.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【C语言】指针剖析(2)

©作者:末央&#xff06; ©系列:C语言初阶(适合小白入门) ©说明:以凡人之笔墨&#xff0c;书写未来之大梦 目录 一、数组名1.概念2.sizeof和&里面的数组名sizeof& 二、使用指针访问数组三、一维数组传参本质四、指针数组1.概念实例&#xff08;模拟二维数…

C语言中常用的运算符、表达式和语句

C语言是一种通用的、高级的编程语言&#xff0c;其历史可以追溯到20世纪60年代末至70年代初。C语言最初是由丹尼斯里奇&#xff08;Dennis Ritchie&#xff09;在贝尔实验室为开发UNIX操作系统而设计的。它继承了许多B语言的特性&#xff0c;而B语言则是由迷糊老师&#xff08;…

C#基于SkiaSharp实现印章管理(3)

本系列第一篇文章中创建的基本框架限定了印章形状为矩形&#xff0c;但常用的印章有方形、圆形等多种形状&#xff0c;本文调整程序以支持定义并显示矩形、圆角矩形、圆形、椭圆等4种形式的印章背景形状。   定义印章背景形状枚举类型&#xff0c;矩形、圆形、椭圆相关的尺寸…

springboot宠物医院管理系统-计算机毕业设计源码07221

目 录 1 绪论 1.1 选题背景和意义 1.2国内外研究现状 1.3论文结构与章节安排 2 宠物医院管理系统系统分析 2.1 可行性分析 2.1.1技术可行性分析 2.1.2 操作可行性分析 2.1.3 法律可行性分析 2.2 系统功能分析 2.2.1 功能性分析 2.2.2 非功能性分析 2.3 系统用例分…

docker配置国内镜像加速器

1、搜索阿里云 2、搜索容器镜像服务 点击管理控制台 配置镜像加速器

uniapp部署服务器,uniapp打包H5部署服务器,uniapp将config.js抽离

目录 步骤一.在static文件夹下新建config.js文件 config.js文件说明 在config.js中放入使用的请求的接口地址,资源路径等 congfig.js中的变量在页面中如何使用 步骤二.manifest.json配置 1.在项目根目录(与app.vue同级)创建template.h5.html文件 2.在manifest.json配置刚刚创…

手机屏幕贴合项目(ni视觉如何找矩形的角坐标)

首先&#xff0c;我们存储了cg和dito感兴趣八个角图像的模板&#xff0c;用来匹配位置。 cover指的是cg的四个角模板&#xff0c;lcm是dito四个角匹配模板。 其次&#xff0c;我们采集的8副图像&#xff08;m_DlgCCDViewArr[2][4]&#xff09;中一定包含匹配模板的特征。 好&…

土体中应力的计算

土中的应力的计算 非水面以下土体中应力的计算&#xff1a;水面以下的土中的应力计算 参考视频&#xff1a; https://www.bilibili.com/video/BV1Rh411J72h/?spm_id_from333.788&vd_source02b2bad477a153eaeb9c48cbbedaf8df 非水面以下土体中应力的计算&#xff1a; 按成…

C++自定义智能指针

template <class T> class counted_ptr;// 智能指针引用计数类 template <class T> class Ref_Ptr {friend class counted_ptr<T>; private:T* m_pTtr; // 实际的指针size_t counted_ptr; // 引用计数Ref_Ptr(T* p);virtual ~Ref_Ptr(); };template <clas…

Golang | Leetcode Golang题解之第200题岛屿数量

题目&#xff1a; 题解&#xff1a; func numIslands(grid [][]byte) int {res : 0for i : 0; i < len(grid); i {for j : 0; j < len(grid[i]); j {if grid[i][j] 1 {resdfs(grid, i, j)}}}return res }func dfs(grid [][]byte, r, c int) {h, w : len(grid), len(gri…

标准版小程序订单中心path审核不通过处理教程

首先看自己小程序是不是已经审核通过并上线状态才在站内信里面提醒的&#xff1f; 如果没有提交过审核&#xff0c;请在提交的时候填写。path地址为&#xff1a;pages/goods/order_list/index 如果是已经上线的小程序&#xff0c;当时没要求填这个&#xff0c;但新的政策要求填…

如何通过Profile快速定位Doris查询瓶颈

1 如何获取profile 参考文档&#xff1a;https://doris.apache.org/zh-CN/docs/query/query-analysis/get-profile 我们时常遇到对应 SQL 执行时间不及预期的情况&#xff0c;为了优化 SQL 达到预期查询时延&#xff0c;通过 Profile 我们能够看出可以做哪些优化。现在说明在…

为何同一PDF文档用不同软件打印效果不同?

通过扫描仪生成的同一PDF文档&#xff0c;同样的设置&#xff0c;为什么别的电脑打出来是白底我的打出来有灰色格子背景&#xff1f;这种情况通常是由于PDF阅读软件的不同造成的差异。 ### 可能的原因和解决方法&#xff1a; 1. **PDF阅读软件的不同**&#xff1a; - **解决方…

小型光纤抗干扰无人机技术详解

一、光纤通信技术应用 光纤通信技术是现代通信技术的重要组成部分&#xff0c;其在小型无人机中的应用为无人机的数据传输带来了革命性的改变。光纤通信具有高速率、大带宽、低损耗和抗电磁干扰等优点&#xff0c;使得无人机在执行任务时能够实时传输高清图像、视频和大量数据…

[JS]BOM操作

介绍 BOM(Browser Object Model)是浏览器对象模型 window对象是一个全局对象, 也是JS中的顶级对象通过var定义在全局作用域中的变量和函数都会变成window对象的属性和方法window对象下的属性和方法调用时一般省略window 间歇函数 定时器 定时器是间歇函数的一种, 可以每个每…

《昇思25天学习打卡营第2天 | 昇思MindSpore张量 Tensor》

第二天学习 1.今天学习了张量 Tensor&#xff0c;了解到Tensor是一个可用来表示在一些矢量、标量和其他张量之间的线性关系的多线性函数&#xff0c;也是一个特殊的数据结构&#xff0c;与数组和矩阵非常相似。是MindSpore网络运算中的基本数据结构。学些了张量和稀疏张量的属性…

Node版本管理工具 fnm 安装使用

fnm 是一个基于 Rust 开发的 Node 版本管理工具&#xff0c;它的目标是提供一个快速、简单且可靠的方式来管理 Node.js 的不同版本。同时&#xff0c;它是跨平台的&#xff0c;支持 macOS、Linux、Windows。&#x1f680; Fast and simple Node.js version manager, built in R…

五十九周:文献阅读+FiLM

目录 摘要 Abstract 文献阅读&#xff1a;用于长时间序列预测的频率改进的勒让德记忆模型 一、现有问题 二、提出方法 三、相关知识 1、Legendre Projection&#xff08;Legendre投影&#xff09; 2、Fourier Transform&#xff08;傅立叶变换&#xff09; 四、提出的…

文件操作与管理

程序经常需要访问文件和目录&#xff0c;读取文件信息或写入文件信息&#xff0c;在Python语言中对文件的读写是通过文件对象&#xff08;file object&#xff09;实现的。Python的文件对象也称为类似文件对象或流&#xff08;stream&#xff09;&#xff0c;因为Python提供一种…

数据库-数据完整性-用户自定义完整性实验

NULL/NOT NULL 约束&#xff1a; 在每个字段后面可以加上 NULL 修饰符来指定该字段是否可以为空&#xff1b;或者加上 NOT NULL 修饰符来指定该字段必须填上数据。 DEFAULT约束说明 DEFAULT 约束用于向列中插入默认值。如果列中没有规定其他的值&#xff0c;那么会将默认值添加…