You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

211 lines
4.0 KiB
Verilog

`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