数字IC经典电路设计
经典电路设计是数字IC设计里基础中的基础,盖大房子的第一部是打造结实可靠的地基,每一篇笔者都会分门别类给出设计原理、设计方法、verilog代码、Testbench、仿真波形。然而实际的数字IC设计过程中考虑的问题远多于此,通过本系列希望大家对数字IC中一些经典电路的设计有初步入门了解。能力有限,纰漏难免,欢迎大家交流指正。快速导航链接如下:
一、前言
序列发生器是一种基于数字电路中逻辑门、触发器等组件设计的模块化电路,可以按照特定的顺序生成一系列数字信号或数据。
为什么需要设计序列发生器呢?
在数字IC设计中,序列发生器通常被用于产生特定的数字序列,以用于测试和验证数字电路的正确性。序列发生器通常被用于产生随机或伪随机数字序列,以模拟实际的操作环境,并测试数字电路的各种情况下的响应。
序列发生器通常用于测试数字电路中的寄存器、计数器、状态机等模块。例如,在设计一个计数器时,需要验证计数器是否可以正确地计数,并且在达到最大计数值时是否能够正确地回滚到初始值。为了验证这些功能,需要使用一个序列发生器来产生一系列的计数值,并将这些值输入到计数器中进行测试。因此,序列发生器在数字IC设计中是一个非常重要的工具,它可以帮助设计师验证数字电路的正确性,并提高数字电路的可靠性和性能。
序列发生器有哪些发生模式呢?
以下是一些常见的序列发生器模式:
简单发生器:按照固定的顺序依次输出数字序列。 密码型发生器:根据特定的编码方式,产生符合要求的数字序列,如曼彻斯特编码、差分曼彻斯特编码等。 伪随机序列发生器:产生看似随机的数字序列,但实际上是按照特定的算法生成的,用于加密和通信等领域。
序列发生器的设计思路同序列检测器相似,常用简单序列发生器设计有如下三种设计思路:(1)状态机法;(2)移位寄存器法;(3)计数器法。
要求:使用状态机设计一个序列发生器,可循环生成序列“1001”,要求序列不重叠。
此处设计思路与序列检测器相似,且更为简单, 参考序列检测器2.1状态机部分。以生成“1001”序列为例,借用万能的状态机,设计四个状态并且依次发生状态转移,通过判断当前的状态从而输出一位对应的数字,四个状态分别对应序列“1001”的四位数字。因为有限状态机的工作原理,序列“1001”将会被逐位循环输出。
//使用状态机设计发生“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) begin
if(!rst_n) begin
curr_state <= IDLE;
end
else begin
curr_state <= next_state;
end
end
//第二段使用组合逻辑判断状态转移条件
always@(*) begin
if(!rst_n) begin
next_state <= IDLE;
end
else begin
case(curr_state)
IDLE :next_state = S1;
S1 :next_state = S2;
S2 :next_state = S3;
S3 :next_state = IDLE;
default:next_state = IDLE; //养成良好代码风格,不能遗漏,防生成latch,也可以通过赋初值避免
endcase
end
end
//第三段使用时序逻辑描述状态输出
//通过判断状态机的状态来判断当前的输出值,达到输出序列“1001”目的
always@(posedge clk or negedge rst_n) begin
if(!rst_n) begin
seq_out <= 1'b0;
end
else begin
case(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;
endcase
end
end
endmodule
`timescale 1ns/1ps //仿真时间单位1ns 仿真时间精度1ps
module sequence_gnerator01_tb();
//信号申明
reg clk;
reg rst_n;
wire seq_out;
//生成复位信号
//为时钟信号和复位信号赋初值
initial begin
clk = 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
要求:使用移位寄存器设计一个序列发生器,可循环生成序列“1001”,要求序列不重叠。
此处设计思路与序列检测器相似,且更为简单, 参考序列检测器2.2移位寄存器部分。设置一个和序列等长的寄存器,且初始数值为“1001”。处于时钟上升沿时完成两步操作:首先,输出当前寄存器的缓存数据的最高位;其次是,将数据的最高位转移到数据的最低位,拼接成新的数据重新缓存到寄存器中。因为移位寄存器的工作原理,缓存在移位寄存器中的序列“1001”将会被逐位循环输出。
//使用移位寄存器设计发生“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)
end
else 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;
end
else begin
seq_out <= seq[3]; //每个时钟上升沿输出最高位
end
end
endmodule
`timescale 1ns/1ps //仿真时间单位1ns 仿真时间精度1ps
module sequence_gnerator02_tb();
//信号申明
reg clk;
reg rst_n;
wire seq_out;
//复位信号生成
//时钟信号与复位信号赋初值
initial begin
clk = 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
要求:使用计数器设计一个序列发生器,可循环生成序列“1001”,要求序列不重叠。
在此处借用计数器设计序列发生器思路同借用状态机设计序列发生器异曲同工,此处的计数器可以理解为“小状态机”,在2.1中状态机状态的转移相当于此处计数器的不断累加。通过判断当前计数器数值从而输出一位对应的数字,四个状态分别对应序列“1001”的四位数字。因为计数器的工作原理,序列“1001”将会被逐位循环输出。
//使用计数器设计发生“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;
end
else if(cnt == 2'b11) begin
cnt <= 2'b00;
end
else begin
cnt <= cnt + 1'b1;
end
end
//根据计数器的计数逐次输出“1001”
always@(posedge clk or negedge rst_n) begin
if(!rst_n) begin
seq_out <= 1'b0;
end
else 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;
endcase
end
end
endmodule
`timescale 1ns/1ps //仿真时间单位1ns 仿真时间精度1ps
module sequence_gnerator03_tb();
//信号申明
reg clk;
reg rst_n;
wire seq_out;
//生成复位信号
//为时钟信号和复位信号赋初值
initial begin
clk = 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
在上一篇序列检测器文章中,我们提到了关于序列检测的四种模式—重叠模式、非重叠模式、连续模式、间隔模式,在序列发生器这里同样存在重叠序列发生模式和非重叠序列发生模式。这里之所以会单独领出来讲,是因为不同的发生模式会对设计出来的电路面积存在影响,尤其以移位寄存器法设计的序列发生器触发器的数量截然不同。以下以寄存器法设计为例来阐述两种模式的差异。
要求:使用移位寄存器设计一个序列发生器,可循环生成序列“1001”,有两个输出,一个要求序列不重叠,一个要求序列重叠。
//使用移位寄存器设计发生“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)
end
else 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;
end
else 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;
end
else 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;
end
else begin
seq_out_2 <= seq_2[2]; //每个时钟上升沿输出最高位
end
end
endmodule
`timescale 1ns/1ps //仿真时间单位1ns 仿真时间精度1ps
module sequence_gnerator04_tb();
//信号申明
reg clk;
reg rst_n;
wire seq_out_1;
wire seq_out_2;
//复位信号生成
//时钟信号与复位信号赋初值
initial begin
clk = 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
要求:设计一个简单序列发生器,可随机产生序列,随机序列无额外特定要求。
这个随机序列发生器可使用一个8位的“种子”来生成随机数。在每个时钟周期上升沿时,它使用当前种子值来生成一个新的种子值,并将其用作下一个时钟周期的种子。它还将当前种子值作为输出随机数。
这个随机序列发生器使用了一个简单的XOR Shift算法来生成新的种子值。这个算法通过将当前种子值向左右移位,并将结果与原始种子值进行异或来生成新的种子值。这个算法在实现上比较简单,并且可以生成高质量的随机数序列。
//使用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) begin
if(!rst_n) begin
seed <= 8'b1; // 初始化种子
end
else begin
seed <= seed ^ (seed >> 2) ^ (seed << 3) ; // 生成新种子
end
end
always@(posedge clk or posedge rst_n) begin
if(!rst_n) begin
seq_out <= 8'b0; // 初始化随机数
end
else begin
seq_out <= seed; // 生成新随机数
end
end
endmodule
`timescale 1ns/1ps //仿真时间单位1ns 仿真时间精度1ps
module sequence_gnerator05_tb();
//信号申明
reg clk;
reg rst_n;
wire seq_out;
//复位信号生成
//时钟信号与复位信号赋初值
initial begin
clk = 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
序列发生器设计方法:常见的固定序列发生器有三种设计思路,分别是状态机法、移位寄存器法、计数器法。在设计的时候虽然都可以使用,但往往在考虑电路的面积后会采取最优的方法。设计时尽量使的电路面积最小,必须考虑采用哪种方法借用的触发器数量最少! 序列重叠发生与非重叠发生:以本篇序列发生器产生无重叠序列“1001”而言: ①若是采用状态机且采用独热码编译状态则需要四个触发器,采用格雷码编译状态只需两个触发器;若是采用移位寄存器,则需要两个触发器;若是采用计数器,则需要两个触发器; ②假设本篇序列发生器产生可重叠序列“1101011”,那么触发器的数目会与无重叠序列发生器一致吗?答案是不一样的!这里变成重叠序列,也就是产生的序列可以是110101101011...,这个序列中有两个1101011,二者共用11,因此以移位寄存器法产生这样的序列只需要一个5位的移位寄存器,而不可重叠序列需要7个。 总的来说,在对序列无特殊要求情况下,若是想减少触发器的数目,可使用状态机格雷码编译状态,且产生的序列是可重叠的。 伪随机序列发生器:除了固定序列的序列发生器,还存在随机序列发生器,这种随机序列发生器有很多种,可根据实际情况采用不同的算法设计出对应的伪随机序列发生器。本篇主要介绍的是最简单的伪随机序列发生器,主要通过 XOR Shift算法实现。undefined
***
以下为补充的几个问题:
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
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。