`timescale 1ns/1ns

module tb_lm();


reg k_1;  // 显示的图像1
reg k_2;  // 显示的图像2

reg key;  // 物理按键 开关显示, 该按键异步的, 每次按下 等于

reg key_1;  // 物理按键的随时钟同步变化信号
reg key_2;  // 
reg is_show;  // 互斥变化的
reg [4:0] flag_time;

reg flag;  // 状态改变周期 现在500纳秒改变一次状态, 显示相反的图像

reg sys_clk;
reg sys_rst;


reg [7:0]x;
reg [7:0]y;

always #10 sys_clk = ~sys_clk;

initial begin
    sys_clk <= 1'b0;
    sys_rst <= 1'b0;
    #200
    sys_rst <= 1'b1;

    // 延迟2000纳秒, 现在x 应该是0
    #2000


    key <= 1'b1;
    #120
    key <= 1'b0;
    #20

    key <= 1'b1;
    #80
    key <= 1'b0;
    #20

    key <= 1'b1;
    #90
    key <= 1'b0;
    #20

    // 延迟4000纳秒观察
    {k_2, k_1} <= 2'b10;
    #3900
    {k_2, k_1} <= 2'b01;
    #3800


    key <= 1'b1;
    #20
    key <= 1'b0;
    #20

    key <= 1'b1;
    #20
    key <= 1'b0;
    #20

    key <= 1'b1;
    #90
    key <= 1'b0;
    #200

    key <= 1'b1;
    #120
    key <= 1'b0;
    #20

    key <= 1'b1;
    #120
    key <= 1'b0;
    #20

    key <= 1'b1;
    #150
    key <= 1'b0;

end


// 显示的时候计时
always @(posedge sys_clk or negedge sys_rst) begin
    if (sys_rst == 1'b0) begin
        flag_time <= 5'd0;
    end
    else if (flag_time < (5'd25 - 5'd1) && is_show) begin
        flag_time <= flag_time + 5'd1;
    end
    else begin
        flag_time <= 5'b0;
    end
end


always @(posedge sys_clk or negedge sys_rst) begin
    if (sys_rst == 1'b0) begin
        {k_2, k_1} <= 2'b11;
        x <= 8'b00000000;
        y <= 8'b11111111;  // 所有的都显示算了
    end
    else if ({k_2, k_1} == 2'b10 && is_show) begin
        case (flag)
            1'b0: x <= 8'b1010_1010;
            1'b1: x <= 8'b0101_0101;
        endcase
    end
    else if ({k_2, k_1} == 2'b01 && is_show) begin
        case (flag)
            1'b0: x <= 8'b1111_0000;
            1'b1: x <= 8'b0000_1111;
        endcase
    end
    else begin
        x <= 8'b00000000;
    end
end

// 每 显示500ns 改变显示的图像
always @(posedge sys_clk or negedge sys_rst) begin
    if (sys_rst == 1'b0) begin
        flag <= 1'b0;
    end
    else if (flag_time == (5'd25 - 5'd1)) begin
        flag <= !flag;
    end
    else begin
    end
end

// 异步信号, 通过比较上次时钟周期的状态和当前时钟周期的状态得到当前是否按下了
always @(posedge sys_clk or negedge sys_rst) begin
    if (sys_rst == 1'b0) begin
        key <= 1'b0;
        key_1 <= 1'b0;
        key_2 <= 1'b0;
    end
    else begin
        key_1 <= key;
        key_2 <= key_1;
    end
end

reg [4:0] click_time;  // max: 20
reg is_down;  // 消抖之后的按键状态, 是一个稳定的状态, 没稳定之前 is_down 一直是上次状态, 稳定之后视key最新的值为定

always @(posedge sys_clk or negedge sys_rst) begin
    if (sys_rst == 1'b0) begin
        is_down <= 1'b0;
        click_time <= 5'd0;
    end
    
    if (key_1 != key_2) begin
        click_time <= 5'd0;
    end
    else begin
        // 如果一直相同持续时间达到20个时钟周期
        if (click_time ==  (5'd20 - 5'd1)) begin
            // 当前的key就是可用的, 返回到外部也就是 is_down
            is_down <= key_1;
        end
        else begin
            click_time <= click_time + 5'd1;
        end
    end
end


// 检查稳定之后的按键是否按下了
wire is_click;
reg is_down_1;
reg is_down_2;
assign is_click = is_down_1 && !is_down_2;
always @(posedge sys_clk or negedge sys_rst) begin
    if (sys_rst == 1'b0) begin
        is_down_1 <= 1'b0;
        is_down_2 <= 1'b0;
    end
    else begin
        is_down_1 <= is_down;
        is_down_2 <= is_down_1;
    end
end

always @(posedge sys_clk or negedge sys_rst) begin
    if (sys_rst == 1'b0) begin
        is_show <= 1'b0;
    end
    else if (is_click) begin
        is_show <= !is_show;
    end
    else begin
    end
end

lm u_lm(
    .x (x),
    .y (y)
);


endmodule