Verilog99题——22-30题(时序逻辑基础)
前言
不忘出芯veriloig99题的22-30题是时序逻辑基础相关。
22. 画一个D触发器的电路图。
23. 说明D触发器与Latch的区别。
都是时序逻辑,输出不但同当前的输入相关还同上一状态的输出相关。
1、latch由电平触发,非同步控制。在使能信号有效时latch相当于通路,在使能信号无效时latch保持输出状态。DFF由时钟沿触发,同步控制。
2、latch容易产生毛刺(glitch),DFF则不易产生毛刺。
3、如果使用门电路来搭建latch和DFF,则latch消耗的门资源比DFF要少,这是latch比DFF优越的地方。所以,在ASIC中使用 latch的集成度比DFF高,但在FPGA中正好相反,因为FPGA中没有标准的latch单元,但有DFF单元,一个LATCH需要多个LE才能实现。
4、latch将静态时序分析变得极为复杂。
上图所示为D锁存器和D触发器输出端随输入信号变化的波形图( Waveform diagram)。由图中可见,输入信号D在ta时刻以前,D锁存器和D触发器输出端随输入信号变化的波形相同;在t时刻,CP=1期间D发生了变化,D锁存器的输出随着输入信号的变化而变化,D触发器则是在下一个时钟到来后输出状态才发生改变。这是由于触发器不具有传输透明性(Transparency),即触发器输入端发生变化并不会同步引起其输出端发生变化。触发器输出端的变化仅受控制输入(时钟)信号或异步置位复位信号的控制。在通常情况下,除了输入信号在CP=1期间发生变化以外,锁存器和触发器的输出响应是相同的。
24. 解释一下D触发器的建立时间与保持时间。
建立时间(setup time) 是指在触发器的时钟信号上升沿到来以前,数据稳定不变的最小时间,如果建立时间不够,数据将不能在这个时钟上升沿被打入触发器;
保持时间(hold time) 是指在触发器的时钟信号上升沿到来以后,数据稳定不变的最小时间,如果保持时间不够,数据同样不能被打入触发器。
25. 解释一下Latch的建立时间与保持时间。
建立时间(Setup time)tsu:锁存器输入信号D到来时刻到输入信号达到稳定所持续的时间。
保持时间(Hold time)th:输入信号D达到稳定时刻至输入信号被锁存器接受所持续的时间。
控制脉冲宽度(Control pulse width)tw:控制时钟(使能)脉冲C1,处于激活状态时的持续时间。
其中,建立时间必须确保数据输入端的任何变化在控制输入信号到来以前能够准确地传送到输入电路:保持时间和控制脉冲宽度必须保证输入信号在产生新状态以前读入当前数据。
传输延迟时间(Propagation delay):是输入信号的时序变化对输出信号的时序影响,定义为从输入信号(D或C)变化时开始,到输出端(Q或QN)出现相应的输出响应所持续的时间。传输延迟时间通常描述为输入端信号发生变化,引起输出端电平从高到低变化时的传输延迟时间tpHL和输出端电平从低到高变化时的传输延迟时间tpLH。
26. 用verilog实现1bit信号边沿检测功能,输出一个周期宽度的脉冲信号。
- 上升沿
- 下降沿
- 上升沿或者下降沿
input clk, rst_n, data;
output data_edge;
Verilog描述
module test26(
input clk, rst_n, data,
output rise_edge, //上升沿
output fall_edge, //下降沿
output data_edge //边沿
);
reg data_r,data_rr;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
data_r <= 1'b0;
data_rr <= 1'b0;
end else begin
data_r <= data;
data_rr <= data_r;
end
end
assign rise_edge = ( ~data_rr && data_r ) ? 1'b1 : 1'b0 ;
assign fall_edge = ( data_rr && ~data_r ) ? 1'b1 : 1'b0 ;
assign data_edge = ( data_rr^data_r ) ? 1'b1 : 1'b0 ;
endmodule
仿真图
27. 用verilog实现一个4bit二进制计数器。
- 异步复位
- 同步复位
input clk, rst_n;
output [3:0] o_cnt;
module test27(
input clk, rst_n,
output [3:0] o_cnt
);
reg [3:0] cnt;
//异步复位
/* always @ (posedge clk or negedge rst_n) begin
if ( !rst_n )
cnt <= 4'b0000;
else if ( cnt == 4'b1111 )
cnt <= 4'b0000;
else
cnt <= cnt + 1'b1;
end */
//同步复位
always @ (posedge clk) begin
if ( !rst_n )
cnt <= 4'b0000;
else if ( cnt == 4'b1111 )
cnt <= 4'b0000;
else
cnt <= cnt + 1'b1;
end
assign o_cnt = cnt;
endmodule
28. 用verilog实现串并转换。
- lsb优先
- msb优先
input clk, rst_n, data_i;
output [7:0] data_o;
Verilog描述
module test28(
input clk, rst_n, data_i,
output [7:0] data_o
);
reg [7:0] data_r;
reg [2:0] cnt;
//lsb
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
data_r <= 8'd0;
cnt <= 3'b0;
end else begin
data_r <= {data_r[6:0],data_i};
cnt <= cnt + 1'b1;
end
end
//msb
/* always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
data_r <= 8'd0;
cnt <= 3'b0;
end else begin
data_r <= {data_i,data_r[7:1]};
cnt <= cnt + 1'b1;
end
end */
assign data_o = (cnt == 3'd0) ? data_r : data_o;
endmodule
testbench
module tb28( );
reg clk, rst_n, data_i;
wire [7:0] data_o;
initial begin
clk = 1;
forever #10 clk = ~clk;
end
initial begin
rst_n = 1'b0;
#22 rst_n = 1'b1;
end
initial begin
repeat(100)begin
@(negedge clk)
data_i = {$random};
end
$finish;
end
initial begin
$dumpfile("tb28.vcd");
$dumpvars();
end
test28 test28(
.clk ( clk ),
.rst_n ( rst_n ),
.data_i ( data_i ),
.data_o ( data_o )
);
endmodule
仿真图
lsb优先:
msb优先:
上下两幅图结果正好相反,进一步验证了正确性。
29. 序列检测器:有“101”序列输入时输出为1,其他输入情况下,输出为0。画出状态转移图,并用verilog描述。
input clk, rst_n, data;
output flag_101;
状态转移图
verilog描述
module test29(
input clk, rst_n, data,
output reg flag_101
);
parameter ST0 = 4'b0001,
ST1 = 4'b0010,
ST2 = 4'b0100,
ST3 = 4'b1000;
reg [3:0] c_st;
reg [3:0] n_st;
//FSM-1
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
c_st <= ST0;
end else begin
c_st <= n_st;
end
end
//FSM-2
always @(*) begin
case (c_st)
ST0: n_st = data ? ST1 : ST0;
ST1: n_st = data ? ST1 : ST2;
ST2: n_st = data ? ST3 : ST0;
ST3: n_st = data ? ST1 : ST2;
default: n_st = ST0;
endcase
end
//FSM-3
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
flag_101 <= 1'b0;
end else begin
case (n_st)
ST3: flag_101 <= 1'b1;
ST0,ST1,ST2: flag_101 <= 1'b0;
default: flag_101 <= 1'b0;
endcase
end
end
endmodule
testbench
module tb29( );
reg clk, rst_n, data;
wire flag_101;
initial begin
clk = 0;
forever #10 clk = ~clk;
end
initial begin
rst_n = 1'b0;
#22 rst_n = 1'b1;
end
initial begin
repeat(100)begin
@(negedge clk)
data = {$random};
end
$finish;
end
/* initial begin
$dumpfile("seq101_tb.vcd");
$dumpvars();
end */
test29 test29(
.clk (clk ),
.rst_n (rst_n ),
.data (data ),
.flag_101 (flag_101)
);
endmodule
仿真结果
30. 用verilog实现两路数据的乘法运算,要求只使用1个乘法器。
input clk, rst_n;
input sel_x;
input [7:0] da_x_y;
input [7:0] db_x_y;
output reg [15:0] dout_x_y;
verilog描述
module test30(
input clk ,
input rst_n ,
input sel_x ,
input [ 7:0] da_x ,
input [ 7:0] da_y ,
input [ 7:0] db_x ,
input [ 7:0] db_y ,
output reg [15:0] dout_x_y
);
wire [ 7:0] da;
wire [ 7:0] db;
wire [15:0] dout;
assign da = sel_x ? da_x : da_y;
assign db = sel_x ? db_y : db_x;
assign dout = da * db ;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
dout_x_y <= 16'd0;
end else begin
dout_x_y <= dout;
end
end
endmodule
即将入行的数字IC设计工程师