Skip to content
Snippets Groups Projects
Commit f124d215 authored by Eric Kooistra's avatar Eric Kooistra
Browse files

Replaced Windows LFCR by Linux LF to avoid ^R at end of line in vi (replace \r...

Replaced Windows LFCR by Linux LF to avoid ^R at end of line in vi (replace \r --> nothing). Removed trailing spaces.
parent 5c2cc725
Branches
No related tags found
2 merge requests!28Master,!15Resolve L2SDP-27
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
-- --
-- Copyright 2020 -- Copyright 2020
-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> -- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands -- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
-- --
-- Licensed under the Apache License, Version 2.0 (the "License"); -- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License. -- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at -- You may obtain a copy of the License at
-- --
-- http://www.apache.org/licenses/LICENSE-2.0 -- http://www.apache.org/licenses/LICENSE-2.0
-- --
-- Unless required by applicable law or agreed to in writing, software -- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS, -- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and -- See the License for the specific language governing permissions and
-- limitations under the License. -- limitations under the License.
-- --
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
-- --
-- Author: E. Kooistra -- Author: E. Kooistra
-- Purpose: Connect a single MM master interface to a list of MM slave -- Purpose: Connect a single MM master interface to a list of MM slave
-- interfaces using a combinatorial muliplexer as bus. -- interfaces using a combinatorial muliplexer as bus.
-- Description: -- Description:
-- * MM bus -- * MM bus
-- The mm_bus_comb creates a memory mapped (MM) bus that connects read -- The mm_bus_comb creates a memory mapped (MM) bus that connects read
-- and write accesses from the master interface to the addressed slave -- and write accesses from the master interface to the addressed slave
-- interface. There is one master that controls the bus and there are -- interface. There is one master that controls the bus and there are
-- g_nof_slaves on the bus. Per slave the start address and address span -- g_nof_slaves on the bus. Per slave the start address and address span
-- have to be specified via g_base_arr and g_width_arr. -- have to be specified via g_base_arr and g_width_arr.
-- --
-- * Slave allocation -- * Slave allocation
-- The slaves have to be located on the bus such that the MSbits of the -- The slaves have to be located on the bus such that the MSbits of the
-- global address can be used to select the slave and the LSbits of the -- global address can be used to select the slave and the LSbits of the
-- global address can directly be used to select the address within the -- global address can directly be used to select the address within the
-- slave. Therefore: -- slave. Therefore:
-- . The width of a slave is the power of 2 that fits the address range of -- . The width of a slave is the power of 2 that fits the address range of
-- the slave. -- the slave.
-- . The span of a slave is 2**width. -- . The span of a slave is 2**width.
-- . The base address of a slave has to be a power of 2 multiple of the -- . The base address of a slave has to be a power of 2 multiple of the
-- slave span. -- slave span.
-- --
-- * The mm_clk is only used when there is a slave with read latency > 0, to -- * The mm_clk is only used when there is a slave with read latency > 0, to
-- pipeline the slave_index_arr for the master_miso.rddata/rdval. -- pipeline the slave_index_arr for the master_miso.rddata/rdval.
-- Typically a master will wait for the last rdval, before accessing -- Typically a master will wait for the last rdval, before accessing
-- another slave port, so then it is not benecessary to pipeline the -- another slave port, so then it is not benecessary to pipeline the
-- slave_index_arr. However registering the slave_index_arr eases timing -- slave_index_arr. However registering the slave_index_arr eases timing
-- closure on the miso part and will allow reading from different slave -- closure on the miso part and will allow reading from different slave
-- ports without waiting, provided that both slaves have the same read -- ports without waiting, provided that both slaves have the same read
-- latency. -- latency.
-- --
-- * Read latency -- * Read latency
-- For read accesses a slave will typically have a read latency > 0, which -- For read accesses a slave will typically have a read latency > 0, which
-- means that when the rd and address are active, then it takes read -- means that when the rd and address are active, then it takes read
-- latency number of clock cycles until the rddata becomes available. The -- latency number of clock cycles until the rddata becomes available. The
-- read latency can be specified per slave via g_rd_latency_arr. -- read latency can be specified per slave via g_rd_latency_arr.
-- The slave_index_arr is used to support that a new wr access or rd access -- The slave_index_arr is used to support that a new wr access or rd access
-- can already start, while a current rd access still has to finish with -- can already start, while a current rd access still has to finish with
-- a rdval. Without the slave_index_arr the master would have to wait with -- a rdval. Without the slave_index_arr the master would have to wait with
-- a new rd or wr access to another slave until the read response from the -- a new rd or wr access to another slave until the read response from the
-- current slave has finished. -- current slave has finished.
-- ________ -- ________
-- | delay| -- | delay|
-- master_mosi.address[h:w] = index --+-->| line |--\ -- master_mosi.address[h:w] = index --+-->| line |--\
-- | |______| | -- | |______| |
-- | | -- | |
-- v | -- v |
-- master_mosi --> slave_mosi_arr.wr[ ]----------------> slave_mosi_arr -- master_mosi --> slave_mosi_arr.wr[ ]----------------> slave_mosi_arr
-- rd | -- rd |
-- v -- v
-- master_miso <--------------------slave_miso_arr[ ]<-- slave_miso_arr -- master_miso <--------------------slave_miso_arr[ ]<-- slave_miso_arr
-- --
-- --
-- * No pipelining -- * No pipelining
-- The mm_bus_comb is combinatorial, so there is no pipelining between -- The mm_bus_comb is combinatorial, so there is no pipelining between
-- the master interface and the slave interfaces. Use mm_bus_pipe to add -- the master interface and the slave interfaces. Use mm_bus_pipe to add
-- pipelining. -- pipelining.
-- --
-- Usage: -- Usage:
-- See mm_bus.vhd. -- See mm_bus.vhd.
-- --
-- Limitations: -- Limitations:
-- * A limitation is that if one slave has a read latency of 2 and another -- * A limitation is that if one slave has a read latency of 2 and another
-- slave has a read latency of 1 then it is not possible to access them -- slave has a read latency of 1 then it is not possible to access them
-- without a gap of 1 mm_clk cycle, because the rdval will then be active -- without a gap of 1 mm_clk cycle, because the rdval will then be active
-- simultaneously from both slaves. Therefore the master can only use -- simultaneously from both slaves. Therefore the master can only use
-- random read access between slaves if all slaves have the same read -- random read access between slaves if all slaves have the same read
-- latency. For slaves that have larger read latency the master must -- latency. For slaves that have larger read latency the master must
-- insert an gap, before it can read a slave that has less read latency. -- insert an gap, before it can read a slave that has less read latency.
-- An alternative workaround would be to use the same read latency for all -- An alternative workaround would be to use the same read latency for all
-- slaves on the bus, by pipelining the miso.rd, rddata for MM slaves that -- slaves on the bus, by pipelining the miso.rd, rddata for MM slaves that
-- have a smaller read latency. -- have a smaller read latency.
-- --
-- Remarks: -- Remarks:
-- . The mm_bus_comb resembles common_mem_mux, but the difference is that -- . The mm_bus_comb resembles common_mem_mux, but the difference is that
-- with common_mem_mux all slaves have the same address range and are -- with common_mem_mux all slaves have the same address range and are
-- spaced without address gaps. It is possible to use common_mem_mux in -- spaced without address gaps. It is possible to use common_mem_mux in
-- series with mm_bus_comb to provide hierarchy by reprensenting an array -- series with mm_bus_comb to provide hierarchy by reprensenting an array
-- of slave ports via a single slave port on the MM bus. -- of slave ports via a single slave port on the MM bus.
-- --
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
LIBRARY IEEE, common_lib; LIBRARY IEEE, common_lib;
USE IEEE.STD_LOGIC_1164.ALL; USE IEEE.STD_LOGIC_1164.ALL;
USE common_lib.common_pkg.ALL; USE common_lib.common_pkg.ALL;
USE common_lib.common_mem_pkg.ALL; USE common_lib.common_mem_pkg.ALL;
ENTITY mm_bus_comb IS ENTITY mm_bus_comb IS
GENERIC ( GENERIC (
g_nof_slaves : POSITIVE; -- Number of MM slave interfaces on the bus g_nof_slaves : POSITIVE; -- Number of MM slave interfaces on the bus
g_base_arr : t_nat_natural_arr; -- Address base per slave g_base_arr : t_nat_natural_arr; -- Address base per slave
g_width_arr : t_nat_natural_arr; -- Address width per slave g_width_arr : t_nat_natural_arr; -- Address width per slave
g_rd_latency_arr : t_nat_natural_arr -- Read latency per slave g_rd_latency_arr : t_nat_natural_arr -- Read latency per slave
); );
PORT ( PORT (
mm_clk : IN STD_LOGIC := '0'; mm_clk : IN STD_LOGIC := '0';
master_mosi : IN t_mem_mosi; master_mosi : IN t_mem_mosi;
master_miso : OUT t_mem_miso; master_miso : OUT t_mem_miso;
slave_mosi_arr : OUT t_mem_mosi_arr(0 TO g_nof_slaves-1); slave_mosi_arr : OUT t_mem_mosi_arr(0 TO g_nof_slaves-1);
slave_miso_arr : IN t_mem_miso_arr(0 TO g_nof_slaves-1) := (OTHERS=>c_mem_miso_rst) slave_miso_arr : IN t_mem_miso_arr(0 TO g_nof_slaves-1) := (OTHERS=>c_mem_miso_rst)
); );
END mm_bus_comb; END mm_bus_comb;
ARCHITECTURE rtl OF mm_bus_comb IS ARCHITECTURE rtl OF mm_bus_comb IS
-- Determine the address range of all slaves on the MM bus. -- Determine the address range of all slaves on the MM bus.
FUNCTION func_derive_mm_bus_addr_w(g_base_arr, g_width_arr : t_nat_natural_arr) RETURN NATURAL IS FUNCTION func_derive_mm_bus_addr_w(g_base_arr, g_width_arr : t_nat_natural_arr) RETURN NATURAL IS
VARIABLE v_base : NATURAL := 0; VARIABLE v_base : NATURAL := 0;
VARIABLE v_width : NATURAL; VARIABLE v_width : NATURAL;
VARIABLE v_mm_bus_addr_max : NATURAL; VARIABLE v_mm_bus_addr_max : NATURAL;
BEGIN BEGIN
FOR I IN g_base_arr'RANGE LOOP FOR I IN g_base_arr'RANGE LOOP
IF g_base_arr(I) > v_base THEN IF g_base_arr(I) > v_base THEN
v_base := g_base_arr(I); v_base := g_base_arr(I);
v_width := g_width_arr(I); v_width := g_width_arr(I);
END IF; END IF;
END LOOP; END LOOP;
-- Largest base address + the width of the slave at this address - 1. The -- Largest base address + the width of the slave at this address - 1. The
-- -1 is because the addresses count from 0 to N-1. -- -1 is because the addresses count from 0 to N-1.
v_mm_bus_addr_max := v_base + 2**v_width - 1; v_mm_bus_addr_max := v_base + 2**v_width - 1;
-- Return number of bits to represent the largest address that will be used -- Return number of bits to represent the largest address that will be used
-- on the MM bus -- on the MM bus
RETURN ceil_log2(v_mm_bus_addr_max); RETURN ceil_log2(v_mm_bus_addr_max);
END; END;
CONSTANT c_mm_bus_addr_w : NATURAL := func_derive_mm_bus_addr_w(g_base_arr, g_width_arr); CONSTANT c_mm_bus_addr_w : NATURAL := func_derive_mm_bus_addr_w(g_base_arr, g_width_arr);
CONSTANT c_rd_latency_max : NATURAL := largest(g_rd_latency_arr); CONSTANT c_rd_latency_max : NATURAL := largest(g_rd_latency_arr);
SIGNAL slave_index_arr : t_nat_natural_arr(0 TO c_rd_latency_max) := (OTHERS=>0); SIGNAL slave_index_arr : t_nat_natural_arr(0 TO c_rd_latency_max) := (OTHERS=>0);
BEGIN BEGIN
gen_single : IF g_nof_slaves=1 GENERATE gen_single : IF g_nof_slaves=1 GENERATE
slave_mosi_arr(0) <= master_mosi; slave_mosi_arr(0) <= master_mosi;
master_miso <= slave_miso_arr(0); master_miso <= slave_miso_arr(0);
END GENERATE; END GENERATE;
gen_multiple : IF g_nof_slaves>1 GENERATE gen_multiple : IF g_nof_slaves>1 GENERATE
-- Detect which slave in the array is addressed -- Detect which slave in the array is addressed
p_index : PROCESS(master_mosi) p_index : PROCESS(master_mosi)
VARIABLE v_base : NATURAL; VARIABLE v_base : NATURAL;
BEGIN BEGIN
slave_index_arr(0) <= g_nof_slaves; -- default index of none existing slave slave_index_arr(0) <= g_nof_slaves; -- default index of none existing slave
FOR I IN 0 TO g_nof_slaves-1 LOOP FOR I IN 0 TO g_nof_slaves-1 LOOP
v_base := TO_UINT(master_mosi.address(c_mm_bus_addr_w-1 DOWNTO g_width_arr(I))); v_base := TO_UINT(master_mosi.address(c_mm_bus_addr_w-1 DOWNTO g_width_arr(I)));
ASSERT g_base_arr(I) MOD 2**g_width_arr(I) = 0 REPORT "Slave base address must be a multiple of the slave width." SEVERITY FAILURE; ASSERT g_base_arr(I) MOD 2**g_width_arr(I) = 0 REPORT "Slave base address must be a multiple of the slave width." SEVERITY FAILURE;
IF v_base = g_base_arr(I) / 2**g_width_arr(I) THEN IF v_base = g_base_arr(I) / 2**g_width_arr(I) THEN
slave_index_arr(0) <= I; -- return index of addressed slave slave_index_arr(0) <= I; -- return index of addressed slave
EXIT; EXIT;
END IF; END IF;
END LOOP; END LOOP;
END PROCESS; END PROCESS;
slave_index_arr(1 TO c_rd_latency_max) <= slave_index_arr(0 TO c_rd_latency_max-1) WHEN rising_edge(mm_clk); slave_index_arr(1 TO c_rd_latency_max) <= slave_index_arr(0 TO c_rd_latency_max-1) WHEN rising_edge(mm_clk);
-- Master access, can be write or read -- Master access, can be write or read
p_slave_mosi_arr : PROCESS(master_mosi, slave_index_arr) p_slave_mosi_arr : PROCESS(master_mosi, slave_index_arr)
BEGIN BEGIN
slave_mosi_arr <= (OTHERS=>master_mosi); -- default assign to all, to avoid latches slave_mosi_arr <= (OTHERS=>master_mosi); -- default assign to all, to avoid latches
FOR I IN 0 TO g_nof_slaves-1 LOOP FOR I IN 0 TO g_nof_slaves-1 LOOP
slave_mosi_arr(I).rd <= '0'; slave_mosi_arr(I).rd <= '0';
slave_mosi_arr(I).wr <= '0'; slave_mosi_arr(I).wr <= '0';
IF I = slave_index_arr(0) THEN -- check index for read or write access IF I = slave_index_arr(0) THEN -- check index for read or write access
slave_mosi_arr(I).rd <= master_mosi.rd; slave_mosi_arr(I).rd <= master_mosi.rd;
slave_mosi_arr(I).wr <= master_mosi.wr; slave_mosi_arr(I).wr <= master_mosi.wr;
END IF; END IF;
END LOOP; END LOOP;
END PROCESS; END PROCESS;
-- Slave response to read access after read latency mm_clk cycles -- Slave response to read access after read latency mm_clk cycles
p_master_miso : PROCESS(slave_miso_arr, slave_index_arr) p_master_miso : PROCESS(slave_miso_arr, slave_index_arr)
VARIABLE v_rd_latency : NATURAL; VARIABLE v_rd_latency : NATURAL;
BEGIN BEGIN
master_miso <= c_mem_miso_rst; -- default clear, to avoid latches master_miso <= c_mem_miso_rst; -- default clear, to avoid latches
FOR I IN 0 TO g_nof_slaves-1 LOOP FOR I IN 0 TO g_nof_slaves-1 LOOP
v_rd_latency := g_rd_latency_arr(I); v_rd_latency := g_rd_latency_arr(I);
IF I = slave_index_arr(v_rd_latency) THEN -- check index for read response IF I = slave_index_arr(v_rd_latency) THEN -- check index for read response
master_miso <= slave_miso_arr(I); master_miso <= slave_miso_arr(I);
END IF; END IF;
END LOOP; END LOOP;
FOR I IN 0 TO g_nof_slaves-1 LOOP FOR I IN 0 TO g_nof_slaves-1 LOOP
IF I = slave_index_arr(0) THEN -- check index for waitrequest IF I = slave_index_arr(0) THEN -- check index for waitrequest
master_miso.waitrequest <= slave_miso_arr(I).waitrequest; master_miso.waitrequest <= slave_miso_arr(I).waitrequest;
END IF; END IF;
END LOOP; END LOOP;
END PROCESS; END PROCESS;
END GENERATE; END GENERATE;
END rtl; END rtl;
...@@ -107,7 +107,10 @@ BEGIN ...@@ -107,7 +107,10 @@ BEGIN
FOR I IN 0 TO g_nof_masters-1 LOOP FOR I IN 0 TO g_nof_masters-1 LOOP
IF master_mosi_arr(I).wr='1' OR master_mosi_arr(I).rd='1' THEN IF master_mosi_arr(I).wr='1' OR master_mosi_arr(I).rd='1' THEN
index <= I; -- index of active master index <= I; -- index of active master
EXIT; EXIT; -- Found active master, no need to loop further. EXIT is not
-- realy needed, because there should be only one active
-- master, and if there are more active masters, then it
-- does not matter whether the first or the last is selected.
END IF; END IF;
END LOOP; END LOOP;
END PROCESS; END PROCESS;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment