Files
risc-v-cpu/pipelined-cpu/srcs/tb/tb_board_top.v
Alpha 9dfff16794 feat(board): 支持 PS/2 键盘(与鼠标共用板载 USB HID 口),并修好 PS/2 帧校验
一、修 PS/2 接收器的真 bug —— 这就是上板“鼠标毫无反应”的根因
  鼠标和键盘两个接收模块原来是同一个写法错误:
  * 帧用整体右移 {data, frame_q[10:1]},判 frame_q[10] 时停止位还没移进来,判到的
    其实是校验位;取数据 frame_q[8:1] 也因此整体错一位
  * 校验位按“偶校验”判,而 PS/2 是“奇校验”
  两者叠加让真设备发来的帧 100% 被丢掉(上板表现为 rx_count 恒为 0,看起来像硬件
  或跳线问题)。现在按“位的下标”存帧(frame_q[i] = 第 i 位,所以字节 = frame_q[8:1]、
  校验 = frame_q[9]),停止位直接在当前拍的 ps2_data 上判,校验按奇校验。

二、新增 PS/2 键盘解码 cpu21_ps2_kbd.v
  扫描码集 2:E0 = 扩展前缀、F0 = 松开前缀,只对“按下”产生事件,并映射成与鼠标
  完全相同的事件格式(↑↓←→ = dy/dx ±8,正好一格;Enter/空格 = 左键;左 Shift/F/C
  = 右键 = 插旗),所以 saolei 的 C 代码一行都不用改;按住方向键 = 连续移动(用的是
  键盘自己的重复码)。

三、顶层 cpu21_board_top:用 SW15 选设备
  同一根 PS/2 线上只会插一个设备,但两个解码器都在听:键盘的扫描码会凑巧组成
  “合法的鼠标包”,两路同时生效会让光标乱跳。因此新增端口 hid_sel(SW15):
  0 = 键盘(默认),1 = 鼠标;诊断 LED 改显示“当前选中设备”收到的字节数。

四、其它
  * XDC:hid_sel -> V10(SW15),引脚号在官方母版里核对过
  * tb_board_top 补 hid_sel 端口,避免悬空
  * 新增自测 srcs/tb/tb_ps2_mouse.v / tb_ps2_kbd.v:含“故意发一个校验位错的帧,
    必须丢帧”的用例,两个都 ALL PASS
  * README / saolei/README:新增“PS/2 键鼠”一节(接线方式、SW15、LED 诊断口诀、
    键位表),修正显存格式(每格 2 字节、0x2000-0x2FFF)、扫雷难度与验证状态、
    修好 riscv 工具链 -Prefix 路径
2026-09-23 22:35:50 +08:00

75 lines
2.8 KiB
Verilog
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
`timescale 1ns / 1ps
// -----------------------------------------------------------------------------
// cpu21_board_top 的仿真测试(不上板,纯 RTL 仿真)
//
// 检查内容:
// 1) 复位释放后 CPU 能从片内 ROM 取指(ROM 由 cpu21_board_rom.vh 初始化);
// 2) 程序通过 MMIO 写 LED,板载 LED 端口上能看到 16 位跑马灯序列。
//
// 默认的 board_demo 程序带约 20 ms 软件延时,仿真只需确认第一次写入;
// 若要完整验证跑马灯序列,可生成一份短延时的 ROM 并用 -d BOARD_ROM_FAST 编译:
// xvlog -d BOARD_ROM_FAST board/cpu21_board_top.v <rtl/*.v> testbench/tb_board_top.v
// -----------------------------------------------------------------------------
module tb_board_top;
reg clk100 = 1'b0;
reg rst_n = 1'b0;
reg go = 1'b0;
reg [2:0] irq_sw = 3'b000;
wire [15:0] led;
wire led_we;
always #5 clk100 = ~clk100; // 100 MHz
cpu21_board_top #(
.LED_ADDR(32'h0000_1000)
) dut (
.clk100(clk100),
.rst_n (rst_n),
.go (go),
.irq_sw(irq_sw),
.led (led),
.led_we(led_we),
// 扫雷扩展端口:本测试平台不复位测试这些功能,输入显式接 0/1,
// 避免悬空(z)传到中断控制器里影响跑马灯的比对结果。
.btnu (1'b0),
.btnd (1'b0),
.btnl (1'b0),
.btnr (1'b0),
.sw_flag (1'b0),
.hid_sel (1'b0),
.ps2_clk (1'b1),
.ps2_data(1'b1),
.an (),
.seg (),
.dp (),
.vga_r (),
.vga_g (),
.vga_b (),
.vga_hs (),
.vga_vs ()
);
integer changes = 0;
reg [15:0] led_prev = 16'hxxxx;
always @(posedge clk100) begin
if (led !== led_prev) begin
changes = changes + 1;
led_prev = led;
$display("t=%t LED=%04h led_we=%b", $time, led, led_we);
end
end
initial begin
$timeformat(-9, 3, " ns", 12); // %t 按 ns 显示(默认按精度 ps 显示)
$display("NOTE: 复位后观察 LED(默认程序首次写入应为 0001)");
repeat (10) @(posedge clk100);
rst_n = 1'b1;
repeat (30000) @(posedge clk100); // 300 us(CPU 时钟为 clk100/2 = 50 MHz)
$display("FINAL: LED 变化次数=%0d 当前 LED=%04h", changes, led);
$finish;
end
endmodule