FPGA project: complex_fsm

module top (
    input wire sys_clk,
    input wire sys_rst_n ,
    input wire one,
    input wire half,

    output wire [03:00] led
);

    wire one_out_w;
    wire half_out_w;
    wire po_cola;
    wire po_money;
key_filter key_filter_insert(
    .sys_clk (sys_clk),
    .sys_rst_n (sys_rst_n),
    .one (one) ,
    .half ( half ) ,

    .one_out ( one_out_w ) ,
    .half_out (half_out_w)
);

complex_fsm complex_fsm_insert (
    .sys_clk (sys_clk),
    .sys_rst_n (sys_rst_n),
    .money_one ( one_out_w ) ,
    .money_half ( half_out_w) ,

    .po_cola ( po_cola ) ,
    .po_money ( po_money ) ,
    .led (led)
);


endmodule

module key_filter
#(
    parameter MAX_CNT_20MS = 20'd100_0000
)(
    input wire sys_clk,
    input wire sys_rst_n ,
    input wire one,
    input wire half,

    output reg one_out ,
    output reg half_out
);
/****************************************************** ****
* What are the elements of a counter?
* 1 Conditions for starting counting. When to start counting?
* 2 Conditions for counting to zero When to end counting
* 3 Bit width of counting register
*Key points:
* How to generate these two conditions is the key.
************************************************* **/
    // wire define
    wire [01:00] key;

    wire nege;
    wire pose;
    wire add_cnt_20ms;
    wire end_cnt_20ms;

    //regdefine
    reg [19:00] cnt_20ms;
    reg [01:00] key_r1;
    reg [01:00] key_r2;
    reg add_cnt_flag;

    // key
    assign key = {one, half};
    // key_r1
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) begin
            key_r1 <= 1'b1;
        end else begin
            key_r1 <= key ;
        end
    end
    // key_r2
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) begin
            key_r2 <= 1'b1;
        end else begin
            key_r2 <= key_r1;
        end
    end

    // nege pose
    assign nege = | ( ~key_r1 & amp; key_r2 ) ; // Both require bitwise operations
    assign pose = | ( key_r1 & amp; ~key_r2 ) ;

    // add_cnt_flag
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) begin
            add_cnt_flag <= 1'b0;
        end else begin
            if(nege) begin
                add_cnt_flag <= 1'b1;
            end else begin
                if( pose || end_cnt_20ms ) begin
                    add_cnt_flag <= 1'b0;
                end else begin
                    add_cnt_flag <= add_cnt_flag;
                end
            end
        end
    end

    // cnt_20ms add_cnt_20ms end_cnt_20ms
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) begin
            cnt_20ms <= 20'd0;
        end else begin
            if(add_cnt_20ms) begin
                if(end_cnt_20ms) begin
                    cnt_20ms <= 20'd0;
                end else begin
                    cnt_20ms <= cnt_20ms + 20'd1;
                end
            end else begin
                cnt_20ms <= 20'd0;
            end
        end
    end
    assign add_cnt_20ms = add_cnt_flag;
    assign end_cnt_20ms = add_cnt_20ms & amp; & amp; cnt_20ms == ( MAX_CNT_20MS - 1'b1 ) ;

    // one_out
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) begin
            one_out <= 1'b0;
        end else begin
            if(end_cnt_20ms) begin
                one_out <= ~key_r2[1];
            end else begin
                one_out <= 1'b0;
            end
        end
    end

    // half_out
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) begin
            half_out <= 1'b0;
        end else begin
            if(end_cnt_20ms) begin
                half_out <= ~key_r2[0];
            end else begin
                half_out <= 1'b0;
            end
        end
    end
endmodule

// `timescale 1ns/1ns
//
// // Author : EmbedFire
// // Create Date : 2019/03/15
// // Module Name : key_filter
// // Project Name : key_filter
// // Target Devices: Altera EP4CE10F17C8N
// // Tool Versions: Quartus 13.0
// // Description: Button debounce module
// //
// // Revision : V1.0
// // Additional Comments:
// //
// // Experimental platform: Wildfire_Zhengtu Pro_FPGA development board
// // Company: http://www.embedfire.com
// // Forum: http://www.firebbs.cn
// // Taobao: https://fire-stm32.taobao.com
//


// module key_filter
// #(
// parameter CNT_MAX = 20'd999_999 //Maximum value of counter count
// )
//(
// input wire sys_clk, // system clock 50Mhz
// input wire sys_rst_n , //global reset
// input wire key_in, //key input signal

//output reg key_flag //When key_flag is 1, it means that the key is detected after debounce.
// //When key_flag is 0, it means that no key has been detected.
// );

// //********************************************** ************************//
// //****************** Parameter and Internal Signal *******************//
// //********************************************** ************************//
// //reg define
// reg [19:0] cnt_20ms; //Counter

// //********************************************** ************************//
// //**************************** Main Code *************** *************//
// //********************************************** ************************//

// //cnt_20ms: If the rising edge of the clock detects that the value of the external key input is low, the counter starts counting.
// always@(posedge sys_clk or negedge sys_rst_n)
// if(sys_rst_n == 1'b0)
// cnt_20ms <= 20'b0;
// else if(key_in == 1'b1)
// cnt_20ms <= 20'b0;
// else if(cnt_20ms == CNT_MAX & amp; & amp; key_in == 1'b0)
// cnt_20ms <= cnt_20ms;
//else
// cnt_20ms <= cnt_20ms + 1'b1;

// //key_flag: The key valid flag is generated when the count reaches 20ms.
// //And key_flag is pulled high at 999_999 and maintained at a high level for one clock
// always@(posedge sys_clk or negedge sys_rst_n)
// if(sys_rst_n == 1'b0)
// key_flag <= 1'b0;
// else if(cnt_20ms == CNT_MAX - 1'b1)
// key_flag <= 1'b1;
//else
// key_flag <= 1'b0;

// endmodule
module complex_fsm
#(
    parameter CNT_1US = 6'd50 ,
              CNT_1K = 10'd1000
)(
    input wire sys_clk,
    input wire sys_rst_n ,
    input wire money_one,
    input wire money_half,

    output reg po_cola ,
    output reg po_money ,
    output reg [03:00] led
);
    // define wire signal
    wire [01:00] money;
    wire clear;
    //define reg signal
    reg [06:00] state ;
    regctrl;
    reg [03:00] water_led;
    // counter
    reg [05:00] cnt_1us;
    wire add_cnt_1us;
    wire end_cnt_1us;
    reg [09:00] cnt_1ms;
    wire add_cnt_1ms;
    wire end_cnt_1ms;
    reg [09:00] cnt_1s;
    wire add_cnt_1s;
    wire end_cnt_1s;
    reg [03:00] cnt_10s;
    wire add_cnt_10s;
    wire end_cnt_10s;
    //define localparam
    localparam IDLE = 7'b0000001 ,
                        HALF = 7'b0000010 ,
                        ONE = 7'b0000100 ,
                        ONE_HALF = 7'b0001000 ,
                        TWO = 7'b0010000 ,
                        WATER_R = 7'b0100000 ,
                        WATER_C = 7'b1000000;
    // money
    // assign money = ( money_half ) ? 2'b01 : ( money_one ) ? 2'b10 : 2'b00 ;
assign money = {money_one,money_half};
    // counter
    // cnt_1us
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) begin
            cnt_1us <= 0 ;
        end else begin
            if(clear) begin
                cnt_1us <= 0 ;
            end else begin
                if(add_cnt_1us) begin // The state machine starts counting in the non-IDLE state
                    if(end_cnt_1us) begin // The state machine needs to be cleared and counted again after the state transition and after it is full.
                        cnt_1us <= 0 ;
                    end else begin
                        cnt_1us <= cnt_1us + 1'b1;
                    end
                end else begin
                    cnt_1us <= 0; // The count value of the state machine returns to zero in the IDLE state
                end
            end
        end
    end
    assign clear = (state != IDLE & amp; & amp; state != WATER_R & amp; & amp; state != WATER_C & amp; & amp; money != 2'b00) ;
    assign add_cnt_1us = state != IDLE ;
    assign end_cnt_1us = add_cnt_1us & amp; & amp; cnt_1us == ( CNT_1US - 1'b1 );
                                                        //|| (state == WATER_R & amp; & amp; end_cnt_10s) || (state == WATER_C & amp; & amp; end_cnt_10s) Since it will be reset to zero when entering IDLE, there is no need to write these two sentences.
    // cnt_1ms
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) begin
            cnt_1ms <= 0 ;
        end else begin
            if(clear) begin
                cnt_1ms <= 0 ;
            end else begin
                if(add_cnt_1ms) begin
                    if(end_cnt_1ms) begin
                        cnt_1ms <= 0 ;
                    end else begin
                        cnt_1ms <= cnt_1ms + 1'b1;
                    end
                end else begin
                    cnt_1ms <= cnt_1ms; // Obviously it cannot be reset to zero here and needs to be maintained.
                end
            end
        end
    end
    assign add_cnt_1ms = end_cnt_1us; // cascade
    assign end_cnt_1ms = add_cnt_1ms & amp; & amp; cnt_1ms == ( CNT_1K - 1'b1 ) ;
    // cnt_1s
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) begin
            cnt_1s <= 0 ;
        end else begin
            if(clear) begin
                cnt_1s <= 0 ;
            end else begin
                if(add_cnt_1s) begin
                    if(end_cnt_1s) begin
                        cnt_1s <= 0 ;
                    end else begin
                        cnt_1s <= cnt_1s + 1'b1;
                    end
                end else begin
                    cnt_1s <= cnt_1s ;
                end
            end
        end
    end
    assign add_cnt_1s = end_cnt_1ms;
    assign end_cnt_1s = add_cnt_1s & amp; & amp; cnt_1s == ( CNT_1K - 1'b1 ) ;
    // cnt_10s
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) begin
            cnt_10s <= 0 ;
        end else begin
            if(clear) begin
                cnt_10s <= 0 ;
            end else begin
                if(add_cnt_10s) begin
                    if(end_cnt_10s) begin
                        cnt_10s <= 0 ;
                    end else begin
                        cnt_10s <= cnt_10s + 1'b1;
                    end
                end else begin
                    cnt_10s <= cnt_10s ;
                end
            end
        end
    end
    assign add_cnt_10s = end_cnt_1s;
    assign end_cnt_10s = add_cnt_10s & amp; & amp; cnt_10s == ( 4'd10 - 4'b1 ) ;
    // state
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) begin
            state <= IDLE ;
        end else begin
            case(state)
            IDLE: begin
                if(money == 2'b01) begin
                    state <= HALF ;
                end else begin
                    if(money == 2'b10) begin
                        state <= ONE ;
                    end else begin
                        state <= IDLE ;
                    end
                end
            end
            HALF: begin
                if(end_cnt_10s) begin
                    state <= IDLE ;
                end else begin
                    if(money == 2'b01) begin
                        state <= ONE ;
                    end else begin
                        if(money == 2'b10) begin
                            state <= ONE_HALF;
                        end else begin
                            state <= HALF ;
                        end
                    end
                end
            end
            ONE: begin
                if(end_cnt_10s) begin
                    state <= IDLE ;
                end else begin
                    if(money == 2'b01) begin
                        state <= ONE_HALF;
                    end else begin
                        if(money == 2'b10) begin
                            state <= TWO ;
                        end else begin
                            state <= ONE ;
                        end
                    end
                end
            end
            ONE_HALF : begin
                if(end_cnt_10s) begin
                    state <= IDLE ;
                end else begin
                    if(money == 2'b01) begin
                        state <= TWO ;
                    end else begin
                        if(money == 2'b10) begin
                            state <= WATER_R; // Exactly 2.5 yuan to enter the right flow state
                        end else begin
                            state <= ONE_HALF;
                        end
                    end
                end
            end
            TWO: begin
                if(end_cnt_10s) begin
                    state <= IDLE ;
                end else begin
                    if(money == 2'b01) begin
                        state <= WATER_R; // Exactly 2.5 yuan to enter the right flow state
                    end else begin
                        if(money == 2'b10) begin
                            state <= WATER_C ;
                        end else begin
                            state <= TWO ;
                        end
                    end
                end
            end
            WATER_R : begin
                if(end_cnt_10s) begin
                    state <= IDLE ;
                end else begin
                    state <= WATER_R ;
                end
            end
            WATER_C : begin
                if(end_cnt_10s) begin
                    state <= IDLE ;
                end else begin
                    state <= WATER_C ;
                end
            end
            default : state <= IDLE ;
            endcase
        end
    end
    //ctrl
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) begin
            ctrl <= 1'b1;
        end else begin
            if(water_led == 4'b1110) begin
                ctrl <= 1'b0;
            end else begin
                if(water_led == 4'b0111) begin
                    ctrl <= 1'b1;
                end else begin
                    ctrl <= ctrl ;
                end
            end
        end
    end
    // water_led
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) begin
            water_led <= 4'b0111;
        end else begin
            case (state)
            WATER_R : begin
                if(end_cnt_1s) begin
                    water_led <= { led[0], led[03:01] };
                end else begin
                    water_led <= water_led;
                end
            end
            WATER_C : begin
                if(end_cnt_1s) begin
                    if( ctrl & amp; & amp; end_cnt_1s ) begin // An enable or control signal is needed here, and end_cnt_1s needs to be connected to maintain the LED 1110 state for 1s
                        water_led <= { led[0], led[03:01] };
                    end else begin
                        water_led <= { led[02:00], led[3] };
                    end
                end else begin
                    water_led <= water_led;
                end
            end
                default: water_led <= 4'b0111; // Unchanged when not in use to save power consumption.
            endcase
        end
    end
    // led 
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) begin
            led <= 4'b1010;
        end else begin
            case (state)
            IDLE: begin
                led <= 4'b1111;
            end
            HALF: begin
                led <= 4'b1110;
            end
            ONE: begin
                led <= 4'b1100;
            end
            ONE_HALF : begin
                led <= 4'b1000;
            end
            TWO: begin
                led <= 4'b0000;
            end
            WATER_R : begin
                led <= water_led ;
            end
            WATER_C : begin
                led <= water_led ;
            end
                default: led <= 4'b0101;
            endcase
        end
    end
    // po_cola
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) begin
            po_cola <= 0 ;
        end else begin
            if( (state == ONE_HALF & amp; & amp; money == 2'b10) || (state == TWO & amp; & amp; money != 2'b00) ) begin
                po_cola <= 1'b1;
            end else begin
                po_cola <= 0 ;
            end
        end
    end
    // po_money
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) begin
            po_money <= 0 ;
        end else begin
            if(state == TWO & amp; & amp; money == 2'b10) begin
                po_money <= 1;
            end else begin
                po_money <= 0 ;
            end
        end
    end
endmodule