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

  • 相关阅读:
    弄清变量名字空间
    Perl中文编码的处理
    了解魔符的含义
    Log::Minimal 小型可定制的log模块
    Perl – 文件测试操作符
    在源代码中使用Unicode字符
    editplus乱码charset的奇怪问题
    ASP.NET程序中常用代码汇总(一)
    ASP.NET程序中常用代码汇总(三)
    ASP.NET程序中常用代码汇总(二)
  • 原文地址:https://www.cnblogs.com/halflife/p/2022321.html
Copyright © 2020-2023  润新知