完成上篇的组合逻辑电路,将要学习的是Verilog语言中的另一重要部分,时序逻辑部分电路,加入了时钟,能让电路实现更丰富的功能。(代码参考自网上)
1.R-S触发器:
基本RS触发器可以由两个与非门按正反馈方式闭合构成。通常将Q端的状态定义为锁存器的状态,即Q=1时,称为锁存器处于1的状态;Q=0时,称锁存器处于0的状态,电路具有两个稳态。电路要改变状态必须加入触发信号,因是与非门构成的基本RS触发器,所以,触发信号是低电平有效。非Rd和非Sd是一次信号,只能一个个加,即它们不能同时为低电平,因为会有逻辑矛盾(Q == 非Q)。
module rs_ff(
input wire clk,r,s, //rs触发器输入信号
output reg q, //输出端口q,在always块里赋值,定义为reg型
output wire qb //输出端口非q
);
assign qb = ~q;
always@(posedge clk)
begin
case({r,s})
2'b00: q <= q; //r,s同时为低电平,触发器保持状态不变
2'b01: q <= 1'b1; //触发器置1状态
2'b10: q <= 1'b0; //触发器置0状态
2'b11: q <= 1'bx; //r,s同时为高电平有效,逻辑矛盾,触发器为不定态
endcase
end
endmodule
`timescale 1ns/100ps //仿真时间单位/时间精度
module rs_ff_tb();
reg clk,r,s; //需要产生的激励信号定义
wire q,qb; //需要观察的输出信号定义
//初始化过程块
initial
begin
clk = 0;
r = 0;
s = 0;
#50
r = 0;
s = 1;
#50
r = 1;
s = 0;
#50
r = 1;
s = 1;
#50
r = 0;
s = 1;
end
always #10 clk = ~clk; //产生输入clk,频率50MHz
//module调用例化格式
rs_ff u1 ( //rs_ff表示所要例化的module名称,u1是我们定义的例化名称
.clk(clk), //输入输出信号连接。
.r(r),
.s(s),
.q(q), //输出信号连接
.qb(qb)
);
endmodule
2.D触发器:
从D触发器的特性我们知道,它的状态仅仅取决于时钟信号达到之前瞬间的D信号。为了防止SR锁存器的S、R被同时置1的情况,常采用维持阻塞结构的D触发器,其电路结构如下,边沿触发器的次态仅仅取决于CLK信号上升沿(或下降沿)到达时刻输入信号的状态。
module dff
( //模块名及参数定义
input clk,rst,d,
output reg q,
output wire qb
);
assign qb = ~q;
always @( posedge clk ) //只有clk上升沿时刻触发
if(!rst) //复位信号判断,低有效
q <= 1'b0; //复位有效时清零
else
q <= d; //触发时输出q值为输入d
endmodule
`timescale 1ns/100ps //仿真时间单位/时间精度
module dff_tb();
reg clk,rst,d; //需要产生的激励信号定义
wire q,qb; //需要观察的输出信号定义
//初始化过程块
initial
begin
clk = 0;
rst = 0;
d = 0;
#50
rst = 1;
end
always #10 clk = ~clk; //产生输入clk,频率50MHz
always #15 d = ~d;
//module调用例化格式
dff u1 ( //dff表示所要例化的module名称,u1是我们定义的例化名称
.clk(clk), //输入输出信号连接。
.rst(rst),
.d(d),
.q(q), //输出信号连接
.qb(qb)
);
endmodule
3.JK触发器:
带使能端RS锁存器的输入端R=S=1时,锁存器的次态不确定,这一因素限制了其应用。为了解决这个问题,根据双稳态元件两个输出端互补的特点,用Q和非Q反馈控制输入信号,并用J代替S,用K代替R,构成了J-K锁存器。
module jk_ff
( //模块名及参数定义
input clk,j,k,rst,set,
output reg q,
output wire qb
);
assign qb = ~q;
//clk上升沿以及复位和置位下降沿时触发器工作
always@(posedge clk or negedge rst or negedge set)
begin
if(!rst)
q <= 1'b0; // 异步清零
else if (!set)
q <= 1'b1; // 异步置1
else
case({j,k})
2'b00: q <= q; //保持
2'b01: q <= 0; //置0
2'b10: q <= 1; //置1
2'b11: q <= ~q; //翻转
endcase
end
endmodule
`timescale 1ns/100ps //仿真时间单位/时间精度
module jk_ff_tb();
reg clk,j,k,rst,set; //需要产生的激励信号定义
wire q,qb; //需要观察的输出信号定义
//初始化过程块
initial
begin
clk = 0;
j = 0;
k = 0;
rst = 1;
set = 1;
#50
set = 0;
#50
set = 1;
#50
rst = 0;
#50
rst = 1;
end
always #10 clk = ~clk; //产生输入clk,频率50MHz
always #20 j = ~j;
always #30 k = ~k;
//module调用例化格式
jk_ff u1 ( //jk_ff表示所要例化的module名称,u1是我们定义的例化名称
.clk(clk), //输入输出信号连接。
.j(j),
.k(k),
.rst(rst),
.set(set),
.q(q), //输出信号连接
.qb(qb)
);
endmodule
4.移位寄存器:
如果将多个触发器级联就构成一个多位的移位寄存器,如下图所示,是以4位移位寄存器为例的逻辑电路图,其中的LD/SHIFT是一个置数/移位控制信号。当LD/SHIFT为1时,在CP作用下,从输入端A、B、C、D并行接收数据;当LD/SHIFT为0时,在CP作用下,将寄存器中的数据顺序移出,空位由输入端SIN补充。这种寄存器常用来进行并行数据到串行数据的转换。
module shift7
(
input wire clk, //输入时钟
input wire rst, //复位信号
input wire [6:0] datain, //并行输入数据
output wire dataout //串行输出数据
);
reg [6:0] data;
always @(posedge clk)
if(!rst)
data <= datain; //同步复位,复位时并行数据存入变量data
else
begin
data[6] <= 1'b0; //最高为补0
data[5] <= data[6];
data[4] <= data[5];
data[3] <= data[4];
data[2] <= data[3];
data[1] <= data[2];
data[0] <= data[1]; //右移一位
end
assign dataout = data[0]; //串行输出
endmodule
`timescale 1ns/100ps //仿真时间单位/时间精度
module shift7_tb;
reg clk, rst; //需要产生的激励信号定义
reg [6:0]datain;
wire dataout; //需要观察的输出信号定义
initial
begin
clk =0;
rst =1;
datain =7'b1110101; //所需移位数据
#50
rst =0;
#100
rst =1;
end
always #20 clk =~clk; //产生时钟信号 频率25MHz
//module调用例化格式
shift7 u1 (
.clk (clk),
.rst (rst),
.datain (datain),
.dataout(dataout)
);
endmodule
5.环形计数器:
将移位寄存器的输出q0连接到触发器q3的输入,并且在这4个触发器中只有一个输出为1,另外3个为0,这样就构成了一个环形计数器。初始化复位时,给q0一个置位信号,则唯一的1将在环形计数器中循环移位,每4个时钟同期输出一个高电平脉冲。
module ring #
(
parameter CNT_SIZE = 8
)
(
input wire clk,rst, //时钟和复位输入
output reg [CNT_SIZE-1:0] cnt //计数器输出
);
always@(posedge clk)
if(!rst)
cnt <= 8'b0000_0001; //复位初值
else
cnt <= {cnt[0],cnt[CNT_SIZE-1:1]}; //右移循环计数
endmodule
`timescale 1ns/100ps //仿真时间单位/时间精度
module ring_tb;
reg clk,rst;
wire [7:0] q;
initial
begin
clk =0;
rst =0;
#20
rst =1;
end
always#10 clk =~clk;
ring u1 (
.clk (clk),
.rst (rst),
.cnt (q)
);
endmodule