]> git.ozlabs.org Git - minimigmac.git/blob - fpga/ps2.v
Initial commit
[minimigmac.git] / fpga / ps2.v
1 `timescale 1ns / 100ps
2
3 /*
4  * Generic PS2 interface module
5  * 
6  * istrobe, oreq, oack and timeout are all 1-clk strobes,
7  * ibyte must be latched on that strobe, obyte is latched
8  * as oreq is detected, oreq is ignore while already
9  * sending.
10  * 
11  * we ignore bad parity on input for now
12  */
13
14 module ps2(input        sysclk,
15            input        reset,
16
17            inout        ps2dat,
18            inout        ps2clk,
19
20            output       istrobe,
21            output [7:0] ibyte,
22
23            input        oreq,
24            input [7:0]  obyte,
25            output       oack,
26
27            output       timeout,
28
29            output[1:0]  dbg_state
30            );
31
32         reg [7:0]       clkbuf;
33         reg [7:0]       datbuf;
34         reg             clksync;
35         reg             clkprev;
36         reg             datsync;        
37         reg [10:0]      shiftreg;
38         reg [3:0]       shiftcnt;
39         wire            shiftend;
40         reg [1:0]       state;
41         wire            datout;
42         reg [23:0]      timecnt;        
43         wire            clkdown;
44         wire            opar;
45
46         /* State machine */
47         localparam ps2_state_idle = 0;
48         localparam ps2_state_ring = 1;
49         localparam ps2_state_send = 2;
50         localparam ps2_state_recv = 3;
51
52         always@(posedge sysclk or posedge reset) begin
53                 if (reset)
54                   state <= ps2_state_idle;
55                 else begin
56                         if (timeout && !oreq)
57                           state <= ps2_state_idle;
58                         else
59                           case(state)
60                                   ps2_state_idle: begin
61                                           if (oreq)
62                                             state <= ps2_state_ring;
63                                           else if (clkdown)
64                                             state <= ps2_state_recv;
65                                   end
66                                   ps2_state_ring: begin
67                                           if (timecnt[12])
68                                             state <= ps2_state_send;
69                                   end
70                                   ps2_state_send: begin
71                                           if (shiftend)
72                                             state <= ps2_state_idle;
73                                   end
74                                   ps2_state_recv: begin
75                                           if (oreq)
76                                             state <= ps2_state_ring;
77                                           else if (shiftend)
78                                             state <= ps2_state_idle;
79                                   end
80                           endcase
81                 end
82         end
83         assign dbg_state = state;       
84
85         /* Tristate control of clk & data */
86         assign datout = state == ps2_state_ring || state == ps2_state_send;
87         assign ps2dat = (datout & ~shiftreg[0]) ? 1'b0 : 1'bz;
88         assign ps2clk = (state == ps2_state_ring) ? 1'b0 : 1'bz;
89
90         /* Bit counter */
91         always@(posedge sysclk or posedge reset) begin
92                 if (reset)
93                   shiftcnt <= 10;
94                 else begin
95                         if (state == ps2_state_idle)
96                           shiftcnt <= 10;
97                         else if (state == ps2_state_ring)
98                           shiftcnt <= 11;                       
99                         else if (clkdown && state != ps2_state_ring)
100                           shiftcnt <= shiftcnt - 1;
101                 end
102         end
103
104         /* Shift register, ticks on falling edge of ps2 clock */
105         always@(posedge sysclk or posedge reset) begin
106                 if (reset)
107                   shiftreg <= 0;
108                 else begin
109                         if (oreq)
110                           shiftreg <= { 1'b1, opar, obyte, 1'b0 };
111                         else if (clkdown && state != ps2_state_ring)
112                           shiftreg <= { datsync, shiftreg[10:1] };
113                 end
114         end
115
116
117         /* Ack/strobe logic */
118         assign shiftend = shiftcnt == 0;        
119         assign oack = (state == ps2_state_send && shiftend);
120         assign istrobe = (state == ps2_state_recv && shiftend); 
121         assign ibyte = shiftreg[8:1];
122
123         /* Filters/synchronizers on PS/2 clock */
124         always@(posedge sysclk or posedge reset) begin
125                 if (reset) begin
126                         clkbuf <= 0;
127                         clksync <= 0;
128                         clkprev <= 0;
129                 end else begin
130                         clkprev <= clksync;                     
131                         clkbuf <= { clkbuf[6:0], ps2clk };
132                         if (clkbuf[7:2] == 6'b000000)
133                           clksync <= 0;
134                         if (clkbuf[7:2] == 6'b111111)
135                           clksync <= 1;
136                 end
137         end
138         assign clkdown = clkprev & ~clksync;
139
140         /* Filters/synchronizers on PS/2 data */
141         always@(posedge sysclk or posedge reset) begin
142                 if (reset) begin
143                         datbuf <= 0;
144                         datsync <= 0;
145                 end else begin
146                         datbuf <= { datbuf[6:0], ps2dat };
147                         if (datbuf[7:2] == 6'b000000)
148                           datsync <= 0;
149                         if (datbuf[7:2] == 6'b111111)
150                           datsync <= 1;
151                 end
152         end
153                       
154         /* Parity for output byte */
155         assign opar = ~(obyte[0] ^ obyte[1] ^ obyte[2] ^ obyte[3] ^
156                         obyte[4] ^ obyte[5] ^ obyte[6] ^ obyte[7]);     
157
158         /* Timeout logic */
159         always@(posedge sysclk or posedge reset) begin
160                 if (reset)
161                   timecnt <= 0;
162                 else begin
163                         if (clkdown | oreq)
164                           timecnt <= 0;
165                         else
166                           timecnt <= timecnt + 1;
167                 end
168         end
169         assign timeout = (timecnt == 24'hff_ffff);      
170 endmodule