目录
写在前面
以下的解题方法不一定为最佳解决方案,有更好的方法欢迎提出,共同学习,共同进步!
Buliding Larger Circuits
count1k
构建一个计数从 0 到 999(包括 0 和 999)的计数器,周期为 1000 个周期。复位输入是同步的,应将计数器复位为0。
module top_module (
input clk,
input reset,
output [9:0] q
);
always @(posedge clk) begin
if (reset) begin
q <= 'd0;
end
else if (q=='d999) begin
q <= 'd0;
end
else begin
q <= q + 'd1;
end
end
endmodule
shiftcount
这是一系列五个练习中的第一个组件,该练习从几个较小的电路中构建一个复杂的计数器。
构建一个四位移位寄存器,该寄存器也可用作向下计数器。当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 [3:0] q
);
always @(posedge clk) begin
if (shift_ena) begin
q <= {q[2:0],data};
end
else if (count_ena) begin
q <= q - 'd1;
end
else begin
q <= q;
end
end
endmodule
fsm seq
这是一系列五个练习中的第二个组件,该练习从几个较小的电路中构建一个复杂的计数器。
构建一个在输入位流中搜索序列 1101 的有限状态机。找到序列后,应将 start_shifting 设置为 1,直到重置。陷入最终状态的目的是模拟在尚未实现的更大的FSM中进入其他状态。我们将在接下来的几个练习中扩展此 FSM。
module top_module (
input clk,
input reset, // Synchronous reset
input data,
output start_shifting
);
//状态申明
parameter IDLE = 'd1;
parameter A_1 = 'd2;
parameter B_1 = 'd3;
parameter C_0 = 'd4;
parameter D_1 = 'd5;
//现态和次态
reg [2:0] state;
reg [2:0] next_state;
//状态机第一段,状态初始化,时序逻辑非阻塞赋值
always @(posedge clk) begin
if (reset) begin
state <= IDLE;
end
else begin
state <= next_state;
end
end
//状态机第二段,状态跳转,阻塞赋值
always @(*) begin
next_state = state;
case(state)
IDLE: begin
if (data) begin
next_state = A_1;
end
else begin
next_state = IDLE;
end
end
A_1: begin
if (data) begin
next_state = B_1;
end
else begin
next_state = IDLE;
end
end
B_1: begin
if (~data) begin
next_state = C_0;
end
else begin
next_state = B_1;
end
end
C_0: begin
if (data) begin
next_state = D_1;
end
else begin
next_state = IDLE;
end
end
D_1: begin
next_state = D_1;
end
default: begin
next_state = IDLE;
end
endcase
end
//状态机第三段,结果输出,组合逻辑
assign start_shifting = (state==D_1);
endmodule
fsmshift
这是一系列五个练习中的第三个组件,该练习从几个较小的电路中构建一个复杂的计数器。
作为用于控制移位寄存器的FSM的一部分,我们希望能够在检测到正确的位模式时使移位寄存器精确4个时钟周期,考虑前面的处理序列检测,因此 FSM 的这一部分仅处理启用移位寄存器 4 个周期。
每当FSM复位时,置位shift_ena 4个周期,然后永远为0(直到复位)。
module top_module (
input clk,
input reset, // Synchronous reset
output shift_ena
);
reg [1:0] cnt;
always @(posedge clk) begin
if (reset) begin
cnt <= 'd0;
end
else begin
cnt <= cnt + 'd1;
end
end
always @(posedge clk) begin
if (reset) begin
shift_ena <= 'd1;
end
else if (cnt=='d3) begin
shift_ena <= 'd0;
end
else begin
shift_ena <= shift_ena;
end
end
endmodule
fsm
这是一系列五个练习中的第四个组件,该练习从几个较小的电路中构建一个复杂的计数器。
想要创建一个计时器,
- 在检测到特定模式 (1101) 时启动,
- 再移位 4 位,以确定延迟的持续时间,
- 等待计数器完成计数,以及
- 通知用户并等待用户确认计时器。
在这个问题中,只实现控制计时器的有限状态机。此处不包括数据路径(计数器和某些比较器)。
串行数据在数据输入引脚上可用。当接收到模式1101时,状态机必须断言输出shift_ena正好4个时钟周期。
之后,状态机断言其计数输出以指示它正在等待计数器,并等待输入done_counting为高电平。
此时,状态机必须断言 done 以通知用户计时器已超时,并等到输入 ack 为 1,然后重置以查找下一个匹配的开始序列 (1101)。
状态机应重置为开始搜索输入序列1101的状态。
下面是预期输入和输出的示例。“x”状态可能读起来有点混乱。它们表明,密克罗尼西亚联邦不应关心该周期中的特定输入信号。例如,一旦检测到 1101 模式,FSM 将不再查看数据输入,直到完成其他所有操作后恢复搜索。
module top_module (
input clk,
input reset, // Synchronous reset
input data,
input ack,
input done_counting,
output shift_ena,
output counting,
output done
);
//状态申明
parameter IDLE = 'd1;
parameter A_1 = 'd2;
parameter B_1 = 'd3;
parameter C_0 = 'd4;
parameter CNT_1 = 'd5;
parameter CNT_2 = 'd6;
parameter CNT_3 = 'd7;
parameter CNT_4 = 'd8;
parameter CNT = 'd9;
parameter WAIT = 'd10;
//现态和次态
reg [3:0] state;
reg [3:0] next_state;
//状态机第一段,状态初始化,时序逻辑非阻塞赋值
always @(posedge clk) begin
if (reset) begin
state <= IDLE;
end
else begin
state <= next_state;
end
end
//状态机第二段,状态跳转,阻塞赋值
always @(*) begin
next_state = state;
case(state)
IDLE: begin
if (data) begin
next_state = A_1;
end
else begin
next_state = IDLE;
end
end
A_1: begin
if (data) begin
next_state = B_1;
end
else begin
next_state = IDLE;
end
end
B_1: begin
if (~data) begin
next_state = C_0;
end
else begin
next_state = B_1;
end
end
C_0: begin
if (data) begin
next_state = CNT_1;
end
else begin
next_state = IDLE;
end
end
CNT_1: begin
next_state = CNT_2;
end
CNT_2: begin
next_state = CNT_3;
end
CNT_3: begin
next_state = CNT_4;
end
CNT_4: begin
next_state = CNT;
end
CNT: begin
if (done_counting) begin
next_state = WAIT;
end
else begin
next_state = CNT;
end
end
WAIT: begin
if (ack) begin
next_state = IDLE;
end
else begin
next_state = WAIT;
end
end
default: begin
next_state = IDLE;
end
endcase
end
//状态机第三段,结果输出,组合逻辑
assign shift_ena = (state==CNT_1) | (state==CNT_2) | (state==CNT_3) | (state==CNT_4);
assign counting = state==CNT;
assign done = state==WAIT;
endmodule
fancytimer
这是一系列五个练习中的第五个组件,该练习从几个较小的电路中构建一个复杂的计数器。
想要创建一个具有一个输入的计时器:
- 当检测到特定输入模式 (1101) 时启动,
- 再移位 4 位,以确定延迟的持续时间,
- 等待计数器完成计数,以及
- 通知用户并等待用户确认计时器。
串行数据在数据输入引脚上可用。当接收到码型1101时,电路必须在接下来的4位中移位,最高有效位在先。这 4 位决定了定时器延迟的持续时间。我把它称为延迟[3:0]。
之后,状态机断言其计数输出以指示它正在计数。状态机必须精确计数(延迟[3:0] + 1)* 1000个时钟周期。例如,delay=0 表示计数 1000 个周期,delay=5 表示计数 6000 个周期。同时输出当前剩余时间。这应该等于延迟 1000 个周期,然后延迟-1 表示 1000 个周期,依此类推,直到 0 表示 1000 个周期。当电路不计数时,计数[3:0]输出是“不在乎”(任何值都方便你实现)。
此时,电路必须断言完成以通知用户计时器已超时,并等到输入ack为1,然后重置以查找下一个出现的开始序列(1101)。
电路应复位到开始搜索输入序列1101的状态。
下面是预期输入和输出的示例。“x”状态可能读起来有点混乱。它们表明,密克罗尼西亚联邦不应关心该周期中的特定输入信号。例如,一旦读取了1101和延迟[3:0],电路就不再查看数据输入,直到完成其他所有操作后恢复搜索。在本例中,电路计数为 2000 个时钟周期,因为延迟 [3:0] 值为 4'b0001。最后几个周期以延迟[3:0] = 4'b1110开始另一个计数,这将计数15000个周期。
module top_module (
input clk,
input reset, // Synchronous reset
input data,
input ack,
output [3:0] count,
output counting,
output done
);
//状态申明
parameter IDLE = 'd1;
parameter A_1 = 'd2;
parameter B_1 = 'd3;
parameter C_0 = 'd4;
parameter SHIFT_1 = 'd5;
parameter SHIFT_2 = 'd6;
parameter SHIFT_3 = 'd7;
parameter SHIFT_4 = 'd8;
parameter CNT = 'd9;
parameter WAIT = 'd10;
//现态和次态
reg [3:0] state;
reg [3:0] next_state;
reg [3:0] delay;
reg [15:0] delay_cnt;
reg [3:0] delay_num;
wire delay_cnt_done;
//当计数到设定的计数值时,将延时计数完成标志信号拉高
assign delay_cnt_done = (delay_cnt == ((delay + 'd1) * 'd1000))?'d1:'d0;
//状态机第一段,状态初始化,时序逻辑非阻塞赋值
always @(posedge clk) begin
if (reset) begin
state <= IDLE;
end
else begin
state <= next_state;
end
end
//状态机第二段,状态跳转,阻塞赋值
always @(*) begin
next_state = state;
case(state)
IDLE: begin
if (data) begin
next_state = A_1;
end
else begin
next_state = IDLE;
end
end
A_1: begin
if (data) begin
next_state = B_1;
end
else begin
next_state = IDLE;
end
end
B_1: begin
if (~data) begin
next_state = C_0;
end
else begin
next_state = B_1;
end
end
C_0: begin
if (data) begin
next_state = SHIFT_1;
end
else begin
next_state = IDLE;
end
end
SHIFT_1: begin
next_state = SHIFT_2;
delay[3] = data;
end
SHIFT_2: begin
next_state = SHIFT_3;
delay[2] = data;
end
SHIFT_3: begin
next_state = SHIFT_4;
delay[1] = data;
end
SHIFT_4: begin
next_state = CNT;
delay[0] = data;
end
CNT: begin
if (delay_cnt_done) begin
next_state = WAIT;
end
else begin
next_state = CNT;
end
end
WAIT: begin
if (ack) begin
next_state = IDLE;
end
else begin
next_state = WAIT;
end
end
default: begin
next_state = IDLE;
end
endcase
end
//delay_cnt
always @(posedge clk) begin
if (reset) begin
delay_cnt <= 'd0;
end
else if (next_state == WAIT) begin
delay_cnt <= 'd0;
end
else if (next_state == CNT) begin
delay_cnt <= delay_cnt + 'd1;
end
else begin
delay_cnt <= delay_cnt;
end
end
//对于延时计数的范围值,确定具体的count值
always @(*) begin
if (delay_cnt <= 'd1000) begin
delay_num = 'd0;
end
else if (delay_cnt > 'd1000 && delay_cnt <= 'd2000) begin
delay_num = 'd1;
end
else if (delay_cnt > 'd2000 && delay_cnt <= 'd3000) begin
delay_num = 'd2;
end
else if (delay_cnt > 'd3000 && delay_cnt <= 'd4000) begin
delay_num = 'd3;
end
else if (delay_cnt > 'd4000 && delay_cnt <= 'd5000) begin
delay_num = 'd4;
end
else if (delay_cnt > 'd5000 && delay_cnt <= 'd6000) begin
delay_num = 'd5;
end
else if (delay_cnt > 'd6000 && delay_cnt <= 'd7000) begin
delay_num = 'd6;
end
else if (delay_cnt > 'd7000 && delay_cnt <= 'd8000) begin
delay_num = 'd7;
end
else if (delay_cnt > 'd8000 && delay_cnt <= 'd9000) begin
delay_num = 'd8;
end
else if (delay_cnt > 'd9000 && delay_cnt <= 'd10000) begin
delay_num = 'd9;
end
else if (delay_cnt > 'd10000 && delay_cnt <= 'd11000) begin
delay_num = 'd10;
end
else if (delay_cnt > 'd11000 && delay_cnt <= 'd12000) begin
delay_num = 'd11;
end
else if (delay_cnt > 'd12000 && delay_cnt <= 'd13000) begin
delay_num = 'd12;
end
else if (delay_cnt > 'd13000 && delay_cnt <= 'd14000) begin
delay_num = 'd13;
end
else if (delay_cnt > 'd14000 && delay_cnt <= 'd15000) begin
delay_num = 'd14;
end
else if (delay_cnt > 'd15000 && delay_cnt <= 'd16000) begin
delay_num = 'd15;
end
else begin
delay_num = 'd0;
end
end
//状态机第三段,结果输出,组合逻辑
assign count = (state == CNT)?(delay - delay_num):'d0;
assign counting = (state == CNT);
assign done = (state == WAIT);
endmodule
fsm onehot
假设使用以下单热编码,则通过检查派生下一状态逻辑方程和输出逻辑方程:(S,S1,S11,S110,B0,B1,B2,B3,计数,等待)= (10'b0000000001,10'b00000000010,10'b00000000100,...,10'b10000000000)
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;
assign B3_next = (state[B2]);
assign S_next = (state[S] && ~d) | (state[S1] && ~d) | (state[S110] && ~d) | (state[Wait] && ack);
assign S1_next = (state[S] && d);
assign Count_next = (state[B3] | (state[Count] && ~done_counting));
assign Wait_next = (state[Count] && done_counting) | (state[Wait] && ~ack);
assign done = state[Wait];
assign counting = state[Count];
assign shift_ena = (state[B0] | state[B1] | state[B2] | state[B3]);
endmodule