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

news2024/12/24 9:35:32

文章目录

  • 前言
  • 一、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.coloradmin.cn/o/1876769.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

程序员学长 | 快速学会一个算法模型,LSTM

本文来源公众号“程序员学长”&#xff0c;仅用于学术分享&#xff0c;侵权删&#xff0c;干货满满。 原文链接&#xff1a;快速学会一个算法模型&#xff0c;LSTM 今天&#xff0c;给大家分享一个超强的算法模型&#xff0c;LSTM。 LSTM&#xff08;Long Short-Term Memory…

AI绘画 Stable Diffusion【实战进阶】:图片的创成式填充,竖图秒变横屏壁纸!想怎么扩就怎么扩!

大家好&#xff0c;我是向阳。 所谓图片的创成式填充&#xff0c;就是基于原有图片进行扩展或延展&#xff0c;在保证图片合理性的同时实现与原图片的高度契合。是目前图像处理中常见应用之一。之前大部分都是通过PS工具来处理的。今天我们来看看在AI绘画工具 Stable Diffusio…

微信内置H5支付

&#x1f9d1;‍&#x1f4bb; 写在开头 点赞 收藏 学会&#x1f923;&#x1f923;&#x1f923; 场景是用户通过微信扫app内的收款码&#xff0c;跳到一个h5页面。然后完成支付。 代码实现的整体流程&#xff1a; 使用微信扫码&#xff0c;码是app内生成的&#xff0c;码…

Qt WPS(有源码)

项目源码地址&#xff1a;WPS完整源码 一.项目详情 该项目仿照WPS&#xff0c;实现了部分的功能&#xff0c;能够很方便对文本和HTML进行修改&#xff0c;并且有打印功能&#xff0c;可以很方便的生成PDF。 应用界面 项目架构分析 这个项目主要可分为两个部分&#xff0c;一…

等保2.0安全计算环境解读

等保2.0&#xff0c;即网络安全等级保护2.0制度&#xff0c;是中国为了适应信息技术的快速发展和安全威胁的新变化而推出的网络安全保护标准。相较于等保1.0&#xff0c;等保2.0更加强调主动防御、动态防御和全面审计&#xff0c;旨在实现对各类信息系统的全面保护。 安全计算环…

鼠尾草(洋苏草)

鼠尾草&#xff08;Salvia japonica Thunb.&#xff09;&#xff0c;又名洋苏草、普通鼠尾草、庭院鼠尾草&#xff0c;属于唇形科鼠尾草属多年生草本植物。鼠尾草以其独特的蓝紫色花序和长而细密的叶片为特点&#xff0c;常用于花坛、庭院和药用植物栽培。 鼠尾草的名字源自于…

Java访问修饰符的区别

public&#xff1a;公开的&#xff0c;任何地方都可以访问。 protected&#xff1a;受保护的&#xff0c;同一个包中的类和所有子类(可跨包)可以访问。 private&#xff1a;私有的&#xff0c;只有在同一个类中可以访问。 默认&#xff08;无修饰符&#xff09;&#xff1a;包级…

[Go 微服务] go-micro + consul 的使用

文章目录 1.go-micro 介绍2.go-micro 的主要功能3.go-micro 安装4.go-micro 的使用4.1 创建服务端4.2 配置服务端 consul4.3 生成客户端 5.goodsinfo 服务5.1 服务端开发5.2 客户端开发 1.go-micro 介绍 Go Micro是一个简化分布式开发 的微服务生态系统&#xff0c;该系统为开…

stm32学习笔记---ADC模数转换器(理论部分)

目录 ADC简介 什么叫逐次逼近型&#xff1f; STM32 ADC框图 模数转换器外围线路 ADC基本结构图 输入通道 规则组的四种转换模式 第一种&#xff1a;单次转换非扫描模式 第二种&#xff1a;连续转换&#xff0c;非扫描模式 第三种&#xff1a;单次转换&#xff0c;扫描…

数据结构03 链表的基本操作【C++数组模拟实现】

前言&#xff1a;本节内容主要了解链表的基本概念及特点&#xff0c;以及能够通过数组模拟学会链表的几种基本操作&#xff0c;下一节我们将通过STL模板完成链表操作&#xff0c;可以通过专栏进入查看下一节哦~ 目录 单链表及其特点 完整链表构成 完整链表简述 创建单链表 …

MySQL自增主键踩坑记录

对于MySQL的自增主键&#xff0c;本文记录、整理下在工作中实际遇到的问题。 下面示例均基于MySQL 8.0 修改列的类型后&#xff0c;自增属性消失 CREATE TABLE users (id INT AUTO_INCREMENT PRIMARY KEY,username VARCHAR(50) NOT NULL,email VARCHAR(100) NOT NULL );上面的…

计算机监控软件有哪些?10款常年霸榜的计算机监控软件

计算机监控软件是企业管理和保护信息安全的重要工具&#xff0c;它们帮助企业管理者监督员工的计算机使用行为&#xff0c;确保工作效率、数据安全以及合规性。在众多监控软件中&#xff0c;有些产品因其卓越的功能、易用性、安全性以及持续获得的良好市场反馈而常年占据行业领…

什么是指令微调(LLM)

经过大规模数据预训练后的语言模型已经具备较强的模型能力&#xff0c;能够编码丰富的世界知识&#xff0c;但是由于预训练任务形式所限&#xff0c;这些模型更擅长于文本补全&#xff0c;并不适合直接解决具体的任务。 指令微调是相对“预训练”来讲的&#xff0c;预训练的时…

spring mvc实现一个自定义Formatter请求参数格式化

使用场景 在Spring Boot应用中&#xff0c;Formatter接口用于自定义数据的格式化&#xff0c;比如将日期对象格式化为字符串&#xff0c;或者将字符串解析回日期对象。这在处理HTTP请求和响应时特别有用&#xff0c;尤其是在展示给用户或从用户接收特定格式的数据时。下面通过…

集合,Collection接口

可动态保存任意多个对象&#xff0c;使用比较方便 提供了一系列方便操作对象的方法&#xff1a;add&#xff0c;remove&#xff0c;set&#xff0c;get等 使用集合添加删除新元素&#xff0c;代码简洁明了 单列集合 多列集合 Collection接口 常用方法 List list new Arra…

【原创图解 算法leetcode 146】实现一个LRU缓存淘汰策略策略的数据结构

1 概念 LRU是Least Recently Used的缩写&#xff0c;即最近最少使用&#xff0c;是一种常见的缓存淘汰算法。 其核心思想为&#xff1a;当内存达到上限时&#xff0c;淘汰最久未被访问的缓存。 2 LeetCode LeetCode: 146. LRU缓存 3 实现 通过上面LRU的淘汰策略可知&#…

北京市大兴区餐饮行业协会成立暨职业技能竞赛总结大会成功举办

2024年6月27日下午&#xff0c;北京市大兴区营商服务中心B1层报告厅迎来了北京市大兴区餐饮行业协会成立仪式暨2024年北京市大兴区餐饮行业职工职业技能竞赛总结大会。此次活动不仅标志着大兴区餐饮行业协会的正式成立&#xff0c;也对在2024年大兴区餐饮行业职工职业技能竞赛中…

Python自动化测试:web自动化测试——selenium API、unittest框架的使用

web自动化测试2 1. 设计用例的方法——selenium API1.1 基本元素定位1&#xff09;定位单个唯一元素2&#xff09;定位一组元素3&#xff09;定位多窗口/多框架4&#xff09;定位连续层级5&#xff09;定位下拉框6&#xff09;定位div框 1.2 基本操作1.3 等待1.4 浏览器操作1.5…

SpringBoot整合Quartz实现动态定时任务

目录 1、Quartz简介1.1 Quartz的三大核心组件1.2 CronTrigger配置格式 2、SpringBoot整合Quartz框架2.1 创建项目2.2 实现定时任务 1、Quartz简介 Quartz是一个开源的任务调度服务&#xff0c;它可以独立使用&#xff0c;也可与其它的Java EE&#xff0c;Java SE应用整合使用。…

Python数据分析案例48——二手房价格影响因素分析

案例背景 房价影响因素也是人们一直关注的问题&#xff0c;本次案例也适合各种学科的同学&#xff0c;无论你是经济管理类还是数学统计&#xff0c;还是电商物流类&#xff0c;都可以使用回归分析。通过数据分析回归分析分组聚合可视化等方法进行研究房价影响因素。 数据介绍 …