apbps2.vhd

来自「The GRLIB IP Library is an integrated se」· VHDL 代码 · 共 314 行

VHD
314
字号
------------------------------------------------------------------------------  This file is a part of the GRLIB VHDL IP LIBRARY--  Copyright (C) 2004 GAISLER RESEARCH----  This program is free software; you can redistribute it and/or modify--  it under the terms of the GNU General Public License as published by--  the Free Software Foundation; either version 2 of the License, or--  (at your option) any later version.----  See the file COPYING for the full details of the license.--------------------------------------------------------------------------------- Entity:      apbps2-- File:        apbps2.vhd-- Author:      Marcus Hellqvist, Jiri Gaisler-- Description: PS/2 keyboard interface-----------------------------------------------------------------------------library ieee;use ieee.std_logic_1164.all;library grlib;use grlib.stdlib.all;use grlib.amba.all;library gaisler;use gaisler.devices.all;use gaisler.misc.all;entity apbps2 is  generic(    pindex      : integer := 0;    paddr       : integer := 0;    pmask       : integer := 16#fff#;    pirq        : integer := 0;    fKHz        : integer := 50000;    fixed       : integer := 1    );  port(    rst         : in std_ulogic;        -- Global asynchronous reset    clk         : in std_ulogic;        -- Global clock    apbi        : in apb_slv_in_type;    apbo        : out apb_slv_out_type;    ps2i        : in ps2_in_type;    ps2o        : out ps2_out_type    );end;architecture rtl of apbps2 isconstant fifosize       : integer := 16;type rxstates is (idle,start,data,parity,stop);type txstates is (idle,waitrequest,start,data,parity,stop,ack);type fifotype is array(0 to fifosize-1) of std_logic_vector(7 downto 0);type ps2_regs is record-- status reg data_ready     : std_ulogic;                                   -- data ready parity_error   : std_ulogic;                                   -- parity carry out/ error bit frame_error    : std_ulogic;                                   -- frame error when receiving kb_inh         : std_ulogic;                                   -- keyboard inhibit obf            : std_ulogic;                                   -- output buffer full ibf            : std_ulogic;                                   -- input buffer full rcnt           : std_logic_vector(log2x(fifosize) downto 0);   -- fifo counter tcnt           : std_logic_vector(log2x(fifosize) downto 0);   -- fifo counter-- control reg rx_en          : std_ulogic;                                   -- receive enable tx_en          : std_ulogic;                                   -- transmit enable rx_irq         : std_ulogic;                                   -- keyboard interrupt tx_irq         : std_ulogic;                                   -- transmit interrupt-- others rxfifo         : fifotype;                                     -- fifo with 16 bytes rraddr         : std_logic_vector(log2x(fifosize)-1 downto 0); -- fifo read address rwaddr         : std_logic_vector(log2x(fifosize)-1 downto 0); -- fifo write address rxstate        : rxstates; txfifo         : fifotype;                                     -- fifo with 16 bytes traddr         : std_logic_vector(log2x(fifosize)-1 downto 0); -- fifo read address twaddr         : std_logic_vector(log2x(fifosize)-1 downto 0); -- fifo write address txstate        : txstates; ps2_clk_syn    : std_ulogic;                                   -- ps2 clock synchronized ps2_data_syn   : std_ulogic;                                   -- ps2 data synchronized ps2_clk_fall   : std_ulogic;                                   -- ps2 clock falling edge detector rshift         : std_logic_vector(7 downto 0);                 -- shift register rpar           : std_ulogic;                                   -- parity check bit tshift         : std_logic_vector(9 downto 0);                 -- shift register tpar           : std_ulogic;                                   -- transmit parity bit ps2clk         : std_ulogic;                                   -- ps2 clock ps2data        : std_ulogic;                                   -- ps2 data ps2clkoe       : std_ulogic;                                   -- ps2 clock output enable ps2dataoe      : std_ulogic;                                   -- ps2 data output enable timer          : std_logic_vector(13 downto 0);                -- timer reload         : std_logic_vector(13 downto 0);                -- reload registerend record; constant rcntzero      : std_logic_vector(log2x(fifosize) downto 0) := (others => '0'); constant REVISION      : integer := 1; constant pconfig       : apb_config_type := (                        0 => ahb_device_reg ( VENDOR_GAISLER, GAISLER_APBPS2, 0, REVISION, pirq),                        1 => apb_iobar(paddr, pmask)); signal r, rin          : ps2_regs; signal ps2_clk, ps2_data : std_ulogic;begin  ps2_op : process(r, rst, ps2_clk, ps2_data,apbi)    variable v  : ps2_regs;    variable rdata : std_logic_vector(31 downto 0);    variable irq : std_logic_vector(NAHBIRQ-1 downto 0);  begin    v := r;    rdata := (others => '0'); v.data_ready := '0'; irq := (others => '0'); irq(pirq) := r.rx_irq or r.tx_irq;    v.rx_irq := '0'; v.tx_irq := '0'; v.obf := r.rcnt(log2x(fifosize)); v.ibf := r.tcnt(log2x(fifosize));    if r.rcnt /= rcntzero then v.data_ready := '1'; end if;    -- Synchronizing ps2 input    v.ps2_clk_syn := ps2_clk; v.ps2_data_syn := ps2_data;    -- read registers    case apbi.paddr(3 downto 2) is      when "00" =>	rdata(7 downto 0) := r.rxfifo(conv_integer(r.rraddr));        if (apbi.psel(pindex) and apbi.penable and (not apbi.pwrite)) = '1' then          if r.rcnt /= rcntzero then            v.rxfifo(conv_integer(r.rraddr)) := (others => '0');            v.rraddr := r.rraddr +1; v.rcnt := r.rcnt -1;          end if;        end if;      when "01" =>	rdata(27 + log2x(fifosize) downto 27) := r.rcnt;        rdata(22 + log2x(fifosize) downto 22) := r.tcnt;        rdata(5 downto 0) := r.ibf & r.obf & r.kb_inh & r.frame_error & r.parity_error & r.data_ready;      when "10" =>	rdata(3 downto 0) := r.tx_irq & r.rx_irq & r.tx_en & r.rx_en;      when others =>	if fixed = 0 then rdata(13 downto 0) := r.reload; end if;    end case;    -- write registers    if (apbi.psel(pindex) and apbi.penable and apbi.pwrite) = '1' then      case apbi.paddr(3 downto 2) is        when "00" =>    v.txfifo(conv_integer(r.twaddr)) := apbi.pwdata(7 downto 0);                        v.twaddr := r.twaddr +1; v.tcnt := r.tcnt +1;        when "01" =>    v.obf := apbi.pwdata(4);                        v.kb_inh := apbi.pwdata(3);                        v.frame_error := apbi.pwdata(2);                        v.parity_error := apbi.pwdata(1);        when "10" =>    v.tx_irq := apbi.pwdata(3);                        v.rx_irq := apbi.pwdata(2);                        v.tx_en := apbi.pwdata(1);                        v.rx_en := apbi.pwdata(0);        when others =>          v.reload := apbi.pwdata(13 downto 0);      end case;    end if;    if v.tx_en = '1' then      v.rxstate := idle;    end if;    if r.ps2_clk_fall = '0' then      if v.ps2_clk_syn /= r.ps2_clk_syn then        if v.ps2_clk_syn = '0' and (v.rx_en = '1' or v.tx_en = '1') then          v.ps2_clk_fall := '1';        end if;      end if;    else      v.ps2_clk_fall := '0';    end if;    if v.tx_en = '0' then    -- receiver state machine      case r.rxstate is      when idle =>        if v.rx_en = '1' and v.ps2_data_syn = '0' then          v.rshift := (others => '1'); v.rxstate := start;        end if;      when start =>        if v.ps2_clk_fall = '1' then          if v.ps2_data_syn = '0' then            v.rshift := v.ps2_data_syn & r.rshift(7 downto 1);            v.rxstate := data; v.rpar := '0';            v.parity_error := '0'; v.frame_error := '0';          else v.rxstate := idle; end if;        end if;      when data =>        if v.ps2_clk_fall = '1' then          v.rshift := v.ps2_data_syn & r.rshift(7 downto 1);          v.rpar := r.rpar xor v.ps2_data_syn;          if r.rshift(0) = '0' then v.rxstate := parity; end if;        end if;      when parity =>        if v.ps2_clk_fall = '1' then          v.parity_error := r.rpar xor (not v.ps2_data_syn);          v.rxstate := stop;        end if;      when stop =>        if v.ps2_clk_fall = '1' then          if v.ps2_data_syn = '1' then            v.rx_irq := '1'; v.rxstate := idle;            if (not v.obf) = '1' and r.parity_error = '0' then              v.rxfifo(conv_integer(r.rwaddr)) := v.rshift(7 downto 0);              v.rwaddr := r.rwaddr +1; v.rcnt :=r.rcnt +1;            end if;          else v.frame_error := '1'; v.rxstate := idle; end if;        end if;      end case;    end if;    -- keyboard inhibit / high impedance    if v.tx_en /= '1' then      if r.obf = '1' then        v.kb_inh := '1'; v.ps2clk := '0'; v.ps2data := '1';        v.ps2dataoe := '0'; v.ps2clkoe := '0';      else        v.ps2clk := '1'; v.ps2data := '1'; v.ps2dataoe := '1';        v.ps2clkoe := '1';      end if;    end if;    if r.tx_irq = '1' then      v.tx_en := '0'; v.rx_en := '1';    end if;    case r.txstate is    when idle =>      if v.tx_en = '1' and v.traddr /= v.twaddr then        v.ps2clk := '0'; v.ps2clkoe := '0';        v.ps2data := '1'; v.ps2dataoe := '0'; v.txstate := waitrequest;      end if;    when waitrequest =>      v.timer := r.timer - 1;      if (v.timer(13) and not r.timer(13)) = '1' then        if fixed = 1 then v.timer := conv_std_logic_vector(fKHz/10,14);        else v.timer := r.reload; end if;        v.ps2clk := '1'; v.ps2data := '0'; v.txstate := start;      end if;    when start  =>      v.ps2clkoe := '1';      v.tshift := "10" & r.txfifo(conv_integer(r.traddr));      v.traddr := r.traddr +1;v.tcnt := r.tcnt -1;      v.tpar := '1';      v.txstate := data;    when data =>      if v.ps2_clk_fall = '1' then        v.ps2data := r.tshift(0);        v.tpar := r.tpar xor r.tshift(0);        v.tshift := '1' & r.tshift(9 downto 1);        if v.tshift = "1111111110" then v.txstate := parity; end if;      end if;    when parity =>      if v.ps2_clk_fall = '1' then        v.ps2data := r.tpar; v.txstate := stop;      end if;    when stop =>      if v.ps2_clk_fall = '1' then        v.ps2data := '1'; v.txstate := ack;      end if;    when ack =>      v.ps2dataoe := '1';      if v.ps2_clk_fall = '1' and v.ps2_data_syn = '0'then        v.ps2data := '1'; v.ps2dataoe := '0'; v.tx_irq := '1';        v.txstate := idle;      end if;    end case;    -- reset operations    if rst = '0' then      v.data_ready := '0'; v.kb_inh := '0'; v.parity_error := '0';      v.frame_error := '0'; v.obf := '0'; v.rx_en := '0';      v.tx_en := '0'; v.rx_irq := '0'; v.tx_irq := '0';      v.ps2_clk_fall  := '0'; v.ps2_clk_syn  := '0'; v.ps2_data_syn := '0';      v.rshift := (others => '0'); v.rxstate := idle; v.txstate := idle;      v.rraddr := (others => '0'); v.rwaddr := (others => '0');      v.rcnt := (others => '0'); v.traddr := (others => '0');      v.twaddr := (others => '0'); v.tcnt := (others => '0');      v.tshift := (others => '0'); v.tpar := '0';      v.timer := conv_std_logic_vector(fKHz/10,14);    end if;    -- update registers    rin <= v;    -- drive outputs    apbo.prdata <= rdata; apbo.pirq <= irq;    apbo.pindex <= pindex;    ps2o.ps2_clk_o <= r.ps2clk;    ps2o.ps2_clk_oe <= r.ps2clkoe;    ps2o.ps2_data_o <= r.ps2data;    ps2o.ps2_data_oe <= r.ps2dataoe;  end process;  apbo.pconfig <= pconfig;  regs : process(clk)  begin    if rising_edge(clk) then      r <= rin;      ps2_data <= to_x01(ps2i.ps2_data_i);      ps2_clk <= to_x01(ps2i.ps2_clk_i);    end if;  end process;-- pragma translate_off    bootmsg : report_version    generic map ("apbps2_" & tost(pindex) & ": APB PS2 interface rev 0, irq "    & tost(pirq));-- pragma translate_onend;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?