序列发生器(两类序列、三种设计方法和两种发生模式|verilog代码|Testbench|仿真结果)

本文主要是介绍序列发生器(两类序列、三种设计方法和两种发生模式|verilog代码|Testbench|仿真结果),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

序列发生器

  • 一、前言
  • 二、状态机法、寄存器法和计数器法
    • 2.1 状态机法
      • 2.1.1使用状态机生成序列1001
      • 2.1.2 Verilog代码
      • 2.1.3 Tsetbench
      • 2.1.4 仿真结果
    • 2.2移位寄存器法
      • 2.2.1使用移位寄存器生成序列1001
      • 2.2.2 Verilog代码
      • 2.2.3 Tsetbench
      • 2.2.4 仿真结果
    • 2.3计数器法
      • 2.3.1 使用计数器生成序列1001
      • 2.3.2 Verilog代码
      • 2.3.3 Tsetbench
      • 2.3.4 仿真结果
  • 三、重叠发生与非重叠发生
    • 3.1非重叠和重叠生成序列“1001”
    • 3.2 verilog代码
    • 3.3 Testbench
    • 3.4 仿真结果
  • 四、伪随机序列发生器
    • 4.1 伪随机序列发生器原理
    • 4.2 verilog代码
    • 4.3 Testbench
    • 4.4 仿真结果
  • 五、总结

在这里插入图片描述



数字IC经典电路设计
经典电路设计是数字IC设计里基础中的基础,盖大房子的第一部是打造结实可靠的地基,每一篇笔者都会分门别类给出设计原理、设计方法、verilog代码、Testbench、仿真波形。然而实际的数字IC设计过程中考虑的问题远多于此,通过本系列希望大家对数字IC中一些经典电路的设计有初步入门了解。能力有限,纰漏难免,欢迎大家交流指正。

快速导航链接如下:

个人主页链接
1.数字分频器设计
2.序列检测器设计
3.序列发生器设计
4.序列模三检测器设计
5.奇偶校验器设计
6.自然二进制数与格雷码转换



一、前言

序列发生器是一种基于数字电路中逻辑门、触发器等组件设计的模块化电路,可以按照特定的顺序生成一系列数字信号或数据。

为什么需要设计序列发生器呢?

在数字IC设计中,序列发生器通常被用于产生特定的数字序列,以用于测试和验证数字电路的正确性。序列发生器通常被用于产生随机或伪随机数字序列,以模拟实际的操作环境,并测试数字电路的各种情况下的响应。

序列发生器通常用于测试数字电路中的寄存器、计数器、状态机等模块。例如,在设计一个计数器时,需要验证计数器是否可以正确地计数,并且在达到最大计数值时是否能够正确地回滚到初始值。为了验证这些功能,需要使用一个序列发生器来产生一系列的计数值,并将这些值输入到计数器中进行测试。因此,序列发生器在数字IC设计中是一个非常重要的工具,它可以帮助设计师验证数字电路的正确性,并提高数字电路的可靠性和性能。

序列发生器有哪些发生模式呢?

以下是一些常见的序列发生器模式:

  • 简单发生器:按照固定的顺序依次输出数字序列。
  • 密码型发生器:根据特定的编码方式,产生符合要求的数字序列,如曼彻斯特编码、差分曼彻斯特编码等。
  • 伪随机序列发生器:产生看似随机的数字序列,但实际上是按照特定的算法生成的,用于加密和通信等领域。

序列发生器的设计思路同序列检测器相似,常用简单序列发生器设计有如下三种设计思路:(1)状态机法;(2)移位寄存器法;(3)计数器法。

二、状态机法、寄存器法和计数器法

2.1 状态机法

2.1.1使用状态机生成序列1001

要求:使用状态机设计一个序列发生器,可循环生成序列“1001”,要求序列不重叠

此处设计思路与序列检测器相似,且更为简单, 参考序列检测器2.1状态机部分。以生成“1001”序列为例,借用万能的状态机,设计四个状态并且依次发生状态转移,通过判断当前的状态从而输出一位对应的数字,四个状态分别对应序列“1001”的四位数字。因为有限状态机的工作原理,序列“1001”将会被逐位循环输出。

2.1.2 Verilog代码

//使用状态机设计发生“1001”的序列发生器
//可非重叠发生序列“1001”
module sequence_generator01(input	  clk, input 	  rst_n,output   reg  seq_out );//采用独热码编译四个状态,初始IDLE状态为待机状态
//独热码相比二进制码和格雷码,方便电路设计判断、状态转移,且逻辑更简单 
parameter        IDLE = 4'b0001;
parameter        S1   = 4'b0010;
parameter 	  	 S2   = 4'b0100;
parameter        S3   = 4'b1000;//定义两个寄存器表示状态机的目前状态和下一状态
reg [3:0]	 curr_state;
reg [3:0] 	 next_state;//第一段使用时序逻辑描述状态转移
always@(posedge clk or negedge rst_n) beginif(!rst_n) begincurr_state <= IDLE;endelse begincurr_state <= next_state;end
end//第二段使用组合逻辑判断状态转移条件
always@(*) beginif(!rst_n) beginnext_state <= IDLE;endelse begincase(curr_state)IDLE  :next_state = S1;S1	  :next_state = S2;S2	  :next_state = S3;S3	  :next_state = IDLE;default:next_state = IDLE;	//养成良好代码风格,不能遗漏,防生成latch,也可以通过赋初值避免endcaseend
end//第三段使用时序逻辑描述状态输出
//通过判断状态机的状态来判断当前的输出值,达到输出序列“1001”目的
always@(posedge clk or negedge rst_n) beginif(!rst_n) beginseq_out <= 1'b0;endelse begincase(next_state)IDLE  :seq_out <= 1'b1;S1	  :seq_out <= 1'b0;S2	  :seq_out <= 1'b0;S3	  :seq_out <= 1'b1;default:seq_out <= 1'b0;endcaseend
endendmodule

2.1.3 Tsetbench

`timescale 1ns/1ps		//仿真时间单位1ns 仿真时间精度1ps
module sequence_gnerator01_tb();//信号申明
reg 	clk;
reg 	rst_n;
wire 	seq_out;//生成复位信号
//为时钟信号和复位信号赋初值
initial beginclk    = 0;rst_n  = 1;#5  rst_n = 0;#10 rst_n = 1;
end//生成时钟信号
always #5  clk = ~clk;//模块实例化(将申明的信号连接起来即可)
sequence_generator01 u_sequence_generator01(.clk        	 (clk),.rst_n		     (rst_n), .seq_out		 (seq_out));endmodule

2.1.4 仿真结果

在这里插入图片描述

2.2移位寄存器法

2.2.1使用移位寄存器生成序列1001

要求:使用移位寄存器设计一个序列发生器,可循环生成序列“1001”,要求序列不重叠

此处设计思路与序列检测器相似,且更为简单, 参考序列检测器2.2移位寄存器部分。设置一个和序列等长的寄存器,且初始数值为“1001”。处于时钟上升沿时完成两步操作:首先,输出当前寄存器的缓存数据的最高位;其次是,将数据的最高位转移到数据的最低位,拼接成新的数据重新缓存到寄存器中。因为移位寄存器的工作原理,缓存在移位寄存器中的序列“1001”将会被逐位循环输出。

2.2.2 Verilog代码

//使用移位寄存器设计发生“1001”的序列发生器
//可非重叠发生序列“1001”
module sequence_generator02(input	  clk, input 	  rst_n,output   reg  seq_out );//定义一个寄存器缓存数据
reg  [3:0]  seq;//使用时序逻辑完成复位和移位寄存器移位过程
always@(posedge clk or negedge rst_n) begin if(!rst_n) begin seq <= 4'b1001;		//初始赋值“1001”(此处复位不是0)endelse begin seq <= {seq[2:0],seq[3]};	//移位寄存器最高位位移至最低位end 
end //使用时序逻辑完成复位与输出
always@(posedge clk or negedge rst_n) begin if(!rst_n) begin seq_out <= 1'b0;endelse begin seq_out <= seq[3];	//每个时钟上升沿输出最高位end 
endendmodule

2.2.3 Tsetbench

`timescale 1ns/1ps	//仿真时间单位1ns 仿真时间精度1ps
module sequence_gnerator02_tb();//信号申明
reg 	clk;
reg 	rst_n;
wire 	seq_out;//复位信号生成
//时钟信号与复位信号赋初值
initial beginclk    = 0;rst_n  = 1;#5  rst_n = 0;#10 rst_n = 1;
end//生成时钟信号
always #5  clk = ~clk;//模块实例化(将申明的信号连接起来即可)
sequence_generator02 u_sequence_generator02(.clk        	 (clk),.rst_n		 	 (rst_n), .seq_out		 (seq_out));endmodule

2.2.4 仿真结果

在这里插入图片描述

2.3计数器法

2.3.1 使用计数器生成序列1001

要求:使用计数器设计一个序列发生器,可循环生成序列“1001”,要求序列不重叠

在此处借用计数器设计序列发生器思路同借用状态机设计序列发生器异曲同工,此处的计数器可以理解为“小状态机”,在2.1中状态机状态的转移相当于此处计数器的不断累加。通过判断当前计数器数值从而输出一位对应的数字,四个状态分别对应序列“1001”的四位数字。因为计数器的工作原理,序列“1001”将会被逐位循环输出。

2.3.2 Verilog代码

//使用计数器设计发生“1001”的序列发生器
//可非重叠发生序列“1001”
module sequence_generator03(input	  clk, input 	  rst_n,output   reg  seq_out );//定义一个计数器
reg  [1:0]  cnt;//计数器模块
//完成0-3的循环计数
always@(posedge clk or negedge rst_n) begin if(!rst_n) begin cnt <= 2'b00;endelse if(cnt == 2'b11) begincnt <= 2'b00;endelse begin cnt <= cnt + 1'b1;end 
end //根据计数器的计数逐次输出“1001” 
always@(posedge clk or negedge rst_n) begin if(!rst_n) begin seq_out <= 1'b0;endelse begin case(cnt)2'b00:seq_out <= 1'b1;2'b01:seq_out <= 1'b0;2'b10:seq_out <= 1'b0;2'b11:seq_out <= 1'b1;endcaseend 
endendmodule

2.3.3 Tsetbench

`timescale 1ns/1ps		//仿真时间单位1ns 仿真时间精度1ps
module sequence_gnerator03_tb();//信号申明
reg 	clk;
reg 	rst_n;
wire 	seq_out;//生成复位信号
//为时钟信号和复位信号赋初值
initial beginclk    = 0;rst_n  = 1;#5  rst_n = 0;#10 rst_n = 1;
end//生成时钟信号
always #5  clk = ~clk;//模块实例化(将申明的信号连接起来即可)
sequence_generator03 u_sequence_generator03(.clk        	 (clk),.rst_n			 (rst_n), .seq_out		 (seq_out));endmodule

2.3.4 仿真结果

在这里插入图片描述

三、重叠发生与非重叠发生

在上一篇序列检测器文章中,我们提到了关于序列检测的四种模式—重叠模式、非重叠模式、连续模式、间隔模式,在序列发生器这里同样存在重叠序列发生模式和非重叠序列发生模式。这里之所以会单独领出来讲,是因为不同的发生模式会对设计出来的电路面积存在影响,尤其以移位寄存器法设计的序列发生器触发器的数量截然不同。以下以寄存器法设计为例来阐述两种模式的差异。

3.1非重叠和重叠生成序列“1001”

要求:使用移位寄存器设计一个序列发生器,可循环生成序列“1001”,有两个输出,一个要求序列不重叠一个要求序列重叠

3.2 verilog代码

//使用移位寄存器设计发生“1001”的序列发生器
//可重叠和非重叠发生序列“1001”
module sequence_generator04(input	  clk, input 	  rst_n,output   reg  seq_out_1,output   reg  seq_out_2);//定义两个个寄存器缓存数据
//寄存器定义的位数不同:非重叠缓存数据“1001”而重叠缓存缓存数据“100”
reg  [3:0]  seq_1;
reg  [2:0]  seq_2;//非重叠序列发生器模块
//使用时序逻辑完成复位和移位寄存器移位过程
always@(posedge clk or negedge rst_n) begin if(!rst_n) begin seq_1 <= 4'b1001;	//非重叠缓存数据“1001”(复位不是0)endelse begin seq_1 <= {seq_1[2:0],seq_1[3]};	//移位寄存器最高位位移至最低位end 
end //使用时序逻辑完成复位与输出 
always@(posedge clk or negedge rst_n) begin if(!rst_n) begin seq_out_1 <= 1'b0;endelse begin seq_out_1 <= seq_1[3];	//每个时钟上升沿输出最高位end 
end//重叠序列发生器模块
//使用时序逻辑完成复位和移位寄存器移位过程 
always@(posedge clk or negedge rst_n) begin if(!rst_n) begin seq_2 <= 4'b100;endelse begin seq_2 <= {seq_2[1:0],seq_2[2]};end 
end //使用时序逻辑完成复位与输出 
always@(posedge clk or negedge rst_n) begin if(!rst_n) begin seq_out_2 <= 1'b0;endelse begin seq_out_2 <= seq_2[2];	//每个时钟上升沿输出最高位end 
endendmodule

3.3 Testbench

`timescale 1ns/1ps	//仿真时间单位1ns 仿真时间精度1ps
module sequence_gnerator04_tb();//信号申明
reg 	clk;
reg 	rst_n;
wire 	seq_out_1;
wire 	seq_out_2;//复位信号生成
//时钟信号与复位信号赋初值
initial beginclk    = 0;rst_n  = 1;#5  rst_n = 0;#10 rst_n = 1;
end//生成时钟信号
always #5  clk = ~clk;//模块实例化(将申明的信号连接起来即可)
sequence_generator04 u_sequence_generator04(.clk        	 (clk),.rst_n		 	 (rst_n), .seq_out_1		 (seq_out_1),.seq_out_2		 (seq_out_2));endmodule

3.4 仿真结果

在这里插入图片描述

四、伪随机序列发生器

4.1 伪随机序列发生器原理

要求:设计一个简单序列发生器,可随机产生序列,随机序列无额外特定要求。

这个随机序列发生器可使用一个8位的“种子”来生成随机数。在每个时钟周期上升沿时,它使用当前种子值来生成一个新的种子值,并将其用作下一个时钟周期的种子。它还将当前种子值作为输出随机数。

这个随机序列发生器使用了一个简单的XOR Shift算法来生成新的种子值。这个算法通过将当前种子值向左右移位,并将结果与原始种子值进行异或来生成新的种子值。这个算法在实现上比较简单,并且可以生成高质量的随机数序列。

4.2 verilog代码

//使用XOR—Shift算法设计伪随机序列发生器
module sequence_generator05(input		clk,input		rst_n,output reg  [7:0] seq_out);//定义一个中间寄存器“种子”
reg [7:0] seed;//使用XOR—Shift算法形成“新种子”
always@(posedge clk or posedge rst_n) beginif(!rst_n) beginseed <= 8'b1; // 初始化种子endelse beginseed <= seed ^ (seed >> 2) ^ (seed << 3) ; // 生成新种子end
endalways@(posedge clk or posedge rst_n) beginif(!rst_n) beginseq_out <= 8'b0; // 初始化随机数endelse beginseq_out <= seed; // 生成新随机数end
endendmodule

4.3 Testbench

`timescale 1ns/1ps	//仿真时间单位1ns 仿真时间精度1ps
module sequence_gnerator05_tb();//信号申明
reg 	clk;
reg 	rst_n;
wire 	seq_out;//复位信号生成
//时钟信号与复位信号赋初值
initial beginclk    = 0;rst_n  = 1;#5  rst_n = 0;#10 rst_n = 1;
end//生成时钟信号
always #5  clk = ~clk;//模块实例化(将申明的信号连接起来即可)
sequence_generator05 u_sequence_generator05(.clk        	 (clk),.rst_n		 	 (rst_n), .seq_out		 (seq_out));endmodule

4.4 仿真结果

在这里插入图片描述

五、总结

  • 序列发生器设计方法:常见的固定序列发生器有三种设计思路,分别是状态机法、移位寄存器法、计数器法。在设计的时候虽然都可以使用,但往往在考虑电路的面积后会采取最优的方法。设计时尽量使的电路面积最小,必须考虑采用哪种方法借用的触发器数量最少!
  • 序列重叠发生与非重叠发生:以本篇序列发生器产生无重叠序列“1001”而言:
    ①若是采用状态机且采用独热码编译状态则需要四个触发器,采用格雷码编译状态只需两个触发器;若是采用移位寄存器,则需要两个触发器;若是采用计数器,则需要两个触发器;
    ②假设本篇序列发生器产生可重叠序列“1101011”,那么触发器的数目会与无重叠序列发生器一致吗?答案是不一样的!这里变成重叠序列,也就是产生的序列可以是110101101011…,这个序列中有两个1101011,二者共用11,因此以移位寄存器法产生这样的序列只需要一个5位的移位寄存器,而不可重叠序列需要7个。
    总的来说,在对序列无特殊要求情况下,若是想减少触发器的数目,可使用状态机格雷码编译状态,且产生的序列是可重叠的。
  • 伪随机序列发生器:除了固定序列的序列发生器,还存在随机序列发生器,这种随机序列发生器有很多种,可根据实际情况采用不同的算法设计出对应的伪随机序列发生器。本篇主要介绍的是最简单的伪随机序列发生器,主要通过 XOR Shift算法实现。


以下为补充的几个问题:

Question:欲产生序列信号 11010111,则至少需要______级触发器,采用______法设计。
Answer:3;状态机

Question:欲用移位寄存器产生序列信号1101010,试分析至少需要几级触发器。
Answer:6级触发器,用6级,移位状态为110101 - 101010 - 010101 - 101011 - 010110 - 101101 - 011010 - 110101……,依次输出最高位1101010。



不定期检查、补充、纠错,欢迎随时交流纠错
最后修改日期:2023.4.27

软件版本:

仿真软件:Modelsim 10.6c
绘图软件:亿图图示
描述语言:verilog

这篇关于序列发生器(两类序列、三种设计方法和两种发生模式|verilog代码|Testbench|仿真结果)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/740909

相关文章

Linux换行符的使用方法详解

《Linux换行符的使用方法详解》本文介绍了Linux中常用的换行符LF及其在文件中的表示,展示了如何使用sed命令替换换行符,并列举了与换行符处理相关的Linux命令,通过代码讲解的非常详细,需要的... 目录简介检测文件中的换行符使用 cat -A 查看换行符使用 od -c 检查字符换行符格式转换将

SpringBoot实现数据库读写分离的3种方法小结

《SpringBoot实现数据库读写分离的3种方法小结》为了提高系统的读写性能和可用性,读写分离是一种经典的数据库架构模式,在SpringBoot应用中,有多种方式可以实现数据库读写分离,本文将介绍三... 目录一、数据库读写分离概述二、方案一:基于AbstractRoutingDataSource实现动态

Linux系统配置NAT网络模式的详细步骤(附图文)

《Linux系统配置NAT网络模式的详细步骤(附图文)》本文详细指导如何在VMware环境下配置NAT网络模式,包括设置主机和虚拟机的IP地址、网关,以及针对Linux和Windows系统的具体步骤,... 目录一、配置NAT网络模式二、设置虚拟机交换机网关2.1 打开虚拟机2.2 管理员授权2.3 设置子

springboot循环依赖问题案例代码及解决办法

《springboot循环依赖问题案例代码及解决办法》在SpringBoot中,如果两个或多个Bean之间存在循环依赖(即BeanA依赖BeanB,而BeanB又依赖BeanA),会导致Spring的... 目录1. 什么是循环依赖?2. 循环依赖的场景案例3. 解决循环依赖的常见方法方法 1:使用 @La

使用C#代码在PDF文档中添加、删除和替换图片

《使用C#代码在PDF文档中添加、删除和替换图片》在当今数字化文档处理场景中,动态操作PDF文档中的图像已成为企业级应用开发的核心需求之一,本文将介绍如何在.NET平台使用C#代码在PDF文档中添加、... 目录引言用C#添加图片到PDF文档用C#删除PDF文档中的图片用C#替换PDF文档中的图片引言在当

Java中的String.valueOf()和toString()方法区别小结

《Java中的String.valueOf()和toString()方法区别小结》字符串操作是开发者日常编程任务中不可或缺的一部分,转换为字符串是一种常见需求,其中最常见的就是String.value... 目录String.valueOf()方法方法定义方法实现使用示例使用场景toString()方法方法

Java中List的contains()方法的使用小结

《Java中List的contains()方法的使用小结》List的contains()方法用于检查列表中是否包含指定的元素,借助equals()方法进行判断,下面就来介绍Java中List的c... 目录详细展开1. 方法签名2. 工作原理3. 使用示例4. 注意事项总结结论:List 的 contain

C#使用SQLite进行大数据量高效处理的代码示例

《C#使用SQLite进行大数据量高效处理的代码示例》在软件开发中,高效处理大数据量是一个常见且具有挑战性的任务,SQLite因其零配置、嵌入式、跨平台的特性,成为许多开发者的首选数据库,本文将深入探... 目录前言准备工作数据实体核心技术批量插入:从乌龟到猎豹的蜕变分页查询:加载百万数据异步处理:拒绝界面

用js控制视频播放进度基本示例代码

《用js控制视频播放进度基本示例代码》写前端的时候,很多的时候是需要支持要网页视频播放的功能,下面这篇文章主要给大家介绍了关于用js控制视频播放进度的相关资料,文中通过代码介绍的非常详细,需要的朋友可... 目录前言html部分:JavaScript部分:注意:总结前言在javascript中控制视频播放

macOS无效Launchpad图标轻松删除的4 种实用方法

《macOS无效Launchpad图标轻松删除的4种实用方法》mac中不在appstore上下载的应用经常在删除后它的图标还残留在launchpad中,并且长按图标也不会出现删除符号,下面解决这个问... 在 MACOS 上,Launchpad(也就是「启动台」)是一个便捷的 App 启动工具。但有时候,应