Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: FIFO (CPLD+SRAM)
Форум разработчиков электроники ELECTRONIX.ru > Программируемая логика ПЛИС (FPGA,CPLD, PLD) > Работаем с ПЛИС, области применения, выбор
uragan90
Доброго времени суток уважаемые!!!
Есть задача построить модуль FIFO на связке CPLD+SRAM. Это образно говоря решение будет использоваться как простое FIFO для передачи данных в микроконтроллер. Мозги кипят и требуется помощь знающих людей которые смогут помочь разобраться в проблеме.
Вопрос коммутационного плана на выложенной схеме дело в том что мк и плис работают на разных тактовых частотах и тут то и проблема.
Я думаю так сделать:
Данные со входа IN_DATA[15..0] поступают во внешнюю sram и там фиксируются сигналом (wd_sram) по адресу схемы которая тут не представлена в принципе это не важно. Начало работы начинается с того что мк подаёт запрос на то чтоб данные записались в регистр (inst5) сигналом (request) и если sram находится в режиме чтения то данные записываются в регистр при этом выставляется флаг регистр загружен -(confirmation) и сбрасывается регистр запроса на запись данных из sram. По приходу следующего запроса записи из sram в регистр (inst5) флаг (confirmation) сбрасывается в ноль и мк ожидает загрузки регистра (inst5) из него потом сдвиговым регистром будут выгружены данные в мк. Так я предположил выйти из проблемы пересечения клоковых доменов асинхронной фифо. Подскажите в правильном ли я направлении двигаюсь?
uragan90
И вообще как такое реализовать можно?
Я делаю так: Завожу 2 счетчика адреса (один для чтения другой для записи). По приходу сигнала на запись в срам счетчик адреса записи инкременирую +1 и записываю данные в срам. По приходу сигнала на загрузку в регистр данных для чтения я инкременирую +1 счетчик чтения и если значение счетчика чтения равно значению счётчика записи то фифо полное и запись не возможна, если же значение счётчика чтения меньше значения счётчика записи на -1 то фифо пустое и чтение запрещено!
Maverick
Цитата(uragan90 @ Sep 5 2015, 18:10) *
И вообще как такое реализовать можно?
Я делаю так: Завожу 2 счетчика адреса (один для чтения другой для записи). По приходу сигнала на запись в срам счетчик адреса записи инкременирую +1 и записываю данные в срам. По приходу сигнала на загрузку в регистр данных для чтения я инкременирую +1 счетчик чтения и если значение счетчика чтения равно значению счётчика записи то фифо полное и запись не возможна, если же значение счётчика чтения меньше значения счётчика записи на -1 то фифо пустое и чтение запрещено!

Для двухклокового фифо нужна блочная память, т.е. FPGA, а не CPLD.
В CPLD мне кажется Вы не сделаете межклоковую развязку, т.к. в CPLD должно войти тогда 2 клока....

ниже пример фифо на регистрах, работающее на 1 клоке, хотя оно Вам вряд ли поможет

CODE

-- Module Name: my_fifo - Behavioral
-- Description: A 32 x 9 FIFO using inferred storage

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity my_fifo is
Port ( clk : in STD_LOGIC;
wr : in STD_LOGIC;
din : in STD_LOGIC_VECTOR(8 downto 0);
empty : out STD_LOGIC;
full : out STD_LOGIC;
rd : in STD_LOGIC;
dout : out STD_LOGIC_VECTOR(8 downto 0));
end my_fifo;

architecture Behavioral of my_fifo is
signal i_full : std_logic;
signal i_empty : std_logic;

type mem_array is array(31 downto 0) of std_logic_vector(8 downto 0);
signal memory : mem_array;
signal wr_ptr : unsigned(4 downto 0) := (others => '0');
signal rd_ptr : unsigned(4 downto 0) := (others => '0');

begin
full <= i_full;
empty <= i_empty;

flag_proc: process(wr_ptr, rd_ptr)
begin
if wr_ptr = rd_ptr then
i_empty <= '1';
else
i_empty <= '0';
end if;

if wr_ptr+1 = rd_ptr then
i_full <= '1';
else
i_full <= '0';
end if;
end process;

clk_proc: process(clk)
begin
if rising_edge(clk) then
if rd = '1' then
if wr = '1' then
if i_empty = '0' then
dout <= memory(to_integer(rd_ptr));
rd_ptr <= rd_ptr + 1;
end if;

memory(to_integer(wr_ptr)) <= din;
wr_ptr <= wr_ptr + 1;

elsif i_empty = '0' then
dout <= memory(to_integer(rd_ptr));
rd_ptr <= rd_ptr + 1;
end if;
elsif wr = '1' then
if i_full = '0' then
memory(to_integer(wr_ptr)) <= din;
wr_ptr <= wr_ptr + 1;
end if;
end if;
end if;
end process;
end Behavioral;
uragan90
Цитата(Maverick @ Sep 5 2015, 19:43) *
Для двухклокового фифо нужна блочная память, т.е. FPGA, а не CPLD.

Мне не нужна двух клоковая фифо! Мне достаточно одного клока основного на стороне плис! Я лишь хочу с мк отправлять запрос на возможность запись во внутренний регистр плис данных и как только это станет возможным плис должна загрузить в свой регистр данные из срам и сообщить об этом факте мк.
Maverick
Цитата(uragan90 @ Sep 5 2015, 18:48) *
Мне не нужна двух клоковая фифо! Мне достаточно одного клока основного на стороне плис! Я лишь хочу с мк отправлять запрос на возможность запись во внутренний регистр плис данных и как только это станет возможным плис должна загрузить в свой регистр данные из срам и сообщить об этом факте мк.

Тогда Вам в помощь одноклоковое фифо (памятью которого является сама SRAM) и логика приема, передачи данных.
Пример фифо на регистрах привел в предыдущем сообщении...

PS Не уверен в коректности Вашей идеи...
krux
Цитата
Мне не нужна двух клоковая фифо! Мне достаточно одного клока основного на стороне плис! Я лишь хочу с мк отправлять запрос на запись в регистр плис данных и как только это станет возможным плис должна загрузить в свой регистр данные из срам и сообщить об этом факте мк.

тогда это не фифо, а озу с ручным управлением. назыавайте вещи своими именами.

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

второй регистр - сигнал-запрос на вычитывание данных из SRAM в плис.
пишет этот регистр - мк. плис способна только сбрасывать его.

третий регистр - сигнал-подтверждение того что чтение со стороны плис окончено.
пишет в этот регистр - плис, мк способна только сбрасывать.


порядок такой.
мк при старте сбрасывает второй и третий регистры, подключает SRAМ к себе первым регистром, обнуляет SRAM.

после записи данных переключает мультиплексоры первым регистром к плис, пишет во второй запрос.
ждет прихода в третий регистр.
проверяет сбросился ли второй. если не сбросился - сбрасывает.
переключает мультиплексоры SRAM на себя первым регистром.
uragan90
Цитата(Maverick @ Sep 5 2015, 19:58) *
Тогда Вам в помощь одноклоковое фифо (памятью которого является сама SRAM) и логика приема, передачи данных.

PS Не уверен в корректности Вашей идеи...

Просто задача идеи состоит в том чтоб на высокой скорости загружать sram и потом по мере необходимости выгружать данные из sram. Но cpld уже есть EPM570 с подключенной к ней sram CY7C1041DV33. Почему б и не попробовать ведь ресурсов их хватает для задачи с головой. Просто криво возможно как то но возможно ведь?
krux
Цитата
Просто криво возможно как то но возможно ведь?

я полагаю, никто до сих пор не понял какого конечного результата вы хотите добиться =)
uragan90
Цитата(krux @ Sep 5 2015, 20:02) *
тогда это не фифо, а озу с ручным управлением. назыавайте вещи своими именами.

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

Запись в срам должна быть выше по приоритету чем чтение. Данных будет немного но быстро их пишем в срам, и если только мы не пишем в срам то есть возможность чтения
Maverick
Цитата(uragan90 @ Sep 5 2015, 19:11) *
Запись в срам должна быть выше по приоритету чем чтение. Данных будет немного но быстро их пишем в срам, и если только мы не пишем в срам то есть возможность чтения

Пожалуйста попытайтесь еще раз объяснить, что нужно сделать и привести требования.
И напишите все режимы/требования работы, а то у Вас в процессе общения появляются новые требования/режимы.
Для наглядности можете привести какие-то "картинки" схемы в виде квадратиков/прямоугольничков со стрелочками
krux
Цитата
Запись в срам должна быть выше по приоритету чем чтение.

при записи одной ячейки озу одновременно и из мк и из плис - какой должен быть результат?
uragan90
Цитата(Maverick @ Sep 5 2015, 20:13) *
Пожалуйста попытайтесь еще объяснить, что нужно сделать и требования.
И напишите все режимы/требования работы, а то у Вас в процессе общения появляются новые требования/режимы.
Для наглядности можете привести какие-то "картинки" схемы

Попытаюсь объяснить. Я с помощью плис захватываю данные с ацп на частоте клока плис 50mhz и пишу их во внешнюю sram. К плис подключен мк и по запросу плис должна загрузить в свой внутренний регистр данные которые читаем по принципу фифо, но только не важно какой там клок- просто послали с мк запрос на загрузку и как только это стало возможным в момент когда данные не записываются в срам, плис загружает данные в свой регистр. Сообщает об этом мк и мк с помощью сдвигового регистра как в интерфейсе SPI выгружает данные из плис к себе. Неужели не понятно объяснил?
Вот картинка вдохновившая меня на реализацию этого "псевдо-фифо"

Цитата(krux @ Sep 5 2015, 20:16) *
при записи одной ячейки озу одновременно и из мк и из плис - какой должен быть результат?

Запись должна проходить с плис в срам! А вот если нет записи в срам но мк требует данные, то плис выгрузит из срам данные в свой внутренний регистр и сообщит об этом мк. - Как думаете это возможно?
krux
Цитата
Сообщает об этом мк и мк с помощью сдвигового регистра как в интерфейсе SPI выгружает данные из плис к себе.

сколько за раз выгружается байт из озу в мк?
что, если посередине передачи по SPI возникла необходимость записи со стороны плис?
uragan90
Цитата(krux @ Sep 5 2015, 20:31) *
сколько за раз выгружается байт из озу в мк?
что, если посередине передачи по SPI возникла необходимость записи со стороны плис?

Тут всё просто мы отправили запрос с мк в плис и ждём ответа когда плис загрузит данные в регистр чтоб потом с помощью сдвигового регистра выгрузить байт из плис в мк. Скорость выгрузки соизмерима с ёмкостью этого псевдо-фифо. Что не понятно то я вот тоже не пойму проблемы что вас воснует в такого рода передачи.

Цитата(krux @ Sep 5 2015, 20:31) *
что, если посередине передачи по SPI возникла необходимость записи со стороны плис?

Этой проблемы не возникнет так как на время передачи из плис в мк запроса на чтение от мк не будет по понятным причинам и не что не потревожит плис загружать данные в срам.
krux
Цитата
я вот тоже не пойму проблемы что вас волнует в такого рода передачи.

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

практика показывает, что от 50% до 80% алгоритмов по объему - это обработка непредвиденных при нормальной работе ситуаций, и если вы ожидаете только тепличных условий по входным воздействиям - то это прямая дорога в адъ.
uragan90
Цитата(krux @ Sep 5 2015, 20:52) *
волнуют возможности возникновения неопределенностей.
и соответственно исключение всяких граничных ситуаций.
меня не покидает ощущение, что вы хотите на них плюнуть/ махнуть рукой, и получившуюся конструкцию, которая может работать иногда продать за конструкцию, которая работает.

Не в коим разе не продаю ничего! Наоборот: Учусь, стараюсь сделать то что будет работать, и исключительно для познания, а не ради продаж!!!

Цитата(krux @ Sep 5 2015, 20:52) *
практика показывает, что от 50% до 80% алгоритмов по объему - это обработка непредвиденных при нормальной работе ситуаций, и если вы ожидаете только тепличных условий по входным воздействиям - то это прямая дорога в адъ.

Собственно для этого я и обратился к вам за помощью. Дельного посоветовали мало, но и не оскорбили никак и на том спасибо!!!
krux
я прошу прощения за мазню в paint, но это было быстрее всего.
я понял вашу задачу следующим образом.
Нажмите для просмотра прикрепленного файла
у вас есть АЦП и есть микроконтроллер.
но поскольку АЦП имеет скорость выдачи отсчетов выше, чем может принять мк, то было сгорожено CPLD и SRAM.
т.е. процесс примерно следющий
1) МК запускает выборку АЦП.
2) АЦП отсылает выборку в CPLD.
3) по мере передачи отсчетов от АЦП в SRAM в CPLD формируются счетчики уровня заполненности. wrptr-rdptr, сигналы fifo_empty, fifo_full, некий аналог usedw
4) при активации SPI со стороны мк вычитывается очередной байт данных. (ограничение - вычитывать из "фифо" можно только по 1 байту за каждую активацию SPI)

оно?
uragan90
Цитата(krux @ Sep 5 2015, 21:55) *
я прошу прощения за мазню в paint, но это было быстрее всего.
я понял вашу задачу следующим образом.
Нажмите для просмотра прикрепленного файла
у вас есть АЦП и есть микроконтроллер.
но поскольку АЦП имеет скорость выдачи отсчетов выше, чем может принять мк, то было сгорожено CPLD и SRAM.
т.е. процесс примерно следющий
1) МК запускает выборку АЦП.
2) АЦП отсылает выборку в CPLD.
3) по мере передачи отсчетов от АЦП в SRAM в CPLD формируются счетчики уровня заполненности. wrptr-rdptr, сигналы fifo_empty, fifo_full, некий аналог usedw
4) при активации SPI со стороны мк вычитывается очередной байт данных. (ограничение - вычитывать из "фифо" можно только по 1 байту за каждую активацию SPI)

оно?

Да! Вы правы! Это то что я имел ввиду в общих чертах, с тем лишь отличием что плис сама загружает данные в срам и мк не как не воздействует на этот прцес! Мк лишь посылает запрос в плис на загрузку очередного байта в выходной spi буфер и как только это произойдёт то плис сигнализирует мк о готовности байта для передачи из плис в мк, а мк по spi выгружает байт к себе
krux
ура! ко второй странице разродились на верхний уровень абстракции.
Цитата
Это то что я имел ввиду в общих чертах

тактирование от АЦП есть всегда? оно на CPLD подано? хотелось бы прорегистрить сигналы от мк на частоте выдачи выборок АЦП. тогда проблема с синхронным дизайном решится сразу.
uragan90
Цитата(krux @ Sep 5 2015, 22:09) *
тактирование от АЦП есть всегда? оно на CPLD подано? хотелось бы прорегистрить сигналы от мк на частоте выдачи выборок АЦП. тогда проблема с синхронным дизайном решится сразу.

Ацп с мк никак не связаны! Плис управляет ацп по скрытому для мк алгаритму и записывает данные в срам нв хранение, мк же должно их оттуда забрать как только на это появится время. Места в срам полно, а ацп тактируется периодически по скрытому алгаритму. Просто хотел посоветоватся по возможности реализации псевдо фифо на связке срам+плис
bugdesigner
А какие сигналы идут от ADC? Если данные поступают на каждый период клока, то такого клока будет недостаточно, потребуется оверсемплинг, иначе как можно будет разрулить режимы записи/чтения в память? Короче, давайте подробности, а именно:
- Какой adc, сигналы, режим работы
- Какой чип RAM будем использовать
- Какие есть клоки
Без этих данных не о чем разговаривать.
В общих чертах - fifo делается в виде циклического буфера с двумя счётчиками адреса, а рулить этим должен конечный автомат (FSM)
krux
для корректной работы плис нужно стабильное тактирование. постоянное.
при этом подразумевается что все входные сигналы, как-то участвующие в логике работы, а не просто проходящие со входа на выход, перед использованием будут засинхронизированы этой частотой.

вопрос состоит в том, каково соотношение частот.
частота, приходящая в плис кратна частоте, подаваемой на ацп? равна? какова задержка данных ацп по фазе относительно этого клока, есть ли она вообще?
во сколько раз эта частота выше, чем частота SPI? насколько критична реализация SPI в вашем микроконтроллере к временным отклонениям MISO относительно SCK?

вот потому и пытаем вас как партизана.
потому как данных мало.
uragan90
Клока, клока... Я ж говорю что по импульсу от мк в плис плис должен зафиксировать факт прихода запроса на запись, дождатся этого самого вашего клока основного в плис и дождатся когда станет не активен сигнал записи из вне в срам и выгрузить байт из срам в регистр свой же и просигналить об этом мк что байт готов и находится в регистре вывода. При этом флаг запроса должен сбросится. Когда мы сново пошлём запрос байта для чтения этим самым сбросится флаг готовности байта.
Это что так сложно привести к основному клоку плис? Я только этого и не пойму в чём тут проблема то? Это что так сложно реализовать. Схема выше опасаной логики дана в первом посте. И вопрос - будет ли работать?
x736C
Цитата(uragan90 @ Sep 5 2015, 22:45) *
Это что так сложно привести к основному клоку плис? Я только этого и не пойму в чём тут проблема то? Это что так сложно реализовать. Схема выше опасаной логики дана в первом посте. И вопрос - будет ли работать?

Есть похожая тема, в которой выкладывал пример ровно с такой связкой: ADC-(CPLD-SRAM)-uC
Кто-то предлагает задействовать UART или SPI для связи CPLD и микроконтроллера. Тут вроде тоже поступало такое предложение.
Наверное, так и сделал, если бы они работали от разных генераторов. От потребных таймингов протокола тоже зависит.

http://electronix.ru/forum/index.php?showt...mp;#entry818823

В общем, задача абсолютно решаемая. Не очень понятно, что вызывает у Вас основную трудность.
bugdesigner
Трудность здесь в пересечении доменов клоков. Как минимум одно пересечение тут есть.
x736C
Цитата(bugdesigner @ Sep 6 2015, 08:15) *
Трудность здесь в пересечении доменов клоков. Как минимум одно пересечение тут есть.

Так выпьем же за то, чтобы это было самыми большими нашими трудностями beer.gif biggrin.gif
Golikov A.
Цитата
Это что так сложно привести к основному клоку плис? Я только этого и не пойму в чём тут проблема то? Это что так сложно реализовать. Схема выше опасаной логики дана в первом посте. И вопрос - будет ли работать?


Народ просто любит поговоритьsm.gif.

Коротко работать будет, но есть реализация проще. Вам надо 2 сигнала
request - запрос данных
и ack - подтверждение готовности
если процу нужны очередные данные, он ставит request <= ~ack, когда ПЛИС видит запрос не равный подтверждению - это запрос на данные, она их выставляет и ставит ack <= request. Как проц видит ack равный request - это подтверждение того что данные готовы. Остается только вопрос есть ли у вас 2 портовая СРАМ или можно ли ее симулировать.

Самая простая симуляция 2 портовой СРАМ это тактировать ее частотой Х, а читать/писать на частоте Х/2, по одному адресу писать, по другому читать, дальше все становиться делом техники.... Вся схема работает на частоте Х/2 и у вас получается фифо на 2 портовой памяти. Сигнал от проца лучше прогнать через 2 триггера, чтобы как бы чего не вышло
EvgenyNik
Просто переключающими регистрами задачу красиво решить, наверное, не получится. Нужен ещё автомат, который, принимая управляющие сигналы, будет прокручивать сценарии завершения работы с АЦП, с записью данных в ОЗУ, полученных от АЦП, корректно переводить сигналы связи CPLD<>RAM в исходное состояние и т.п.
Особенно наглядно это видно, если АЦП имеет последовательный канал связи (SPI и т.п.), когда Вам, получив команду от МК, необходимо "принять её к сведению" и завершить протокол обмена с АЦП в штатном режиме, потом записать эти данные в ОЗУ, переназначить адресные индексы кольцевого буфера (ну или глубины стека FIFO), хранящегося в ОЗУ.
Не видя основного направления применения задачи, трудно строить умозаключения, но в общем случае я за кольцевой буфер, т.к. такое построение позволяет всегда иметь акутальные данные. Надо будет вести 2 параметра для "кольца": адрес последнего значения и длина буфера (т.к. пока кольцо не замкнулось - длина не равна размеру ОЗУ).
Golikov A.
Цитата
принимая управляющие сигналы, будет прокручивать сценарии завершения работы с АЦП, с записью данных в ОЗУ, полученных от АЦП, корректно переводить сигналы связи CPLD<>RAM в исходное состояние и т.п.

и зачем это все?
Пусть модуль сбора данных с АЦП этим занимается, а когда все сделает кладет в регистр и ставит флаг записать данные. Как фифо будет готово оно забирает данные. Как процу надо данные, фифо опять же выдает их в регистр. А дальше уже другое устройство (модуль) переписывает данные в проц, хоть по СПИ, хоть по телеграфу...
Зачем усложнять, то? ТС спросил можно ли сделать такое фифо, а вы уже все обсудили и интерфейсы, и АЦП, и прочее...

Maverick
Цитата(Golikov A. @ Sep 6 2015, 20:09) *
Народ просто любит поговоритьsm.gif.

Коротко работать будет, но есть реализация проще. Вам надо 2 сигнала
request - запрос данных
и ack - подтверждение готовности
если процу нужны очередные данные, он ставит request <= ~ack, когда ПЛИС видит запрос не равный подтверждению - это запрос на данные, она их выставляет и ставит ack <= request. Как проц видит ack равный request - это подтверждение того что данные готовы. Остается только вопрос есть ли у вас 2 портовая СРАМ или можно ли ее симулировать.

Самая простая симуляция 2 портовой СРАМ это тактировать ее частотой Х, а читать/писать на частоте Х/2, по одному адресу писать, по другому читать, дальше все становиться делом техники.... Вся схема работает на частоте Х/2 и у вас получается фифо на 2 портовой памяти. Сигнал от проца лучше прогнать через 2 триггера, чтобы как бы чего не вышло

как я понял у ТС однопортовая память SRAM

Цитата(uragan90 @ Sep 5 2015, 19:05) *
Просто задача идеи состоит в том чтоб на высокой скорости загружать sram и потом по мере необходимости выгружать данные из sram. Но cpld уже есть EPM570 с подключенной к ней sram CY7C1041DV33. Почему б и не попробовать ведь ресурсов их хватает для задачи с головой. Просто криво возможно как то но возможно ведь?
EvgenyNik
Цитата(Golikov A. @ Sep 7 2015, 08:36) *
и зачем это все?
Чтобы проц имел доступ к последним данным, а не к тем, которые были когда-то до тех пор, пока FIFO не забилось.
Цитата(Golikov A. @ Sep 7 2015, 08:36) *
ТС спросил можно ли сделать такое фифо, а вы уже все обсудили и интерфейсы, и АЦП, и прочее...
При таком подходе - согласен. Но, вообще говоря, из задачи не совсем ясна конечная цель ТС. Правильность того или иного подхода будет сильно зависеть от прочих условий.
uragan90
Цитата(Maverick @ Sep 7 2015, 10:02) *
как я понял у ТС однопортовая память SRAM

Да! Одно портовая память срам! Хочу создать модуль контроллера срам, чтоб с ней работать как с фифо, но писать в неё по фронту сигнала WD который приходит из другого модуля, а по спаду WD сбрасывать в регистр и хранить там пока не перелью данные в мк и не произведу следующий запрос чтения.
Вот начал писать модуль сий. Затык с этим самым "автоматом состояний" который должен активировать регистр rdy когда посылаем запрос и ожидаем данные, вот тут за спотыкался.

CODE
module sram_control(
input clk_pld, //основной такт плис
input wd, //запись в sram, (высокий приоритет)
input request, //запрос данных
output reg ack, //подтверждение готовности данных
output empty, //sram пустая (читать нельзя)
output full, //sram полная (писать нельзя)
output [17:0] addr, //адрес sram
input [15:0] din, //вход данных для записи во внешнюю sram
output reg [15:0] dout, //выход данных для чтения из sram
inout [15:0] dinout //двунаправленный порт данных для подключения непосредственно к sram
);

reg rdy = 0;
reg [15:0] buff = 0; //буфер 3х состояний
reg [18:0] count_w = 0; //регистр счётчика записи
reg [18:0] count_r = 0; //регистр счётчика чтения

//счётчик адреса записи
always @(posedge clk)
begin
if(wd) count_w = count_w + 1;
end

//счётчик адреса чтения
always @(posedge clk)
begin
if(rdу) count_r = count_r + 1;
end

//процес управляющий логикой чтения данных
always @(posedge clk)
begin
if(request)
begin

//??????????????????????????????????
end
end


always @(posedge clk)
begin
if(wd) buff = din;
else
begin
buff = 16'bz;
if(rdу)
dout = dinout;
end
end

assign dinout = buff;
assign addr = (!wd && rdу)? count_r : count_w;

assign full = ((count_w[17:0] == count_r[17:0]) && (count_w[18] ^^ count_r[18]))? 1'b1 : 1'b0;
assign empty = ((count_w[17:0] == count_r[17:0]) && (!(count_w[18] ^^ count_r[18])))? 1'b1 : 1'b0;
endmodule

krux
при старте, если указатели чтения и записи равны (т.е. записей в озу нет), то первая запись должна идти напрямую в dout.
empty при этом падает в 0.
следующие записи если empty в нуле идут в sram, счетчик записей увеличивается.
если активны циклы записи, а микроконтроллер увидев не empty решил почитать, то он читает dout, и empty становится в 1 до момента, когда будет возможность прочитать данные из sram в dout.
в ближайший возможный момент когда записи нет, а empty в 1, и есть записи в озу - из sram вычитывается в dout, empty падает в 0.

идея понятна?
uragan90
Цитата(krux @ Sep 7 2015, 11:22) *
при старте, если указатели чтения и записи равны (т.е. записей в озу нет), то первая запись должна идти напрямую в dout.
empty при этом падает в 0.
следующие записи если empty в нуле идут в sram, счетчик записей увеличивается.
если активны циклы записи, а микроконтроллер увидев не empty решил почитать, то он читает dout, и empty становится в 1 до момента, когда будет возможность прочитать данные из sram в dout.
в ближайший возможный момент когда записи нет, а empty в 1, из sram вычитывается в dout, empty падает в 0.

идея понятна?

Оооо.. Точно!!!! Спасибо!!! Действительно в начале должны данные на выход захлопнутся, а уж потом сливаться в sram. Ведь если первым зашёл то первым и выйти должен по принципу фифо

Вобщем суть такая данные у меня заливаются в плис по 8 бит шине, а sram 16бит это дало мне возможность написать модуль который забирает данные по 8 бит и складывает в регистр 16 бит для того чтоб залить их в sram и плюс время целых два такта на то чтоб можно было по одному из них записывать, а по другому считывать.
Вот текст этой прослойки типа

CODE
module translator(
input wire clk, //клок
input wire [7:0]sbyte, //вход 1байт
input wire rdy, //загрузка байта
output reg [15:0]word, //выход 2байта
output reg wr //данные готовы
);

reg cnt = 0;
reg [15:0]buff0 = 0;

always @(posedge rdy)
begin
if(!cnt)
begin
buff0[15:8] = sbyte[7:0];
end
else
begin
buff0[7:0] = sbyte[7:0];
word = buff0;
end
cnt = cnt + 1'b1;
end

always @(posedge clk)
begin
wr = ~cnt && rdy;
end

endmodule
uragan90
Удалось реализовать такой модуль FIFO на внешней SRAM, но работает он как то не стабильно и через раз!
Уважаемые спецы, помогите найти причины не стабильности.

CODE

module FIFO_SRAM(
input Reset,
input Wclk,
input Rclk,
input Rd,
input Wd,
output full,
output empty,
input [DATA-1:0] Din,
output reg [DATA-1:0] Dout,
output [ADDR-1:0] Addr_Sram,
inout [DATA-1:0] Data_Sram,
output nCS,
output nOE,
output nWE
);

parameter ADDR = 4; // Параметр разрядности Адреса SRAM
parameter DATA = 4; // Параметр разрядности Данных SRAM

//--- Счётчики адресов чтения и записи ------------------------------
assign Addr_Sram = (Wd) ? write_addr[ADDR-1 : 0] : read_addr[ADDR-1 : 0];
reg [ADDR:0] read_addr=0;
always @(posedge Rclk) //По такту чтения
begin
if(Reset)
begin
read_addr <= 0;
end
else
begin
if (Rd) read_addr <= read_addr + 1'b1;
else read_addr <= read_addr;
end
end
//---
reg [ADDR:0] write_addr=0;
always @(posedge Wclk) //По такту записи
begin
if(Reset)
begin
write_addr <= 0;
end
else
begin
if (Wd) write_addr <= write_addr + 1'b1;
else write_addr <= write_addr;
end
end
//--- Абработка флагов заполненности ФИФО ------------------------------
assign full = ((write_addr[ADDR-1:0] == read_addr[ADDR-1:0]) && (write_addr[ADDR] ^ read_addr[ADDR]))? 1'b1 : 1'b0; //Фифо полное
assign empty = ((write_addr[ADDR-1:0] == read_addr[ADDR-1:0]) && (!(write_addr[ADDR] ^ read_addr[ADDR])))? 1'b1 : 1'b0; //Фифо пустое

//--- Логика комутации данных ------------------------------
wire [DATA-1 : 0] bus_data_out;
always@(posedge Wd or posedge Rd)
begin
Dout <= bus_data_out; //При любом запросе пишим на выход
end

assign bus_data_out = (Wd & empty)? Din : 'bz ; //Если запись и фифо пустое то со входа пишем на прямую в выходной регистр
assign Data_Sram = (Wd & ~empty)? Din : 'bz ; //Если запись и в выходном регистре не пусто то заполняем SRAM
assign bus_data_out = (~Wd & Rd)? Data_Sram : 'bz ; //Если нет записи, но есть чтение то из SRAM в выходной регистр

assign nCS = ~(Wd | Rd); //Разрешение чипа SRAM
assign nOE = ~(Rd); //Чтение чипа SRAM
assign nWE = ~(Wd); //Запись чипа SRAM

endmodule
Gorby
Цитата(krux @ Sep 5 2015, 20:10) *
я полагаю, никто до сих пор не понял какого конечного результата вы хотите добиться =)


Значит, у Вас такой задачи не стояло biggrin.gif

Автору топика: вполне заурядная задача, смелее делайте и будет всё работать.
Не забудьте про довольно большие счетчики адресов, их сравнение, и результат этого сравнения.

Тут правильно советуют - операция записи в ОЗУ имеет приоритет перед чтением.
Работу с ОЗУ разбиваем на циклы. Цикл состоит из записи и потом чтения.
Если есть запрос на запись - пишем. Если есть запрос на чтение - читаем, пока не появится запрос на запись или не кончится чтение.
Если одновременно присутствует и запрос на запись, и на чтение, то в каждом цикле одно слово должно записаться, и одно-вычитаться.
Тут надо кропотливо поработать с таймингами ОЗУ.
Очень помогает моделирование в Моделсиме или что там у Вас есть.
uragan90
Цитата(Gorby @ Sep 24 2015, 17:04) *
Тут правильно советуют - операция записи в ОЗУ имеет приоритет перед чтением.
Работу с ОЗУ разбиваем на циклы. Цикл состоит из записи и потом чтения.
Если есть запрос на запись - пишем. Если есть запрос на чтение - читаем, пока не появится запрос на запись или не кончится чтение.
Если одновременно присутствует и запрос на запись, и на чтение, то в каждом цикле одно слово должно записаться, и одно-вычитаться.
Тут надо кропотливо поработать с таймингами ОЗУ.

Так получается тут нужно реализовывать конечный автомат состояний?
Проблема видимо в том что у меня два клоковых домина и я не соображу как мне преодалеть эту проблему. У меня есть основной клок в CPLD 100Mhz. Частота записи 50Mhz а частота чтения 10Mhz. Эти частоты я реализовал делителями.
Была идея:
Запись в абсолютном приоритете!! Если поступил запрос на чтение то мы ждём пока кончится запись и как только это произойдёт то мы прочитаем данные на выход и выставим флаг готовности данных, сбросив при этом флаги запроса. Но при таком раскладе у меня в RTL модели видны защёлки, а это явная ошибка проекта.
Как же быть?

Я просто чувствую что это вполне реализуемо, но нет идей и помощи более опытных товарищей. laughing.gif
Gorby
Цитата(uragan90 @ Sep 24 2015, 17:22) *
Так получается тут нужно реализовывать конечный автомат состояний?
Я просто чувствую что это вполне реализуемо, но нет идей и помощи более опытных товарищей. laughing.gif

Да, конечный автомат нужен. Но он простой, один-два триггера.

Вы с частотами-то поосторожнее. Тщательно просчитайте, возможно ли в принипе добиться от Вашей памяти такой растактовки. Тут нужен в клеточку лист бумаги, карандаш и мозг. Оно само всё покажет. Если основной клок 100МГц и данные поступают на каждом втором такте - то у Вас просто нет шансов даже на запись - каким образом сформировать управляющие сигналы? Или делать асинхронщину на RC цепях. У Вас нету системного подхода. Сначала - растактовка памяти (управляющие сигналы формируются из виртуального клока, и это будет явно не 100МГц, а 180, 166 или рядом). Критерий - максимально выжать быстродействие ОЗУ при условии, что управление идет почти на макс скорости (половина системного клока).

Вижу сам, что сумбурно. Вы сами сразу всё увидите, как растактовку ОЗУ нарисуете.
uragan90
Цитата(Gorby @ Sep 24 2015, 17:49) *
Да, конечный автомат нужен. Но он простой, один-два триггера.

Вы с частотами-то поосторожнее. Тщательно просчитайте, возможно ли в принипе добиться от Вашей памяти такой растактовки. Тут нужен в клеточку лист бумаги, карандаш и мозг. Оно само всё покажет. Если основной клок 100МГц и данные поступают на каждом втором такте - то у Вас просто нет шансов даже на запись - каким образом сформировать управляющие сигналы? Или делать асинхронщину на RC цепях. У Вас нету системного подхода. Сначала - растактовка памяти (управляющие сигналы формируются из виртуального клока, и это будет явно не 100МГц, а 180, 166 или рядом). Критерий - максимально выжать быстродействие ОЗУ при условии, что управление идет почти на макс скорости (половина системного клока).

Вижу сам, что сумбурно. Вы сами сразу всё увидите, как растактовку ОЗУ нарисуете.

Да вроде работает, но видно что что то не то. Сложность заключается в проблеме моделирования шин с 3мя состояниями. В железе видно что работает но не так как хотелось бы
EvgenyNik
Цитата(Gorby @ Sep 24 2015, 16:49) *
Если основной клок 100МГц и данные поступают на каждом втором такте - то у Вас просто нет шансов даже на запись - каким образом сформировать управляющие сигналы?
Но данные приходят по 8 бит, а ширина шины данных ОЗУ 16 бит, что даёт ему возможность накопить слово и записать его одним махом. А пока оно копится - прочитать 16 бит для выдачи.
uragan90
Цитата(EvgenyNik @ Sep 24 2015, 18:04) *
Но данные приходят по 8 бит, а ширина шины данных ОЗУ 16 бит, что даёт ему возможность накопить слово и записать его одним махом. А пока оно копится - прочитать 16 бит для выдачи.

Именно так я и делаю!!! На частоте 100 я собераю данные по 8 бит, в регистр 16 бит. И того частота делится надвое. получается 50 Mhz. Память у меня 16ти разрядная и тем самым частота записи снижается. Читать я буду на частоте 10Mhz вот такой расклад получается, но проблема то в том что у меня 2 клоковых домина пересекающийся между собой!
EvgenyNik
Цитата(uragan90 @ Sep 24 2015, 17:09) *
Читать я буду на частоте 10Mhz вот такой расклад получается, но проблема то в том что у меня 2 клоковых домина пересекающийся между собой!
Ну тогда читать Вам надо по системе "запрос-ответ". Т.е. некий мастер выставляет запрос на чтение по определённому адресу, ваша ПЛИС "принимает" этот запрос и ожидает паузы между записями. Наступает пауза максимум через 4 такта, Вы читаете из ОЗУ и выставляете готовность - "забирай" sm.gif
Более того, учитывая, что читаете Вы на 10МГц, у Вас, как навскидку думается, есть все шансы - обработать "запрос на чтение" в этом же цикле чтения, не заставляя читающее устройство ждать.
Golikov A.
задача проста как 2 копейки, вы мудрите...
первое: делаете 2 портовую память.
- это просто, она на частоте 100 МГц, то пишет в 1 адрес (если есть сигнал записи, или не пишите), то выставляет 2 адрес и читает. Получаете 50 МГц 2 портовую память.

схема,без размерности и может быть с ошибками, но суть должна быть понятна

Код
input addr1;
input addr2;
input we;
input data_in;
output data_out;
reg PortSel; //регистр для выбора порта
reg mem_data_in; //регистр для сохранения

always @(posedge clk)
begin
   if(PortSel == 0)
      begin
        mem_addr <= addr2; //готовимся читать со 2 адреса
        mem_we <= 1'b0; //снимаем сигнал записи, 2 адрес чтение
        data_out <= mem_data_out; //защелкиваем данные с памяти (с прошлого задания адреса)
        PortSel <= 1'b1;
      end
   else
      begin
        mem_addr <= addr1; //готовимся писать в 1 адрес если надо
        mem_we <= we; //ставим we если надо
        mem_data_in <= data_in; //защелкиваем данные для записи
        PortSel <= 1'b0;
      end
end



А после того как вы это сделали, у вас остается сделать правильный переход из домена 100 МГц в домен 10.
Это просто запрос на чтение через 2 триггера, из 10 в 100, там выставляете защелкиваете данные на выход, через 1 клок данные будут валидны и стоять на входе 10. То есть на след такте вы их легко считаете...
uragan90
Цитата(Golikov A. @ Sep 24 2015, 23:32) *
задача проста как 2 копейки, вы мудрите...
первое: делаете 2 портовую память.
- это просто, она на частоте 100 МГц, то пишет в 1 адрес (если есть сигнал записи, или не пишите), то выставляет 2 адрес и читает. Получаете 50 МГц 2 портовую память.

У меня не двух портовая память CY7C1041DV33
У неё нет такой возможности обращения к одним и тем же данным по разным портам
EvgenyNik
Цитата(uragan90 @ Sep 25 2015, 10:45) *
У меня не двух портовая память...
Дык, Вам и пишут - как из обычного 100МГц ОЗУ сделать а-ля двухпортовое 50МГц ОЗУ. Только порты будут фактически на ПЛИСке.
Gorby
Цитата(uragan90 @ Sep 25 2015, 10:45) *
У меня не двух портовая память CY7C1041DV33
У неё нет такой возможности обращения к одним и тем же данным по разным портам

Да и не надо. Не о том речь.
Используйте Актив-ХДЛ!
Нарисуйте пути данных, а управление уже очевидным будет.

обратите внимание на часть "схемы" справа. С буквой М - сигналы на память. Внутренняя шина MUXERR - вход ФИФО. Шина UD - выход ФИФО.
M2D - двунаправленная шина данных микросхемы памяти (16 бит). M2A - адреса памяти. U11 и U7 -вот собственно две простые машинки, рулящие управлением. FIFO_FULL - внешний вход, собственно ЗАПРОС данных (имелся в виду фифо юсб контроллера). Если фулл, то данные НЕ слать. Данные из ФИФО наружу (UD) стробируются USBWRN (низкий уровень) по клоку IFCLK - формируется из основного клока.

А какие там проблемы с моделированием шин? Есть там конечно нюансы, но не страшные.

Нажмите для просмотра прикрепленного файла
Corner
Цитата(EvgenyNik @ Sep 25 2015, 11:55) *
Дык, Вам и пишут - как из обычного 100МГц ОЗУ сделать а-ля двухпортовое 50МГц ОЗУ. Только порты будут фактически на ПЛИСке.

Ничего не выйдет. СОЗУ то и 100 МГц, да чтение за 1 такт никак даже на ФПГА. А ЦПЛД еще тормознее. Выйдет 33 МГц на чтение и 20... 25 на запись. Но работать будет несомненно. Только еще придется ФИФО на регистрах небольшое сделать для когерентности с МК, а то лаг на чтение неизбежен.
RobFPGA
Приветствую!

Цитата(Corner @ Sep 28 2015, 22:28) *
Ничего не выйдет. СОЗУ то и 100 МГц, да чтение за 1 такт никак даже на ФПГА. А ЦПЛД еще тормознее. Выйдет 33 МГц на чтение и 20... 25 на запись. Но работать будет несомненно. Только еще придется ФИФО на регистрах небольшое сделать для когерентности с МК, а то лаг на чтение неизбежен.


Ой да что вы говорите! Не пугайте маленьких. Я еще на MAX7000 серии делал подобное и на статике и на просто DDR 100 MHz вполне себе рабочая была. У TC конечно память слегка неудобная для таких частот тут лучше синхронная статика подошла бы - придется помурыжится с таймингами чтобы вытянуть 100 MHz рабочей

Судя по схеме у вас запись и чтение последовательные - что еще сильнее упрощает задачу
Просто чередовать WR/RD циклы, Запись при накоплении 2 отсчетов, чтение ПОСТОЯННО по текущему указателю. Соответственно данные для чтения MK будут доступны сразу. Если времянка памяти не позволит переключение WR/RD в пределах такта (no ZBT) тогда придется делат WR,WR,WR,-,RD,-, итого за 6 тактов - 3 записи - 1 чтение -
Для WR путь синхронный, а частота RD значительно ниже рабочей так что синхронизация будет не сложной.

Дерзайте!

Удачи! Rob.
uragan90
Цитата(RobFPGA @ Sep 29 2015, 03:46) *
Приветствую!



Ой да что вы говорите! Не пугайте маленьких. Я еще на MAX7000 серии делал подобное и на статике и на просто DDR 100 MHz вполне себе рабочая была. У TC конечно память слегка неудобная для таких частот тут лучше синхронная статика подошла бы - придется помурыжится с таймингами чтобы вытянуть 100 MHz рабочей

Дерзайте!

Удачи! Rob.


Спасибо за поддержку!
Вот такая схема вырисовывается, остаётся реализовать конечный автомат.
8 разрядные данные гружу в регистр 16 бит и сигнал sby который теперь фактически сформировался и снизил частоту со 100 до 50Мгц.
Всем этим делом будет рулить конечный автомат, получать запросы на чтение и формировать подтверждение когда процесс записи деактивируется.
Ну как думаете, получится иль нет?

Текст счётчика адреса выглядит следующим образом:
CODE
module ADDR_counter(
input res,
input clk,
input wr,
input rd,
output full,
output empty,
output [ADDR-1:0] Addr_Sram
);

parameter ADDR = 5; // Параметр разрядности Адреса SRAM

//--- Счётчики адресов чтения и записи ------------------------------
assign Addr_Sram = (wr) ? write_addr[ADDR-1 : 0] : read_addr[ADDR-1 : 0];
reg [ADDR:0] read_addr=0;
always @(posedge clk or posedge res) //По такту чтения
begin
if(res)
begin
read_addr <= 0;
end
else
begin
if (rd) read_addr <= read_addr + 1'b1;
else read_addr <= read_addr;
end
end
//---
reg [ADDR:0] write_addr=0;
always @(posedge clk or posedge res) //По такту записи
begin
if(res)
begin
write_addr <= 0;
end
else
begin
if (wr) write_addr <= write_addr + 1'b1;
else write_addr <= write_addr;
end
end
//--- Абработка флагов заполненности ФИФО ------------------------------
assign full = ((write_addr[ADDR-1:0] == read_addr[ADDR-1:0]) && (write_addr[ADDR] ^ read_addr[ADDR]))? 1'b1 : 1'b0; //Фифо полное
assign empty = ((write_addr[ADDR-1:0] == read_addr[ADDR-1:0]) && (!(write_addr[ADDR] ^ read_addr[ADDR])))? 1'b1 : 1'b0; //Фифо пустое

endmodule


А вот схема
uragan90
Начертал схемку которая решает практически половину всего дела laughing.gif
Пока идёт запись sby мы можем записать в регистр запрос на чтение rqs и как только sby деактивируется, мы читаем байт и выставляем подтверждение ack, сбросив тем самым регистр чтения. При следующем запросе чтения мы сбросим подтверждение ack.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.