Friday, 18 August 2017

FPGA Verilog PS2 mouse test Waveshare Xilinx Spartan 3 development board

The project uses a simple testing circuit to demonstrate the use of the PS2 interface. The code for the circuit supports a ps2 mouse interface. Only one of the eight LEDs is lit and the position of that LED follows the x-axis movement of the mouse. The pressing of the left or right button places the lit LED to the leftmost or rightmost position. A 10-bit counter to keeps track of the current x-axis position. The counter is updated when a new data item is available.

FILES DOWNLOAD

TOP MODULE

 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'b00000001;  
      3'b001: led = 8'b00000010;  
      3'b010: led = 8'b00000100;  
      3'b011: led = 8'b00001000;  
      3'b100: led = 8'b00010000;  
      3'b101: led = 8'b00100000;  
      3'b110: led = 8'b01000000;  
      default:led = 8'b10000000;  
    endcase  
 endmodule  


MOUSE MAIN PROGRAM MODULE

 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  

RECEIVER TRANSMITTER MODULE

 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  

RECEIVER

 module ps2_rx  
   (  
   input wire clk, reset,  
   input wire ps2d, ps2c, rx_en,  
   output reg rx_done_tick,  
   output wire [7:0] dout  
   );  
   // symbolic state declaration  
   localparam [1:0]  
    idle = 2'b00,  
    dps = 2'b01,  
    load = 2'b10;  
   // signal declaration  
   reg [1: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 [10:0] b_reg, b_next;  
   wire fall_edge;  
   // 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;  
       n_reg <= 0;  
       b_reg <= 0;  
      end  
    else  
      begin  
       state_reg <= state_next;  
       n_reg <= n_next;  
       b_reg <= b_next;  
      end  
   // FSMD next-state logic  
   always @*  
   begin  
    state_next = state_reg;  
    rx_done_tick = 1'b0;  
    n_next = n_reg;  
    b_next = b_reg;  
    case (state_reg)  
      idle:  
       if (fall_edge & rx_en)  
         begin  
          // shift in start bit  
          b_next = {ps2d, b_reg[10:1]};  
          n_next = 4'b1001;  
          state_next = dps;  
         end  
      dps: // 8 data + 1 parity + 1 stop  
       if (fall_edge)  
         begin  
          b_next = {ps2d, b_reg[10:1]};  
          if (n_reg==0)  
            state_next = load;  
          else  
            n_next = n_reg - 1;  
         end  
      load: // 1 extra clock to complete the last shift  
       begin  
         state_next = idle;  
         rx_done_tick = 1'b1;  
       end  
    endcase  
   end  
   // output  
   assign dout = b_reg[8:1]; // data bits  
 endmodule  


TRANSMITTER

 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  
            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)  
          state_next = start;  
       end  
      start: // assert start bit  
       begin  
         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  

TUTORIAL ON HOW TO ADD TIMING CONSTRAINTS TO A MODULE


CONSTRAINT FILE
 #Created by Constraints Editor (xc3s250e-tled144-4) - 2017/07/29  
 NET "clk" LOC = "P129"; #TNM_NET = clk;  
 TIMESPEC TS_clk = PERIOD "clk" 50 MHz HIGH 50%;  
 #8I/Os_2 (Input)  
 NET "reset" LOC = "p94" ;  
 #16I/Os_1 (output)  
 NET "ps2d" LOC = "p83" ;  
 NET "ps2c" LOC = "p82" ;  
 #16I/Os_1  
 NET "led[0]" LOC = "p126";  
 NET "led[1]" LOC = "p124" ;  
 NET "led[2]" LOC = "p122";  
 NET "led[3]" LOC = "p116";  
 NET "led[4]" LOC = "p112";  
 NET "led[5]" LOC = "p105";  
 NET "led[6]" LOC = "p103";  
 NET "led[7]" LOC = "p97";  

No comments:

Post a Comment