Nagisa 0 18 февраля, 2021 Опубликовано 18 февраля, 2021 · Жалоба делаю на Verloge контроллер SDRAM c обработкой 3х запросов а именно: по приоритетам начиная с самого высокого 1. rd - запрос на чтение из памяти, синхронный 2. rdb - запрос на пакетное чтение, отложенный - те можем немного ждать 3. wr - запрос на запись, полностью асинхронный, делаем когда можем Соответственно RD - синхронный, ждем результата и отдаем внешней системе WR это адрес+данные в регистр и отработаем когда будем свободны, но запомнить факт поступления запроса мы должны тк запрос на запись может поступить во время пакетного чтения. RB - запрос пакетного чтения 128 слов, можем немного подождать и завершить процессы чтения/записи общий автомат памяти localparam STATE_FIRST = 4'd0; // first state in cycle localparam STATE_CMD_START = 4'd1; // state in which a new command can be started localparam STATE_CMD_CONT = 4'd4; // STATE_CMD_START + RASCAS_DELAY; // 4 command can be continued localparam STATE_CMD_READ_STOP = 4'd5; // остановка чтения, примеряется при однословном чтении localparam STATE_CMD_READ = 4'd7; // данные готовы localparam STATE_LAST = 4'd15; // last state in cycle reg [3:0] q; always @(posedge clk) begin if (reset_done==1 && ct_rb_zr==1) // процедура инициализации завершена и нет чтения пакета q <= q + 3'd1; // тогда меняем состояение автомата end кусок кода с автоматами обработки запросов // автомат состояний очереди записи localparam STATE_W_WAIT =2'd1; localparam STATE_W_PREPARE =2'd2; localparam STATE_W_WRITE =2'd3; localparam STATE_W_WRITED =2'd0; reg [1:0] statew; always @ (posedge clk) begin if(((statew==STATE_W_WAIT ) && (wr==1 )) || // мы готовы к приему сигнала записи и он поступил - идем в STATEW_PREPARE ((statew==STATE_W_PREPARE) && (q == STATE_FIRST) && oe==0 && rb==0) || // есть данные на запись + есть готовность к началу обработки + ждем завершения других процессов ((statew==STATE_W_WRITE ) && (q == STATE_LAST)) || // запись завершена ((statew==STATE_W_WRITED ) && (wr== 0)) // исходная система завершила цикл записи ) statew <= statew + 2'd1; // меняем статус вперед end wire we= statew[1] ; // автомат состояний очереди чтения localparam STATE_R_WAIT =2'd1; localparam STATE_R_PREPARE =2'd2; localparam STATE_R_READ =2'd3; localparam STATE_R_READED =2'd0; reg [1:0] stater; always @ (posedge clk) begin if(((stater==STATE_R_WAIT ) && (rd== 1 && we==0 && rb==0)) || // мы готовы к приему сигнала чтения и он поступил + есть готовность к началу обработки - идем в STATER_PREPARE ((stater==STATE_R_PREPARE) && (q == STATE_FIRST)) || // есть команда на чтение ((stater==STATE_R_READ ) && (q == STATE_LAST)) || // чтение завершено ((stater==STATE_R_READED ) && (rd== 0)) // исходная система завершила цикл чтения ) stater <= stater + 2'd1; // меняем статус вперед end wire oe=stater[1]; // автомат состояний чтения строки в буфер localparam STATE_RB_WAIT =2'd1; localparam STATE_RB_PREPARE =2'd2; localparam STATE_RB_READ =2'd3; localparam STATE_RB_READED =2'd0; reg [1:0] staterb; always @ (posedge clk) begin if(((staterb==STATE_RB_WAIT ) && (rdb== 1)) || // мы готовы к приему сигнала пакетного чтения и он поступил - идем в STATERB_PREPARE ((staterb==STATE_RB_PREPARE) && (q == STATE_FIRST) && we==0 && oe==0) || // есть команда на чтение + есть готовность к началу обработки ((staterb==STATE_RB_READ ) && (q == STATE_LAST)) || // запись завершена ((staterb==STATE_RB_READED ) ) // исходная система завершила цикл чтения ) staterb <= staterb + 2'd1; // меняем статус вперед end wire rb= staterb[1]; reg [6:0] ct_rb; // счетчик burst-а wire startrb=(q==STATE_CMD_READ) && (staterb==STATE_RB_READ); wire ct_rb_zr=~(|ct_rb); always @ (posedge clk) begin if ( (ct_rb_zr==1 && startrb==1) || (ct_rb_zr==0) ) // условия счета ct_rb<=ct_rb+1; end в куске пакетного чтения как только у нас наступает статус STATE_CMD_READ - я торможу автомат и читаю 128 слов при одиночных чтениях/записях конфликта работает, при интенсивном использовании - глюки нутром чую что делаю не так, но не могу сообразить как это правильнее - подскажите также вопрос - что лучше для определения ноля ? reg [6:0] ct_rb; // счетчик burst-а wire ct_rb_zr=(ct_rb==0); или wire ct_rb_zr=~(|ct_rb); в первом случае в RTL я вижу модуль сравнения, во втором простой логический элемент к чему лучше стремиться ? конструкция с большим if лучше чем case с if-ами в каждом состоянии ? имеет ли смысл делать вместо счетчика состояний автомата делать сдвиговый регистр, и уже проверять состояния автомата по нужному биту в регистре ? те не надо сравнивать регистр целиком а достаточно 1 бита ? прошу направить на путь правильный Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Flip-fl0p 4 18 февраля, 2021 Опубликовано 18 февраля, 2021 · Жалоба Прежде чем заниматься оптимизацией - назовите критерий оптимизации. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Nagisa 0 18 февраля, 2021 Опубликовано 18 февраля, 2021 · Жалоба 8 minutes ago, Flip-fl0p said: Прежде чем заниматься оптимизацией - назовите критерий оптимизации. скорость те у меня циклон 2 и я хочу 130MHz на SDRAM. без бурста на 130 работает, с бурстом нет. конечно, в крайнем случае я могу опустится до 65MHz .... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Flip-fl0p 4 18 февраля, 2021 Опубликовано 18 февраля, 2021 · Жалоба 17 минут назад, Nagisa сказал: скорость те у меня циклон 2 и я хочу 130MHz на SDRAM. без бурста на 130 работает, с бурстом нет. конечно, в крайнем случае я могу опустится до 65MHz .... Я бы для начала реализовал автомат в его классическом стиле. Более того, такие конструкции раскладываются в большую и сложную логику: always @ (posedge clk) begin if(((stater==STATE_R_WAIT ) && (rd== 1 && we==0 && rb==0)) || // мы готовы к приему сигнала чтения и он поступил + есть готовность к началу обработки - идем в STATER_PREPARE ((stater==STATE_R_PREPARE) && (q == STATE_FIRST)) || // есть команда на чтение ((stater==STATE_R_READ ) && (q == STATE_LAST)) || // чтение завершено ((stater==STATE_R_READED ) && (rd== 0)) // исходная система завершила цикл чтения ) stater <= stater + 2'd1; // меняем статус вперед end Я бы порекомендовал поработать над архитектурой контроллера, а потом уже над кодом. Для запросов - сделайте 3 разных буфера: rd, rdb , wr. И организовывайте арбитраж между этими буферами. Я когда делал SDRAM контроллер, пришел к выводу, что контроллер должен иметь максимально простой и удобный интерфейс. Адрес откуда читать\писать. Количество слов сколько писать\читать. Тип запроса, адрес или чтение. Можно чуть усложнить, добавив ID запроса и его обработку. Но это уже мелочи. Контроллер представлял собой автомат, выполняющий циклограмму SDRAM. Модуль формирования задержек, на основании которых переключался автомат. И входной буфер для хранения нескольких запросов. Над таким интерфейсом очень удобно ставить внешние арбитры, которые уже будут рулить приоритетами. Разбивать запросы на более мелкие и пр ништяки. Т.е задачей контроллера SDRAM - отработать задание. А что ему указали делать, пусть рулят арбитры))) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Nagisa 0 18 февраля, 2021 Опубликовано 18 февраля, 2021 · Жалоба 15 minutes ago, Flip-fl0p said: Я бы для начала реализовал автомат в его классическом стиле. Более того, такие конструкции раскладываются в большую и сложную логику: always @ (posedge clk) begin if(((stater==STATE_R_WAIT ) && (rd== 1 && we==0 && rb==0)) || // мы готовы к приему сигнала чтения и он поступил + есть готовность к началу обработки - идем в STATER_PREPARE ((stater==STATE_R_PREPARE) && (q == STATE_FIRST)) || // есть команда на чтение ((stater==STATE_R_READ ) && (q == STATE_LAST)) || // чтение завершено ((stater==STATE_R_READED ) && (rd== 0)) // исходная система завершила цикл чтения ) stater <= stater + 2'd1; // меняем статус вперед end Я бы порекомендовал поработать над архитектурой контроллера, а потом уже над кодом. Для запросов - сделайте 3 разных буфера: rd, rdb , wr. И организовывайте арбитраж между этими буферами. Я когда делал SDRAM контроллер, пришел к выводу, что контроллер должен иметь максимально простой и удобный интерфейс. Адрес откуда читать\писать. Количество слов сколько писать\читать. Тип запроса, адрес или чтение. Можно чуть усложнить, добавив ID запроса и его обработку. Но это уже мелочи. Контроллер представлял собой автомат, выполняющий циклограмму SDRAM. Модуль формирования задержек, на основании которых переключался автомат. И входной буфер для хранения нескольких запросов. Над таким интерфейсом очень удобно ставить внешние арбитры, которые уже будут рулить приоритетами. Разбивать запросы на более мелкие и пр ништяки. Т.е задачей контроллера SDRAM - отработать задание. А что ему указали делать, пусть рулят арбитры))) а можно конкретнее ? я потому и спрашиваю как это правильно сделать тк сам затупил. изначально я взял автомат синхронизированный с шиной, переделал на асинхронный вариант (те автомат состояний крутится постоянно), сделал защелку, прикрутил полную корректную инциализационную процедуру, все на 130 завелось а вот стал прикручивать burst и тут столкнулся с проблемами. собственно бурст мне нужен для упреждающего чтения строки в внутриплисовую память, из которой она размеренно пойдет на VGA если есть примеры реализации контроллера памяти для обслуживания проца и видеопамяти будет очень полезно идею с упрощением я понял (и пытался максимально унифицировать, включив бурст на чтение постоянно, но в обычном режиме посылая прерывание чтения), но не понял как это сделать если у меня разные адресаты и мне точно надо разделять чтение строки и одного слова. как тут правильнее сделать автомат ? и таки хочется получить ответы на вопросы в конце Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
andrew_b 16 18 февраля, 2021 Опубликовано 18 февраля, 2021 · Жалоба 2 часа назад, Nagisa сказал: также вопрос - что лучше для определения ноля ? reg [6:0] ct_rb; // счетчик burst-а wire ct_rb_zr=(ct_rb==0); или wire ct_rb_zr=~(|ct_rb); в первом случае в RTL я вижу модуль сравнения, во втором простой логический элемент Без разницы. В итоге должно получиться одно и тоже. RTL -- это как написано, так и показывает. Дальше в дело вступает оптимизатор, и смотреть надо после синтеза и разводки. Соревноваться в оптимизирующим компилятором бессмыссленно. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Flip-fl0p 4 18 февраля, 2021 Опубликовано 18 февраля, 2021 · Жалоба 2 часа назад, Nagisa сказал: а можно конкретнее ? я потому и спрашиваю как это правильно сделать тк сам затупил. изначально я взял автомат синхронизированный с шиной, переделал на асинхронный вариант (те автомат состояний крутится постоянно), сделал защелку, прикрутил полную корректную инциализационную процедуру, все на 130 завелось а вот стал прикручивать burst и тут столкнулся с проблемами. собственно бурст мне нужен для упреждающего чтения строки в внутриплисовую память, из которой она размеренно пойдет на VGA если есть примеры реализации контроллера памяти для обслуживания проца и видеопамяти будет очень полезно идею с упрощением я понял (и пытался максимально унифицировать, включив бурст на чтение постоянно, но в обычном режиме посылая прерывание чтения), но не понял как это сделать если у меня разные адресаты и мне точно надо разделять чтение строки и одного слова. как тут правильнее сделать автомат ? и таки хочется получить ответы на вопросы в конце На самом деле в SDRAM нет приниципиальной разницы читать BURST или нет. Скорость работы это не изменит. Burst просто позволяет за 1 запрос к памяти получить больше данных. Не более. В VGA можно спокойно успеть считать из SDRAM памяти данные во время интервалов гашения. Хотите правильно - рисуйте схему. Будет схема - можно будет что-то обсуждать более конкретно. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
des00 25 19 февраля, 2021 Опубликовано 19 февраля, 2021 · Жалоба On 2/19/2021 at 1:36 AM, Flip-fl0p said: Хотите правильно - рисуйте схему. Будет схема - можно будет что-то обсуждать более конкретно. @Nagisa помимо схемы, смените стиль описания ваших автоматов на case(state) bla-bla-bla. Это поможет вам увидеть ваши логические ошибки. Ну и нормальный tb с рандомной бомбардировкой контороллера вам тут сильно поможет в отладке. PS. Ну и SDRAM работает же в режиме постоянного чтения ряда, пока не потребуется переход на другой ряд. Поэтому с точки зрения доступа, что burst, что одиночный доступ, схожи (в схеме с ручным precharge). Может быть в эту сторону порыть? Тогда у вас будет автомат записи и автомат чтения. Но вообще @Flip-fl0p дело советует, один автомат, а все остальное на внешнем арбитре, который управляет очередями и формирует поток. ЗЫ. Если поможет, вот в свое время баловался https://opencores.org/projects/hssdrc Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
SVNKz 3 19 февраля, 2021 Опубликовано 19 февраля, 2021 · Жалоба Необходима НИР по исследованию временных диаграмм каждой исполняемой команды и группы команд. Эти команды выделяются отдельно и запускаются в цикле по одной, двум и т.д. с целью проверки на возможность параллельной работы. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Nagisa 0 23 февраля, 2021 Опубликовано 23 февраля, 2021 · Жалоба On 2/19/2021 at 11:20 AM, des00 said: @Nagisa помимо схемы, смените стиль описания ваших автоматов на case(state) bla-bla-bla. Это поможет вам увидеть ваши логические ошибки. Ну и нормальный tb с рандомной бомбардировкой контороллера вам тут сильно поможет в отладке. PS. Ну и SDRAM работает же в режиме постоянного чтения ряда, пока не потребуется переход на другой ряд. Поэтому с точки зрения доступа, что burst, что одиночный доступ, схожи (в схеме с ручным precharge). Может быть в эту сторону порыть? Тогда у вас будет автомат записи и автомат чтения. Но вообще @Flip-fl0p дело советует, один автомат, а все остальное на внешнем арбитре, который управляет очередями и формирует поток. ЗЫ. Если поможет, вот в свое время баловался https://opencores.org/projects/hssdrc на счет стиля, с точки зрения красоты, да case-вид лучше, но вот тестирование показало что: wire [3:0] run_cmd = (act && (q == STATE_CMD_START ))?CMD_ACTIVE: // есть чтение или запись -> начинаем процесс (!act && (q == STATE_CMD_START ))?CMD_AUTO_REFRESH: // нет ничего - авторефреш ( wre && (q == STATE_CMD_CONT ))?CMD_WRITE: // we -> запись (( oe || rb ) && (q == STATE_CMD_CONT ))?CMD_READ: // не we + oe -> чтение ( oe && (q == STATE_CMD_READ_STOP ))?CMD_BURST_TERMINATE: // тормозим чтение CMD_INHIBIT; работает на 130MHz а вот это нет- максимум 108 wire [3:0] run_cmd; always @ * begin case (q) STATE_CMD_START: if (act) run_cmd=CMD_ACTIVE; else run_cmd=CMD_AUTO_REFRESH; STATE_CMD_CONT: if (wre) run_cmd=CMD_WRITE; else if ( oe || rb ) run_cmd=CMD_READ; STATE_CMD_READ_STOP: if (oe) run_cmd=CMD_BURST_TERMINATE; default: run_cmd=CMD_INHIBIT; endcase end Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
RobFPGA 34 23 февраля, 2021 Опубликовано 23 февраля, 2021 · Жалоба Приветствую! 54 minutes ago, Nagisa said: работает на 130MHz а вот это нет- максимум 108 Это не эквивалентные описания соответственно и результат после синтеза будет другим. Например чему будет равен run_cmd в состоянии STATE_CMD_CONT если wre==0 и ( oe || rb )==0 Надо добавить еще одну строчку чтобы сделать оба варианта эквивалентными. Удачи! Rob. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Nagisa 0 23 февраля, 2021 Опубликовано 23 февраля, 2021 · Жалоба 3 hours ago, RobFPGA said: Приветствую! Это не эквивалентные описания соответственно и результат после синтеза будет другим. Например чему будет равен run_cmd в состоянии STATE_CMD_CONT если wre==0 и ( oe || rb )==0 Надо добавить еще одну строчку чтобы сделать оба варианта эквивалентными. Удачи! Rob. справедливо, но увы 130 не тянет. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Flip-fl0p 4 23 февраля, 2021 Опубликовано 23 февраля, 2021 · Жалоба 37 минут назад, Nagisa сказал: справедливо, но увы 130 не тянет. Тут есть что улучать. Без полного кода тяжко что-либо посоветовать, но мне кажется, что можно конвееризировать Ваш код. Да и атрибуты синтеза могут помочь. Например сделать автомат в виде ONE_HOT Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Nagisa 0 23 февраля, 2021 Опубликовано 23 февраля, 2021 · Жалоба да, я сейчас планирую кардинально переделать автомат, те сделать его приоритетом burst-чтение ибо сейчас или хвост или нос - или нормально работает burst-чтение или операции с шиной, совмещение несет проблемы. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Flip-fl0p 4 23 февраля, 2021 Опубликовано 23 февраля, 2021 · Жалоба 32 минуты назад, Nagisa сказал: да, я сейчас планирую кардинально переделать автомат, те сделать его приоритетом burst-чтение ибо сейчас или хвост или нос - или нормально работает burst-чтение или операции с шиной, совмещение несет проблемы. Подумайте вот над чем. Нужен ли Вам Burst. Ибо никакого преимущества скорости он не дает. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться