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

posted on 2011-04-19 11:33  齐威王  阅读(2537)  评论(0编辑  收藏  举报

导航