URL
https://opencores.org/ocsvn/next186_soc_pc/next186_soc_pc/trunk
Subversion Repositories next186_soc_pc
[/] [next186_soc_pc/] [trunk/] [HW/] [KB_8042.v] - Rev 15
Go to most recent revision | Compare with Previous | Blame | View Log
////////////////////////////////////////////////////////////////////////////////// // // This file is part of the Next186 Soc PC project // http://opencores.org/project,next186 // // Filename: KB_8042.v // Description: Part of the Next186 SoC PC project, keyboard/mouse PS2 controller // Simplified 8042 implementation // Version 1.0 // Creation date: Jan2013 // // Author: Nicolae Dumitrache // e-mail: ndumitrache@opencores.org // ///////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2013 Nicolae Dumitrache // // This source file may be used and distributed without // restriction provided that this copyright statement is not // removed from the file and that any derivative work contains // the original copyright notice and the associated disclaimer. // // This source file is free software; you can redistribute it // and/or modify it under the terms of the GNU Lesser General // Public License as published by the Free Software Foundation; // either version 2.1 of the License, or (at your option) any // later version. // // This source is distributed in the hope that it will be // useful, but WITHOUT ANY WARRANTY; without even the implied // warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the GNU Lesser General Public License for more // details. // // You should have received a copy of the GNU Lesser General // Public License along with this source; if not, download it // from http://www.opencores.org/lgpl.shtml // /////////////////////////////////////////////////////////////////////////////////// // Additional Comments: // // http://www.computer-engineering.org/ps2keyboard/ // http://wiki.osdev.org/%228042%22_PS/2_Controller // http://wiki.osdev.org/Mouse_Input // // Primary connection // NET "PS2_CLK1" LOC = "W12" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; // NET "PS2_DATA1" LOC = "V11" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; // Secondary connection (requires Y-splitter cable) // NET "PS2_CLK2" LOC = "U11" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; // NET "PS2_DATA2" LOC = "Y12" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; ////////////////////////////////////////////////////////////////////////////////// `timescale 1ns / 1ps module KB_Mouse_8042( input CS, input WR, input cmd, // 0x60 = data, 0x64 = cmd input [7:0]din, output OE, output [7:0]dout, input clk, // cpu CLK output I_KB, // interrupt keyboard output I_MOUSE, // interrupt mouse output reg CPU_RST = 0, inout PS2_CLK1, inout PS2_CLK2, inout PS2_DATA1, inout PS2_DATA2 ); // status bit5 = MOBF (mouse to host buffer full - with OBF), bit4=INH, bit2(1-initialized ok), bit1(IBF-input buffer full - host to kb/mouse), bit0(OBF-output buffer full - kb/mouse to host) reg [3:0]cmdbyte = 4'b1100; // EN2,EN,INT2,INT reg wcfg = 0; // write config byte reg next_mouse = 0; reg ctl_outb = 0; reg [9:0]wr_data; reg [14:0]cnt100us = 0; // single delay counter for both kb and mouse reg wr_mouse = 0; reg wr_kb = 0; reg rd_kb = 0; reg rd_mouse = 0; reg OBF = 0; reg MOBF = 0; wire [7:0]kb_data; wire [7:0]mouse_data; wire kb_data_out_ready; wire kb_data_in_ready; wire mouse_data_out_ready; wire mouse_data_in_ready; wire IBF = ((wr_kb | ~kb_data_in_ready) & ~cmdbyte[2]) | ((wr_mouse | ~mouse_data_in_ready) & ~cmdbyte[3]); wire [7:0]inb = ctl_outb ? {2'b00, cmdbyte[3:2], 2'b00, cmdbyte[1:0]} : MOBF ? mouse_data : kb_data; wire kb_shift; wire mouse_shift; assign OE = CS & ~WR; assign dout = cmd ? {2'b00, MOBF, 1'b1, wcfg, 1'b1, IBF, OBF | MOBF | ctl_outb} : inb; assign I_KB = cmdbyte[0] & OBF; // INT & OBF assign I_MOUSE = cmdbyte[1] & MOBF; // INT2 & MOBF PS2Interface Keyboard ( .PS2_CLK(PS2_CLK1), .PS2_DATA(PS2_DATA1), .clk(clk), .rd(rd_kb), .wr(wr_kb), .data_in(wr_data[0]), .data_out(kb_data), .data_out_ready(kb_data_out_ready), .data_in_ready(kb_data_in_ready), .delay100us(cnt100us[14]), .data_shift(kb_shift) ); PS2Interface Mouse ( .PS2_CLK(PS2_CLK2), .PS2_DATA(PS2_DATA2), .clk(clk), .rd(rd_mouse), .wr(wr_mouse), .data_in(wr_data[0]), .data_out(mouse_data), .data_out_ready(mouse_data_out_ready), .data_in_ready(mouse_data_in_ready), .delay100us(cnt100us[14]), .data_shift(mouse_shift) ); always @(posedge clk) begin CPU_RST <= 0; if(~kb_data_in_ready) wr_kb <= 0; if(~kb_data_out_ready) rd_kb <= 1'b0; if(~mouse_data_in_ready) wr_mouse <= 0; if(~mouse_data_out_ready) rd_mouse <= 1'b0; if(CS & WR & ~cmd & ~wcfg) cnt100us <= 0; // reset 100us counter for PS2 writing else if(!cnt100us[14]) cnt100us <= cnt100us + 1; if(~OBF & ~MOBF) if(kb_data_out_ready & ~rd_kb & ~cmdbyte[2]) OBF <= 1'b1; else MOBF <= mouse_data_out_ready & ~rd_mouse & ~cmdbyte[3]; if(kb_shift | mouse_shift) wr_data <= {1'b1, wr_data[9:1]}; if(CS) if(WR) if(cmd) // 0x64 write case(din) 8'h20: ctl_outb <= 1; // read config byte 8'h60: wcfg <= 1; // write config byte 8'ha7: cmdbyte[3] <= 1; // disable mouse 8'ha8: cmdbyte[3] <= 0; // enable mouse 8'had: cmdbyte[2] <= 1; // disable kb 8'hae: cmdbyte[2] <= 0; // enable kb 8'hd4: next_mouse <= 1; // write next byte to mouse /*8'hf0, 8'hf2, 8'hf4, 8'hf6, 8'hf8, 8'hfa, 8'hfc,*/ 8'hfe: CPU_RST <= 1; // CPU reset endcase else begin // 0x60 write if(wcfg) cmdbyte <= {din[5:4], din[1:0]}; else begin next_mouse <= 0; wr_mouse <= next_mouse; wr_kb <= ~next_mouse; wr_data <= {~^din, din, 1'b0}; // cnt100us <= 0; // reset 100us counter for PS2 writing end wcfg <= 0; end else // read data if(~cmd) begin ctl_outb <= 1'b0; if(!ctl_outb) begin OBF <= 1'b0; MOBF <= 1'b0; rd_kb <= OBF; rd_mouse <= MOBF; end end end endmodule module PS2Interface( inout PS2_CLK, inout PS2_DATA, input clk, input rd, // enable PS2 data reading input wr, // can write data from controller to PS2 input data_in, // data from controller input delay100us, output [7:0]data_out, // data from PS2 output reg data_out_ready = 1, // PS2 received data ready output reg data_in_ready = 1, // PS2 sent data ready output data_shift ); reg [1:0]s_clk = 2'b11; reg [9:0]data = 0; reg rd_progress = 0; assign PS2_CLK = ((~data_out_ready & data_in_ready) | (~data_in_ready & delay100us)) ? 1'bz : 1'b0; assign PS2_DATA = (data_in_ready | data_in | ~delay100us) ? 1'bz : 1'b0; assign data_out = data[7:0]; assign data_shift = ~data_in_ready && delay100us && s_clk == 2'b10; always @(posedge clk) begin s_clk <= {s_clk[0], PS2_CLK}; if(data_out_ready) rd_progress <= 1'b0; if(~data_in_ready) begin // send data to PS2 if(data_shift) data_in_ready <= data_in ^ PS2_DATA; end else if(wr && ~rd_progress) begin // initiate data sending to PS2 data_in_ready <= 1'b0; end else if(~data_out_ready) begin // receive data from PS2 if(s_clk == 2'b10) begin rd_progress <= 1'b1; if(!rd_progress) data <= 10'b1111111111; end if(s_clk == 2'b01 && rd_progress) {data, data_out_ready} <= {PS2_DATA, data[9:1], ~data[0]}; // receive is ended by the stop bit end else if(rd) begin // initiate data receiving from PS2 // data <= 10'b1111111111; data_out_ready <= 1'b0; end end endmodule
Go to most recent revision | Compare with Previous | Blame | View Log