Perdachillo 0 Posted August 1, 2019 · Report post Всем привет. Пытаюсь реализовать очистку памяти путем последовательной записи во все ячейки нулей. Возникли трудности в понимании того, чем руководствуется Quartus, когда разводит RAM на логике, а когда на блоках памяти. Например, изначально я сделал трехмерную память с по-отчетной записью данных (в том числе и при очистке), при этом чтение происходит областями. Получилось что-то типа byte enabled simple dual port ram, но только отчет равен не байту, а другому заданному значению: logic [DEEP_BACKET-1:0][WIDTH_RECORD-1:0] ram [0:N_BUCKET-1]; logic [$clog2(N_BUCKET*DEEP_BACKET)-1:0] clear_cnt; logic clear_val; always_ff@(posedge clk or posedge clear_table) begin if (clear_table) clear_val <= 1'd1; else if (clear_cnt == N_BUCKET*DEEP_BACKET - 1) clear_val <= 1'd0; end always_ff@(posedge clk) begin if (clear_val) clear_cnt <= clear_cnt + 1'd1; end always_ff@(posedge clk) begin if (clear_val) ram[clear_cnt[$clog2(N_BUCKET)-1:0]][clear_cnt[$clog2(N_BUCKET*DEEP_BACKET)-1:$clog2(N_BUCKET)]] <= '0; else begin if(we) begin ram[waddr][be] <= wdata; end q <= ram[raddr]; end end В данном случае Quartus все развел на блоках памяти. Однако, в таком случае для полной очистки памяти требуется N_BUCKET*DEEP_BACKET тактов. Чтобы снизить это время, я попытался разбить трехмерную память на несколько двумерных: logic [$clog2(N_BUCKET)-1:0] clear_cnt; logic clear_val; always_ff@(posedge clk or posedge clear_table) begin if (clear_table) clear_val <= 1'd1; else if (clear_cnt == N_BUCKET - 1) clear_val <= 1'd0; end always_ff@(posedge clk) begin if (clear_val) clear_cnt <= clear_cnt + 1'd1; end genvar i; generate for (i = 0; i < DEEP_BACKET; i++) begin: slice_table logic [WIDTH_RECORD-1:0] ram [0:N_BUCKET-1]; always_ff@(posedge clk) begin if (clear_val) ram[clear_cnt] <= '0; else begin if (we & be == i) begin ram[waddr] <= wdata; end q[i*WIDTH_RECORD +: WIDTH_RECORD] <= ram[raddr]; end end end: slice_table endgenerate Здесь очистка будет производится всего за N_BUCKET тактов. Но Quartus развел все это дело на логике. Почему? И в том и в другом случае, запись в каждый момент времени ведется только в один адрес. Пересечения условий быть не может. Аналогично с чтением. Quote Ответить с цитированием Share this post Link to post Share on other sites
DuHast 0 Posted August 1, 2019 · Report post Советую использовать IP блоки или примитивы, если не хочется таскать файлы из проекта в проект. Всякие сюрпризы исключены. Quote Ответить с цитированием Share this post Link to post Share on other sites
Perdachillo 0 Posted August 2, 2019 · Report post 16 часов назад, DuHast сказал: Советую использовать IP блоки или примитивы, если не хочется таскать файлы из проекта в проект. Всякие сюрпризы исключены. Обычно я так и делаю, просто беру мегафункции Quartus. Но в данном случае мне не хотелось бы ставить мультиплексоры на входе портов data и wraddr у модуля RAM. Да и просто возник интерес, по каким принципам Quartus определяет, что является памятью, а что нет? Мб какой документ есть, где это затрагивается? Quote Ответить с цитированием Share this post Link to post Share on other sites
DimaG 0 Posted August 2, 2019 · Report post 50 minutes ago, Perdachillo said: Да и просто возник интерес, по каким принципам Quartus определяет, что является памятью, а что нет? Мб какой документ есть, где это затрагивается? Recommended HDL Coding Styles в Quartus Handbook возможно поможет Quote Ответить с цитированием Share this post Link to post Share on other sites
iosifk 0 Posted August 2, 2019 · Report post 21 час назад, Perdachillo сказал: Пытаюсь реализовать очистку памяти путем последовательной записи во все ячейки нулей. Однако, в таком случае для полной очистки памяти требуется N_BUCKET*DEEP_BACKET тактов. Чтобы снизить это время, я попытался разбить трехмерную память на несколько двумерных: Здесь очистка будет производится всего за N_BUCKET тактов. Я довольно часто сталкивался с тем, что задавались "нестандартные" вопросы, которые и вызывали трудности. Но обычно все сводилось к тому, что не "вопрос" сложный, а "постановка задачи" не верная. Если не трудно, объясните зачем все это нужно. Ведь в рабочем режиме никакой "очистки" уже не требуется. Память обычно используется с дескрипторами, в которых можно прописать "условие" - очищено или нет. Ну и что касается числа тактов. А так ли важно, за сколько именно тактов пройдет инициализация всего устройства. Ну ведь наверняка есть и микроконтроллер. И пока в ПЛИС делается загрузка и инициализация, то и в микроконтроллере делается то же самое. А если есть хост, то и он не мгновенно включается в работу. Вот я и хочу узнать, есть ли смысл биться лбом в "очистку"... PS. Кстати, у блочной памяти есть еще биты, которые обычно используются как биты четности. Но ведь их же так же можно использовать и как тэги. Или один из блоков памяти приклеить к основной памяти и использовать как тэги. И если в него писать байтами, то в тегах бит "очищено-не очищено" будет читаться как бит. И весь процесс пойдет как минимум в 8 раз быстрее... Quote Ответить с цитированием Share this post Link to post Share on other sites
Perdachillo 0 Posted August 2, 2019 · Report post 3 минуты назад, iosifk сказал: Вот я и хочу узнать, есть ли смысл биться лбом в "очистку"... Необходимо сделать, что то типа таблицы коммутации, которую при изменении топологии сети требуется очищать. Таблицу я сделал на основе трёхмерного массива. Запись в неё, и соответственно чтение, производится по хэшу, который считается на основе MAC адреса. Как раз для обработки коллизий память и сделана трехмерной. Другого варианта, как все это сделать я честно говоря не нашёл 40 минут назад, DimaG сказал: Recommended HDL Coding Styles в Quartus Handbook возможно поможет Спасибо, поищу там Quote Ответить с цитированием Share this post Link to post Share on other sites
iosifk 0 Posted August 2, 2019 · Report post 4 минуты назад, Perdachillo сказал: Необходимо сделать, что то типа таблицы коммутации, которую при изменении топологии сети требуется очищать. Таблицу я сделал на основе трёхмерного массива. Запись в неё, и соответственно чтение, производится по хэшу, который считается на основе MAC адреса. Как раз для обработки коллизий память и сделана трехмерной. Так тем более, там же кроме адреса должны быть признаки валидности. Их то и надо сбрасывать. А сами данные при этом не важны. Но еще хочу добавить. Для поисковых таблиц используют обычно не RAM, а CAM... А вот в них и "очищать" ничего не нужно... Quote Ответить с цитированием Share this post Link to post Share on other sites
Perdachillo 0 Posted August 2, 2019 · Report post 1 минуту назад, iosifk сказал: Так тем более, там же кроме адреса должны быть признаки валидности. Их то и надо сбрасывать. А сами данные при этом не важны. Но еще хочу добавить. Для поисковых таблиц используют обычно не RAM, а CAM... А вот в них и "очищать" ничего не нужно... CAM у меня нет, к сожалению, есть только ПЛИС) Предположим я добавлю флаг валидности у записей в таблице. При изменении топологии мне придётся у всех записей снимать этот флаг? Чем тогда это в корне отличается от обычного обнуления? То есть в одном случае я получается один бит в ноль сбрасываю, а в другом все. Или я что то не понял? Поскольку это таблица коммутации, то мне при чтении ячейки неизвестно понадобиться ли мне её ещё раз читать. Она там должна храниться, пока не придёт сигнал изменение топологии, либо пока таймер устаревания не закончится. Quote Ответить с цитированием Share this post Link to post Share on other sites
andrew_b 0 Posted August 2, 2019 · Report post 2 минуты назад, Perdachillo сказал: CAM у меня нет, к сожалению, есть только ПЛИС) CAM (Content-Addressable Memory) делается в ПЛИС. Quote Ответить с цитированием Share this post Link to post Share on other sites
Perdachillo 0 Posted August 2, 2019 (edited) · Report post 8 минут назад, andrew_b сказал: CAM (Content-Addressable Memory) делается в ПЛИС. Я думал имеется в виду готовое решение. А почему cam очищать не нужно? Предположим мне пришёл сигнал, который говорит, что топология изменилась данные о местоположение узлов в сети недействительны (в таблице) . А затем пришёл пакет с данными с определённым MAC адресом назначения. Моё устройство начинает адрес назначения искать в таблице и находит запись, но она же недействительна и использовать её нельзя. Edited August 2, 2019 by Perdachillo Quote Ответить с цитированием Share this post Link to post Share on other sites
RobFPGA 0 Posted August 2, 2019 · Report post Приветствую! 27 minutes ago, iosifk said: ... Для поисковых таблиц используют обычно не RAM, а CAM... А вот в них и "очищать" ничего не нужно... Очень смелое утверждение, - то что очищать не нужно. Да и более-менее приличная CAM обычно строится на RAM. Нужно ли очищать, как и что очищать это обычно зависит от конкретного дизайна и требованиям к его функциональности. TC нужно аккуратно просмотреть стиль описания памяти. Увы правильный синтез памяти из описания в RTL требует соблюдения неких паттернов этого описания. Синтезаторы обычно пытаются выделить этот паттерн из AST дерева в процессе синтеза. И если этого не получается то лепят память как попало. Так что смотрите как вам советовали Recommended HDL Coding Styles. Ну а если хотите делать переносимый код, не привязанный к конкретному вендору, то выносите память в собственные врапперы где уже можете расписывать реализацию (RTL, примитивы и атрибуты синтеза) в зависимости от вендора и семейства FPGA Удачи! Rob. Quote Ответить с цитированием Share this post Link to post Share on other sites
Perdachillo 0 Posted August 2, 2019 · Report post Только что, RobFPGA сказал: Приветствую! Очень смелое утверждение, - то что очищать не нужно. Ведь более-менее приличная CAM обычно строится на RAM. Нужно ли очищать, как очищать и что это обычно зависит от конкретного дизайна и требованиям к его функциональности. TC нужно аккуратно просмотреть стиль описания памяти. Увы правильный синтез памяти из описания в RTL требует соблюдения неких паттернов этого описания. Синтезаторы обычно пытаются выделить этот паттерн из AST дерева в процессе синтеза. И если этого не получается то лепят память как попало. Так что смотрите как вам советовали Recommended HDL Coding Styles. Ну а если хотите делать переносимый код, не привязанный к конкретному вендору, то выносите память в собственные врапперы где уже можете расписывать реализацию (RTL, примитивы и атрибуты синтеза) в зависимости от вендора и семейства FPGA Удачи! Rob. Хорошо, спасибо. Этим и займусь. Quote Ответить с цитированием Share this post Link to post Share on other sites
iosifk 0 Posted August 2, 2019 · Report post 5 минут назад, Perdachillo сказал: Моё устройство начинает адрес назначения искать в таблице и находит запись, но она же недействительна и использовать её нельзя. Видимо используется еще и метка времени, ведь свитч умеет определять "устаревание" и умеет делать "обучение"... Quote Ответить с цитированием Share this post Link to post Share on other sites
Perdachillo 0 Posted August 2, 2019 · Report post 1 минуту назад, iosifk сказал: Видимо используется еще и метка времени, ведь свитч умеет определять "устаревание" и умеет делать "обучение"... В любом случае, записи как то надо похерить, причём не одну конкретную, а все сразу Quote Ответить с цитированием Share this post Link to post Share on other sites
Nick_K 0 Posted August 2, 2019 · Report post 3 hours ago, Perdachillo said: В любом случае, записи как то надо похерить, причём не одну конкретную, а все сразу Если стоит задача избавится от всех записей сразу и при этомиспользовать RAMпочему не реализовать на выходе памяти коммутатор валидности. По сути это будет просто набор регистров с сигналом сброса инверсным валидному. если данные не валидны, то не важно что читать - будет ноль. Если же нужно сбросить и потом перезаписать всё - идеальное решение. Если же в процессе работы будет периодическая перепроверка всего диапазона памяти, тогда не годится. Quote Ответить с цитированием Share this post Link to post Share on other sites