PS2鼠标解码
鼠标的数据包格式


鼠标的初始化


PS2发送数据


The t r i - c and t r i - d signals are enable signals that control the tri-state buffers.When they are asserted, the corresponding ps2c-out and ps2d-out signals will be routed to the output ports.
滤波和下降沿检测程序:
// body
//=================================================
// filter and falling-edge tick generation for ps2c
//=================================================
always @(posedge clk, posedge reset)
if (reset)
begin
filter_reg <= 0;
f_ps2c_reg <= 0;
end
else
begin
filter_reg <= filter_next;
f_ps2c_reg <= f_ps2c_next;
end
assign filter_next = {ps2c, filter_reg[7:1]};
assign f_ps2c_next = (filter_reg==8'b11111111) ? 1'b1 :
(filter_reg==8'b00000000) ? 1'b0 :
f_ps2c_reg;
assign fall_edge = f_ps2c_reg & ~f_ps2c_next;
鼠标发送数据模块
代码如下:
//Listing 10.1
module ps2_tx
(
input wire clk, reset,
input wire wr_ps2,
input wire [7:0] din,
inout wire ps2d, ps2c,
output reg tx_idle, tx_done_tick
);
// symbolic state declaration
localparam [2:0]
idle = 3'b000,
rts = 3'b001,
start = 3'b010,
data = 3'b011,
stop = 3'b100;
// signal declaration
reg [2:0] state_reg, state_next;
reg [7:0] filter_reg;
wire [7:0] filter_next;
reg f_ps2c_reg;
wire f_ps2c_next;
reg [3:0] n_reg, n_next;
reg [8:0] b_reg, b_next;
reg [12:0] c_reg, c_next;
wire par, fall_edge;
reg ps2c_out, ps2d_out;
reg tri_c, tri_d;
// body
//=================================================
// filter and falling-edge tick generation for ps2c
//=================================================
always @(posedge clk, posedge reset)
if (reset)
begin
filter_reg <= 0;
f_ps2c_reg <= 0;
end
else
begin
filter_reg <= filter_next;
f_ps2c_reg <= f_ps2c_next;
end
assign filter_next = {ps2c, filter_reg[7:1]};
assign f_ps2c_next = (filter_reg==8'b11111111) ? 1'b1 :
(filter_reg==8'b00000000) ? 1'b0 :
f_ps2c_reg;
assign fall_edge = f_ps2c_reg & ~f_ps2c_next;
//=================================================
// FSMD
//=================================================
// FSMD state & data registers
always @(posedge clk, posedge reset)
if (reset)
begin
state_reg <= idle;
c_reg <= 0;
n_reg <= 0;
b_reg <= 0;
end
else
begin
state_reg <= state_next;
c_reg <= c_next;
n_reg <= n_next;
b_reg <= b_next;
end
// odd parity bit
assign par = ~(^din);
// FSMD next-state logic
always @*
begin
state_next = state_reg;
c_next = c_reg;
n_next = n_reg;
b_next = b_reg;
tx_done_tick = 1'b0;
ps2c_out = 1'b1;
ps2d_out = 1'b1;
tri_c = 1'b0;
tri_d = 1'b0;
tx_idle = 1'b0;
case (state_reg)
idle:
begin
tx_idle = 1'b1;
if (wr_ps2)
begin
b_next = {par, din};
c_next = 13'h1fff; // 2^13-1 to delay 164us
state_next = rts;
end
end
rts: // request to send
begin
ps2c_out = 1'b0;
tri_c = 1'b1;
c_next = c_reg - 1;
if (c_reg==0) //FPGA拉低PS2C 164us
state_next = start;
end
start: // assert start bit PS2 clock line is disabled and the data line is set to 1
begin //the mouse now take over and generates a clock signal over the PS2c line
ps2d_out = 1'b0;
tri_d = 1'b1;
if (fall_edge)
begin
n_next = 4'h8;
state_next = data;
end
end
data: // 8 data + 1 parity
begin
ps2d_out = b_reg[0];
tri_d = 1'b1;
if (fall_edge)
begin
b_next = {1'b0, b_reg[8:1]};
if (n_reg == 0)
state_next = stop;
else
n_next = n_reg - 1;
end
end
stop: // assume floating high for ps2d
if (fall_edge)
begin
state_next = idle;
tx_done_tick = 1'b1;
end
endcase
end
// tri-state buffers
assign ps2c = (tri_c) ? ps2c_out : 1'bz;
assign ps2d = (tri_d) ? ps2d_out : 1'bz;
endmodule

PS2接收
We use the tx-idle and rx-en signals to coordinate the transmitting and receiving operations. Priority is given to the transmitting operation.When the transmitting subsystem is in operation, the tx-idle signal is deasserted, which, in turn, disables the receiving subsystem.The receiving subsystem can process input only when the transmitting subsystem is idle.
PS2三态输入输出模块
代码:
//Listing 10.2
module ps2_rxtx
(
input wire clk, reset,
input wire wr_ps2,
inout wire ps2d, ps2c,
input wire [7:0] din,
output wire rx_done_tick, tx_done_tick,
output wire [7:0] dout
);
// signal declaration
wire tx_idle;
// body
// instantiate ps2 receiver
ps2_rx ps2_rx_unit
(.clk(clk), .reset(reset), .rx_en(tx_idle),
.ps2d(ps2d), .ps2c(ps2c),
.rx_done_tick(rx_done_tick), .dout(dout));
// instantiate ps2 transmitter
ps2_tx ps2_tx_unit
(.clk(clk), .reset(reset), .wr_ps2(wr_ps2),
.din(din), .ps2d(ps2d), .ps2c(ps2c),
.tx_idle(tx_idle), .tx_done_tick(tx_done_tick));
endmodule
PS2鼠标接口
代码:
//Listing 10.4
module mouse
(
input wire clk, reset,
inout wire ps2d, ps2c,
output wire [8:0] xm, ym,
output wire [2:0] btnm,
output reg m_done_tick
);
// constant declaration
localparam STRM=8'hf4; // stream command F4
// symbolic state declaration
localparam [2:0]
init1 = 3'b000,
init2 = 3'b001,
init3 = 3'b010,
pack1 = 3'b011,
pack2 = 3'b100,
pack3 = 3'b101,
done = 3'b110;
// signal declaration
reg [2:0] state_reg, state_next;
wire [7:0] rx_data;
reg wr_ps2;
wire rx_done_tick, tx_done_tick;
reg [8:0] x_reg, y_reg, x_next, y_next;
reg [2:0] btn_reg, btn_next;
// body
// instantiation
ps2_rxtx ps2_unit
(.clk(clk), .reset(reset), .wr_ps2(wr_ps2),
.din(STRM), .dout(rx_data), .ps2d(ps2d), .ps2c(ps2c),
.rx_done_tick(rx_done_tick),
.tx_done_tick(tx_done_tick));
// body
// FSMD state and data registers
always @(posedge clk, posedge reset)
if (reset)
begin
state_reg <= init1;
x_reg <= 0;
y_reg <= 0;
btn_reg <= 0;
end
else
begin
state_reg <= state_next;
x_reg <= x_next;
y_reg <= y_next;
btn_reg <= btn_next;
end
// FSMD next-state logic
always @*
begin
state_next = state_reg;
wr_ps2 = 1'b0;
m_done_tick = 1'b0;
x_next = x_reg;
y_next = y_reg;
btn_next = btn_reg;
case (state_reg)
init1:
begin
wr_ps2 = 1'b1;
state_next = init2;
end
init2: // wait for send to complete
if (tx_done_tick)
state_next = init3;
init3: // wait for acknowledge packet
if (rx_done_tick)
state_next = pack1;
pack1: // wait for 1st data packet
if (rx_done_tick)
begin
state_next = pack2;
y_next[8] = rx_data[5];
x_next[8] = rx_data[4];
btn_next = rx_data[2:0];
end
pack2: // wait for 2nd data packet
if (rx_done_tick)
begin
state_next = pack3;
x_next[7:0] = rx_data;
end
pack3: // wait for 3rd data packet
if (rx_done_tick)
begin
state_next = done;
y_next[7:0] = rx_data;
end
done:
begin
m_done_tick = 1'b1;
state_next = pack1;
end
endcase
end
// output
assign xm = x_reg;
assign ym = y_reg;
assign btnm = btn_reg;
endmodule
实验:鼠标对LED控制
代码:
//Listing 10.5
module mouse_led
(
input wire clk, reset,
inout wire ps2d, ps2c,
output reg [7:0] led
);
// signal declaration
reg [9:0] p_reg;
wire [9:0] p_next;
wire [8:0] xm;
wire [2:0] btnm;
wire m_done_tick;
// body
// instantiation
mouse mouse_unit
(.clk(clk), .reset(reset), .ps2d(ps2d), .ps2c(ps2c),
.xm(xm), .ym(), .btnm(btnm),
.m_done_tick(m_done_tick));
// counter
always @(posedge clk, posedge reset)
if (reset)
p_reg <= 0;
else
p_reg <= p_next;
assign p_next = (~m_done_tick) ? p_reg : // no activity
(btnm[0]) ? 10'b0 : // left button
(btnm[1]) ? 10'h3ff : // right button
p_reg + {xm[8], xm}; // x movement
always @*
case (p_reg[9:7])
3'b000: led = 8'b10000000;
3'b001: led = 8'b01000000;
3'b010: led = 8'b00100000;
3'b011: led = 8'b00010000;
3'b100: led = 8'b00001000;
3'b101: led = 8'b00000100;
3'b110: led = 8'b00000010;
default: led = 8'b00000001;
endcase
endmodule
路漫漫其修远兮,吾将上下而求索
浙公网安备 33010602011771号