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

Интересен пример описания блочной памяти, где были бы два независимых конфигурируемых порта по записи и по чтению, с такой синтезируемой моделью можно легко будет делать преобразователи из последовательного в параллельный код, минуя сдвиговые регистры (сейчас я с ними делаю).

Какие есть решения по данной реализации на Verilog (VHDL), чтобы ещё и понятно было :)? выкладывайте.

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


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

Интересен пример описания блочной памяти, где были бы два независимых конфигурируемых порта по записи и по чтению, с такой синтезируемой моделью можно легко будет делать преобразователи из последовательного в параллельный код, минуя сдвиговые регистры (сейчас я с ними делаю).

Обсуждалось.

Какие есть решения по данной реализации на Verilog (VHDL), чтобы ещё и понятно было :)? выкладывайте.

Используйте поиск.

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


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

Интересен пример описания блочной памяти, где были бы два независимых конфигурируемых порта по записи и по чтению, с такой синтезируемой моделью можно легко будет делать преобразователи из последовательного в параллельный код, минуя сдвиговые регистры (сейчас я с ними делаю).

Какие есть решения по данной реализации на Verilog (VHDL), чтобы ещё и понятно было :)? выкладывайте.

У ксайлинсков около 10 апнот на эту тему!!!!!!!!

ищите по BLOCK RAM DATA WIDTH CONVERTION FIFO

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


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

Если это обсуждалось (в чем я сильно сомневаюсь), дайте ссылочку, пожалуйста, то же и по appnotes, использовал для примера CORE Generator, он сослался на библиотечный элемент BLKMEMDP_V6_1.v, слишком все тяжело описано в нем, разобраться не могу, сам придумал реализацию, по крайней мере в моделе всё как и задумывалось:

<==================================================

/* ОБЪЯВЛЕНИЕ МОДУЛЯ */

module C_DPINDEP_RAM

/*-----------------------------------------------------------------------------

* Объявление параметров:

*/

#(

parameter

WIDTH_WR_DATA = 1,

WIDTH_WR_ADDR = 12,

DEPTH_WR = (1<<WIDTH_WR_ADDR),

 

WIDTH_RD_DATA = 8,

WIDTH_RD_ADDR = 9

)

/*-----------------------------------------------------------------------------

* Объявление портов:

*/

(

// порт записи

input

i_WR_CLK, // тактовый импульс записи

 

i_WR_EN, // строб разрешения записи

 

input [(WIDTH_WR_DATA-1): 0]

i_WR_DATA,// шина данных записи

 

input [(WIDTH_WR_ADDR-1): 0]

i_WR_ADDR,// адресная шина записи

 

// порт чтения

input

i_RD_CLK, // тактовый импульс чтения

 

input [(WIDTH_RD_ADDR-1): 0]

i_RD_ADDR, // адресная шина чтения

 

output reg [(WIDTH_RD_DATA-1): 0]

o_RD_DATA // шина данных чтения

);

/*-----------------------------------------------------------------------------

* Объявление сигналов:

*/

reg R_tmp_mem [(WIDTH_WR_DATA*DEPTH_WR-1):0];

reg [(WIDTH_RD_ADDR-1): 0] R_rd_addr;

integer j, k;

 

/* synthesis translate_off */

integer i;

initial begin

for (i = 0; i < WIDTH_WR_DATA*DEPTH_WR; i= i + 1)

R_tmp_mem <= 1'b0;

 

R_rd_addr <= {WIDTH_RD_ADDR{1'b0}};

end

/* synthesis translate_on */

 

/*-----------------------------------------------------------------------------

* Основной код:

*/

always @(posedge i_WR_CLK) begin

if (i_WR_EN)

for (j = 0; j < WIDTH_WR_DATA; j = j + 1)

R_tmp_mem[(i_WR_ADDR * WIDTH_WR_DATA) + j] <= i_WR_DATA[j];

end

 

always @(posedge i_RD_CLK) begin

R_rd_addr <= i_RD_ADDR;

end

 

always @*//(posedge i_RD_CLK) <=== пробовал и в комментарии и без

for (k = 0; k < WIDTH_RD_DATA; k = k + 1)

o_RD_DATA[k] = R_tmp_mem[(R_rd_addr * WIDTH_RD_DATA) + k];

 

endmodule

<==================================================

 

только вот беда, синтезатор (Symplify_pro8.1) не берет это описание как БЛОЧНУЮ ПАМЯТЬ, и пишет: Could not implement Block RAM. Is the read address registered using the same clock as the RAM?

 

Как правильно описать такую модель для Блочной памяти?

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


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

Если это обсуждалось (в чем я сильно сомневаюсь), дайте ссылочку, пожалуйста, то же и по appnotes, использовал для примера CORE Generator, он сослался на библиотечный элемент BLKMEMDP_V6_1.v, слишком все тяжело описано в нем, разобраться не могу, сам придумал реализацию, по крайней мере в моделе всё как и задумывалось:

<==================================================

/*  ОБЪЯВЛЕНИЕ МОДУЛЯ  */

module C_DPINDEP_RAM

/*-----------------------------------------------------------------------------

*  Объявление параметров:

*/

#(

parameter

WIDTH_WR_DATA = 1,

WIDTH_WR_ADDR = 12,

DEPTH_WR = (1<<WIDTH_WR_ADDR),

 

WIDTH_RD_DATA = 8,

WIDTH_RD_ADDR = 9

)

/*-----------------------------------------------------------------------------

* Объявление портов:

*/

(

// порт записи

input

i_WR_CLK, // тактовый импульс записи

 

i_WR_EN, // строб разрешения записи

 

input [(WIDTH_WR_DATA-1): 0]

i_WR_DATA,// шина данных записи

 

input [(WIDTH_WR_ADDR-1): 0]

i_WR_ADDR,// адресная шина записи

 

// порт чтения

input

i_RD_CLK, // тактовый импульс чтения

 

input [(WIDTH_RD_ADDR-1): 0]

i_RD_ADDR, // адресная шина чтения

 

output reg [(WIDTH_RD_DATA-1): 0]

o_RD_DATA // шина данных чтения

);

/*-----------------------------------------------------------------------------

* Объявление сигналов:

*/

reg R_tmp_mem [(WIDTH_WR_DATA*DEPTH_WR-1):0];

reg [(WIDTH_RD_ADDR-1): 0] R_rd_addr;

integer j, k;

 

/* synthesis translate_off */

integer i;

initial begin

for (i = 0; i < WIDTH_WR_DATA*DEPTH_WR; i= i + 1)

R_tmp_mem <= 1'b0;

 

R_rd_addr <= {WIDTH_RD_ADDR{1'b0}};

end

/* synthesis translate_on */

 

/*-----------------------------------------------------------------------------

* Основной код:

*/

always @(posedge i_WR_CLK) begin

if (i_WR_EN)

for (j = 0; j < WIDTH_WR_DATA; j = j + 1)

R_tmp_mem[(i_WR_ADDR * WIDTH_WR_DATA) + j] <= i_WR_DATA[j];

end

 

always @(posedge i_RD_CLK) begin

R_rd_addr <= i_RD_ADDR;

end

 

always @*//(posedge i_RD_CLK)  <=== пробовал и в комментарии и без

for (k = 0; k < WIDTH_RD_DATA; k = k + 1)

o_RD_DATA[k] = R_tmp_mem[(R_rd_addr * WIDTH_RD_DATA) + k];

 

endmodule

<==================================================

 

только вот беда, синтезатор (Symplify_pro8.1) не берет это описание как БЛОЧНУЮ ПАМЯТЬ, и пишет: Could not implement Block RAM. Is the read address registered using the same clock as the RAM?

 

Как правильно описать такую модель для Блочной памяти?

Зачем core generator !!!!!!!

XAPP205 - Data-Width Conversion FIFOs Using the Virtex Block SelectRAM Memory

XAPP261 - Data-Width Conversion FIFOs Using the Virtex-II Block RAM Memory

XAPP258 - FIFOs Using Virtex-II Block RAM

и т.д.

просто берем компоненит RAMB_16 и конфигурим его ручками

-- Component declaration of the "ramb16(ramb16_v)" unit defined in
    -- file: "./src/unisim_vital.vhd"
    component ramb16
    generic(
 DOA_REG : INTEGER := 0;
 DOB_REG : INTEGER := 0;
INVERT_CLK_DOA_REG : BOOLEAN := false;
 INVERT_CLK_DOB_REG : BOOLEAN := false;
 RAM_EXTENSION_A : STRING := "NONE";
 RAM_EXTENSION_B : STRING := "NONE";
 READ_WIDTH_A : INTEGER := 0;
 READ_WIDTH_B : INTEGER := 0;
 SIM_COLLISION_CHECK : STRING := "ALL";
 SRVAL_A : BIT_VECTOR := X"000000000";
 SRVAL_B : BIT_VECTOR := X"000000000";
 WRITE_MODE_A : STRING := "WRITE_FIRST";
 WRITE_MODE_B : STRING := "WRITE_FIRST";
 WRITE_WIDTH_A : INTEGER := 0;
 WRITE_WIDTH_B : INTEGER := 0);
    port(
 CASCADEOUTA : out std_ulogic;
 CASCADEOUTB : out std_ulogic;
 DOA : out std_logic_vector(31 downto 0);
 DOB : out std_logic_vector(31 downto 0);
 DOPA : out std_logic_vector(3 downto 0);
 DOPB : out std_logic_vector(3 downto 0);
 ADDRA : in std_logic_vector(14 downto 0);
 ADDRB : in std_logic_vector(14 downto 0);
 CASCADEINA : in std_ulogic;
 CASCADEINB : in std_ulogic;
 CLKA : in std_ulogic;
 CLKB : in std_ulogic;
 DIA : in std_logic_vector(31 downto 0);
 DIB : in std_logic_vector(31 downto 0);
 DIPA : in std_logic_vector(3 downto 0);
 DIPB : in std_logic_vector(3 downto 0);
 ENA : in std_ulogic;
 ENB : in std_ulogic;
 REGCEA : in std_ulogic;
 REGCEB : in std_ulogic;
 SSRA : in std_ulogic;
 SSRB : in std_ulogic;
 WEA : in std_logic_vector(3 downto 0);
 WEB : in std_logic_vector(3 downto 0));
    end component;
    for all: ramb16 use entity unisim.ramb16(ramb16_v);

если уже совсем не в моготу то пользуем уже готовый компоненты библитеки унисим типа RAMB_X_X.

Все это описанно в Lib Guide

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


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

На харр дал ссылки это очень хорошо, спасибо, только вернемся к вопросу, необходимо не ручками брать "готовый компоненты библиотеки унисим типа RAMB_X_X" и конфигурить их, а было бы классно, чтобы синтезатор сам понимал, что из описания модели RAM сделать блочную память, к примеру, как есть описание из Language Templates ISE, которое он в дальнейщем понимает как Block Ram, так и здеcь хотелось бы тоже самое.

Это делает код более мобильным и переносимым на другие ПЛИС, ASIC.

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


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

Это делает код более мобильным и переносимым на другие ПЛИС, ASIC.

Ну во первых это боольшой вопрос, т.к. :

1. Вам "повезло" с семейством, т.к. разная ширина шин у кмпонента это "фишка" данного семества и на "другие" так просто не переноситься.

2. Если вы хотите универсальности в ручную мапте адреса и демультиплексируете потоки.(как и сделано в компоненте). Но вот мне не удалось сказать синтезатору ИСЕ и симплифай (даже с контрейнами) что то что я описал на языке должно быть не блоком памяти с мультеплексором, а одним компонентом.

 

А так это описываеться элементарно, а вот синтезируеться ......

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


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

Как мы все дружно решаем данную ситуацию, давайте, парни, поднапряжемся, кто-нибудь найдет решение :).

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


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

Как мы все дружно решаем данную ситуацию, давайте, парни, поднапряжемся, кто-нибудь найдет решение :).

 

Ты скажи русским/английским языком что тебе надо ?? :glare:

Если память сконфигуровать то читай апноты или руками конфигури.

Если описать на языке то принцип тебе расказали,

или ты хочешь что бы тебе еще и код с коментариями запостили ?? ну ты ленивый

:excl:

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


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

Возможно ты прав, возможно я и ленивый, если ты ставишь вопрос таким образом, то:

1) помоги найди некорректность в моем описании на Verilog выложенное выше.

2) расскажи ещё раз принцип описания на языке, я его что-то не увидел здесь.

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


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

Возможно ты прав, возможно я и ленивый, если ты ставишь вопрос таким образом, то:

1) помоги найди некорректность в моем описании на Verilog выложенное выше.

2) расскажи ещё раз принцип описания на языке, я его что-то не увидел здесь.

 

мне бежать надо по этому вкратце

1. порт записи 32 бита, адрес 8 бит. порт чтения 16 бит адресс 9 бит

пишем просто по входным адресам, когда читаем

первые 8 бит это адрес памяти, младший бит на выходной мультиплексор.

2. если наоборотт, то мультиплексируем сигнал разрешения записи. младшим битом а старшие 8 бит на адресс.

 

В твоем описании (подробно не смотрел) симплифай ругаеться, т.к. у тебя есть массив пр.32 по 32 бита а ты почему то решил из него сделать 64 на 16 бит, адреса не совпадають :)

удачи

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


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

мне бежать надо по этому вкратце

1. порт записи 32 бита, адрес 8 бит. порт чтения 16 бит адресс 9 бит

пишем просто по входным адресам, когда читаем

первые 8 бит это адрес памяти, младший бит на выходной мультиплексор.

2. если наоборотт, то мультиплексируем сигнал разрешения записи.  младшим битом а старшие 8 бит на адресс.

 

В твоем описании (подробно не смотрел) симплифай ругаеться, т.к. у тебя есть массив пр.32 по 32 бита а ты почему то решил из него сделать 64 на 16 бит, адреса не совпадають :)

удачи

 

то что ты вкратце описал, не очень красивое решение, т.к. все равно обращаешься на компоненты памяти, или я не прав?

Да и было бы интереснее если бы ты показал на примере <== что ты имеешь ввиду

 

Моё описание корректно:

parameter

WIDTH_WR_DATA = 1,

WIDTH_WR_ADDR = 12,

DEPTH_WR = (1<<WIDTH_WR_ADDR), // это будет 2**12=4096 <==

WIDTH_RD_DATA = 8,

WIDTH_RD_ADDR = 9

 

reg R_tmp_mem [(WIDTH_WR_DATA*DEPTH_WR-1):0];

reg [(WIDTH_RD_ADDR-1): 0] R_rd_addr;

 

отсюда:

reg R_tmp_mem [(1*4096-1):0];

reg [(9-1): 0] R_rd_addr; // 9 разрядный счетчик (2**9=512) по WIDTH_RD_DATA = 8

получается, что бит я покрываю 512*8=4096 при чтении, всё корректно.

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


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

то что ты вкратце описал, не очень красивое решение, т.к. все равно обращаешься на компоненты памяти, или я не прав?

Да и было бы интереснее если бы ты показал на примере <== что ты имеешь ввиду

правда на ВХДЛ но смысл бумаю будет понятен

library IEEE;
use IEEE.std_logic_1164.all;    
use IEEE.std_logic_arith.all;    
use IEEE.std_logic_unsigned.all;

library WORK;
use WORK.define_pkg.all;

entity RAM_16_DWC_Dev is 
   generic (WIDTH : integer := 16);
   port 
       (
       in_clock      : in std_logic;
       in_reset_b    : in std_logic;
       in_wr_data    : in std_logic_vector(4*WIDTH-1 downto 0);              
       in_wr_strobe  : in std_logic;
 in_wr_addr   : in std_logic_vector(3 downto 0);
       in_rd_addr   : in std_logic_vector(5 downto 0);
       out_rd_data   : out std_logic_vector(WIDTH-1 downto 0)
       ); 
end entity RAM_16_DWC_Dev;

architecture RAM_16_DWC_Dev of RAM_16_DWC_Dev is 
   
   type RAM_16 is array (0 to 7) of std_logic_vector(4*WIDTH-1 downto 0);
   signal mem : RAM_16; 
   attribute RAM_STYLE of mem : signal is "distributed";
    attribute SYN_RAMSTYLE of mem : signal is "select_ram";
   
begin
    mem_read_proc : 
    process(in_clock) is 
   variable reg0, reg1, reg2, reg3 : std_logic_vector(WIDTH-1 downto 0); 
    variable mem_data : std_logic_vector(4*WIDTH-1 downto 0);
    begin
       if (rising_edge(in_clock)) then 
     if (in_reset_b = '0') then
         out_rd_data <= (others => '0');
       else 
   mem_data := mem(conv_integer(in_rd_addr(5 downto 2)));  
   demux_data(mem_data, reg0, reg1, reg2, reg3);
   case (in_rd_addr(1 downto 0)) is 
             when "00" => out_rd_data <= reg0;
             when "01" => out_rd_data <= reg1;
             when "10" => out_rd_data <= reg2;
             when "11" => out_rd_data <= reg3;
       when others => null;
   end case;
     end if;
       end if;
   end process mem_read_proc;
   
   mem_write_proc : 
    process(in_clock) is
   begin                 
       if (rising_edge(in_clock)) then 
           if (in_wr_strobe = '1') then 
               mem(conv_integer(in_wr_addr)) <= in_wr_data;
           end if;
       end if;
   end process mem_write_proc;   
    
end architecture RAM_16_DWC_Dev;

насчет корректности твоего описания

 

reg R_tmp_mem [(WIDTH_WR_DATA*DEPTH_WR-1):0];

reg [(WIDTH_RD_ADDR-1): 0] R_rd_addr;

вот здесь ты объявляешь не память а регистр. А тебе нужна именно память, а не набор регистров.

 

reg R_tmp_mem [(1*4096-1):0];

reg [(9-1): 0] R_rd_addr; // 9 разрядный счетчик (2**9=512) по WIDTH_RD_DATA = 8

получается, что бит я покрываю 512*8=4096 при чтении, всё корректно.

А теперь скажи как ты будешь адресовать 8 ми битные слова ?

 

Мы разговариваем про разные вещи, память это двумерный массив. У памяти может быть 1-2 порта чтения записи, если же их больше, то это приведет к памяти на регистрах. Если у тебя их много то ......

а если нет ??

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


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

правда на ВХДЛ но смысл бумаю будет понятен

entity RAM_16_DWC_Dev is 
   generic (WIDTH : integer := 16);
   port 
       (
       in_clock      : in std_logic;
       in_reset_b    : in std_logic;
       in_wr_data    : in std_logic_vector(4*WIDTH-1 downto 0);              
       in_wr_strobe  : in std_logic;
 in_wr_addr   : in std_logic_vector(3 downto 0);
       in_rd_addr   : in std_logic_vector(5 downto 0);
       out_rd_data   : out std_logic_vector(WIDTH-1 downto 0)
       ); 
end entity RAM_16_DWC_Dev;

Ты изначально заложил то, что у тебя не может быть вход данных in_wr_data однобитовым

    mem_read_proc : 
    process(in_clock) is 
   variable reg0, reg1, reg2, reg3 : std_logic_vector(WIDTH-1 downto 0); 
    variable mem_data : std_logic_vector(4*WIDTH-1 downto 0);
    begin
       if (rising_edge(in_clock)) then 
     if (in_reset_b = '0') then
         out_rd_data <= (others => '0');
       else 
   mem_data := mem(conv_integer(in_rd_addr(5 downto 2)));  
   demux_data(mem_data, reg0, reg1, reg2, reg3);
   case (in_rd_addr(1 downto 0)) is 
             when "00" => out_rd_data <= reg0;
             when "01" => out_rd_data <= reg1;
             when "10" => out_rd_data <= reg2;
             when "11" => out_rd_data <= reg3;
       when others => null;
   end case;
     end if;
       end if;
   end process mem_read_proc;

Вот и мультиплексор вылез о котором ты и упоминал ранее

 

насчет корректности твоего описания

reg R_tmp_mem [(WIDTH_WR_DATA*DEPTH_WR-1):0];

reg [(WIDTH_RD_ADDR-1): 0] R_rd_addr;

вот здесь ты объявляешь не память а регистр. А тебе нужна именно память, а не набор регистров.

Поправь меня, если я не прав, память с разрядностью шины данных в один бит не существует? R_tmp_mem - длинная однобитовая память, с которой я и работаю в дальнейшем по записи и по чтению.

 

А теперь скажи как ты будешь адресовать 8 ми битные слова ?

для меня в этот момент важен перевод последовательный в параллельный, и ты прав для записи многоразрядных слов это описание некорректно

 

Мы разговариваем про разные вещи, память это двумерный массив. У памяти может быть 1-2 порта чтения записи, если же их больше, то это приведет к памяти на регистрах. Если у тебя их много то ......

а если нет ??

Что то ты здесь перемудрил :) в моем случае R_tmp_mem - двумерный массив [1]x[4096]. Запись reg R_tmp_mem [(WIDTH_WR_DATA*DEPTH_WR-1):0]; как раз это отображает.

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


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

понятно, мы говорим о разных вещах. У нас разные задачи и разные подходы

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


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

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

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

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

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

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

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

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

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

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