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

Subversion Repositories s80186

[/] [s80186/] [trunk/] [fpga/] [ps2/] [PS2Host.sv] - Blame information for rev 2

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 jamieiles
// Copyright Jamie Iles, 2017
2
//
3
// This file is part of s80x86.
4
//
5
// s80x86 is free software: you can redistribute it and/or modify
6
// it under the terms of the GNU General Public License as published by
7
// the Free Software Foundation, either version 3 of the License, or
8
// (at your option) any later version.
9
//
10
// s80x86 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 s80x86.  If not, see .
17
 
18
module PS2Host #(parameter clkf=50000000)
19
                (input logic clk,
20
                 input logic reset,
21
                 // Host signals
22
                 output logic [7:0] rx,
23
                 output logic rx_valid,
24
                 output logic error,
25
                 input logic start_tx,
26
                 input logic [7:0] tx,
27
                 output logic tx_busy,
28
                 // Connector signals
29
                 inout ps2_clk,
30
                 inout ps2_dat);
31
 
32
localparam tx_clock_inhibit_reload = (clkf / 1000000) * 100;
33
localparam tx_clock_inhibit_bits = $clog2(tx_clock_inhibit_reload);
34
reg [tx_clock_inhibit_bits-1:0] clk_inhibit_count;
35
 
36
wire ps2_clk_sync;
37
wire ps2_dat_sync;
38
 
39
reg last_ps2_clk;
40
reg [2:0] bitpos;
41
 
42
reg [7:0] tx_reg;
43
 
44
typedef enum logic [3:0] {
45
    STATE_IDLE,
46
    // Receive
47
    STATE_RX,
48
    STATE_RX_PARITY,
49
    STATE_STOP,
50
    // Transmit
51
    STATE_INHIBIT,
52
    STATE_TX_START,
53
    STATE_TX,
54
    STATE_TX_PARITY,
55
    STATE_TX_STOP,
56
    STATE_TX_ACK
57
} state_t;
58
 
59
state_t state, next_state;
60
 
61
// Host samples on the negative edge.
62
wire do_sample = last_ps2_clk & ~ps2_clk_sync;
63
 
64
assign rx_valid = state == STATE_STOP && do_sample;
65
 
66
reg dat_o;
67
reg drive_dat;
68
 
69
assign ps2_clk = state == STATE_INHIBIT ? 1'b0 : 1'bz;
70
assign ps2_dat = drive_dat ? dat_o : 1'bz;
71
 
72
BitSync         ClkSync(.clk(clk),
73
                        .d(ps2_clk),
74
                        .q(ps2_clk_sync));
75
 
76
BitSync         DatSync(.clk(clk),
77
                        .d(ps2_dat),
78
                        .q(ps2_dat_sync));
79
 
80
always_ff @(posedge clk or posedge reset)
81
    if (reset)
82
        last_ps2_clk <= 1'b0;
83
    else
84
        last_ps2_clk <= ps2_clk_sync;
85
 
86
always_comb begin
87
    case (state)
88
    STATE_IDLE: next_state = do_sample && !ps2_dat_sync ? STATE_RX : STATE_IDLE;
89
    STATE_RX: next_state = do_sample && bitpos == 3'd7 ? STATE_RX_PARITY : STATE_RX;
90
    STATE_RX_PARITY: next_state = do_sample ? STATE_STOP : STATE_RX_PARITY;
91
    STATE_STOP: next_state = do_sample ? STATE_IDLE : STATE_STOP;
92
    STATE_INHIBIT: next_state = ~|clk_inhibit_count ? STATE_TX_START : STATE_INHIBIT;
93
    STATE_TX_START: next_state = STATE_TX;
94
    STATE_TX: next_state = do_sample && bitpos == 3'd7 ? STATE_TX_PARITY : STATE_TX;
95
    STATE_TX_PARITY: next_state = do_sample ? STATE_TX_STOP : STATE_TX_PARITY;
96
    STATE_TX_STOP: next_state = do_sample ? STATE_TX_ACK : STATE_TX_STOP;
97
    STATE_TX_ACK: next_state = do_sample ? STATE_IDLE : STATE_TX_ACK;
98
    default: next_state = STATE_IDLE;
99
    endcase
100
 
101
    if (start_tx)
102
        next_state = STATE_INHIBIT;
103
 
104
    if (reset)
105
        next_state = STATE_IDLE;
106
end
107
 
108
always_ff @(posedge clk)
109
    if (state == STATE_TX_START)
110
        dat_o <= 1'b0;
111
    else if (do_sample && state == STATE_TX)
112
        dat_o <= tx_reg[bitpos];
113
    else if (do_sample && state == STATE_TX_PARITY)
114
        dat_o <= ~^tx_reg;
115
 
116
always_comb
117
    case (state)
118
    STATE_TX_START: drive_dat = 1'b1;
119
    STATE_TX: drive_dat = 1'b1;
120
    STATE_TX_PARITY: drive_dat = 1'b1;
121
    default: drive_dat = 1'b0;
122
    endcase
123
 
124
always_ff @(posedge clk or posedge reset)
125
    if (reset)
126
        tx_busy <= 1'b0;
127
    else if (start_tx)
128
        tx_busy <= 1'b1;
129
    else if (state == STATE_IDLE)
130
        tx_busy <= 1'b0;
131
 
132
always_ff @(posedge clk)
133
    if (state == STATE_INHIBIT)
134
        clk_inhibit_count <= clk_inhibit_count - 1'b1;
135
    else
136
        clk_inhibit_count <= tx_clock_inhibit_bits'(tx_clock_inhibit_reload);
137
 
138
always_ff @(posedge clk)
139
    state <= next_state;
140
 
141
always_ff @(posedge clk)
142
    if (state == STATE_RX || state == STATE_TX)
143
        bitpos <= do_sample ? bitpos + 1'b1 : bitpos;
144
    else
145
        bitpos <= 3'b0;
146
 
147
always_ff @(posedge clk)
148
    if (state == STATE_RX && do_sample)
149
        rx <= {ps2_dat_sync, rx[7:1]};
150
 
151
always_ff @(posedge clk or posedge reset)
152
    if (reset)
153
        error <= 1'b0;
154
    else if (state == STATE_IDLE)
155
        error <= 1'b0;
156
    else if (state == STATE_RX_PARITY && do_sample)
157
        error <= ~^{rx, ps2_dat_sync};
158
 
159
always_ff @(posedge clk)
160
    if (start_tx)
161
        tx_reg <= tx;
162
 
163
endmodule

powered by: WebSVN 2.1.0

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