构建更大的电路
1、周期为1000的计数器
构建一个从 0 到 999(包括 0 到 999)计数的计数器,周期为 1000 个周期。复位输入是同步的,应将计数器复位为 0。
代码实现:
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 + 1'b1;
end
endmodule
验证结果:
2、四位移位寄存器和递减计数器
构造一个4bit的移位寄存器,同时也可以做递减的计数器使用。其中当shift_ena为1时数据data的高位先进到移位寄存器中;当count_ena为1时,计数器从寄存器中存储的数开始逐时钟递减;shift_ena和count_ena没有重要级先后顺序,因为他们不会同时使能。
代码实现:
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) begin
if(q == 4'd0)
q <= 4'd15;
else
q <= q -1'b1;
end
end
endmodule
验证结果:
3、FSM 序列1101识别器
构造一个有限状态机检测data中的1101序列,如果检测到该序列,则将输出一直拉高直到同步复位信号为高。
代码实现:
module top_module (
input clk,
input reset, // Synchronous reset
input data,
output start_shifting);
parameter IDLE = 3'd0, S1 = 3'd1, S2 = 3'd2;
parameter S3 = 3'd3, OUT = 3'd4;
reg [2:0] current_state, next_state;
always @(*) begin
case(current_state)
IDLE: next_state = data ? S1 : IDLE;
S1: next_state = data ? S2 : IDLE;
S2: next_state = data ? S2 : S3;
S3: next_state = data ? OUT : IDLE;
OUT: next_state = OUT;
default: next_state = IDLE;
endcase
end
always @(posedge clk) begin
if(reset)
current_state <= IDLE;
else
current_state <= next_state;
end
assign start_shifting = (current_state == OUT);
endmodule
验证结果:
4、FSM:使能移位寄存器
当有限状态机被复位时,将shift_ena拉高4个周期,之后保持为0直到再次复位。
注意:复位一直为高的时候输出也一直为高电平。
代码实现:
module top_module (
input clk,
input reset, // Synchronous reset
output shift_ena);
parameter IDLE = 2'd0, ENA = 2'd1, STOP = 2'd2;
reg [1:0] current_state, next_state;
reg [1:0] count;
always @(*) begin
case(current_state)
IDLE: next_state = ENA ;
ENA: next_state = (count == 2'd3) ? STOP : ENA;
STOP: next_state = STOP;
default: next_state = IDLE;
endcase
end
always @(posedge clk) begin
if(reset)
current_state <= IDLE;
else
current_state <= next_state;
end
always @(posedge clk) begin
if(reset)
count <= 2'd0;
else if(count == 2'd3)
count <= 2'd0;
else
count <= count + 1'b1;
end
assign shift_ena = (current_state == ENA)| (current_state == IDLE);
endmodule
验证结果:
5、FSM:完整的FSM
我们想要创建一个计时器:
(1)在检测到特定模式(1101)时启动,
(2)再移位4位来确定延迟时间,
(3)等待计数器完成计数,然后
(4)通知用户并等待用户确认计时器。
在这个问题中,只实现控制计时器的有限状态机。这里不包括数据路径(计数器和一些比较器)。
串行数据在数据输入管脚上可用。当接收到模式1101时,状态机必须断言输出shift_ena为4个时钟周期。
之后,状态机断言其计数输出以指示它正在等待计数器,并等待直到输入done_counting为高。
在这一点上,状态机必须断言完成以通知用户定时器已超时,并等待直到输入ack为 1,然后才被重置以寻找下一次出现的启动序列 (1101)。
状态机应重置为开始搜索输入序列 1101 的状态。
这是预期输入和输出的示例。‘x’ 状态读起来可能有点混乱。它们表明 FSM 不应关心该周期中的特定输入信号。例如,一旦检测到 1101 模式,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 = 4'd0, S1 = 4'd1, S11 = 4'd2, S110 = 4'd3, B0 = 4'd4, B1 = 4'd5;
parameter B2 = 4'd6, B3 = 4'd7, Count = 4'd8, Wait = 4'd9;
reg [3:0] current_state, next_state;
always @(*) begin
case(current_state)
S: next_state = data ? S1 : S;
S1: next_state = data ? S11 : S;
S11: next_state = data ? S11 : S110;
S110: next_state = data ? B0 : S;
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 ? S : Wait;
default: next_state = S;
endcase
end
always @(posedge clk) begin
if(reset)
current_state <= S;
else
current_state <= next_state;
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
验证结果:
6、完整的计时器
我们想用一个输入创建一个计时器:
(1)当检测到特定的输入模式 (1101) 时启动,
(2)再移动 4 位以确定延迟的持续时间,
(2)等待计数器完成计数,并且
(4)通知用户并等待用户确认定时器。
串行数据在数据输入引脚上可用。当接收到模式 1101 时,电路必须移入接下来的 4 位,最高有效位在前。这 4 位决定了定时器延迟的持续时间。我将其称为delay[3:0]。
之后,状态机断言其计数输出以指示它正在计数。状态机必须精确计数(delay[3:0] + 1) * 1000 个时钟周期。例如,delay=0 表示计数 1000 个周期,delay=5 表示计数 6000 个周期。同时输出当前剩余时间。这应该等于延迟1000 个周期,然后延迟 1为 1000 个周期,依此类推,直到 1000 个周期为 0。当电路不计数时, count[3:0] 输出无关紧要(任何值都方便您实现)。
此时,电路必须断言done以通知用户定时器已超时,并等待直到输入ack为 1,然后才被重置以寻找下一次出现的启动序列 (1101)。
电路应重置为开始搜索输入序列 1101 的状态。
这是预期输入和输出的示例。‘x’ 状态读起来可能有点混乱。它们表明 FSM 不应关心该周期中的特定输入信号。例如,一旦 1101 和 delay[3:0] 被读取,电路将不再查看数据输入,直到它在其他所有事情完成后恢复搜索。在本例中,电路计数 2000 个时钟周期,因为延迟 [3:0] 值为 4’b0001。最后几个周期以 delay[3:0] = 4’b1110 开始另一个计数,这将计数 15000 个周期。
提示:本题是前面几道状态机的组合,需要设置计数器。
代码实现:
parameter S = 4'd0, S1 = 4'd1, S11 = 4'd2, S110 = 4'd3, B0 = 4'd4, B1 = 4'd5;
parameter B2 = 4'd6, B3 = 4'd7, Count = 4'd8, Wait = 4'd9;
reg [3:0] current_state, next_state;
reg [15:0] num;
reg [3:0] delay;
reg [3:0] already_count;
wire count_state;
assign count_state = (num == (delay + 1'b1) * 10'd1000) ? 1'b1 : 1'b0;
always @(posedge clk) begin
if(reset) begin
num <= 16'd0;
end
else if(next_state == Wait) begin
num <= 16'd0;
end
else if(next_state == Count) begin
num <= num + 16'd1;
end
end
always @(*) begin
if(num <= 16'd1000)
already_count = 4'd0;
else if(num >= 16'd1000 && num <= 16'd2000)
already_count = 4'd1;
else if(num >= 16'd2000 && num <= 16'd3000)
already_count = 4'd2;
else if(num >= 16'd3000 && num <= 16'd4000)
already_count = 4'd3;
else if(num >= 16'd4000 && num <= 16'd5000)
already_count = 4'd4;
else if(num >= 16'd5000 && num <= 16'd6000)
already_count = 4'd5;
else if(num >= 16'd6000 && num <= 16'd7000)
already_count = 4'd6;
else if(num >= 16'd7000 && num <= 16'd8000)
already_count = 4'd7;
else if(num >= 16'd8000 && num <= 16'd9000)
already_count = 4'd8;
else if(num >= 16'd9000 && num <= 16'd10000)
already_count = 4'd9;
else if(num >= 16'd10000 && num <= 16'd11000)
already_count = 4'd10;
else if(num >= 16'd11000 && num <= 16'd12000)
already_count = 4'd11;
else if(num >= 16'd12000 && num <= 16'd13000)
already_count = 4'd12;
else if(num >= 16'd13000 && num <= 16'd14000)
already_count = 4'd13;
else if(num >= 16'd14000 && num <= 16'd15000)
already_count = 4'd14;
else
already_count = 4'd15;
end
always @(*) begin
case(current_state)
S: next_state = data ? S1 : S;
S1: next_state = data ? S11 : S;
S11: next_state = data ? S11 : S110;
S110: next_state = data ? B0 : S;
B0:begin
next_state = B1;
delay[3] = data;
end
B1:begin
next_state = B2;
delay[2] = data;
end
B2:begin
next_state = B3;
delay[1] = data;
end
B3:begin
next_state = Count;
delay[0] = data;
end
Count: next_state = count_state ? Wait : Count;
Wait : next_state = ack ? S : Wait;
default: next_state = S;
endcase
end
always @(posedge clk) begin
if(reset)
current_state <= S;
else
current_state <= next_state;
end
assign counting = (current_state == Count);
assign count = (current_state == Count) ? (delay - already_count) : 4'd0;
assign done = (current_state == Wait);
endmodule
验证结果:
7、FSM:One hot 逻辑方程
给定以下具有 3 个输入、3 个输出和 10 个状态的状态机:
假设使用以下独热编码,通过检查导出下一状态逻辑方程和输出逻辑方程: (S, S1, S11, S110, B0, B1, B2, B3, Count, Wait) = (10’b0000000001, 10 'b0000000010, 10’b0000000100, … , 10’b1000000000)
通过检查假设单热编码来导出状态转换和输出逻辑方程。仅为此状态机实现状态转换逻辑和输出逻辑(组合逻辑部分)。
编写生成以下等式的代码:
- B3_next – next-state logic for state B1
- S_next
- S1_next
- Count_next
- Wait_next
- done – output logic
- counting
- shift_ena
用one-hot编码的状态写出状态转移代码。
代码实现:
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=4'd0, S1=4'd1, S11=4'd2, S110=4'd3, B0=4'd4, B1=4'd5, B2=4'd6, B3=4'd7, Count=4'd8, Wait=4'd9;
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
验证结果: