目录
3.3.1 Counter with period 1000(Exams/review2015 count1k)
3.3.2 4-bit shift register and down counter(Exams/review2015 shiftcount)
3.3.3 FSM:Sequence 1101 recognizer(Exams/review2015 fsmseq)
3.3.4 FSM:Enable shift register(Exams/review2015 fsmshift)
3.3.5 FSM:The complete FSM(Exams/review2015 fsm)
3.3.6 The complete timer(Exams/review2015 fancytimer)
3.3.7 FSM:One-hot logic equations(Exams/review2015 fsmonehot)
前言
HDLbits网站如下
Problem sets - HDLBits (01xz.net)
从本期开始我们继续HDLbits第三章Circuits的学习,本期的内容是Building larger circuits(3.3.1-3.3.7)
3.3.1 Counter with period 1000(Exams/review2015 count1k)
构建一个计数范围为0到999(含0到999)的计数器,周期为1000个周期。复位输入是同步的,应将计数器重置为0。
Solution:
module top_module (
input clk,
input reset,
output [9:0] q);
always@(posedge clk) begin
if(reset)
q<=10'd0;
else if(q==10'd999)
q<=10'd0;
else
q<=q+10'd1;
end
endmodule
3.3.2 4-bit shift register and down counter(Exams/review2015 shiftcount)
这是一系列五个练习的第一部分,这些练习用几个较小的电路构建复杂的计数器。有关整体设计,请参见 3.3.6the final exercise。
构建一个四位移位寄存器,它也可以作为下行(递减)计数器。当shift_ena为1时,data向最高有效位移位即左移。当count_ena为1时,移位寄存器中当前的数字递减。由于整个系统从未同时使用shift_ena和count_ena,因此如果两个控制输入都为1(这主要意味着哪种情况具有更高的优先级),则电路的功能无关紧要。
Solution:
module top_module (
input clk,
input shift_ena,
input count_ena,
input data,
output [3:0] q);
always@(posedge clk) begin
if(shift_ena)
q<={q[2:0],data};
else if(count_ena)
q<=q-1;
end
endmodule
3.3.3 FSM:Sequence 1101 recognizer(Exams/review2015 fsmseq)
这是一系列五个练习的第二部分,这些练习用几个较小的电路构建复杂的计数器。有关整体设计,请参见 3.3.6the final exercise。
构建一个在输入比特流中搜索序列1101的有限状态机。找到序列后,应将start_shifting设置为1,直到复位。保持最终状态是为了在一个尚未实施的更大的FSM中模拟前往其他状态。我们将在接下来的几个练习中扩展此FSM。
Solution:
module top_module (
input clk,
input reset, // Synchronous reset
input data,
output start_shifting);
parameter s0=0,s1=1,s11=2,s110=3,s1101=4;
reg [2:0]state,next;
always@(posedge clk) begin
if(reset)
state<=0;
else
state<=next;
end
always@(*) begin
case(state)
s0:next=data?s1:s0;
s1:next=data?s11:s0;
s11:next=data?s11:s110;
s110:next=data?s1101:s0;
s1101:next=s1101;
endcase
end
assign start_shifting=(state==s1101);
endmodule
3.3.4 FSM:Enable shift register(Exams/review2015 fsmshift)
这是一系列五个练习的第三部分,这些练习用几个较小的电路构建复杂的计数器。有关整体设计,请参见 3.3.6the final exercise。
作为用于控制移位寄存器的FSM的一部分,我们希望能够在检测到正确的位模式时,使移位寄存器能够精确地工作4个时钟周期。我们在3.3.3中处理序列检测,因此FSM的这部分仅处理移位寄存器的4个周期启用。
无论何时复位FSM,都要将shift_ena有效4个周期,然后永远为0(直到复位)。
Solution:
module top_module (
input clk,
input reset, // Synchronous reset
output shift_ena);
reg [2:0]cnt;
always@(posedge clk) begin
if(reset)
cnt<=0;
else if(cnt<=3)
cnt<=cnt+1;
else
cnt<=cnt;
end
always@(*) begin
if(cnt==4)
shift_ena=0;
else
shift_ena=1;
end
endmodule
3.3.5 FSM:The complete FSM(Exams/review2015 fsm)
这是一系列五个练习的第四部分,这些练习用几个较小的电路构建复杂的计数器。有关整体设计,请参见 3.3.6the final exercise。
我们想创建一个计时器:
- 当检测到特定序列(1101)时启动
- 再移位四位以确定延迟的持续时间
- 等待计数器完成计数
- 通知用户并等待用户确认计时器。
在这个问题中,只实现控制计时器的FSM。这里不包括数据路径(计数器和一些比较器)。
串行数据在数据输入引脚上可用。当接收到序列1101时,状态机必须在整整4个时钟周期内使shift_ena有效。
之后,状态机使其计数输出有效,以指示它正在等待计数器,并等待直到输入done_counting为高。
此时,状态机必须断言done以通知用户计时器已超时,并等待直到输入 ack为1,然后再复位,以查找启动序列的下一次出现(1101)。
状态机应复位为开始搜索输入序列1101的状态。
以下是预期输入和输出的示例。“x”状态读起来可能有点混乱。它们表明FSM不应该关心该周期中的特定输入信号。例如,一旦检测到1101模式,FSM将不再查看数据输入,直到完成所有其他操作后恢复搜索。
Hint:
Solution:
module top_module (
input clk,
input reset, // Synchronous reset
input data,
output shift_ena,
output counting,
input done_counting,
output done,
input ack );
parameter s=0,s1=1,s11=2,s110=3,shift=5,count=6,idle=7;
reg [2:0]state,next;
reg [2:0]cnt;
always@(*) begin
case(state)
s:next=data?s1:s;
s1:next=data?s11:s;
s11:next=data?s11:s110;
s110:next=data?shift:s;
shift:next=(cnt<3)?shift:count;
count:next=done_counting?idle:count;
idle:next=ack?s:idle;
endcase
end
always@(posedge clk) begin
if(reset)
state<=s;
else
state<=next;
end
always@(posedge clk) begin
case(state)
s110:cnt<=0;
shift:cnt<=cnt+1;
endcase
end
assign shift_ena = (state==shift);
assign counting = (state==count);
assign done = (state==idle);
endmodule
3.3.6 The complete timer(Exams/review2015 fancytimer)
这是一系列五个练习的第五部分,这些练习用几个较小的电路构建复杂的计数器。
我们想创建一个计时器:
- 当检测到特定序列(1101)时启动
- 再移位四位以确定延迟的持续时间
- 等待计数器完成计数
- 通知用户并等待用户确认计时器。
串行数据在data输入引脚上可用。当接收到序列1101时,电路必须在接下来的4位中移位,最高有效位首先移位。这4位决定计时器延迟的持续时间。我称之为delay[3:0]。
之后,状态机使其counting输出有效,以指示其正在计数。状态机必须精确计数(delay[3:0]+1)*1000个时钟周期。 例如,delay=0表示计数1000个周期,delay=5表示计数6000个周期。同时输出当前剩余时间。这等价于delay对应1000个周期,delay-1对应1000个周期,依此类推,直到0对应1000个周期。当电路不计数时,count[3:0]输出是dont-care(无论什么值便于实现)。
此时,电路必须断言done,以通知用户计时器已超时,并等待输入ack为1,然后再复位,以查找下一次出现的启动序列(1101)。
电路应复位至开始搜索输入序列1101的状态。
以下是预期输入和输出的示例。“x”状态读起来可能有点混乱。它们表明FSM不应该关心该周期中的特定输入信号。例如,一旦1101和delay[3:0]被读取,电路将不再查看数据输入,直到完成所有其他操作后恢复搜索。在本例中,电路计数2000个时钟周期,因为delay[3:0]值为4'b0001。最后几个周期开始另一次计数,delay[3:0]=4'b1110,这将计15000个周期。
Solution:
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,s11=2,s110=3,shift=4,timer=5,wait_=6;
reg[2:0]state,next;
always@(*) begin
case(state)
idle:next=data?s1:idle;
s1:next=data?s11:idle;
s11:next=data?s11:s110;
s110:next=data?shift:idle;
shift:next=(shift_cnt==3)?timer:shift;
timer:next=(timer_cnt==(delay+1)*1000-1)?wait_:timer;
wait_:next=ack?idle:wait_;
endcase
end
always@(posedge clk) begin
if(reset)
state<=idle;
else
state<=next;
end
reg[3:0]delay;
always@(posedge clk) begin
if(reset)
delay<=4'b0;
else if(state==shift)
delay<={delay[2:0],data};
else
delay<=delay;
end
reg[1:0]shift_cnt;
always@(posedge clk) begin
if(reset)
shift_cnt<=0;
else if(state==shift&&shift_cnt<2'd3)
shift_cnt<=shift_cnt+2'd1;
else
shift_cnt<=0;
end
reg[15:0]timer_cnt;
always@(posedge clk) begin
if(reset)
timer_cnt<=16'd0;
else if(state==timer&&timer_cnt<((delay+1)*1000-1))
timer_cnt<=timer_cnt+16'd1;
else
timer_cnt<=16'd0;
end
reg[10:0]cnt_1k;
reg[3:0]num_1k;
always@(posedge clk) begin
if(reset)
cnt_1k<=11'd0;
else if(state==timer&&cnt_1k!=11'd999)
cnt_1k<=cnt_1k+11'd1;
else
cnt_1k<=11'd0;
end
always@(posedge clk) begin
if(reset)
num_1k<=4'd0;
else if(cnt_1k==11'd999)
num_1k<=num_1k+1'b1;
else if(state==timer)
num_1k<=num_1k;
else
num_1k<=4'd0;
end
assign counting=(state==timer);
assign done=(state==wait_);
assign count=(state==timer)?(delay-num_1k):4'b0;
endmodule
3.3.7 FSM:One-hot logic equations(Exams/review2015 fsmonehot)
给定以下具有3个输入、3个输出和10个状态的状态机:
假设使用以下独热码,通过检查推导next_state态逻辑方程和output逻辑方程:(S、S1、S11、S110、B0、B1、B2、B3、Count、Wait)=(10'b0000000001、10'b0000000010、10'b0000000100、…、10'b1000000000)
编写生成以下方程式的代码:
- B3_next -- B3的下个状态
- S_next
- S1_next
- Count_next
- Wait_next
- done -- output logic
- counting
- shift_ena
Solution:
module top_module(
input d,
input done_counting,
input ack,
input [9:0] state, // 10-bit one-hot current state
output B3_next,
output S_next,
output S1_next,
output Count_next,
output Wait_next,
output done,
output counting,
output shift_ena
); //
parameter S=0, S1=1, S11=2, S110=3, B0=4, B1=5, B2=6, B3=7, Count=8, Wait=9;
reg[9:0]next;
always@(*) begin
next[S]=(state[S]&&~d)||(state[S1]&&~d)||(state[S110]&&~d)||(state[Wait]&&ack);
next[S1]=state[S]&&d;
next[S11]=state[S1]&&d;
next[S110]=state[S11]&&~d;
next[B0]=state[S110]&&d;
next[B1]=state[B0];
next[B2]=state[B1];
next[B3]=state[B2];
next[Count]=state[B3]||state[Count]&&~(done_counting);
next[Wait]=state[Count]&&done_counting||state[Wait]&&~ack;
end
assign B3_next=next[B3];
assign S_next=next[S];
assign S1_next=next[S1];
assign Count_next=next[Count];
assign Wait_next=next[Wait];
assign done=state[Wait];
assign counting=state[Count];
assign shift_ena=state[B0]||state[B1]||state[B2]||state[B3];
endmodule
3.3.6分解成小任务就没有那么难了