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

  • 相关阅读:
    还不懂mock测试?一篇文章带你熟悉mock
    android studio历史版本
    文档04_webfrom
    LeetCode 1763. Longest Nice Substring
    LeetCode 2006. Count Number of Pairs With Absolute Difference K
    LeetCode 539. Minimum Time Difference
    LeetCode 2000. Reverse Prefix of Word
    LeetCode 747. Largest Number At Least Twice of Others
    行为面试技巧之 STAR 法则 All In One
    LeetCode 字符串相乘算法题解 All In One
  • 原文地址:https://www.cnblogs.com/halflife/p/2022321.html
Copyright © 2020-2023  润新知