实验7 有限状态机
目的:练习使用有限状态机。
Part I
实现一个FSM用于识别2中指定的输入序列:4个1或4个0。输入信号为w,输出为z。当连续4个时钟w=1或0时,z=1;否则,z=0.序列允许重合,比如连续5个时钟w=1,在第4,5个时钟z=1。图1描述了w和z的关系。
状态图如图2所示。用9个触发器,状态编码用独热码,实现本FSM。
在DE2上按以下步骤实现设计:
1. 为FSM项目创建一个新的Quartus II项目。选定目标芯片。
2. 例化9个触发器。只用assign语句指定反馈。注意,独热码便于检查逻辑表达式。使用开关SW0作为FSM的同步复位(低有效)。SW1作为w的输入,按键KEY0作为clock输入。LEDG0作为输出z,状态输出到LEDR8到LEDR0.
3. 分配引脚,编译。
4. 仿真。
5. 仿真正确后,下载验证。
6. 修改。简化设计,因为FPGA的触发器通常包含clear端口且不一定有set端口,便于实现reset状态。将状态A的编码改为全0.如表2所示。修改代码并测试。
代码:
1 /part 1 top module
2 module part1(
3 input [0:0] KEY,
4 input [1:0] SW,
5 output [0:0] LEDG,
6 output [8:0] LEDR
7 );
8
9 sequence_detector u0(
10 .w(SW[1]), //序列检测器的输入信号
11 .clk(KEY[0]), //时钟
12 .rst_n(SW[0]), //复位
13 .z(LEDG[0]), //序列检测器的输出信号
14 .state(LEDR) //FSM的状态,编码方式为独热码
15 );
16
17 endmodule
18
19 //序列检测器,能识别连续输入的4个1或0
20
21 module sequence_detector(
22 input w,clk,rst_n,
23 output z,
24 output [8:0] state
25 );
26
27 wire [8:0] D,Q; //9个触发器的输入/出
28
29 //用9个触发器构成状态机
30 assign D[0]=1'b0; //初始状态A
31 ff da(.d(D[0]),.clk(clk),.rst_n(1'b1),.set_n(rst_n),.q(Q[0]));
32 assign D[1]=(Q[0]|Q[5]|Q[6]|Q[7]|Q[8])&~w; //状态B
33 ff db(.d(D[1]),.clk(clk),.rst_n(rst_n),.set_n(1'b1),.q(Q[1]));
34 assign D[2]=Q[1]&~w; //状态C
35 ff dc(.d(D[2]),.clk(clk),.rst_n(rst_n),.set_n(1'b1),.q(Q[2]));
36 assign D[3]=Q[2]&~w; //状态D
37 ff dd(.d(D[3]),.clk(clk),.rst_n(rst_n),.set_n(1'b1),.q(Q[3]));
38 assign D[4]=(Q[3]|Q[4])&~w; //状态E
39 ff de(.d(D[4]),.clk(clk),.rst_n(rst_n),.set_n(1'b1),.q(Q[4]));
40 assign D[5]=(Q[0]|Q[1]|Q[2]|Q[3]|Q[4])&w; //状态F
41 ff df(.d(D[5]),.clk(clk),.rst_n(rst_n),.set_n(1'b1),.q(Q[5]));
42 assign D[6]=Q[5]&w; //状态G
43 ff dg(.d(D[6]),.clk(clk),.rst_n(rst_n),.set_n(1'b1),.q(Q[6]));
44 assign D[7]=Q[6]&w; //状态H
45 ff dh(.d(D[7]),.clk(clk),.rst_n(rst_n),.set_n(1'b1),.q(Q[7]));
46 assign D[8]=(Q[7]|Q[8])&w; //状态I
47 ff di(.d(D[8]),.clk(clk),.rst_n(rst_n),.set_n(1'b1),.q(Q[8]));
48
49 assign z=Q[4]|Q[8];
50 assign state=Q;
51
52 endmodu
53
54 //具有同步复位和置位功能的dff
55 module ff(
56 input d,clk,rst_n,set_n,
57 output reg q
58 );
59
60 always @(posedge clk)
61 begin
62 if(!rst_n)
63 q<=1'b0;
64 else if(!set_n)
65 q<=1'b1;
66 else
67 q<=d;
68 end
69
70 endmodule
1 module test;
2 reg clk;
3 reg rst_n,w;
4 wire z;
5 wire [8:0] state;
6
7 parameter CLK_PERIOD=20;
8 parameter MULT_RATIO=10;
9 parameter RESET_TIME=CLK_PERIOD*MULT_RATIO+1;
10
11 part1 u1(
12 .KEY(clk),
13 .SW[1](w),
14 .SW[0](rst_n),
15 .LEDG[0](z),
16 .LEDR(state)
17 );
18
19 initial
20 begin
21 rst_n=1'b0;
22 #RESET_TIME rst_n=1'b1;
23 end
24
25 initial
26 begin
27 clk=1'b0;
28 forever
29 #(CLK_PERIOD/2) clk=~clk;
30 end
31
32 initial
33 begin
34 w=1'b0;
35 #(CLK_PERIOD) w=1'b1;
36 #(CLK_PERIOD*2) w=1'b0;
37 #(CLK_PERIOD*3) w=1'b1;
38 #(CLK_PERIOD*5) w=1'b0;
39 #(CLK_PERIOD) w=1'b1;
40 end
41
42 initial
43 #1000 $finish;
44
45 endmodule
修改版:
1 /part 1 top module
2 module part1(
3 input [0:0] KEY,
4 input [1:0] SW,
5 output [0:0] LEDG,
6 output [8:0] LEDR
7 );
8
9 sequence_detector u0(
10 .w(SW[1]), //序列检测器的输入信号
11 .clk(KEY[0]), //时钟
12 .rst_n(SW[0]), //复位
13 .z(LEDG[0]), //序列检测器的输出信号
14 .state(LEDR) //FSM的状态,编码方式为独热码
15 );
16
17 endmodule
18
19 //序列检测器,能识别连续输入的4个1或0
20
21 module sequence_detector(
22 input w,clk,rst_n,
23 output z,
24 output [8:0] state
25 );
26
27 wire [8:0] D,Q; //9个触发器的输入/出
28
29 //用9个触发器构成状态机
30 assign D[0]=1'b1; //初始状态A
31 ff da(.d(D[0]),.clk(clk),.rst_n(rst_n),.q(Q[0]));
32 assign D[1]=(~Q[0]|Q[5]|Q[6]|Q[7]|Q[8])&~w; //状态B
33 ff db(.d(D[1]),.clk(clk),.rst_n(rst_n),.q(Q[1]));
34 assign D[2]=Q[1]&~w; //状态C
35 ff dc(.d(D[2]),.clk(clk),.rst_n(rst_n),.q(Q[2]));
36 assign D[3]=Q[2]&~w; //状态D
37 ff dd(.d(D[3]),.clk(clk),.rst_n(rst_n),.q(Q[3]));
38 assign D[4]=(Q[3]|Q[4])&~w; //状态E
39 ff de(.d(D[4]),.clk(clk),.rst_n(rst_n),.q(Q[4]));
40
41 assign D[5]=(~Q[0]|Q[1]|Q[2]|Q[3]|Q[4])&w; //状态F
42 ff df(.d(D[5]),.clk(clk),.rst_n(rst_n),.q(Q[5]));
43 assign D[6]=Q[5]&w; //状态G
44 ff dg(.d(D[6]),.clk(clk),.rst_n(rst_n),.q(Q[6]));
45 assign D[7]=Q[6]&w; //状态H
46 ff dh(.d(D[7]),.clk(clk),.rst_n(rst_n),.q(Q[7]));
47 assign D[8]=(Q[7]|Q[8])&w; //状态I
48 ff di(.d(D[8]),.clk(clk),.rst_n(rst_n),.q(Q[8]));
49
50 assign z=Q[4]|Q[8];
51 assign state=Q;
52
53 endmodule
54
55 //具有同步复位的dff
56 module ff(
57 input d,clk,rst_n,
58 output reg q
59 );
60
61 always @(posedge clk)
62 begin
63 if(!rst_n)
64 q<=1'b0;
65 else
66 q<=d;
67 end
68
69 endmodule
Part II
本练习要求用另外一种风格描述图2的FSM。用always块和case语句代替手工推导的逻辑表达式。状态编码如表3.
按以下步骤实现电路:
1. 为FSM创建一个新工程。指定目标芯片。
2. 引脚功能:SW0—复位、SW1—w输入、KEY0—clock、LEDG0—z、:LEDR3-0—状态。
3. 编译之前,必须设定综合工具以指定的状态编码实现FSM。选择Assignments > Setting > Analysis and Synthsis 将State Machine Processing 设为User-encoded。
4. 打开RTL Viewer工具查看Quartus II生成的电路。双击电路图中表示状态机的方框图,查看状态图。要查看状态编码,可在编译报告里选择Analysis and Synthesis > State M:achines.
5. 仿真。
6. 下载测试。
7. 修改,在第3步,选择Assignments > Settings > Analysis and Synthesis > State Machine Processing > One-Hot。重新编译,查看区别。
代码:
1 //part2 用always和case描述序列检测器
2
3 module part2(
4 input [0:0] KEY, //clk
5 input [1:0] SW, //SW[1]=w,SW[0]=rst_n
6 output [0:0] LEDG,
7 output [3:0] LEDR
8 );
9
10 wire clk,rst_n,w,z;
11 reg [3:0] q,d; //q表示当前状态,d表示下一个状态
12
13 parameter A=4'b0000,
14 B=4'b0001,
15 C=4'b0010,
16 D=4'b0011,
17 E=4'b0100,
18 F=4'b0101,
19 G=4'b0110,
20 H=4'b0111,
21 I=4'b1000;
22
23 assign clk=KEY[0];
24 assign rst_n=SW[0];
25 assign w=SW[1];
26
27 always @(w,q)
28 begin: state_table
29 case(q)
30 A:
31 if(!w)
32 d=B;
33 else
34 d=F;
35 B:
36 if(!w)
37 d=C;
38 else
39 d=F;
40 C:
41 if(!w)
42 d=D;
43 else
44 d=F;
45 D:
46 if(!w)
47 d=E;
48 else
49 d=F;
50 E:
51 if(!w)
52 d=E;
53 else
54 d=F;
55 F:
56 if(w)
57 d=G;
58 else
59 d=B;
60 G:
61 if(w)
62 d=H;
63 else
64 d=B;
65 H:
66 if(w)
67 d=I;
68 else
69 d=B;
70 I:
71 if(w)
72 d=I;
73 else
74 d=B;
75 default:
76 d=4'bxxxx;
77 endcase
78 end //state_table
79
80 always @(posedge clk)
81 begin: state_FFs
82 if(!rst_n)
83 q<=A;
84 else
85 q<=d;
86 end
87
88 assign z=((q==E)|(q==I))?1'b1:1'b0;
89 assign LEDG[0]=z;
90 assign LEDR[3:0]=q;
91
92 endmodule
93
Part III
本练习用移位寄存器实现序列检测器FSM。例化2个4位的移位寄存器;一个用来识别4个0,另一个用来识别4个1.试问:能否用一个4位的移位寄存器实现上述电路。
代码:
1 //part3 top module
2 module part3(
3 input [0:0] KEY,
4 input [1:0] SW,
5 output [0:0] LEDG,
6 output [7:0] LEDR
7 );
8
9 sequence_detector u1(
10 .clk(KEY),
11 .rst_n(SW[0]),
12 .w(SW[1]),
13 .z(LEDG),
14 .s1(LEDR[7:4]),
15 .s0(LEDR[3:0])
16 );
17
18 endmodule
19
20
21 //part3 use shift reg to implement the fsm
22 module sequence_detector(
23 input w,rst_n,clk,
24 output z,
25 output [3:0] s1,s0 //2个寄存器的状态
26 );
27
28 reg [3:0] shift_reg0,shift_reg1; //2个4-bit移位寄存器
29
30 always @(posedge clk)
31 begin
32 if(!rst_n)
33 begin
34 shift_reg0<=4'b1111;
35 shift_reg1<=4'b0000;
36 end
37 else
38 begin
39 shift_reg0<={shift_reg0[2:0],w};
40 shift_reg1<={shift_reg1[2:0],w};
41 end
42 end
43
44 assign z=((shift_reg0==4'b0000)|(shift_reg1==4'b1111))?1'b1:1'b0;
45 assign s1=shift_reg1;
46 assign s0=shift_reg0;
47
48 endmodule
本练习本能只用一个移位寄存器实现,因为复位的状态必须有全1或全0两种。
Part IV
设计一个类模10的计数器,复位清零,输入信号w1,w0的组合控制计数操作,
w1w0 |
操作 |
00 |
不变 |
01 |
+1 |
10 |
+2 |
11 |
-1 |
对应DE2上的引脚功能
SW0 |
rst_n |
SW2-1 |
w1-0 |
KEY0 |
clk |
HEX0 |
显示计数结果 |
代码:
1 //modulo-10 counter
2
3 module part4(
4 input [2:0] SW,
5 input [0:0] KEY,
6 output [0:6] HEX0
7 );
8
9 wire w1,w0,rst_n,clk;
10 reg [3:0] cnt; //模10计数器输出
11 reg [3:0] q,d; //FSM的现态和次态
12
13 parameter A=4'd0,
14 B=4'd1,
15 C=4'd2,
16 D=4'd3,
17 E=4'd4,
18 F=4'd5,
19 G=4'd6,
20 H=4'd7,
21 I=4'd8,
22 J=4'd9;
23
24 always @(posedge clk)
25 begin
26 if(!rst_n)
27 q<=A;
28 else
29 q<=d;
30 end
31
32 always @({w1,w0},q)
33 begin
34 case(q)
35 A:
36 case({w1,w0})
37 2'b00:d=A;
38 2'b01:d=B;
39 2'b10:d=C;
40 2'b11:d=J;
41 endcase
42 B:
43 case({w1,w0})
44 2'b00:d=B;
45 2'b01:d=C;
46 2'b10:d=D;
47 2'b11:d=A;
48 endcase
49 C:
50 case({w1,w0})
51 2'b00:d=C;
52 2'b01:d=D;
53 2'b10:d=E;
54 2'b11:d=B;
55 endcase
56 D:
57 case({w1,w0})
58 2'b00:d=D;
59 2'b01:d=E;
60 2'b10:d=F;
61 2'b11:d=C;
62 endcase
63 E:
64 case({w1,w0})
65 2'b00:d=E;
66 2'b01:d=F;
67 2'b10:d=G;
68 2'b11:d=D;
69 endcase
70 F:
71 case({w1,w0})
72 2'b00:d=F;
73 2'b01:d=G;
74 2'b10:d=H;
75 2'b11:d=E;
76 endcase
77 G:
78 case({w1,w0})
79 2'b00:d=G;
80 2'b01:d=H;
81 2'b10:d=I;
82 2'b11:d=F;
83 endcase
84 H:
85 case({w1,w0})
86 2'b00:d=H;
87 2'b01:d=I;
88 2'b10:d=J;
89 2'b11:d=G;
90 endcase
91 I:
92 case({w1,w0})
93 2'b00:d=I;
94 2'b01:d=J;
95 2'b10:d=A;
96 2'b11:d=H;
97 endcase
98 J:
99 case({w1,w0})
100 2'b00:d=J;
101 2'b01:d=A;
102 2'b10:d=B;
103 2'b11:d=I;
104 endcase
105 default:d=4'bxxxx;
106 endcase
107 end
108
109 assign clk=KEY[0];
110 assign {w1,w0}=SW[2:1];
111 assign rst_n=SW[0];
112
113 bcd7seg u0(q,HEX0);
114
115 endmodule
116
117 module bcd7seg(
118 input [3:0] bcd,
119 output reg [0:6] display
120 );
121
122 /*
123 * 0
124 * ---
125 * | |
126 * 5| |1
127 * | 6 |
128 * ---
129 * | |
130 * 4| |2
131 * | |
132 * ---
133 * 3
134 */
135 always @ (bcd)
136 case (bcd)
137 4'h0: display = 7'b0000001;
138 4'h1: display = 7'b1001111;
139 4'h2: display = 7'b0010010;
140 4'h3: display = 7'b0000110;
141 4'h4: display = 7'b1001100;
142 4'h5: display = 7'b0100100;
143 4'h6: display = 7'b1100000;
144 4'h7: display = 7'b0001111;
145 4'h8: display = 7'b0000000;
146 4'h9: display = 7'b0001100;
147 default: display = 7'b1111111;
148 endcase
149 endmodule
Part V
设计一个循环显示HELLO的电路。字符从右向左移动。
用8个7-bit的寄存器组成pipeline。每个寄存器的输出直接驱动7-segment。设计一个FSM控制pipeline:
1) 系统复位后的前8个时钟,插入正确的字符(HELLO)。
2) 完成1)后,将pipeline的最后一个寄存器的输出回馈到第一个寄存器的输入,建立循环。
引脚说明:
KEY0—clk SW0—rst_n
代码:
1 //part5 用pipeline寄存器实现循环显示HELLO
2
3 module part5(
4 input [0:0] KEY, //clk
5 input [0:0] SW, //rst_n
6 output [0:6] HEX7,HEX6,HEX5,HEX4,HEX3,HEX2,HEX1,HEX0
7 );
8
9 wire clk,rst_n;
10 reg [3:0] q,d; //FSM的现态和次态
11 reg [0:6] char; //复位后前8个时钟pipeline寄存器的输入,也是循环显示的内容
12
13 reg pipe_s; //循环启动
14 wire [0:6] pipe_in,pipe_o0,pipe_o1,pipe_o2,pipe_o3,pipe_o4,
15 pipe_o5,pipe_o6,pipe_o7; //pipeline寄存器的输入和输出
16
17 parameter S0=4'd0,S1=4'd1,S2=4'd2,S3=4'd3,S4=4'd4,S5=4'd5,S6=4'd6,
18 S7=4'd7,S8=4'd8; //状态:初始8个,启动pipeline寄存器后1个
19 parameter H=7'b1001000, E = 7'b0110000, L = 7'b1110001, O = 7'b0000001,
20 Blank = 7'b1111111;
21
22 assign clk=KEY[0];
23 assign rst_n=SW[0];
24
25 //状态转换
26 always @(posedge clk)
27 begin
28 if(!rst_n)
29 q<=S0;
30 else
31 q<=d;
32 end
33
34 //状态表
35 always @(q)
36 begin
37 case(q)
38 S0:
39 d<=S1;
40 S1:
41 d<=S2;
42 S2:
43 d<=S3;
44 S3:
45 d<=S4;
46 S4:
47 d<=S5;
48 S5:
49 d<=S6;
50 S6:
51 d<=S7;
52 S7:
53 d<=S8;
54 S8:
55 d<=S8;
56 default:
57 d<=4'bxxxx;
58 endcase
59 end
60
61 //每种状态的输出
62 always @(q)
63 begin
64 pipe_s=1'b0;
65 char=7'bxxx_xxxx;
66 case(q)
67 S0:
68 char=H;
69 S1:
70 char=E;
71 S2:
72 char=L;
73 S3:
74 char=L;
75 S4:
76 char=O;
77 S5:
78 char=Blank;
79 S6:
80 char=Blank;
81 S7:
82 char=Blank;
83 S8:
84 pipe_s=1'b1; //启动循环显示
85 default:
86 d=4'bxxxx;
87 endcase
88 end
89
90 assign pipe_in=(pipe_s==1'b1)?pipe_o7:char;
91
92 //pipeline寄存器
93 reg_p r0(pipe_in,clk,rst_n,pipe_o0);
94 reg_p r1(pipe_o0,clk,rst_n,pipe_o1);
95 reg_p r2(pipe_o1,clk,rst_n,pipe_o2);
96 reg_p r3(pipe_o2,clk,rst_n,pipe_o3);
97 reg_p r4(pipe_o3,clk,rst_n,pipe_o4);
98 reg_p r5(pipe_o4,clk,rst_n,pipe_o5);
99 reg_p r6(pipe_o5,clk,rst_n,pipe_o6);
100 reg_p r7(pipe_o6,clk,rst_n,pipe_o7);
101
102 assign HEX0=pipe_o0,
103 HEX1=pipe_o1,
104 HEX2=pipe_o2,
105 HEX3=pipe_o3,
106 HEX4=pipe_o4,
107 HEX5=pipe_o5,
108 HEX6=pipe_o6,
109 HEX7=pipe_o7;
110
111 endmodule
112
113 module reg_p(
114 input [0:6] r,
115 input clk,rst_n,
116 output reg [0:6] q
117 );
118
119 always @(posedge clk)
120 begin
121 if(!rst_n)
122 q<=7'b111_1111;
123 else
124 q<=r;
125 end
126
127 endmodule
128
129
Part VI
修改part V,使用一个约1s的时钟驱动FSM。
代码:
1 //part6 间隔约1s循环显示HELLO
2
3 module part6(
4 input [0:0] KEY, //rst_n
5 input CLOCK_50, //50 MHz
6 output [0:6] HEX7,HEX6,HEX5,HEX4,HEX3,HEX2,HEX1,HEX0
7 );
8
9 wire clk,rst_n,clk_1;
10 reg [3:0] q,d; //FSM的现态和次态
11 reg [0:6] char; //复位后前8个时钟pipeline寄存器的输入,也是循环显示的内容
12
13 reg pipe_s; //循环启动
14 wire [0:6] pipe_in,pipe_o0,pipe_o1,pipe_o2,pipe_o3,pipe_o4,
15 pipe_o5,pipe_o6,pipe_o7; //pipeline寄存器的输入和输出
16
17 reg [25:0] cnt; //用于分频的计数器
18
19 parameter S0=4'd0,S1=4'd1,S2=4'd2,S3=4'd3,S4=4'd4,S5=4'd5,S6=4'd6,
20 S7=4'd7,S8=4'd8; //状态:初始8个,启动pipeline寄存器后1个
21 parameter H=7'b1001000, E = 7'b0110000, L = 7'b1110001, O = 7'b0000001,
22 Blank = 7'b1111111;
23
24 assign rst_n=KEY[0];
25 assign clk=CLOCK_50;
26
27 //分频,产生约1s的时钟clk_1
28 always @(posedge clk)
29 begin
30 if(!rst_n)
31 cnt<=1'b0;
32 else
33 cnt<=cnt+1;
34 end
35 assign clk_1=~|cnt; //产生约1s的时钟
36
37 //状态转换
38 always @(posedge clk)
39 begin
40 if(!rst_n)
41 q<=S0;
42 else
43 q<=d;
44 end
45
46 //状态表
47 always @(q,clk_1)
48 begin
49 case(q)
50 S0:
51 if(clk_1)
52 d<=S1;
53 else
54 d<=S0;
55 S1:
56 if(clk_1)
57 d<=S2;
58 else
59 d<=S1;
60 S2:
61 if(clk_1)
62 d<=S3;
63 else
64 d<=S2;
65 S3:
66 if(clk_1)
67 d<=S4;
68 else
69 d<=S3;
70 S4:
71 if(clk_1)
72 d<=S5;
73 else
74 d<=S4;
75 S5:
76 if(clk_1)
77 d<=S6;
78 else
79 d<=S5;
80 S6:
81 if(clk_1)
82 d<=S7;
83 else
84 d<=S6;
85 S7:
86 if(clk_1)
87 d<=S8;
88 else
89 d<=S7;
90 S8:
91 d<=S8;
92 default:
93 d<=4'bxxxx;
94 endcase
95 end
96
97 //每种状态的输出
98 always @(q)
99 begin
100 pipe_s=1'b0;
101 char=7'bxxx_xxxx;
102 case(q)
103 S0:
104 char=H;
105 S1:
106 char=E;
107 S2:
108 char=L;
109 S3:
110 char=L;
111 S4:
112 char=O;
113 S5:
114 char=Blank;
115 S6:
116 char=Blank;
117 S7:
118 char=Blank;
119 S8:
120 pipe_s=1'b1; //启动循环显示
121 default:
122 d=4'bxxxx;
123 endcase
124 end
125
126 assign pipe_in=(pipe_s==1'b1)?pipe_o7:char;
127
128 //pipeline寄存器
129 reg_p r0(pipe_in,clk,rst_n,clk_1,pipe_o0);
130 reg_p r1(pipe_o0,clk,rst_n,clk_1,pipe_o1);
131 reg_p r2(pipe_o1,clk,rst_n,clk_1,pipe_o2);
132 reg_p r3(pipe_o2,clk,rst_n,clk_1,pipe_o3);
133 reg_p r4(pipe_o3,clk,rst_n,clk_1,pipe_o4);
134 reg_p r5(pipe_o4,clk,rst_n,clk_1,pipe_o5);
135 reg_p r6(pipe_o5,clk,rst_n,clk_1,pipe_o6);
136 reg_p r7(pipe_o6,clk,rst_n,clk_1,pipe_o7);
137
138 assign HEX0=pipe_o0,
139 HEX1=pipe_o1,
140 HEX2=pipe_o2,
141 HEX3=pipe_o3,
142 HEX4=pipe_o4,
143 HEX5=pipe_o5,
144 HEX6=pipe_o6,
145 HEX7=pipe_o7;
146
147 endmodule
148
149 module reg_p(
150 input [0:6] r,
151 input clk,rst_n,e,
152 output reg [0:6] q
153 );
154
155 always @(posedge clk)
156 begin
157 if(!rst_n)
158 q<=7'b111_1111;
159 else if(e)
160 q<=r;
161 end
162
163 endmodule
Part VII
修改PART VI的设计,用KEY2和KEY1控制字母移动的速度。当按下KEY1,字母移动速度为以前的2倍。当按下KEY2,字母移动速度减为以前的一半。
注意,KEY2和KEY1是防跳变开关,当按下时只产生一个低电平。但是,不知道每个开关按下会保持多久,也就意味着脉冲持续的时间任意长。设计这个电路较好的方法是添加一个FSM,用来响应按键操作。这个FSM的输出随按键变化,直到每次按键结束才继续。这个FSM的输出可作为可变时间间隔电路的一部分。注意,KEY2和KEY1是异步输入,确保在使用这些信号之前与时钟同步。
本练习目标。当电路复位后,字符以1s的间隔移动,连续按下KEY1字符加速滚动,最大1s显示4个字符。连续按下KEY2,字符减速显示,最慢达到4秒滚动一个字符。
代码:
1 //part 7 循环显示HELLO。正常情况下滚动间隔时间为1S,KEY1按下加速,KEY2按下减速。
2
3 module part7(KEY,CLOCK_50,HEX7,HEX6,HEX5,HEX4,HEX3,HEX2,HEX1,HEX0,
4 LEDG);
5 input [2:0] KEY;
6 input CLOCK_50;
7 output [0:6] HEX7,HEX6,HEX5,HEX4,HEX3,HEX2,HEX1,HEX0;
8 output [3:0] LEDG;
9
10
11 wire clk,rst_n,tick;
12 reg [3:0] yq,Yd; //控制pipeline的FSM的现态和次态
13 wire fast,slow; //控制字符滚动的快慢
14 reg [3:0] ysq,Ysd; //第2个FSM的状态,用于产生快慢的时间间隔
15 reg [0:6] char; //循环显示的字符HELLO
16 reg pipe_s; //pipeline的启动标记
17 wire [0:6] pipe_in,pipe0,pipe1,pipe2,pipe3,pipe4,pipe5,pipe6,pipe7;
18 reg var_count_sync;
19 reg [3:0] var_count,Modulus; //可变延迟
20
21 parameter m=23;
22 reg [m-1:0] slow_count;
23
24 assign clk=CLOCK_50;
25 assign rst_n=KEY[0];
26
27 //同步按键输入
28 wire KEY_sync[2:1];
29 regne #(.n(1)) k1(~KEY[1],clk,rst_n,1'b1,KEY_sync[1]);
30 regne #(.n(1)) k2(KEY_sync[1],clk,rst_n,1'b1,fast);
31 regne #(.n(1)) k3(~KEY[2],clk,rst_n,1'b1,KEY_sync[2]);
32 regne #(.n(1)) k4(KEY_sync[2],clk,rst_n,1'b1,slow);
33
34 //产生可变时间间隔的FSM的状态名
35 parameter Sync3=4'b0000, //常规状态
36 Speed3=4'b0001, //1倍速
37 Sync4=4'b0010, //加速
38 Speed4=4'b0011, //2倍速
39 Sync5=4'b0100, //加速
40 Speed5=4'b0101, //4倍速
41 Sync1=4'b0110, //减速
42 Speed1=4'b0111, //1/4倍速
43 Sync2=4'b1000, //减速
44 Speed2=4'b1001; //1/2倍速
45
46 //pipeline FSM的状态
47 parameter S0=4'b0000,
48 S1=4'b0001,
49 S2=4'b0010,
50 S3=4'b0011,
51 S4=4'b0100,
52 S5=4'b0101,
53 S6=4'b0110,
54 S7=4'b0111,
55 S8=4'b1000;
56
57 parameter H=7'b100_1000,
58 E=7'b011_0000,
59 L=7'b111_0001,
60 O=7'b000_0001,
61 Blank=7'b111_1111;
62
63 //产生可变时间间隔的FSM:根据字符滚动的速度分为5个级别,每个级别对应一个状态,相应
64 //的状态由按键按下时开始进入,当按键释放时,改变为相应的速度等级。即完成每次速度变
65 //换,对应按键的按和放,各有2个状态完成(Sync*和Speed*)。
66
67 always @(ysq,fast,slow)
68 begin:state_table_speed
69 case(ysq)
70 Sync5: if(slow|fast) Ysd=Sync5; //等待按键释放
71 else Ysd=Speed5;
72 Speed5: if(!slow) Ysd=Speed5; //4倍速
73 else Ysd=Sync4; //减速
74
75 Sync4: if(slow|fast) Ysd=Sync4; //等待按键释放
76 else Ysd=Speed4;
77 Speed4: if(!slow & !fast) Ysd=Speed4; //保持
78 else if(slow) Ysd=Sync3; //减速
79 else Ysd=Sync5; //加速
80
81 Sync3: if(slow|fast) Ysd=Sync3; //等待按键释放
82 else Ysd=Speed3;
83 Speed3: if(!slow | !fast) Ysd=Speed3;//保持
84 else if(slow) Ysd=Sync2; //减速
85 else Ysd=Sync4; //加速
86
87 Sync2: if(slow|fast) Ysd=Sync2; //等待按键释放
88 else Ysd=Speed2;
89 Speed2: if(!slow | !fast) Ysd=Speed2; //保持
90 else if(slow) Ysd=Sync1; //减速
91 else Ysd=Sync3; //加速
92
93 Sync1: if(slow | fast) Ysd=Sync1;
94 else Ysd=Speed1;
95 Speed1: if(!fast) Ysd=Speed1;
96 else Ysd=Sync2;
97
98 default: Ysd=4'bxxxx;
99 endcase
100 end
101
102 always @(posedge clk)
103 if(!rst_n)
104 ysq<=Sync3; //正常速度的状态
105 else
106 ysq<=Ysd;
107
108 always @(ysq)
109 begin:state_outputs_speed
110 Modulus=4'bxxxx;
111 var_count_sync=1'b1;
112 case(ysq)
113 Sync5: var_count_sync=1'b0;
114 Speed5: Modulus=4'b0000;
115 Sync4: var_count_sync=1'b0;
116 Speed4: Modulus=4'b0001;
117 Sync3: var_count_sync=1'b0;
118 Speed3: Modulus=4'b0011;
119 Sync2: var_count_sync=1'b0;
120 Speed2:Modulus=4'b0110;
121 Sync1: var_count_sync=1'b0;
122 Speed1: Modulus=4'b1100;
123 endcase
124 end
125
126 assign LEDG[3:0]=Modulus;
127
128 //分频产生约0.25s的时钟
129 always @(posedge clk)
130 slow_count<=slow_count+1'b1;
131
132 //产生可变延时的计数
133 always @(posedge clk)
134 if(!var_count_sync)
135 var_count<=0;
136 else if(!slow_count )
137 if(var_count==Modulus)
138 var_count<=0;
139 else
140 var_count<=var_count+1'b1;
141
142
143 assign tick=~|var_count & ~| slow_count & var_count_sync;
144
145 //控制pipeline的状态机
146 always @(yq,tick)
147 begin:state_table
148 case(yq)
149 S0: if(tick) Yd=S1;
150 else Yd=S0;
151 S1: if(tick) Yd=S2;
152 else Yd=S1;
153 S2: if(tick) Yd=S3;
154 else Yd=S2;
155 S3: if(tick) Yd=S4;
156 else Yd=S3;
157 S4: if(tick) Yd=S5;
158 else Yd=S4;
159 S5: if(tick) Yd=S6;
160 else Yd=S5;
161 S6: if(tick) Yd=S7;
162 else Yd=S6;
163 S7: if(tick) Yd=S8;
164 else Yd=S7;
165 S8: Yd=S8;
166 default: Yd=4'bxxxx;
167 endcase
168 end
169
170 always @(posedge clk)
171 if(!rst_n)
172 yq<=S0;
173 else
174 yq<=Yd;
175
176 always @(yq)
177 begin:state_outputs
178 pipe_s=1'b0;
179 char=7'bxxx_xxxx;
180 case(yq)
181 S0:char=H;
182 S1:char=E;
183 S2:char=L;
184 S3:char=L;
185 S4:char=O;
186 S5:char=Blank;
187 S6:char=Blank;
188 S7:char=Blank;
189 S8:pipe_s=1'b1; //启动循环
190 default: Yd=4'bxxxx;
191 endcase
192 end
193
194 assign pipe_in=(pipe_s==1'b0)?char:pipe7;
195 //regne(r,clk,rst_n,e,q);
196 regne p0(pipe_in,clk,rst_n,tick,pipe0);
197 regne p1(pipe0,clk,rst_n,tick,pipe1);
198 regne p2(pipe1,clk,rst_n,tick,pipe2);
199 regne p3(pipe2,clk,rst_n,tick,pipe3);
200 regne p4(pipe3,clk,rst_n,tick,pipe4);
201 regne p5(pipe4,clk,rst_n,tick,pipe5);
202 regne p6(pipe5,clk,rst_n,tick,pipe6);
203 regne p7(pipe6,clk,rst_n,tick,pipe7);
204
205 assign HEX0=pipe0;
206 assign HEX1=pipe1;
207 assign HEX2=pipe2;
208 assign HEX3=pipe3;
209 assign HEX4=pipe4;
210 assign HEX5=pipe5;
211 assign HEX6=pipe6;
212 assign HEX7=pipe7;
213
214 endmodule
215
216 module regne(r,clk,rst_n,e,q);
217 parameter n=7;
218 input [n-1:0] r;
219 input clk,rst_n,e;
220 output reg [n-1:0] q;
221
222 always @(posedge clk)
223 if(!rst_n)
224 q<={n{1'b1}};
225 else if(e)
226 q<=r;
227
228 endmodule
229
230
231
232
PS:part VII的代码似乎还有问题,有待验证。