Перейти к содержанию
    

описание двухпортовой памяти с CS

Добрый день

подскажите пожалуйста как правильно описать двухпортовую память с CS(Chip select) (altera)

такое решение

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use IEEE.NUMERIC_STD.ALL;


entity bram_tdp is
generic (
    DATA    : integer := 32;
    ADDR    : integer := 12
);
port (
    -- Port A
    a_clk   : in  std_logic;
    ena     : in  std_logic;--
	 a_wr    : in  std_logic;
    a_addr  : in  std_logic_vector(ADDR-1 downto 0);
    a_din   : in  std_logic_vector(DATA-1 downto 0);
    a_dout  : out std_logic_vector(DATA-1 downto 0);

    -- Port B
    b_clk   : in  std_logic;
	 enb     : in  std_logic;--
    b_wr    : in  std_logic;
    b_addr  : in  std_logic_vector(ADDR-1 downto 0);
    b_din   : in  std_logic_vector(DATA-1 downto 0);
    b_dout  : out std_logic_vector(DATA-1 downto 0)
);
end bram_tdp;

architecture rtl of bram_tdp is
    -- Shared memory
    type mem_type is array ( (2**ADDR)-1 downto 0 ) of std_logic_vector(DATA-1 downto 0);
    
    FUNCTION initialize_ram  return mem_type is variable result : mem_type;
    BEGIN
		FOR i IN ((2**ADDR)-1) DOWNTO 0 LOOP
			result(i) := std_logic_vector( to_unsigned(natural(i), natural'((DATA))));
		END LOOP;
    RETURN result;
    END initialize_ram;
    
	 shared variable mem : mem_type := initialize_ram;
    --shared variable mem : mem_type := (others => (others => '0')); -- := initialize_ram;
begin

-- Port A
process(a_clk)
begin
    if(a_clk'event and a_clk='1') then
       if ena = '1' then --
		 if(a_wr='1') then
            mem(conv_integer(a_addr)) := a_din;
        end if;
        a_dout <= mem(conv_integer(a_addr));
    end if; --
	 end if;
end process;

-- Port B
process(b_clk)
begin
   if(b_clk'event and b_clk='1') then
		  if enb = '1' then	--
        if(b_wr='1') then
            mem(conv_integer(b_addr)) := b_din;
        end if;
        b_dout <= mem(conv_integer(b_addr));
    end if;  --
	 end if;
end process;

end rtl;

мне кажется не коректным т.к.  не задействуется порт CS (technology viewer) - вложение.

Основной вопрос как осуществить доступ к нескольким портам памяти (BRAM) имея один вход:

Шина данных

Шина адреса

Сигнал WE

Решение через сигнал WE мне кажется не очень быстродейственным - большой mux.

Мне надо соедениться с 16 памятями - чтобы их инициализировать

Можно конечно сделать pipeline.

Может у кого есть более оригинальные решения?

PS Для avalon MM для соединения мастера со многими слейвами MM - все намного проще
"Chip select signal to the slave. The slave port should ignore all other Avalon signal inputs unless chipselect is asserted."

 

 

 

 

bram.png

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Насчет возможности с помощью Core Generator я  знаю...

Начал сомневаться что описать память с Chip select можно - только через Core Generator

Вот еще архитектура для записи - вложение

photo_2021-11-30_13-50-25.jpg

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 hour ago, Maverick_ said:

подскажите пожалуйста как правильно описать двухпортовую память с CS(Chip select) (altera)

такое решение

мне кажется не коректным т.к.  не задействуется порт CS (technology viewer) - вложение.

ReadEnable/WriteEnable задействованы. Работают как clock_enable. Вам не нравиться что именно сам порт inclkockena не задействован? А есть разница?

Quote

Решение через сигнал WE мне кажется не очень быстродейственным - большой mux.

Не большой мукс, а несколько декодеров. Вы же пишете. Для 16 блоков памяти это будет 16 LUT5, использовать триггер по выбору.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

des00 спасибо за подсказку...

Добрый день. (update)

есть несколько индентичных модулей (размножены с помощью generic).

Модуль выдает ready как данные готовы. Все модули ready  выдать одновремнно не могут - только один срабатывет

Выход каждого модуля это порт памяти с которого необходимо прочитать результат обработки после ready = '1'.

Вопрос как мне определить с какого модуля мне надо забрать данные и как построить мультиплексор к портам памяти (возможно есть другие красивые решения).

Мое решение сложное - как по мне: ниже ход мыслей

Объеденяем все ready от модулей  в один регистр, далее

module bitscan (req,sel);
parameter WIDTH = 16;
input [WIDTH-1:0] req;
output [WIDTH-1:0] sel;

assign sel = req & ~(req-1);

endmodule

(что делает этот модуль во вложении картинка)

от результата отнимаем 1 и считаем количество едениц
ответом и будет номер модуля с какого модуля мне надо забрать данные в котором сработал ready

Потом мультиплексор ...

library ieee ;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;


entity mux4 is
port(
d0 : in std_logic_vector(1 downto 0);
d1 : in std_logic_vector(1 downto 0);
d2 : in std_logic_vector(1 downto 0);
d3 : in std_logic_vector(1 downto 0);
s : in std_logic_vector(1 downto 0);
m : out std_logic_vector(1 downto 0));
end mux4;

architecture rtl of mux4 is
type t_array_mux is array (0 to 3) of std_logic_vector(1 downto 0);
signal array_mux : t_array_mux;

begin

array_mux(0) <= d0;
array_mux(1) <= d1;
array_mux(2) <= d2;
array_mux(3) <= d3;

m <= array_mux(to_integer(unsigned(s)));

end rtl;

Для шины адреса и данных - необходимых для чтения из памяти (BRAM)


 

Интересуют идеи по реализации.

scan1.PNG

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Приветствую!

1 hour ago, Maverick_ said:

Вопрос как мне определить с какого модуля мне надо забрать данные.

Тут надо уточнить что значит (для чего) "... определить с какого"?  Получить бинарный код?  Ну и доп. условие - могут ли быть одновременно несколько ready? Если да  то каков приоритет выбора?  
Если одновременно может быть только один ready и бинарный код не нужен то объединять шины можно через простой AND-OR мукс.      

Удачи! Rob.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Дополню задачу - внесу более четкость

Выход каждого модуля это порт памяти с которого необходимо прочитать результат обработки после ready = '1'

Давайте пока считать что только 1 ready = '1' может быть

Предыдущий пост дополнил для ясности задачи

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

38 минут назад, Maverick_ сказал:

Дополню задачу - внесу более четкость

Выход каждого модуля это порт памяти с которого необходимо прочитать результат обработки после ready = '1'

Давайте пока считать что только 1 ready = '1' может быть

Предыдущий пост дополнил для ясности задачи

1. Простой round_robin

2. Нашли первую единичку в векторе -> прочитали эту память -> обунлили этот сигнал -> Нашли первую единичку в векторе...

3. Обычный кольцевой арбитр.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

22 minutes ago, Flip-fl0p said:

1. Простой round_robin

2. Нашли первую единичку в векторе -> прочитали эту память -> обунлили этот сигнал -> Нашли первую единичку в векторе...

3. Обычный кольцевой арбитр.

можно поподробнее пожалуйста особенно второй пункт с намеком на схемотехнику...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

22 минуты назад, Maverick_ сказал:

можно поподробнее пожалуйста особенно второй пункт. У меня проблема что не могу в оптимальную схемотехнику перевести ... из за этого и прошу помощи

Есть старый математический трюк   b = a & (-a) 

Он возвращает вектор где все значения нули, кроме првого бита, где есть лог. 1. Вы как раз картинку этого выложили. 

Я для этого имею функцию

    --===========================================================
    -- Получить вектор, где есть только старший бит
    --===========================================================
    function GET_LSB_ON_VECTOR
    (
        data : std_logic_vector
    )
        return std_logic_vector is 
        variable minus_data   : std_logic_vector(data'left downto 0);
        variable b         : std_logic_vector(data'left downto 0);
        
    begin
        minus_data := std_logic_vector(unsigned(not data) + "1");     -- Получаем отрицательное значение      -a
        b          := data and minus_data;                            -- Умножаем их                           a & (-a)
        return b;
    end function;

Ну а далее простой FSM. 

Анализируем вектор b ---> Вектор b != 0  ---> запускаем чтение из памяти по адресу памяти который выставил ready (адрес определяем как раз таки при помощи этого вектора b, операцией обратной декодеру) ---> данные прочитаны ---> обнуляем сигал ready этой памяти ---> Анализируем вектор b.

Например

1. Имеем 4 памяти.

2. Внезапно  и одномоментно вектор  ready стал "1010"

3. пользуемся трюком и получаем вектор b = "0010"

4. Подаем вектор b на энкодер - и получаем addr = 1

case b is
    when "0001"  => addr <= "00";
    when "0010"  => addr <= "01";
    when "0100"  => addr <= "10";
    when "1000"  => addr <= "11";
    when "others => addr <= "--";
end case;

5. Читаем память с адресом addr = 1.

6. После чтения памяти обнуляем соответствующий ready. Т.е было ready  = 1010, стало ready  = 1000.

7. Опа ! У нас ready = 1000

8. пользуемся трюком и получаем вектор b = "1000"

9 ..... 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 minute ago, Flip-fl0p said:

Есть старый математический трюк   b = a & (-a) 

Он возвращает вектор где все значения нули, кроме првого бита, где есть лог. 1. Вы как раз картинку этого выложили. 

Я для этого имею функцию


    --===========================================================
    -- Получить вектор, где есть только старший бит
    --===========================================================
    function GET_LSB_ON_VECTOR
    (
        data : std_logic_vector
    )
        return std_logic_vector is 
        variable minus_data   : std_logic_vector(data'left downto 0);
        variable b         : std_logic_vector(data'left downto 0);
        
    begin
        minus_data := std_logic_vector(unsigned(not data) + "1");     -- Получаем отрицательное значение      -a
        b          := data and minus_data;                            -- Умножаем их                           a & (-a)
        return b;
    end function;

Ну а далее простой FSM. 

Анализируем вектор b ---> Вектор b != 0  ---> запускаем чтение из памяти по адресу памяти который выставил ready (адрес определяем как раз таки при помощи этого вектора b, операцией обратной декодеру) ---> данные прочитаны ---> обнуляем сигал ready этой памяти ---> Анализируем вектор b.

Например

1. Имеем 4 памяти.

2. Внезапно  и одномоментно вектор  ready стал "1010"

3. пользуемся трюком и получаем вектор b = "0010"

4. Подаем вектор b на энкодер - и получаем addr = 1


case b is
    when "0001"  => addr <= "00";
    when "0010"  => addr <= "01";
    when "0100"  => addr <= "10";
    when "1000"  => addr <= "11";
    when "others => addr <= "--";
end case;

5. Читаем память с адресом addr = 1.

6. После чтения памяти обнуляем соответствующий ready. Т.е было ready  = 1010, стало ready  = 1000.

7. Опа ! У нас ready = 1000

8. пользуемся трюком и получаем вектор b = "1000"

9 ..... 

 

мне пока нравиться решение

Спасибо

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

13 hours ago, Maverick_ said:

Давайте пока считать что только 1 ready = '1' может быть

если уникальный 146% и будет уникальный до окончания чтения памяти, то, как написал @RobFPGA AND-OR мультиплексор,

Если не уникальный то либо простой приоритетный арбитраж, как предложил @Flip-fl0p или RRA арбитр. Вот псевдокод ядра RRA

  typedef logic      [pN-1 : 0] request_t;
  typedef logic [pN_LOG2-1 : 0] winner_t;

  logic     request     ;
  winner_t  last_winner ;
  winner_t  winner      ;

  assign request  = (ireq != 0);
  assign winner   = get_winner(ireq, last_winner);

  always_ff @(posedge iclk) begin
    if (request) begin
      last_winner   <= winner;
      grant <= '0;
      grant[winner] <= request;
    end
  end

  function automatic winner_t get_winner (input request_t request, input winner_t last_winner);
    get_winner = last_winner;
    //
    for (int i = 0; i < pN; i++) begin
      get_winner = get_winner + 1'b1;
      if (get_winner == pN) begin
        get_winner = 0;
      end
      if (request [get_winner]) begin
        return get_winner;
      end
    end
  endfunction

ну а дальше уже, зная того кто победил, интегрируете это в ваш FSM по чтению

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

12 часов назад, Flip-fl0p сказал:

variable minus_data : std_logic_vector(data'left downto 0);

Занудства ради.

Вы рассчитываете на то, что в вашу функцию будут передавться только вектора с индексацией (N downto 0). А вдруг ей передадут вектор (N downto M)? Или тем паче (M to N)?

 

 

12 часов назад, Flip-fl0p сказал:

minus_data := std_logic_vector(unsigned(not data) + "1"); -- Получаем отрицательное значение -a

Почему не

minus_data := std_logic_vector(-signed(data));

?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

9 часов назад, andrew_b сказал:

Занудства ради.

Вы рассчитываете на то, что в вашу функцию будут передавться только вектора с индексацией (N downto 0). А вдруг ей передадут вектор (N downto M)? Или тем паче (M to N)?

 

 

Почему не


minus_data := std_logic_vector(-signed(data));

?

Функцию писал для себя. Я почти никогда не пользуюсь векторами(M to N). Ну разве что описание массивов исключение из этого правила. А разве при передаче в функцию Вектора N downto M этот вектор в функции не будет автоматом считаться (M-N downto 0) ? 

minus_data := std_logic_vector(-signed(data));

До этого не додумался :blush:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2 часа назад, Flip-fl0p сказал:

Функцию писал для себя. Я почти никогда не пользуюсь векторами(M to N).

Нет никаких сложностей сделать универсальную функцию.

2 часа назад, Flip-fl0p сказал:

А разве при передаче в функцию Вектора N downto M этот вектор в функции не будет автоматом считаться (M-N downto 0) ? 

А на каком основании? Чем 0 лучше любого другого числа?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...