【原创】DE2实验解答—lab7 (Quartus II)(Digital Logic)(Verilog HDL)

实验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的关系。

clip_image002

状态图如图2所示。用9个触发器,状态编码用独热码,实现本FSM。

clip_image004

clip_image006

在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所示。修改代码并测试。

clip_image008

代码:

  
    
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

clip_image010

修改版:

  
    
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.

clip_image012

按以下步骤实现电路:

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

clip_image014

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的代码似乎还有问题,有待验证。

你可能感兴趣的:(Verilog)