Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • project/gn4124-core
1 result
Show changes
Commits on Source (87)
Showing
with 1985 additions and 2343 deletions
---
# SPDX-FileCopyrightText: 2024 CERN (home.cern)
#
# SPDX-License-Identifier: BSD-3-Clause
version: '1.0.0'
name: 'Gennum GN4124 core'
description: 'https://ohwr.org/project/gn4124-core/wikis/home'
website: 'https://ohwr.org/project/gn4124-core'
images:
- 'https://ohwr.org/project/gn4124-core/uploads/e1ac973d81801d37c00cb46c666addd3/GN4124core_arch.png'
documentation: 'https://ohwr.org/project/gn4124-core/wikis'
issues: 'https://ohwr.org/project/gn4124-core/issues'
newsfeed: 'https://ohwr.org/project/gn4124-core/wikis/news'
licenses:
- 'CC0-1.0'
forum: 'https://forums.ohwr.org/c/gn4124-core'
..
SPDX-License-Identifier: CC0-1.0
SPDX-FileCopyrightText: 2019-2020 CERN
==========
Change Log
==========
- Format inspired by: `Keep a Changelog <https://keepachangelog.com/en/1.0.0/>`_
- Versioning scheme follows: `Semantic Versioning <https://semver.org/spec/v2.0.0.html>`_
3.1.2 - 2023-11-20
==================
https://www.ohwr.org/project/gn4124-core/tree/v3.1.2
Changed
-------
- hdl: pipeline l2p arbiter outputs to relax timing (#3)
- hdl: simplify l2p_dma_master FIFO reset logic (#4)
3.1.1 - 2022-11-03
==================
https://www.ohwr.org/project/gn4124-core/tree/v3.1.1
Fixed
-----
- hdl: adjust component
3.1.0 - 2020-11-09
==================
https://www.ohwr.org/project/gn4124-core/tree/v3.1.0
Fixed
-----
- hdl: L2P DMA cross page issue
- hdl: L2P incorrect handling of stall signal
- hdl: P2L allow transfer longer than 4KB
3.0.1 - 2020-09-29
==================
https://www.ohwr.org/project/gn4124-core/tree/v3.0.1
Fixed
-----
- hdl: L2P DMA issues reported with slower hosts
3.0.0 - 2020-07-27
==================
https://www.ohwr.org/project/gn4124-core/tree/v3.0.0
Added
-----
- hdl: SystemVerilog BFM and testbench.
- hdl: Add wrapper with wishbone records and slave adapters.
- hdl: Add generics to tune the depths of the various async FIFOs.
Changed
-------
- hdl: Major rewrite of DMA engine, in particular the L2P DMA Master.
- hdl: Major cleanup of resets and cross-clock domain synchronisation.
- hdl: Stop using coregen FIFOs, switch to FIFOs from general-cores.
- hdl: Make DMA optional (g_WITH_DMA generic).
- hdl: Use cheby to describe registers, only one interrupt (level).
- hdl: Test, verify and enable byte swap feature.
- hdl: Extend SV BFM with tasks to read/write from simulated host memory.
Fixed
-----
- hdl: Fixed incorrect 64-bit DMA transaction generation bug.
- hdl: Allow larger DMA reads (up to the full 32 bits of the "length" register) for L2P DMA master.
- hdl: Add flow control to the write buffer of the BFM to prevent overflows during 'wr' commands.
- hdl: Fix swapped bits in attributes.
- hdl: Handle host 32-bit address overflow in L2P DMA master.
- hdl: Fix bug in BFM not respecting P2L_RDY during DMA writes.
- hdl: Fix bug in BFM not accepting 4096B writes.
2.0.0 - 2014-04-03
==================
https://www.ohwr.org/project/gn4124-core/tree/v2.0.0
Added
-----
- Second release of gn4124-core
1.0.0 - 2013-03-01
==================
https://www.ohwr.org/project/gn4124-core/tree/v1.0.0
Added
-----
- First release of gn4124-core
Creative Commons Legal Code
CC0 1.0 Universal
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
HEREUNDER.
Statement of Purpose
The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator
and subsequent owner(s) (each and all, an "owner") of an original work of
authorship and/or a database (each, a "Work").
Certain owners wish to permanently relinquish those rights to a Work for
the purpose of contributing to a commons of creative, cultural and
scientific works ("Commons") that the public can reliably and without fear
of later claims of infringement build upon, modify, incorporate in other
works, reuse and redistribute as freely as possible in any form whatsoever
and for any purposes, including without limitation commercial purposes.
These owners may contribute to the Commons to promote the ideal of a free
culture and the further production of creative, cultural and scientific
works, or to gain reputation or greater distribution for their Work in
part through the use and efforts of others.
For these and/or other purposes and motivations, and without any
expectation of additional consideration or compensation, the person
associating CC0 with a Work (the "Affirmer"), to the extent that he or she
is an owner of Copyright and Related Rights in the Work, voluntarily
elects to apply CC0 to the Work and publicly distribute the Work under its
terms, with knowledge of his or her Copyright and Related Rights in the
Work and the meaning and intended legal effect of CC0 on those rights.
1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not
limited to, the following:
i. the right to reproduce, adapt, distribute, perform, display,
communicate, and translate a Work;
ii. moral rights retained by the original author(s) and/or performer(s);
iii. publicity and privacy rights pertaining to a person's image or
likeness depicted in a Work;
iv. rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;
v. rights protecting the extraction, dissemination, use and reuse of data
in a Work;
vi. database rights (such as those arising under Directive 96/9/EC of the
European Parliament and of the Council of 11 March 1996 on the legal
protection of databases, and under any national implementation
thereof, including any amended or successor version of such
directive); and
vii. other similar, equivalent or corresponding rights throughout the
world based on applicable law or treaty, and any national
implementations thereof.
2. Waiver. To the greatest extent permitted by, but not in contravention
of, applicable law, Affirmer hereby overtly, fully, permanently,
irrevocably and unconditionally waives, abandons, and surrenders all of
Affirmer's Copyright and Related Rights and associated claims and causes
of action, whether now known or unknown (including existing as well as
future claims and causes of action), in the Work (i) in all territories
worldwide, (ii) for the maximum duration provided by applicable law or
treaty (including future time extensions), (iii) in any current or future
medium and for any number of copies, and (iv) for any purpose whatsoever,
including without limitation commercial, advertising or promotional
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
member of the public at large and to the detriment of Affirmer's heirs and
successors, fully intending that such Waiver shall not be subject to
revocation, rescission, cancellation, termination, or any other legal or
equitable action to disrupt the quiet enjoyment of the Work by the public
as contemplated by Affirmer's express Statement of Purpose.
3. Public License Fallback. Should any part of the Waiver for any reason
be judged legally invalid or ineffective under applicable law, then the
Waiver shall be preserved to the maximum extent permitted taking into
account Affirmer's express Statement of Purpose. In addition, to the
extent the Waiver is so judged Affirmer hereby grants to each affected
person a royalty-free, non transferable, non sublicensable, non exclusive,
irrevocable and unconditional license to exercise Affirmer's Copyright and
Related Rights in the Work (i) in all territories worldwide, (ii) for the
maximum duration provided by applicable law or treaty (including future
time extensions), (iii) in any current or future medium and for any number
of copies, and (iv) for any purpose whatsoever, including without
limitation commercial, advertising or promotional purposes (the
"License"). The License shall be deemed effective as of the date CC0 was
applied by Affirmer to the Work. Should any part of the License for any
reason be judged legally invalid or ineffective under applicable law, such
partial invalidity or ineffectiveness shall not invalidate the remainder
of the License, and in such case Affirmer hereby affirms that he or she
will not (i) exercise any of his or her remaining Copyright and Related
Rights in the Work or (ii) assert any associated claims and causes of
action with respect to the Work, in either case contrary to Affirmer's
express Statement of Purpose.
4. Limitations and Disclaimers.
a. No trademark or patent rights held by Affirmer are waived, abandoned,
surrendered, licensed or otherwise affected by this document.
b. Affirmer offers the Work as-is and makes no representations or
warranties of any kind concerning the Work, express, implied,
statutory or otherwise, including without limitation warranties of
title, merchantability, fitness for a particular purpose, non
infringement, or the absence of latent or other defects, accuracy, or
the present or absence of errors, whether or not discoverable, all to
the greatest extent permissible under applicable law.
c. Affirmer disclaims responsibility for clearing rights of other persons
that may apply to the Work or any use thereof, including without
limitation any person's Copyright and Related Rights in the Work.
Further, Affirmer disclaims responsibility for obtaining any necessary
consents, permissions or other rights required for any use of the
Work.
d. Affirmer understands and acknowledges that Creative Commons is not a
party to this document and has no duty or obligation with respect to
this CC0 or use of the Work.
# Solderpad Hardware Licence Version 2.0
This licence (the “Licence”) operates as a wraparound licence to the Apache License Version 2.0 (the
“Apache License”) and grants to You the rights, and imposes the obligations, set out in the Apache
License (which can be found here: http://apache.org/licenses/LICENSE-2.0), with the following
extensions. It must be read in conjunction with the Apache License. Section 1 below modifies
definitions in the Apache License, and section 2 below replaces sections 2 of the Apache
License. You may, at your option, choose to treat any Work released under this License as released
under the Apache License (thus ignoring all sections written below entirely). Words in *italics*
indicate changes rom the Apache License, but are indicative and not to be taken into account in
interpretation.
1. The definitions set out in the Apache License are modified as follows:
**Copyright** any reference to ‘copyright’ (whether capitalised or not) includes ‘Rights’ (as
defined below).
**Contribution** also includes any *design*, as well as any work of authorship.
**Derivative Works** shall not include works that remain *reversibly* separable from, or merely link
(or bind by name) or *physically connect* to or *interoperate with* the interfaces of the Work and
Derivative Works thereof.
**Object** form shall mean any form resulting from mechanical transformation or translation of a
Source form or the application of a Source form to physical material, including but not limited to
compiled object code, generated documentation, the *instantiation* of a hardware design or physical
object* and conversions to other media types, *including intermediate forms such as bytecodes, FPGA
bitstreams, moulds, artwork and semiconductor topographies (mask works)*.
**Rights** means copyright and any similar right including design right (whether registered or
unregistered), semiconductor topography (mask) rights and database rights (but excluding Patents and
Trademarks).
**Source** form shall mean the preferred form for making modifications, including but not limited to
source code, *net lists, board layouts, CAD files*, documentation source, and configuration files.
**Work** also includes a *design* or work of authorship, whether in Source form or *other* Object
form.
2. Grant of Licence
2.1 Subject to the terms and conditions of this License, each Contributor hereby grants to You a
perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable license *under the Rights*
to reproduce, prepare Derivative Works of, *make, adapt, repair,* publicly display, publicly perform,
sublicense, and distribute the Work and such Derivative Works in Source or Object form *and do
anything in relation to the Work as if the Rights did not exist*.
if target=="xilinx":
modules = {
"local" : [
"hdl/gn4124core/rtl",
"hdl/rtl",
],
}
if action == "simulation":
modules['local'].append("hdl/gn4124core/sim/gn4124_bfm")
modules['local'].append("hdl/sim/gn4124_bfm")
--------------------------------------------------------------------------------
-- CERN BE-CO-HT
-- GN4124 core for PCIe FMC carrier
-- http://www.ohwr.org/projects/gn4124-core
--------------------------------------------------------------------------------
--
-- unit name: dma_controller
--
-- description: Manages the DMA transfers.
--
--------------------------------------------------------------------------------
-- Copyright CERN 2010-2018
--------------------------------------------------------------------------------
-- Copyright and related rights are licensed under the Solderpad Hardware
-- License, Version 2.0 (the "License"); you may not use this file except
-- in compliance with the License. You may obtain a copy of the License at
-- http://solderpad.org/licenses/SHL-2.0.
-- Unless required by applicable law or agreed to in writing, software,
-- hardware and materials distributed under this License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
-- or implied. See the License for the specific language governing permissions
-- and limitations under the License.
--------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.NUMERIC_STD.all;
use work.gn4124_core_pkg.all;
entity dma_controller is
port
(
---------------------------------------------------------
-- GN4124 core clock and reset
clk_i : in std_logic;
rst_n_i : in std_logic;
---------------------------------------------------------
-- Interrupt request
dma_ctrl_irq_o : out std_logic_vector(1 downto 0);
---------------------------------------------------------
-- To the L2P DMA master and P2L DMA master
dma_ctrl_carrier_addr_o : out std_logic_vector(31 downto 0);
dma_ctrl_host_addr_h_o : out std_logic_vector(31 downto 0);
dma_ctrl_host_addr_l_o : out std_logic_vector(31 downto 0);
dma_ctrl_len_o : out std_logic_vector(31 downto 0);
dma_ctrl_start_l2p_o : out std_logic; -- To the L2P DMA master
dma_ctrl_start_p2l_o : out std_logic; -- To the P2L DMA master
dma_ctrl_start_next_o : out std_logic; -- To the P2L DMA master
dma_ctrl_byte_swap_o : out std_logic_vector(1 downto 0);
dma_ctrl_abort_o : out std_logic;
dma_ctrl_done_i : in std_logic;
dma_ctrl_error_i : in std_logic;
---------------------------------------------------------
-- From P2L DMA master
next_item_carrier_addr_i : in std_logic_vector(31 downto 0);
next_item_host_addr_h_i : in std_logic_vector(31 downto 0);
next_item_host_addr_l_i : in std_logic_vector(31 downto 0);
next_item_len_i : in std_logic_vector(31 downto 0);
next_item_next_l_i : in std_logic_vector(31 downto 0);
next_item_next_h_i : in std_logic_vector(31 downto 0);
next_item_attrib_i : in std_logic_vector(31 downto 0);
next_item_valid_i : in std_logic;
---------------------------------------------------------
-- Wishbone slave interface
wb_rst_n_i : in std_logic;
wb_clk_i : in std_logic; -- Bus clock
wb_adr_i : in std_logic_vector(3 downto 0); -- Adress
wb_dat_o : out std_logic_vector(31 downto 0); -- Data in
wb_dat_i : in std_logic_vector(31 downto 0); -- Data out
wb_sel_i : in std_logic_vector(3 downto 0); -- Byte select
wb_cyc_i : in std_logic; -- Read or write cycle
wb_stb_i : in std_logic; -- Read or write strobe
wb_we_i : in std_logic; -- Write
wb_ack_o : out std_logic -- Acknowledge
);
end dma_controller;
architecture behaviour of dma_controller is
------------------------------------------------------------------------------
-- Constants declaration
------------------------------------------------------------------------------
constant c_IDLE : std_logic_vector(2 downto 0) := "000";
constant c_DONE : std_logic_vector(2 downto 0) := "001";
constant c_BUSY : std_logic_vector(2 downto 0) := "010";
constant c_ERROR : std_logic_vector(2 downto 0) := "011";
constant c_ABORT : std_logic_vector(2 downto 0) := "100";
------------------------------------------------------------------------------
-- Signals declaration
------------------------------------------------------------------------------
signal dma_ctrl_carrier_addr : std_logic_vector(31 downto 0) := (others => '0');
signal dma_ctrl_host_addr_h : std_logic_vector(31 downto 0) := (others => '0');
signal dma_ctrl_host_addr_l : std_logic_vector(31 downto 0) := (others => '0');
signal dma_ctrl_len : std_logic_vector(31 downto 0) := (others => '0');
-- DMA controller registers
signal dma_ctrl : std_logic_vector(31 downto 0);
signal dma_stat : std_logic_vector(31 downto 0);
signal dma_cstart : std_logic_vector(31 downto 0);
signal dma_hstartl : std_logic_vector(31 downto 0);
signal dma_hstarth : std_logic_vector(31 downto 0);
signal dma_len : std_logic_vector(31 downto 0);
signal dma_nextl : std_logic_vector(31 downto 0);
signal dma_nexth : std_logic_vector(31 downto 0);
signal dma_attrib : std_logic_vector(31 downto 0);
signal dma_ctrl_load : std_logic;
signal dma_stat_load : std_logic;
signal dma_cstart_load : std_logic;
signal dma_hstartl_load : std_logic;
signal dma_hstarth_load : std_logic;
signal dma_len_load : std_logic;
signal dma_nextl_load : std_logic;
signal dma_nexth_load : std_logic;
signal dma_attrib_load : std_logic;
signal dma_ctrl_reg : std_logic_vector(31 downto 0);
signal dma_stat_reg : std_logic_vector(31 downto 0);
signal dma_cstart_reg : std_logic_vector(31 downto 0);
signal dma_hstartl_reg : std_logic_vector(31 downto 0);
signal dma_hstarth_reg : std_logic_vector(31 downto 0);
signal dma_len_reg : std_logic_vector(31 downto 0);
signal dma_nextl_reg : std_logic_vector(31 downto 0);
signal dma_nexth_reg : std_logic_vector(31 downto 0);
signal dma_attrib_reg : std_logic_vector(31 downto 0);
-- DMA controller FSM
type dma_ctrl_state_type is (DMA_IDLE, DMA_START_TRANSFER, DMA_TRANSFER,
DMA_START_CHAIN, DMA_CHAIN,
DMA_ERROR, DMA_ABORT);
signal dma_ctrl_current_state : dma_ctrl_state_type;
-- status signals
signal dma_status : std_logic_vector(2 downto 0);
signal dma_error_irq : std_logic;
signal dma_done_irq : std_logic;
begin
------------------------------------------------------------------------------
-- Wishbone slave instantiation
------------------------------------------------------------------------------
dma_controller_wb_slave_0 : entity work.dma_controller_wb_slave port map (
rst_n_i => wb_rst_n_i,
wb_clk_i => wb_clk_i,
wb_addr_i => wb_adr_i,
wb_data_i => wb_dat_i,
wb_data_o => wb_dat_o,
wb_cyc_i => wb_cyc_i,
wb_sel_i => wb_sel_i,
wb_stb_i => wb_stb_i,
wb_we_i => wb_we_i,
wb_ack_o => wb_ack_o,
clk_i => clk_i,
dma_ctrl_o => dma_ctrl,
dma_ctrl_i => dma_ctrl_reg,
dma_ctrl_load_o => dma_ctrl_load,
dma_stat_o => open,
dma_stat_i => dma_stat_reg,
dma_stat_load_o => open,
dma_cstart_o => dma_cstart,
dma_cstart_i => dma_cstart_reg,
dma_cstart_load_o => dma_cstart_load,
dma_hstartl_o => dma_hstartl,
dma_hstartl_i => dma_hstartl_reg,
dma_hstartl_load_o => dma_hstartl_load,
dma_hstarth_o => dma_hstarth,
dma_hstarth_i => dma_hstarth_reg,
dma_hstarth_load_o => dma_hstarth_load,
dma_len_o => dma_len,
dma_len_i => dma_len_reg,
dma_len_load_o => dma_len_load,
dma_nextl_o => dma_nextl,
dma_nextl_i => dma_nextl_reg,
dma_nextl_load_o => dma_nextl_load,
dma_nexth_o => dma_nexth,
dma_nexth_i => dma_nexth_reg,
dma_nexth_load_o => dma_nexth_load,
dma_attrib_o => dma_attrib,
dma_attrib_i => dma_attrib_reg,
dma_attrib_load_o => dma_attrib_load
);
------------------------------------------------------------------------------
-- DMA controller registers
------------------------------------------------------------------------------
p_regs : process (clk_i)
begin
if rising_edge(clk_i) then
if (rst_n_i = '0') then
dma_ctrl_reg <= (others => '0');
dma_stat_reg <= (others => '0');
dma_cstart_reg <= (others => '0');
dma_hstartl_reg <= (others => '0');
dma_hstarth_reg <= (others => '0');
dma_len_reg <= (others => '0');
dma_nextl_reg <= (others => '0');
dma_nexth_reg <= (others => '0');
dma_attrib_reg <= (others => '0');
else
-- Control register
if (dma_ctrl_load = '1') then
dma_ctrl_reg <= dma_ctrl;
end if;
-- Status register
dma_stat_reg(2 downto 0) <= dma_status;
dma_stat_reg(31 downto 3) <= (others => '0');
-- Target start address
if (dma_cstart_load = '1') then
dma_cstart_reg <= dma_cstart;
end if;
-- Host start address lowest 32-bit
if (dma_hstartl_load = '1') then
dma_hstartl_reg <= dma_hstartl;
end if;
-- Host start address highest 32-bit
if (dma_hstarth_load = '1') then
dma_hstarth_reg <= dma_hstarth;
end if;
-- DMA transfer length in byte
if (dma_len_load = '1') then
dma_len_reg <= dma_len;
end if;
-- next item address lowest 32-bit
if (dma_nextl_load = '1') then
dma_nextl_reg <= dma_nextl;
end if;
-- next item address highest 32-bit
if (dma_nexth_load = '1') then
dma_nexth_reg <= dma_nexth;
end if;
-- Chained DMA control
if (dma_attrib_load = '1') then
dma_attrib_reg <= dma_attrib;
end if;
-- next item received => start a new transfer
if (next_item_valid_i = '1') then
dma_ctrl_reg(0) <= '1';
dma_cstart_reg <= next_item_carrier_addr_i;
dma_hstartl_reg <= next_item_host_addr_l_i;
dma_hstarth_reg <= next_item_host_addr_h_i;
dma_len_reg <= next_item_len_i;
dma_nextl_reg <= next_item_next_l_i;
dma_nexth_reg <= next_item_next_h_i;
dma_attrib_reg <= next_item_attrib_i;
end if;
-- Start DMA, 1 tick pulse
if (dma_ctrl_reg(0) = '1') then
dma_ctrl_reg(0) <= '0';
end if;
end if;
end if;
end process p_regs;
dma_ctrl_byte_swap_o <= dma_ctrl_reg(3 downto 2);
------------------------------------------------------------------------------
-- IRQ output assignement
------------------------------------------------------------------------------
dma_ctrl_irq_o <= dma_error_irq & dma_done_irq;
------------------------------------------------------------------------------
-- DMA controller FSM
------------------------------------------------------------------------------
p_fsm : process (clk_i)
begin
if rising_edge(clk_i) then
if(rst_n_i = '0') then
dma_ctrl_current_state <= DMA_IDLE;
dma_ctrl_start_l2p_o <= '0';
dma_ctrl_start_p2l_o <= '0';
dma_ctrl_start_next_o <= '0';
dma_status <= c_IDLE;
dma_error_irq <= '0';
dma_done_irq <= '0';
dma_ctrl_abort_o <= '0';
else
case dma_ctrl_current_state is
when DMA_IDLE =>
-- Clear done irq to make it 1 tick pulse
dma_done_irq <= '0';
if(dma_ctrl_reg(0) = '1') then
-- Starts a new transfer
dma_ctrl_current_state <= DMA_START_TRANSFER;
end if;
when DMA_START_TRANSFER =>
-- Clear abort signal
dma_ctrl_abort_o <= '0';
if (unsigned(dma_len_reg(31 downto 2)) = 0) then
-- Requesting a DMA of 0 word length gives a error
dma_error_irq <= '1';
dma_ctrl_current_state <= DMA_ERROR;
else
-- Start the DMA if the length is not 0
if (dma_attrib_reg(1) = '0') then
-- L2P transfer (from target to PCIe)
dma_ctrl_start_l2p_o <= '1';
elsif (dma_attrib_reg(1) = '1') then
-- P2L transfer (from PCIe to target)
dma_ctrl_start_p2l_o <= '1';
end if;
dma_ctrl_current_state <= DMA_TRANSFER;
dma_ctrl_carrier_addr <= dma_cstart_reg;
dma_ctrl_host_addr_h <= dma_hstarth_reg;
dma_ctrl_host_addr_l <= dma_hstartl_reg;
dma_ctrl_len <= dma_len_reg;
dma_status <= c_BUSY;
end if;
when DMA_TRANSFER =>
-- Clear start signals, to make them 1 tick pulses
dma_ctrl_start_l2p_o <= '0';
dma_ctrl_start_p2l_o <= '0';
if (dma_ctrl_reg(1) = '1') then
-- Transfer aborted
dma_ctrl_current_state <= DMA_ABORT;
elsif(dma_ctrl_error_i = '1') then
-- An error occurs !
dma_error_irq <= '1';
dma_ctrl_current_state <= DMA_ERROR;
elsif(dma_ctrl_done_i = '1') then
-- End of DMA transfer
if(dma_attrib_reg(0) = '1') then
-- More transfer in chained DMA
dma_ctrl_current_state <= DMA_START_CHAIN;
else
-- Was the last transfer
dma_status <= c_DONE;
dma_done_irq <= '1';
dma_ctrl_current_state <= DMA_IDLE;
end if;
end if;
when DMA_START_CHAIN =>
-- Catch the next item in host memory
dma_ctrl_current_state <= DMA_CHAIN;
dma_ctrl_host_addr_h <= dma_nexth_reg;
dma_ctrl_host_addr_l <= dma_nextl_reg;
dma_ctrl_len <= X"0000001C";
dma_ctrl_start_next_o <= '1';
when DMA_CHAIN =>
-- Clear start next signal, to make it 1 tick pulse
dma_ctrl_start_next_o <= '0';
if (dma_ctrl_reg(1) = '1') then
-- Transfer aborted
dma_ctrl_current_state <= DMA_ABORT;
elsif(dma_ctrl_error_i = '1') then
-- An error occurs !
dma_error_irq <= '1';
dma_ctrl_current_state <= DMA_ERROR;
elsif (next_item_valid_i = '1') then
-- next item received
dma_ctrl_current_state <= DMA_START_TRANSFER;
end if;
when DMA_ERROR =>
dma_status <= c_ERROR;
-- Clear error irq to make it 1 tick pulse
dma_error_irq <= '0';
if(dma_ctrl_reg(0) = '1') then
-- Starts a new transfer
dma_ctrl_current_state <= DMA_START_TRANSFER;
end if;
when DMA_ABORT =>
dma_status <= c_ABORT;
dma_ctrl_abort_o <= '1';
if(dma_ctrl_reg(0) = '1') then
-- Starts a new transfer
dma_ctrl_current_state <= DMA_START_TRANSFER;
end if;
when others =>
dma_ctrl_current_state <= DMA_IDLE;
dma_ctrl_carrier_addr <= (others => '0');
dma_ctrl_host_addr_h <= (others => '0');
dma_ctrl_host_addr_l <= (others => '0');
dma_ctrl_len <= (others => '0');
dma_ctrl_start_l2p_o <= '0';
dma_ctrl_start_p2l_o <= '0';
dma_ctrl_start_next_o <= '0';
dma_status <= (others => '0');
dma_error_irq <= '0';
dma_done_irq <= '0';
dma_ctrl_abort_o <= '0';
end case;
end if;
end if;
end process p_fsm;
dma_ctrl_carrier_addr_o <= dma_ctrl_carrier_addr;
dma_ctrl_host_addr_h_o <= dma_ctrl_host_addr_h;
dma_ctrl_host_addr_l_o <= dma_ctrl_host_addr_l;
dma_ctrl_len_o <= dma_ctrl_len;
end behaviour;
---------------------------------------------------------------------------------------
-- Title : Wishbone slave core for GN4124 core DMA controller
---------------------------------------------------------------------------------------
-- File : dma_controller_wb_slave.vhd
-- Author : auto-generated by wbgen2 from dma_controller_wb_slave.wb
-- Created : Wed Oct 6 15:30:35 2010
-- Standard : VHDL'87
---------------------------------------------------------------------------------------
-- THIS FILE WAS GENERATED BY wbgen2 FROM SOURCE FILE dma_controller_wb_slave.wb
-- DO NOT HAND-EDIT UNLESS IT'S ABSOLUTELY NECESSARY!
---------------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity dma_controller_wb_slave is
port (
rst_n_i : in std_logic;
wb_clk_i : in std_logic;
wb_addr_i : in std_logic_vector(3 downto 0);
wb_data_i : in std_logic_vector(31 downto 0);
wb_data_o : out std_logic_vector(31 downto 0);
wb_cyc_i : in std_logic;
wb_sel_i : in std_logic_vector(3 downto 0);
wb_stb_i : in std_logic;
wb_we_i : in std_logic;
wb_ack_o : out std_logic;
clk_i : in std_logic;
-- Ports for asynchronous (clock: clk_i) std_logic_vector field: 'DMA engine control' in reg: 'DMACTRLR'
dma_ctrl_o : out std_logic_vector(31 downto 0);
dma_ctrl_i : in std_logic_vector(31 downto 0);
dma_ctrl_load_o : out std_logic;
-- Ports for asynchronous (clock: clk_i) std_logic_vector field: 'DMA engine status' in reg: 'DMASTATR'
dma_stat_o : out std_logic_vector(31 downto 0);
dma_stat_i : in std_logic_vector(31 downto 0);
dma_stat_load_o : out std_logic;
-- Ports for asynchronous (clock: clk_i) std_logic_vector field: 'DMA start address in the carrier' in reg: 'DMACSTARTR'
dma_cstart_o : out std_logic_vector(31 downto 0);
dma_cstart_i : in std_logic_vector(31 downto 0);
dma_cstart_load_o : out std_logic;
-- Ports for asynchronous (clock: clk_i) std_logic_vector field: 'DMA start address (low) in the host' in reg: 'DMAHSTARTLR'
dma_hstartl_o : out std_logic_vector(31 downto 0);
dma_hstartl_i : in std_logic_vector(31 downto 0);
dma_hstartl_load_o : out std_logic;
-- Ports for asynchronous (clock: clk_i) std_logic_vector field: 'DMA start address (high) in the host' in reg: 'DMAHSTARTHR'
dma_hstarth_o : out std_logic_vector(31 downto 0);
dma_hstarth_i : in std_logic_vector(31 downto 0);
dma_hstarth_load_o : out std_logic;
-- Ports for asynchronous (clock: clk_i) std_logic_vector field: 'DMA read length in bytes' in reg: 'DMALENR'
dma_len_o : out std_logic_vector(31 downto 0);
dma_len_i : in std_logic_vector(31 downto 0);
dma_len_load_o : out std_logic;
-- Ports for asynchronous (clock: clk_i) std_logic_vector field: 'Pointer (low) to next item in list' in reg: 'DMANEXTLR'
dma_nextl_o : out std_logic_vector(31 downto 0);
dma_nextl_i : in std_logic_vector(31 downto 0);
dma_nextl_load_o : out std_logic;
-- Ports for asynchronous (clock: clk_i) std_logic_vector field: 'Pointer (high) to next item in list' in reg: 'DMANEXTHR'
dma_nexth_o : out std_logic_vector(31 downto 0);
dma_nexth_i : in std_logic_vector(31 downto 0);
dma_nexth_load_o : out std_logic;
-- Ports for asynchronous (clock: clk_i) std_logic_vector field: 'DMA chain control' in reg: 'DMAATTRIBR'
dma_attrib_o : out std_logic_vector(31 downto 0);
dma_attrib_i : in std_logic_vector(31 downto 0);
dma_attrib_load_o : out std_logic
);
end dma_controller_wb_slave;
architecture syn of dma_controller_wb_slave is
signal dma_ctrl_int_read : std_logic_vector(31 downto 0);
signal dma_ctrl_int_write : std_logic_vector(31 downto 0);
signal dma_ctrl_lw : std_logic ;
signal dma_ctrl_lw_delay : std_logic ;
signal dma_ctrl_lw_read_in_progress : std_logic ;
signal dma_ctrl_lw_s0 : std_logic ;
signal dma_ctrl_lw_s1 : std_logic ;
signal dma_ctrl_lw_s2 : std_logic ;
signal dma_ctrl_rwsel : std_logic ;
signal dma_stat_int_read : std_logic_vector(31 downto 0);
signal dma_stat_int_write : std_logic_vector(31 downto 0);
signal dma_stat_lw : std_logic ;
signal dma_stat_lw_delay : std_logic ;
signal dma_stat_lw_read_in_progress : std_logic ;
signal dma_stat_lw_s0 : std_logic ;
signal dma_stat_lw_s1 : std_logic ;
signal dma_stat_lw_s2 : std_logic ;
signal dma_stat_rwsel : std_logic ;
signal dma_cstart_int_read : std_logic_vector(31 downto 0);
signal dma_cstart_int_write : std_logic_vector(31 downto 0);
signal dma_cstart_lw : std_logic ;
signal dma_cstart_lw_delay : std_logic ;
signal dma_cstart_lw_read_in_progress : std_logic ;
signal dma_cstart_lw_s0 : std_logic ;
signal dma_cstart_lw_s1 : std_logic ;
signal dma_cstart_lw_s2 : std_logic ;
signal dma_cstart_rwsel : std_logic ;
signal dma_hstartl_int_read : std_logic_vector(31 downto 0);
signal dma_hstartl_int_write : std_logic_vector(31 downto 0);
signal dma_hstartl_lw : std_logic ;
signal dma_hstartl_lw_delay : std_logic ;
signal dma_hstartl_lw_read_in_progress : std_logic ;
signal dma_hstartl_lw_s0 : std_logic ;
signal dma_hstartl_lw_s1 : std_logic ;
signal dma_hstartl_lw_s2 : std_logic ;
signal dma_hstartl_rwsel : std_logic ;
signal dma_hstarth_int_read : std_logic_vector(31 downto 0);
signal dma_hstarth_int_write : std_logic_vector(31 downto 0);
signal dma_hstarth_lw : std_logic ;
signal dma_hstarth_lw_delay : std_logic ;
signal dma_hstarth_lw_read_in_progress : std_logic ;
signal dma_hstarth_lw_s0 : std_logic ;
signal dma_hstarth_lw_s1 : std_logic ;
signal dma_hstarth_lw_s2 : std_logic ;
signal dma_hstarth_rwsel : std_logic ;
signal dma_len_int_read : std_logic_vector(31 downto 0);
signal dma_len_int_write : std_logic_vector(31 downto 0);
signal dma_len_lw : std_logic ;
signal dma_len_lw_delay : std_logic ;
signal dma_len_lw_read_in_progress : std_logic ;
signal dma_len_lw_s0 : std_logic ;
signal dma_len_lw_s1 : std_logic ;
signal dma_len_lw_s2 : std_logic ;
signal dma_len_rwsel : std_logic ;
signal dma_nextl_int_read : std_logic_vector(31 downto 0);
signal dma_nextl_int_write : std_logic_vector(31 downto 0);
signal dma_nextl_lw : std_logic ;
signal dma_nextl_lw_delay : std_logic ;
signal dma_nextl_lw_read_in_progress : std_logic ;
signal dma_nextl_lw_s0 : std_logic ;
signal dma_nextl_lw_s1 : std_logic ;
signal dma_nextl_lw_s2 : std_logic ;
signal dma_nextl_rwsel : std_logic ;
signal dma_nexth_int_read : std_logic_vector(31 downto 0);
signal dma_nexth_int_write : std_logic_vector(31 downto 0);
signal dma_nexth_lw : std_logic ;
signal dma_nexth_lw_delay : std_logic ;
signal dma_nexth_lw_read_in_progress : std_logic ;
signal dma_nexth_lw_s0 : std_logic ;
signal dma_nexth_lw_s1 : std_logic ;
signal dma_nexth_lw_s2 : std_logic ;
signal dma_nexth_rwsel : std_logic ;
signal dma_attrib_int_read : std_logic_vector(31 downto 0);
signal dma_attrib_int_write : std_logic_vector(31 downto 0);
signal dma_attrib_lw : std_logic ;
signal dma_attrib_lw_delay : std_logic ;
signal dma_attrib_lw_read_in_progress : std_logic ;
signal dma_attrib_lw_s0 : std_logic ;
signal dma_attrib_lw_s1 : std_logic ;
signal dma_attrib_lw_s2 : std_logic ;
signal dma_attrib_rwsel : std_logic ;
signal ack_sreg : std_logic_vector(9 downto 0);
signal rddata_reg : std_logic_vector(31 downto 0);
signal wrdata_reg : std_logic_vector(31 downto 0);
signal bwsel_reg : std_logic_vector(3 downto 0);
signal rwaddr_reg : std_logic_vector(3 downto 0);
signal ack_in_progress : std_logic ;
signal wr_int : std_logic ;
signal rd_int : std_logic ;
signal bus_clock_int : std_logic ;
signal allones : std_logic_vector(31 downto 0);
signal allzeros : std_logic_vector(31 downto 0);
begin
-- Some internal signals assignments. For (foreseen) compatibility with other bus standards.
wrdata_reg <= wb_data_i;
bwsel_reg <= wb_sel_i;
bus_clock_int <= wb_clk_i;
rd_int <= wb_cyc_i and (wb_stb_i and (not wb_we_i));
wr_int <= wb_cyc_i and (wb_stb_i and wb_we_i);
allones <= (others => '1');
allzeros <= (others => '0');
--
-- Main register bank access process.
process (wb_clk_i, rst_n_i)
begin
if (rst_n_i = '0') then
ack_sreg <= "0000000000";
ack_in_progress <= '0';
rddata_reg <= "00000000000000000000000000000000";
dma_ctrl_lw <= '0';
dma_ctrl_lw_delay <= '0';
dma_ctrl_lw_read_in_progress <= '0';
dma_ctrl_rwsel <= '0';
dma_ctrl_int_write <= "00000000000000000000000000000000";
dma_stat_lw <= '0';
dma_stat_lw_delay <= '0';
dma_stat_lw_read_in_progress <= '0';
dma_stat_rwsel <= '0';
dma_stat_int_write <= "00000000000000000000000000000000";
dma_cstart_lw <= '0';
dma_cstart_lw_delay <= '0';
dma_cstart_lw_read_in_progress <= '0';
dma_cstart_rwsel <= '0';
dma_cstart_int_write <= "00000000000000000000000000000000";
dma_hstartl_lw <= '0';
dma_hstartl_lw_delay <= '0';
dma_hstartl_lw_read_in_progress <= '0';
dma_hstartl_rwsel <= '0';
dma_hstartl_int_write <= "00000000000000000000000000000000";
dma_hstarth_lw <= '0';
dma_hstarth_lw_delay <= '0';
dma_hstarth_lw_read_in_progress <= '0';
dma_hstarth_rwsel <= '0';
dma_hstarth_int_write <= "00000000000000000000000000000000";
dma_len_lw <= '0';
dma_len_lw_delay <= '0';
dma_len_lw_read_in_progress <= '0';
dma_len_rwsel <= '0';
dma_len_int_write <= "00000000000000000000000000000000";
dma_nextl_lw <= '0';
dma_nextl_lw_delay <= '0';
dma_nextl_lw_read_in_progress <= '0';
dma_nextl_rwsel <= '0';
dma_nextl_int_write <= "00000000000000000000000000000000";
dma_nexth_lw <= '0';
dma_nexth_lw_delay <= '0';
dma_nexth_lw_read_in_progress <= '0';
dma_nexth_rwsel <= '0';
dma_nexth_int_write <= "00000000000000000000000000000000";
dma_attrib_lw <= '0';
dma_attrib_lw_delay <= '0';
dma_attrib_lw_read_in_progress <= '0';
dma_attrib_rwsel <= '0';
dma_attrib_int_write <= "00000000000000000000000000000000";
elsif rising_edge(wb_clk_i) then
-- advance the ACK generator shift register
ack_sreg(8 downto 0) <= ack_sreg(9 downto 1);
ack_sreg(9) <= '0';
if (ack_in_progress = '1') then
if (ack_sreg(0) = '1') then
ack_in_progress <= '0';
else
dma_ctrl_lw <= dma_ctrl_lw_delay;
dma_ctrl_lw_delay <= '0';
if ((ack_sreg(1) = '1') and (dma_ctrl_lw_read_in_progress = '1')) then
dma_ctrl_lw_read_in_progress <= '0';
rddata_reg(31 downto 0) <= dma_ctrl_int_read;
end if;
dma_stat_lw <= dma_stat_lw_delay;
dma_stat_lw_delay <= '0';
if ((ack_sreg(1) = '1') and (dma_stat_lw_read_in_progress = '1')) then
dma_stat_lw_read_in_progress <= '0';
rddata_reg(31 downto 0) <= dma_stat_int_read;
end if;
dma_cstart_lw <= dma_cstart_lw_delay;
dma_cstart_lw_delay <= '0';
if ((ack_sreg(1) = '1') and (dma_cstart_lw_read_in_progress = '1')) then
dma_cstart_lw_read_in_progress <= '0';
rddata_reg(31 downto 0) <= dma_cstart_int_read;
end if;
dma_hstartl_lw <= dma_hstartl_lw_delay;
dma_hstartl_lw_delay <= '0';
if ((ack_sreg(1) = '1') and (dma_hstartl_lw_read_in_progress = '1')) then
dma_hstartl_lw_read_in_progress <= '0';
rddata_reg(31 downto 0) <= dma_hstartl_int_read;
end if;
dma_hstarth_lw <= dma_hstarth_lw_delay;
dma_hstarth_lw_delay <= '0';
if ((ack_sreg(1) = '1') and (dma_hstarth_lw_read_in_progress = '1')) then
dma_hstarth_lw_read_in_progress <= '0';
rddata_reg(31 downto 0) <= dma_hstarth_int_read;
end if;
dma_len_lw <= dma_len_lw_delay;
dma_len_lw_delay <= '0';
if ((ack_sreg(1) = '1') and (dma_len_lw_read_in_progress = '1')) then
dma_len_lw_read_in_progress <= '0';
rddata_reg(31 downto 0) <= dma_len_int_read;
end if;
dma_nextl_lw <= dma_nextl_lw_delay;
dma_nextl_lw_delay <= '0';
if ((ack_sreg(1) = '1') and (dma_nextl_lw_read_in_progress = '1')) then
dma_nextl_lw_read_in_progress <= '0';
rddata_reg(31 downto 0) <= dma_nextl_int_read;
end if;
dma_nexth_lw <= dma_nexth_lw_delay;
dma_nexth_lw_delay <= '0';
if ((ack_sreg(1) = '1') and (dma_nexth_lw_read_in_progress = '1')) then
dma_nexth_lw_read_in_progress <= '0';
rddata_reg(31 downto 0) <= dma_nexth_int_read;
end if;
dma_attrib_lw <= dma_attrib_lw_delay;
dma_attrib_lw_delay <= '0';
if ((ack_sreg(1) = '1') and (dma_attrib_lw_read_in_progress = '1')) then
dma_attrib_lw_read_in_progress <= '0';
rddata_reg(31 downto 0) <= dma_attrib_int_read;
end if;
end if;
else
if ((wb_cyc_i = '1') and (wb_stb_i = '1')) then
case rwaddr_reg(3 downto 0) is
when "0000" =>
if (wb_we_i = '1') then
dma_ctrl_int_write <= wrdata_reg(31 downto 0);
dma_ctrl_lw <= '1';
dma_ctrl_lw_delay <= '1';
dma_ctrl_lw_read_in_progress <= '0';
dma_ctrl_rwsel <= '1';
else
dma_ctrl_lw <= '1';
dma_ctrl_lw_delay <= '1';
dma_ctrl_lw_read_in_progress <= '1';
dma_ctrl_rwsel <= '0';
end if;
ack_sreg(5) <= '1';
ack_in_progress <= '1';
when "0001" =>
if (wb_we_i = '1') then
dma_stat_int_write <= wrdata_reg(31 downto 0);
dma_stat_lw <= '1';
dma_stat_lw_delay <= '1';
dma_stat_lw_read_in_progress <= '0';
dma_stat_rwsel <= '1';
else
dma_stat_lw <= '1';
dma_stat_lw_delay <= '1';
dma_stat_lw_read_in_progress <= '1';
dma_stat_rwsel <= '0';
end if;
ack_sreg(5) <= '1';
ack_in_progress <= '1';
when "0010" =>
if (wb_we_i = '1') then
dma_cstart_int_write <= wrdata_reg(31 downto 0);
dma_cstart_lw <= '1';
dma_cstart_lw_delay <= '1';
dma_cstart_lw_read_in_progress <= '0';
dma_cstart_rwsel <= '1';
else
dma_cstart_lw <= '1';
dma_cstart_lw_delay <= '1';
dma_cstart_lw_read_in_progress <= '1';
dma_cstart_rwsel <= '0';
end if;
ack_sreg(5) <= '1';
ack_in_progress <= '1';
when "0011" =>
if (wb_we_i = '1') then
dma_hstartl_int_write <= wrdata_reg(31 downto 0);
dma_hstartl_lw <= '1';
dma_hstartl_lw_delay <= '1';
dma_hstartl_lw_read_in_progress <= '0';
dma_hstartl_rwsel <= '1';
else
dma_hstartl_lw <= '1';
dma_hstartl_lw_delay <= '1';
dma_hstartl_lw_read_in_progress <= '1';
dma_hstartl_rwsel <= '0';
end if;
ack_sreg(5) <= '1';
ack_in_progress <= '1';
when "0100" =>
if (wb_we_i = '1') then
dma_hstarth_int_write <= wrdata_reg(31 downto 0);
dma_hstarth_lw <= '1';
dma_hstarth_lw_delay <= '1';
dma_hstarth_lw_read_in_progress <= '0';
dma_hstarth_rwsel <= '1';
else
dma_hstarth_lw <= '1';
dma_hstarth_lw_delay <= '1';
dma_hstarth_lw_read_in_progress <= '1';
dma_hstarth_rwsel <= '0';
end if;
ack_sreg(5) <= '1';
ack_in_progress <= '1';
when "0101" =>
if (wb_we_i = '1') then
dma_len_int_write <= wrdata_reg(31 downto 0);
dma_len_lw <= '1';
dma_len_lw_delay <= '1';
dma_len_lw_read_in_progress <= '0';
dma_len_rwsel <= '1';
else
dma_len_lw <= '1';
dma_len_lw_delay <= '1';
dma_len_lw_read_in_progress <= '1';
dma_len_rwsel <= '0';
end if;
ack_sreg(5) <= '1';
ack_in_progress <= '1';
when "0110" =>
if (wb_we_i = '1') then
dma_nextl_int_write <= wrdata_reg(31 downto 0);
dma_nextl_lw <= '1';
dma_nextl_lw_delay <= '1';
dma_nextl_lw_read_in_progress <= '0';
dma_nextl_rwsel <= '1';
else
dma_nextl_lw <= '1';
dma_nextl_lw_delay <= '1';
dma_nextl_lw_read_in_progress <= '1';
dma_nextl_rwsel <= '0';
end if;
ack_sreg(5) <= '1';
ack_in_progress <= '1';
when "0111" =>
if (wb_we_i = '1') then
dma_nexth_int_write <= wrdata_reg(31 downto 0);
dma_nexth_lw <= '1';
dma_nexth_lw_delay <= '1';
dma_nexth_lw_read_in_progress <= '0';
dma_nexth_rwsel <= '1';
else
dma_nexth_lw <= '1';
dma_nexth_lw_delay <= '1';
dma_nexth_lw_read_in_progress <= '1';
dma_nexth_rwsel <= '0';
end if;
ack_sreg(5) <= '1';
ack_in_progress <= '1';
when "1000" =>
if (wb_we_i = '1') then
dma_attrib_int_write <= wrdata_reg(31 downto 0);
dma_attrib_lw <= '1';
dma_attrib_lw_delay <= '1';
dma_attrib_lw_read_in_progress <= '0';
dma_attrib_rwsel <= '1';
else
dma_attrib_lw <= '1';
dma_attrib_lw_delay <= '1';
dma_attrib_lw_read_in_progress <= '1';
dma_attrib_rwsel <= '0';
end if;
ack_sreg(5) <= '1';
ack_in_progress <= '1';
when others =>
-- prevent the slave from hanging the bus on invalid address
ack_in_progress <= '1';
ack_sreg(0) <= '1';
end case;
end if;
end if;
end if;
end process;
-- Drive the data output bus
wb_data_o <= rddata_reg;
-- DMA engine control
-- asynchronous std_logic_vector register : DMA engine control (type RW/WO, clk_i <-> wb_clk_i)
process (clk_i, rst_n_i)
begin
if (rst_n_i = '0') then
dma_ctrl_lw_s0 <= '0';
dma_ctrl_lw_s1 <= '0';
dma_ctrl_lw_s2 <= '0';
dma_ctrl_o <= "00000000000000000000000000000000";
dma_ctrl_load_o <= '0';
dma_ctrl_int_read <= "00000000000000000000000000000000";
elsif rising_edge(clk_i) then
dma_ctrl_lw_s0 <= dma_ctrl_lw;
dma_ctrl_lw_s1 <= dma_ctrl_lw_s0;
dma_ctrl_lw_s2 <= dma_ctrl_lw_s1;
if ((dma_ctrl_lw_s2 = '0') and (dma_ctrl_lw_s1 = '1')) then
if (dma_ctrl_rwsel = '1') then
dma_ctrl_o <= dma_ctrl_int_write;
dma_ctrl_load_o <= '1';
else
dma_ctrl_load_o <= '0';
dma_ctrl_int_read <= dma_ctrl_i;
end if;
else
dma_ctrl_load_o <= '0';
end if;
end if;
end process;
-- DMA engine status
-- asynchronous std_logic_vector register : DMA engine status (type RW/WO, clk_i <-> wb_clk_i)
process (clk_i, rst_n_i)
begin
if (rst_n_i = '0') then
dma_stat_lw_s0 <= '0';
dma_stat_lw_s1 <= '0';
dma_stat_lw_s2 <= '0';
dma_stat_o <= "00000000000000000000000000000000";
dma_stat_load_o <= '0';
dma_stat_int_read <= "00000000000000000000000000000000";
elsif rising_edge(clk_i) then
dma_stat_lw_s0 <= dma_stat_lw;
dma_stat_lw_s1 <= dma_stat_lw_s0;
dma_stat_lw_s2 <= dma_stat_lw_s1;
if ((dma_stat_lw_s2 = '0') and (dma_stat_lw_s1 = '1')) then
if (dma_stat_rwsel = '1') then
dma_stat_o <= dma_stat_int_write;
dma_stat_load_o <= '1';
else
dma_stat_load_o <= '0';
dma_stat_int_read <= dma_stat_i;
end if;
else
dma_stat_load_o <= '0';
end if;
end if;
end process;
-- DMA start address in the carrier
-- asynchronous std_logic_vector register : DMA start address in the carrier (type RW/WO, clk_i <-> wb_clk_i)
process (clk_i, rst_n_i)
begin
if (rst_n_i = '0') then
dma_cstart_lw_s0 <= '0';
dma_cstart_lw_s1 <= '0';
dma_cstart_lw_s2 <= '0';
dma_cstart_o <= "00000000000000000000000000000000";
dma_cstart_load_o <= '0';
dma_cstart_int_read <= "00000000000000000000000000000000";
elsif rising_edge(clk_i) then
dma_cstart_lw_s0 <= dma_cstart_lw;
dma_cstart_lw_s1 <= dma_cstart_lw_s0;
dma_cstart_lw_s2 <= dma_cstart_lw_s1;
if ((dma_cstart_lw_s2 = '0') and (dma_cstart_lw_s1 = '1')) then
if (dma_cstart_rwsel = '1') then
dma_cstart_o <= dma_cstart_int_write;
dma_cstart_load_o <= '1';
else
dma_cstart_load_o <= '0';
dma_cstart_int_read <= dma_cstart_i;
end if;
else
dma_cstart_load_o <= '0';
end if;
end if;
end process;
-- DMA start address (low) in the host
-- asynchronous std_logic_vector register : DMA start address (low) in the host (type RW/WO, clk_i <-> wb_clk_i)
process (clk_i, rst_n_i)
begin
if (rst_n_i = '0') then
dma_hstartl_lw_s0 <= '0';
dma_hstartl_lw_s1 <= '0';
dma_hstartl_lw_s2 <= '0';
dma_hstartl_o <= "00000000000000000000000000000000";
dma_hstartl_load_o <= '0';
dma_hstartl_int_read <= "00000000000000000000000000000000";
elsif rising_edge(clk_i) then
dma_hstartl_lw_s0 <= dma_hstartl_lw;
dma_hstartl_lw_s1 <= dma_hstartl_lw_s0;
dma_hstartl_lw_s2 <= dma_hstartl_lw_s1;
if ((dma_hstartl_lw_s2 = '0') and (dma_hstartl_lw_s1 = '1')) then
if (dma_hstartl_rwsel = '1') then
dma_hstartl_o <= dma_hstartl_int_write;
dma_hstartl_load_o <= '1';
else
dma_hstartl_load_o <= '0';
dma_hstartl_int_read <= dma_hstartl_i;
end if;
else
dma_hstartl_load_o <= '0';
end if;
end if;
end process;
-- DMA start address (high) in the host
-- asynchronous std_logic_vector register : DMA start address (high) in the host (type RW/WO, clk_i <-> wb_clk_i)
process (clk_i, rst_n_i)
begin
if (rst_n_i = '0') then
dma_hstarth_lw_s0 <= '0';
dma_hstarth_lw_s1 <= '0';
dma_hstarth_lw_s2 <= '0';
dma_hstarth_o <= "00000000000000000000000000000000";
dma_hstarth_load_o <= '0';
dma_hstarth_int_read <= "00000000000000000000000000000000";
elsif rising_edge(clk_i) then
dma_hstarth_lw_s0 <= dma_hstarth_lw;
dma_hstarth_lw_s1 <= dma_hstarth_lw_s0;
dma_hstarth_lw_s2 <= dma_hstarth_lw_s1;
if ((dma_hstarth_lw_s2 = '0') and (dma_hstarth_lw_s1 = '1')) then
if (dma_hstarth_rwsel = '1') then
dma_hstarth_o <= dma_hstarth_int_write;
dma_hstarth_load_o <= '1';
else
dma_hstarth_load_o <= '0';
dma_hstarth_int_read <= dma_hstarth_i;
end if;
else
dma_hstarth_load_o <= '0';
end if;
end if;
end process;
-- DMA read length in bytes
-- asynchronous std_logic_vector register : DMA read length in bytes (type RW/WO, clk_i <-> wb_clk_i)
process (clk_i, rst_n_i)
begin
if (rst_n_i = '0') then
dma_len_lw_s0 <= '0';
dma_len_lw_s1 <= '0';
dma_len_lw_s2 <= '0';
dma_len_o <= "00000000000000000000000000000000";
dma_len_load_o <= '0';
dma_len_int_read <= "00000000000000000000000000000000";
elsif rising_edge(clk_i) then
dma_len_lw_s0 <= dma_len_lw;
dma_len_lw_s1 <= dma_len_lw_s0;
dma_len_lw_s2 <= dma_len_lw_s1;
if ((dma_len_lw_s2 = '0') and (dma_len_lw_s1 = '1')) then
if (dma_len_rwsel = '1') then
dma_len_o <= dma_len_int_write;
dma_len_load_o <= '1';
else
dma_len_load_o <= '0';
dma_len_int_read <= dma_len_i;
end if;
else
dma_len_load_o <= '0';
end if;
end if;
end process;
-- Pointer (low) to next item in list
-- asynchronous std_logic_vector register : Pointer (low) to next item in list (type RW/WO, clk_i <-> wb_clk_i)
process (clk_i, rst_n_i)
begin
if (rst_n_i = '0') then
dma_nextl_lw_s0 <= '0';
dma_nextl_lw_s1 <= '0';
dma_nextl_lw_s2 <= '0';
dma_nextl_o <= "00000000000000000000000000000000";
dma_nextl_load_o <= '0';
dma_nextl_int_read <= "00000000000000000000000000000000";
elsif rising_edge(clk_i) then
dma_nextl_lw_s0 <= dma_nextl_lw;
dma_nextl_lw_s1 <= dma_nextl_lw_s0;
dma_nextl_lw_s2 <= dma_nextl_lw_s1;
if ((dma_nextl_lw_s2 = '0') and (dma_nextl_lw_s1 = '1')) then
if (dma_nextl_rwsel = '1') then
dma_nextl_o <= dma_nextl_int_write;
dma_nextl_load_o <= '1';
else
dma_nextl_load_o <= '0';
dma_nextl_int_read <= dma_nextl_i;
end if;
else
dma_nextl_load_o <= '0';
end if;
end if;
end process;
-- Pointer (high) to next item in list
-- asynchronous std_logic_vector register : Pointer (high) to next item in list (type RW/WO, clk_i <-> wb_clk_i)
process (clk_i, rst_n_i)
begin
if (rst_n_i = '0') then
dma_nexth_lw_s0 <= '0';
dma_nexth_lw_s1 <= '0';
dma_nexth_lw_s2 <= '0';
dma_nexth_o <= "00000000000000000000000000000000";
dma_nexth_load_o <= '0';
dma_nexth_int_read <= "00000000000000000000000000000000";
elsif rising_edge(clk_i) then
dma_nexth_lw_s0 <= dma_nexth_lw;
dma_nexth_lw_s1 <= dma_nexth_lw_s0;
dma_nexth_lw_s2 <= dma_nexth_lw_s1;
if ((dma_nexth_lw_s2 = '0') and (dma_nexth_lw_s1 = '1')) then
if (dma_nexth_rwsel = '1') then
dma_nexth_o <= dma_nexth_int_write;
dma_nexth_load_o <= '1';
else
dma_nexth_load_o <= '0';
dma_nexth_int_read <= dma_nexth_i;
end if;
else
dma_nexth_load_o <= '0';
end if;
end if;
end process;
-- DMA chain control
-- asynchronous std_logic_vector register : DMA chain control (type RW/WO, clk_i <-> wb_clk_i)
process (clk_i, rst_n_i)
begin
if (rst_n_i = '0') then
dma_attrib_lw_s0 <= '0';
dma_attrib_lw_s1 <= '0';
dma_attrib_lw_s2 <= '0';
dma_attrib_o <= "00000000000000000000000000000000";
dma_attrib_load_o <= '0';
dma_attrib_int_read <= "00000000000000000000000000000000";
elsif rising_edge(clk_i) then
dma_attrib_lw_s0 <= dma_attrib_lw;
dma_attrib_lw_s1 <= dma_attrib_lw_s0;
dma_attrib_lw_s2 <= dma_attrib_lw_s1;
if ((dma_attrib_lw_s2 = '0') and (dma_attrib_lw_s1 = '1')) then
if (dma_attrib_rwsel = '1') then
dma_attrib_o <= dma_attrib_int_write;
dma_attrib_load_o <= '1';
else
dma_attrib_load_o <= '0';
dma_attrib_int_read <= dma_attrib_i;
end if;
else
dma_attrib_load_o <= '0';
end if;
end if;
end process;
rwaddr_reg <= wb_addr_i;
-- ACK signal generation. Just pass the LSB of ACK counter.
wb_ack_o <= ack_sreg(0);
end syn;
--------------------------------------------------------------------------------
-- CERN BE-CO-HT
-- GN4124 core for PCIe FMC carrier
-- http://www.ohwr.org/projects/gn4124-core
--------------------------------------------------------------------------------
--
-- unit name: l2p_dma_master
--
-- description: L2P DMA master
--
--------------------------------------------------------------------------------
-- Copyright CERN 2010-2018
--------------------------------------------------------------------------------
-- Copyright and related rights are licensed under the Solderpad Hardware
-- License, Version 2.0 (the "License"); you may not use this file except
-- in compliance with the License. You may obtain a copy of the License at
-- http://solderpad.org/licenses/SHL-2.0.
-- Unless required by applicable law or agreed to in writing, software,
-- hardware and materials distributed under this License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
-- or implied. See the License for the specific language governing permissions
-- and limitations under the License.
--------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.NUMERIC_STD.all;
use work.gn4124_core_pkg.all;
use work.gencores_pkg.all;
use work.genram_pkg.all;
entity l2p_dma_master is
generic (
g_BYTE_SWAP : boolean := false
);
port (
-- GN4124 core clk and reset
clk_i : in std_logic;
rst_n_i : in std_logic;
-- From the DMA controller
dma_ctrl_target_addr_i : in std_logic_vector(31 downto 0);
dma_ctrl_host_addr_h_i : in std_logic_vector(31 downto 0);
dma_ctrl_host_addr_l_i : in std_logic_vector(31 downto 0);
dma_ctrl_len_i : in std_logic_vector(31 downto 0);
dma_ctrl_start_l2p_i : in std_logic;
dma_ctrl_done_o : out std_logic;
dma_ctrl_error_o : out std_logic;
dma_ctrl_byte_swap_i : in std_logic_vector(1 downto 0);
dma_ctrl_abort_i : in std_logic;
-- To the arbiter (L2P data)
ldm_arb_valid_o : out std_logic;
ldm_arb_dframe_o : out std_logic;
ldm_arb_data_o : out std_logic_vector(31 downto 0);
ldm_arb_req_o : out std_logic;
arb_ldm_gnt_i : in std_logic;
-- L2P channel control
l2p_edb_o : out std_logic; -- Asserted when transfer is aborted
l_wr_rdy_i : in std_logic; -- Asserted when GN4124 is ready to receive master write
l2p_rdy_i : in std_logic; -- De-asserted to pause transdert already in progress
tx_error_i : in std_logic; -- Asserted when unexpected or malformed paket received
-- DMA Interface (Pipelined Wishbone)
l2p_dma_rst_n_i : in std_logic; -- Active low reset in sync with l2p_dma_clk_i
l2p_dma_clk_i : in std_logic;
l2p_dma_adr_o : out std_logic_vector(31 downto 0);
l2p_dma_dat_i : in std_logic_vector(31 downto 0);
l2p_dma_dat_o : out std_logic_vector(31 downto 0);
l2p_dma_sel_o : out std_logic_vector(3 downto 0);
l2p_dma_cyc_o : out std_logic;
l2p_dma_stb_o : out std_logic;
l2p_dma_we_o : out std_logic;
l2p_dma_ack_i : in std_logic;
l2p_dma_stall_i : in std_logic;
p2l_dma_cyc_i : in std_logic -- P2L dma WB cycle for bus arbitration
);
end l2p_dma_master;
architecture behavioral of l2p_dma_master is
---------------------
-- Constants
---------------------
constant c_L2P_MAX_PAYLOAD : integer := 32;
constant c_ADDR_FIFO_FULL_THRES : integer := 700;
constant c_DATA_FIFO_FULL_THRES : integer := 700;
constant c_TIMEOUT : integer := 2000;
---------------------
-- Signals
---------------------
signal fifo_rst_n : std_logic;
signal fifo_rst_t : std_logic;
signal wb_fifo_rst_n : std_logic;
-- Data FIFO
signal data_fifo_rd : std_logic;
signal data_fifo_wr : std_logic;
signal data_fifo_empty : std_logic;
signal data_fifo_full : std_logic;
signal data_fifo_dout : std_logic_vector(31 downto 0);
signal data_fifo_din : std_logic_vector(31 downto 0) := x"DEADBABE";
-- Addr FIFO
signal addr_fifo_rd : std_logic;
signal addr_fifo_wr : std_logic;
signal addr_fifo_empty : std_logic;
signal addr_fifo_full : std_logic;
signal addr_fifo_dout : std_logic_vector(31 downto 0);
signal addr_fifo_din : std_logic_vector(31 downto 0) := (others => '0');
-- L2P FSM
type l2p_dma_state_type is (L2P_IDLE, L2P_SETUP, L2P_HEADER,
L2P_ADDR_H, L2P_ADDR_L, L2P_SETUP_DATA, L2P_DATA,
L2P_LAST_DATA, L2P_ERROR);
signal l2p_dma_current_state : l2p_dma_state_type;
-- L2P packets
signal s_l2p_header : std_logic_vector(31 downto 0);
signal l2p_len_cnt : unsigned(12 downto 0) := (others => '0');
signal l2p_address_h : std_logic_vector(31 downto 0) := (others => '0');
signal l2p_address_l : std_logic_vector(31 downto 0) := (others => '0');
signal l2p_data_cnt : unsigned(12 downto 0) := (others => '0');
signal l2p_64b_address : std_logic;
signal l2p_len_header : unsigned(12 downto 0);
signal l2p_byte_swap : std_logic_vector(1 downto 0) := (others => '0');
signal l2p_last_packet : std_logic;
signal l2p_lbe_header : std_logic_vector(3 downto 0);
signal ldm_arb_data_l : std_logic_vector(31 downto 0) := (others => '0');
signal ldm_arb_valid : std_logic;
signal data_fifo_valid : std_logic;
signal addr_fifo_valid : std_logic;
-- Counter
signal target_addr_cnt : std_logic_vector(31 downto 0) := (others => '0');
signal dma_length_cnt : unsigned(12 downto 0) := (others => '0');
signal l2p_timeout_cnt : unsigned(12 downto 0) := (others => '0');
-- Wishbone
signal l2p_dma_cyc_t : std_logic;
signal l2p_dma_stb_t : std_logic;
signal l2p_dma_sel_t : std_logic_vector(3 downto 0) := (others => '0');
signal l2p_dma_adr_t : std_logic_vector(31 downto 0) := (others => '0');
signal wb_read_cnt : unsigned(12 downto 0);
signal l2p_cyc_start : std_logic;
signal wb_cyc_start : std_logic;
signal l2p_cyc_cnt : unsigned(12 downto 0);
signal wb_cyc_cnt : unsigned(12 downto 0);
begin
------------------------------
-- Active low reset for fifos
------------------------------
fifo_rst_n <= rst_n_i and (not fifo_rst_t);
-- Local resynced copy of fifo_rst_n to make sure that both sides of the fifo
-- are reset if rst_n_i = '0'
cmp_wb_fifo_rst_sync: gc_sync_ffs
port map (
clk_i => l2p_dma_clk_i,
rst_n_i => l2p_dma_rst_n_i,
data_i => fifo_rst_n,
synced_o => wb_fifo_rst_n);
ldm_arb_valid_o <= ldm_arb_valid;
ldm_arb_data_o <= ldm_arb_data_l;
---------------------
-- L2P FSM
---------------------
p_l2p_fsm : process (clk_i)
begin
if rising_edge(clk_i) then
if (rst_n_i = '0') then
l2p_dma_current_state <= L2P_IDLE;
ldm_arb_req_o <= '0';
ldm_arb_valid <= '0';
ldm_arb_dframe_o <= '0';
data_fifo_rd <= '0';
dma_ctrl_done_o <= '0';
l2p_edb_o <= '0';
fifo_rst_t <= '1';
data_fifo_valid <= '0';
else
case l2p_dma_current_state is
when L2P_IDLE =>
l2p_timeout_cnt <= (others => '0');
l2p_edb_o <= '0';
fifo_rst_t <= '0';
ldm_arb_req_o <= '0';
ldm_arb_data_l <= (others => '0');
ldm_arb_valid <= '0';
ldm_arb_dframe_o <= '0';
data_fifo_rd <= '0';
data_fifo_valid <= '0';
dma_ctrl_done_o <= '0';
data_fifo_valid <= '0';
if (dma_ctrl_start_l2p_i = '1') then
l2p_dma_current_state <= L2P_SETUP;
end if;
when L2P_SETUP =>
ldm_arb_valid <= '0';
ldm_arb_dframe_o <= '0';
data_fifo_rd <= '0';
data_fifo_valid <= '0';
l2p_timeout_cnt <= (others => '0');
if (l2p_rdy_i = '1') then
l2p_dma_current_state <= L2P_HEADER;
ldm_arb_req_o <= '1'; -- Request bus
end if;
when L2P_HEADER =>
ldm_arb_valid <= '0';
if (arb_ldm_gnt_i = '1' and l_wr_rdy_i = '1') then
ldm_arb_req_o <= '0'; -- Bus has been granted
-- Send header
ldm_arb_data_l <= s_l2p_header;
ldm_arb_valid <= '1';
ldm_arb_dframe_o <= '1'; -- Keep asserted to stay bus master
if (l2p_64b_address = '1') then
l2p_dma_current_state <= L2P_ADDR_H;
else
l2p_dma_current_state <= L2P_ADDR_L;
end if;
end if;
when L2P_ADDR_H =>
ldm_arb_data_l <= l2p_address_h;
l2p_dma_current_state <= L2P_ADDR_L;
when L2P_ADDR_L =>
ldm_arb_data_l <= l2p_address_l;
l2p_dma_current_state <= L2P_DATA;
when L2P_DATA =>
ldm_arb_data_l <= x"DEADBEEF";
if (data_fifo_empty = '0' and l2p_rdy_i = '1') then
data_fifo_rd <= '1';
else
data_fifo_rd <= '0';
end if;
if (data_fifo_rd = '1' and data_fifo_empty = '0' and l2p_data_cnt = 1) then
ldm_arb_data_l <= f_byte_swap(g_BYTE_SWAP, data_fifo_dout, l2p_byte_swap);
ldm_arb_valid <= '1';
ldm_arb_dframe_o <= '0';
l2p_dma_current_state <= L2P_LAST_DATA;
data_fifo_rd <= '0'; -- Don't read too much
elsif (data_fifo_rd = '1' and data_fifo_empty = '0' and l2p_data_cnt > 1) then
ldm_arb_data_l <= f_byte_swap(g_BYTE_SWAP, data_fifo_dout, l2p_byte_swap);
ldm_arb_valid <= '1';
ldm_arb_dframe_o <= '1';
else
ldm_arb_data_l <= f_byte_swap(g_BYTE_SWAP, data_fifo_dout, l2p_byte_swap);
ldm_arb_valid <= '0';
ldm_arb_dframe_o <= '1';
end if;
-- Error condition, aboirt transfer
if (tx_error_i = '1' or l2p_timeout_cnt > c_TIMEOUT or dma_ctrl_abort_i = '1') then
l2p_dma_current_state <= L2P_ERROR;
end if;
-- Timeout counter
if (data_fifo_empty = '1' or l2p_rdy_i = '1') then
l2p_timeout_cnt <= l2p_timeout_cnt + 1;
else
l2p_timeout_cnt <= (others => '0');
end if;
when L2P_LAST_DATA =>
ldm_arb_data_l <= x"DEADBEEF";
ldm_arb_dframe_o <= '0';
ldm_arb_valid <= '0';
data_fifo_rd <= '0';
data_fifo_valid <= '0';
if (dma_ctrl_abort_i = '1' or tx_error_i = '1') then
l2p_dma_current_state <= L2P_IDLE;
dma_ctrl_done_o <= '1';
elsif (l2p_last_packet = '0') then
l2p_dma_current_state <= L2P_SETUP;
else
l2p_dma_current_state <= L2P_IDLE;
dma_ctrl_done_o <= '1';
end if;
when L2P_ERROR =>
ldm_arb_data_l <= x"DEADBEEF";
ldm_arb_dframe_o <= '0';
ldm_arb_valid <= '1';
l2p_edb_o <= '1';
fifo_rst_t <= '1';
l2p_dma_current_state <= L2P_IDLE;
when others =>
l2p_dma_current_state <= L2P_IDLE;
end case;
end if;
end if;
end process p_l2p_fsm;
---------------------
--- Paket Generator
---------------------
-- Last Byte Enable must be "0000" when length = 1
l2p_lbe_header <= "0000" when l2p_len_header = 1 else "1111";
-- 64bit address flag
l2p_64b_address <= '0' when l2p_address_h = x"00000000" else '1';
-- Packet header
s_l2p_header(31 downto 29) <= "000"; --> Traffic Class
s_l2p_header(28) <= '0'; --> Snoop
s_l2p_header(27 downto 25) <= "001"; --> Header type,
-- memory write 32-bit or
-- memory write 64-bit
s_l2p_header(24) <= l2p_64b_address;
s_l2p_header(23 downto 20) <= l2p_lbe_header; --> LBE (Last Byte Enable)
s_l2p_header(19 downto 16) <= "1111"; --> FBE (First Byte Enable)
s_l2p_header(15 downto 13) <= "000"; --> Reserved
s_l2p_header(12) <= '0'; --> VC (Virtual Channel)
s_l2p_header(11 downto 10) <= "00"; --> Reserved
s_l2p_header(9 downto 0) <= STD_LOGIC_VECTOR(l2p_len_header(9 downto 0)); --> Length (in 32-bit words)
-- 0x000 => 1024 words (4096 bytes)
p_pkt_gen : process (clk_i)
begin
if rising_edge(clk_i) then
if (rst_n_i = '0') then
l2p_len_header <= (others => '0');
l2p_last_packet <= '0';
else
if (l2p_dma_current_state = L2P_IDLE) then
l2p_len_cnt <= unsigned(dma_ctrl_len_i(14 downto 2));
l2p_address_h <= dma_ctrl_host_addr_h_i;
l2p_address_l <= dma_ctrl_host_addr_l_i;
l2p_byte_swap <= dma_ctrl_byte_swap_i;
l2p_last_packet <= '0';
elsif (l2p_dma_current_state = L2P_SETUP) then
if (l2p_len_cnt > c_L2P_MAX_PAYLOAD) then
l2p_data_cnt <= TO_UNSIGNED(c_L2P_MAX_PAYLOAD, 13);
l2p_len_header <= TO_UNSIGNED(c_L2P_MAX_PAYLOAD, 13);
l2p_last_packet <= '0';
elsif (l2p_len_cnt = c_L2P_MAX_PAYLOAD) then
l2p_data_cnt <= TO_UNSIGNED(c_L2P_MAX_PAYLOAD, 13);
l2p_len_header <= TO_UNSIGNED(c_L2P_MAX_PAYLOAD, 13);
l2p_last_packet <= '1';
else
l2p_data_cnt <= l2p_len_cnt;
l2p_len_header <= l2p_len_cnt;
l2p_last_packet <= '1';
end if;
elsif (l2p_dma_current_state = L2P_DATA) then
if (data_fifo_empty = '0' and data_fifo_rd = '1') then
l2p_data_cnt <= l2p_data_cnt - 1;
end if;
elsif (l2p_dma_current_state = L2P_LAST_DATA) then
if (l2p_last_packet = '0') then
-- Increase Address
-- TODO Not overflow safe !
l2p_address_l <= std_logic_vector(unsigned(l2p_address_l) + (c_L2P_MAX_PAYLOAD * 4));
l2p_len_cnt <= l2p_len_cnt - c_L2P_MAX_PAYLOAD;
else
l2p_len_cnt <= (others => '0');
end if;
end if;
end if;
end if;
end process p_pkt_gen;
---------------------
-- Address Counter
---------------------
p_target_cnt : process (clk_i)
begin
if rising_edge(clk_i) then
if (rst_n_i = '0') then
dma_ctrl_error_o <= '0';
addr_fifo_wr <= '0';
else
-- New Transfer started
if (l2p_dma_current_state = L2P_ERROR) then
target_addr_cnt <= (others => '0');
dma_ctrl_error_o <= '1';
addr_fifo_wr <= '0';
dma_length_cnt <= (others => '0');
elsif (dma_ctrl_start_l2p_i = '1') then
if (l2p_dma_current_state = L2P_IDLE) then
-- dma target adrr is byte address, need 32bit address
target_addr_cnt(31 downto 30) <= "00";
target_addr_cnt(29 downto 0) <= dma_ctrl_target_addr_i(31 downto 2);
-- dma target length is in byte, need 32bit
dma_length_cnt <= unsigned(dma_ctrl_len_i(14 downto 2));
dma_ctrl_error_o <= '0';
else
target_addr_cnt <= (others => '0');
dma_length_cnt <= (others => '0');
dma_ctrl_error_o <= '1';
end if;
addr_fifo_wr <= '0';
elsif (dma_length_cnt > 0) and (addr_fifo_full = '0') then
addr_fifo_wr <= '1';
target_addr_cnt <= std_logic_vector(unsigned(target_addr_cnt) + 1);
dma_length_cnt <= dma_length_cnt - 1;
addr_fifo_din <= target_addr_cnt;
else
addr_fifo_wr <= '0';
dma_ctrl_error_o <= '0';
end if;
end if;
end if;
end process p_target_cnt;
---------------------
-- Wishbone Master
---------------------
-- Tie offs
l2p_dma_cyc_o <= l2p_dma_cyc_t;
l2p_dma_stb_o <= l2p_dma_stb_t; --and not addr_fifo_empty;
l2p_dma_sel_o <= l2p_dma_sel_t;
l2p_dma_adr_o <= l2p_dma_adr_t;
l2p_dma_dat_o <= (others => '0');
l2p_dma_we_o <= '0';
addr_fifo_valid <= not(addr_fifo_empty or l2p_dma_stall_i or data_fifo_full or p2l_dma_cyc_i);
p_wb_master : process (l2p_dma_clk_i)
begin
if rising_edge(l2p_dma_clk_i) then
if wb_fifo_rst_n = '0' then
l2p_dma_stb_t <= '0';
l2p_dma_cyc_t <= '0';
addr_fifo_rd <= '0';
wb_read_cnt <= (others => '0');
else
l2p_dma_sel_t <= (others => '1');
l2p_dma_adr_t <= addr_fifo_dout;
if (addr_fifo_valid = '1') then
addr_fifo_rd <= '1';
else
addr_fifo_rd <= '0';
end if;
if (addr_fifo_rd = '1' and addr_fifo_empty = '0') then
l2p_dma_stb_t <= '1';
else
l2p_dma_stb_t <= '0';
end if;
if (l2p_dma_stb_t = '1' and l2p_dma_ack_i = '0' and l2p_dma_cyc_t = '1') then
wb_read_cnt <= wb_read_cnt + 1;
elsif (l2p_dma_stb_t = '0' and l2p_dma_ack_i = '1' and l2p_dma_cyc_t = '1') then
wb_read_cnt <= wb_read_cnt - 1;
end if;
if (addr_fifo_valid = '1') then
l2p_dma_cyc_t <= '1';
elsif (wb_read_cnt = 0) then
l2p_dma_cyc_t <= '0';
end if;
end if;
end if;
end process p_wb_master;
-- Receive data
data_rec_proc : process(l2p_dma_clk_i)
begin
if rising_edge(l2p_dma_clk_i) then
if wb_fifo_rst_n = '0' then
data_fifo_wr <= '0';
else
if (l2p_dma_cyc_t = '1') then
data_fifo_din <= l2p_dma_dat_i;
data_fifo_wr <= l2p_dma_ack_i;
else
data_fifo_din <= x"BABEDEAD";
data_fifo_wr <= '0';
end if;
end if;
end if;
end process data_rec_proc;
---------------------
-- FIFOs
---------------------
cmp_addr_fifo: generic_async_fifo_dual_rst
generic map (
g_data_width => 32,
g_size => 1024,
g_show_ahead => true,
g_with_wr_full => false,
g_with_wr_almost_full => true,
g_almost_empty_threshold => 0,
g_almost_full_threshold => c_ADDR_FIFO_FULL_THRES)
port map (
rst_wr_n_i => fifo_rst_n,
clk_wr_i => clk_i,
d_i => addr_fifo_din,
we_i => addr_fifo_wr,
wr_almost_full_o => addr_fifo_full,
rst_rd_n_i => wb_fifo_rst_n,
clk_rd_i => l2p_dma_clk_i,
q_o => addr_fifo_dout,
rd_i => addr_fifo_rd,
rd_empty_o => addr_fifo_empty);
cmp_data_fifo: generic_async_fifo_dual_rst
generic map (
g_data_width => 32,
g_size => 1024,
g_show_ahead => true,
g_with_wr_full => false,
g_with_wr_almost_full => true,
g_almost_empty_threshold => 0,
g_almost_full_threshold => c_DATA_FIFO_FULL_THRES)
port map (
rst_wr_n_i => wb_fifo_rst_n,
clk_wr_i => l2p_dma_clk_i,
d_i => data_fifo_din,
we_i => data_fifo_wr,
wr_almost_full_o => data_fifo_full,
rst_rd_n_i => fifo_rst_n,
clk_rd_i => clk_i,
q_o => data_fifo_dout,
rd_i => data_fifo_rd,
rd_empty_o => data_fifo_empty);
end behavioral;
//------------------------------------------------------------------------------
// CERN BE-CO-HT
// GN4124 core for PCIe FMC carrier
// http://www.ohwr.org/projects/gn4124-core
//------------------------------------------------------------------------------
//
// unit name: main
//
// description: This is a simple example testbench, to demonstrate how to use
// the SystemVerilog BFM of the GN4124 to perform simple accesses over wishbone.
//
// The testbench simply connects the wishbone master of the GN4124 to its own
// DMA configuration wishbone slave and attaches a pre-initialised dummy RAM
// with a wishbone interface to the pipelined DMA interface in order to perform
// a DMA read.
//
//------------------------------------------------------------------------------
// Copyright CERN 2019
//------------------------------------------------------------------------------
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 2.0 (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-2.0.
// Unless required by applicable law or agreed to in writing, software,
// hardware and materials distributed under this License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
// or implied. See the License for the specific language governing permissions
// and limitations under the License.
//------------------------------------------------------------------------------
`timescale 1ns/1ps
`include "gn4124_bfm.svh"
import wishbone_pkg::*;
module main;
reg clk_125m = 0;
logic gn4124_irq;
t_wishbone_master_in wb_in, wb_dma_in, wb_mem_in;
t_wishbone_master_out wb_out, wb_dma_out, wb_mem_out;
always #4ns clk_125m <= ~clk_125m;
logic rst_125m_n;
initial begin
rst_125m_n = 0;
#80ns rst_125m_n = 1;
end
IGN4124PCIMaster i_gn4124 ();
xwb_gn4124_core
DUT (
.rst_n_a_i (i_gn4124.rst_n),
.p2l_clk_p_i (i_gn4124.p2l_clk_p),
.p2l_clk_n_i (i_gn4124.p2l_clk_n),
.p2l_data_i (i_gn4124.p2l_data),
.p2l_dframe_i (i_gn4124.p2l_dframe),
.p2l_valid_i (i_gn4124.p2l_valid),
.p2l_rdy_o (i_gn4124.p2l_rdy),
.p_wr_req_i (i_gn4124.p_wr_req),
.p_wr_rdy_o (i_gn4124.p_wr_rdy),
.rx_error_o (i_gn4124.rx_error),
.vc_rdy_i (i_gn4124.vc_rdy),
.l2p_clk_p_o (i_gn4124.l2p_clk_p),
.l2p_clk_n_o (i_gn4124.l2p_clk_n),
.l2p_data_o (i_gn4124.l2p_data),
.l2p_dframe_o (i_gn4124.l2p_dframe),
.l2p_valid_o (i_gn4124.l2p_valid),
.l2p_edb_o (i_gn4124.l2p_edb),
.l2p_rdy_i (i_gn4124.l2p_rdy),
.l_wr_rdy_i (i_gn4124.l_wr_rdy),
.p_rd_d_rdy_i (i_gn4124.p_rd_d_rdy),
.tx_error_i (i_gn4124.tx_error),
.dma_irq_o (),
.irq_p_i (1'b0),
.irq_p_o (gn4124_irq),
.status_o (),
.wb_master_clk_i (clk_125m),
.wb_master_rst_n_i (rst_125m_n),
.wb_master_i (wb_in),
.wb_master_o (wb_out),
.wb_dma_cfg_clk_i (clk_125m),
.wb_dma_cfg_rst_n_i (rst_125m_n),
.wb_dma_cfg_i (wb_out),
.wb_dma_cfg_o (wb_in),
.wb_dma_dat_clk_i (clk_125m),
.wb_dma_dat_rst_n_i (rst_125m_n),
.wb_dma_dat_i (wb_dma_in),
.wb_dma_dat_o (wb_dma_out)
);
xwb_dpram #
(
.g_size (32),
.g_init_file ("mem_init.bram"),
.g_slave1_interface_mode (1), // 1 = PIPELINED
.g_slave2_interface_mode (1),
.g_slave1_granularity (1), // 1 = WORD
.g_slave2_granularity (1)
)
MEM (
.rst_n_i (1'b1),
.clk_sys_i (clk_125m),
.slave1_i (wb_dma_out),
.slave1_o (wb_dma_in),
.slave2_i (wb_mem_out),
.slave2_o (wb_mem_in)
);
CBusAccessor acc;
task val_check(string name, uint64_t addr, val, expected);
if (val != expected)
begin
$display();
$display("Simulation FAILED");
$fatal(1, "%s error at address 0x%.2x. Expected 0x%.8x, got 0x%.8x",
name, addr, expected, val);
end
$display("%s at address 0x%.2x: 0x%.8x [OK]",
name, addr, val);
endtask // val_check
task reg_check(uint64_t addr, expected);
uint64_t val;
acc.read(addr, val);
val_check("Register read-back", addr, val, expected);
endtask // reg_check
initial begin
uint64_t addr, val, expected;
@(posedge i_gn4124.ready);
acc = i_gn4124.get_accessor();
acc.set_default_xfer_size(4);
@(posedge clk_125m);
// Verify simple read/writes over wishbone
reg_check('h0, 'h0);
acc.write('h10, 'hffacce55);
acc.write('h20, 'h1badcafe);
reg_check('h10, 'hffacce55);
reg_check('h20, 'h1badcafe);
// Reset all DMA config registers
for (addr = 'h00; addr <= 'h20; addr += 4)
begin
acc.write(addr, 'h0);
end
// Perform 32 reads over DMA
acc.write('h14, 'h80);
acc.write('h00, 'h01);
// Check values read from memory
@(posedge i_gn4124.l2p_valid); // skip header
@(posedge i_gn4124.l2p_valid);
for (addr = 'h20; addr > 'h00; addr -= 1)
begin
expected = 64'h80000000 + addr - 1;
val = i_gn4124.l2p_data;
@(posedge i_gn4124.l2p_clk_n);
val |= i_gn4124.l2p_data << 16;
val_check("DMA read-back", 'h20-addr, val, expected);
@(posedge i_gn4124.l2p_clk_p);
end
#1us;
$display();
$display("Simulation PASSED");
$finish;
end
endmodule // main
10000000000000000000000000011111
10000000000000000000000000011110
10000000000000000000000000011101
10000000000000000000000000011100
10000000000000000000000000011011
10000000000000000000000000011010
10000000000000000000000000011001
10000000000000000000000000011000
10000000000000000000000000010111
10000000000000000000000000010110
10000000000000000000000000010101
10000000000000000000000000010100
10000000000000000000000000010011
10000000000000000000000000010010
10000000000000000000000000010001
10000000000000000000000000010000
10000000000000000000000000001111
10000000000000000000000000001110
10000000000000000000000000001101
10000000000000000000000000001100
10000000000000000000000000001011
10000000000000000000000000001010
10000000000000000000000000001001
10000000000000000000000000001000
10000000000000000000000000000111
10000000000000000000000000000110
10000000000000000000000000000101
10000000000000000000000000000100
10000000000000000000000000000011
10000000000000000000000000000010
10000000000000000000000000000001
10000000000000000000000000000000
--------------------------------------------------------------------------------
-- CERN BE-CO-HT
-- GN4124 core for PCIe FMC carrier
-- http://www.ohwr.org/projects/gn4124-core
--------------------------------------------------------------------------------
--
-- unit name: dma_controller_wb_slave
--
-- description: GN4124 core DMA controller registers block layout (wbgen2)
--
--------------------------------------------------------------------------------
-- Copyright CERN 2010-2018
--------------------------------------------------------------------------------
-- Copyright and related rights are licensed under the Solderpad Hardware
-- License, Version 2.0 (the "License"); you may not use this file except
-- in compliance with the License. You may obtain a copy of the License at
-- http://solderpad.org/licenses/SHL-2.0.
-- Unless required by applicable law or agreed to in writing, software,
-- hardware and materials distributed under this License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
-- or implied. See the License for the specific language governing permissions
-- and limitations under the License.
--------------------------------------------------------------------------------
peripheral {
name = "GN4124 core DMA controller ";
description = "Wishbone slave for the DMA controller of the GN4124 core";
hdl_entity = "dma_controller_wb_slave";
prefix = "dma";
reg {
name = "DMACTRLR";
prefix = "ctrl";
field {
name = "DMA engine control";
type = SLV;
size = 32;
load = LOAD_EXT;
access_bus = READ_WRITE;
access_dev = READ_WRITE;
clock = "clk_i"
};
};
reg {
name = "DMASTATR";
prefix = "stat";
field {
name = "DMA engine status";
type = SLV;
size = 32;
load = LOAD_EXT;
access_bus = READ_WRITE;
access_dev = READ_WRITE;
clock = "clk_i"
};
};
reg {
name = "DMACSTARTR";
prefix = "cstart";
field {
name = "DMA start address in the carrier";
type = SLV;
size = 32;
load = LOAD_EXT;
access_bus = READ_WRITE;
access_dev = READ_WRITE;
clock = "clk_i"
};
};
reg {
name = "DMAHSTARTLR";
prefix = "hstartl";
field {
name = "DMA start address (low) in the host";
type = SLV;
size = 32;
load = LOAD_EXT;
access_bus = READ_WRITE;
access_dev = READ_WRITE;
clock = "clk_i"
};
};
reg {
name = "DMAHSTARTHR";
prefix = "hstarth";
field {
name = "DMA start address (high) in the host";
type = SLV;
size = 32;
load = LOAD_EXT;
access_bus = READ_WRITE;
access_dev = READ_WRITE;
clock = "clk_i"
};
};
reg {
name = "DMALENR";
prefix = "len";
field {
name = "DMA read length in bytes";
type = SLV;
size = 32;
load = LOAD_EXT;
access_bus = READ_WRITE;
access_dev = READ_WRITE;
clock = "clk_i"
};
};
reg {
name = "DMANEXTLR";
prefix = "nextl";
field {
name = "Pointer (low) to next item in list";
type = SLV;
size = 32;
load = LOAD_EXT;
access_bus = READ_WRITE;
access_dev = READ_WRITE;
clock = "clk_i"
};
};
reg {
name = "DMANEXTHR";
prefix = "nexth";
field {
name = "Pointer (high) to next item in list";
type = SLV;
size = 32;
load = LOAD_EXT;
access_bus = READ_WRITE;
access_dev = READ_WRITE;
clock = "clk_i"
};
};
reg {
name = "DMAATTRIBR";
prefix = "attrib";
field {
name = "DMA chain control";
type = SLV;
size = 32;
load = LOAD_EXT;
access_bus = READ_WRITE;
access_dev = READ_WRITE;
clock = "clk_i"
};
};
};
Subproject commit 4e5f7badf0b72f51bdb01c63fcdc6d69afb4b750
Subproject commit 258eb8e00f99f795fe9b98840b01ac4a8b92ec94
files = [
"dma_controller.vhd",
"dma_controller_wb_slave.vhd",
"dma_controller_regs.vhd",
"l2p_arbiter.vhd",
"l2p_dma_master.vhd",
"p2l_decode32.vhd",
......
--------------------------------------------------------------------------------
-- CERN BE-CO-HT
-- GN4124 core for PCIe FMC carrier
-- http://www.ohwr.org/projects/gn4124-core
--------------------------------------------------------------------------------
--
-- unit name: dma_controller
--
-- description: Manages the DMA transfers.
--
--------------------------------------------------------------------------------
-- Copyright CERN 2010-2019
--------------------------------------------------------------------------------
-- Copyright and related rights are licensed under the Solderpad Hardware
-- License, Version 2.0 (the "License"); you may not use this file except
-- in compliance with the License. You may obtain a copy of the License at
-- http://solderpad.org/licenses/SHL-2.0.
-- Unless required by applicable law or agreed to in writing, software,
-- hardware and materials distributed under this License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
-- or implied. See the License for the specific language governing permissions
-- and limitations under the License.
--------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.NUMERIC_STD.all;
entity dma_controller is
port (
---------------------------------------------------------
-- GN4124 core clock and reset
clk_i : in std_logic;
rst_n_i : in std_logic;
---------------------------------------------------------
-- Interrupt request
dma_ctrl_irq_o : out std_logic;
---------------------------------------------------------
-- Used to control the DMA WB mux
dma_ctrl_direction_o : out std_logic;
---------------------------------------------------------
-- To the L2P DMA master and P2L DMA master
dma_ctrl_carrier_addr_o : out std_logic_vector(31 downto 0);
dma_ctrl_host_addr_h_o : out std_logic_vector(31 downto 0);
dma_ctrl_host_addr_l_o : out std_logic_vector(31 downto 0);
dma_ctrl_len_o : out std_logic_vector(31 downto 0);
dma_ctrl_start_l2p_o : out std_logic; -- To the L2P DMA master
dma_ctrl_start_p2l_o : out std_logic; -- To the P2L DMA master
dma_ctrl_start_next_o : out std_logic; -- To the P2L DMA master
dma_ctrl_byte_swap_o : out std_logic_vector(1 downto 0);
dma_ctrl_abort_o : out std_logic;
dma_ctrl_done_i : in std_logic;
dma_ctrl_error_i : in std_logic;
---------------------------------------------------------
-- From P2L DMA master
next_item_carrier_addr_i : in std_logic_vector(31 downto 0);
next_item_host_addr_h_i : in std_logic_vector(31 downto 0);
next_item_host_addr_l_i : in std_logic_vector(31 downto 0);
next_item_len_i : in std_logic_vector(31 downto 0);
next_item_next_l_i : in std_logic_vector(31 downto 0);
next_item_next_h_i : in std_logic_vector(31 downto 0);
next_item_attrib_i : in std_logic_vector(31 downto 0);
next_item_valid_i : in std_logic;
---------------------------------------------------------
-- Wishbone slave interface
wb_rst_n_i : in std_logic;
wb_clk_i : in std_logic; -- Bus clock
wb_adr_i : in std_logic_vector(3 downto 0); -- Adress
wb_dat_o : out std_logic_vector(31 downto 0); -- Data in
wb_dat_i : in std_logic_vector(31 downto 0); -- Data out
wb_sel_i : in std_logic_vector(3 downto 0); -- Byte select
wb_cyc_i : in std_logic; -- Read or write cycle
wb_stb_i : in std_logic; -- Read or write strobe
wb_we_i : in std_logic; -- Write
wb_ack_o : out std_logic -- Acknowledge
);
end dma_controller;
architecture arch of dma_controller is
-- Values for the STAT register
constant c_DMA_STAT_IDLE : std_logic_vector(1 downto 0) := "00";
constant c_DMA_STAT_BUSY : std_logic_vector(1 downto 0) := "01";
constant c_DMA_STAT_ERROR : std_logic_vector(1 downto 0) := "10";
constant c_DMA_STAT_ABORT : std_logic_vector(1 downto 0) := "11";
-- DMA controller registers
signal dma_ctrl_start_wb : std_logic;
signal dma_ctrl_abort_wb : std_logic;
signal dma_ctrl_wr_wb : std_logic;
signal dma_ctrl_wack_wb : std_logic;
signal dma_ctrl_byte_swap_wb : std_logic_vector(1 downto 0);
signal dma_ctrl_byte_swap : std_logic_vector(1 downto 0);
signal dma_ctrl_start : std_logic;
signal dma_ctrl_abort : std_logic;
signal dma_ctrl_wr : std_logic;
signal dma_async_cstart : std_logic_vector(31 downto 0);
signal dma_async_hstartl : std_logic_vector(31 downto 0);
signal dma_async_hstarth : std_logic_vector(31 downto 0);
signal dma_async_len : std_logic_vector(31 downto 0);
signal dma_async_nextl : std_logic_vector(31 downto 0);
signal dma_async_nexth : std_logic_vector(31 downto 0);
signal dma_async_attrib_chain : std_logic;
signal dma_async_attrib_dir : std_logic;
signal dma_stat_irq_i_wb : std_logic;
signal dma_stat_irq_o_wb : std_logic;
signal dma_stat_status_wb : std_logic_vector(1 downto 0);
signal dma_stat_wr_wb : std_logic;
signal dma_stat_wack_wb : std_logic;
signal dma_stat_rd_wb : std_logic;
signal dma_stat_rack_wb : std_logic;
signal dma_stat_irq_wr_wb : std_logic;
signal dma_stat_irq_wr : std_logic;
signal dma_stat_wr : std_logic;
signal dma_cstart_reg : std_logic_vector(31 downto 0);
signal dma_hstartl_reg : std_logic_vector(31 downto 0);
signal dma_hstarth_reg : std_logic_vector(31 downto 0);
signal dma_len_reg : std_logic_vector(31 downto 0);
signal dma_nextl_reg : std_logic_vector(31 downto 0);
signal dma_nexth_reg : std_logic_vector(31 downto 0);
signal dma_attrib_chain_reg : std_logic;
signal dma_attrib_dir_reg : std_logic;
signal dma_ctrl_byte_swap_reg : std_logic_vector(1 downto 0);
-- DMA controller FSM
type dma_ctrl_state_type is (DMA_IDLE, DMA_START_TRANSFER, DMA_TRANSFER, DMA_CHAIN);
signal dma_ctrl_current_state : dma_ctrl_state_type;
-- status signals
signal dma_stat_reg : std_logic_vector(1 downto 0);
signal dma_irq_reg : std_logic;
-- This signals come from registers clocked by the dma_reg_clk but read by registers clocked
-- by sys_clk. Synchronization is safe because they are read many clocks later (when a DMA
-- is started), assuming the user doesn't modify them...
-- To relax timing constraints, they share a common prefix 'dma_async_'.
attribute keep : string;
attribute keep of dma_async_cstart, dma_async_hstartl, dma_async_hstarth, dma_async_len,
dma_async_nextl, dma_async_nexth, dma_async_attrib_chain, dma_async_attrib_dir : signal is "true";
begin
------------------------------------------------------------------------------
-- Wishbone slave instantiation
------------------------------------------------------------------------------
inst_dma_controller_regs : entity work.dma_controller_regs
port map (
rst_n_i => wb_rst_n_i,
clk_i => wb_clk_i,
wb_adr_i => wb_adr_i,
wb_dat_i => wb_dat_i,
wb_dat_o => wb_dat_o,
wb_cyc_i => wb_cyc_i,
wb_sel_i => wb_sel_i,
wb_stb_i => wb_stb_i,
wb_we_i => wb_we_i,
wb_ack_o => wb_ack_o,
ctrl_start_o => dma_ctrl_start_wb,
ctrl_start_i => '0',
ctrl_abort_o => dma_ctrl_abort_wb,
ctrl_abort_i => '0',
ctrl_byteswap_o => dma_ctrl_byte_swap_wb,
ctrl_wr_o => dma_ctrl_wr_wb,
ctrl_wack_i => dma_ctrl_wack_wb,
stat_status_o => open,
stat_status_i => dma_stat_status_wb,
stat_irq_i => dma_stat_irq_i_wb,
stat_irq_o => dma_stat_irq_o_wb,
stat_wr_o => dma_stat_wr_wb,
stat_wack_i => dma_stat_wack_wb,
stat_rd_o => dma_stat_rd_wb,
stat_rack_i => dma_stat_rack_wb,
cstart_o => dma_async_cstart,
hstartl_o => dma_async_hstartl,
hstarth_o => dma_async_hstarth,
len_o => dma_async_len,
nextl_o => dma_async_nextl,
nexth_o => dma_async_nexth,
attrib_chain_o => dma_async_attrib_chain,
attrib_dir_o => dma_async_attrib_dir,
cur_cstart_i => dma_cstart_reg,
cur_hstartl_i => dma_hstartl_reg,
cur_hstarth_i => dma_hstarth_reg,
cur_len_i => dma_len_reg);
-- Synchronizers for control.
inst_sync_ctrl : entity work.gc_sync_word_wr
generic map (
g_WIDTH => 4)
port map (
clk_in_i => wb_clk_i,
rst_in_n_i => wb_rst_n_i,
clk_out_i => clk_i,
rst_out_n_i => rst_n_i,
data_i(0) => dma_ctrl_start_wb,
data_i(1) => dma_ctrl_abort_wb,
data_i(3 downto 2) => dma_ctrl_byte_swap_wb,
wr_i => dma_ctrl_wr_wb,
ack_o => dma_ctrl_wack_wb,
data_o(0) => dma_ctrl_start,
data_o(1) => dma_ctrl_abort,
data_o(3 downto 2) => dma_ctrl_byte_swap,
wr_o => dma_ctrl_wr);
dma_stat_irq_wr_wb <= dma_stat_wr_wb and dma_stat_irq_o_wb;
-- Pulse is generated when a '1' is written to the irq bit of the stat reg.
inst_sync_stat_wr : entity work.gc_sync_word_wr
generic map (
g_auto_wr => FALSE,
g_width => 1)
port map (
clk_in_i => wb_clk_i,
rst_in_n_i => wb_rst_n_i,
clk_out_i => clk_i,
rst_out_n_i => rst_n_i,
data_i(0) => dma_stat_irq_wr_wb,
wr_i => dma_stat_wr_wb,
ack_o => dma_stat_wack_wb,
data_o(0) => dma_stat_irq_wr,
wr_o => dma_stat_wr);
-- Sync stat
inst_sync_stat_rd : entity work.gc_sync_word_rd
generic map (
g_WIDTH => 3)
port map (
clk_out_i => wb_clk_i,
rst_out_n_i => wb_rst_n_i,
clk_in_i => clk_i,
rst_in_n_i => rst_n_i,
data_in_i(1 downto 0) => dma_stat_reg,
data_in_i(2) => dma_irq_reg,
rd_out_i => dma_stat_rd_wb,
ack_out_o => dma_stat_rack_wb,
data_out_o(1 downto 0) => dma_stat_status_wb,
data_out_o(2) => dma_stat_irq_i_wb,
rd_in_o => open);
------------------------------------------------------------------------------
-- DMA controller FSM
------------------------------------------------------------------------------
p_fsm : process (clk_i)
begin
if rising_edge(clk_i) then
if(rst_n_i = '0') then
dma_ctrl_current_state <= DMA_IDLE;
dma_ctrl_start_l2p_o <= '0';
dma_ctrl_start_p2l_o <= '0';
dma_ctrl_start_next_o <= '0';
dma_ctrl_direction_o <= '0';
dma_ctrl_abort_o <= '0';
dma_stat_reg <= c_DMA_STAT_IDLE;
dma_irq_reg <= '0';
dma_cstart_reg <= (others => '0');
dma_hstartl_reg <= (others => '0');
dma_hstarth_reg <= (others => '0');
dma_len_reg <= (others => '0');
dma_nextl_reg <= (others => '0');
dma_nexth_reg <= (others => '0');
dma_ctrl_byte_swap_reg <= "00";
dma_attrib_chain_reg <= '0';
dma_attrib_dir_reg <= '0';
else
-- Clear interrupt when idle status is read.
if dma_stat_irq_wr = '1' and dma_stat_wr = '1' then
dma_irq_reg <= '0';
end if;
case dma_ctrl_current_state is
when DMA_IDLE =>
if (dma_ctrl_wr and dma_ctrl_start) = '1' then
-- Capture parameters
-- All these inputs registers are synchronized on the start pulse.
dma_cstart_reg <= dma_async_cstart;
dma_hstartl_reg <= dma_async_hstartl;
dma_hstarth_reg <= dma_async_hstarth;
dma_len_reg <= dma_async_len;
dma_nextl_reg <= dma_async_nextl;
dma_nexth_reg <= dma_async_nexth;
dma_attrib_chain_reg <= dma_async_attrib_chain;
dma_attrib_dir_reg <= dma_async_attrib_dir;
dma_ctrl_byte_swap_reg <= dma_ctrl_byte_swap;
-- Set it early to ease timing.
dma_ctrl_direction_o <= dma_async_attrib_dir;
-- Starts a new transfer
dma_ctrl_current_state <= DMA_START_TRANSFER;
end if;
when DMA_START_TRANSFER =>
-- Clear abort signal
dma_ctrl_abort_o <= '0';
if unsigned(dma_len_reg(31 downto 2)) = 0 then
-- Requesting a DMA of 0 word length gives a error
dma_irq_reg <= '1';
dma_stat_reg <= c_DMA_STAT_ERROR;
dma_ctrl_current_state <= DMA_IDLE;
else
if dma_attrib_dir_reg = '0' then
-- L2P transfer (from target to PCIe)
dma_ctrl_start_l2p_o <= '1';
dma_ctrl_direction_o <= '0';
else
-- P2L transfer (from PCIe to target)
dma_ctrl_start_p2l_o <= '1';
dma_ctrl_direction_o <= '1';
end if;
dma_stat_reg <= c_DMA_STAT_BUSY;
dma_ctrl_current_state <= DMA_TRANSFER;
end if;
when DMA_TRANSFER =>
-- Clear start signals, to make them 1 tick pulses
dma_ctrl_start_l2p_o <= '0';
dma_ctrl_start_p2l_o <= '0';
if (dma_ctrl_abort and dma_ctrl_wr) = '1' then
-- Transfer aborted
dma_ctrl_abort_o <= '1';
dma_stat_reg <= c_DMA_STAT_ABORT;
dma_ctrl_current_state <= DMA_IDLE;
elsif dma_ctrl_error_i = '1' then
-- An error occured
dma_irq_reg <= '1';
dma_stat_reg <= c_DMA_STAT_ERROR;
dma_ctrl_current_state <= DMA_IDLE;
elsif dma_ctrl_done_i = '1' then
-- End of DMA transfer
if dma_attrib_chain_reg = '1' then
-- More transfers in chained DMA
dma_hstarth_reg <= dma_nexth_reg;
dma_hstartl_reg <= dma_nextl_reg;
dma_len_reg <= X"0000001C";
dma_ctrl_start_next_o <= '1';
dma_ctrl_current_state <= DMA_CHAIN;
else
-- Was the last transfer
dma_irq_reg <= '1';
dma_stat_reg <= c_DMA_STAT_IDLE;
dma_ctrl_current_state <= DMA_IDLE;
end if;
end if;
when DMA_CHAIN =>
-- Clear start next signal, to make it 1 tick pulse
dma_ctrl_start_next_o <= '0';
if (dma_ctrl_abort and dma_ctrl_wr) = '1' then
-- Transfer aborted
dma_ctrl_abort_o <= '1';
dma_stat_reg <= c_DMA_STAT_ABORT;
dma_ctrl_current_state <= DMA_IDLE;
elsif dma_ctrl_error_i = '1' then
-- An error occured
dma_irq_reg <= '1';
dma_stat_reg <= c_DMA_STAT_ERROR;
dma_ctrl_current_state <= DMA_IDLE;
elsif next_item_valid_i = '1' then
-- Capture parameters
dma_cstart_reg <= next_item_carrier_addr_i;
dma_hstartl_reg <= next_item_host_addr_l_i;
dma_hstarth_reg <= next_item_host_addr_h_i;
dma_len_reg <= next_item_len_i;
dma_nextl_reg <= next_item_next_l_i;
dma_nexth_reg <= next_item_next_h_i;
dma_attrib_chain_reg <= next_item_attrib_i(1);
dma_attrib_dir_reg <= next_item_attrib_i(0);
-- Next item received
dma_ctrl_current_state <= DMA_START_TRANSFER;
end if;
end case;
end if;
end if;
end process p_fsm;
dma_ctrl_carrier_addr_o <= dma_cstart_reg;
dma_ctrl_host_addr_h_o <= dma_hstarth_reg;
dma_ctrl_host_addr_l_o <= dma_hstartl_reg;
dma_ctrl_len_o <= dma_len_reg;
dma_ctrl_irq_o <= dma_irq_reg;
dma_ctrl_byte_swap_o <= dma_ctrl_byte_swap_reg;
end architecture arch;
# ------------------------------------------------------------------------------
# CERN BE-CO-HT
# GN4124 core for PCIe FMC carrier
# http://www.ohwr.org/projects/gn4124-core
# ------------------------------------------------------------------------------
#
# unit name: dma_controller_regs
#
# description: GN4124 core DMA controller registers block layout
#
# ------------------------------------------------------------------------------
# Copyright CERN 2010-2019
# ------------------------------------------------------------------------------
# Copyright and related rights are licensed under the Solderpad Hardware
# License, Version 2.0 (the "License"); you may not use this file except
# in compliance with the License. You may obtain a copy of the License at
# http://solderpad.org/licenses/SHL-2.0.
# Unless required by applicable law or agreed to in writing, software,
# hardware and materials distributed under this License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
# or implied. See the License for the specific language governing permissions
# and limitations under the License.
# ------------------------------------------------------------------------------
memory-map:
bus: wb-32-be
name: dma_controller_regs
description: "GN4124 core DMA controller"
comment: Wishbone slave for the DMA controller of the GN4124 core
children:
- reg:
name: ctrl
address: 0x00000000
width: 32
access: rw
description: DMACTRLR
children:
- field:
name: start
range: 0
comment: Start DMA transfer
description: Write '1' to start a DMA transfer
x-hdl:
type: wire
- field:
name: abort
range: 1
comment: Abort current DMA transfer
description: Write '1' to abort the DMA transfer
x-hdl:
type: wire
- field:
name: byteswap
range: 3-2
description: Control byte-swapping
comment: |
- 00: ABCD -> ABCD
- 01: ABCD -> DCBA
- 10: ABCD -> CDAB
- 11: ABCD -> BADC
x-hdl:
write-strobe: True
write-ack: True
- reg:
name: stat
address: 0x00000004
width: 32
access: rw
description: DMASTATR
children:
- field:
name: status
comment: DMA state
description: |
DMA state:
00: idle
01: busy
10: error
11: abort
range: 1-0
x-hdl:
type: wire
- field:
name: irq
comment: IRQ status, write 1 to clear
range: 2
x-hdl:
type: wire
x-hdl:
write-strobe: True
write-ack: True
read-strobe: True
read-ack: True
- reg:
name: cstart
address: 0x00000008
width: 32
access: rw
comment: DMACSTARTR
description: Carrier start address
- reg:
name: hstartl
address: 0x0000000c
width: 32
access: rw
comment: DMAHSTARTLR
description: DMA start address (low) in the host
- reg:
name: hstarth
address: 0x00000010
width: 32
access: rw
comment: DMAHSTARTHR
description: DMA start address (high) in the host
- reg:
name: len
address: 0x00000014
width: 32
access: rw
comment: DMALENR
description: DMA read length in bytes
- reg:
name: nextl
address: 0x00000018
width: 32
access: rw
comment: DMANEXTLR
description: Pointer (low) to next item in list
- reg:
name: nexth
address: 0x0000001c
width: 32
access: rw
comment: DMANEXTHR
description: Pointer (high) to next item in list
- reg:
name: attrib
address: 0x00000020
width: 32
access: rw
comment: DMAATTRIBR
description: DMA chain control
children:
- field:
name: chain
comment: Transfer chain (if 1)
range: 1
- field:
name: dir
comment: "Transfer direction (0: to host, 1: to carrier)"
range: 0
- reg:
name: cur_cstart
width: 32
access: ro
description: Current carrier start address
- reg:
name: cur_hstartl
width: 32
access: ro
description: Current DMA start address (low) in the host
- reg:
name: cur_hstarth
width: 32
access: ro
description: Current DMA start address (high) in the host
- reg:
name: cur_len
width: 32
access: ro
description: Current DMA read length in bytes
-- Do not edit; this file was generated by Cheby using these options:
-- --gen-hdl=dma_controller_regs.vhd -i dma_controller_regs.cheby
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity dma_controller_regs is
port (
rst_n_i : in std_logic;
clk_i : in std_logic;
wb_cyc_i : in std_logic;
wb_stb_i : in std_logic;
wb_adr_i : in std_logic_vector(5 downto 2);
wb_sel_i : in std_logic_vector(3 downto 0);
wb_we_i : in std_logic;
wb_dat_i : in std_logic_vector(31 downto 0);
wb_ack_o : out std_logic;
wb_err_o : out std_logic;
wb_rty_o : out std_logic;
wb_stall_o : out std_logic;
wb_dat_o : out std_logic_vector(31 downto 0);
-- Start DMA transfer
ctrl_start_i : in std_logic;
ctrl_start_o : out std_logic;
-- Abort current DMA transfer
ctrl_abort_i : in std_logic;
ctrl_abort_o : out std_logic;
-- Control byte-swapping
ctrl_byteswap_o : out std_logic_vector(1 downto 0);
ctrl_wr_o : out std_logic;
ctrl_wack_i : in std_logic;
-- DMA state
stat_status_i : in std_logic_vector(1 downto 0);
stat_status_o : out std_logic_vector(1 downto 0);
-- IRQ status, write 1 to clear
stat_irq_i : in std_logic;
stat_irq_o : out std_logic;
stat_wr_o : out std_logic;
stat_rd_o : out std_logic;
stat_wack_i : in std_logic;
stat_rack_i : in std_logic;
-- Carrier start address
cstart_o : out std_logic_vector(31 downto 0);
-- DMA start address (low) in the host
hstartl_o : out std_logic_vector(31 downto 0);
-- DMA start address (high) in the host
hstarth_o : out std_logic_vector(31 downto 0);
-- DMA read length in bytes
len_o : out std_logic_vector(31 downto 0);
-- Pointer (low) to next item in list
nextl_o : out std_logic_vector(31 downto 0);
-- Pointer (high) to next item in list
nexth_o : out std_logic_vector(31 downto 0);
-- Transfer chain (if 1)
attrib_chain_o : out std_logic;
-- Transfer direction (0: to host, 1: to carrier)
attrib_dir_o : out std_logic;
-- Current carrier start address
cur_cstart_i : in std_logic_vector(31 downto 0);
-- Current DMA start address (low) in the host
cur_hstartl_i : in std_logic_vector(31 downto 0);
-- Current DMA start address (high) in the host
cur_hstarth_i : in std_logic_vector(31 downto 0);
-- Current DMA read length in bytes
cur_len_i : in std_logic_vector(31 downto 0)
);
end dma_controller_regs;
architecture syn of dma_controller_regs is
signal rd_int : std_logic;
signal wr_int : std_logic;
signal rd_ack_int : std_logic;
signal wr_ack_int : std_logic;
signal wb_en : std_logic;
signal ack_int : std_logic;
signal wb_rip : std_logic;
signal wb_wip : std_logic;
signal ctrl_byteswap_reg : std_logic_vector(1 downto 0);
signal cstart_reg : std_logic_vector(31 downto 0);
signal hstartl_reg : std_logic_vector(31 downto 0);
signal hstarth_reg : std_logic_vector(31 downto 0);
signal len_reg : std_logic_vector(31 downto 0);
signal nextl_reg : std_logic_vector(31 downto 0);
signal nexth_reg : std_logic_vector(31 downto 0);
signal attrib_chain_reg : std_logic;
signal attrib_dir_reg : std_logic;
signal reg_rdat_int : std_logic_vector(31 downto 0);
signal rd_ack1_int : std_logic;
begin
-- WB decode signals
wb_en <= wb_cyc_i and wb_stb_i;
process (clk_i) begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
wb_rip <= '0';
else
wb_rip <= (wb_rip or (wb_en and not wb_we_i)) and not rd_ack_int;
end if;
end if;
end process;
rd_int <= (wb_en and not wb_we_i) and not wb_rip;
process (clk_i) begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
wb_wip <= '0';
else
wb_wip <= (wb_wip or (wb_en and wb_we_i)) and not wr_ack_int;
end if;
end if;
end process;
wr_int <= (wb_en and wb_we_i) and not wb_wip;
ack_int <= rd_ack_int or wr_ack_int;
wb_ack_o <= ack_int;
wb_stall_o <= not ack_int and wb_en;
wb_rty_o <= '0';
wb_err_o <= '0';
-- Assign outputs
ctrl_byteswap_o <= ctrl_byteswap_reg;
cstart_o <= cstart_reg;
hstartl_o <= hstartl_reg;
hstarth_o <= hstarth_reg;
len_o <= len_reg;
nextl_o <= nextl_reg;
nexth_o <= nexth_reg;
attrib_chain_o <= attrib_chain_reg;
attrib_dir_o <= attrib_dir_reg;
-- Process for write requests.
process (clk_i) begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
wr_ack_int <= '0';
ctrl_wr_o <= '0';
ctrl_byteswap_reg <= "00";
stat_wr_o <= '0';
cstart_reg <= "00000000000000000000000000000000";
hstartl_reg <= "00000000000000000000000000000000";
hstarth_reg <= "00000000000000000000000000000000";
len_reg <= "00000000000000000000000000000000";
nextl_reg <= "00000000000000000000000000000000";
nexth_reg <= "00000000000000000000000000000000";
attrib_chain_reg <= '0';
attrib_dir_reg <= '0';
else
wr_ack_int <= '0';
ctrl_wr_o <= '0';
stat_wr_o <= '0';
case wb_adr_i(5 downto 2) is
when "0000" =>
-- Register ctrl
ctrl_wr_o <= wr_int;
if wr_int = '1' then
ctrl_start_o <= wb_dat_i(0);
ctrl_abort_o <= wb_dat_i(1);
ctrl_byteswap_reg <= wb_dat_i(3 downto 2);
end if;
wr_ack_int <= ctrl_wack_i;
when "0001" =>
-- Register stat
stat_wr_o <= wr_int;
if wr_int = '1' then
stat_status_o <= wb_dat_i(1 downto 0);
stat_irq_o <= wb_dat_i(2);
end if;
wr_ack_int <= stat_wack_i;
when "0010" =>
-- Register cstart
if wr_int = '1' then
cstart_reg <= wb_dat_i;
end if;
wr_ack_int <= wr_int;
when "0011" =>
-- Register hstartl
if wr_int = '1' then
hstartl_reg <= wb_dat_i;
end if;
wr_ack_int <= wr_int;
when "0100" =>
-- Register hstarth
if wr_int = '1' then
hstarth_reg <= wb_dat_i;
end if;
wr_ack_int <= wr_int;
when "0101" =>
-- Register len
if wr_int = '1' then
len_reg <= wb_dat_i;
end if;
wr_ack_int <= wr_int;
when "0110" =>
-- Register nextl
if wr_int = '1' then
nextl_reg <= wb_dat_i;
end if;
wr_ack_int <= wr_int;
when "0111" =>
-- Register nexth
if wr_int = '1' then
nexth_reg <= wb_dat_i;
end if;
wr_ack_int <= wr_int;
when "1000" =>
-- Register attrib
if wr_int = '1' then
attrib_chain_reg <= wb_dat_i(1);
attrib_dir_reg <= wb_dat_i(0);
end if;
wr_ack_int <= wr_int;
when "1001" =>
-- Register cur_cstart
when "1010" =>
-- Register cur_hstartl
when "1011" =>
-- Register cur_hstarth
when "1100" =>
-- Register cur_len
when others =>
wr_ack_int <= wr_int;
end case;
end if;
end if;
end process;
-- Process for registers read.
process (clk_i) begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
rd_ack1_int <= '0';
stat_rd_o <= '0';
else
stat_rd_o <= '0';
reg_rdat_int <= (others => '0');
case wb_adr_i(5 downto 2) is
when "0000" =>
-- ctrl
reg_rdat_int(0) <= ctrl_start_i;
reg_rdat_int(1) <= ctrl_abort_i;
reg_rdat_int(3 downto 2) <= ctrl_byteswap_reg;
rd_ack1_int <= rd_int;
when "0001" =>
-- stat
reg_rdat_int(1 downto 0) <= stat_status_i;
reg_rdat_int(2) <= stat_irq_i;
stat_rd_o <= rd_int;
rd_ack1_int <= stat_rack_i;
when "0010" =>
-- cstart
reg_rdat_int <= cstart_reg;
rd_ack1_int <= rd_int;
when "0011" =>
-- hstartl
reg_rdat_int <= hstartl_reg;
rd_ack1_int <= rd_int;
when "0100" =>
-- hstarth
reg_rdat_int <= hstarth_reg;
rd_ack1_int <= rd_int;
when "0101" =>
-- len
reg_rdat_int <= len_reg;
rd_ack1_int <= rd_int;
when "0110" =>
-- nextl
reg_rdat_int <= nextl_reg;
rd_ack1_int <= rd_int;
when "0111" =>
-- nexth
reg_rdat_int <= nexth_reg;
rd_ack1_int <= rd_int;
when "1000" =>
-- attrib
reg_rdat_int(1) <= attrib_chain_reg;
reg_rdat_int(0) <= attrib_dir_reg;
rd_ack1_int <= rd_int;
when "1001" =>
-- cur_cstart
reg_rdat_int <= cur_cstart_i;
rd_ack1_int <= rd_int;
when "1010" =>
-- cur_hstartl
reg_rdat_int <= cur_hstartl_i;
rd_ack1_int <= rd_int;
when "1011" =>
-- cur_hstarth
reg_rdat_int <= cur_hstarth_i;
rd_ack1_int <= rd_int;
when "1100" =>
-- cur_len
reg_rdat_int <= cur_len_i;
rd_ack1_int <= rd_int;
when others =>
reg_rdat_int <= (others => 'X');
rd_ack1_int <= rd_int;
end case;
end if;
end if;
end process;
-- Process for read requests.
process (wb_adr_i, reg_rdat_int, rd_ack1_int, rd_int) begin
-- By default ack read requests
wb_dat_o <= (others => '0');
case wb_adr_i(5 downto 2) is
when "0000" =>
-- ctrl
wb_dat_o <= reg_rdat_int;
rd_ack_int <= rd_ack1_int;
when "0001" =>
-- stat
wb_dat_o <= reg_rdat_int;
rd_ack_int <= rd_ack1_int;
when "0010" =>
-- cstart
wb_dat_o <= reg_rdat_int;
rd_ack_int <= rd_ack1_int;
when "0011" =>
-- hstartl
wb_dat_o <= reg_rdat_int;
rd_ack_int <= rd_ack1_int;
when "0100" =>
-- hstarth
wb_dat_o <= reg_rdat_int;
rd_ack_int <= rd_ack1_int;
when "0101" =>
-- len
wb_dat_o <= reg_rdat_int;
rd_ack_int <= rd_ack1_int;
when "0110" =>
-- nextl
wb_dat_o <= reg_rdat_int;
rd_ack_int <= rd_ack1_int;
when "0111" =>
-- nexth
wb_dat_o <= reg_rdat_int;
rd_ack_int <= rd_ack1_int;
when "1000" =>
-- attrib
wb_dat_o <= reg_rdat_int;
rd_ack_int <= rd_ack1_int;
when "1001" =>
-- cur_cstart
wb_dat_o <= reg_rdat_int;
rd_ack_int <= rd_ack1_int;
when "1010" =>
-- cur_hstartl
wb_dat_o <= reg_rdat_int;
rd_ack_int <= rd_ack1_int;
when "1011" =>
-- cur_hstarth
wb_dat_o <= reg_rdat_int;
rd_ack_int <= rd_ack1_int;
when "1100" =>
-- cur_len
wb_dat_o <= reg_rdat_int;
rd_ack_int <= rd_ack1_int;
when others =>
rd_ack_int <= rd_int;
end case;
end process;
end syn;
......@@ -86,6 +86,9 @@ architecture rtl of l2p_arbiter is
signal arb_ser_valid_t : std_logic;
signal arb_ser_dframe_t : std_logic;
signal arb_ser_data_t : std_logic_vector(31 downto 0) := (others => '0');
signal arb_ser_valid_d : std_logic;
signal arb_ser_dframe_d : std_logic;
signal arb_ser_data_d : std_logic_vector(31 downto 0) := (others => '0');
begin
......@@ -174,9 +177,12 @@ begin
arb_ser_valid_o <= '0';
arb_ser_dframe_o <= '0';
else
arb_ser_valid_o <= arb_ser_valid_t;
arb_ser_dframe_o <= arb_ser_dframe_t;
arb_ser_data_o <= arb_ser_data_t;
arb_ser_valid_d <= arb_ser_valid_t;
arb_ser_dframe_d <= arb_ser_dframe_t;
arb_ser_data_d <= arb_ser_data_t;
arb_ser_valid_o <= arb_ser_valid_d;
arb_ser_dframe_o <= arb_ser_dframe_d;
arb_ser_data_o <= arb_ser_data_d;
end if;
end if;
end process;
......
--------------------------------------------------------------------------------
-- CERN BE-CO-HT
-- GN4124 core for PCIe FMC carrier
-- http://www.ohwr.org/projects/gn4124-core
--------------------------------------------------------------------------------
--
-- unit name: l2p_dma_master
--
-- description: 32 bit L2P DMA master. Provides a pipelined wishbone interface
-- that performs DMA transfer from the local application to PCI express host.
--
--------------------------------------------------------------------------------
-- Copyright CERN 2010-2020
--------------------------------------------------------------------------------
-- Copyright and related rights are licensed under the Solderpad Hardware
-- License, Version 2.0 (the "License"); you may not use this file except
-- in compliance with the License. You may obtain a copy of the License at
-- http://solderpad.org/licenses/SHL-2.0.
-- Unless required by applicable law or agreed to in writing, software,
-- hardware and materials distributed under this License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
-- or implied. See the License for the specific language governing permissions
-- and limitations under the License.
--------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.NUMERIC_STD.all;
use work.gn4124_core_pkg.all;
use work.gencores_pkg.all;
use work.wishbone_pkg.all;
use work.genram_pkg.all;
entity l2p_dma_master is
generic (
-- It is important to set this threshold such that the FIFO has room to store
-- all pending read requests from the pipelined wishbone interface in case
-- the Gennum decides to stall and the FIFO starts filling up. The default
-- value is correct if the WB slave is the Spartan-6 DDR controller.
g_FIFO_FULL_THRES : positive := 64;
g_FIFO_SIZE : positive := 256;
g_BYTE_SWAP : boolean := FALSE);
port (
-- GN4124 core clk and reset
clk_i : in std_logic;
rst_n_i : in std_logic;
-- From the DMA controller
dma_ctrl_target_addr_i : in std_logic_vector(31 downto 0);
dma_ctrl_host_addr_h_i : in std_logic_vector(31 downto 0);
dma_ctrl_host_addr_l_i : in std_logic_vector(31 downto 0);
dma_ctrl_len_i : in std_logic_vector(31 downto 0);
dma_ctrl_start_l2p_i : in std_logic;
dma_ctrl_done_o : out std_logic;
dma_ctrl_error_o : out std_logic;
dma_ctrl_byte_swap_i : in std_logic_vector(1 downto 0);
dma_ctrl_abort_i : in std_logic;
-- To the arbiter (L2P data)
ldm_arb_valid_o : out std_logic;
ldm_arb_dframe_o : out std_logic;
ldm_arb_data_o : out std_logic_vector(31 downto 0);
ldm_arb_req_o : out std_logic;
ldm_arb_gnt_i : in std_logic;
-- L2P channel control
l2p_edb_o : out std_logic; -- Asserted when transfer is aborted
l_wr_rdy_i : in std_logic; -- Asserted when GN4124 is ready to receive master write
l2p_rdy_i : in std_logic; -- De-asserted to pause transfer already in progress
tx_error_i : in std_logic; -- Asserted when unexpected or malformed paket received
-- DMA Interface (Pipelined Wishbone Master)
wb_dma_rst_n_i : in std_logic; -- Active low reset in sync with wb_dma_clk_i
wb_dma_clk_i : in std_logic;
wb_dma_i : in t_wishbone_master_in;
wb_dma_o : out t_wishbone_master_out);
end l2p_dma_master;
architecture arch of l2p_dma_master is
-- Used to tweak the almost full flag threshold of the SYNC FIFO
-- in order to help with timing by giving an advanced warning
-- that we can then pipeline through an equal number of registers.
constant c_SYNC_FIFO_FULL_DELAY : natural := 3;
-- Even though the actual limit is 4KiB, the GN4124 really hates it
-- if we try to send more than 256 Bytes (64 Words) within a single packet.
-- During tests, we've seen that the GN4124 chip might freeze when such
-- a request arrives, with the probability of a freeze increasing with
-- the size of the packet.
-- The overhead of the extra transaction is minimal so we keep here the
-- limit that was there in previous versions of this code (128 Bytes,
-- or 32 Words).
constant c_L2P_MAX_PAYLOAD : integer := 32;
type l2p_dma_state_type is (L2P_IDLE, L2P_WB_SETUP, L2P_SETUP,
L2P_WAIT, L2P_HEADER, L2P_HOLD,
L2P_ADDR_H, L2P_ADDR_L, L2P_DATA,
L2P_ERROR);
signal l2p_dma_current_state : l2p_dma_state_type := L2P_IDLE;
type wb_dma_state_type is (WB_IDLE, WB_SETUP, WB_DATA, WB_WAIT_ACK);
signal wb_dma_current_state : wb_dma_state_type := WB_IDLE;
signal dma_target_addr : unsigned(31 downto 2) := (others => '0');
signal dma_total_len : unsigned(31 downto 2) := (others => '0');
signal dma_packet_len : unsigned(5 downto 0) := (others => '0'); -- In word
signal dma_host_addr : unsigned(63 downto 0) := (others => '0');
signal dma_byte_swap : std_logic_vector(1 downto 0) := (others => '0');
alias dma_host_addr_h : unsigned(31 downto 0) is dma_host_addr(63 downto 32);
alias dma_host_addr_l : unsigned(31 downto 0) is dma_host_addr(31 downto 0);
signal l2p_64b_address : std_logic := '0';
signal dma_size_page : unsigned(12 downto 2);
signal l2p_fsm_valid : std_logic := '0';
signal l2p_fsm_dframe : std_logic := '0';
signal l2p_fsm_data : std_logic_vector(31 downto 0) := (others => '0');
signal l2p_fsm_dma_param_wr : std_logic := '0';
signal l2p_fsm_dma_param_busy : std_logic := '0';
signal dma_param_sync : std_logic_vector(59 downto 0) := (others => '0');
signal dma_param_to_sync : std_logic_vector(59 downto 0);
signal dma_param_wr : std_logic := '0';
signal l2p_timeout_cnt : unsigned(12 downto 0) := (others => '0');
signal wb_dma_cyc : std_logic := '0';
signal wb_dma_stb : std_logic := '0';
signal wb_dma_fsm_en : std_logic := '0';
signal wb_dma_fsm_en_sync : std_logic := '0';
signal data_fifo_rd : std_logic := '0';
signal data_fifo_wr : std_logic := '0';
signal data_fifo_empty : std_logic := '1';
signal data_fifo_full : std_logic := '0';
signal data_fifo_din : std_logic_vector(31 downto 0) := (others => '0');
signal data_fifo_dout : std_logic_vector(31 downto 0) := (others => '0');
signal data_fifo_dout_d : std_logic_vector(31 downto 0) := (others => '0');
signal fsm_fifo_rst_n : std_logic := '0';
signal data_fifo_full_d : std_logic_vector(c_SYNC_FIFO_FULL_DELAY - 1 downto 0) := (others => '0');
signal data_fifo_full_next : std_logic;
signal data_fifo_rst_wr_n : std_logic;
signal data_fifo_rst_rd_n : std_logic;
begin
-- 64bit address flag used to generate the L2P header and as an input to
-- the L2P FSM to control the transition through the L2P_ADDR states.
l2p_64b_address <= '0' when dma_host_addr_h = x"00000000" else '1';
---------------------------------------
-- L2P FSM (in the Gennum clock domain)
---------------------------------------
p_l2p_fsm : process (clk_i)
begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
l2p_dma_current_state <= L2P_IDLE;
ldm_arb_req_o <= '0';
l2p_fsm_valid <= '0';
l2p_fsm_dframe <= '0';
dma_ctrl_done_o <= '0';
dma_ctrl_error_o <= '0';
wb_dma_fsm_en <= '0';
l2p_edb_o <= '0';
fsm_fifo_rst_n <= '0';
data_fifo_rd <= '0';
l2p_fsm_dma_param_wr <= '0';
else
data_fifo_dout_d <= data_fifo_dout;
-- default values if not overriden by current state
ldm_arb_req_o <= '0';
l2p_fsm_valid <= '0';
l2p_fsm_dframe <= '0';
l2p_fsm_dma_param_wr <= l2p_fsm_dma_param_busy;
dma_ctrl_done_o <= '0';
dma_ctrl_error_o <= '0';
l2p_edb_o <= '0';
fsm_fifo_rst_n <= '1';
data_fifo_rd <= '0';
wb_dma_fsm_en <= '1';
l2p_timeout_cnt <= (others => '0');
case l2p_dma_current_state is
when L2P_IDLE =>
wb_dma_fsm_en <= '0';
fsm_fifo_rst_n <= '0';
if dma_ctrl_start_l2p_i = '1' then
dma_target_addr <= unsigned(dma_ctrl_target_addr_i(31 downto 2));
dma_host_addr_h <= unsigned(dma_ctrl_host_addr_h_i);
dma_host_addr_l <= unsigned(dma_ctrl_host_addr_l_i);
dma_total_len <= unsigned(dma_ctrl_len_i(31 downto 2));
dma_byte_swap <= dma_ctrl_byte_swap_i;
l2p_dma_current_state <= L2P_WB_SETUP;
end if;
when L2P_WB_SETUP =>
-- Start to fill the data fifo (from DDR). Need to cross clock domain.
l2p_fsm_dma_param_wr <= '1';
if l2p_fsm_dma_param_busy = '1' then
l2p_dma_current_state <= L2P_SETUP;
end if;
when L2P_SETUP =>
-- Calculate DMA packet length for next tranfer. A transfer can be
-- up to 1024 words, limited by the "length" field in the L2P header.
-- We limit it artificially to c_L2P_MAX_PAYLOAD (see note in
-- constant declaration).
if dma_total_len > c_L2P_MAX_PAYLOAD then
dma_packet_len <= to_unsigned(c_L2P_MAX_PAYLOAD, dma_packet_len'length);
else
dma_packet_len <= dma_total_len(7 downto 2);
end if;
-- Compute the number of word remaining in the current host page.
dma_size_page <= ('0' & not dma_host_addr(11 downto 2)) + 1;
l2p_dma_current_state <= L2P_WAIT;
when L2P_WAIT =>
-- A PCI transfer cannot cross a 4-KB boundary
-- (See PCI Express Base Specification Revision 5.0 version 1.0 p 128)
if dma_packet_len > dma_size_page then
dma_packet_len <= dma_size_page(7 downto 2);
end if;
-- Send request to DMA arbiter
ldm_arb_req_o <= not ldm_arb_gnt_i;
-- Move to next state when:
-- a) granted DMA access by arbiter
-- b) there is data waiting in the FIFO
-- c) Gennum is ready
if ldm_arb_gnt_i = '1' and data_fifo_empty = '0' and
l_wr_rdy_i = '1' and l2p_rdy_i = '1'
then
l2p_dma_current_state <= L2P_HEADER;
end if;
-- Note: we don't check l2p_rdy_i again until we reach the L2P_DATA state.
-- That's ok, according to Gennum, we have up to 7 clock cycles to
-- drop ldm_arb_valid after the Gennum drops l2p_rdy.
when L2P_HEADER =>
-- Must keep dframe asserted to stay bus master until end of transfer
l2p_fsm_dframe <= '1';
l2p_fsm_valid <= '1';
l2p_fsm_data <= (others => '0');
-- Header type
l2p_fsm_data(25) <= '1';
l2p_fsm_data(24) <= l2p_64b_address;
-- LBE (Last Byte Enable) must be "0000" only
-- when the length field is equal to 1
if dma_packet_len /= 1 then
l2p_fsm_data(23 downto 20) <= "1111";
end if;
-- FBE (First Byte Enable)
l2p_fsm_data(19 downto 16) <= "1111";
-- Length field (in 32 bit words). When zero it means 1024 words.
l2p_fsm_data(9 downto 0) <= "0000" & std_logic_vector(dma_packet_len);
if l2p_64b_address = '1' then
l2p_dma_current_state <= L2P_ADDR_H;
else
l2p_dma_current_state <= L2P_ADDR_L;
end if;
when L2P_ADDR_H =>
l2p_fsm_dframe <= '1';
l2p_fsm_valid <= '1';
l2p_fsm_data <= std_logic_vector(dma_host_addr_h);
l2p_dma_current_state <= L2P_ADDR_L;
when L2P_ADDR_L =>
l2p_fsm_dframe <= '1';
l2p_fsm_valid <= '1';
l2p_fsm_data <= std_logic_vector(dma_host_addr_l);
-- Already checked data_fifo_empty flag during L2P_WAIT.
-- Start readout here to get first data out on the next cycle.
data_fifo_rd <= '1';
-- Update host address (for the next transfer)
dma_host_addr <= dma_host_addr + 4*dma_packet_len;
dma_total_len <= dma_total_len - dma_packet_len;
l2p_dma_current_state <= L2P_DATA;
when L2P_DATA =>
l2p_fsm_dframe <= '1';
-- Data FIFO readout
if data_fifo_empty = '1' or l2p_rdy_i = '0' then
-- Not ready - wait
l2p_dma_current_state <= L2P_HOLD;
else
data_fifo_rd <= '1';
l2p_fsm_valid <= '1';
l2p_fsm_data <= f_byte_swap(g_BYTE_SWAP, data_fifo_dout, dma_byte_swap);
dma_packet_len <= dma_packet_len - 1;
-- Detect end of transfer
if dma_packet_len = 1 then
l2p_fsm_dframe <= '0';
data_fifo_rd <= '0';
if dma_total_len /= 0 then
-- There a still data to transfer, continue.
l2p_dma_current_state <= L2P_SETUP;
else
-- No more data, done.
l2p_dma_current_state <= L2P_IDLE;
dma_ctrl_done_o <= '1';
end if;
end if;
end if;
-- Timeout counter, it is reset to 0 by default FSM value
-- if not increased here.
if l2p_rdy_i = '1' then
l2p_timeout_cnt <= l2p_timeout_cnt + 1;
end if;
-- Check for errors
if tx_error_i = '1' or dma_ctrl_abort_i = '1' or l2p_timeout_cnt = x"fff" then
l2p_fsm_dframe <= '0';
l2p_dma_current_state <= L2P_ERROR;
end if;
when L2P_HOLD =>
l2p_fsm_dframe <= '1';
l2p_fsm_valid <= '0';
if data_fifo_empty = '0' and l2p_rdy_i = '1' then
data_fifo_rd <= '1';
l2p_dma_current_state <= L2P_DATA;
end if;
when L2P_ERROR =>
wb_dma_fsm_en <= '0';
fsm_fifo_rst_n <= '0';
dma_ctrl_error_o <= '1';
l2p_edb_o <= '1';
l2p_dma_current_state <= L2P_IDLE;
when others =>
l2p_dma_current_state <= L2P_ERROR;
end case;
end if;
end if;
end process p_l2p_fsm;
ldm_arb_valid_o <= l2p_fsm_valid;
ldm_arb_dframe_o <= l2p_fsm_dframe;
ldm_arb_data_o <= l2p_fsm_data;
-------------------------------------------------
-- Wishbone Master (in the Wishbone clock domain)
-------------------------------------------------
-- Info crossing clocks domains (GN -> DDR) at the start of a dma transfer.
dma_param_to_sync(59 downto 30) <= std_logic_vector(dma_target_addr);
dma_param_to_sync(29 downto 0) <= std_logic_vector(dma_total_len);
cmp_sync_dma_param : entity work.gc_sync_word_wr
generic map (
g_AUTO_WR => FALSE,
g_WIDTH => 60)
port map (
clk_in_i => clk_i,
rst_in_n_i => '1',
clk_out_i => wb_dma_clk_i,
rst_out_n_i => '1',
data_i => dma_param_to_sync,
wr_i => l2p_fsm_dma_param_wr,
busy_o => l2p_fsm_dma_param_busy,
ack_o => open,
data_o => dma_param_sync,
wr_o => dma_param_wr);
cmp_wb_dma_fsm_en_sync : gc_sync
port map (
clk_i => wb_dma_clk_i,
rst_n_a_i => '1',
d_i => wb_dma_fsm_en,
q_o => wb_dma_fsm_en_sync);
wb_dma_o.cyc <= wb_dma_cyc;
wb_dma_o.stb <= wb_dma_stb;
wb_dma_o.we <= '0';
wb_dma_o.sel <= (others => '1');
wb_dma_o.dat <= (others => '0');
-- No need to check FIFO full, it was done earlier
-- when we decided to strobe (in combination with a proper
-- almost_full flag from the FIFO).
data_fifo_din <= wb_dma_i.dat;
data_fifo_wr <= wb_dma_i.ack;
p_wb_fsm : process (wb_dma_clk_i)
variable wb_dma_addr : unsigned(29 downto 0) := (others => '0');
variable wb_dma_cnt_stb : unsigned(29 downto 0) := (others => '0');
variable wb_dma_cnt_ack : unsigned(29 downto 0) := (others => '0');
begin
if rising_edge(wb_dma_clk_i) then
if wb_dma_rst_n_i = '0' or wb_dma_fsm_en_sync = '0' then
wb_dma_cyc <= '0';
wb_dma_stb <= '0';
wb_dma_addr := (others => '0');
wb_dma_o.adr <= (others => '0');
wb_dma_current_state <= WB_IDLE;
else
case wb_dma_current_state is
when WB_IDLE =>
-- Start when the new DMA parameters (address, size) have been received
if dma_param_wr = '1' then
wb_dma_addr := unsigned(dma_param_sync(59 downto 30));
wb_dma_cnt_stb := unsigned(dma_param_sync(29 downto 0));
wb_dma_cnt_ack := unsigned(dma_param_sync(29 downto 0));
wb_dma_current_state <= WB_SETUP;
end if;
when WB_SETUP =>
-- Start/maintain the WB cycle
wb_dma_cyc <= '1';
-- Always keep track of pending ACKs
if wb_dma_i.ack = '1' then
wb_dma_cnt_ack := wb_dma_cnt_ack - 1;
end if;
-- If there is space in the FIFO, send the first/next read request
if data_fifo_full = '0' then
wb_dma_o.adr <= "00" & std_logic_vector(wb_dma_addr);
wb_dma_stb <= '1';
wb_dma_current_state <= WB_DATA;
end if;
when WB_DATA =>
-- Maintain the WB cycle
wb_dma_cyc <= '1';
-- Always keep track of pending ACKs
if wb_dma_i.ack = '1' then
wb_dma_cnt_ack := wb_dma_cnt_ack - 1;
end if;
-- If the slave was not stalling on the previous cycle,
-- update address and counters
if wb_dma_i.stall = '0' then
wb_dma_addr := wb_dma_addr + 1;
wb_dma_cnt_stb := wb_dma_cnt_stb - 1;
-- If all read requests have been issued, move to next state
if wb_dma_cnt_stb = 0 then
wb_dma_stb <= '0';
wb_dma_current_state <= WB_WAIT_ACK;
-- If there is no room in the FIFO, drop strobe and wait
elsif data_fifo_full = '1' then
wb_dma_stb <= '0';
wb_dma_current_state <= WB_SETUP;
-- Otherwise send the next request
else
wb_dma_o.adr <= "00" & std_logic_vector(wb_dma_addr);
wb_dma_stb <= '1';
end if;
end if;
when WB_WAIT_ACK =>
-- Maintain the WB cycle
wb_dma_cyc <= '1';
-- Always keep track of pending ACKs
if wb_dma_i.ack = '1' then
wb_dma_cnt_ack := wb_dma_cnt_ack - 1;
end if;
-- If all ACKs have been received, we are done
if wb_dma_cnt_ack = 0 then
wb_dma_cyc <= '0';
wb_dma_current_state <= WB_IDLE;
end if;
when others =>
wb_dma_current_state <= WB_IDLE;
end case;
end if;
end if;
end process p_wb_fsm;
-----------------------------------------
-- Flow Control FIFO (cross-clock domain)
-----------------------------------------
cmp_data_fifo_rst_rd_n_sync : gc_sync
port map (
clk_i => clk_i,
rst_n_a_i => fsm_fifo_rst_n,
d_i => wb_dma_rst_n_i,
q_o => data_fifo_rst_rd_n);
cmp_data_fifo_rst_wr_n_sync : gc_sync
port map (
clk_i => wb_dma_clk_i,
rst_n_a_i => wb_dma_rst_n_i,
d_i => fsm_fifo_rst_n,
q_o => data_fifo_rst_wr_n);
p_fifo_full_delay_reg : process (wb_dma_clk_i) is
begin
if rising_edge(wb_dma_clk_i) then
-- we want proper registers to help with timing and
-- having a reset prevents inferring of shift register.
if data_fifo_rst_wr_n = '0' then
data_fifo_full_d <= (others => '0');
else
data_fifo_full_d <= data_fifo_full_d(data_fifo_full_d'high-1 downto 0) & data_fifo_full_next;
end if;
end if;
end process p_fifo_full_delay_reg;
data_fifo_full <= data_fifo_full_d(data_fifo_full_d'high);
cmp_data_fifo : generic_async_fifo_dual_rst
generic map (
g_DATA_WIDTH => 32,
g_SIZE => g_FIFO_SIZE,
g_SHOW_AHEAD => TRUE,
g_WITH_WR_FULL => FALSE,
g_WITH_WR_ALMOST_FULL => TRUE,
g_ALMOST_FULL_THRESHOLD => g_FIFO_FULL_THRES - c_SYNC_FIFO_FULL_DELAY)
port map (
-- write port
rst_wr_n_i => data_fifo_rst_wr_n,
clk_wr_i => wb_dma_clk_i,
d_i => data_fifo_din,
we_i => data_fifo_wr,
wr_almost_full_o => data_fifo_full_next,
-- read port
rst_rd_n_i => data_fifo_rst_rd_n,
clk_rd_i => clk_i,
q_o => data_fifo_dout,
rd_i => data_fifo_rd,
rd_empty_o => data_fifo_empty);
end architecture arch;
......@@ -95,7 +95,6 @@ architecture rtl of p2l_decode32 is
signal des_p2l_dframe_d : std_logic := '0';
signal p2l_packet_start : std_logic;
signal p2l_packet_start_d : std_logic;
signal p2l_packet_end : std_logic;
signal p2l_addr_cycle : std_logic;
......@@ -113,7 +112,6 @@ architecture rtl of p2l_decode32 is
signal p2l_addr : unsigned(31 downto 0) := (others => '0'); -- Registered and counting Address
signal p2l_d_valid : std_logic; -- Indicates Address/Data is valid
signal p2l_d_first : std_logic;
signal p2l_d_last : std_logic; -- Indicates end of the packet
signal p2l_d : std_logic_vector(31 downto 0) := (others => '0'); -- Address/Data
signal p2l_be : std_logic_vector(3 downto 0) := (others => '0'); -- Byte Enable for data
......
......@@ -7,11 +7,18 @@
-- unit name: p2l_dma_master
--
-- description: 32 bit P2L DMA master. Provides a pipelined Wishbone interface
-- to performs DMA transfers from PCI express host to local application.
-- that performs DMA transfers from PCI express host to local application.
-- This entity is also used to catch the next item in chained DMA.
--
-- IMPORTANT NOTE: This module has a known bug, where the FSM will consider a
-- transfer complete and signal the "done" to the DMA controller module without
-- waiting for the WB side to write all data. This can be a problem, especially
-- when the WB side is slower and the next DMA transaction is a read which will
-- switch the WB signals to the L2P module, thus cutting the previous WB write
-- transfer from this module in the middle.
--
--------------------------------------------------------------------------------
-- Copyright CERN 2010-2018
-- Copyright CERN 2010-2020
--------------------------------------------------------------------------------
-- Copyright and related rights are licensed under the Solderpad Hardware
-- License, Version 2.0 (the "License"); you may not use this file except
......@@ -27,17 +34,17 @@
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.NUMERIC_STD.all;
use work.gn4124_core_pkg.all;
use work.gencores_pkg.all;
use work.wishbone_pkg.all;
use work.genram_pkg.all;
entity p2l_dma_master is
generic (
-- Enable byte swap module (if false, no swap)
g_BYTE_SWAP : boolean := false
);
port
(
g_FIFO_SIZE : positive := 64;
g_BYTE_SWAP : boolean := FALSE);
port (
---------------------------------------------------------
-- GN4124 core clock and reset
clk_i : in std_logic;
......@@ -86,19 +93,11 @@ entity p2l_dma_master is
arb_pdm_gnt_i : in std_logic;
---------------------------------------------------------
-- DMA Interface (Pipelined Wishbone)
p2l_dma_rst_n_i : in std_logic; -- Active low reset in sync with p2l_dma_clk_i
p2l_dma_clk_i : in std_logic; -- Bus clock
p2l_dma_adr_o : out std_logic_vector(31 downto 0); -- Adress
p2l_dma_dat_i : in std_logic_vector(31 downto 0); -- Data in
p2l_dma_dat_o : out std_logic_vector(31 downto 0); -- Data out
p2l_dma_sel_o : out std_logic_vector(3 downto 0); -- Byte select
p2l_dma_cyc_o : out std_logic; -- Read or write cycle
p2l_dma_stb_o : out std_logic; -- Read or write strobe
p2l_dma_we_o : out std_logic; -- Write
p2l_dma_ack_i : in std_logic; -- Acknowledge
p2l_dma_stall_i : in std_logic; -- for pipelined Wishbone
l2p_dma_cyc_i : in std_logic; -- L2P dma wb cycle (for bus arbitration)
-- DMA Interface (Pipelined Wishbone Master)
wb_dma_rst_n_i : in std_logic; -- Active low reset in sync with wb_dma_clk_i
wb_dma_clk_i : in std_logic; -- Bus clock
wb_dma_i : in t_wishbone_master_in;
wb_dma_o : out t_wishbone_master_out;
---------------------------------------------------------
-- To the DMA controller
......@@ -114,17 +113,21 @@ entity p2l_dma_master is
end p2l_dma_master;
architecture behaviour of p2l_dma_master is
architecture arch of p2l_dma_master is
-----------------------------------------------------------------------------
-- Constants declaration
-----------------------------------------------------------------------------
-- Used to tweak the almost full flag threshold of the SYNC FIFO
-- in order to help with timing by giving an advanced warning
-- that we can then pipeline through an equal number of registers.
constant c_SYNC_FIFO_FULL_DELAY : natural := 3;
-- c_MAX_READ_REQ_SIZE is the maximum size (in 32-bit words) of the payload of a packet.
-- Allowed c_MAX_READ_REQ_SIZE values are: 32, 64, 128, 256, 512, 1024.
-- This constant must be set according to the GN4124 and motherboard chipset capabilities.
constant c_MAX_READ_REQ_SIZE : unsigned(10 downto 0) := to_unsigned(1024, 11);
constant c_TO_WB_FIFO_FULL_THRES : integer := 500;
-----------------------------------------------------------------------------
-- Signals declaration
......@@ -134,7 +137,6 @@ architecture behaviour of p2l_dma_master is
signal is_next_item : std_logic;
signal completion_error : std_logic;
signal dma_busy_error : std_logic;
signal dma_length_error : std_logic;
signal dma_ctrl_done_t : std_logic := '0';
signal rx_error_t : std_logic := '0';
signal rx_error_d : std_logic := '0';
......@@ -143,11 +145,8 @@ architecture behaviour of p2l_dma_master is
signal l2p_address_h : std_logic_vector(31 downto 0) := (others => '0');
signal l2p_address_l : std_logic_vector(31 downto 0) := (others => '0');
signal l2p_len_cnt : unsigned(29 downto 0) := (others => '0');
signal l2p_len_header : unsigned(9 downto 0) := (others => '0');
signal l2p_len_header : unsigned(10 downto 0);
signal l2p_64b_address : std_logic;
signal s_l2p_header : std_logic_vector(31 downto 0);
signal l2p_last_packet : std_logic;
signal l2p_lbe_header : std_logic_vector(3 downto 0);
signal pdm_arb_data : std_logic_vector(31 downto 0) := (others => '0');
......@@ -166,21 +165,15 @@ architecture behaviour of p2l_dma_master is
signal to_wb_fifo_din : std_logic_vector(63 downto 0) := (others => '0');
signal to_wb_fifo_din_d : std_logic_vector(63 downto 0) := (others => '0');
signal to_wb_fifo_dout : std_logic_vector(63 downto 0);
signal to_wb_fifo_valid : std_logic;
signal to_wb_fifo_byte_swap : std_logic_vector(1 downto 0) := (others => '0');
-- wishbone
signal wb_write_cnt : unsigned(31 downto 0);
signal wb_ack_cnt : unsigned(31 downto 0);
signal p2l_dma_cyc_t : std_logic;
signal p2l_dma_stb_t : std_logic;
signal p2l_dma_stall_d : std_logic_vector(1 downto 0) := (others => '0');
signal p2l_dma_sel_t : std_logic_vector(3 downto 0) := (others => '0');
signal p2l_dma_adr_t : std_logic_vector(31 downto 0) := (others => '0');
signal p2l_dma_dat_t : std_logic_vector(31 downto 0) := (others => '0');
signal wb_ack_cnt : unsigned(15 downto 0);
signal wb_dma_out_stb : std_logic;
signal wb_dma_tfr : boolean;
-- P2L DMA read request FSM
type p2l_dma_state_type is (P2L_IDLE, P2L_HEADER, P2L_ADDR_H, P2L_ADDR_L, P2L_WAIT_READ_COMPLETION);
type p2l_dma_state_type is (P2L_IDLE, P2L_SETUP, P2L_HEADER, P2L_ADDR_H, P2L_ADDR_L, P2L_WAIT_READ_COMPLETION);
signal p2l_dma_current_state : p2l_dma_state_type;
signal p2l_data_cnt : unsigned(10 downto 0) := (others => '0');
......@@ -192,106 +185,22 @@ architecture behaviour of p2l_dma_master is
signal next_item_next_h : std_logic_vector(31 downto 0) := (others => '0');
signal next_item_attrib : std_logic_vector(31 downto 0) := (others => '0');
begin
------------------------------------------------------------------------------
-- Active low reset for fifos
------------------------------------------------------------------------------
fifo_rst_n <= rst_n_i;
-- Local resynced copy of fifo_rst_n to make sure that both sides of the fifo
-- are reset if rst_n_i = '0'
cmp_wb_fifo_rst_sync: gc_sync_ffs
port map (
clk_i => p2l_dma_clk_i,
rst_n_i => p2l_dma_rst_n_i,
data_i => fifo_rst_n,
synced_o => wb_fifo_rst_n);
signal to_wb_fifo_full_d : std_logic_vector(c_SYNC_FIFO_FULL_DELAY - 1 downto 0) := (others => '0');
signal to_wb_fifo_full_next : std_logic;
begin
-- Errors to DMA controller
dma_ctrl_error_o <= dma_busy_error or completion_error;
------------------------------------------------------------------------------
-- PCIe read request
------------------------------------------------------------------------------
-- Stores information for read request packet
-- Can be a P2L DMA transfer or catching the next item of a chained DMA
p_read_req : process (clk_i)
begin
if rising_edge(clk_i) then
if (rst_n_i = '0') then
l2p_64b_address <= '0';
is_next_item <= '0';
l2p_last_packet <= '0';
else
if (p2l_dma_current_state = P2L_IDLE) then
if (dma_ctrl_start_p2l_i = '1' or dma_ctrl_start_next_i = '1') then
-- Stores DMA info locally
l2p_address_h <= dma_ctrl_host_addr_h_i;
l2p_address_l <= dma_ctrl_host_addr_l_i;
l2p_len_cnt <= unsigned(dma_ctrl_len_i(31 downto 2)); -- dma_ctrl_len_i is in byte
if (dma_ctrl_start_next_i = '1') then
-- Catching next DMA item
is_next_item <= '1'; -- flag for data retrieve block
else
-- P2L DMA transfer
is_next_item <= '0';
end if;
if (dma_ctrl_host_addr_h_i = X"00000000") then
l2p_64b_address <= '0';
else
l2p_64b_address <= '1';
end if;
end if;
elsif (p2l_dma_current_state = P2L_HEADER) then
-- if DMA length is bigger than the max PCIe payload size,
-- we have to generate several read request
if (l2p_len_cnt > c_MAX_READ_REQ_SIZE) then
-- when max payload length is 1024, the header length field = 0
l2p_len_header <= c_MAX_READ_REQ_SIZE(9 downto 0);
l2p_last_packet <= '0';
elsif (l2p_len_cnt = c_MAX_READ_REQ_SIZE) then
-- when max payload length is 1024, the header length field = 0
l2p_len_header <= c_MAX_READ_REQ_SIZE(9 downto 0);
l2p_last_packet <= '1';
else
l2p_len_header <= l2p_len_cnt(9 downto 0);
l2p_last_packet <= '1';
end if;
elsif (p2l_dma_current_state = P2L_ADDR_L) then
-- Subtract the number of word requested to generate a new read request if needed
if (l2p_last_packet = '0') then
l2p_len_cnt <= l2p_len_cnt - c_MAX_READ_REQ_SIZE;
else
l2p_len_cnt <= (others => '0');
end if;
end if;
end if;
end if;
end process p_read_req;
-- Last Byte Enable must be "0000" when length = 1
l2p_lbe_header <= "0000" when l2p_len_header = 1 else "1111";
s_l2p_header <= "000" --> Traffic Class
& '0' --> Snoop
& "000" & l2p_64b_address --> Packet type = read request (32 or 64 bits)
& l2p_lbe_header --> LBE (Last Byte Enable)
& "1111" --> FBE (First Byte Enable)
& "000" --> Reserved
& '0' --> VC (Virtual Channel)
& "01" --> CID
& std_logic_vector(l2p_len_header); --> Length (in 32-bit words)
-- 0x000 => 1024 words (4096 bytes)
-----------------------------------------------------------------------------
-- PCIe read request FSM
-----------------------------------------------------------------------------
-- Stores information for read request packet
-- Can be a P2L DMA transfer or catching the next item of a chained DMA
p_read_req_fsm : process (clk_i)
begin
if rising_edge(clk_i) then
if(rst_n_i = '0') then
if rst_n_i = '0' then
p2l_dma_current_state <= P2L_IDLE;
pdm_arb_req_o <= '0';
pdm_arb_valid_o <= '0';
......@@ -300,6 +209,8 @@ begin
next_item_valid_o <= '0';
completion_error <= '0';
rx_error_t <= '0';
l2p_64b_address <= '0';
is_next_item <= '0';
else
case p2l_dma_current_state is
......@@ -311,23 +222,58 @@ begin
rx_error_t <= '0';
-- Start a read request when a P2L DMA is initated or when the DMA
-- controller asks for the next DMA info (in a chained DMA).
if (dma_ctrl_start_p2l_i = '1' or dma_ctrl_start_next_i = '1') then
-- request access to PCIe bus
pdm_arb_req_o <= '1';
if dma_ctrl_start_p2l_i = '1' or dma_ctrl_start_next_i = '1' then
-- Stores DMA info locally
l2p_address_h <= dma_ctrl_host_addr_h_i;
l2p_address_l <= dma_ctrl_host_addr_l_i;
l2p_len_cnt <= unsigned(dma_ctrl_len_i(31 downto 2)); -- dma_ctrl_len_i is in byte
-- Catching whether this is a P2L DMA transfer or just a fetch of the next DMA item
is_next_item <= dma_ctrl_start_next_i;
if dma_ctrl_host_addr_h_i = X"00000000" then
l2p_64b_address <= '0';
else
l2p_64b_address <= '1';
end if;
-- prepare a packet, first the header
p2l_dma_current_state <= P2L_HEADER;
p2l_dma_current_state <= P2L_SETUP;
end if;
when P2L_SETUP =>
-- if DMA length is bigger than the max PCIe payload size,
-- we have to generate several read request
if l2p_len_cnt > c_MAX_READ_REQ_SIZE then
-- when max payload length is 1024, the header length field = 0
l2p_len_header <= c_MAX_READ_REQ_SIZE;
else
l2p_len_header <= l2p_len_cnt(10 downto 0);
end if;
-- request access to PCIe bus
pdm_arb_req_o <= '1';
p2l_dma_current_state <= P2L_HEADER;
when P2L_HEADER =>
if(arb_pdm_gnt_i = '1') then
if arb_pdm_gnt_i = '1' then
-- clear access request to the arbiter
-- access is granted until dframe is cleared
pdm_arb_req_o <= '0';
-- send header
pdm_arb_data <= s_l2p_header;
pdm_arb_data(31 downto 29) <= "000"; --> Traffic Class
pdm_arb_data(28) <= '0'; --> Snoop
pdm_arb_data(27 downto 24) <= "000" & l2p_64b_address; --> Packet type = read req (32 or 64)
if l2p_len_header = 1 then
-- Last Byte Enable must be "0000" when length = 1
pdm_arb_data(23 downto 20) <= "0000"; --> LBE (Last Byte Enable)
else
pdm_arb_data(23 downto 20) <= "1111"; --> LBE (Last Byte Enable)
end if;
pdm_arb_data(19 downto 16) <= "1111"; --> FBE (First Byte Enable)
pdm_arb_data(15 downto 13) <= "111"; --> Reserved
pdm_arb_data(12) <= '0'; --> VC (Virtual Channel)
pdm_arb_data(11 downto 10) <= "01"; --> CID
pdm_arb_data(9 downto 0) <= std_logic_vector(l2p_len_header (9 downto 0)); --> Length (in words)
pdm_arb_valid_o <= '1';
pdm_arb_dframe_o <= '1';
if(l2p_64b_address = '1') then
if l2p_64b_address = '1' then
-- if host address is 64-bit, we have to send an additionnal
-- 32-word containing highest bits of the host address
p2l_dma_current_state <= P2L_ADDR_H;
......@@ -347,39 +293,46 @@ begin
pdm_arb_data <= l2p_address_l;
-- clear dframe signal to indicate the end of packet
pdm_arb_dframe_o <= '0';
-- Subtract the number of word requested to generate a new read request if needed
l2p_len_cnt <= l2p_len_cnt - l2p_len_header;
l2p_address_l <= std_logic_vector(unsigned(l2p_address_l) + 4*l2p_len_header);
p2l_dma_current_state <= P2L_WAIT_READ_COMPLETION;
when P2L_WAIT_READ_COMPLETION =>
-- End of the read request packet
pdm_arb_valid_o <= '0';
if (dma_ctrl_abort_i = '1') then
if pd_pdm_data_valid_i = '1' and pd_pdm_master_cpld_i = '1' then
-- Received a word.
l2p_len_header <= l2p_len_header - 1;
end if;
if dma_ctrl_abort_i = '1' then
rx_error_t <= '1';
p2l_dma_current_state <= P2L_IDLE;
elsif (pd_pdm_master_cpld_i = '1' and pd_pdm_data_last_i = '1'
and p2l_data_cnt <= 1) then
elsif pd_pdm_master_cpld_i = '1' and pd_pdm_data_last_i = '1'
and l2p_len_header = 1
then
-- Note: a read request may result in multiple read completion.
-- last word of read completion has been received
if (l2p_last_packet = '0') then
if l2p_len_cnt /= 0 then
-- A new read request is needed, DMA size > max payload
p2l_dma_current_state <= P2L_HEADER;
-- As the end of packet is used to delimit arbitration phases
-- we have to ask again for permission
pdm_arb_req_o <= '1';
p2l_dma_current_state <= P2L_SETUP;
else
-- indicate end of DMA transfer
if (is_next_item = '1') then
if is_next_item = '1' then
next_item_valid_o <= '1';
else
dma_ctrl_done_t <= '1';
end if;
p2l_dma_current_state <= P2L_IDLE;
end if;
elsif (pd_pdm_master_cpln_i = '1') then
elsif pd_pdm_master_cpln_i = '1' then
-- should not return a read completion without data
completion_error <= '1';
p2l_dma_current_state <= P2L_IDLE;
end if;
when others =>
p2l_dma_current_state <= P2L_IDLE;
pdm_arb_req_o <= '0';
......@@ -410,32 +363,19 @@ begin
end if;
end process p_ctrl_pipe;
-- NOTE: this pipeline was here before the reset and resync rehaul,
-- however it was clocked by the wrong clock (clk_i).
p_dma_stall_d2 : process (p2l_dma_clk_i)
begin
if rising_edge(p2l_dma_clk_i) then
p2l_dma_stall_d(0) <= p2l_dma_stall_i;
p2l_dma_stall_d(1) <= p2l_dma_stall_d(0);
end if;
end process p_dma_stall_d2;
------------------------------------------------------------------------------
-- Received data counter
------------------------------------------------------------------------------
p_recv_data_cnt : process (clk_i)
begin
if rising_edge(clk_i) then
if (p2l_dma_current_state = P2L_ADDR_L) then
if p2l_dma_current_state = P2L_ADDR_L then
-- Store number of 32-bit data words to be received for the current read request
if l2p_len_header = 0 then
p2l_data_cnt <= to_unsigned(1024, p2l_data_cnt'length);
else
p2l_data_cnt <= '0' & l2p_len_header;
end if;
elsif (p2l_dma_current_state = P2L_WAIT_READ_COMPLETION
and pd_pdm_data_valid_i = '1'
and pd_pdm_master_cpld_i = '1') then
p2l_data_cnt <= l2p_len_header;
elsif p2l_dma_current_state = P2L_WAIT_READ_COMPLETION
and pd_pdm_data_valid_i = '1'
and pd_pdm_master_cpld_i = '1'
then
-- decrement number of data to be received
p2l_data_cnt <= p2l_data_cnt - 1;
end if;
......@@ -448,9 +388,10 @@ begin
p_next_item : process (clk_i)
begin
if rising_edge(clk_i) then
if (p2l_dma_current_state = P2L_WAIT_READ_COMPLETION
and is_next_item = '1' and pd_pdm_data_valid_i = '1') then
-- next item data are supposed to be received in the right order !!
if p2l_dma_current_state = P2L_WAIT_READ_COMPLETION
and is_next_item = '1' and pd_pdm_data_valid_i = '1'
then
-- next item data are supposed to be received in the right order !!
case p2l_data_cnt(2 downto 0) is
when "111" =>
next_item_carrier_addr <= pd_pdm_data_i;
......@@ -487,7 +428,7 @@ begin
p_addr_cnt : process (clk_i)
begin
if rising_edge(clk_i) then
if (rst_n_i = '0') then
if rst_n_i = '0' then
dma_busy_error <= '0';
to_wb_fifo_wr <= '0';
to_wb_fifo_wr_d <= '0';
......@@ -495,8 +436,8 @@ begin
to_wb_fifo_din_d <= to_wb_fifo_din;
to_wb_fifo_wr_d <= to_wb_fifo_wr;
if (dma_ctrl_start_p2l_i = '1') then
if (p2l_dma_current_state = P2L_IDLE) then
if dma_ctrl_start_p2l_i = '1' then
if p2l_dma_current_state = P2L_IDLE then
-- dma_ctrl_target_addr_i is a byte address and target_addr_cnt is a
-- 32-bit word address
target_addr_cnt <= unsigned(dma_ctrl_carrier_addr_i(31 downto 2));
......@@ -505,14 +446,15 @@ begin
else
dma_busy_error <= '1';
end if;
elsif (p2l_dma_current_state = P2L_WAIT_READ_COMPLETION
and is_next_item = '0' and pd_pdm_data_valid_i = '1') then
-- increment target address counter
target_addr_cnt <= target_addr_cnt + 1;
elsif p2l_dma_current_state = P2L_WAIT_READ_COMPLETION
and is_next_item = '0' and pd_pdm_data_valid_i = '1'
then
-- write target address and data to the sync fifo
to_wb_fifo_wr <= '1';
to_wb_fifo_din(31 downto 0) <= f_byte_swap(g_BYTE_SWAP, pd_pdm_data_i, to_wb_fifo_byte_swap);
to_wb_fifo_din(61 downto 32) <= std_logic_vector(target_addr_cnt);
-- increment target address counter
target_addr_cnt <= target_addr_cnt + 1;
else
dma_busy_error <= '0';
to_wb_fifo_wr <= '0';
......@@ -522,51 +464,61 @@ begin
end process p_addr_cnt;
------------------------------------------------------------------------------
-- FIFOs for transition between GN4124 core and wishbone clock domain
-- FIFO for transition between GN4124 core and wishbone clock domain
------------------------------------------------------------------------------
cmp_to_wb_fifo : generic_async_fifo_dual_rst
generic map (
g_data_width => 64,
g_size => 512,
g_show_ahead => false,
g_with_rd_empty => true,
g_with_rd_full => false,
g_with_rd_almost_empty => false,
g_with_rd_almost_full => false,
g_with_rd_count => false,
g_with_wr_empty => false,
g_with_wr_full => false,
g_with_wr_almost_empty => false,
g_with_wr_almost_full => true,
g_with_wr_count => false,
g_almost_empty_threshold => 0,
g_almost_full_threshold => c_TO_WB_FIFO_FULL_THRES)
------------------------------------------------------------------------------
-- Active low reset for fifos
------------------------------------------------------------------------------
fifo_rst_n <= rst_n_i;
-- Local resynced copy of fifo_rst_n to make sure that both sides of the fifo
-- are reset if rst_n_i = '0'
cmp_wb_fifo_rst_sync : gc_sync
port map (
rst_wr_n_i => fifo_rst_n,
clk_wr_i => clk_i,
d_i => to_wb_fifo_din_d,
we_i => to_wb_fifo_wr_d,
wr_empty_o => open,
wr_full_o => open,
wr_almost_empty_o => open,
wr_almost_full_o => to_wb_fifo_full,
wr_count_o => open,
rst_rd_n_i => wb_fifo_rst_n,
clk_rd_i => p2l_dma_clk_i,
q_o => to_wb_fifo_dout,
rd_i => to_wb_fifo_rd,
rd_empty_o => to_wb_fifo_empty,
rd_full_o => open,
rd_almost_empty_o => open,
rd_almost_full_o => open,
rd_count_o => open);
p_gen_fifo_valid : process(p2l_dma_clk_i)
clk_i => wb_dma_clk_i,
rst_n_a_i => wb_dma_rst_n_i,
d_i => fifo_rst_n,
q_o => wb_fifo_rst_n);
-- Pipeline to_wb_fifo_full to help with timing. This requires the
-- equivalent setting in g_ALMOST_FULL_THRESHOLD to prevent overflows.
p_fifo_full_delay_reg : process (wb_dma_clk_i) is
begin
if rising_edge(p2l_dma_clk_i) then
to_wb_fifo_valid <= to_wb_fifo_rd and (not to_wb_fifo_empty);
if rising_edge(wb_dma_clk_i) then
-- we want proper registers to help with timing and
-- having a reset prevents inferring of shift register.
if wb_fifo_rst_n = '0' then
to_wb_fifo_full_d <= (others => '0');
else
to_wb_fifo_full_d <= to_wb_fifo_full_d(to_wb_fifo_full_d'high-1 downto 0) & to_wb_fifo_full_next;
end if;
end if;
end process;
end process p_fifo_full_delay_reg;
to_wb_fifo_full <= to_wb_fifo_full_d(to_wb_fifo_full_d'high);
cmp_to_wb_fifo : generic_async_fifo_dual_rst
generic map (
g_DATA_WIDTH => 64,
g_SIZE => g_FIFO_SIZE,
g_SHOW_AHEAD => TRUE,
g_WITH_WR_FULL => FALSE,
g_WITH_WR_ALMOST_FULL => TRUE,
-- 20 less to give time to the GN4124 to react to P2L_RDY going low.
g_ALMOST_FULL_THRESHOLD => g_FIFO_SIZE - c_SYNC_FIFO_FULL_DELAY - 20)
port map (
-- write port
rst_wr_n_i => fifo_rst_n,
clk_wr_i => clk_i,
d_i => to_wb_fifo_din_d,
we_i => to_wb_fifo_wr_d,
wr_almost_full_o => to_wb_fifo_full_next,
-- read port
rst_rd_n_i => wb_fifo_rst_n,
clk_rd_i => wb_dma_clk_i,
q_o => to_wb_fifo_dout,
rd_i => to_wb_fifo_rd,
rd_empty_o => to_wb_fifo_empty);
-- pause transfer from GN4124 if fifo is (almost) full
p2l_rdy_o <= not(to_wb_fifo_full);
......@@ -575,80 +527,61 @@ begin
-- Wishbone master (write only)
------------------------------------------------------------------------------
-- fifo read
to_wb_fifo_rd <= not(to_wb_fifo_empty)
and not(p2l_dma_stall_i)
and not(l2p_dma_cyc_i);
-- write only
p2l_dma_we_o <= '1';
wb_dma_o.we <= '1';
wb_dma_o.sel <= (others => '1');
wb_dma_o.stb <= wb_dma_out_stb;
-- Set when a wishbone transfer occurred.
wb_dma_tfr <= wb_dma_out_stb = '1' and wb_dma_i.stall = '0';
-- Read from fifo.
-- Only when the fifo is not empty
-- and either no previous data or previous data read.
-- wb_dma_out_stb = '1' when there are previous data.
to_wb_fifo_rd <= '1' when to_wb_fifo_empty = '0' and (wb_dma_tfr or wb_dma_out_stb = '0') else '0';
-- Wishbone master process
p_wb_master : process (p2l_dma_clk_i)
p_wb_master : process (wb_dma_clk_i)
begin
if rising_edge(p2l_dma_clk_i) then
if rising_edge(wb_dma_clk_i) then
if wb_fifo_rst_n = '0' then
p2l_dma_cyc_t <= '0';
p2l_dma_stb_t <= '0';
wb_dma_o.cyc <= '0';
wb_dma_out_stb <= '0';
wb_ack_cnt <= (others => '0');
else
-- data and address
if (to_wb_fifo_valid = '1') then
p2l_dma_adr_t(31 downto 30) <= "00";
p2l_dma_adr_t(29 downto 0) <= to_wb_fifo_dout(61 downto 32);
p2l_dma_dat_t <= to_wb_fifo_dout(31 downto 0);
end if;
-- stb and sel signals management
if (to_wb_fifo_valid = '1') then
p2l_dma_stb_t <= '1';
p2l_dma_sel_t <= (others => '1');
if to_wb_fifo_rd = '1' then
-- Data available, read them from the fifo.
wb_dma_o.adr(31 downto 30) <= "00";
wb_dma_o.adr(29 downto 0) <= to_wb_fifo_dout(61 downto 32);
wb_dma_o.dat <= to_wb_fifo_dout(31 downto 0);
-- Data/addresses are valid when fifo was just read.
wb_dma_out_stb <= '1';
wb_dma_o.cyc <= '1';
else
p2l_dma_stb_t <= '0';
p2l_dma_sel_t <= (others => '0');
end if;
-- cyc signal management
if (to_wb_fifo_valid = '1') then
p2l_dma_cyc_t <= '1';
elsif (wb_ack_cnt >= wb_write_cnt and p2l_dma_stall_d(1) = '0') then
-- last ack received -> end of the transaction
p2l_dma_cyc_t <= '0';
end if;
end if;
end if;
end process p_wb_master;
-- for read back
p2l_dma_cyc_o <= p2l_dma_cyc_t;
p2l_dma_stb_o <= p2l_dma_stb_t;
p2l_dma_sel_o <= p2l_dma_sel_t;
p2l_dma_adr_o <= p2l_dma_adr_t;
p2l_dma_dat_o <= p2l_dma_dat_t;
-- No read.
if wb_dma_out_stb = '1' and wb_dma_i.stall = '1' then
-- Data were not read, just wait.
null;
elsif to_wb_fifo_empty = '1' then
-- No more data to produce.
wb_dma_out_stb <= '0';
-- Wishbone write cycle counter
p_wb_write_cnt : process (p2l_dma_clk_i)
begin
if rising_edge(p2l_dma_clk_i) then
if wb_fifo_rst_n = '0' then
wb_write_cnt <= (others => '0');
else
if (to_wb_fifo_valid = '1') then
wb_write_cnt <= wb_write_cnt + 1;
if wb_ack_cnt = 0 then
-- End of the burst
wb_dma_o.cyc <= '0';
end if;
end if;
end if;
end if;
end if;
end process p_wb_write_cnt;
-- Wishbone ack counter
p_wb_ack_cnt : process (p2l_dma_clk_i)
begin
if rising_edge(p2l_dma_clk_i) then
if wb_fifo_rst_n = '0' then
wb_ack_cnt <= (others => '0');
else
if (p2l_dma_ack_i = '1' and p2l_dma_cyc_t = '1') then
-- Track number of expected ack.
if wb_dma_tfr and wb_dma_i.ack = '0' then
wb_ack_cnt <= wb_ack_cnt + 1;
elsif not wb_dma_tfr and wb_dma_i.ack = '1' then
wb_ack_cnt <= wb_ack_cnt - 1;
end if;
end if;
end if;
end process p_wb_ack_cnt;
end behaviour;
end process p_wb_master;
end architecture arch;