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
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.
代码:
//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
代码:
//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
代码:
//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