Root/lm32/logic/sakc/cores/ps2/rtl/ps2.v

1/*
2 * PS2 Interface
3 * Copyright (C) 2009 Takeshi Matsuya
4 * Copyright (C) 2007, 2008, 2009 Sebastien Bourdeauducq
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, version 3 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19module ps2 #(
20    parameter csr_addr = 4'h0,
21    parameter clk_freq = 100000000
22) (
23    input sys_rst,
24    input sys_clk,
25
26    input [13:0] csr_a,
27    input csr_we,
28    input [31:0] csr_di,
29    output reg [31:0] csr_do,
30
31    inout ps2_clk,
32    inout ps2_data,
33    output reg irq
34);
35
36/* CSR interface */
37wire csr_selected = csr_a[13:10] == csr_addr;
38reg tx_busy;
39
40//-----------------------------------------------------------------
41// divisor
42//-----------------------------------------------------------------
43reg [9:0] enable_counter;
44wire enable;
45assign enable = (enable_counter == 10'd0);
46
47parameter divisor = clk_freq/12800/16;
48
49always @(posedge sys_clk) begin
50    if(sys_rst)
51        enable_counter <= divisor - 10'd1;
52    else begin
53        enable_counter <= enable_counter - 10'd1;
54        if(enable)
55            enable_counter <= divisor - 10'd1;
56    end
57end
58
59//-----------------------------------------------------------------
60// Synchronize ps2 clock and data
61//-----------------------------------------------------------------
62reg ps2_clk_1;
63reg ps2_data_1;
64reg ps2_clk_2;
65reg ps2_data_2;
66reg ps2_clk_out;
67reg ps2_data_out1, ps2_data_out2;
68
69always @(posedge sys_clk) begin
70    ps2_clk_1 <= ps2_clk;
71    ps2_data_1 <= ps2_data;
72    ps2_clk_2 <= ps2_clk_1;
73    ps2_data_2 <= ps2_data_1;
74end
75
76/* PS2 */
77reg [7:0] kcode;
78reg rx_clk_data;
79reg [5:0] rx_clk_count;
80reg [4:0] rx_bitcount;
81reg [10:0] rx_data;
82reg [10:0] tx_data;
83reg we_reg;
84
85/* FSM */
86reg [2:0] state;
87reg [2:0] next_state;
88
89parameter RECEIVE = 3'd0;
90parameter WAIT_READY = 3'd1;
91parameter CLOCK_LOW = 3'd2;
92parameter CLOCK_HIGH = 3'd3;
93parameter CLOCK_HIGH1 = 3'd4;
94parameter CLOCK_HIGH2 = 3'd5;
95parameter WAIT_CLOCK_LOW = 3'd6;
96parameter TRANSMIT = 3'd7;
97
98assign state_receive = state == RECEIVE;
99assign state_transmit = state == TRANSMIT;
100
101always @(posedge sys_clk) begin
102    if(sys_rst)
103        state = RECEIVE;
104    else begin
105        state = next_state;
106    end
107end
108
109/* ps2 clock falling edge 100us counter */
110//parameter divisor_100us = clk_freq/10000;
111parameter divisor_100us = 1;
112reg [16:0] watchdog_timer;
113wire watchdog_timer_done;
114assign watchdog_timer_done = (watchdog_timer == 17'd0);
115always @(sys_clk) begin
116    if(sys_rst||ps2_clk_out)
117        watchdog_timer <= divisor_100us - 1;
118    else if(~watchdog_timer_done)
119            watchdog_timer <= watchdog_timer - 1;
120end
121
122always @(*) begin
123    ps2_clk_out = 1'b1;
124    ps2_data_out1 = 1'b1;
125    tx_busy = 1'b1;
126
127    next_state = state;
128
129    case(state)
130        RECEIVE: begin
131            tx_busy = 1'b0;
132            if(we_reg) begin
133                next_state = WAIT_READY;
134            end
135        end
136        WAIT_READY: begin
137            if(rx_bitcount == 5'd0) begin
138                ps2_clk_out = 1'b0;
139                next_state = CLOCK_LOW;
140            end
141        end
142        CLOCK_LOW: begin
143            ps2_clk_out = 1'b0;
144            if(watchdog_timer_done) begin
145                next_state = CLOCK_HIGH;
146            end
147        end
148        CLOCK_HIGH: begin
149            next_state = CLOCK_HIGH1;
150        end
151        CLOCK_HIGH1: begin
152            next_state = CLOCK_HIGH2;
153        end
154        CLOCK_HIGH2: begin
155            ps2_data_out1 = 1'b0;
156            next_state = WAIT_CLOCK_LOW;
157        end
158        WAIT_CLOCK_LOW: begin
159            ps2_data_out1 = 1'b0;
160            if(ps2_clk_2 == 1'b0) begin
161                next_state = TRANSMIT;
162            end
163        end
164        TRANSMIT: begin
165            if(rx_bitcount == 5'd10) begin
166                next_state = RECEIVE;
167            end
168        end
169    endcase
170end
171
172//-----------------------------------------------------------------
173// PS2 RX/TX Logic
174//-----------------------------------------------------------------
175always @(posedge sys_clk) begin
176    if(sys_rst) begin
177        rx_clk_data <= 1'd1;
178        rx_clk_count <= 5'd0;
179        rx_bitcount <= 5'd0;
180        rx_data <= 11'b11111111111;
181        irq <= 1'd0;
182        csr_do <= 32'd0;
183        we_reg <= 1'b0;
184        ps2_data_out2 <= 1'b1;
185    end else begin
186        irq <= 1'b0;
187        we_reg <= 1'b0;
188        csr_do <= 32'd0;
189        if(csr_selected) begin
190            case(csr_a[0])
191                1'b0: csr_do <= kcode;
192                1'b1: csr_do <= tx_busy;
193            endcase
194            if(csr_we && csr_a[0] == 1'b0) begin
195                tx_data <= {2'b11, ~(^csr_di[7:0]), csr_di[7:0]}; // STOP+PARITY+DATA
196                we_reg <= 1'b1;
197            end
198        end
199        if(enable) begin
200            if(rx_clk_data == ps2_clk_2) begin
201                rx_clk_count <= rx_clk_count + 5'd1;
202            end else begin
203                rx_clk_count <= 5'd0;
204                rx_clk_data <= ps2_clk_2;
205            end
206            if(state_receive && rx_clk_data == 1'b0 && rx_clk_count == 5'd4) begin
207                rx_data <= {ps2_data_2, rx_data[10:1]};
208                rx_bitcount <= rx_bitcount + 5'd1;
209                if(rx_bitcount == 5'd10) begin
210                    irq <= 1'b1;
211                    kcode <= rx_data[9:2];
212                end
213            end
214            if(state_transmit && rx_clk_data == 1'b0 && rx_clk_count == 5'd0) begin
215                ps2_data_out2 <= tx_data[rx_bitcount];
216                rx_bitcount <= rx_bitcount + 5'd1;
217                if(rx_bitcount == 5'd10) begin
218                    ps2_data_out2 <= 1'b1;
219                end
220            end
221            if(rx_clk_count == 5'd16) begin
222                rx_bitcount <= 5'd0;
223                rx_data <= 11'b11111111111;
224            end
225        end
226    end
227end
228
229assign ps2_clk = ps2_clk_out ? 1'hz : 1'b0;
230assign ps2_data = ps2_data_out1 & ps2_data_out2 ? 1'hz : 1'b0;
231
232endmodule
233

Archive Download this file

Branches:
master



interactive