某同步时序电路转换表如下,请使用D触发器和必要的逻辑门实现此同步时序电路,用Verilog语言描述。
电路的接口如下图所示。
input A ,
input clk ,
input rst_n
output wire Y
本题要求根据时序电路的状态表实现同步时序电路,要求使用D触发器。
基础的时序电路设计,可采用列激励方程、输出方程,进而用D触发器和组合逻辑电路实现的方案。
由状态表可得出,电路共4个状态,所以使用2个寄存器来实现状态的寄存。两个寄存器的输出为Q1和Q0。
由状态转换表可列出激励方程如下:
Q_1^{n+1}=D1=Q_1^n ⊕Q_0^n·~A+Q_1^n⊙Q_0^n·A=Q_1^n ⊕Q_0^n⊕AQ1n+1=D1=Q1n⊕Q0n⋅ A+Q1n⊙Q0n⋅A=Q1n⊕Q0n⊕A
Q_0^{n+1}=D0=~Q_0^nQ0n+1=D0= Q0n
输出方程如下:
Y=Q_1 ·Q_0Y=Q1⋅Q0
表中的Qn表示现态,Qn+1表示次态
根据激励方程和输出方程以及思路整理,关键电路如下:
将电路转换成Verilog代码描述如下:
`timescale 1ns/1ns
module seq_circuit(
input A ,
input clk ,
input rst_n,
output wire Y
);
reg Q1 ;
reg Q0 ;
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
Q1 <= 1'b0;
else
Q1 <= Q1 ^ Q0 ^A;
end
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
Q0 <= 1'b0;
else
Q0 <= ~Q0;
end
assign Y = Q1 & Q0;
endmodule
答案2
先拆分状态,有四个状态
利用两段式状态机
`timescale 1ns/1ns
module seq_circuit(
input A ,
input clk ,
input rst_n,
output wire Y
);
parameter IDLE = 2'b00 ;
parameter S1 = 2'b01 ;
parameter S2 = 2'b10 ;
parameter S3 = 2'b11 ;
reg [1:0] CS ;
reg [1:0] NS ;
always@(posedge clk or negedge rst_n) begin
if(!rst_n) begin
CS <= IDLE ;
end
else
CS <= NS ;
end
always@(* ) begin
case(CS)
IDLE: begin
if(A==0) begin
NS <= S1 ;
end
else begin
NS <= S3 ;
end
end
S1: begin
if(A==0) begin
NS <= S2 ;
end
else begin
NS <= IDLE ;
end
end
S2: begin
if(A==0) begin
NS <= S3 ;
end
else begin
NS <= S1 ;
end
end
S3: begin
if(A==0) begin
NS <= IDLE ;
end
else begin
NS <= S2 ;
end
end
endcase
end
assign Y=(CS==S3)?1:0;
endmodule
描述
某同步时序电路的状态转换图如下,→上表示“C/Y”,圆圈内为现态,→指向次态。
请使用D触发器和必要的逻辑门实现此同步时序电路,用Verilog语言描述。
电路的接口如下图所示,C是单bit数据输入端。
input C ,
input clk ,
input rst_n
output wire Y
本题要求根据题目提供的状态转换图实现同步时序电路,要求使用D触发器。
本题提供的是状态转换图,可采用状态机实现,也可采用列激励方程、输出方程,进而用D触发器和组合逻辑电路实现。本题解采用第二种方案实现。
由状态转换图可得出,电路共4个状态,所以使用2个寄存器来实现状态的寄存。两个寄存器的输出为Q1和Q0,两个寄存器的输入为D1和D0。可列出状态转换表如下:
由状态转换表可列出激励方程如下:
Q_1^{n+1}=D1=Q_1^n ·Q_0^n+Q_1^n·\bar{Q_0^n}·C+~\bar{Q_1^n}·Q_0^n·\bar{C}Q1n+1=D1=Q1n⋅Q0n+Q1n⋅Q0nˉ⋅C+ Q1nˉ⋅Q0n⋅Cˉ
Q_0^{n+1}=D0=\bar{Q_1^n} ·Q_0^n+\bar{Q_1^n}·\bar{Q_0^n}·C+Q_1^n·Q_0^n·\bar{C}Q0n+1=D0=Q1nˉ⋅Q0n+Q1nˉ⋅Q0nˉ⋅C+Q1n⋅Q0n⋅Cˉ
输出方程如下:
Y=C·Q_1+Q_1 ·Q_0Y=C⋅Q1+Q1⋅Q0
根据激励方程和输出方程以及思路整理,关键电路如下:
将电路转换成Verilog代码描述如下:
reg Q1 ;
reg Q0 ;
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
Q1 <= 1'b0;
else
Q1 <= (Q1 & (Q0 | C)) | (~Q1 & Q0 & ~C);
end
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
Q0 <= 1'b0;
else
Q0 <= (~Q1 & (Q0 | C)) | (Q1 & Q0 & ~C);
end
assign Y = (C & Q1) | (Q1 & Q0);
三段式FSM
`timescale 1ns/1ns
module seq_circuit(
input C ,
input clk ,
input rst_n,
output wire Y
);
reg [1:0] state, next_state;
// state transition
always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin
state <= 2'b00;
end
else begin
state <= next_state;
end
end
// next_state logic
always @ (*) begin
next_state = 2'b00;
case (state)
2'b00: next_state = C ? 2'b01 : 2'b00;
2'b01: next_state = C ? 2'b01 : 2'b11;
2'b10: next_state = C ? 2'b10 : 2'b00;
2'b11: next_state = C ? 2'b10 : 2'b11;
default: next_state = state;
endcase
end
// output logic
assign Y = (next_state == 2'b10) | (state == 2'b11);
endmodule
实现一个深度为8,位宽为4bit的ROM,数据初始化为0,2,4,6,8,10,12,14。可以通过输入地址addr,输出相应的数据data。
接口信号图如下:
clk:系统时钟
rst_n:异步复位信号,低电平有效
addr:8bit位宽的无符号数,输入到ROM的地址
data:4bit位宽的无符号数,从ROM中读出的数据
要实现ROM,首先要声明数据的存储空间,例如:[3:0] rom [7:0];变量名称rom之前的[3:0]表示每个数据具有多少位,指位宽;变量名称rom之后的[7:0]表示需要多少个数据,指深度,注意这里深度为8,应该是使用[7:0],而不是[2:0];
声明存储变量之后,需要对rom进行初始化,写入数据,然后将输入地址作为rom的索引值,将索引值对应的数据输出。
可以按照如下的方式开辟存储空间,并进行数据初始化:
reg [3:0] rom_data [7:0];
//保持ROM中的数据不变
always @(posedge clk or negedge rst_n)
if (!rst_n) //对ROM中的数据进行初始化
begin
rom_data[0] <= 4'd0;
rom_data[1] <= 4'd2;
rom_data[2] <= 4'd4;
rom_data[3] <= 4'd6;
rom_data[4] <= 4'd8;
rom_data[5] <= 4'd10;
rom_data[6] <= 4'd12;
rom_data[7] <= 4'd14;
end
else
begin //保持ROM中的数据不变
rom_data[0] <= 4'd0;
rom_data[1] <= 4'd2;
rom_data[2] <= 4'd4;
rom_data[3] <= 4'd6;
rom_data[4] <= 4'd8;
rom_data[5] <= 4'd10;
rom_data[6] <= 4'd12;
rom_data[7] <= 4'd14;
end
初始化完成之后的rom的形式如下,内部存在地址和数据的对应关系,通过输入相应的地址,可以得到相应的输出数据。
always @(posedge clk or negedge rst_n)
if (!rst_n)
data <= 4'd0;
else
data <= rom_data[addr];
只需要将地址作为rom的索引,即可得到相应的数据
`timescale 1ns/1ns
module rom(
input clk,
input rst_n,
input [7:0]addr,
output [3:0]data
);
reg [3:0] rom_data [7:0];
assign data = rom_data[addr];
//保持ROM中的数据不变
always @(posedge clk or negedge rst_n)
if (!rst_n)
begin
rom_data[0] <= 4'd0;
rom_data[1] <= 4'd2;
rom_data[2] <= 4'd4;
rom_data[3] <= 4'd6;
rom_data[4] <= 4'd8;
rom_data[5] <= 4'd10;
rom_data[6] <= 4'd12;
rom_data[7] <= 4'd14;
end
else
begin
rom_data[0] <= rom_data[0];
rom_data[1] <= rom_data[1];
rom_data[2] <= rom_data[2];
rom_data[3] <= rom_data[3];
rom_data[4] <= rom_data[4];
rom_data[5] <= rom_data[5];
rom_data[6] <= rom_data[6];
rom_data[7] <= rom_data[7];
end
endmodule
有一个缓慢变化的1bit信号a,编写一个程序检测a信号的上升沿给出指示信号rise,当a信号出现下降沿时给出指示信号down。
注:rise,down应为单脉冲信号,在相应边沿出现时的下一个时钟为高,之后恢复到0,一直到再一次出现相应的边沿。
clk:系统时钟信号
rst_n:异步复位信号,低电平有效
a:单比特信号,作为待检测的信号
rise:单比特信号,当输入信号a出现上升沿时为1,其余时刻为0
down:单比特信号,当输入信号a出现下降沿时为1,其余时刻为0
题目要求检测输入信号a的边沿,即当a信号的值从0跳变到1,视为出现上升沿,把指示信号rise拉高;当a信号的值从1跳变到0,视为出现下降沿,把指示信号down拉高。其余时刻两个指示信号因保持0。
检测信号a的边沿需要缓存信号前一时刻的值,例如记为a_tem。当前一时刻为0,这一时刻为1,说明信号出现上升沿,即 a&&!a_tem = 1; 当前一时刻为1,这一时刻为0,说明信号出现上升沿,即 !a&&a_tem = 1;
输入信号:
系统时钟,复位信号:clk,rst_n;
待检测边沿的信号:a;
输出信号:
上升沿指示信号:rise
下降沿指示信号:down
缓存a的数值
always @(posedge clk or negedge rst_n)
if (!rst_n)
a_tem <= 1'b0;
else
a_tem <= a;
分别使用a&&!a_tem和!a&&a_tem作为判断条件,判断是否出现上升沿或者下降沿。
//检测边沿,给出相应的信号
always @(posedge clk or negedge rst_n)
if (!rst_n)
begin
rise <= 1'b0;
down <= 1'b0;
end
else if (!a_tem && a) //当前一时刻a=0,当前时刻a=1,表示a出现一次上升沿
begin
rise <= 1'b1;
down <= 1'b0;
end
else if (a_tem && !a)//当前一时刻a=1,当前时刻a=0,表示a出现一次下降沿
begin
down <= 1'b1;
rise <= 1'b0;
end
else
begin
down <= 1'b0;
rise <= 1'b0;
end
`timescale 1ns/1ns
module edge_detect(
input clk,
input rst_n,
input a,
output reg rise,
output reg down
);
reg a_tem;
//缓存a的数值
always @(posedge clk or negedge rst_n)
if (!rst_n)
a_tem <= 1'b0;
else
a_tem <= a;
//检测边沿,给出相应的信号
always @(posedge clk or negedge rst_n)
if (!rst_n)
begin
rise <= 1'b0;
down <= 1'b0;
end
else if (!a_tem && a) //当前一时刻a=0,当前时刻a=1,表示a出现一次上升沿
begin
rise <= 1'b1;
down <= 1'b0;
end
else if (a_tem && !a) //当前一时刻a=1,当前时刻a=0,表示a出现一次下降沿
begin
down <= 1'b1;
rise <= 1'b0;
end
else
begin
down <= 1'b0;
rise <= 1'b0;
end
endmodule