前言
刚学前端设计的时候,听到的就是组合逻辑、时序逻辑,很重要!但是究竟有什么用?到底怎么体现,没有多少老师可以明确指出来,当自己看的东西多了,就可以理解了,甚至可以得出自己的范式。
到目前为止,要想掌握组合逻辑,就请先掌握本文列出的计数器、触发器、锁存器、寄存器分频器等简单的组合逻辑电路。
1.触发器
包括RS触发器、JK触发器、D触发器、T触发器。
2.锁存器和寄存器
锁存器的功能同触发器类似,但也有本质区别:触发器是在有效时钟沿到来时才发生作用,而锁存器是电平敏感的,只要时钟信号有效,锁存器就会起作用
2.1锁存器
2.1.1电平敏感的1位数据锁存器
module latch1(
clk,
d,
q
);
input clk,d;
output q;
assign q = clk?d:q;
endmodule
综合的电路图如下:
2.1.2带有置位功能和复位功能的电平敏感的1位数据锁存器
module latch2(
clk,load,reset,d,q
);
input clk,load,reset,d;
output q;
assign q = reset?1'b0:(load?1'b1:(clk?d:q));
endmodule
综合得到的电路图如下:
2.2 寄存器
推荐阅读FPGA应该掌握的小笔记中涉及到的寄存器知识点。
带有清零功能的8位数据寄存器reg_8.v
module reg_8(
out,
in,
clk,
clr
);
output [7:0] out;
input [7:0] in;
input clk;
input clr;
reg [7:0] out;
always@(posedge clk or posedge clr)
if(clr) out <= 0;
else out <= in;
endmodule
综合得到的电路图如下:
3.移位寄存器
3.1 8位左移移位寄存器shiftleft_reg.v
module shiftleft_reg(clk,rst,l_in,s,q);
input clk,rst,l_in,s;
output [7:0] q;
reg [7:0] q;
always@(posedge clk)
begin
if(rst)
q <= 8'b0;
else if(s)
q <= {q[6:0],l_in};
else
q <= q;
end
endmodule
3.2 8位右移移位寄存器
module shiftright_reg(clk,rst,r_in,s,q);
input clk,rst,r_in,s;
output [7:0] q;
reg [7:0] q;
always@(posedge clk)
begin
if(rst)
q <= 8'b0;
else if(s)
q <= {r_in,q[7:1]};
else
q <= q;
end
endmodule
4.分频器
5.计数器
6.其他时序逻辑电路
6.1同步器
当一个时序电路的输入由另一个时钟驱动的电路产生或来自一个外部异步电路时,需要用同步器将输入数据与需要的时钟同步。即常用在跨时钟处理!
简单同步器设计代码Synchronizer.v
module Synchronizer(
clk,
data,
syn
);
input clk;
input data;
output syn;
reg syn;
always@(posedge clk)
if(data == 0)
syn <= 0;
else
syn <=1;
endmodule
仿真文件Synchronizer_tb.v
`timescale 1ns/1ns
`define clk_period 20
module Synchronizer_tb;
reg clk;
reg data;
wire syn;
Synchronizer Synchronizer_inst(
clk,
data,
syn
);
initial clk = 1;
always #(`clk_period/2) clk = ~clk;
initial begin
data = 1'b0;
#(`clk_period*2+5);
data = 1'b1;
#(`clk_period*2);
data = 1'b0;
#(`clk_period*2+6);
data = 1'b1;
#8;
data = 1'b0;
#16;
data = 1'b1;
#(`clk_period);
data = 1'b0;
#(`clk_period*2);
$stop;
end
endmodule
功能仿真
6.2边沿检测电路
设计代码edge_detect.v
module edge_detect(
clk ,
rst_n ,
data ,
raising_edge ,
faling_edge ,
double_edge
);
input clk ;
input rst_n ;
input data ;
output raising_edge ;
output faling_edge ;
output double_edge ;
reg data_reg0,data_reg1;
always@(posedge clk or negedge rst_n)
if(!rst_n)begin
data_reg0 <= 1'b0;
data_reg1 <= 1'b0;
end
else begin
data_reg0 <= data;
data_reg1 <= data_reg0;
end
assign raising_edge = ~data_reg1 && data_reg0;
assign faling_edge = data_reg1 && ~data_reg0;
assign double_edge = data_reg1 ^ data_reg0;
endmodule
仿真文件edge_detect_tb.v
`timescale 1ns/1ns
`define clk_period 20
module edge_detect_tb;
reg clk ;
reg rst_n ;
reg data ;
wire raising_edge ;
wire faling_edge ;
wire double_edge ;
edge_detect edge_detect_inst(
.clk (clk ),
.rst_n (rst_n ),
.data (data ),
.raising_edge (raising_edge ),
.faling_edge (faling_edge ),
.double_edge (double_edge )
);
initial clk = 1;
always #(`clk_period/2) clk = ~clk;
initial begin
rst_n = 1'b0;
#(`clk_period);
rst_n = 1'b1;
end
initial begin
data = 1'b0;
#(`clk_period+10);
data = 1'b1;
#(`clk_period*3);
data = 1'b0;
#(`clk_period-5);
data = 1'b1;
#(`clk_period*2);
data = 1'b0;
#(`clk_period*3);
$stop;
end
endmodule