基于有限状态机的计数器

HDLBits链接


前言

今天更新搭建更大的电路部分的习题,内容主要跟计数器和有限状态机有关。


题库

Counter with period 1000

构造一个0-999的计数器,同步高电平复位。

Solution

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
module top_module (
input clk,
input reset,
output [9:0] q);

always @(posedge clk) begin
if(reset) begin
q <= 10'd0;
end
else if(q == 10'd999) begin
q <= 10'd0;
end
else begin
q <= q + 1'b1;
end
end

endmodule

4-bit shift register and down counter

构造一个4bit的移位寄存器,同时也可以做倒数的计数器使用。其中当shift_ena为1时数据data的高位先进到移位寄存器中;当count_ena为1时,计数器从寄存器中存储的数开始逐时钟递减;shift_enacount_ena没有重要级先后顺序,因为他们不会同时使能。

1

Solution:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
module top_module (
input clk,
input shift_ena,
input count_ena,
input data,
output [3:0] q);

reg [3:0] q_temp;

always @(posedge clk) begin
if(shift_ena) begin
q_temp <= {q_temp[2:0],data};
end
else if(count_ena) begin
if(q_temp == 4'd0) begin
q_temp <= 4'd15;
end
else begin
q_temp <= q_temp - 1'b1;
end
end
end

assign q = q_temp;

endmodule

我以为计数器到0时停止计数,本来按这个逻辑写的,然后在线提交时出错。作者的意思是0后面下一个状态是15,这个大家做题时需注意。

FSM:Sequence 1101 recognizer

构造一个有限状态机检测data中的1101序列,如果检测到该序列,则将输出一直拉高直到同步复位信号为高。

2

Solution

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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) begin
current_state <= IDLE;
end
else begin
current_state <= next_state;
end
end

assign start_shifting = current_state == OUT;

endmodule

FSM:Enable shift register

当有限状态机被复位时,将shift_ena拉高4个周期,之后保持为0直到再次复位。

3

Solution

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
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 [2:0] counter;

always @(*) begin
case(current_state)
IDLE: next_state = ENA;
ENA: next_state = (counter == 3'd3) ? STOP : ENA;
STOP: next_state = STOP;
default: next_state = IDLE;
endcase
end

always @(posedge clk) begin
if(reset) begin
current_state <= IDLE;
end
else begin
current_state <= next_state;
end
end

always @(posedge clk) begin
if(reset) begin
counter <= 3'd0;
end
else begin
case(next_state)
IDLE: counter <= 3'd0;
ENA: counter <= counter + 1'b1;
STOP: counter <= 3'd0;
default: counter <= 3'd0;
endcase
end
end

assign shift_ena = current_state == ENA | current_state == IDLE;

endmodule

需注意的是复位一直为高的时候输出也一直为高电平;

FSM:The complete FSM

4

官方提供的状态转移图

5

Solution

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
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;
parameter B0 = 4'd4, B1 = 4'd5, B2 = 4'd6, B3 = 4'd7;
parameter 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) begin
current_state <= S;
end
else begin
current_state <= next_state;
end
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

标准的FSM格式,没啥说的,画出状态转移表写就行了。

The complete timer

该道状态机就是前面几道状态机的组合,大家需注意的是计数那边的部分;之前我将计数子的位宽设置不当,导致这题卡的挺久,希望大家做题分析时注意。

6

Solution

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
module top_module (
input clk,
input reset, // Synchronous reset
input data,
output [3:0] count,
output counting,
output done,
input ack );

parameter IDLE = 4'd0, S1 = 4'd1, S2 = 4'd2, S3 = 4'd3;
parameter C0 = 4'd4, C1 = 4'd5, C2 = 4'd6, C3 = 4'd7;
parameter Count_1000 = 4'd8, Done = 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)*1000) ? 1'b1 : 1'b0;

always @(*) begin
if(num <= 16'd1000) begin
already_count = 4'd0;
end
else if(num > 16'd1000 && num <= 16'd2000) begin
already_count = 4'd1;
end
else if(num > 16'd2000 && num <= 16'd3000) begin
already_count = 4'd2;
end
else if(num > 16'd3000 && num <= 16'd4000) begin
already_count = 4'd3;
end
else if(num > 16'd4000 && num <= 16'd5000) begin
already_count = 4'd4;
end
else if(num > 16'd5000 && num <= 16'd6000) begin
already_count = 4'd5;
end
else if(num > 16'd6000 && num <= 16'd7000) begin
already_count = 4'd6;
end
else if(num > 16'd7000 && num <= 16'd8000) begin
already_count = 4'd7;
end
else if(num > 16'd8000 && num <= 16'd9000) begin
already_count = 4'd8;
end
else if(num > 16'd9000 && num <= 16'd10000) begin
already_count = 4'd9;
end
else if(num > 16'd10000 && num <= 16'd11000) begin
already_count = 4'd10;
end
else if(num > 16'd11000 && num <= 16'd12000) begin
already_count = 4'd11;
end
else if(num > 16'd12000 && num <= 16'd13000) begin
already_count = 4'd12;
end
else if(num > 16'd13000 && num <= 16'd14000) begin
already_count = 4'd13;
end
else if(num > 16'd14000 && num <= 16'd15000) begin
already_count = 4'd14;
end
else begin
already_count = 4'd15;
end
end

always @(posedge clk) begin
if(reset) begin
num <= 16'd0;
end
else if(next_state == Done) begin
num <= 16'd0;
end
else if(next_state == Count_1000) begin
num <= num + 16'd1;
end
end

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 ? C0 : IDLE;
C0:begin
next_state = C1;
delay[3] = data;
end
C1:begin
next_state = C2;
delay[2] = data;
end
C2:begin
next_state = C3;
delay[1] = data;
end
C3:begin
next_state = Count_1000;
delay[0] = data;
end
Count_1000: next_state = count_state ? Done : Count_1000;
Done: next_state = ack ? IDLE : Done;
default: next_state = IDLE;
endcase
end

always @(posedge clk) begin
if(reset) begin
current_state <= IDLE;
end
else begin
current_state <= next_state;
end
end

assign count = (current_state == Count_1000) ? (delay - already_count) : 4'd0;
assign counting = (current_state == Count_1000);
assign done = current_state == Done;

endmodule

FSM:One-hot logic equations

用one-hot编码的状态写出状态转移代码。

7

Solution

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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

结语

该小结就算更新结束了,下面剩的也不多了。如有不对的还望大家指正。