关注 望森FPGA 查看更多FPGA资讯
这是望森的第 21 期分享
作者 | 望森
来源 | 望森FPGA
目录
[1 Counter with period 1000](#1 Counter with period 1000)
[2 4-bit shift register and down counter](#2 4-bit shift register and down counter)
[3 FSM: Sequence 1101 recognizer](#3 FSM: Sequence 1101 recognizer)
[4 FSM: Enable shift register](#4 FSM: Enable shift register)
[5 FSM: The complete FSM](#5 FSM: The complete FSM)
[6 The complete timer](#6 The complete timer)
[7 FSM: One-hot logic equations](#7 FSM: One-hot logic equations)
本文中的代码都能够正常运行,请放心食用😋~
练习的官方网站是:https://hdlbits.01xz.net/
注:作者将每个练习的知识点都放在了题目和答案之后
1 Counter with period 1000
题目:
构建一个计数器,计数范围从 0 到 999(含 0 和 999),周期为 1000 个周期。复位输入是同步的,应将计数器复位为 0。
答案:
module top_module (
input clk,
input reset,
output [9:0] q);
reg [9:0] cnt;
wire end_cnt;
parameter x = 10'd1000;
always@(posedge clk) begin
if(reset)begin
cnt <= 0;
end
else if(end_cnt)begin
cnt <= 0;
end
else begin
cnt <= cnt + 1;
end
end
assign end_cnt = cnt==x-1;
assign q = cnt;
endmodule
2 4-bit shift register and down counter
题目:
构建一个四位移位寄存器,该寄存器也可用作减计数器。当 shift_ena 为 1 时,数据首先以最高有效位移位。当 count_ena 为 1 时,移位寄存器中的当前数字会减少。由于整个系统从不一起使用 shift_ena 和 count_ena,因此如果两个控制输入都是 1,您的电路做什么都无关紧要(这主要意味着哪种情况具有更高的优先级并不重要)。
答案:
module top_module (
input clk,
input shift_ena,
input count_ena,
input data,
output reg [3:0] q);
always@(posedge clk)begin
if(shift_ena)begin
q <= {q[2:0],data};
end
if(count_ena)begin
q <= q-1;
end
end
endmodule
3 FSM: Sequence 1101 recognizer
题目:
构建一个有限状态机,在输入位流中搜索序列 1101。找到该序列后,它应将 start_shifting 设置为 1,直到重置。卡在最终状态旨在模拟在尚未实现的更大的 FSM 中进入其他状态。我们将在接下来的几个练习中扩展此 FSM。
答案:
1.状态转换图
2.代码
module top_module (
input clk,
input reset, // Synchronous reset
input data,
output start_shifting);
parameter IDLE =3'd0;
parameter S0 =3'd1;
parameter S1 =3'd2;
parameter S2 =3'd3;
parameter S3 =3'd4;
reg [2:0] state,next_state;
wire IDLE2IDLE,IDLE2S0;
wire S02IDLE,S02S1;
wire S12S2,S12S1;
wire S22IDLE,S22S3;
always@(posedge clk) begin
if(reset)
state <= IDLE;
else
state <= next_state;
end
always@(*) begin
case(state)
IDLE:begin
if (IDLE2IDLE)begin
next_state = IDLE;
end
else if (IDLE2S0)begin
next_state = S0;
end
end
S0: begin
if (S02IDLE)begin
next_state = IDLE;
end
else if (S02S1)begin
next_state = S1;
end
end
S1: begin
if (S12S2)begin
next_state = S2;
end
else if (S12S1)begin
next_state = S1;
end
end
S2: begin
if (S22IDLE)begin
next_state = IDLE;
end
else if (S22S3)begin
next_state = S3;
end
end
S3: begin
next_state = S3;
end
default next_state = IDLE;
endcase
end
assign IDLE2IDLE = data==1'b0;
assign IDLE2S0 = data==1'b1;
assign S02IDLE = data==1'b0;
assign S02S1 = data==1'b1;
assign S12S2 = data==1'b0;
assign S12S1 = data==1'b1;
assign S22IDLE = data==1'b0;
assign S22S3 = data==1'b1;
assign start_shifting = (state == S3);
endmodule
4 FSM: Enable shift register
题目:
作为控制移位寄存器的 FSM 的一部分,我们希望能够在检测到正确的位模式时启用移位寄存器恰好 4 个时钟周期。我们在 Exams/review2015_fsmseq 中处理序列检测,因此 FSM 的这一部分仅处理启用移位寄存器 4 个周期。
每当 FSM 重置时,置位 shift_ena 4 个周期,然后永远置位 0(直到重置)。
答案:
module top_module (
input clk,
input reset, // Synchronous reset
output reg shift_ena
);
parameter x = 4;
//counter
reg [1:0] cnt;
wire add_cnt;
wire end_cnt;
always@(posedge clk)begin
if(reset)begin
cnt <= 0;
end
else if(add_cnt)begin
if(end_cnt)begin
cnt <= 0;
end
else begin
cnt <= cnt + 1;
end
end
end
assign add_cnt = !reset;
assign end_cnt = add_cnt && cnt==x-1;
//
always@(posedge clk)begin
if(reset)begin
shift_ena <= 1;
end
else if(cnt==x-1)begin
shift_ena <= 0;
end
end
endmodule
5 FSM: The complete FSM
题目:
您可能希望先执行 FSM:启用移位寄存器和 FSM:序列识别器。
我们想要创建一个计时器:
1.在检测到特定模式 (1101) 时启动,
2.shift 4 个比特以确定延迟的持续时间,
3.等待计数器完成计数
4.通知用户并等待用户确认计时器。
在此问题中,仅实现控制计时器的有限状态机。数据路径(计数器和一些比较器)不包括在这里。
串行数据在数据输入引脚上可用。当接收到模式 1101 时,状态机必须输出正好 4 个时钟周期的 shift_ena 高电平。
此后,状态机 counting 输出为高电平以指示它正在等待计数器,并等待输入 done_counting 为高。
此时,状态机必须拉高 done 以通知用户计时器已超时,并等待输入 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;
parameter S1 =4'd1;
parameter S11 =4'd2;
parameter S110 =4'd3;
parameter B0 =4'd4;
parameter B1 =4'd5;
parameter B2 =4'd6;
parameter B3 =4'd7;
parameter Count =4'd8;
parameter Wait =4'd9;
reg [3:0] state, next_state;
wire S2S,S2S1;
wire S12S,S12S11;
wire S112S110,S112S11;
wire S1102S,S1102B0;
wire Count2Count,Count2Wait;
wire Wait2Wait,Wait2S;
//状态跳转
always @(posedge clk) begin
if(reset)begin
state <= S;
end
else begin
state <= next_state;
end
end
//状态跳转控制
always @(*) begin
case(state)
S : begin
if (S2S)begin
next_state = S;
end
else if(S2S1)begin
next_state = S1;
end
end
S1 : begin
if (S12S)begin
next_state = S;
end
else if(S12S11)begin
next_state = S11;
end
end
S11 : begin
if (S112S110)begin
next_state = S110;
end
else if(S112S11)begin
next_state = S11;
end
end
S110 : begin
if (S1102S)begin
next_state = S;
end
else if(S1102B0)begin
next_state = B0;
end
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
if (Count2Count)begin
next_state = Count;
end
else if(Count2Wait)begin
next_state = Wait;
end
end
Wait : begin
if (Wait2Wait)begin
next_state = Wait;
end
else if(Wait2S)begin
next_state = S;
end
end
default next_state = S;
endcase
end
//状态跳转控制条件
assign S2S = data == 0;
assign S2S1 = data == 1;
assign S12S = data == 0;
assign S12S11 = data == 1;
assign S112S110 = data == 0;
assign S112S11 = data == 1;
assign S1102S = data == 0;
assign S1102B0 = data == 1;
assign Count2Count = done_counting == 0;
assign Count2Wait = done_counting == 1;
assign Wait2Wait = ack == 0;
assign Wait2S = ack == 1;
//输出信号
assign shift_ena = state==B0 || state==B1 || state==B2 || state==B3;
assign counting = state==Count;
assign done = state==Wait;
endmodule
知识点:
提示:
6 The complete timer
题目:
这是由几个较小的电路构建复杂计数器的五个练习系列中的第五个组件。您可能希望先进行前面四个练习(计数器、序列识别器 FSM、FSM 延迟和组合 FSM)。
我们想要创建一个具有一个输入的计时器,该计时器:
1.在检测到特定输入模式 (1101) 时启动,
2.shift 4 比特以确定延迟持续时间,
3.等待计数器完成计数
4.通知用户并等待用户确认计时器。
串行数据在数据输入引脚上可用。当接收到模式 1101 时,电路必须移入接下来的 4 位,优先移入最高有效位。这 4 位决定了计时器延迟的持续时间。我将其称为 delay[3:0] 。
之后,状态机拉高其 counting output 以指示它正在计数。状态机必须精确计数 (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 个时钟周期,因为 delay[3:0] 值为 4'b0001。最后几个周期以 delay[3:0] = 4'b1110 开始另一个计数,这将计数 15000 个周期。
答案:
1.状态转换图
2.代码
module top_module (
input clk,
input reset, // Synchronous reset
input data,
output [3:0] count,
output counting,
output done,
input ack );
parameter S =4'd0;
parameter S1 =4'd1;
parameter S11 =4'd2;
parameter S110 =4'd3;
parameter B0 =4'd4;
parameter B1 =4'd5;
parameter B2 =4'd6;
parameter B3 =4'd7;
parameter Count =4'd8;
parameter Wait =4'd9;
reg [3:0] state, next_state;
wire S2S,S2S1;
wire S12S,S12S11;
wire S112S110,S112S11;
wire S1102S,S1102B0;
wire Count2Count,Count2Wait;
wire Wait2Wait,Wait2S;
//状态跳转
always @(posedge clk) begin
if(reset)begin
state <= S;
end
else begin
state <= next_state;
end
end
//状态跳转控制
always @(*) begin
case(state)
S : begin
if (S2S)begin
next_state = S;
end
else if(S2S1)begin
next_state = S1;
end
end
S1 : begin
if (S12S)begin
next_state = S;
end
else if(S12S11)begin
next_state = S11;
end
end
S11 : begin
if (S112S110)begin
next_state = S110;
end
else if(S112S11)begin
next_state = S11;
end
end
S110 : begin
if (S1102S)begin
next_state = S;
end
else if(S1102B0)begin
next_state = B0;
end
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
if (Count2Count)begin
next_state = Count;
end
else if(Count2Wait)begin
next_state = Wait;
end
end
Wait : begin
if (Wait2Wait)begin
next_state = Wait;
end
else if(Wait2S)begin
next_state = S;
end
end
default next_state = S;
endcase
end
//
reg [3:0] cnt_num;
always@(posedge clk)begin
if(reset)begin
cnt_num <= 0;
end
else begin
case(state)
B0: cnt_num[3] <= data;
B1: cnt_num[2] <= data;
B2: cnt_num[1] <= data;
B3: cnt_num[0] <= data;
default cnt_num <= cnt_num;
endcase
end
end
//计数器
wire done_counting;
reg [31:0] cnt;
wire add_cnt,end_cnt;
always@(posedge clk)begin
if(reset)begin
cnt <= 0;
end
else if(add_cnt)begin
if(end_cnt)begin
cnt <= 0;
end
else begin
cnt <= cnt + 1;
end
end
end
assign add_cnt = state==Count;
assign end_cnt = add_cnt && cnt==(cnt_num+1)*1000-1;
assign done_counting = end_cnt;
//状态跳转控制条件
assign S2S = data == 0;
assign S2S1 = data == 1;
assign S12S = data == 0;
assign S12S11 = data == 1;
assign S112S110 = data == 0;
assign S112S11 = data == 1;
assign S1102S = data == 0;
assign S1102B0 = data == 1;
assign Count2Count = done_counting == 0;
assign Count2Wait = done_counting == 1;
assign Wait2Wait = ack == 0;
assign Wait2S = ack == 1;
//输出信号
assign count = cnt_num - cnt/1000;
assign counting = state==Count;
assign done = state==Wait;
endmodule
7 FSM: One-hot logic equations
题目:
给定以下具有 3 个输入、3 个输出和 10 个状态的状态机:
假设使用以下独热编码,通过检查得出下一状态逻辑方程和输出逻辑方程:(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 - 输出逻辑
-
Counting
-
shift_ena
答案:
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 =4'd0;
parameter S1 =4'd1;
parameter S11 =4'd2;
parameter S110 =4'd3;
parameter B0 =4'd4;
parameter B1 =4'd5;
parameter B2 =4'd6;
parameter B3 =4'd7;
parameter Count =4'd8;
parameter Wait =4'd9;
//输出信号
assign B3_next = state[B2];
assign S_next = (state[S] && d==0) ||
(state[S1] && d==0) || (state[S110] && d==0) || (state[Wait] && ack==1);
assign S1_next = state[S] && d==1;
assign Count_next = state[B3] || (state[Count] && done_counting==0);
assign Wait_next = (state[Count] && done_counting==1) ||
(state[Wait] && ack==0);
assign done = state[Wait];
assign counting = state[Count];
assign shift_ena = (state[B0]) || (state[B1]) || (state[B2]) || (state[B3]);
endmodule
- END -
公z号/CSDN/知乎搜索【望森FPGA】,查看更多FPGA资讯~
相关推荐文章,点击跳转: