Files
risc-v-cpu/pipelined-cpu/srcs/constrs/cpu21_board_top.xdc
T
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

109 lines
7.5 KiB
Tcl
Raw 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.
## cpu21_board_top.xdc —— Nexys4DDR (xc7a100tcsg324-1) 上板引脚
## 引脚编号取自 ConstraintsData/Nexys4DDR_Master.xdc(母版默认全部注释)。
## 只约束 cpu21_board_top 实际使用的端口。
## 100 MHz 板载时钟(分频器输入)
set_property -dict { PACKAGE_PIN E3 IOSTANDARD LVCMOS33 } [get_ports { clk100 }]
create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports { clk100 }]
## CPU 时钟:板上 100 MHz 经 CLK_DIV(=2) 分频到 50 MHz
## (与 cpu21_board_top.v 的 CLK_DIV 保持一致;改分频比时这里也要改。
## 乘除法已是多周期单元,不再需要 16 分频;实测 100 MHz 下剩余违例路径是
## EX 级分支判决/中断保存 → BPB 更新,50 MHz 则余量充足)
create_generated_clock -name cpu_clk -source [get_ports { clk100 }] \
-divide_by 2 [get_pins { clk_div_reg/Q }]
## 这里固定按最坏情况 50 MHz(-divide_by 2)约束。跑中断综合测试程序时 RTL 里的
## CPU_DIV 会变成 8(12.5 MHz,见 cpu21_board_top.v 的 CLK_DIV_INTRUPT),实际
## 时钟比这里的约束更慢,因此仍然满足——约束偏严,不会掩盖时序违例。
## (真要改分频比时,两处都要改;把这里的 -divide_by 调大反而会放松约束。)
## 复位按键(CPU_RESETN,低有效)与"继续运行"按键(BTNC)
set_property -dict { PACKAGE_PIN C12 IOSTANDARD LVCMOS33 } [get_ports { rst_n }]
set_property -dict { PACKAGE_PIN N17 IOSTANDARD LVCMOS33 } [get_ports { go }]
## 拨码开关 SW[2:0] 作为三路中断源
set_property -dict { PACKAGE_PIN J15 IOSTANDARD LVCMOS33 } [get_ports { irq_sw[0] }]
set_property -dict { PACKAGE_PIN L16 IOSTANDARD LVCMOS33 } [get_ports { irq_sw[1] }]
set_property -dict { PACKAGE_PIN M13 IOSTANDARD LVCMOS33 } [get_ports { irq_sw[2] }]
## 16 位 LED:LED[2:0] = 三路中断指示(请求出现即亮,ISR 执行 uret 返回后灭),
## LED[15:3] 熄灭
set_property -dict { PACKAGE_PIN H17 IOSTANDARD LVCMOS33 } [get_ports { led[0] }]
set_property -dict { PACKAGE_PIN K15 IOSTANDARD LVCMOS33 } [get_ports { led[1] }]
set_property -dict { PACKAGE_PIN J13 IOSTANDARD LVCMOS33 } [get_ports { led[2] }]
set_property -dict { PACKAGE_PIN N14 IOSTANDARD LVCMOS33 } [get_ports { led[3] }]
set_property -dict { PACKAGE_PIN R18 IOSTANDARD LVCMOS33 } [get_ports { led[4] }]
set_property -dict { PACKAGE_PIN V17 IOSTANDARD LVCMOS33 } [get_ports { led[5] }]
set_property -dict { PACKAGE_PIN U17 IOSTANDARD LVCMOS33 } [get_ports { led[6] }]
set_property -dict { PACKAGE_PIN U16 IOSTANDARD LVCMOS33 } [get_ports { led[7] }]
set_property -dict { PACKAGE_PIN V16 IOSTANDARD LVCMOS33 } [get_ports { led[8] }]
set_property -dict { PACKAGE_PIN T15 IOSTANDARD LVCMOS33 } [get_ports { led[9] }]
set_property -dict { PACKAGE_PIN U14 IOSTANDARD LVCMOS33 } [get_ports { led[10] }]
set_property -dict { PACKAGE_PIN T16 IOSTANDARD LVCMOS33 } [get_ports { led[11] }]
set_property -dict { PACKAGE_PIN V15 IOSTANDARD LVCMOS33 } [get_ports { led[12] }]
set_property -dict { PACKAGE_PIN V14 IOSTANDARD LVCMOS33 } [get_ports { led[13] }]
set_property -dict { PACKAGE_PIN V12 IOSTANDARD LVCMOS33 } [get_ports { led[14] }]
set_property -dict { PACKAGE_PIN V11 IOSTANDARD LVCMOS33 } [get_ports { led[15] }]
## LED16_B:MMIO 写入指示(约 0.34 s @50 MHz;中断程序的 12.5 MHz 下约 1.36 s)
set_property -dict { PACKAGE_PIN R12 IOSTANDARD LVCMOS33 } [get_ports { led_we }]
## 上板调试时可把 MMIO 写入的 LED 寄存器也引到 LED16_R/G,
## 但默认只用一个引脚,避免与 led_we 争用。
## ======================= 扫雷扩展外设 =======================
## 5 向按键:BTNC 已作 go(同时也当鼠标左键),另外 4 个当光标方向
set_property -dict { PACKAGE_PIN M18 IOSTANDARD LVCMOS33 } [get_ports { btnu }]
set_property -dict { PACKAGE_PIN P18 IOSTANDARD LVCMOS33 } [get_ports { btnd }]
set_property -dict { PACKAGE_PIN P17 IOSTANDARD LVCMOS33 } [get_ports { btnl }]
set_property -dict { PACKAGE_PIN M17 IOSTANDARD LVCMOS33 } [get_ports { btnr }]
## SW[3]:插旗模式(1 = 点击时插旗/取消旗)
set_property -dict { PACKAGE_PIN R15 IOSTANDARD LVCMOS33 } [get_ports { sw_flag }]
## SW[15]:选 PS/2 设备(0 = 键盘,1 = 鼠标);工程里插的是哪个就拨到哪边
set_property -dict { PACKAGE_PIN V10 IOSTANDARD LVCMOS33 } [get_ports { hid_sel }]
## 七段数码管(共阳极:位选/段选都是低有效)
set_property -dict { PACKAGE_PIN T10 IOSTANDARD LVCMOS33 } [get_ports { seg[0] }]
set_property -dict { PACKAGE_PIN R10 IOSTANDARD LVCMOS33 } [get_ports { seg[1] }]
set_property -dict { PACKAGE_PIN K16 IOSTANDARD LVCMOS33 } [get_ports { seg[2] }]
set_property -dict { PACKAGE_PIN K13 IOSTANDARD LVCMOS33 } [get_ports { seg[3] }]
set_property -dict { PACKAGE_PIN P15 IOSTANDARD LVCMOS33 } [get_ports { seg[4] }]
set_property -dict { PACKAGE_PIN T11 IOSTANDARD LVCMOS33 } [get_ports { seg[5] }]
set_property -dict { PACKAGE_PIN L18 IOSTANDARD LVCMOS33 } [get_ports { seg[6] }]
set_property -dict { PACKAGE_PIN H15 IOSTANDARD LVCMOS33 } [get_ports { dp }]
set_property -dict { PACKAGE_PIN J17 IOSTANDARD LVCMOS33 } [get_ports { an[0] }]
set_property -dict { PACKAGE_PIN J18 IOSTANDARD LVCMOS33 } [get_ports { an[1] }]
set_property -dict { PACKAGE_PIN T9 IOSTANDARD LVCMOS33 } [get_ports { an[2] }]
set_property -dict { PACKAGE_PIN J14 IOSTANDARD LVCMOS33 } [get_ports { an[3] }]
set_property -dict { PACKAGE_PIN P14 IOSTANDARD LVCMOS33 } [get_ports { an[4] }]
set_property -dict { PACKAGE_PIN T14 IOSTANDARD LVCMOS33 } [get_ports { an[5] }]
set_property -dict { PACKAGE_PIN K2 IOSTANDARD LVCMOS33 } [get_ports { an[6] }]
set_property -dict { PACKAGE_PIN U13 IOSTANDARD LVCMOS33 } [get_ports { an[7] }]
## VGA(640x480@60,25 MHz 像素节拍由 CPU 时钟使能产生)
set_property -dict { PACKAGE_PIN A3 IOSTANDARD LVCMOS33 } [get_ports { vga_r[0] }]
set_property -dict { PACKAGE_PIN B4 IOSTANDARD LVCMOS33 } [get_ports { vga_r[1] }]
set_property -dict { PACKAGE_PIN C5 IOSTANDARD LVCMOS33 } [get_ports { vga_r[2] }]
set_property -dict { PACKAGE_PIN A4 IOSTANDARD LVCMOS33 } [get_ports { vga_r[3] }]
set_property -dict { PACKAGE_PIN C6 IOSTANDARD LVCMOS33 } [get_ports { vga_g[0] }]
set_property -dict { PACKAGE_PIN A5 IOSTANDARD LVCMOS33 } [get_ports { vga_g[1] }]
set_property -dict { PACKAGE_PIN B6 IOSTANDARD LVCMOS33 } [get_ports { vga_g[2] }]
set_property -dict { PACKAGE_PIN A6 IOSTANDARD LVCMOS33 } [get_ports { vga_g[3] }]
set_property -dict { PACKAGE_PIN B7 IOSTANDARD LVCMOS33 } [get_ports { vga_b[0] }]
set_property -dict { PACKAGE_PIN C7 IOSTANDARD LVCMOS33 } [get_ports { vga_b[1] }]
set_property -dict { PACKAGE_PIN D7 IOSTANDARD LVCMOS33 } [get_ports { vga_b[2] }]
set_property -dict { PACKAGE_PIN D8 IOSTANDARD LVCMOS33 } [get_ports { vga_b[3] }]
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 鼠标:接**板载 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 }]