diff --git a/pipelined-cpu/srcs/rtl/cpu21_ps2_kbd.v b/pipelined-cpu/srcs/rtl/cpu21_ps2_kbd.v index cc3439c..f9fd385 100644 --- a/pipelined-cpu/srcs/rtl/cpu21_ps2_kbd.v +++ b/pipelined-cpu/srcs/rtl/cpu21_ps2_kbd.v @@ -6,9 +6,13 @@ // 键盘只要产出**同样格式**的事件,软件一行都不用改。 // // ↑ ↓ ← → 光标移动(dx/dy = ±8,恰好是软件里的"一格") +// W A S D 同上(别名,与 tools/play_saolei.tcl 一致) // Enter / 空格 左键(开格) // 左 Shift / F / C 右键(软件里右键 = 插旗) // +// 方向约定跟软件对齐:**dy = +8 是向下**(与 cpu21_pointer 的 BTND、cpu21_ps2_mouse 一致), +// 所以 ↑ 发 dy = 248(= -8 的补码)。 +// // PS/2 键盘发扫描码(集 2): // 0xF0 前缀 -> 下一个码是"松开"(break);0xE0 前缀 -> 下一个码是扩展键 // 方向键是扩展键:↑ = E0 75、↓ = E0 72、← = E0 6B、→ = E0 74 @@ -89,6 +93,11 @@ module cpu21_ps2_kbd ( 8'h12: begin ev_dx_o <= 8'd0; ev_dy_o <= 8'd0; ev_btn_o <= 5'b00010; ev_valid_o <= 1'b1; end // 左 Shift 8'h2B: begin ev_dx_o <= 8'd0; ev_dy_o <= 8'd0; ev_btn_o <= 5'b00010; ev_valid_o <= 1'b1; end // F 8'h2E: begin ev_dx_o <= 8'd0; ev_dy_o <= 8'd0; ev_btn_o <= 5'b00010; ev_valid_o <= 1'b1; end // C + // W/A/S/D 也当方向键(和 tools/play_saolei.tcl 里的别名保持一致) + 8'h1D: begin ev_dx_o <= 8'd0; ev_dy_o <= 8'd248; ev_btn_o <= 5'd0; ev_valid_o <= 1'b1; end // W = ↑ + 8'h1B: begin ev_dx_o <= 8'd0; ev_dy_o <= 8'd8; ev_btn_o <= 5'd0; ev_valid_o <= 1'b1; end // S = ↓ + 8'h1C: begin ev_dx_o <= 8'd248; ev_dy_o <= 8'd0; ev_btn_o <= 5'd0; ev_valid_o <= 1'b1; end // A = ← + 8'h23: begin ev_dx_o <= 8'd8; ev_dy_o <= 8'd0; ev_btn_o <= 5'd0; ev_valid_o <= 1'b1; end // D = → default: ; endcase end diff --git a/pipelined-cpu/srcs/rtl/cpu21_ps2_mouse.v b/pipelined-cpu/srcs/rtl/cpu21_ps2_mouse.v index 31b0bda..ae9795a 100644 --- a/pipelined-cpu/srcs/rtl/cpu21_ps2_mouse.v +++ b/pipelined-cpu/srcs/rtl/cpu21_ps2_mouse.v @@ -19,7 +19,8 @@ // 所以字节 = frame_q[8:1](frame_q[1] 就是 d0),校验 = frame_q[9]。 // 注意 PS/2 是**奇校验**:data + parity 9 位里 1 的个数为奇数。 // 2) 解析:byte0 = 标志(bit0 左键、bit1 右键、bit3 固定 1),byte1 = dx, -// byte2 = dy,bit7 为符号位; +// byte2 = dy,bit7 为符号位;dx 正 = 右,**dy 正 = 上**(PS/2 的原生方向), +// 而软件里正 dy = 下,所以上报前把 dy 取负,让鼠标和板载按键/键盘方向一致; // 3) 上报:当 dx/dy 非 0 或按键状态变化时产生一个事件(单位与 // cpu21_pointer 相同,即原始计数 = 1/8 格); // 4) 本模块只做"接收",不实现主机→鼠标的命令发送(0xF4 使能上报)。多数 @@ -131,8 +132,10 @@ module cpu21_ps2_mouse ( end 8'd2: begin byte_cnt_q <= 8'd0; - ev_dx_o <= pkt_q[15:8]; // byte1 = dx - ev_dy_o <= frame_q[8:1]; // byte2 = dy + ev_dx_o <= pkt_q[15:8]; // byte1 = dx(正 = 右,与软件一致) + // byte2 = dy:**PS/2 的正 dy 是鼠标上移**,而软件里正 dy = 光标下移 + // (与 cpu21_pointer 的 BTND = +8 一致),所以这里要取负。 + ev_dy_o <= 8'd0 - frame_q[8:1]; // 与 cpu21_mmio / mmio.h 一致:bit0=左键, bit1=右键, bit2=中键 ev_btn_o <= {2'b0, pkt_q[2], pkt_q[1], pkt_q[0]}; ev_valid_o <= 1'b1; diff --git a/pipelined-cpu/srcs/tb/tb_ps2_kbd.v b/pipelined-cpu/srcs/tb/tb_ps2_kbd.v index 618277e..43c4260 100644 --- a/pipelined-cpu/srcs/tb/tb_ps2_kbd.v +++ b/pipelined-cpu/srcs/tb/tb_ps2_kbd.v @@ -4,6 +4,7 @@ // // 发 → 键(E0 74)应产生 dx=+8;发 ↑(E0 75)应产生 dy=-8; // 发 Enter(5A)应产生 btn=1(开格);发 左Shift(12)应产生 btn=2(插旗); +// 发 W(1D)应产生 dy=-8(W/A/S/D 别名); // 松开码(F0 xx)不应产生事件;校验位错的帧应被整帧丢掉。 // // PS/2 键盘发扫描码(集 2):0xF0 前缀 = 下一个码是"松开",0xE0 前缀 = 扩展键, @@ -152,8 +153,13 @@ module tb_ps2_kbd; send_byte(8'h12); #(100_000); + $display("[kbd] W 键(1D)期望 dy=-8(W/A/S/D 是方向键别名)"); + exp_dx = 0; exp_dy = -8; exp_btn = 0; + send_byte(8'h1D); + #(100_000); + $display("[kbd] rx_count=%0d events=%0d", rx_count, n_ev); - if ((ok == 0) || (n_ev != 4)) + if ((ok == 0) || (n_ev != 5)) $display("[kbd] === FAIL ==="); else $display("[kbd] === ALL PASS ==="); diff --git a/pipelined-cpu/srcs/tb/tb_ps2_mouse.v b/pipelined-cpu/srcs/tb/tb_ps2_mouse.v index 21d3218..5604998 100644 --- a/pipelined-cpu/srcs/tb/tb_ps2_mouse.v +++ b/pipelined-cpu/srcs/tb/tb_ps2_mouse.v @@ -11,6 +11,11 @@ // 再拉低时钟。一帧 11 位 = 起始 0 + 8 位数据(LSB 先) + **奇校验** + 停止 1。 // 奇校验 = 校验位让 data + parity 共 9 位里 1 的个数为奇数(真设备就是这么发的)。 // +// 方向约定:PS/2 的 **dx 正 = 右、dy 正 = 上**(真鼠标往上推,byte2 是正数); +// 而软件(saolei.c / cpu21_pointer)里 **dy 正 = 向下(行号增加)**, +// 所以 cpu21_ps2_mouse 上报前把 dy 取负 —— 本测试就是盯这个约定: +// 发“向上”的 dy,事件里必须得到负的 dy。 +// // 跑法(Vivado 的 xvlog/xelab/xsim 或其它仿真器都行): // xvlog srcs/rtl/cpu21_ps2_mouse.v srcs/tb/tb_ps2_mouse.v // xelab -top tb_ps2_mouse -snapshot ps2sim @@ -95,13 +100,13 @@ module tb_ps2_mouse; $display(" [ps2] event #%0d: dx=%0d dy=%0d btn=%b", n_ev, $signed(ev_dx), $signed(ev_dy), ev_btn); if (n_ev == 1) begin if (($signed(ev_dx) != 8) || ($signed(ev_dy) != -8) || (ev_btn != 5'b00000)) begin - $display(" [ps2] FAIL: 第 1 包应为 dx=+8 dy=-8 btn=00000"); + $display(" [ps2] FAIL: 第 1 包应为 dx=+8 dy=-8 btn=00000(鼠标向上 -> 事件 dy 为负)"); ok = 0; end end if (n_ev == 2) begin if (($signed(ev_dx) != -3) || ($signed(ev_dy) != 5) || (ev_btn[0] != 1'b1)) begin - $display(" [ps2] FAIL: 第 2 包应为 dx=-3 dy=+5 btn=xxxx1"); + $display(" [ps2] FAIL: 第 2 包应为 dx=-3 dy=+5 btn=xxxx1(鼠标向下 -> 事件 dy 为正)"); ok = 0; end end @@ -125,16 +130,16 @@ module tb_ps2_mouse; end rx_after_bad = rx_count; - $display("[ps2] packet 1: flag=0x08(no button) dx=+8 dy=-8"); + $display("[ps2] packet 1: flag=0x08(no button) dx=+8 dy=+8(鼠标向右上移)"); + send_byte(8'h08); send_byte(8'h08); send_byte(8'h08); - send_byte(8'hF8); #(100_000); - $display("[ps2] packet 2: flag=0x09(left) dx=-3 dy=+5"); + $display("[ps2] packet 2: flag=0x09(left) dx=-3 dy=-5(向左下移)"); send_byte(8'h09); send_byte(8'hFD); - send_byte(8'h05); + send_byte(8'hFB); #(100_000); $display("[ps2] rx_count=%0d events=%0d", rx_count, n_ev);