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

Subversion Repositories mips_enhanced

[/] [mips_enhanced/] [trunk/] [grlib-gpl-1.0.19-b3188/] [lib/] [gaisler/] [misc/] [apbps2.vhd] - Blame information for rev 2

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 dimamali
------------------------------------------------------------------------------
2
--  This file is a part of the GRLIB VHDL IP LIBRARY
3
--  Copyright (C) 2003, Gaisler Research
4
--
5
--  This program 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 2 of the License, or
8
--  (at your option) any later version.
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, write to the Free Software
17
--  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
18
-----------------------------------------------------------------------------
19
-- Entity:      apbps2
20
-- File:        apbps2.vhd
21
-- Author:      Marcus Hellqvist, Jiri Gaisler
22
-- Description: PS/2 keyboard interface
23
-----------------------------------------------------------------------------
24
 
25
library ieee;
26
use ieee.std_logic_1164.all;
27
 
28
library grlib;
29
use grlib.stdlib.all;
30
use grlib.amba.all;
31
use grlib.devices.all;
32
library gaisler;
33
use gaisler.misc.all;
34
 
35
entity apbps2 is
36
  generic(
37
    pindex      : integer := 0;
38
    paddr       : integer := 0;
39
    pmask       : integer := 16#fff#;
40
    pirq        : integer := 0;
41
    fKHz        : integer := 50000;
42
    fixed       : integer := 1
43
    );
44
  port(
45
    rst         : in std_ulogic;        -- Global asynchronous reset
46
    clk         : in std_ulogic;        -- Global clock
47
    apbi        : in apb_slv_in_type;
48
    apbo        : out apb_slv_out_type;
49
    ps2i        : in ps2_in_type;
50
    ps2o        : out ps2_out_type
51
    );
52
end;
53
 
54
architecture rtl of apbps2 is
55
 
56
constant fifosize       : integer := 16;
57
type rxstates is (idle,start,data,parity,stop);
58
type txstates is (idle,waitrequest,start,data,parity,stop,ack);
59
type fifotype is array(0 to fifosize-1) of std_logic_vector(7 downto 0);
60
 
61
type ps2_regs is record
62
  -- status reg
63
  data_ready     : std_ulogic;                                   -- data ready
64
  parity_error   : std_ulogic;                                   -- parity carry out/ error bit
65
  frame_error    : std_ulogic;                                   -- frame error when receiving
66
  kb_inh         : std_ulogic;                                   -- keyboard inhibit
67
  rbf            : std_ulogic;                                   -- receiver buffer full
68
  tbf            : std_ulogic;                                   -- transmitter buffer full
69
  rcnt           : std_logic_vector(log2x(fifosize) downto 0);   -- fifo counter
70
  tcnt           : std_logic_vector(log2x(fifosize) downto 0);   -- fifo counter
71
 
72
  -- control reg
73
  rx_en          : std_ulogic;                                   -- receive enable
74
  tx_en          : std_ulogic;                                   -- transmit enable
75
  rx_irq_en      : std_ulogic;                                   -- keyboard interrupt enable
76
  tx_irq_en      : std_ulogic;                                   -- transmit interrupt enable
77
 
78
  -- others
79
  tx_act         : std_ulogic;                                   -- tx active
80
  rxdf           : std_logic_vector(4 downto 0);                 -- rx data filter
81
  rxcf           : std_logic_vector(4 downto 0);                 -- rx clock filter
82
  rx_irq         : std_ulogic;                                   -- keyboard interrupt
83
  tx_irq         : std_ulogic;                                   -- transmit interrupt
84
  rxfifo         : fifotype;                                     -- fifo with 16 bytes
85
  rraddr         : std_logic_vector(log2x(fifosize)-1 downto 0); -- fifo read address
86
  rwaddr         : std_logic_vector(log2x(fifosize)-1 downto 0); -- fifo write address
87
  rxstate        : rxstates;
88
  txfifo         : fifotype;                                     -- fifo with 16 bytes
89
  traddr         : std_logic_vector(log2x(fifosize)-1 downto 0); -- fifo read address
90
  twaddr         : std_logic_vector(log2x(fifosize)-1 downto 0); -- fifo write address
91
  txstate        : txstates;
92
  ps2_clk_syn    : std_ulogic;                                   -- ps2 clock synchronized
93
  ps2_data_syn   : std_ulogic;                                   -- ps2 data synchronized
94
  ps2_clk_fall   : std_ulogic;                                   -- ps2 clock falling edge detector
95
  rshift         : std_logic_vector(7 downto 0);                 -- shift register
96
  rpar           : std_ulogic;                                   -- parity check bit
97
  tshift         : std_logic_vector(9 downto 0);                 -- shift register
98
  tpar           : std_ulogic;                                   -- transmit parity bit
99
  ps2clk         : std_ulogic;                                   -- ps2 clock
100
  ps2data        : std_ulogic;                                   -- ps2 data
101
  ps2clkoe       : std_ulogic;                                   -- ps2 clock output enable
102
  ps2dataoe      : std_ulogic;                                   -- ps2 data output enable
103
  timer          : std_logic_vector(13 downto 0);                -- timer
104
  reload         : std_logic_vector(13 downto 0);                -- reload register
105
end record;
106
 
107
 constant rcntzero      : std_logic_vector(log2x(fifosize) downto 0) := (others => '0');
108
 constant REVISION      : integer := 1;
109
 constant pconfig       : apb_config_type := (
110
 
111
                        1 => apb_iobar(paddr, pmask));
112
 
113
 signal r, rin          : ps2_regs;
114
 signal ps2_clk, ps2_data : std_ulogic;
115
 
116
begin
117
  ps2_op : process(r, rst, ps2_clk, ps2_data,apbi)
118
    variable v  : ps2_regs;
119
    variable rdata : std_logic_vector(31 downto 0);
120
    variable irq : std_logic_vector(NAHBIRQ-1 downto 0);
121
  begin
122
    v := r;
123
    rdata := (others => '0'); v.data_ready := '0'; irq := (others => '0'); irq(pirq) := r.rx_irq or r.tx_irq;
124
    v.rx_irq := '0'; v.tx_irq := '0'; v.rbf := r.rcnt(log2x(fifosize)); v.tbf := r.tcnt(log2x(fifosize));
125
 
126
    if r.rcnt /= rcntzero then v.data_ready := '1'; end if;
127
 
128
    -- Synchronize and filter ps2 input
129
    v.rxdf(0) := ps2_data; v.rxdf(4 downto 1) := r.rxdf(3 downto 0);
130
    v.rxcf(0) := ps2_clk; v.rxcf(4 downto 1) := r.rxcf(3 downto 0);
131
 
132
    if (r.rxdf(4) & r.rxdf(4) & r.rxdf(4) & r.rxdf(4)) = r.rxdf(3 downto 0) then
133
      v.ps2_data_syn := r.rxdf(4);
134
    end if;
135
 
136
    if (r.rxcf(4) & r.rxcf(4) & r.rxcf(4) & r.rxcf(4)) = r.rxcf(3 downto 0) then
137
      v.ps2_clk_syn := r.rxcf(4);
138
    end if;
139
 
140
    if (v.ps2_clk_syn /= r.ps2_clk_syn) and (v.ps2_clk_syn = '0') then
141
      v.ps2_clk_fall := '1';
142
    else
143
      v.ps2_clk_fall := '0';
144
    end if;
145
 
146
    -- read registers
147
    case apbi.paddr(3 downto 2) is
148
      when "00" =>
149
        rdata(7 downto 0) := r.rxfifo(conv_integer(r.rraddr));
150
        if (apbi.psel(pindex) and apbi.penable and (not apbi.pwrite)) = '1' then
151
          if r.rcnt /= rcntzero then
152
            v.rxfifo(conv_integer(r.rraddr)) := (others => '0');
153
            v.rraddr := r.rraddr + 1; v.rcnt := r.rcnt - 1;
154
          end if;
155
        end if;
156
      when "01" =>
157
        rdata(27 + log2x(fifosize) downto 27) := r.rcnt;
158
        rdata(22 + log2x(fifosize) downto 22) := r.tcnt;
159
        rdata(5 downto 0) := r.tbf & r.rbf & r.kb_inh & r.frame_error & r.parity_error & r.data_ready;
160
      when "10" =>
161
        rdata(3 downto 0) := r.tx_irq_en & r.rx_irq_en & r.tx_en & r.rx_en;
162
      when others =>
163
        if fixed = 0 then rdata(13 downto 0) := r.reload; end if;
164
    end case;
165
 
166
    -- write registers
167
    if (apbi.psel(pindex) and apbi.penable and apbi.pwrite) = '1' then
168
      case apbi.paddr(3 downto 2) is
169
        when "00" =>
170
          if r.tcnt(log2x(fifosize)) = '0' then
171
            v.txfifo(conv_integer(r.twaddr)) := apbi.pwdata(7 downto 0);
172
            v.twaddr := r.twaddr + 1; v.tcnt := r.tcnt + 1;
173
          end if;
174
        when "01" =>
175
          v.kb_inh := apbi.pwdata(3);
176
          v.frame_error := apbi.pwdata(2);
177
          v.parity_error := apbi.pwdata(1);
178
        when "10" =>
179
          v.tx_irq_en := apbi.pwdata(3);
180
          v.rx_irq_en := apbi.pwdata(2);
181
          v.tx_en := apbi.pwdata(1);
182
          v.rx_en := apbi.pwdata(0);
183
        when "11" =>
184
          if fixed = 0 then
185
            v.reload := apbi.pwdata(13 downto 0);
186
          end if;
187
        when others =>
188
          null;
189
      end case;
190
    end if;
191
 
192
    case r.txstate is
193
    when idle =>
194
      if r.tx_en = '1' and r.tcnt /= rcntzero then
195
        v.ps2clk := '0'; v.ps2clkoe := '0'; v.tx_act := '1';
196
        v.ps2data := '1'; v.ps2dataoe := '0'; v.txstate := waitrequest;
197
      end if;
198
    when waitrequest =>
199
      v.timer := r.timer - 1;
200
      if (v.timer(13) and not r.timer(13)) = '1' then
201
        if fixed = 1 then v.timer := conv_std_logic_vector(fKHz/10,14);
202
        else v.timer := r.reload; end if;
203
        v.ps2clk := '1'; v.ps2data := '0'; v.txstate := start;
204
      end if;
205
    when start  =>
206
      v.ps2clkoe := '1';
207
      v.tshift := "10" & r.txfifo(conv_integer(r.traddr));
208
      v.traddr := r.traddr + 1; v.tcnt := r.tcnt - 1;
209
      v.tpar := '1';
210
      v.txstate := data;
211
    when data =>
212
      if r.ps2_clk_fall = '1' then
213
        v.ps2data := r.tshift(0);
214
        v.tpar := r.tpar xor r.tshift(0);
215
        v.tshift := '1' & r.tshift(9 downto 1);
216
        if v.tshift = "1111111110" then v.txstate := parity; end if;
217
      end if;
218
    when parity =>
219
      if r.ps2_clk_fall = '1' then
220
        v.ps2data := r.tpar; v.txstate := stop;
221
      end if;
222
    when stop =>
223
      if r.ps2_clk_fall = '1' then
224
        v.ps2data := '1'; v.txstate := ack;
225
      end if;
226
    when ack =>
227
      v.ps2dataoe := '1';
228
      if r.ps2_clk_fall = '1' and r.ps2_data_syn = '0'then
229
        v.ps2data := '1'; v.ps2dataoe := '0'; v.tx_irq := r.tx_irq_en;
230
        v.txstate := idle; v.tx_act := '0';
231
      end if;
232
    end case;
233
 
234
    -- receiver state machine
235
    case r.rxstate is
236
    when idle =>
237
      if (r.rx_en and not r.tx_act) = '1' then
238
        v.rshift := (others => '1'); v.rxstate := start;
239
      end if;
240
    when start =>
241
      if r.ps2_clk_fall = '1' then
242
        if r.ps2_data_syn = '0' then
243
          v.rshift := r.ps2_data_syn & r.rshift(7 downto 1);
244
          v.rxstate := data; v.rpar := '0';
245
          v.parity_error := '0'; v.frame_error := '0';
246
        else v.rxstate := idle; end if;
247
      end if;
248
    when data =>
249
      if r.ps2_clk_fall = '1' then
250
        v.rshift := r.ps2_data_syn & r.rshift(7 downto 1);
251
        v.rpar := r.rpar xor r.ps2_data_syn;
252
        if r.rshift(0) = '0' then v.rxstate := parity; end if;
253
      end if;
254
    when parity =>
255
      if r.ps2_clk_fall = '1' then
256
        v.parity_error := r.rpar xor (not r.ps2_data_syn);
257
        v.rxstate := stop;
258
      end if;
259
    when stop =>
260
      if r.ps2_clk_fall = '1' then
261
        if r.ps2_data_syn = '1' then
262
          v.rx_irq := r.rx_irq_en; v.rxstate := idle;
263
          if (r.rbf or r.parity_error) = '0' then
264
            v.rxfifo(conv_integer(r.rwaddr)) := r.rshift(7 downto 0);
265
            v.rwaddr := r.rwaddr + 1; v.rcnt := r.rcnt + 1;
266
          end if;
267
        else v.frame_error := '1'; v.rxstate := idle; end if;
268
      end if;
269
    end case;
270
 
271
    -- keyboard inhibit / high impedance
272
    if v.tx_act = '0' then
273
      if r.rbf = '1' then
274
        v.kb_inh := '1'; v.ps2clk := '0'; v.ps2data := '1';
275
        v.ps2dataoe := '0'; v.ps2clkoe := '0';
276
      else
277
        v.ps2clk := '1'; v.ps2data := '1'; v.ps2dataoe := '1';
278
        v.ps2clkoe := '1';
279
      end if;
280
    end if;
281
 
282
    if r.tx_act = '1' then
283
      v.rxstate := idle;
284
    end if;
285
 
286
    -- reset operations
287
    if rst = '0' then
288
      v.data_ready := '0'; v.kb_inh := '0'; v.parity_error := '0';
289
      v.frame_error := '0'; v.rx_en := '0'; v.tx_act := '0';
290
      v.tx_en := '0'; v.rx_irq := '0'; v.tx_irq := '0';
291
      v.ps2_clk_fall  := '0'; v.ps2_clk_syn  := '0'; v.ps2_data_syn := '0';
292
      v.rshift := (others => '0'); v.rxstate := idle; v.txstate := idle;
293
      v.rraddr := (others => '0'); v.rwaddr := (others => '0');
294
      v.rcnt := (others => '0'); v.traddr := (others => '0');
295
      v.twaddr := (others => '0'); v.tcnt := (others => '0');
296
      v.tshift := (others => '0'); v.tpar := '0';
297
      v.timer := conv_std_logic_vector(fKHz/10,14);
298
    end if;
299
 
300
    -- update registers
301
    rin <= v;
302
 
303
    -- drive outputs
304
    apbo.prdata      <= rdata;
305
    apbo.pirq        <= irq;
306
    apbo.pindex      <= pindex;
307
    ps2o.ps2_clk_o   <= r.ps2clk;
308
    ps2o.ps2_clk_oe  <= r.ps2clkoe;
309
    ps2o.ps2_data_o  <= r.ps2data;
310
    ps2o.ps2_data_oe <= r.ps2dataoe;
311
  end process;
312
 
313
  apbo.pconfig <= pconfig;
314
 
315
  regs : process(clk)
316
  begin
317
    if rising_edge(clk) then
318
      r <= rin;
319
      ps2_data <= to_x01(ps2i.ps2_data_i);
320
      ps2_clk <= to_x01(ps2i.ps2_clk_i);
321
    end if;
322
  end process;
323
 
324
-- pragma translate_off
325
    bootmsg : report_version
326
    generic map ("apbps2_" & tost(pindex) & ": APB PS2 interface rev 0, irq "
327
    & tost(pirq));
328
-- pragma translate_on
329
 
330
end;

powered by: WebSVN 2.1.0

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