From 77dd1026756d9719480e8840864b02d324affc18 Mon Sep 17 00:00:00 2001 From: Alex-create-beep <2965312221@qq.com> Date: Wed, 23 Sep 2026 21:50:06 +0800 Subject: [PATCH] =?UTF-8?q?feat(board):=20=E6=9D=BF=E8=BD=BD=20USB=20HID?= =?UTF-8?q?=20=E5=8F=A3=E6=8E=A5=20PS/2=20=E9=BC=A0=E6=A0=87=EF=BC=8C?= =?UTF-8?q?=E4=B8=8E=E6=9D=BF=E8=BD=BD=E6=8C=89=E9=94=AE=E5=B9=B6=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Nexys4DDR 的 USB HOST 口由板上芯片把 USB 键鼠转成 PS/2 信号(官方母版 Nexys4DDR_Master.xdc 标明 ps2_clk = F4、ps2_data = B2),所以不用写 USB 协议栈。 - cpu21_board_top.v: * USE_PS2_MOUSE 默认打开;原来是 if/else 二选一(选鼠标就没按键),现在 cpu21_pointer 与 cpu21_ps2_mouse 同时例化,两路事件在顶层合并成 ev_valid/ ev_dx/ev_dy/ev_btn(同拍优先 PS/2),板载按键一个不删 * 新增 DEBUG_PS2_RX_LED(默认 1):把 PS/2 收到的字节数显示到 LED[15:3] (LED[2:0] 仍是中断指示)。没有调试器时靠它判断 PS/2 到底有没有数据: 鼠标一动数字就跳 = 通了;一直是 0 = 根本没收到 - cpu21_board_top.xdc:ps2_clk/ps2_data 从 Pmod JA(C17/D18)改到板载 USB HID (F4/B2),并在注释里留了改回 Pmod 的方法 软件侧不用改:鼠标事件与按键事件格式相同,且 PS/2 的 dx/dy 天然满足 "8 个计数 = 一格"(saolei.c 里就是 acc_x += dx; while (acc_x >= 8) 移动一格)。 额外好处:鼠标右键 = 插旗(handle_event 本来就支持)。 --- pipelined-cpu/srcs/board/cpu21_board_top.v | 69 +++++++++++++------ .../srcs/constrs/cpu21_board_top.xdc | 9 ++- 2 files changed, 55 insertions(+), 23 deletions(-) diff --git a/pipelined-cpu/srcs/board/cpu21_board_top.v b/pipelined-cpu/srcs/board/cpu21_board_top.v index 93e822d..7e6022d 100644 --- a/pipelined-cpu/srcs/board/cpu21_board_top.v +++ b/pipelined-cpu/srcs/board/cpu21_board_top.v @@ -53,7 +53,10 @@ module cpu21_board_top #( // 所以不会掩盖时序违例(约束偏严)。 parameter integer CLK_DIV_INTRUPT = 32, // 鼠标事件源:0 = 板上 5 向按键(免外设,默认);1 = PS/2 鼠标(Pmod JA) - parameter integer USE_PS2_MOUSE = 0, + parameter integer USE_PS2_MOUSE = 1, // 1 = 启用板载 USB HID 口(PS/2 键鼠),板载按键同时有效 + // 调试:1 = 把 PS/2 收到的字节数显示在 LED[15:3](LED[2:0] 仍是中断指示)。 + // 验证 PS/2 通不通时打开:鼠标一动数字就跳;一直是 0 说明根本没收到 PS/2 数据。 + parameter integer DEBUG_PS2_RX_LED = 1, // 5 向按键去抖的采样周期(CPU 周期数):上板默认 50000(1 ms @50 MHz)。 // 仿真里可以传一个小值,让"按一下"在几十微秒内就被识别。 parameter integer POINTER_SAMPLE_DIV = 50000 @@ -160,6 +163,7 @@ module cpu21_board_top #( wire [31:0] data_wdata; wire [ 3:0] data_wstrb; wire data_we; + wire [15:0] ps2_rx_count; // PS/2 收到的字节数(用于 LED 调试显示) wire [31:0] led_data; // LED_ADDR 写入值,同时作为七段数码管显示数据 wire led_valid; // 扫雷扩展外设的连线(先声明,例化在下面) @@ -337,7 +341,10 @@ module cpu21_board_top #( end end - assign led = {{13{1'b0}}, irq_led_q}; + // LED[15:3] 平时熄灭;DEBUG_PS2_RX_LED=1 时用它显示 PS/2 收到的字节数, + // 便于在没有调试器的情况下判断"鼠标到底有没有数据进来"。 + assign led = (DEBUG_PS2_RX_LED != 0) ? {ps2_rx_count[12:0], irq_led_q} + : {{13{1'b0}}, irq_led_q}; reg [23:0] led_we_cnt; @@ -417,12 +424,34 @@ module cpu21_board_top #( .dp_o (dp) ); - // ---- 鼠标事件源 ---- + // ---- 鼠标事件源:板载按键 与 PS/2 鼠标**同时**有效(两路事件在顶层合并) ---- wire ev_valid; wire [7:0] ev_dx, ev_dy; wire [4:0] ev_btn; wire [4:0] btn_vec = {go, btnu, btnd, btnl, btnr}; // {BTNC, BTNU, BTND, BTNL, BTNR} + // 1) 板载按键:永远保留(BTNC 当左键、上下左右当移动、SW3 当插旗开关) + wire ptr_valid; + wire [7:0] ptr_dx, ptr_dy; + wire [4:0] ptr_btn; + + cpu21_pointer #( + .SAMPLE_DIV(POINTER_SAMPLE_DIV) + ) u_ptr ( + .clk (clk_cpu), + .reset (reset), + .btn_i (btn_vec), + .ev_valid_o(ptr_valid), + .ev_dx_o (ptr_dx), + .ev_dy_o (ptr_dy), + .ev_btn_o (ptr_btn) + ); + + // 2) PS/2 鼠标:板载 USB HID 口经板上芯片转成 PS/2 信号(ps2_clk/ps2_data) + wire ps2_valid; + wire [7:0] ps2_dx, ps2_dy; + wire [4:0] ps2_btn; + generate if (USE_PS2_MOUSE != 0) begin : g_ps2 cpu21_ps2_mouse u_ps2 ( @@ -432,27 +461,27 @@ module cpu21_board_top #( .ps2_clk_oe_o (), .ps2_data_i (ps2_data), .ps2_data_oe_o(), - .ev_valid_o (ev_valid), - .ev_dx_o (ev_dx), - .ev_dy_o (ev_dy), - .ev_btn_o (ev_btn), - .rx_count_o () - ); - end else begin : g_btn - cpu21_pointer #( - .SAMPLE_DIV(POINTER_SAMPLE_DIV) - ) u_ptr ( - .clk (clk_cpu), - .reset (reset), - .btn_i (btn_vec), - .ev_valid_o(ev_valid), - .ev_dx_o (ev_dx), - .ev_dy_o (ev_dy), - .ev_btn_o (ev_btn) + .ev_valid_o (ps2_valid), + .ev_dx_o (ps2_dx), + .ev_dy_o (ps2_dy), + .ev_btn_o (ps2_btn), + .rx_count_o (ps2_rx_count) ); + end else begin : g_no_ps2 + assign ps2_valid = 1'b0; + assign ps2_dx = 8'd0; + assign ps2_dy = 8'd0; + assign ps2_btn = 5'd0; + assign ps2_rx_count = 16'd0; end endgenerate + // 3) 合并:同一拍只有一方产生事件(两个源相互独立),优先 PS/2 + assign ev_valid = ps2_valid | ptr_valid; + assign ev_dx = ps2_valid ? ps2_dx : ptr_dx; + assign ev_dy = ps2_valid ? ps2_dy : ptr_dy; + assign ev_btn = ps2_valid ? ps2_btn : ptr_btn; + endmodule `default_nettype wire diff --git a/pipelined-cpu/srcs/constrs/cpu21_board_top.xdc b/pipelined-cpu/srcs/constrs/cpu21_board_top.xdc index 0bde45c..0bc2209 100644 --- a/pipelined-cpu/srcs/constrs/cpu21_board_top.xdc +++ b/pipelined-cpu/srcs/constrs/cpu21_board_top.xdc @@ -97,6 +97,9 @@ set_property -dict { PACKAGE_PIN D8 IOSTANDARD LVCMOS33 } [get_ports { vga_b[ set_property -dict { PACKAGE_PIN B11 IOSTANDARD LVCMOS33 } [get_ports { vga_hs }] set_property -dict { PACKAGE_PIN B12 IOSTANDARD LVCMOS33 } [get_ports { vga_vs }] -## PS/2 鼠标(可选:Pmod JA 插 Pmod PS2,顶层 USE_PS2_MOUSE=1) -set_property -dict { PACKAGE_PIN C17 IOSTANDARD LVCMOS33 PULLUP true } [get_ports { ps2_clk }] -set_property -dict { PACKAGE_PIN D18 IOSTANDARD LVCMOS33 PULLUP true } [get_ports { ps2_data }] +## PS/2 鼠标:接**板载 USB HID 口**(板上芯片把 USB 键鼠转成 PS/2) +## Nexys4DDR_Master.xdc 里写明:ps2_clk = F4、ps2_data = B2 +## 顶层参数 USE_PS2_MOUSE=1 启用;板载按键仍然可用(两路事件在顶层合并) +## 若改用 Pmod JA 上的 Pmod PS2,把下面两行的引脚换成 C17 / D18 即可 +set_property -dict { PACKAGE_PIN F4 IOSTANDARD LVCMOS33 PULLUP true } [get_ports { ps2_clk }] +set_property -dict { PACKAGE_PIN B2 IOSTANDARD LVCMOS33 PULLUP true } [get_ports { ps2_data }]