Commit a38d51dc authored by Phil Clarke's avatar Phil Clarke Committed by Phil Clarke

Add AXI4 slave RTL and testbench

testbench is parameterised to simplify testing with / without AXI and WB_DMA
update style on most files
parent 84e177ed
......@@ -2,9 +2,19 @@ files = [
"dma_controller.vhd",
"dma_controller_regs.vhd",
"l2p_arbiter.vhd",
"rl0_pl_stage_flowcontrol_srst.vhd",
"l2p_dma_master.vhd",
"p2l_decode32.vhd",
"p2l_dma_master.vhd",
"gn4124_axi4_pkg.vhd",
"gn4124_axi_stream_dcfifo.vhd",
"gn4124_axi_r_chl_dcfifo.vhd",
"l2p_axi4_wr_initiator.vhd",
"l2p_axi4_wr_preprocessor.vhd",
"l2p_axi4_wr_dc.vhd",
"p2l_axi4_rd_initiator.vhd",
"p2l_axi4_rd_preprocessor.vhd",
"p2l_axi4_rd_dc.vhd",
"wbmaster32.vhd",
]
......
......@@ -9,7 +9,7 @@
-- description: Manages the DMA transfers.
--
--------------------------------------------------------------------------------
-- Copyright CERN 2010-2019
-- Copyright CERN 2010-2021
--------------------------------------------------------------------------------
-- Copyright and related rights are licensed under the Solderpad Hardware
-- License, Version 2.0 (the "License"); you may not use this file except
......
This diff is collapsed.
--------------------------------------------------------------------------------
-- GN4124 core for PCIe FMC carrier
-- http://www.ohwr.org/projects/gn4124-core
--------------------------------------------------------------------------------
--
-- unit name: gn4124_axi_stream_dcfifo
--
-- description: wraps the CERN generic DC_FIFO to provide AXI_Stream Style signalling
-- Additionally for the dc_fifo running in showahead mode, it is intended
-- to mask any W -> R races and resultant metastability on the data output
-- by controlling sampling based on empty
--
--------------------------------------------------------------------------------
--
-- This source describes Open Hardware and is licensed under the CERN-OHL-W v2.
-- You may redistribute and modify this source and make products using it
-- under the terms of the CERN-OHL-W v2 or future versions (https://ohwr.org/cern_ohl_w_v2.txt).
--
-- This source is distributed WITHOUT ANY EXPRESS OR IMPLIED
-- WARRANTY, INCLUDING OF MERCHANTABILITY, SATISFACTORY
-- QUALITY AND FITNESS FOR A PARTICULAR PURPOSE. Please see
-- the CERN-OHL-W v2 for applicable conditions.
--
--------------------------------------------------------------------------------
-- Copyright CERN 2021
--------------------------------------------------------------------------------
--
-- NOTES:
--------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use work.genram_pkg.all;
use work.gencores_pkg.all;
entity gn4124_axi_r_chl_dcfifo is
generic (
g_DATA_WIDTH : positive := 32;
g_NUM_WORDS : positive := 8;
g_ALMOST_FULL_THRESHOLD : positive;
g_RESET_SRC_DAT : boolean := true
);
port (
-- sink interface
snk_clk_i : in std_logic;
snk_rst_n_i : in std_logic;
snk_rdy_o : out std_logic;
snk_vld_i : in std_logic;
snk_dat_i : in std_logic_vector(g_DATA_WIDTH -1 downto 0);
snk_lvl_o : out std_logic_vector(f_log2_size(g_NUM_WORDS) -1 downto 0);
snk_almost_full_o : out std_logic;
-- source interface
src_clk_i : in std_logic;
src_rst_n_i : in std_logic;
src_rdy_i : in std_logic;
src_vld_o : out std_logic;
src_dat_o : out std_logic_vector(g_DATA_WIDTH -1 downto 0)
);
end entity gn4124_axi_r_chl_dcfifo;
architecture rtl of gn4124_axi_r_chl_dcfifo is
signal wr_full : std_logic;
signal wr_write : std_logic;
signal rd_empty : std_logic;
signal src_valid_int : std_logic;
signal src_dat_clk_en : std_logic;
-- TBD: Apply attributes on this to make it a clk_en for the regs
signal rd_dat : std_logic_vector(g_DATA_WIDTH -1 downto 0);
signal almost_full : std_logic;
begin
snk_rdy_o <= not wr_full;
wr_write <= snk_vld_i and not wr_full;
snk_almost_full_o <= almost_full;
inst_dcfifo : entity work.generic_async_fifo_dual_rst
generic map(
g_data_width => g_DATA_WIDTH,
g_size => g_NUM_WORDS,
g_show_ahead => true,
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 => true,
g_with_wr_almost_empty => false,
g_with_wr_almost_full => true,
g_with_wr_count => true,
g_almost_empty_threshold => 0,
g_almost_full_threshold => g_ALMOST_FULL_THRESHOLD
) port map (
rst_wr_n_i => snk_rst_n_i,
clk_wr_i => snk_clk_i,
d_i => snk_dat_i,
we_i => wr_write,
wr_full_o => wr_full,
wr_empty_o => open,
wr_almost_empty_o => open,
wr_almost_full_o => almost_full,
wr_count_o => snk_lvl_o,
rst_rd_n_i => src_rst_n_i,
clk_rd_i => src_clk_i,
q_o => rd_dat,
rd_i => src_dat_clk_en,
rd_empty_o => rd_empty,
rd_full_o => open,
rd_almost_empty_o => open,
rd_almost_full_o => open,
rd_count_o => open
);
p_dat : process (src_clk_i)
begin
if rising_edge(src_clk_i) then
if src_dat_clk_en = '1' then
src_dat_o <= rd_dat;
end if;
if g_RESET_SRC_DAT and src_rst_n_i = '0' then
src_dat_o <= (others => '0');
end if;
end if;
end process p_dat;
p_valid : process (src_clk_i)
begin
if rising_edge(src_clk_i) then
if src_rst_n_i = '0' then
src_valid_int <= '0';
else
if src_dat_clk_en = '1' then
src_valid_int <= '1';
elsif src_rdy_i = '1' and src_valid_int = '1' then
src_valid_int <= '0';
end if;
end if;
end if;
end process p_valid;
src_vld_o <= src_valid_int;
p_int_clken : process (src_valid_int, src_rdy_i, rd_empty)
begin
if src_valid_int = '1' and src_rdy_i = '1' and rd_empty = '0' then
src_dat_clk_en <= '1';
elsif src_valid_int = '0' and rd_empty = '0' then
src_dat_clk_en <= '1';
else
src_dat_clk_en <= '0';
end if;
end process p_int_clken;
end architecture rtl;
--------------------------------------------------------------------------------
-- GN4124 core for PCIe FMC carrier
-- http://www.ohwr.org/projects/gn4124-core
--------------------------------------------------------------------------------
--
-- unit name: gn4124_axi_stream_dcfifo
--
-- description: wraps the CERN generic (Dual clock) DC_FIFO to provide AXI_Stream Style
-- signalling Additionally for the dc_fifo running in showahead mode, it is
-- intended to mask any W -> R races and resultant metastability on the data
-- output by controlling sampling based on empty
--
--------------------------------------------------------------------------------
--
-- This source describes Open Hardware and is licensed under the CERN-OHL-W v2.
-- You may redistribute and modify this source and make products using it
-- under the terms of the CERN-OHL-W v2 or future versions (https://ohwr.org/cern_ohl_w_v2.txt).
--
-- This source is distributed WITHOUT ANY EXPRESS OR IMPLIED
-- WARRANTY, INCLUDING OF MERCHANTABILITY, SATISFACTORY
-- QUALITY AND FITNESS FOR A PARTICULAR PURPOSE. Please see
-- the CERN-OHL-W v2 for applicable conditions.
--
--------------------------------------------------------------------------------
-- Copyright CERN 2021
--------------------------------------------------------------------------------
--
-- NOTES:
--------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use work.genram_pkg.all;
entity gn4124_axi_stream_dcfifo is
generic (
g_DATA_WIDTH : positive := 32;
g_NUM_WORDS : positive := 8;
g_RESET_SRC_DAT : boolean := true
);
port (
snk_clk_i : in std_logic;
snk_rst_n_i : in std_logic;
snk_rdy_o : out std_logic;
snk_vld_i : in std_logic;
snk_dat_i : in std_logic_vector(g_DATA_WIDTH -1 downto 0);
src_clk_i : in std_logic;
src_rst_n_i : in std_logic;
src_rdy_i : in std_logic;
src_vld_o : out std_logic;
src_dat_o : out std_logic_vector(g_DATA_WIDTH -1 downto 0)
);
end entity gn4124_axi_stream_dcfifo;
architecture rtl of gn4124_axi_stream_dcfifo is
signal wr_full : std_logic;
signal wr_write : std_logic;
signal rd_empty : std_logic;
signal src_valid_int : std_logic;
signal src_dat_clk_en : std_logic;
-- TBD: Apply attributes on this to make it a clk_en for the regs
signal rd_dat : std_logic_vector(g_DATA_WIDTH -1 downto 0);
begin
snk_rdy_o <= not wr_full;
wr_write <= snk_vld_i and not wr_full;
inst_dcfifo : entity work.generic_async_fifo_dual_rst
generic map(
g_data_width => g_DATA_WIDTH,
g_size => g_NUM_WORDS,
g_show_ahead => true,
g_with_rd_empty => true, -- with empty flag
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 => true, -- with full flag
g_with_wr_almost_empty => false,
g_with_wr_almost_full => false,
g_with_wr_count => false, -- with words counter
g_almost_empty_threshold => 0, -- threshold for almost empty flag
g_almost_full_threshold => 0 -- threshold for almost full flag
) port map (
rst_wr_n_i => snk_rst_n_i,
clk_wr_i => snk_clk_i,
d_i => snk_dat_i,
we_i => wr_write,
wr_full_o => wr_full,
wr_empty_o => open,
wr_almost_empty_o => open,
wr_almost_full_o => open,
wr_count_o => open,
rst_rd_n_i => src_rst_n_i,
clk_rd_i => src_clk_i,
q_o => rd_dat,
rd_i => src_dat_clk_en,
rd_empty_o => rd_empty,
rd_full_o => open,
rd_almost_empty_o => open,
rd_almost_full_o => open,
rd_count_o => open
);
p_dat : process (src_clk_i)
begin
if rising_edge(src_clk_i) then
if src_dat_clk_en = '1' then
src_dat_o <= rd_dat;
end if;
if g_RESET_SRC_DAT and src_rst_n_i = '0' then
src_dat_o <= (others => '0');
end if;
end if;
end process p_dat;
p_valid : process (src_clk_i)
begin
if rising_edge(src_clk_i) then
if src_dat_clk_en = '1' then
src_valid_int <= '1';
elsif src_rdy_i = '1' and src_valid_int = '1' then
src_valid_int <= '0';
end if;
if src_rst_n_i = '0' then
src_valid_int <= '0';
end if;
end if;
end process p_valid;
src_vld_o <= src_valid_int;
p_int_clken : process (src_valid_int, src_rdy_i, rd_empty)
begin
if src_valid_int = '1' and src_rdy_i = '1' and rd_empty = '0' then
src_dat_clk_en <= '1';
elsif src_valid_int = '0' and rd_empty = '0' then
src_dat_clk_en <= '1';
else
src_dat_clk_en <= '0';
end if;
end process p_int_clken;
end architecture rtl;
\ No newline at end of file
......@@ -10,7 +10,7 @@
-- L2P DMA master and P2L DMA master
--
--------------------------------------------------------------------------------
-- Copyright CERN 2010-2018
-- Copyright CERN 2010-2021
--------------------------------------------------------------------------------
-- Copyright and related rights are licensed under the Solderpad Hardware
-- License, Version 2.0 (the "License"); you may not use this file except
......@@ -30,42 +30,25 @@ use work.gn4124_core_pkg.all;
entity l2p_arbiter is
port
(
generic (
g_NUM_PORTS : positive := 4
);
port (
---------------------------------------------------------
-- GN4124 core clock and reset
clk_i : in std_logic;
rst_n_i : in std_logic;
clk_i : in std_logic;
rst_n_i : in std_logic;
---------------------------------------------------------
-- From Wishbone master (wbm) to arbiter (arb)
wbm_arb_valid_i : in std_logic;
wbm_arb_dframe_i : in std_logic;
wbm_arb_data_i : in std_logic_vector(31 downto 0);
wbm_arb_req_i : in std_logic;
arb_wbm_gnt_o : out std_logic;
---------------------------------------------------------
-- From P2L DMA master (pdm) to arbiter (arb)
pdm_arb_valid_i : in std_logic;
pdm_arb_dframe_i : in std_logic;
pdm_arb_data_i : in std_logic_vector(31 downto 0);
pdm_arb_req_i : in std_logic;
arb_pdm_gnt_o : out std_logic;
---------------------------------------------------------
-- From L2P DMA master (ldm) to arbiter (arb)
ldm_arb_valid_i : in std_logic;
ldm_arb_dframe_i : in std_logic;
ldm_arb_data_i : in std_logic_vector(31 downto 0);
ldm_arb_req_i : in std_logic;
arb_ldm_gnt_o : out std_logic;
-- From initiators to arbiter (arb)
-- indexing is deliberatley from n downto 1 not 0!
dat_i : in a_arbiter_rec( g_NUM_PORTS downto 1);
req_i : in std_logic_vector(g_NUM_PORTS downto 1);
gnt_o : out std_logic_vector(g_NUM_PORTS downto 1);
---------------------------------------------------------
-- From arbiter (arb) to serializer (ser)
arb_ser_valid_o : out std_logic;
arb_ser_dframe_o : out std_logic;
arb_ser_data_o : out std_logic_vector(31 downto 0)
arb_2_ser_o : out t_arbiter_rec
);
end l2p_arbiter;
......@@ -76,113 +59,116 @@ architecture rtl of l2p_arbiter is
------------------------------------------------------------------------------
-- Signals declaration
------------------------------------------------------------------------------
signal wbm_arb_req_valid : std_logic;
signal pdm_arb_req_valid : std_logic;
signal ldm_arb_req_valid : std_logic;
signal arb_wbm_gnt : std_logic;
signal arb_pdm_gnt : std_logic;
signal arb_ldm_gnt : std_logic;
signal eop : std_logic; -- End of packet
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 req_valid : std_logic_vector(g_NUM_PORTS downto 1);
signal granted_interface : integer range 0 to g_NUM_PORTS;
-- encoding: '0' is no ports active, any other value is the selected port's index
signal padded_input_array : a_arbiter_rec(g_NUM_PORTS downto 0);
signal selected_idat : t_arbiter_rec;
signal data_pipeline : t_arbiter_rec;
constant c_CONST_NO_VALID_REQUESTS : std_logic_vector(g_NUM_PORTS downto 1) := (others => '0');
begin
-- A request is valid only if the access not already granted to another source
wbm_arb_req_valid <= wbm_arb_req_i and (not(arb_pdm_gnt) and not(arb_ldm_gnt));
pdm_arb_req_valid <= pdm_arb_req_i and (not(arb_wbm_gnt) and not(arb_ldm_gnt));
ldm_arb_req_valid <= ldm_arb_req_i and (not(arb_wbm_gnt) and not(arb_pdm_gnt));
-- Detect end of packet to delimit the arbitration phase
eop <= ((arb_wbm_gnt and not(wbm_arb_dframe_i) and wbm_arb_valid_i) or
(arb_pdm_gnt and not(pdm_arb_dframe_i) and pdm_arb_valid_i) or
(arb_ldm_gnt and not(ldm_arb_dframe_i) and ldm_arb_valid_i));
-----------------------------------------------------------------------------
-- Arbitration is started when a valid request is present and ends when the
-- EOP condition is detected
--
-- Strict priority arbitration scheme
-- Highest : WBM request
-- : LDM request
-- Lowest : PDM request
-----------------------------------------------------------------------------
process (clk_i)
p_req_valid : process (granted_interface, req_i)
begin
for i in req_valid'range loop
if req_i(i) = '1' and (granted_interface = 0 or granted_interface = i) then
req_valid(i) <= '1';
else
req_valid(i) <= '0';
end if;
end loop;
end process p_req_valid;
padded_input_array(g_NUM_PORTS downto 1) <= dat_i;
padded_input_array(0) <= c_DEFAULT_ARBITER_REC;
selected_idat <= padded_input_array(granted_interface);
p_grant_generation : process (clk_i)
begin
if rising_edge(clk_i) then
if(rst_n_i = '0') then
arb_wbm_gnt <= '0';
arb_pdm_gnt <= '0';
arb_ldm_gnt <= '0';
if rst_n_i = '0' then
gnt_o <= (others => '0');
granted_interface <= 0;
else
if (wbm_arb_req_valid = '1') then
arb_wbm_gnt <= '1';
arb_pdm_gnt <= '0';
arb_ldm_gnt <= '0';
elsif (ldm_arb_req_valid = '1') then
arb_wbm_gnt <= '0';
arb_pdm_gnt <= '0';
arb_ldm_gnt <= '1';
elsif (pdm_arb_req_valid = '1') then
arb_wbm_gnt <= '0';
arb_pdm_gnt <= '1';
arb_ldm_gnt <= '0';
elsif (eop = '1') then
arb_wbm_gnt <= '0';
arb_pdm_gnt <= '0';
arb_ldm_gnt <= '0';
if req_valid /= c_CONST_NO_VALID_REQUESTS then -- if there is >= 1 valid_request
for i in g_NUM_PORTS downto 1 loop -- scan through all ports &
if req_valid(i) = '1' then -- priority encode which valid gets used.
gnt_o <= (others => '0');
gnt_o(i) <= '1';
granted_interface <= i;
end if;
end loop;
elsif selected_idat.valid = '1' and selected_idat.dframe = '0' then -- last beat of transfer
gnt_o <= (others => '0');
granted_interface <= 0;
end if;
end if;
end if;
end process;
end process p_grant_generation;
process (clk_i)
p_selected_src_register : process (clk_i)
begin
if rising_edge(clk_i) then
data_pipeline <= selected_idat;
-- abnormal style to make sure that arb_ser_data_t does not use rst_n_i as a clk_en
if rst_n_i = '0' then
arb_ser_valid_t <= '0';
arb_ser_dframe_t <= '0';
else
if arb_wbm_gnt = '1' then
arb_ser_valid_t <= wbm_arb_valid_i;
arb_ser_dframe_t <= wbm_arb_dframe_i;
arb_ser_data_t <= wbm_arb_data_i;
elsif arb_pdm_gnt = '1' then
arb_ser_valid_t <= pdm_arb_valid_i;
arb_ser_dframe_t <= pdm_arb_dframe_i;
arb_ser_data_t <= pdm_arb_data_i;
elsif arb_ldm_gnt = '1' then
arb_ser_valid_t <= ldm_arb_valid_i;
arb_ser_dframe_t <= ldm_arb_dframe_i;
arb_ser_data_t <= ldm_arb_data_i;
else
arb_ser_valid_t <= '0';
arb_ser_dframe_t <= '0';
arb_ser_data_t <= (others => '0');
end if;
data_pipeline.valid <= '0';
data_pipeline.dframe <= '0';
end if;
end if;
end process;
end process p_selected_src_register;
process (clk_i)
p_output_pipeline : process (clk_i)
begin
if rising_edge(clk_i) then
arb_2_ser_o <= data_pipeline;
-- as arb_ser_data_o is not reset, do not use the "else statement"; we dont want a clk_en
if rst_n_i = '0' then
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_2_ser_o.valid <= '0';
arb_2_ser_o.dframe <= '0';
end if;
end if;
end process;
end process p_output_pipeline;
-- Implement some code to show unused data trasnfer cycles while something
-- is granted (help optimise *_req_i) this is to provide a little help for system optimisation.
-- we do not want to synthesise it
--synthesis translate_off
b_SIMONLY_unused_granted_bus_cycles : block -- use a block so the signal are invisible and self-contained
signal gnt_was_unused : std_logic_vector(g_NUM_PORTS downto 1);
begin
p_optimisation_helper : process (clk_i)
begin
if rising_edge(clk_i) then
for i in gnt_was_unused'range loop
if i = granted_interface then
gnt_was_unused(i) <= not(padded_input_array(i).dframe or padded_input_array(i).valid);
else
gnt_was_unused(i) <= '0';
end if;
end loop;
end if;
end process p_optimisation_helper;
end block b_SIMONLY_unused_granted_bus_cycles;
-- TBD: assert to make sure only a single bit in req_valid is asserted if granted_interface/= 0
--synthesis translate_on
arb_wbm_gnt_o <= arb_wbm_gnt;
arb_pdm_gnt_o <= arb_pdm_gnt;
arb_ldm_gnt_o <= arb_ldm_gnt;
end rtl;
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -10,7 +10,7 @@
-- that performs DMA transfer from the local application to PCI express host.
--
--------------------------------------------------------------------------------
-- Copyright CERN 2010-2020
-- Copyright CERN 2010-2021
--------------------------------------------------------------------------------
-- Copyright and related rights are licensed under the Solderpad Hardware
-- License, Version 2.0 (the "License"); you may not use this file except
......@@ -38,13 +38,13 @@ entity l2p_dma_master is
-- 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);
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;
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);
......@@ -58,24 +58,24 @@ entity l2p_dma_master is
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;
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
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);
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
......@@ -95,14 +95,14 @@ architecture arch of l2p_dma_master is
-- 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 t_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 : t_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;
type t_wb_dma_state_type is (WB_IDLE, WB_SETUP, WB_DATA, WB_WAIT_ACK);
signal wb_dma_current_state : t_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');
......@@ -139,7 +139,6 @@ architecture arch of l2p_dma_master is
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';
......@@ -177,8 +176,6 @@ begin
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';
......
This diff is collapsed.
This diff is collapsed.
--------------------------------------------------------------------------------
-- GN4124 core for PCIe FMC carrier
-- http://www.ohwr.org/projects/gn4124-core
--------------------------------------------------------------------------------
--
-- unit name: p2l_axi4_rd_preprocessor
--
-- description: Implements a AXI4 peripheral slave write port, its purpose is to format and buffer
-- AXI read transactions ready for the L2P interface.
--
--------------------------------------------------------------------------------
--
-- This source describes Open Hardware and is licensed under the CERN-OHL-W v2.
-- You may redistribute and modify this source and make products using it
-- under the terms of the CERN-OHL-W v2 or future versions (https://ohwr.org/cern_ohl_w_v2.txt).
--
-- This source is distributed WITHOUT ANY EXPRESS OR IMPLIED
-- WARRANTY, INCLUDING OF MERCHANTABILITY, SATISFACTORY
-- QUALITY AND FITNESS FOR A PARTICULAR PURPOSE. Please see
-- the CERN-OHL-W v2 for applicable conditions.
--
--------------------------------------------------------------------------------
-- Copyright CERN 2021
--------------------------------------------------------------------------------
--
--
-- TBD: implement enable modifications : e.g. splitting Xactions to PCIE_MAX_READ_REQ_SIZE,
-- 4K boundary checks
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.NUMERIC_STD.all;
use work.gn4124_axi4_pkg.all;
entity p2l_axi4_rd_preprocessor is
generic (
g_EN_AXI_QOS_2_TC_LOOKUP : boolean := false;
g_PCIE_DEAGULT_QOS : std_logic_vector(2 downto 0) := "000";
g_ID_WIDTH : positive := 2
);
port (
---------------------------------------------------------
clk_i : in std_logic;
rst_n_i : in std_logic;
seen_err_o : out std_logic;
err_code_o : out std_logic_vector(2 downto 0);
enable_no_snoop_i : in std_logic;
vc_i : in std_logic := '0';
enable_modifications_i : in std_logic := '0';
modified_max_size_i : in unsigned(7 downto 0);
---------------------------------------------------------
-- AXI4 input interfaces:
---------------------------------------------------------
-- Write address channel
ar_ready_o : out std_logic;
ar_valid_i : in std_logic;
ar_chl_i : in t_gn4124_axi4_ax_chnl;
ar_chl_id_i : in std_logic_vector(g_ID_WIDTH-1 downto 0);
ctrl_rdy_i : in std_logic;
ctrl_vld_o : out std_logic;
ctrl_rec_o : out t_ar_preprocessed;
ctrl_rec_id_o : out std_logic_vector(g_ID_WIDTH-1 downto 0)
);
end p2l_axi4_rd_preprocessor;
architecture rtl of p2l_axi4_rd_preprocessor is
type t_proc_state is (
S_IDLE,
S_ERR,
S_SEND_CMD
);
signal state : t_proc_state;
type t_err_code is (
ERR_NONE,
ERR_RECOVERABLE_AR_CACHE_ILLEGAL_VALUE,
ERR_RECOVERABLE_AR_BURST_TYPE_UNSUPPORTED,
ERR_RECOVERABLE_AR_SIZE_UNSUPPORTED
);
signal sm_errcode : t_err_code;
signal int_seen_error : std_logic;
-- signal to enable optional pipelining on input... & it makes sure it is registered instead of comb!
signal ar_chl_sm : t_gn4124_axi4_ax_chnl;
signal ar_chl_sm_id : std_logic_vector(g_ID_WIDTH-1 downto 0);
signal ar_sm_rdy : std_logic;
signal ar_sm_vld : std_logic;
signal ctrl_vld_int : std_logic;
begin
b_ar_in_pl : block
signal ar_chl_pl : t_gn4124_axi4_ax_chnl;
signal ar_chl_id_pl : std_logic_vector(g_ID_WIDTH-1 downto 0);
signal clken_ar_plreg : std_logic;
signal clken_ar_opreg : std_logic;
signal ar_use_pl : std_logic;
begin
-- logic to give us "standarad AXI" write data control....
-- if we had VHDL2008 this would just take the generic type and be a single instantiation
-- instead of a block!
axi_ar_pipeline_control : entity work.rl0_pl_stage_flowcontrol_srst
port map (
clk_i => clk_i,
rst_n_i => rst_n_i,
in_rdy_o => ar_ready_o,
in_vld_i => ar_valid_i,
out_rdy_i => ar_sm_rdy,
out_vld_o => ar_sm_vld,
clk_en_pl_reg_o => clken_ar_plreg,
clk_en_op_reg_o => clken_ar_opreg,
use_dat_from_pl_reg_o => ar_use_pl
);
p_ar_register_pipeline : process (clk_i)
begin
if rising_edge(clk_i) then
if clken_ar_plreg = '1' then
ar_chl_pl <= ar_chl_i;
ar_chl_id_pl <= ar_chl_id_i;
end if;
if clken_ar_opreg = '1' then
if ar_use_pl = '1' then
ar_chl_sm <= ar_chl_pl;
ar_chl_sm_id <= ar_chl_id_pl;
else
ar_chl_sm <= ar_chl_i;
ar_chl_sm_id <= ar_chl_id_i;
end if;
end if;
end if;
end process p_ar_register_pipeline;
end block b_ar_in_pl;
-- catch the first error seen and hold untill we reset the module.
p_error_hold : process (clk_i)
begin
if rising_edge(clk_i) then
if int_seen_error = '0' then
if sm_errcode /= ERR_NONE then
int_seen_error <= '1';
case sm_errcode is
when ERR_RECOVERABLE_AR_CACHE_ILLEGAL_VALUE => err_code_o <= "001";
when ERR_RECOVERABLE_AR_BURST_TYPE_UNSUPPORTED => err_code_o <= "010";
when ERR_RECOVERABLE_AR_SIZE_UNSUPPORTED => err_code_o <= "011";
when others => err_code_o <= "000";
end case;
end if;
end if;
if rst_n_i = '0' then
int_seen_error <= '0';
err_code_o <= "000";
end if;
end if;
end process p_error_hold;
seen_err_o <= int_seen_error;
-----------------------------------------------------------------------------
-- PCIe read request FSM
-----------------------------------------------------------------------------
p_fsm : process (clk_i)
begin
if rising_edge(clk_i) then
ar_sm_rdy <= '0';
sm_errcode <= ERR_NONE;
case state is
when S_IDLE =>
ctrl_rec_o.err <= '0';
ctrl_rec_o.addr <= ar_chl_sm.addr(63 downto 2);
ctrl_rec_o.tc <= g_PCIE_DEAGULT_QOS;
ctrl_rec_o.nosnoop <= f_ar_cache_2_nosnoop(ar_chl_sm.cache, enable_no_snoop_i);
ctrl_rec_o.vc <= vc_i;
if ar_chl_sm.addr(63 downto 32) = x"00000000" then
ctrl_rec_o.addr_is_64b <= '0';
else
ctrl_rec_o.addr_is_64b <= '1';
end if;
ctrl_rec_o.len <= ('0' & unsigned(ar_chl_sm.len)) +1;
-- these should be calculable from AR_ADDR, AR_SIZE, AR_LEN
case ar_chl_sm.addr(1 downto 0) is
when "00" => ctrl_rec_o.fwbe <= "1111";
when "01" => ctrl_rec_o.fwbe <= "1110";
when "10" => ctrl_rec_o.fwbe <= "1100";
when others => ctrl_rec_o.fwbe <= "1000";
end case;
if ar_chl_sm.len = x"00" then
ctrl_rec_o.lwbe <= "0000";
else
ctrl_rec_o.lwbe <= "1111";
end if;
ctrl_rec_o.r_last <= '1'; -- FOR now, the initiator is responsible for length
ctrl_rec_o.r_resp <= "00"; -- OK
ctrl_rec_id_o <= ar_chl_sm_id;
if ar_sm_vld = '1' and ar_sm_rdy = '0' then
-- Makes sure the cache bits are legal. - if not error...
if f_ar_cache_is_legal(ar_chl_sm.cache) /= '1' then
state <= S_ERR;
sm_errcode <= ERR_RECOVERABLE_AR_CACHE_ILLEGAL_VALUE;
elsif ar_chl_sm.burst /= C_GN4124_AXI4_BURST_TYPE_INCR then -- only support INCR
state <= S_ERR;
sm_errcode <= ERR_RECOVERABLE_AR_BURST_TYPE_UNSUPPORTED;
elsif ar_chl_sm.size /= "010" then -- only support 32bit ops
state <= S_ERR;
sm_errcode <= ERR_RECOVERABLE_AR_SIZE_UNSUPPORTED;
-- TBD: we might want to do burst splitting OR equivalent here as another elsif choice
else
state <= S_SEND_CMD;
end if;
end if;
when S_ERR =>
state <= S_SEND_CMD;
ctrl_rec_o.err <= '1';
ctrl_rec_o.r_resp <= "10"; -- SLVERR
when S_SEND_CMD =>
ctrl_vld_int <= '1';
if ctrl_vld_int = '1' and ctrl_rdy_i = '1' then
ctrl_vld_int <= '0';
state <= S_IDLE;
ar_sm_rdy <= '1';
end if;
when others =>
state <= S_IDLE;
end case;
-- Not implementing RESET as an if elsif end-if so we dont get a clk_enable inferred!
if rst_n_i = '0' then
state <= S_IDLE;
ctrl_vld_int <= '0';
ar_sm_rdy <= '0';
sm_errcode <= ERR_NONE;
end if;
end if;
end process p_fsm;
ctrl_vld_o <= ctrl_vld_int;
end architecture rtl;
......@@ -9,7 +9,7 @@
-- description: P2L 32-bit datapath decoder
--
--------------------------------------------------------------------------------
-- Copyright CERN 2010-2018
-- Copyright CERN 2010-2021
--------------------------------------------------------------------------------
-- Copyright and related rights are licensed under the Solderpad Hardware
-- License, Version 2.0 (the "License"); you may not use this file except
......@@ -33,14 +33,14 @@ entity p2l_decode32 is
(
---------------------------------------------------------
-- GN4124 core clock and reset
clk_i : in std_logic;
rst_n_i : in std_logic;
clk_i : in std_logic;
rst_n_i : in std_logic;
---------------------------------------------------------
-- Input from the deserializer
des_p2l_valid_i : in std_logic;
des_p2l_dframe_i : in std_logic;
des_p2l_data_i : in std_logic_vector(31 downto 0);
des_p2l_valid_i : in std_logic;
des_p2l_dframe_i : in std_logic;
des_p2l_data_i : in std_logic_vector(31 downto 0);
---------------------------------------------------------
-- Decoder outputs
......@@ -81,10 +81,10 @@ architecture rtl of p2l_decode32 is
-----------------------------------------------------------------------------
function f_to_mvl (b : in boolean) return std_logic is
begin
if (b = true) then
return('1');
if b then
return '1';
else
return('0');
return '0';
end if;
end f_to_mvl;
......@@ -156,7 +156,7 @@ begin
master_cpln <= '0';
else
-- New packet starts, check type for routing
if (p2l_packet_start = '1') then
if p2l_packet_start = '1' then
-- Target read request
target_mrd <= f_to_mvl(des_p2l_data_i(27 downto 24) = "0000");
-- Target write
......@@ -165,7 +165,7 @@ begin
master_cpld <= f_to_mvl(des_p2l_data_i(27 downto 24) = "0101");
-- Master read completion without data
master_cpln <= f_to_mvl(des_p2l_data_i(27 downto 24) = "0100");
elsif (p2l_packet_end = '1') then
elsif p2l_packet_end = '1' then
target_mrd <= '0';
target_mwr <= '0';
master_cpld <= '0';
......@@ -188,12 +188,12 @@ begin
p2l_hdr_fbe <= (others => '0');
p2l_hdr_lbe <= (others => '0');
else
if (p2l_packet_start = '1') then
if p2l_packet_start = '1' then
p2l_hdr_strobe <= '1';
p2l_hdr_length <= des_p2l_data_i(9 downto 0);
p2l_hdr_cid <= des_p2l_data_i(11 downto 10);
p2l_hdr_last <= des_p2l_data_i(15);
if (des_p2l_data_i(26) = '1') then
if des_p2l_data_i(26) = '1' then
-- packet type = read completion
p2l_hdr_stat <= des_p2l_data_i(17 downto 16); -- Completion status
else
......@@ -221,15 +221,15 @@ begin
-- Indicate address cycle(s)
-- Address cycle comes just after the header.
-- Read completion packet doesn't have an address field, then addr_cycle is not asserted.
if (p2l_packet_start = '1' and des_p2l_data_i(26) = '0') then
if p2l_packet_start = '1' and des_p2l_data_i(26) = '0' then
p2l_addr_cycle <= '1';
elsif (p2l_addr_cycle = '1' and des_p2l_valid_i = '1') then
elsif p2l_addr_cycle = '1' and des_p2l_valid_i = '1' then
p2l_addr_cycle <= '0';
end if;
-- Generates address strobe
-- No address strobe for read completion packets
if ((target_mwr or target_mrd) = '1') then
if (target_mwr or target_mrd) = '1' then
p2l_addr_start <= p2l_addr_cycle and des_p2l_valid_i;
else
p2l_addr_start <= '0';
......@@ -241,10 +241,10 @@ begin
-- "01" = BAR 2
-- "10" = Expansion ROM
-- "11" = Reserved
if (p2l_addr_cycle = '1' and des_p2l_valid_i = '1' and (target_mwr or target_mrd) = '1') then
if p2l_addr_cycle = '1' and des_p2l_valid_i = '1' and (target_mwr or target_mrd) = '1' then
-- Latch target address
p2l_addr <= unsigned(des_p2l_data_i);
elsif (p2l_d_valid = '1' and (target_mwr or target_mrd) = '1') then
elsif p2l_d_valid = '1' and (target_mwr or target_mrd) = '1' then
-- Increment address with data (32-bit data word => increment = +4 bytes)
p2l_addr(31 downto 2) <= p2l_addr(31 downto 2) + 1;
end if;
......@@ -266,10 +266,10 @@ begin
-- Indicates data cycle(s)
-- Data cycle comes after an address cycle, exept for read completion packet
-- in this case it comes just after the header.
if ((p2l_addr_cycle = '1' or (p2l_packet_start = '1' and des_p2l_data_i(26) = '1'))
and des_p2l_valid_i = '1' and des_p2l_dframe_i = '1') then
if (p2l_addr_cycle = '1' or (p2l_packet_start = '1' and des_p2l_data_i(26) = '1'))
and des_p2l_valid_i = '1' and des_p2l_dframe_i = '1' then
p2l_data_cycle <= '1';
elsif (des_p2l_dframe_i = '0') then
elsif des_p2l_dframe_i = '0' then
p2l_data_cycle <= '0';
end if;
......@@ -281,7 +281,7 @@ begin
p2l_d_last <= p2l_data_cycle and not(des_p2l_dframe_i);
-- Latch data on the bus
if(des_p2l_valid_i = '1') then
if des_p2l_valid_i = '1' then
p2l_d <= des_p2l_data_i;
end if;
end if;
......@@ -297,11 +297,11 @@ begin
if rst_n_i = '0' then
p2l_be <= (others => '0');
else
if (p2l_addr_start = '1') then
if p2l_addr_start = '1' then
p2l_be <= p2l_hdr_fbe; -- First Byte Enable
elsif ((p2l_data_cycle and not(des_p2l_dframe_i)) = '1') then
elsif (p2l_data_cycle and not(des_p2l_dframe_i)) = '1' then
p2l_be <= p2l_hdr_lbe; -- Last Byte Enable
elsif(p2l_data_cycle = '1') then
elsif p2l_data_cycle = '1' then
p2l_be <= (others => '1'); -- Intermediate Byte Enables
end if;
end if;
......
......@@ -46,64 +46,64 @@ use work.genram_pkg.all;
entity p2l_dma_master is
generic (
g_FIFO_SIZE : positive := 64;
g_BYTE_SWAP : boolean := FALSE;
g_TID_CID : std_logic_vector(1 downto 0) := "01"
g_FIFO_SIZE : positive := 64;
g_BYTE_SWAP : boolean := FALSE;
g_TID_CID : std_logic_vector(1 downto 0) := "01"
);
port (
---------------------------------------------------------
-- GN4124 core clock and reset
clk_i : in std_logic;
rst_n_i : in std_logic;
clk_i : in std_logic;
rst_n_i : in std_logic;
---------------------------------------------------------
-- From the DMA controller
dma_ctrl_carrier_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_p2l_i : in std_logic;
dma_ctrl_start_next_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;
dma_ctrl_carrier_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_p2l_i : in std_logic;
dma_ctrl_start_next_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;
---------------------------------------------------------
-- From P2L Decoder (receive the read completion)
--
-- Header
pd_pdm_hdr_start_i : in std_logic; -- Header strobe
pd_pdm_hdr_length_i : in std_logic_vector(9 downto 0); -- Packet length in 32-bit words multiples
pd_pdm_hdr_cid_i : in std_logic_vector(1 downto 0); -- Completion ID
pd_pdm_master_cpld_i : in std_logic; -- Master read completion with data
pd_pdm_master_cpln_i : in std_logic; -- Master read completion without data
pd_pdm_hdr_start_i : in std_logic; -- Header strobe
pd_pdm_hdr_length_i : in std_logic_vector(9 downto 0); -- Packet length in 32-bit words multiples
pd_pdm_hdr_cid_i : in std_logic_vector(1 downto 0); -- Completion ID
pd_pdm_master_cpld_i : in std_logic; -- Master read completion with data
pd_pdm_master_cpln_i : in std_logic; -- Master read completion without data
--
-- Data
pd_pdm_data_valid_i : in std_logic; -- Indicates Data is valid
pd_pdm_data_last_i : in std_logic; -- Indicates end of the packet
pd_pdm_data_i : in std_logic_vector(31 downto 0); -- Data
pd_pdm_be_i : in std_logic_vector(3 downto 0); -- Byte Enable for data
pd_pdm_data_valid_i : in std_logic; -- Indicates Data is valid
pd_pdm_data_last_i : in std_logic; -- Indicates end of the packet
pd_pdm_data_i : in std_logic_vector(31 downto 0); -- Data
pd_pdm_be_i : in std_logic_vector(3 downto 0); -- Byte Enable for data
---------------------------------------------------------
-- P2L control
p2l_rdy_o : out std_logic; -- De-asserted to pause transfer already in progress
rx_error_o : out std_logic; -- Asserted when transfer is aborted
p2l_rdy_o : out std_logic; -- De-asserted to pause transfer already in progress
rx_error_o : out std_logic; -- Asserted when transfer is aborted
---------------------------------------------------------
-- To the P2L Interface (send the DMA Master Read request)
pdm_arb_valid_o : out std_logic; -- Read completion signals
pdm_arb_dframe_o : out std_logic; -- Toward the arbiter
pdm_arb_data_o : out std_logic_vector(31 downto 0);
pdm_arb_req_o : out std_logic;
arb_pdm_gnt_i : in std_logic;
pdm_arb_valid_o : out std_logic; -- Read completion signals
pdm_arb_dframe_o : out std_logic; -- Toward the arbiter
pdm_arb_data_o : out std_logic_vector(31 downto 0);
pdm_arb_req_o : out std_logic;
arb_pdm_gnt_i : in std_logic;
---------------------------------------------------------
-- 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;
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
......@@ -181,9 +181,9 @@ architecture arch of p2l_dma_master is
signal wb_dma_tfr : boolean;
-- P2L DMA read request FSM
type p2l_dma_state_type is (P2L_IDLE, P2L_SETUP, P2L_HEADER, P2L_ADDR_H, P2L_ADDR_L,
P2L_WAIT_READ_COMPLETION, P2L_WAIT_WISHBONE_COMPLETE);
signal p2l_dma_current_state : p2l_dma_state_type;
type t_p2l_dma_state_type is (P2L_IDLE, P2L_SETUP, P2L_HEADER, P2L_ADDR_H, P2L_ADDR_L,
P2L_WAIT_READ_COMPLETION, P2L_WAIT_WISHBONE_COMPLETE);
signal p2l_dma_current_state : t_p2l_dma_state_type;
signal p2l_data_cnt : unsigned(10 downto 0) := (others => '0');
signal next_item_carrier_addr : std_logic_vector(31 downto 0) := (others => '0');
......@@ -358,12 +358,12 @@ begin
end if;
when P2L_WAIT_WISHBONE_COMPLETE =>
if dma_ctrl_abort_i = '1' then
p2l_dma_current_state <= P2L_IDLE;
elsif fsm_wb_reading_complete = '1' then
dma_ctrl_done_t <= '1';
p2l_dma_current_state <= P2L_IDLE;
end if;
if dma_ctrl_abort_i = '1' then
p2l_dma_current_state <= P2L_IDLE;
elsif fsm_wb_reading_complete = '1' then
dma_ctrl_done_t <= '1';
p2l_dma_current_state <= P2L_IDLE;
end if;
when others =>
p2l_dma_current_state <= P2L_IDLE;
......@@ -472,9 +472,9 @@ begin
to_wb_fifo_wr_d <= to_wb_fifo_wr;
if p2l_dma_current_state /= P2L_IDLE and dma_ctrl_start_p2l_i = '1' then
dma_busy_error <= '1';
dma_busy_error <= '1';
else
dma_busy_error <= '0';
dma_busy_error <= '0';
end if;
if dma_ctrl_start_p2l_i = '1' then
......
--------------------------------------------------------------------------------
-- GN4124 core for PCIe FMC carrier
-- http://www.ohwr.org/projects/gn4124-core
--------------------------------------------------------------------------------
--
-- unit name: rl0_pl_stage_flowcontrol_srst
--
-- description: generates AXI_STREAM or AVALON_ST (RL0) flowcontrol signals
-- and provide the control signals to make a pipeline stage of whatever type
--
--
--------------------------------------------------------------------------------
--
-- This source describes Open Hardware and is licensed under the CERN-OHL-W v2.
-- You may redistribute and modify this source and make products using it
-- under the terms of the CERN-OHL-W v2 or future versions (https://ohwr.org/cern_ohl_w_v2.txt).
--
-- This source is distributed WITHOUT ANY EXPRESS OR IMPLIED
-- WARRANTY, INCLUDING OF MERCHANTABILITY, SATISFACTORY
-- QUALITY AND FITNESS FOR A PARTICULAR PURPOSE. Please see
-- the CERN-OHL-W v2 for applicable conditions.
--
--------------------------------------------------------------------------------
-- Copyright CERN 2021
--------------------------------------------------------------------------------
--
-- NOTES:
-- expected usecase: control for a axi pipeline stage, but as we dont have generic types
-- in ISE, this at least allows re-use of pre-verified control logic!
--
-- ..........
-- signal internal_pipeline_stage : t_data_or_rec;
-- signal output_data : t_data_or_rec;
--
-- BEGIN
-- ..................
-- <instantiate the component here >
-- ...................
--
-- p_pl_stage : process (clk) begin
-- if rising_edge(clk) then
-- if clk_en_pl_reg = '1' then
-- internal_pipeline_stage <= data_to_pipeline;
-- end if;
--
-- if clk_en_op_reg = '1' then
-- if use_dat_from_pl_reg = '1' then
-- output_data <= internal_pipeline_stage;
-- else
-- output_data <= data_to_pipeline;
-- end if;
-- end if;
-- end if;
-- end process p_pl_stage;
--------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
entity rl0_pl_stage_flowcontrol_srst is
port (
clk_i : in std_logic;
rst_n_i : in std_logic;
in_rdy_o : out std_logic;
in_vld_i : in std_logic;
out_rdy_i : in std_logic;
out_vld_o : out std_logic;
clk_en_pl_reg_o : out std_logic;
clk_en_op_reg_o : out std_logic;
use_dat_from_pl_reg_o : out std_logic
);
end entity rl0_pl_stage_flowcontrol_srst;
architecture rtl of rl0_pl_stage_flowcontrol_srst is
-- TBD: is there a XILINX, Intel(Altera), and microsemi freindly way to not optimise this out....,
-- or do I need to go to a per vendor architecture approach....
signal pl_reg_is_valid : std_logic;
signal in_ready_int : std_logic;
signal out_valid_int : std_logic;
begin
clk_en_pl_reg_o <= in_vld_i and in_ready_int;
use_dat_from_pl_reg_o <= pl_reg_is_valid;
out_vld_o <= out_valid_int;
in_rdy_o <= in_ready_int;
p_comb_clken : process (out_valid_int, out_rdy_i, in_vld_i)
begin
if (out_valid_int = '1' and out_rdy_i = '1')
or (out_valid_int = '0' and in_vld_i = '1')
then
clk_en_op_reg_o <= '1';
else
clk_en_op_reg_o <= '0';
end if;
end process p_comb_clken;
p_reg_state_tracking : process (clk_i)
begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
pl_reg_is_valid <= '0';
in_ready_int <= '1';
else
if pl_reg_is_valid = '1' and out_rdy_i = '1' and out_valid_int = '1' then
pl_reg_is_valid <= '0';
in_ready_int <= '1';
elsif pl_reg_is_valid = '0' and in_vld_i = '1' and out_valid_int = '1' and out_rdy_i = '0' then
pl_reg_is_valid <= '1';
in_ready_int <= '0';
end if;
end if;
end if;
end process p_reg_state_tracking;
p_out_valid_reg : process (clk_i)
begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
out_valid_int <= '0';
else
if out_valid_int = '1' and out_rdy_i = '1' then
out_valid_int <= '0';
if pl_reg_is_valid = '1' then
out_valid_int <= '1';
elsif pl_reg_is_valid = '0' and in_vld_i = '1' then
out_valid_int <= '1';
end if;
elsif out_valid_int = '0' and in_vld_i = '1' then
out_valid_int <= '1';
end if;
end if;
end if;
end process p_out_valid_reg;
end architecture rtl;
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -17,6 +17,7 @@ include_dirs = [
files = [
"main.sv",
"wrapped_xwb_gn4124_core.vhd"
]
modules = {
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment