组合逻辑:输出只是当前输入逻辑电平的函数(有延时),与电路的原始状态无关。当前电路输入信号任何一个发生改变,输出都将发生改变。
时序逻辑:输出不仅是当前输入电平的函数,还与目前电路的状态有关。
assign out = (controlswitch)?in:8'b0;
若controlswitch为1,则输出in信号,否则输出0。
inout[7:0] bus;//定义总线wire
assign bus = Linkbusswitch?outbuf:8'bz;
always@(posedge clk)
begin
if(!Linkbusswitch)
begin
inbuf <= bus;
end
end
后者与前者的区别在于,前者控制信号切断时,输出为0,而后者控制信号切断时,输出为高阻,与总线脱离连接,此时如果总线的另一端有驱动源,总线可以作为模块的输入信号线。
同步时序:表示状态的寄存器组只能在唯一确定的触发条件发生时刻改变。
异步时序:表示触发条件由多个控制因素组成,如一个触发器的输出连接到另一个触发器的时钟就是异步时序逻辑。
在verilog HDL设计可综合模块时,要避免异步时序,一方面许多综合器不支持异步时序,另外异步时序很难控制由组合逻辑产生的竞争冒险。
同步时序在第一个时钟的正跳沿为输入做准备,在第一个时钟正跳沿和下一个时钟正跳沿之间有足够的时间使输入稳定,在第二个时钟正跳沿,可以产生稳定的输出。同步时序有个前提:确定下一状态所使用的组合电路的延迟与时钟到各触发器的差值必须小于一个周期。这就要求:全局时钟布线时尽量使各分支时钟一致,并且采用平衡树结构,在每一级加入缓冲器,使到各个触发器时钟同步。
数据接口的同步是数字系统设计常见问题。比如前级输出延时是随机的,如何在后级完成数据同步?级联的两个模块的基本时钟是异步时钟域,如何把前级输出的数据准确传送到下一级模块?
答:双口RAM或者FIFO,在输入端口使用前级时钟写数据,在输出端口使用本级时钟读数据,并有缓冲器空和满控制信号管理数据的读写。
Mealy状态机:时序逻辑的输出不但取决于状态还取决于输入。
Moore状态机:时序逻辑的输出仅取决于状态。
三段式状态机:
状态转移图:
三段式:
时序逻辑(状态寄存器):state<=nextstate;//nextstate为激励信号,state为当前状态。
组合逻辑:
module test(
clk,
reset,
A,
k1,
k2
);
input clk,reset,A;
output reg k1,k2;
reg[3:0] state,nextstate;//define state and next state
parameter idle = 4'b0001;
parameter start = 4'b0010;
parameter stop = 4'b0100;
parameter clear = 4'b1000;
//state register
always@(posedge clk or negedge reset)
begin
if(!reset)
state <= idle;
else
state <= nextstate;
end
//generate next state
always@(state or A)
begin
case(state)
idle:
if(A)
nextstate = start;
else
nextstate = idle;
state:
if(!A)
nextstate = stop;
else
nextstate = start;
stop:
if(A)
nextstate = clear;
else
nextstate = stop;
clear:
if(!A)
nextstate = idle;
else
nextstate = clear;
default:
nextstate = idle;
endcase
end
//generate output
always@(state or A or reset)
begin
if(!reset)
k1 = 0;
else if(!A&&state == clear)
k1 = 1;
else
k1 = 0;
end
always@(state or A or reset)
begin
if(!reset)
k2 = 0;
else if(A&&state == stop)
k2 = 1;
else
k2 = 0;
end
endmodule
testbench
module testbench(
);
reg clk,reset,A;
wire k1,k2;
initial
begin
clk = 0;
A = 0;
end
//clock
always #50 clk = ~clk;
//reset
initial
begin
reset = 1;
#22 reset = 0;
#133 reset = 1;
end
//
always@(posedge clk)
begin
#30 A = {$random}%2;
#(3*50+12);
end
test my_test(.clk(clk),.reset(reset),.A(A),.k1(k1),.k2(k2));
endmodule