/**************************************************************************** PS/2 mouse interface the top level module is: ps2_mouse(clock, mdata, mclock, data, receive_key); ****************************************************************************/ `define TIMEOUT_WIDTH 24 // timeout a byte after 2^24 clock ticks // mouse should send a "heart beat" signal more frequently than this if alive `define CLOCKLOW_TIME 11'd1500 // time to pulse the clock low for to transmit - 60us `define CLOCK_LOW_BITS 11 module parallel_to_serial( clock, data_to_send, do_send, sending, mdata_out, mclock_in, mclock_out ); input clock; // high frequency clock input [7:0] data_to_send; // data to be sent input do_send; // 4-phase data send request output sending; // 4-phase data send acknowledge output mdata_out; // mouse serial data out input mclock_in; // mouse clock in output mclock_out; // mouse clock out reg sending, reset_clock_pulse; reg [`CLOCK_LOW_BITS-1:0] clock_low_timer; reg [9:0] data_shifter; reg [3:0] bit_counter; reg [2:0] sample_mclock; wire bits_to_send = (bit_counter!=0); assign mdata_out = bits_to_send ? data_shifter[0] : 1; assign mclock_out = !reset_clock_pulse; always @(posedge clock) begin sample_mclock <= {sample_mclock[1:0],mclock_in}; if(reset_clock_pulse) begin clock_low_timer <= clock_low_timer-1; if(clock_low_timer==0) reset_clock_pulse<=0; end else if(bits_to_send) begin if(sample_mclock[2] && !sample_mclock[1]) // after falling edge so shift data begin data_shifter <= {1'b1, data_shifter[9:1]}; bit_counter <= bit_counter-1; end end else begin clock_low_timer <= `CLOCKLOW_TIME; sending <= do_send; if(do_send && !sending) begin data_shifter <= {~(^data_to_send),data_to_send,1'b0}; bit_counter <= 10; // 1-start bit, 8-data bits, 1-parity bit, 1-stop bit reset_clock_pulse <= 1; end end end endmodule module serial_to_parallel( clock, enable, mdata_in, mclock_in, data_received, data_received_toggle ); input clock; // 25MHz clock input enable; // enable serial receive input mdata_in; // serial mouse data input input mclock_in; // mouse clock input output [7:0] data_received; // parallel version of data received output data_received_toggle; // 2-phase output signal indicating new data reg [7:0] data_received; reg [8:0] data_shiftreg; reg [3:0] recv_bit_counter; reg [2:0] mclock_history, mdata_history; reg byte_waiting, receiving, data_received_toggle; wire mclock_falling = mclock_history[2:1]==2'b10; wire reset = !enable; always @(posedge clock or posedge reset) if(reset) receiving <= 0; else begin mclock_history <= {mclock_history[1:0],mclock_in}; mdata_history <= {mdata_history[1:0],mdata_in}; if( mclock_falling && enable ) begin // data bit ready to recieve if( receiving ) if( recv_bit_counter < 4'd9 ) begin data_shiftreg[8:0] <= {mdata_history[2],data_shiftreg[8:1]}; recv_bit_counter <= recv_bit_counter+4'd1; end else begin // stop bit receiving <= 0; if( mdata_history[2] && (^data_shiftreg) ) begin // high stop bit, odd parity, so good data data_received <= data_shiftreg[7:0]; data_received_toggle <= !data_received_toggle; end end else if( !mdata_history[2] ) // legal start bit? begin receiving <= 1; recv_bit_counter <= 4'd0; end end end endmodule module ps2_mouse(clock, mdata, mclock, data, receive_key); input clock; // 25MHz clock inout mdata; // bidirectional mouse data (open collector) inout mclock; // bidirectional mouse clock (open collector) output [7:0] data; // data byte received output receive_key; // 2-phase signal to indicate data received wire mdata_out, mclock_out, sending; reg [`TIMEOUT_WIDTH-1:0] timeout_ctr; wire timeout = timeout_ctr[`TIMEOUT_WIDTH-1]; wire reset_timeout = !mclock; // clear timeout if mouse active always @(posedge clock) // timeout stuff if( reset_timeout ) timeout_ctr <= 0; else timeout_ctr <= timeout_ctr+1; wire do_reset = timeout_ctr[`TIMEOUT_WIDTH-1]; serial_to_parallel ser( .clock(clock), .mdata_in(mdata), .mclock_in(mclock), .data_received(data), .data_received_toggle( receive_key ), .enable(!sending) ); parallel_to_serial p2s( .clock(clock), .data_to_send(8'hF4), .do_send(do_reset), .sending(sending), .mdata_out(mdata_out), .mclock_in(mclock), .mclock_out(mclock_out) ); TRI op1( 0, !mdata_out, mdata ); // open collector output TRI op2( 0, !mclock_out, mclock ); endmodule