本题是一组系列题(5题)的最后一题,从移位器、计数器、序列检测器、状态机到最后多功能Timer设计,前面的题目比较简单,所以这一系列的题目就只放最后一题。
创建一个计时器:①当检测到特定模式(1101)时启动;②再移4位以确定延迟时间;③等待计数器完成计数,然后通知用户并等待用户确认计时器。
当接收到模式1101时,状态机必须在4个时钟周期内断言输出shift_ena。此后,状态机声明其计数输出以指示其正在等待计数器,并等待直到输入done_counting为高。
串行数据在数据输入引脚上可用。当接收到模式1101时,电路必须随后移入接下来的4位,即最高有效位在前。这4位确定定时器延迟的持续时间。将其称为delay [3:0]。
此后,状态机声明其计数输出以指示其正在计数。状态机必须精确计数(delay [3:0] + 1)* 1000个时钟周期。例如,delay = 0表示计数1000个周期,而delay = 5表示计数6000个周期。同时输出当前剩余时间。这应该等于1000个周期的延迟,然后等于1000个周期的delay-1,依此类推,直到1000个周期为0。当电路不计数时,count [3:0]输出无关紧要。
此时,电路必须断言完成,以通知用户计时器已超时,并等待直到输入ack为1才复位,以查找下一次出现的启动序列(1101)。电路应重置为开始搜索输入序列1101的状态。
这是预期输入和输出的示例。“ x”状态可能会使阅读有些混乱,它们表明FSM在该周期中不应关心该特定输入信号。例如,一旦读取了1101和delay [3:0],电路将不再查看数据输入,直到在完成所有其他操作后恢复搜索为止。在此示例中,电路的计数为2000个时钟周期,因为delay [3:0]值为4'b0001。最后几个周期以delay [3:0] = 4'b1110开始另一个计数,该计数将计数15000个周期。
module top_module ( input clk, input reset, // Synchronous reset input data, output [3:0] count, output counting, output done, input ack );
根据题目的要求,先列出状态转移图,然后就可以进行设计了。
module top_module (
input clk,
input reset, // Synchronous reset
input data,
output [3:0] count,
output counting,
output done,
input ack );
parameter IDLE = 0, S1 = 1, S2 = 2, S3 = 3, B0 = 4, B1 = 5, B2 = 6, B3 = 7, COUNT = 8, WAIT = 9;
reg[3:0] state, next_state;
reg[3:0] shift;
reg[13:0] counter;
wire done_counting;
wire shift_ena;
assign shift_ena = (state == B0 || state == B1 || state == B2 || state == B3);
always@(*)begin
case(state)
IDLE:next_state=data?S1:IDLE;
S1:next_state=data?S2:IDLE;
S2:next_state=data?S2:S3;
S3:next_state=data?B0:IDLE;
B0:next_state=B1;
B1:next_state=B2;
B2:next_state=B3;
B3:next_state=COUNT;
COUNT:next_state=done_counting?WAIT:COUNT;
WAIT:next_state=ack?IDLE:WAIT;
endcase
end
//state
always@(posedge clk)begin
if(reset)
state <= IDLE;
else
state <= next_state;
end
//shift
always@(posedge clk)begin
if(reset)
shift <= 0;
else if(shift_ena)
shift <= {shift[2:0], data};
end
//counter
always@(posedge clk)begin
if(reset)
counter <= 0;
else
case(state)
COUNT:counter <= counter + 1;
default:counter <= 0;
endcase
end
assign done_counting = (counter == (shift + 1) * 1000 - 1);
assign count = shift - counter / 1000;
assign counting = state == COUNT;
assign done = state == WAIT;
endmodule
建立了一个微信公众号“Andy的ICer之路”,此公众号主要分享数字IC相关的学习经验,做公众号的目的就是记录自己的学习过程,很多东西回过头来可能就忘记了,为了记住知识和分享知识,希望自己可以保持更新,有兴趣的朋友可以关注一下!