是滴,你没看错,最近在学习这玩意。没办法,又被换方向了。
基本上这5个弄懂了,后面就可以独立写写简单的东西啦!
count1k
构建一个计数器,其计数范围从0到999(包含0和999),周期为1000个时钟周期。
复位输入是同步的,并且应将计数器重置为0。

module top_module (
input clk,
input reset,
output [9:0] q);
always@(posedge clk)begin
if(reset == 1'b1)begin
q<=10'd0;
end
else if(q==10'd999)begin
q <= 10'd0;
end
else begin
q <= q+1'b1;
end
end
endmodule

shiftcount
构建一个四位移位寄存器,该寄存器同时也充当一个递减计数器。
当shift_ena为1时,数据以最高有效位(MSB)优先的方式移入。
当count_ena为1时,当前存储在移位寄存器中的数值将递减。
由于整个系统从不会同时使用shift_ena和count_ena,因此如果这两个控制输入同时为1,您的电路如何响应并不重要(这主要意味着哪个情况具有更高优先级并不重要)。
请注意,在Verilog中实现这个功能时,您需要设计一个四位的寄存器,该寄存器能够根据shift_ena信号进行数据的MSB优先移位操作,同时根据count_ena信号执行递减操作。由于题目指出这两个控制信号不会同时被激活,因此在设计电路时,您无需考虑它们同时激活时的行为。

module top_module (
input clk,
input shift_ena,
input count_ena,
input data,
output [3:0] q);
always@(posedge clk)begin
case({shift_ena, count_ena})
2'b10:begin
q <= {q[2:0],data};
end
2'b01:begin
q <= q-1'b1;
end
endcase
end
endmodule

fsmseq
这是由五个练习组成的系列中的第二个练习,旨在通过几个较小的电路组合构建一个复杂的计数器。有关整体设计,请参阅最后一个练习。
构建一个有限状态机(FSM),用于在输入比特流中搜索序列1101。
当找到该序列时,它应将start_shifting永久设置为1,直到复位为止。
停留在最终状态是为了模拟在尚未实现的更大FSM中转移到其他状态的情况。
在接下来的几个练习中,我们将扩展这个FSM。

module top_module (
input clk,
input reset, // Synchronous reset
input data,
output start_shifting);
parameter S0 = 3'd0, S1 = 3'd1, S2 = 3'd2, S3 = 3'd3, S4 = 3'd4;
reg [2:0] current_state;
reg [2:0] next_state;
always@(posedge clk)begin
if(reset)begin
current_state <= S0;
end
else begin
current_state <= next_state;
end
end
always@(*)begin
case(current_state)
S0:begin
next_state = data ? S1 : S0;
end
S1:begin
next_state = data ? S2 : S0;
end
S2:begin
next_state = data ? S2 : S3;
end
S3:begin
next_state = data ? S4 : S0;
end
S4:begin
next_state = S4;
end
default:begin
next_state = S0;
end
endcase
end
always@(posedge clk)begin
if(reset)begin
start_shifting <= 1'b0;
end
else if(next_state == S4)begin
start_shifting <= 1'b1;
end
end
//assign start_shifting = current_state == S4;
endmodule

fsmshift
作为控制移位寄存器的有限状态机(FSM)的一部分,我们希望在检测到正确的位模式时,能够精确地使移位寄存器启用4个时钟周期。
我们在"Exams/review2015_fsmseq"中处理序列检测,因此该FSM的这一部分仅处理使移位寄存器启用4个周期的功能。
每当FSM被重置时,先让shift_ena断言4个周期,然后永久保持为0(直到再次重置)。

这道题题目中说,如果复位信号有效,shift_ena信号就变为1,当复位信号撤销以后,shift_ena信号保持4个周期为1后变为0。
module top_module (
input clk,
input reset, // Synchronous reset
output shift_ena);
parameter S0 = 3'd0, S1 = 3'd1, S2 = 3'd2, S3 = 3'd3, S4 = 3'd4;
reg [2:0] current_state;
reg [2:0] next_state;
always@(posedge clk)begin
if(reset)begin
current_state <= S0;
end
else begin
current_state <= next_state;
end
end
always@(*)begin
case(current_state)
S0:begin
next_state = S1;
end
S1:begin
next_state = S2;
end
S2:begin
next_state = S3;
end
S3:begin
next_state = S4;
end
S4:begin
next_state = S4;
end
default:begin
next_state = S4;
end
endcase
end
assign shift_ena = (current_state == S0 || current_state == S1 || current_state == S2 || current_state == S3);
endmodule
用状态机定义几个状态,然后当复位信号有效,进入状态S0,复位信号撤销就进入S1,然后进入S2、S3、S4,当进入S4状态,下一个状态就永远保持为S4。然后shift_ena信号在状态S0、S1、S2、S3时有效,这样就完成了题目。
fsm
题目背景
这是五个练习系列中的第四个,旨在通过多个小电路组合构建一个复杂的计数器。整体设计请参见最后一个练习。
建议先行完成以下练习:
- FSM:启用移位寄存器
- FSM:序列识别器
题目要求
我们需要创建一个定时器,该定时器需满足以下功能:
- 在检测到特定模式(1101)时启动;
- 再移入4位数据以确定延迟时长;
- 等待计数器完成计数;
- 通知用户并等待用户确认定时器。
本题仅要求实现控制定时器的有限状态机(FSM),不包括数据路径(如计数器和比较器)。
输入与输出
- 串行数据通过数据输入引脚接收。
- 接收到1101模式时,状态机需连续4个时钟周期使
shift_ena
输出有效。 - 随后,状态机使计数输出有效,表明正在等待计数器,并持续等待直至
done_counting
输入为高电平。 - 此时,状态机必须使
done
输出有效,通知用户定时器已超时,并等待ack
输入为1后再重置,以寻找下一个启动序列(1101)的出现。 - 状态机重置后应进入搜索输入序列1101的状态。
输入输出示例
以下是一个预期的输入输出示例。其中,"x"状态可能稍显困惑,它们表示在该周期中,FSM无需关注特定的输入信号。例如,一旦检测到1101模式,FSM在完成其他所有操作并重新开始搜索之前,将不再查看数据输入。
(注:此处未给出具体的输入输出序列示例,需根据FSM的设计自行构建或参考相关资料。)
注意:在实际设计中,需根据题目要求和FSM的工作原理,详细设计状态转换图和状态机逻辑,以确保满足所有功能需求。同时,还需考虑状态机的复位、初始化以及异常处理等情况。

题目中说要创建一个计时器,当检测到序列1101时启动,接着等待4位,然后计数器完成计数,最后等待用户确认计数器。
大家也看出来了,这道题其实就是前面几道题目的组合。
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, B0=4, B1=5, B2=6, B3=7, COUNT=8, WAIT=9;
reg [3:0] current_state;
reg [3:0] next_state;
always@(posedge clk)begin
if(reset)begin
current_state <= S;
end
else begin
current_state <= next_state;
end
end
always@(*)begin
case(current_state)
S:begin
next_state = data ? S1 : S;
end
S1:begin
next_state = data ? S11 : S;
end
S11:begin
next_state = data ? S11 : S110;
end
S110:begin
next_state = data ? B0 : S;
end
B0:begin
next_state = B1;
end
B1:begin
next_state = B2;
end
B2:begin
next_state = B3;
end
B3:begin
next_state = COUNT;
end
COUNT:begin
next_state = done_counting ? WAIT : COUNT;
end
WAIT:begin
next_state = ack ? S : WAIT;
end
default:begin
next_state = S;
end
endcase
end
assign shift_ena = (current_state == B0 || current_state == B1 || current_state == B2 || current_state == B3);
assign counting = (current_state == COUNT);
assign done = (current_state == WAIT);
endmodule
fancytimer
题目背景
这是五个练习系列中的第五个,旨在通过组合多个小电路来构建一个复杂的计数器。建议先完成前四个练习(计数器、序列识别有限状态机(FSM)、FSM延迟和组合FSM)。
题目要求
我们需要创建一个具有单一输入的定时器,该定时器需满足以下功能:
- 在检测到特定输入模式(1101)时启动;
- 接着移入4位数据以确定延迟时长;
- 等待计数器完成计数;
- 通知用户并等待用户确认定时器。
串行数据通过数据输入引脚接收。当接收到1101模式时,电路需按最高有效位优先的顺序移入接下来的4位。这4位数据决定了定时器的延迟时长,记为delay[3:0]
。
随后,状态机断言其计数输出,表明正在计数。状态机需精确计数(delay[3:0] + 1) * 1000
个时钟周期。例如,delay=0
表示计数1000个周期,delay=5
表示计数6000个周期。同时,还需输出当前剩余时间,其值在1000个周期内等于delay
,接着在下一个1000个周期内减1,依此类推,直至在1000个周期内为0。当电路未计数时,count[3:0]
输出的值无关紧要(实现时采用任意方便的值即可)。
此时,电路必须断言done
以通知用户定时器已超时,并等待ack
输入为1后再重置,以寻找下一个启动序列(1101)的出现。
电路重置后应进入搜索输入序列1101的状态。
输入输出示例
以下是预期的输入输出示例。其中,"x"状态可能稍显困惑,它们表示在该周期中,FSM无需关注特定的输入信号。例如,一旦读取了1101和delay[3:0]
,电路在完成其他所有操作并重新开始搜索之前,将不再查看数据输入。在本例中,由于delay[3:0]
的值为4'b0001,因此电路计数了2000个时钟周期。最后几个周期开始另一个计数,此时delay[3:0] = 4'b1110
,将计数15000个周期。
注意:在实际设计中,需根据题目要求和FSM的工作原理,详细设计状态转换图和状态机逻辑,以确保满足所有功能需求。同时,还需考虑状态机的复位、初始化、计数逻辑以及异常处理等情况。
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, B0=4, B1=5, B2=6, B3=7, COUNT=8, WAIT=9;
reg [3:0] current_state;
reg [3:0] next_state;
always@(posedge clk)begin
if(reset)begin
current_state <= S;
end
else begin
current_state <= next_state;
end
end
always@(*)begin
case(current_state)
S:begin
next_state = data ? S1 : S;
end
S1:begin
next_state = data ? S11 : S;
end
S11:begin
next_state = data ? S11 : S110;
end
S110:begin
next_state = data ? B0 : S;
end
B0:begin
next_state = B1;
end
B1:begin
next_state = B2;
end
B2:begin
next_state = B3;
end
B3:begin
next_state = COUNT;
end
COUNT:begin
next_state = done_counting ? WAIT : COUNT;
end
WAIT:begin
next_state = ack ? S : WAIT;
end
default:begin
next_state = S;
end
endcase
end
assign shift_ena = (current_state == B0 || current_state == B1 || current_state == B2 || current_state == B3);
assign counting = (current_state == COUNT);
assign done = (current_state == WAIT);
endmodule
fsmonehot

-
- 状态机是什么?
状态机是一个可以处于不同状态并在输入信号的作用下从一个状态转移到另一个状态的设备或系统。它就像是一个有"记忆"的开关,可以根据输入来改变它的"状态"。
-
- 一位有效编码(One-Hot Encoding)
在这个题目中,状态机有10个状态,但我们不直接用一个数字来表示这些状态(比如0到9),而是用一个10位的二进制数来表示,其中只有一个位是1,其余位都是0。这个1所在的位就代表了当前的状态。比如,状态S可以表示为0000000001
,状态S1可以表示为0000000010
,以此类推。
-
- 推导逻辑方程
我们需要根据状态机的行为(也就是它在不同状态下对输入信号的响应)来推导每个状态的下一个状态是什么,以及输出信号应该是什么。这个过程就像是在看一个"说明书",告诉我们在每个状态下应该怎么做。
-
- 实现逻辑
推导出逻辑方程后,我们需要用代码来实现这些逻辑。这就像是按照"说明书"来编程,让计算机能够模拟状态机的行为。
-
- 题目要求
- 推导状态B3、S、S1、Count、Wait的下一个状态逻辑方程。
- 推导输出信号done、counting、shift_ena的逻辑方程。
- 用代码实现这些逻辑。
简化的示例
假设我们有一个简单的状态机,它有两个状态(我们用A和B表示),一个输入信号(我们用X表示),和一个输出信号(我们用Y表示)。
- 当状态机处于状态A且输入X为1时,它转移到状态B,输出Y为1。
- 当状态机处于状态B且输入X为0时,它返回到状态A,输出Y为0。
在这个简化的例子中,我们可以这样推导逻辑方程:
- 如果当前状态是A且输入X是1,则下一个状态是B(A_next = B)。
- 如果当前状态是B且输入X是0,则下一个状态是A(B_next = A)。
- 如果当前状态是A且输入X是1,则输出Y是1(Y = 1 当 A 且 X = 1)。
- 如果当前状态是B且输入X是0,则输出Y是0(Y = 0 当 B 且 X = 0)。
当然,在实际的问题中,状态机会更加复杂,但我们可以用类似的方法来推导逻辑方程并实现它们。
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
); //
// You may use these parameters to access state bits using e.g., state[B2] instead of state[6].
parameter S=0, S1=1, S11=2, S110=3, B0=4, B1=5, B2=6, B3=7, Count=8, Wait=9;
assign B3_next = state[B2];
assign S_next = ~d & state[S] | ~d & state[S1] | ~d & state[S110] | ack & state[Wait];
assign S1_next = d & state[S];
assign Count_next = state[B3] | ~done_counting & state[Count];
assign Wait_next = done_counting & state[Count] | ~ack & state[Wait];
assign done = state[Wait];
assign counting = state[Count];
assign shift_ena = state[B0] | state[B1] | state[B2] |state[B3];
endmodule