1 |
2 |
ndumitrach |
//////////////////////////////////////////////////////////////////////////////////
|
2 |
|
|
//
|
3 |
|
|
// This file is part of the Next186 Soc PC project
|
4 |
|
|
// http://opencores.org/project,next186
|
5 |
|
|
//
|
6 |
|
|
// Filename: KB_8042.v
|
7 |
|
|
// Description: Part of the Next186 SoC PC project, keyboard/mouse PS2 controller
|
8 |
|
|
// Simplified 8042 implementation
|
9 |
|
|
// Version 1.0
|
10 |
|
|
// Creation date: Jan2013
|
11 |
|
|
//
|
12 |
|
|
// Author: Nicolae Dumitrache
|
13 |
|
|
// e-mail: ndumitrache@opencores.org
|
14 |
|
|
//
|
15 |
|
|
/////////////////////////////////////////////////////////////////////////////////
|
16 |
|
|
//
|
17 |
|
|
// Copyright (C) 2013 Nicolae Dumitrache
|
18 |
|
|
//
|
19 |
|
|
// This source file may be used and distributed without
|
20 |
|
|
// restriction provided that this copyright statement is not
|
21 |
|
|
// removed from the file and that any derivative work contains
|
22 |
|
|
// the original copyright notice and the associated disclaimer.
|
23 |
|
|
//
|
24 |
|
|
// This source file is free software; you can redistribute it
|
25 |
|
|
// and/or modify it under the terms of the GNU Lesser General
|
26 |
|
|
// Public License as published by the Free Software Foundation;
|
27 |
|
|
// either version 2.1 of the License, or (at your option) any
|
28 |
|
|
// later version.
|
29 |
|
|
//
|
30 |
|
|
// This source is distributed in the hope that it will be
|
31 |
|
|
// useful, but WITHOUT ANY WARRANTY; without even the implied
|
32 |
|
|
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
33 |
|
|
// PURPOSE. See the GNU Lesser General Public License for more
|
34 |
|
|
// details.
|
35 |
|
|
//
|
36 |
|
|
// You should have received a copy of the GNU Lesser General
|
37 |
|
|
// Public License along with this source; if not, download it
|
38 |
|
|
// from http://www.opencores.org/lgpl.shtml
|
39 |
|
|
//
|
40 |
|
|
///////////////////////////////////////////////////////////////////////////////////
|
41 |
|
|
// Additional Comments:
|
42 |
|
|
//
|
43 |
|
|
// http://www.computer-engineering.org/ps2keyboard/
|
44 |
|
|
// http://wiki.osdev.org/%228042%22_PS/2_Controller
|
45 |
|
|
// http://wiki.osdev.org/Mouse_Input
|
46 |
|
|
//
|
47 |
|
|
// Primary connection
|
48 |
|
|
// NET "PS2_CLK1" LOC = "W12" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
|
49 |
|
|
// NET "PS2_DATA1" LOC = "V11" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
|
50 |
|
|
// Secondary connection (requires Y-splitter cable)
|
51 |
|
|
// NET "PS2_CLK2" LOC = "U11" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
|
52 |
|
|
// NET "PS2_DATA2" LOC = "Y12" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
|
53 |
|
|
//////////////////////////////////////////////////////////////////////////////////
|
54 |
|
|
`timescale 1ns / 1ps
|
55 |
|
|
|
56 |
|
|
module KB_Mouse_8042(
|
57 |
|
|
input CS,
|
58 |
|
|
input WR,
|
59 |
|
|
input cmd, // 0x60 = data, 0x64 = cmd
|
60 |
|
|
input [7:0]din,
|
61 |
|
|
output OE,
|
62 |
|
|
output [7:0]dout,
|
63 |
|
|
input clk, // cpu CLK
|
64 |
|
|
output I_KB, // interrupt keyboard
|
65 |
|
|
output I_MOUSE, // interrupt mouse
|
66 |
|
|
output reg CPU_RST = 0,
|
67 |
|
|
inout PS2_CLK1,
|
68 |
|
|
inout PS2_CLK2,
|
69 |
|
|
inout PS2_DATA1,
|
70 |
|
|
inout PS2_DATA2
|
71 |
|
|
);
|
72 |
|
|
|
73 |
|
|
// 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)
|
74 |
|
|
reg [3:0]cmdbyte = 4'b1100; // EN2,EN,INT2,INT
|
75 |
|
|
reg wcfg = 0; // write config byte
|
76 |
|
|
reg next_mouse = 0;
|
77 |
|
|
reg ctl_outb = 0;
|
78 |
|
|
reg [9:0]wr_data;
|
79 |
|
|
reg [14:0]cnt100us = 0; // single delay counter for both kb and mouse
|
80 |
|
|
reg wr_mouse = 0;
|
81 |
|
|
reg wr_kb = 0;
|
82 |
|
|
reg rd_kb = 0;
|
83 |
|
|
reg rd_mouse = 0;
|
84 |
|
|
reg OBF = 0;
|
85 |
|
|
reg MOBF = 0;
|
86 |
|
|
|
87 |
|
|
wire [7:0]kb_data;
|
88 |
|
|
wire [7:0]mouse_data;
|
89 |
|
|
wire kb_data_out_ready;
|
90 |
|
|
wire kb_data_in_ready;
|
91 |
|
|
wire mouse_data_out_ready;
|
92 |
|
|
wire mouse_data_in_ready;
|
93 |
|
|
wire IBF = ((wr_kb | ~kb_data_in_ready) & ~cmdbyte[2]) | ((wr_mouse | ~mouse_data_in_ready) & ~cmdbyte[3]);
|
94 |
|
|
wire [7:0]inb = ctl_outb ? {2'b00, cmdbyte[3:2], 2'b00, cmdbyte[1:0]} : MOBF ? mouse_data : kb_data;
|
95 |
|
|
wire kb_shift;
|
96 |
|
|
wire mouse_shift;
|
97 |
|
|
|
98 |
|
|
assign OE = CS & ~WR;
|
99 |
|
|
assign dout = cmd ? {2'b00, MOBF, 1'b1, wcfg, 1'b1, IBF, OBF | MOBF | ctl_outb} : inb;
|
100 |
|
|
assign I_KB = cmdbyte[0] & OBF; // INT & OBF
|
101 |
|
|
assign I_MOUSE = cmdbyte[1] & MOBF; // INT2 & MOBF
|
102 |
|
|
|
103 |
|
|
PS2Interface Keyboard
|
104 |
|
|
(
|
105 |
|
|
.PS2_CLK(PS2_CLK1),
|
106 |
|
|
.PS2_DATA(PS2_DATA1),
|
107 |
|
|
.clk(clk),
|
108 |
|
|
.rd(rd_kb),
|
109 |
|
|
.wr(wr_kb),
|
110 |
|
|
.data_in(wr_data[0]),
|
111 |
|
|
.data_out(kb_data),
|
112 |
|
|
.data_out_ready(kb_data_out_ready),
|
113 |
|
|
.data_in_ready(kb_data_in_ready),
|
114 |
|
|
.delay100us(cnt100us[14]),
|
115 |
|
|
.data_shift(kb_shift)
|
116 |
|
|
);
|
117 |
|
|
|
118 |
|
|
PS2Interface Mouse
|
119 |
|
|
(
|
120 |
|
|
.PS2_CLK(PS2_CLK2),
|
121 |
|
|
.PS2_DATA(PS2_DATA2),
|
122 |
|
|
.clk(clk),
|
123 |
|
|
.rd(rd_mouse),
|
124 |
|
|
.wr(wr_mouse),
|
125 |
|
|
.data_in(wr_data[0]),
|
126 |
|
|
.data_out(mouse_data),
|
127 |
|
|
.data_out_ready(mouse_data_out_ready),
|
128 |
|
|
.data_in_ready(mouse_data_in_ready),
|
129 |
|
|
.delay100us(cnt100us[14]),
|
130 |
|
|
.data_shift(mouse_shift)
|
131 |
|
|
);
|
132 |
|
|
|
133 |
|
|
always @(posedge clk) begin
|
134 |
|
|
CPU_RST <= 0;
|
135 |
|
|
if(~kb_data_in_ready) wr_kb <= 0;
|
136 |
|
|
if(~kb_data_out_ready) rd_kb <= 1'b0;
|
137 |
|
|
if(~mouse_data_in_ready) wr_mouse <= 0;
|
138 |
|
|
if(~mouse_data_out_ready) rd_mouse <= 1'b0;
|
139 |
|
|
|
140 |
|
|
if(CS & WR & ~cmd & ~wcfg) cnt100us <= 0; // reset 100us counter for PS2 writing
|
141 |
|
|
else if(!cnt100us[14]) cnt100us <= cnt100us + 1;
|
142 |
|
|
|
143 |
|
|
if(~OBF & ~MOBF)
|
144 |
|
|
if(kb_data_out_ready & ~rd_kb & ~cmdbyte[2]) OBF <= 1'b1;
|
145 |
|
|
else MOBF <= mouse_data_out_ready & ~rd_mouse & ~cmdbyte[3];
|
146 |
|
|
|
147 |
|
|
if(kb_shift | mouse_shift) wr_data <= {1'b1, wr_data[9:1]};
|
148 |
|
|
|
149 |
|
|
if(CS)
|
150 |
|
|
if(WR)
|
151 |
|
|
if(cmd) // 0x64 write
|
152 |
|
|
case(din)
|
153 |
|
|
8'h20: ctl_outb <= 1; // read config byte
|
154 |
|
|
8'h60: wcfg <= 1; // write config byte
|
155 |
|
|
8'ha7: cmdbyte[3] <= 1; // disable mouse
|
156 |
|
|
8'ha8: cmdbyte[3] <= 0; // enable mouse
|
157 |
|
|
8'had: cmdbyte[2] <= 1; // disable kb
|
158 |
|
|
8'hae: cmdbyte[2] <= 0; // enable kb
|
159 |
|
|
8'hd4: next_mouse <= 1; // write next byte to mouse
|
160 |
|
|
/*8'hf0, 8'hf2, 8'hf4, 8'hf6, 8'hf8, 8'hfa, 8'hfc,*/ 8'hfe: CPU_RST <= 1; // CPU reset
|
161 |
|
|
endcase
|
162 |
|
|
else begin // 0x60 write
|
163 |
|
|
if(wcfg) cmdbyte <= {din[5:4], din[1:0]};
|
164 |
|
|
else begin
|
165 |
|
|
next_mouse <= 0;
|
166 |
|
|
wr_mouse <= next_mouse;
|
167 |
|
|
wr_kb <= ~next_mouse;
|
168 |
|
|
wr_data <= {~^din, din, 1'b0};
|
169 |
|
|
// cnt100us <= 0; // reset 100us counter for PS2 writing
|
170 |
|
|
end
|
171 |
|
|
wcfg <= 0;
|
172 |
|
|
end
|
173 |
|
|
else // read data
|
174 |
|
|
if(~cmd) begin
|
175 |
|
|
ctl_outb <= 1'b0;
|
176 |
|
|
if(!ctl_outb) begin
|
177 |
|
|
OBF <= 1'b0;
|
178 |
|
|
MOBF <= 1'b0;
|
179 |
|
|
rd_kb <= OBF;
|
180 |
|
|
rd_mouse <= MOBF;
|
181 |
|
|
end
|
182 |
|
|
end
|
183 |
|
|
end
|
184 |
|
|
endmodule
|
185 |
|
|
|
186 |
|
|
|
187 |
|
|
module PS2Interface(
|
188 |
|
|
inout PS2_CLK,
|
189 |
|
|
inout PS2_DATA,
|
190 |
|
|
input clk,
|
191 |
|
|
input rd, // enable PS2 data reading
|
192 |
|
|
input wr, // can write data from controller to PS2
|
193 |
|
|
input data_in, // data from controller
|
194 |
|
|
input delay100us,
|
195 |
|
|
output [7:0]data_out, // data from PS2
|
196 |
|
|
output reg data_out_ready = 1, // PS2 received data ready
|
197 |
|
|
output reg data_in_ready = 1, // PS2 sent data ready
|
198 |
|
|
output data_shift
|
199 |
|
|
);
|
200 |
|
|
reg [1:0]s_clk = 2'b11;
|
201 |
|
|
reg [9:0]data = 0;
|
202 |
|
|
reg rd_progress = 0;
|
203 |
|
|
|
204 |
|
|
assign PS2_CLK = ((~data_out_ready & data_in_ready) | (~data_in_ready & delay100us)) ? 1'bz : 1'b0;
|
205 |
|
|
assign PS2_DATA = (data_in_ready | data_in | ~delay100us) ? 1'bz : 1'b0;
|
206 |
|
|
assign data_out = data[7:0];
|
207 |
|
|
assign data_shift = ~data_in_ready && delay100us && s_clk == 2'b10;
|
208 |
|
|
|
209 |
|
|
always @(posedge clk) begin
|
210 |
|
|
s_clk <= {s_clk[0], PS2_CLK};
|
211 |
|
|
if(data_out_ready) rd_progress <= 1'b0;
|
212 |
|
|
|
213 |
|
|
if(~data_in_ready) begin // send data to PS2
|
214 |
|
|
if(data_shift) data_in_ready <= data_in ^ PS2_DATA;
|
215 |
|
|
end else if(wr && ~rd_progress) begin // initiate data sending to PS2
|
216 |
|
|
data_in_ready <= 1'b0;
|
217 |
|
|
end else if(~data_out_ready) begin // receive data from PS2
|
218 |
|
|
if(s_clk == 2'b10) begin
|
219 |
|
|
rd_progress <= 1'b1;
|
220 |
|
|
if(!rd_progress) data <= 10'b1111111111;
|
221 |
|
|
end
|
222 |
|
|
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
|
223 |
|
|
end else if(rd) begin // initiate data receiving from PS2
|
224 |
|
|
// data <= 10'b1111111111;
|
225 |
|
|
data_out_ready <= 1'b0;
|
226 |
|
|
end
|
227 |
|
|
end
|
228 |
|
|
endmodule
|