OpenCores
URL https://opencores.org/ocsvn/rtf68ksys/rtf68ksys/trunk

Subversion Repositories rtf68ksys

[/] [rtf68ksys/] [trunk/] [rtl/] [verilog/] [FF_PS2kbd.v] - Blame information for rev 2

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 robfinch
// ============================================================================
2
//      FF_PS2kbd.v - PS2 compatibla keyboard interface
3
//
4
//      2005.2010  Robert Finch
5
//      robfinch<remove>@FPGAfield.ca
6
//
7
//
8
//  This source code is available for evaluation and validation purposes
9
//  only. This copyright statement and disclaimer must remain present in
10
//  the file.
11
//
12
//
13
//      NO WARRANTY.
14
//  THIS Work, IS PROVIDEDED "AS IS" WITH NO WARRANTIES OF ANY KIND, WHETHER
15
//  EXPRESS OR IMPLIED. The user must assume the entire risk of using the
16
//  Work.
17
//
18
//  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY
19
//  INCIDENTAL, CONSEQUENTIAL, OR PUNITIVE DAMAGES WHATSOEVER RELATING TO
20
//  THE USE OF THIS WORK, OR YOUR RELATIONSHIP WITH THE AUTHOR.
21
//
22
//  IN ADDITION, IN NO EVENT DOES THE AUTHOR AUTHORIZE YOU TO USE THE WORK
23
//  IN APPLICATIONS OR SYSTEMS WHERE THE WORK'S FAILURE TO PERFORM CAN
24
//  REASONABLY BE EXPECTED TO RESULT IN A SIGNIFICANT PHYSICAL INJURY, OR IN
25
//  LOSS OF LIFE. ANY SUCH USE BY YOU IS ENTIRELY AT YOUR OWN RISK, AND YOU
26
//  AGREE TO HOLD THE AUTHOR AND CONTRIBUTORS HARMLESS FROM ANY CLAIMS OR
27
//  LOSSES RELATING TO SUCH UNAUTHORIZED USE.
28
//
29
//
30
//      PS2 compatible keyboard / mouse interface
31
//
32
//              This core provides a raw interface to the a PS2
33
//      keyboard or mouse. The interface is raw in the sense
34
//      that it doesn't do any scan code processing, it
35
//      just supplies it to the system. The core uses a
36
//      WISHBONE compatible bus interface.
37
//              Both transmit and recieve are
38
//      supported. It is possible to build the core without
39
//      the transmitter to reduce the size of the core; however
40
//      then it would not be possible to control the leds on
41
//      the keyboard. (The transmitter is required for a mouse
42
//      interface).
43
//              There is a 5us debounce circuit on the incoming
44
//      clock.
45
//              The transmitter does not have a watchdog timer, so
46
//      it may cause the keyboard to stop responding if there
47
//      was a problem with the transmit. It relys on the system
48
//      to reset the transmitter after 30ms or so of no
49
//      reponse. Resetting the transmitter should allow the
50
//      keyboard to respond again.
51
//      Note: keyboard clock must be at least three times slower
52
//      than the clk_i input to work reliably.
53
//      A typical keyboard clock is <30kHz so this should be ok
54
//      for most systems.
55
//      * There must be pullup resistors on the keyboard clock
56
//      and data lines, and the keyboard clock and data lines
57
//      are assumed to be open collector.
58
//              To read the keyboard, wait for bit 7 of the status
59
//      register to be set, then read the transmit / recieve
60
//      register. Reading the transmit / recieve register clears
61
//      the keyboard reciever, and allows the next character to
62
//      be recieved.
63
//
64
//      Reg
65
//      0        keyboard transmit/receive register
66
//      1       status reg.             itk xxxx p
67
//              i = interrupt status
68
//              t = transmit complete
69
//              k = transmit acknowledge receipt (from keyboard)
70
//              p = parity error
71
//              A write to the status register clears the transmitter
72
//              state
73
//
74
//
75
//
76
//      Webpack 9.1i xc3s1000-4ft256    
77
//      LUTs / slices / MHz
78
//       block rams
79
//      multiplier
80
//
81
// ============================================================================
82
//      A good source of info:
83
//      http://panda.stb_i.ndsu.nodak.edu/~achapwes/PICmicro/PS2/ps2.htm
84
//      http://www.beyondlogic.org/keyboard/keybrd.htm
85
//
86
//      From the keyboard
87
//      1 start bit
88
//      8 data bits
89
//      1 parity bit
90
//      1 stop bit
91
//
92
//      +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
93
//      |WISHBONE Datasheet
94
//      |WISHBONE SoC Architecture Specification, Revision B.3
95
//      |
96
//      |Description:                                           Specifications:
97
//      +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
98
//      |General Description:                           PS2 keyboard / mouse interface
99
//      +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
100
//      |Supported Cycles:                                      SLAVE,READ/WRITE
101
//      |                                                                       SLAVE,BLOCK READ/WRITE
102
//      |                                                                       SLAVE,RMW
103
//      +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
104
//      |Data port, size:                                       8 bit
105
//      |Data port, granularity:                        8 bit
106
//      |Data port, maximum operand size:       8 bit
107
//      |Data transfer ordering:                        Undefined
108
//      |Data transfer sequencing:                      Undefined
109
//      +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
110
//      |Clock frequency constraints:           none
111
//      +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
112
//      |Supported signal list and                      Signal Name             WISHBONE equiv.
113
//      |cross reference to equivalent          ack_o                   ACK_O
114
//      |WISHBONE signals                                       adr_i                   ADR_I()
115
//      |                                                                       clk_i                   CLK_I
116
//      |                                   cyc_i           CYC_I
117
//      |                                                                       dat_i(7:0)              DAT_I()
118
//      |                                                                       dat_o(7:0)              DAT_O()
119
//      |                                                                       stb_i                   STB_I
120
//      |                                                                       we_i                    WE_I
121
//      |
122
//      +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
123
//      |Special requirements:
124
//      +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
125
//
126
//      Note to self:
127
//      117LUTs / 66 slices / 95MHz
128
//      57LUTs / 32 slices / 107MHz - no transmitter
129
//==================================================================
130
 
131
`define KBD_TX          // include transmitter
132
 
133
`define S_KBDRX_WAIT_CLK                0
134
`define S_KBDRX_CHK_CLK_LOW             1
135
`define S_KBDRX_CAPTURE_BIT             2
136
 
137
module FF_PS2kbd(
138
        // WISHBONE/SoC bus interface 
139
        input rst_i,
140
        input clk_i,    // system clock
141
        input cyc_i,
142
        input stb_i,    // core select (active high)
143
        output ack_o,   // bus transfer acknowledged
144
        input we_i,     // I/O write taking place (active high)
145
        input [43:0] adr_i,      // address
146
        input [15:0] dat_i,      // data in
147
        output reg [15:0] dat_o, // data out
148
        output vol_o,   // volatile register selected
149
        //-------------
150
        output irq,     // interrupt request (active high)
151
        inout tri kclk, // keyboard clock from keyboard
152
        inout tri kd    // keyboard data
153
);
154
parameter pClkFreq = 28636360;
155
parameter p5us = pClkFreq / 200000;             // number of clocks for 5us
156
parameter p100us = pClkFreq / 10000;    // number of clocks for 100us
157
 
158
reg [11:0] os;   // one shot
159
wire os_5us_done = os==p5us;
160
wire os_100us_done = os==p100us;
161
reg [10:0] q;    // receive register
162
reg tc;                 // transmit complete indicator
163
reg [1:0] s_rx;  // keyboard receive state
164
reg [1:0] kq;
165
reg [1:0] kqc;
166
wire kqcne;                     // negative edge on kqc
167
wire kqcpe;                     // positive edge on kqc
168
assign irq = ~q[0];
169
reg kack;                       // keyboard acknowledge bit
170
`ifdef KBD_TX
171
reg [16:0] tx_state;     // transmitter states
172
reg klow;               // force clock line low
173
reg [10:0] t;    // transmit register
174
wire rx_inh = ~tc;      // inhibit receive while transmit occuring
175
reg [3:0] bitcnt;
176
wire shift_done = bitcnt==0;
177
reg tx_oe;                      // transmitter output enable / shift enable
178
`else
179
wire rx_inh = 0;
180
`endif
181
 
182
wire cs = cyc_i && stb_i && (adr_i[43:8]==36'hFFF_FFDC_00);
183
assign vol_o = cs;
184
assign ack_o = cs;
185
 
186
// register read path
187
always @(adr_i or q or tc or kack or cs) begin
188
        if (cs)
189
        case(adr_i[1:0])
190
        2'd0:   dat_o <= q[8:1];
191
        2'd2:   dat_o <= {~q[0],tc,~kack,4'b0,~^q[9:1]};
192
        default:        dat_o <= 16'd0;
193
        endcase
194
        else
195
                dat_o <= 16'h0000;
196
end
197
 
198
// Prohibit keyboard device from further transmits until
199
// this character has been processed.
200
// Holding the clock line low does this.
201
assign kclk = irq ? 1'b0 : 1'bz;
202
`ifdef KBD_TX
203
// Force clock and data low during transmits
204
assign kclk = klow ? 1'b0 : 1'bz;
205
assign kd = tx_oe & ~t[0] ? 1'b0 : 1'bz;
206
`endif
207
 
208
// stabilize clock and data
209
always @(posedge clk_i) begin
210
        kq <= {kq[0],kd};
211
        kqc <= {kqc[0],kclk};
212
end
213
 
214
edge_det ed0 (.rst(rst_i), .clk(clk_i), .ce(1'b1), .i(kqc[1]), .pe(kqcpe), .ne(kqcne) );
215
 
216
 
217
// The debounce one-shot and 100us timer        
218
always @(posedge clk_i)
219
        if (rst_i)
220
                os <= 0;
221
        else begin
222
                if ((s_rx==`S_KBDRX_WAIT_CLK && kqcne && ~rx_inh)||
223
                        (s_rx==`S_KBDRX_CHK_CLK_LOW && rx_inh)
224
`ifdef KBD_TX
225
                        ||tx_state[0]||tx_state[2]||tx_state[5]||tx_state[7]||tx_state[9]||tx_state[11]||tx_state[14]
226
`endif
227
                        )
228
                        os <= 0;
229
                else
230
                        os <= os + 1;
231
        end
232
 
233
 
234
// Receive state machine
235
always @(posedge clk_i) begin
236
        if (rst_i) begin
237
                q <= 11'h7FF;
238
                s_rx <= `S_KBDRX_WAIT_CLK;
239
        end
240
        else begin
241
 
242
                // clear rx on read
243
                if (ack_o & ~we_i & ~adr_i[0])
244
                        q <= 11'h7FF;
245
 
246
                // Receive state machine
247
                case (s_rx)     // synopsys full_case parallel_case
248
                // negedge on kclk ?
249
                // then set debounce one-shot
250
                `S_KBDRX_WAIT_CLK:
251
                        if (kqcne && ~rx_inh)
252
                                s_rx <= `S_KBDRX_CHK_CLK_LOW;
253
 
254
                // wait 5us
255
                // check if clock low
256
                `S_KBDRX_CHK_CLK_LOW:
257
                        if (rx_inh)
258
                                s_rx <= `S_KBDRX_WAIT_CLK;
259
                        else if (os_5us_done) begin
260
                                // clock low ?
261
                                if (~kqc[1])
262
                                        s_rx <= `S_KBDRX_CAPTURE_BIT;
263
                                else
264
                                        s_rx <= `S_KBDRX_WAIT_CLK;      // no - spurious
265
                        end
266
 
267
                // capture keyboard bit
268
                // keyboard transmits LSB first
269
                `S_KBDRX_CAPTURE_BIT:
270
                        begin
271
                        q <= {kq,q[10:1]};
272
                        s_rx <= `S_KBDRX_WAIT_CLK;
273
                        end
274
 
275
                default:
276
                        s_rx <= `S_KBDRX_WAIT_CLK;
277
                endcase
278
        end
279
end
280
 
281
 
282
`ifdef KBD_TX
283
 
284
// Transmit state machine
285
// a shift register / ring counter is used
286
reg adv_tx_state;                       // advance transmitter state
287
reg start_tx;                           // start the transmitter
288
reg clear_tx;                           // clear the transmit state
289
always @(posedge clk_i)
290
        if (rst_i)
291
                tx_state <= 0;
292
        else begin
293
                if (clear_tx)
294
                        tx_state <= 0;
295
                else if (start_tx)
296
                        tx_state[0] <= 1;
297
                else if (adv_tx_state) begin
298
                        tx_state[6:0] <= {tx_state[5:0],1'b0};
299
                        tx_state[7] <= (tx_state[8] && !shift_done) || tx_state[6];
300
                        tx_state[8] <= tx_state[7];
301
                        tx_state[9] <= tx_state[8] && shift_done;
302
                        tx_state[16:10] <= tx_state[15:9];
303
                end
304
        end
305
 
306
 
307
// detect when to advance the transmit state
308
always @(tx_state or kqcne or kqcpe or kqc or os_100us_done or os_5us_done)
309
        case (1'b1)             // synopsys parallel_case
310
        tx_state[0]:     adv_tx_state <= 1;
311
        tx_state[1]:    adv_tx_state <= os_100us_done;
312
        tx_state[2]:    adv_tx_state <= 1;
313
        tx_state[3]:    adv_tx_state <= os_5us_done;
314
        tx_state[4]:    adv_tx_state <= 1;
315
        tx_state[5]:    adv_tx_state <= kqcne;
316
        tx_state[6]:    adv_tx_state <= os_5us_done;
317
        tx_state[7]:    adv_tx_state <= kqcpe;
318
        tx_state[8]:    adv_tx_state <= os_5us_done;
319
        tx_state[9]:    adv_tx_state <= kqcpe;
320
        tx_state[10]:   adv_tx_state <= os_5us_done;
321
        tx_state[11]:   adv_tx_state <= kqcne;
322
        tx_state[12]:   adv_tx_state <= os_5us_done;
323
        tx_state[13]:   adv_tx_state <= 1;
324
        tx_state[14]:   adv_tx_state <= kqcpe;
325
        tx_state[15]:   adv_tx_state <= os_5us_done;
326
        default:                adv_tx_state <= 0;
327
        endcase
328
 
329
wire load_tx = ack_o & we_i & ~adr_i[1];
330
wire shift_tx = (tx_state[7] & kqcpe)|tx_state[4];
331
 
332
// It can take up to 20ms for the keyboard to accept data
333
// from the host.
334
always @(posedge clk_i) begin
335
        if (rst_i) begin
336
                klow <= 0;
337
                tc <= 1;
338
                start_tx <= 0;
339
                tx_oe <= 0;
340
        end
341
        else begin
342
 
343
                clear_tx <= 0;
344
                start_tx <= 0;
345
 
346
                // write to keyboard register triggers whole thing
347
                if (load_tx) begin
348
                        start_tx <= 1;
349
                        tc <= 0;
350
                end
351
                // write to status register clears transmit state
352
                else if (ack_o & we_i & adr_i[1]) begin
353
                        tc <= 1;
354
                        tx_oe <= 0;
355
                        klow <= 1'b0;
356
                        clear_tx <= 1;
357
                end
358
                else begin
359
 
360
                        case (1'b1)     // synopsys parallel_case
361
 
362
                        tx_state[0]:     klow <= 1'b1;   // First step: pull the clock low
363
                        tx_state[1]:    ;                               // wait 100 us (hold clock low)
364
                        tx_state[2]:    tx_oe <= 1;             // bring data low / enable shift
365
                        tx_state[3]:    ;       // wait 5us
366
                        // at this point the clock should go high
367
                        // and shift out the start bit
368
                        tx_state[4]:    klow <= 0;               // release clock line
369
                        tx_state[5]:    ;                               // wait for clock to go low
370
                        tx_state[6]:    ;                               // wait 5us
371
                        // state7, 8 shift the data out
372
                        tx_state[7]:    ;                               // wait for clock to go high
373
                        tx_state[8]:    ;                               // wait 5us, go back to state 7
374
                        tx_state[9]:    tx_oe <= 0;              // wait for clock to go high // disable transmit output / shift
375
                        tx_state[10]:   ;                               // wait 5us
376
                        tx_state[11]:   ;                               // wait for clock to go low
377
                        tx_state[12]:   ;                               // wait 5us
378
                        tx_state[13]:   kack <= kq[1];  // capture the ack_o bit from the keyboard
379
                        tx_state[14]:   ;                               // wait for clock to go high
380
                        tx_state[15]:   ;                               // wait 5us
381
                        tx_state[16]:
382
                                begin
383
                                        tc <= 1;                // transmit is now complete
384
                                        clear_tx <= 1;
385
                                end
386
 
387
                        default:        ;
388
 
389
                        endcase
390
                end
391
        end
392
end
393
 
394
 
395
// transmitter shift register
396
always @(posedge clk_i)
397
        if (rst_i)
398
                t <= 11'd0;
399
        else begin
400
                if (load_tx)
401
                        t <= {~(^dat_i),dat_i,2'b0};
402
                else if (shift_tx)
403
                        t <= {1'b1,t[10:1]};
404
        end
405
 
406
 
407
// transmitter bit counter
408
always @(posedge clk_i)
409
        if (rst_i)
410
                bitcnt <= 4'd0;
411
        else begin
412
                if (load_tx)
413
                        bitcnt <= 4'd11;
414
                else if (shift_tx)
415
                        bitcnt <= bitcnt - 4'd1;
416
        end
417
 
418
`endif
419
 
420
endmodule

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.