`timescale 1ns / 100ps module sim_mouse(inout clk, inout dat); `define CLK_HALF 5000 /* faster sim, should be more like 50000 */ reg aclk; reg adat; reg [7:0] cmd; task do_send; input [7:0] d; output ok; reg [10:0] sr; reg p; integer i; begin $display("sim_mouse: send %x", d); p = ~(d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[5] ^ d[6] ^ d[7]); sr = { 1'b1, p, d, 1'b0 }; aclk = 0; adat = 0; ok = 1; i = 11; while(i > 0 && ok) begin if (clk == 0) begin $display("Mouse: Clock low, aborting send"); ok = 0; end else begin adat = ~sr[0]; #`CLK_HALF aclk = 1; #`CLK_HALF aclk = 0; #1; sr = { 1'b0, sr[10:1] }; i = i - 1; end end aclk = 0; adat = 0; #`CLK_HALF; #`CLK_HALF; end endtask task do_receive; output [7:0] d; output ok; reg [10:0] sr; reg p; integer i; begin aclk = 0; adat = 0; sr = 0; wait(dat == 0); wait(clk != 0); ok = 1; i = 10; while(i > 0 && ok) begin if (clk == 0) begin $display("Mouse: Clock low, aborting receive"); ok = 0; end else begin #`CLK_HALF aclk = 1; #`CLK_HALF aclk = 0; #1; sr = { dat != 0, sr[10:1] }; i = i - 1; end end // while (i > 0 && ok) adat = 1; #`CLK_HALF aclk = 1; #`CLK_HALF aclk = 0; adat = 0; // $display("rx shift final: %b", sr); aclk = 0; adat = 0; d = sr[8:1]; #`CLK_HALF; #`CLK_HALF; $display("sim_mouse: got %x ok=%b", d, ok); end endtask pullup(clk); pullup(dat); assign clk = aclk ? 1'b0 : 1'bz; assign dat = adat ? 1'b0 : 1'bz; reg ok; always@(clk, dat) begin while (clk == 0) begin #`CLK_HALF; if (clk == 0) begin #`CLK_HALF; if (clk == 0) begin do_receive(cmd, ok); if (ok) begin if (cmd == 8'hf4) begin do_send(8'hfa, ok); end else if (cmd == 8'hff) begin if (ok) do_send(8'haa, ok); if (ok) do_send(8'h00, ok); end end end end end end initial begin aclk = 0; adat = 0; #`CLK_HALF; #`CLK_HALF; #`CLK_HALF; #`CLK_HALF; do_send(8'haa, ok); do_send(8'h00, ok); #6000000; do_send(8'h00, ok); do_send(8'h02, ok); do_send(8'h00, ok); #1000000; do_send(8'h00, ok); do_send(8'h02, ok); do_send(8'h00, ok); #1000000; do_send(8'h00, ok); do_send(8'h00, ok); do_send(8'h02, ok); end endmodule