刚学前端设计的时候,听到的就是组合逻辑、时序逻辑,很重要!但是究竟有什么用?到底怎么体现,没有多少老师可以明确指出来,当自己看的东西多了,就可以理解了,甚至可以得出自己的范式。
到目前为止,要想掌握组合逻辑,就请先掌握本文列出的计数器、触发器、锁存器、寄存器分频器等简单的组合逻辑电路。
包括RS触发器、JK触发器、D触发器、T触发器。
锁存器的功能同触发器类似,但也有本质区别:触发器是在有效时钟沿到来时才发生作用,而锁存器是电平敏感的,只要时钟信号有效,锁存器就会起作用
module latch1(
clk,
d,
q
);
input clk,d;
output q;
assign q = clk?d:q;
endmodule
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
推荐阅读FPGA应该掌握的小笔记中涉及到的寄存器知识点。
推荐阅读:异步复位清零的一些常识
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
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
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
当一个时序电路的输入由另一个时钟驱动的电路产生或来自一个外部异步电路时,需要用同步器将输入数据与需要的时钟同步。即常用在跨时钟处理!
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
`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
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
`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