Files
risc-v-cpu/pipelined-cpu/srcs/rtl/cpu21_pointer.v
T
Alpha df7b3aee6d fix(rtl): 清除被工具反复注入到 .v 末尾的 README 残行; 新增 RTL 文本自检脚本
- cpu21_pointer.v / cpu21_ps2_mouse.v / cpu21_vga.v 末尾多出一行 README 正文
  (Tcl ...), 会导致 Vivado: ERROR: [Synth 8-2715] non-printable character 0xe4
- 新增 pipelined-cpu/tools/check_rtl_text.ps1: 综合前秒级自检, 检出代码位置上
  的非 ASCII 文本/粘贴进来的正文行
2026-09-18 16:02:02 +08:00

106 lines
4.0 KiB
Verilog
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.
`timescale 1ns / 1ps
`default_nettype none
// -----------------------------------------------------------------------------
// cpu21_pointer —— 把板上的 5 向按键变成"鼠标"事件源(板级顶层用它给 MMIO 送事件)。
//
// 事件单位:1/8 格。按键一次 = 8 个单位 = 光标移动一格,这样软件端用
// 纯整数加减(不需要任何除法)就能把累积量换算成格,配合 PS/2 鼠标时
// 手感也一致(PS/2 的原始计数直接按 1/8 格处理)。
//
// BTNU -> dy = -8 BTND -> dy = +8
// BTNL -> dx = -8 BTNR -> dx = +8
// BTNC -> 左键按下(btn[0] = 1,dx = dy = 0)
//
// 去抖方式:用 ~1 ms 的采样节拍(50 MHz 下计数 50000)采样两级同步后的按键,
// 与上一次的稳定值比较,只在"按下"的边沿产生事件。一次采样可能同时检测到
// 多个按下,此时用 press_pend_q 排队,由优先级选择器逐个上报(每个时钟周期
// 最多一个事件),因此不会丢按键。
// -----------------------------------------------------------------------------
module cpu21_pointer #(
// 采样节拍 = clk / (SAMPLE_DIV),默认 50 MHz / 50000 = 1 kHz
parameter integer SAMPLE_DIV = 50000
) (
input wire clk,
input wire reset,
input wire [4:0] btn_i, // {BTNC, BTNU, BTND, BTNL, BTNR}
output wire ev_valid_o, // 单周期脉冲
output wire [7:0] ev_dx_o, // 有符号,1/8 格
output wire [7:0] ev_dy_o,
output wire [4:0] ev_btn_o
);
// ---------------------------------------------------------------------------
// 1 ms 采样节拍
// ---------------------------------------------------------------------------
reg [15:0] div_q;
wire sample = (div_q == (SAMPLE_DIV - 1));
always @(posedge clk or posedge reset) begin
if (reset)
div_q <= 16'd0;
else if (sample)
div_q <= 16'd0;
else
div_q <= div_q + 16'd1;
end
// ---------------------------------------------------------------------------
// 两级同步 + 采样保持(采样率远低于按键抖动频率,等效去抖)
// ---------------------------------------------------------------------------
reg [4:0] btn_sync1_q, btn_sync2_q, btn_stable_q;
always @(posedge clk or posedge reset) begin
if (reset) begin
btn_sync1_q <= 5'b0;
btn_sync2_q <= 5'b0;
btn_stable_q <= 5'b0;
end
else begin
btn_sync1_q <= btn_i;
btn_sync2_q <= btn_sync1_q;
if (sample)
btn_stable_q <= btn_sync2_q;
end
end
// 只在按下的边沿产生新事件
wire [4:0] press_new = sample ? (btn_sync2_q & ~btn_stable_q) : 5'b0;
// ---------------------------------------------------------------------------
// 待上报队列 + 优先级选择(每周期最多上报一个)
// ---------------------------------------------------------------------------
reg [4:0] press_pend_q;
wire [4:0] pend_next = press_pend_q | press_new;
reg [4:0] sel;
always @* begin
sel = 5'b0;
if (pend_next[4])
sel = 5'b10000; // BTNC:点击
else if (pend_next[3])
sel = 5'b01000; // BTNU:上
else if (pend_next[2])
sel = 5'b00010; // BTND:下
else if (pend_next[1])
sel = 5'b00001; // BTNL:左
else if (pend_next[0])
sel = 5'b00100; // BTNR:右
end
always @(posedge clk or posedge reset) begin
if (reset)
press_pend_q <= 5'b0;
else
press_pend_q <= pend_next & ~sel;
end
assign ev_valid_o = |pend_next;
assign ev_dx_o = sel[1] ? 8'd248 : (sel[0] ? 8'd8 : 8'd0); // 248 = -8 的补码
assign ev_dy_o = sel[3] ? 8'd248 : (sel[2] ? 8'd8 : 8'd0);
assign ev_btn_o = {4'b0, sel[4]};
endmodule
`default_nettype wire