apb_ifc.vhd 5.91 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
--------------------------------------------------------------------------------
--
-- CTU CAN FD IP Core
-- Copyright (C) 2015-2018 Ondrej Ille <ondrej.ille@gmail.com>
--
-- Project advisors and co-authors:
-- 	Jiri Novak <jnovak@fel.cvut.cz>
-- 	Pavel Pisa <pisa@cmp.felk.cvut.cz>
-- 	Martin Jerabek <jerabma7@fel.cvut.cz>
-- Department of Measurement         (http://meas.fel.cvut.cz/)
-- Faculty of Electrical Engineering (http://www.fel.cvut.cz)
-- Czech Technical University        (http://www.cvut.cz/)
--
-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this VHDL component and associated documentation files (the "Component"),
-- to deal in the Component without restriction, including without limitation
-- the rights to use, copy, modify, merge, publish, distribute, sublicense,
-- and/or sell copies of the Component, and to permit persons to whom the
-- Component is furnished to do so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in
-- all copies or substantial portions of the Component.
--
-- THE COMPONENT IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHTHOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-- FROM, OUT OF OR IN CONNECTION WITH THE COMPONENT OR THE USE OR OTHER DEALINGS
-- IN THE COMPONENT.
--
-- The CAN protocol is developed by Robert Bosch GmbH and protected by patents.
-- Anybody who wants to implement this IP core on silicon has to obtain a CAN
-- protocol license from Bosch.
--
--------------------------------------------------------------------------------

--------------------------------------------------------------------------------
-- Purpose:
--    Adaptor from APB4 to internal bus.
41 42
--    NOTE: This is not strictly APB conformant as the read data stays only
--          for the next cycle; after that they are zeroed.
43 44 45
--------------------------------------------------------------------------------
-- Revision History:
--    May 2018   First Implementation - Martin Jerabek
46 47 48
--    31.08.2018 Ensure that reg_rden_o is always asserted for only one cycle.
--               This is important for reads with side effects, such as
--               reading from FIFO.
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
--------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.CANconstants.all;

entity apb_ifc is
    generic (
        -- ID (bits  19-16 of reg_addr_o)
        ID : natural := 1
    );
    port (
        aclk             : in  std_logic;
        arstn            : in  std_logic;

        reg_data_in_o    : out std_logic_vector(31 downto 0);
        reg_data_out_i   : in  std_logic_vector(31 downto 0);
        reg_addr_o       : out std_logic_vector(23 downto 0);
        reg_be_o         : out std_logic_vector(3 downto 0);
        reg_rden_o       : out std_logic;
        reg_wren_o       : out std_logic;

        s_apb_paddr      : in  std_logic_vector(31 downto 0);
        s_apb_penable    : in  std_logic;
        s_apb_pprot      : in  std_logic_vector(2 downto 0);
        s_apb_prdata     : out std_logic_vector(31 downto 0);
        s_apb_pready     : out std_logic;
        s_apb_psel       : in  std_logic;
        s_apb_pslverr    : out std_logic;
        s_apb_pstrb      : in  std_logic_vector(3 downto 0);
        s_apb_pwdata     : in  std_logic_vector(31 downto 0);
        s_apb_pwrite     : in  std_logic
    );
end entity;

architecture rtl of apb_ifc is
85
    signal rst_countdown_reg : natural range 0 to 3;
86 87 88 89 90 91 92 93 94 95 96
    signal next_apb_pready   : std_logic;
    signal ready_for_read    : std_logic;

    function to_std_logic(a : boolean) return std_logic is
    begin
        if a then
            return '1';
        else
            return '0';
        end if;
    end function to_std_logic;
97
begin
98 99 100
    -- psl default clock is rising_edge (aclk);
    -- psl assert_onecycle_rden: assert always reg_rden_o = '1' -> next reg_rden_o = '0';

101 102 103
    reg_data_in_o <= s_apb_pwdata;
    s_apb_prdata  <= reg_data_out_i;

104 105 106 107 108 109
    reg_addr_o(COMP_TYPE_ADRESS_HIGHER downto COMP_TYPE_ADRESS_LOWER) <=
        CAN_COMPONENT_TYPE;

    reg_addr_o(ID_ADRESS_HIGHER downto ID_ADRESS_LOWER) <=
        std_logic_vector(to_unsigned(ID, 4));

110
    -- forward only aligned addresses
111 112 113
    -- (the bridge/CPU will then pick the bytes itself)
    reg_addr_o(ID_ADRESS_LOWER - 1 downto 2) <=
        s_apb_paddr(ID_ADRESS_LOWER - 1 downto 2);
114

115 116
    reg_addr_o(1 downto 0) <= (others => '0');

117
    -- path can be shortened by registering
118
    reg_be_o   <= s_apb_pstrb when s_apb_pwrite = '1'
119 120 121
                              else
                  (others => '1');

122 123 124 125 126 127 128 129

    -- Read must be issued one cycle before finishing the transaction
    -- and must be active only for 1 cycle so that when reading from a FIFO
    -- the pointer is only incremented once.
    -- rst_countdown_reg = 0 -> not s_apb_penable
    -- otherwise rst_countdown_reg = 1 (s_apb_penable will stay in '1', so double trigger won't happen)
    ready_for_read <= (not s_apb_penable and next_apb_pready) or to_std_logic(rst_countdown_reg = 1);
    reg_rden_o <= s_apb_psel and not s_apb_pwrite and ready_for_read;
130 131

    -- path can be shortened by registering it
132
    -- ignore s_apb_pprot
133
    reg_wren_o <= s_apb_psel and s_apb_pwrite and s_apb_penable;
134

135
    p_rready : process(arstn, aclk)
136 137
    begin
        if arstn = '0' then
138
            rst_countdown_reg <= 3;
139 140 141 142 143 144 145
        elsif rising_edge(aclk) then
            if rst_countdown_reg > 0 then
                rst_countdown_reg <= rst_countdown_reg - 1;
            end if;
        end if;
    end process;

146 147
    next_apb_pready <= '1' when rst_countdown_reg = 0 else '0';
    s_apb_pready <= next_apb_pready;
148 149
    s_apb_pslverr <= '0';
end architecture rtl;