目录
以下的解题方法不一定为最佳解决方案,有更好的方法欢迎提出,共同学习,共同进步!
构建一个计数从 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
这是一系列五个练习中的第一个组件,该练习从几个较小的电路中构建一个复杂的计数器。
构建一个四位移位寄存器,该寄存器也可用作向下计数器。当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
这是一系列五个练习中的第二个组件,该练习从几个较小的电路中构建一个复杂的计数器。
构建一个在输入位流中搜索序列 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
这是一系列五个练习中的第三个组件,该练习从几个较小的电路中构建一个复杂的计数器。
作为用于控制移位寄存器的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
这是一系列五个练习中的第四个组件,该练习从几个较小的电路中构建一个复杂的计数器。
想要创建一个计时器,
在这个问题中,只实现控制计时器的有限状态机。此处不包括数据路径(计数器和某些比较器)。
串行数据在数据输入引脚上可用。当接收到模式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
这是一系列五个练习中的第五个组件,该练习从几个较小的电路中构建一个复杂的计数器。
想要创建一个具有一个输入的计时器:
串行数据在数据输入引脚上可用。当接收到码型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
假设使用以下单热编码,则通过检查派生下一状态逻辑方程和输出逻辑方程:(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