Lesson 30

🖱️ PS/2鼠标

🏆 坐标包解析正确
✅ Verilator仿真验证通过

📖 实验描述

实现PS/2鼠标接口,接收11位帧数据,解析3字节移动数据包。

PS/2协议是早期鼠标键盘的标准接口,至今仍在很多FPGA开发板上使用。 PS/2帧格式(11位): 1. 起始位:0 2. 数据位:D0-D7(LSB first) 3. 校验位:奇校验 4. 停止位:1 PS/2鼠标数据包(3字节): Byte 0: Y溢出 X溢出 Y8 X8 1 中键 右键 左键 Byte 1: X方向移动量[7:0] Byte 2: Y方向移动量[7:0] PS/2时序: - 时钟由设备(鼠标)产生,约10-16.7kHz - 数据在时钟下降沿有效

🧠 核心概念

📐 电路结构

电路与状态图
PS/2帧时序:

  PS2_CLK  ──┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌──
              └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘
  PS2_DATA  S   D0  D1  D2  D3  D4  D5  D6  D7   P   E
              ↑   ↑   ↑   ↑   ↑   ↑   ↑   ↑   ↑   ↑   ↑
           下降沿采样

  鼠标数据包:
  Byte0: [YOVR][XOVR][Y8][X8][1][MID][RIGHT][LEFT]
  Byte1: X[7:0]  ← 水平移动量
  Byte2: Y[7:0]  ← 垂直移动量

📝 设计步骤

  1. 1同步PS2_CLK和PS2_DATA输入
  2. 2检测PS2_CLK下降沿
  3. 3接收11位帧:起始+8数据+校验+停止
  4. 4奇校验验证帧完整性
  5. 53字节缓冲:byte0(标志)+byte1(X)+byte2(Y)
  6. 6解析按键状态和XY坐标
  7. 7data_valid脉冲通知数据包完成

💻 Verilog实现

ps2_mouse.svSystemVerilog · Verilator 5.020
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
// PS/2 Mouse Interface — PS/2鼠标接口
module ps2_mouse (
    input wire clk, rst, ps2_clk, ps2_data,
    output reg [7:0] mouse_x, mouse_y,
    output reg [2:0] buttons, output reg data_valid
);
reg ps2_clk_s1,ps2_clk_s2,ps2_clk_s3, ps2_data_s1,ps2_data_s2;
always @(posedge clk or posedge rst) begin
    if (rst) begin ps2_clk_s1<=1;ps2_clk_s2<=1;ps2_clk_s3<=1;ps2_data_s1<=1;ps2_data_s2<=1; end
    else begin ps2_clk_s1<=ps2_clk;ps2_clk_s2<=ps2_clk_s1;ps2_clk_s3<=ps2_clk_s2;
        ps2_data_s1<=ps2_data;ps2_data_s2<=ps2_data_s1; end
end
wire ps2_clk_fall = ps2_clk_s3 & ~ps2_clk_s2;
typedef enum logic [1:0] {FR_START,FR_DATA,FR_PARITY,FR_STOP} fr_state_t;
fr_state_t fr_state; reg [3:0] bit_cnt; reg [7:0] shift_reg; reg parity_bit, frame_valid;
always @(posedge clk or posedge rst) begin
    if (rst) begin fr_state<=FR_START;bit_cnt<=0;shift_reg<=0;parity_bit<=0;frame_valid<=0; end
    else begin
        frame_valid<=0;
        if (ps2_clk_fall) begin
            case (fr_state)
                FR_START: if (ps2_data_s2==0) begin fr_state<=FR_DATA;bit_cnt<=0;shift_reg<=0; end
                FR_DATA: begin shift_reg<={ps2_data_s2,shift_reg[7:1]};
                    if (bit_cnt==7) fr_state<=FR_PARITY; else bit_cnt<=bit_cnt+1; end
                FR_PARITY: begin parity_bit<=ps2_data_s2;fr_state<=FR_STOP; end
                FR_STOP: begin if (ps2_data_s2==1 && (^shift_reg ^ parity_bit == 1'b1)) frame_valid<=1;
                    fr_state<=FR_START; end
                default: fr_state<=FR_START;
            endcase
        end
    end
end
reg [1:0] byte_cnt; reg [7:0] byte0, byte1;
always @(posedge clk or posedge rst) begin
    if (rst) begin byte_cnt<=0;byte0<=0;byte1<=0;mouse_x<=0;mouse_y<=0;buttons<=0;data_valid<=0; end
    else begin
        data_valid<=0;
        if (frame_valid) begin
            case (byte_cnt)
                0: begin byte0<=shift_reg;byte_cnt<=1; end
                1: begin byte1<=shift_reg;byte_cnt<=2; end
                2: begin buttons<=byte0[2:0];mouse_x<=byte1;mouse_y<=shift_reg;data_valid<=1;byte_cnt<=0; end
            endcase
        end
    end
end
endmodule

🔬 仿真说明

仿真环境与策略

测试:模拟PS/2时钟发送3字节鼠标数据包。Byte0=0x08(仅左键), Byte1=0x0A(X=10), Byte2=0xFF(Y=-1)。验证mouse_x=10, mouse_y=0xFF, buttons=000, data_valid=1。

✅ 验证结果

Verilator 5.020 仿真通过

本实验所有Verilog代码已通过Verilator编译验证,功能行为正确。测试用例覆盖核心功能路径,确保设计满足规格要求。

⚠️ 常见错误

🌍 真实世界

工业应用

PS/2接口虽然已被USB取代,但FPGA开发板仍广泛使用。DE10-Nano、Basys3都有PS/2接口。理解PS/2协议有助于学习USB HID协议。

💡 扩展挑战

🚀 自己动手

# 编译验证
verilator --lint-only ps2_mouse.sv --timing
verilator --cc ps2_mouse.sv --exe tb.cpp --build -j 0 --timing

🎯 试一试

修改参数

尝试修改代码中的关键参数,观察仿真结果变化:

  • 调整深度/位宽,观察行为变化
  • 修改时钟分频,测试不同速度
  • 改变初始值/种子,观察不同起始条件

💡 Verilator会在位宽不匹配时给出Warning,这是学习的好机会

添加功能

在现有基础上增加新功能:

  • 添加新的控制信号和状态
  • 增加状态或修改状态转移条件
  • 扩展输出,增加更多信息

🔧 增量开发:每次只改一个地方,验证通过后再改下一个

📋 Verilog速查

语法说明示例
reg [7:0]8位寄存器reg [7:0] data;
wire组合逻辑连线wire valid = cnt > 5;
always @(posedge clk)时序逻辑上升沿触发
always @(*)组合逻辑敏感列表自动推导
localparam局部常量localparam DIV = 50000000;
case多分支选择注意default分支
$clog2计算位宽$clog2(16)=4

📊 性能指标

资源估算(FPGA参考)

本设计在典型FPGA上的资源占用估算:LUT约20-150个,FF约30-120个,无BRAM/DSP依赖(特殊模块除外)。时钟频率可达50-100MHz+。Verilator仿真速度约5-10M周期/秒。

← 上一课 📚 目录 下一课 →