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;
---------------------------------------------------------
-- 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 process;
end if;
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');
data_pipeline.valid <= '0';
data_pipeline.dframe <= '0';
end if;
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';
arb_2_ser_o.valid <= '0';
arb_2_ser_o.dframe <= '0';
end if;
end if;
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
arb_ser_valid_o <= arb_ser_valid_t;
arb_ser_dframe_o <= arb_ser_dframe_t;
arb_ser_data_o <= arb_ser_data_t;
gnt_was_unused(i) <= '0';
end if;
end loop;
end if;
end process;
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
......@@ -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,
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 : l2p_dma_state_type := L2P_IDLE;
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
......@@ -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;
......
......@@ -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,
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 : p2l_dma_state_type;
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');
......
--------------------------------------------------------------------------------
-- 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.
......@@ -11,7 +11,7 @@
-- Version for Spartan6 FPGAs.
--
--------------------------------------------------------------------------------
-- Copyright CERN 2018 - 2020
-- Copyright CERN 2018 - 2021
--------------------------------------------------------------------------------
-- Copyright and related rights are licensed under the Solderpad Hardware
-- License, Version 2.0 (the "License"); you may not use this file except
......@@ -34,6 +34,12 @@ entity xwb_gn4124_core is
generic (
-- If TRUE, enable the DMA interface
g_WITH_DMA : boolean := TRUE;
-- if true then enable AXI read and write interfaces...
g_WITH_AXI : boolean := FALSE;
g_AXI4S_RD_ID_W : positive := 2;
g_AXI4S_WR_ID_W : positive := 2;
-- Tunable size and threshold for all async FIFOs.
-- If not sure, leave the defaults.
g_WBM_TO_WB_FIFO_SIZE : positive := 128;
......@@ -115,7 +121,51 @@ entity xwb_gn4124_core is
wb_dma_dat_clk_i : in std_logic;
wb_dma_dat_rst_n_i : in std_logic;
wb_dma_dat_i : in t_wishbone_master_in;
wb_dma_dat_o : out t_wishbone_master_out);
wb_dma_dat_o : out t_wishbone_master_out;
---------------------------------------------------------
-- AXI4 Slave port
axi_rst_n_i : in std_logic := '0';
axi_clk_i : in std_logic := '0';
axi4s_aw_ready_o : out std_logic;
axi4s_aw_valid_i : in std_logic := '0';
axi4s_aw_addr_i : in std_logic_vector(63 downto 0) := (others => '0');
axi4s_aw_id_i : in std_logic_vector(g_AXI4S_WR_ID_W-1 downto 0) := (others => '0');
axi4s_aw_len_i : in std_logic_vector(7 downto 0) := (others => '0');
axi4s_aw_size_i : in std_logic_vector(2 downto 0) := (others => '0');
axi4s_aw_burst_i : in std_logic_vector(1 downto 0) := (others => '0');
axi4s_aw_cache_i : in std_logic_vector(3 downto 0) := (others => '0');
axi4s_aw_qos_i : in std_logic_vector(3 downto 0) := (others => '0');
axi4s_w_ready_o : out std_logic;
axi4s_w_valid_i : in std_logic := '0';
axi4s_w_data_i : in std_logic_vector(31 downto 0) := (others => '0');
axi4s_w_strobe_i : in std_logic_vector(3 downto 0) := (others => '0');
axi4s_w_last_i : in std_logic := '0';
axi4s_b_ready_i : in std_logic := '0';
axi4s_b_valid_o : out std_logic;
axi4s_b_id_o : out std_logic_vector(g_AXI4S_WR_ID_W-1 downto 0);
axi4s_b_resp_o : out std_logic_vector(1 downto 0);
axi4s_ar_ready_o : out std_logic;
axi4s_ar_valid_i : in std_logic := '0';
axi4s_ar_addr_i : in std_logic_vector(63 downto 0) := (others => '0');
axi4s_ar_id_i : in std_logic_vector(g_AXI4S_RD_ID_W-1 downto 0) := (others => '0');
axi4s_ar_len_i : in std_logic_vector(7 downto 0) := (others => '0');
axi4s_ar_size_i : in std_logic_vector(2 downto 0) := (others => '0');
axi4s_ar_burst_i : in std_logic_vector(1 downto 0) := (others => '0');
axi4s_ar_cache_i : in std_logic_vector(3 downto 0) := (others => '0');
axi4s_ar_qos_i : in std_logic_vector(3 downto 0) := (others => '0');
axi4s_r_ready_i : in std_logic := '0';
axi4s_r_valid_o : out std_logic;
axi4s_r_id_o : out std_logic_vector(g_AXI4S_RD_ID_W-1 downto 0);
axi4s_r_resp_o : out std_logic_vector(1 downto 0);
axi4s_r_data_o : out std_logic_vector(31 downto 0);
axi4s_r_last_o : out std_logic
);
end xwb_gn4124_core;
......@@ -188,6 +238,12 @@ begin
cmp_wrapped_gn4124 : gn4124_core
generic map (
g_WITH_DMA => g_WITH_DMA,
g_EN_AXI4S_WR => g_WITH_AXI,
g_EN_AXI4S_RD => g_WITH_AXI,
g_AXI4S_RD_ID_W => g_AXI4S_RD_ID_W,
g_AXI4S_WR_ID_W => g_AXI4S_WR_ID_W,
g_AXI4S_RD_DAT_BW => 4,
g_AXI4S_WR_DAT_BW => 4,
g_WBM_TO_WB_FIFO_SIZE => g_WBM_TO_WB_FIFO_SIZE,
g_WBM_TO_WB_FIFO_FULL_THRES => g_WBM_TO_WB_FIFO_FULL_THRES,
g_WBM_FROM_WB_FIFO_SIZE => g_WBM_FROM_WB_FIFO_SIZE,
......@@ -258,7 +314,43 @@ begin
dma_ack_i => wb_dma_dat_in.ack,
dma_stall_i => wb_dma_dat_in.stall,
dma_err_i => wb_dma_dat_in.err,
dma_rty_i => wb_dma_dat_in.rty);
dma_rty_i => wb_dma_dat_in.rty,
axi_rst_n_i => axi_rst_n_i,
axi_clk_i => axi_clk_i,
axi4s_aw_ready_o => axi4s_aw_ready_o,
axi4s_aw_valid_i => axi4s_aw_valid_i,
axi4s_aw_addr_i => axi4s_aw_addr_i,
axi4s_aw_id_i => axi4s_aw_id_i,
axi4s_aw_len_i => axi4s_aw_len_i,
axi4s_aw_size_i => axi4s_aw_size_i,
axi4s_aw_burst_i => axi4s_aw_burst_i,
axi4s_aw_cache_i => axi4s_aw_cache_i,
axi4s_aw_qos_i => axi4s_aw_qos_i,
axi4s_w_ready_o => axi4s_w_ready_o,
axi4s_w_valid_i => axi4s_w_valid_i,
axi4s_w_data_i => axi4s_w_data_i,
axi4s_w_strobe_i => axi4s_w_strobe_i,
axi4s_w_last_i => axi4s_w_last_i,
axi4s_b_ready_i => axi4s_b_ready_i,
axi4s_b_valid_o => axi4s_b_valid_o,
axi4s_b_id_o => axi4s_b_id_o,
axi4s_b_resp_o => axi4s_b_resp_o,
axi4s_ar_ready_o => axi4s_ar_ready_o,
axi4s_ar_valid_i => axi4s_ar_valid_i,
axi4s_ar_addr_i => axi4s_ar_addr_i,
axi4s_ar_id_i => axi4s_ar_id_i,
axi4s_ar_len_i => axi4s_ar_len_i,
axi4s_ar_size_i => axi4s_ar_size_i,
axi4s_ar_burst_i => axi4s_ar_burst_i,
axi4s_ar_cache_i => axi4s_ar_cache_i,
axi4s_ar_qos_i => axi4s_ar_qos_i,
axi4s_r_ready_i => axi4s_r_ready_i,
axi4s_r_valid_o => axi4s_r_valid_o,
axi4s_r_id_o => axi4s_r_id_o,
axi4s_r_resp_o => axi4s_r_resp_o,
axi4s_r_data_o => axi4s_r_data_o,
axi4s_r_last_o => axi4s_r_last_o
);
-- drive unused outputs
wb_dma_cfg_out.err <= '0';
......
......@@ -10,7 +10,7 @@
-- single read and write control and status registers.
--
--------------------------------------------------------------------------------
-- 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
......@@ -56,8 +56,8 @@ entity wbmaster32 is
--
-- Address
pd_wbm_addr_start_i : in std_logic; -- Address strobe
pd_wbm_addr_i : in std_logic_vector(31 downto 0); -- Target address (in byte) that will increment with data
-- increment = 4 bytes
pd_wbm_addr_i : in std_logic_vector(31 downto 0); -- Target address (in byte) that
-- will increment with data increment = 4 bytes
--
-- Data
pd_wbm_data_valid_i : in std_logic; -- Indicates Data is valid
......@@ -68,8 +68,10 @@ entity wbmaster32 is
---------------------------------------------------------
-- P2L channel control
p_wr_rdy_o : out std_logic_vector(1 downto 0); -- Ready to accept target write
p2l_rdy_o : out std_logic; -- De-asserted to pause transfer already in progress
p_rd_d_rdy_i : in std_logic; -- Asserted when GN4124 ready to accept read completion with data
p2l_rdy_o : out std_logic; -- De-asserted to pause transfer
-- already in progress
p_rd_d_rdy_i : in std_logic; -- Asserted when GN4124 ready to
-- accept read completion with data
---------------------------------------------------------
-- To the arbiter (L2P data)
......@@ -98,7 +100,7 @@ entity wbmaster32 is
end wbmaster32;
architecture behaviour of wbmaster32 is
architecture rtl of wbmaster32 is
-----------------------------------------------------------------------------
-- Signals declaration
......@@ -129,8 +131,8 @@ architecture behaviour of wbmaster32 is
signal wbm_arb_data : std_logic_vector(31 downto 0) := (others => '0');
-- Wishbone
type wishbone_state_type is (WB_IDLE, WB_READ_FIFO, WB_CYCLE, WB_WAIT_ACK);
signal wishbone_current_state : wishbone_state_type;
type t_wishbone_state_type is (WB_IDLE, WB_READ_FIFO, WB_CYCLE, WB_WAIT_ACK);
signal wishbone_current_state : t_wishbone_state_type;
signal wb_ack_t : std_logic;
signal wb_err_t : std_logic;
......@@ -148,8 +150,8 @@ architecture behaviour of wbmaster32 is
signal wb_ack_timeout : std_logic;
-- L2P packet generator
type l2p_read_cpl_state_type is (L2P_IDLE, L2P_HEADER, L2P_DATA);
signal l2p_read_cpl_current_state : l2p_read_cpl_state_type;
type t_l2p_read_cpl_state_type is (L2P_IDLE, L2P_HEADER, L2P_DATA);
signal l2p_read_cpl_current_state : t_l2p_read_cpl_state_type;
signal p2l_cid : std_logic_vector(1 downto 0);
signal s_l2p_header : std_logic_vector(31 downto 0);
......@@ -165,7 +167,7 @@ begin
-- 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
cmp_wb_fifo_rst_sync : gc_sync_ffs
port map (
clk_i => wb_clk_i,
rst_n_i => wb_rst_n_i,
......@@ -185,10 +187,10 @@ begin
p_from_decoder : process (clk_i)
begin
if rising_edge(clk_i) then
if (rst_n_i = '0') then
if rst_n_i = '0' then
to_wb_fifo_wr <= '0';
else
if (pd_wbm_target_mwr_i = '1' and pd_wbm_data_valid_i = '1') then
if pd_wbm_target_mwr_i = '1' and pd_wbm_data_valid_i = '1' then
-- Target write
-- wishbone address is in 32-bit words and address from PCIe in byte
-- pd_wbm_addr_i(0) represent the BAR (0 = BAR0, 1 = BAR 2)
......@@ -197,7 +199,7 @@ begin
to_wb_fifo_din(63) <= '1';
to_wb_fifo_din(65 downto 64) <= pd_wbm_hdr_cid_i;
to_wb_fifo_wr <= '1';
elsif (pd_wbm_target_mrd_i = '1' and pd_wbm_addr_start_i = '1') then
elsif pd_wbm_target_mrd_i = '1' and pd_wbm_addr_start_i = '1' then
-- Target read request
-- wishbone address is in 32-bit words and address from PCIe in byte
-- pd_wbm_addr_i(0) represent the BAR (0 = BAR0, 1 = BAR 2)
......@@ -237,19 +239,19 @@ begin
------------------------------------------------------------------------------
-- L2P packet write FSM
------------------------------------------------------------------------------
process( from_wb_fifo_empty, p_rd_d_rdy_i, l2p_read_cpl_current_state )
process (from_wb_fifo_empty, p_rd_d_rdy_i, l2p_read_cpl_current_state)
begin
if(l2p_read_cpl_current_state = L2P_IDLE and from_wb_fifo_empty = '0' and p_rd_d_rdy_i = '1') then
if l2p_read_cpl_current_state = L2P_IDLE and from_wb_fifo_empty = '0' and p_rd_d_rdy_i = '1' then
from_wb_fifo_rd <= '1';
else
from_wb_fifo_rd <= '0';
end if;
end process;
process (clk_i)
p_l2p_packet_fsm : process (clk_i)
begin
if rising_edge(clk_i) then
if(rst_n_i = '0') then
if rst_n_i = '0' then
l2p_read_cpl_current_state <= L2P_IDLE;
wbm_arb_req_o <= '0';
wbm_arb_valid_o <= '0';
......@@ -262,7 +264,7 @@ begin
wbm_arb_data <= (others => '0');
wbm_arb_valid_o <= '0';
wbm_arb_dframe_o <= '0';
if(from_wb_fifo_empty = '0' and p_rd_d_rdy_i = '1') then
if from_wb_fifo_empty = '0' and p_rd_d_rdy_i = '1' then
-- generate a packet when read data in fifo
-- and GN4124 ready to receive the packet
wbm_arb_req_o <= '1';
......@@ -272,7 +274,7 @@ begin
when L2P_HEADER =>
if(arb_wbm_gnt_i = '1') then
if arb_wbm_gnt_i = '1' then
wbm_arb_req_o <= '0';
wbm_arb_data <= s_l2p_header;
wbm_arb_valid_o <= '1';
......@@ -295,7 +297,7 @@ begin
end case;
end if;
end if;
end process;
end process p_l2p_packet_fsm;
wbm_arb_data_o <= wbm_arb_data;
......@@ -408,7 +410,7 @@ begin
wb_stb_t <= '0';
wb_sel_t <= "0000";
-- wait for a Wishbone cycle
if (to_wb_fifo_empty = '0') then
if to_wb_fifo_empty = '0' then
-- read request in fifo (address, data and transfer type)
to_wb_fifo_rd <= '1';
wishbone_current_state <= WB_READ_FIFO;
......@@ -435,9 +437,9 @@ begin
if wb_stall_t = '0' then
wb_stb_t <= '0';
end if;
if (wb_ack_t = '1') then
if wb_ack_t = '1' then
-- for read cycles write read data to fifo
if (wb_we_t = '0') then
if wb_we_t = '0' then
from_wb_fifo_din(31 downto 0) <= wb_dat_i_t;
from_wb_fifo_din(33 downto 32) <= wb_cid_t;
from_wb_fifo_wr <= '1';
......@@ -445,12 +447,12 @@ begin
-- end of the bus cycle
wb_cyc_t <= '0';
wishbone_current_state <= WB_IDLE;
elsif (wb_err_t = '1') or (wb_ack_timeout = '1') then
elsif wb_err_t = '1' or wb_ack_timeout = '1' then
-- e.g. When trying to access unmapped wishbone addresses,
-- the wb crossbar asserts ERR. If ERR is not asserted when
-- accessing un-mapped addresses, a timeout makes sure the
-- transaction terminates.
if (wb_we_t = '0') then
if wb_we_t = '0' then
-- dummy data as the transaction failed
from_wb_fifo_din(31 downto 0) <= (others => '1');
from_wb_fifo_din(33 downto 32) <= wb_cid_t;
......@@ -523,4 +525,4 @@ begin
end if;
end process p_ack_timeout;
end behaviour;
end rtl;
......@@ -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