bmv89 0 1 июня, 2020 Опубликовано 1 июня, 2020 · Жалоба Здравствуйте, знатоки ПЛИС! Только что начал познавать ПЛИС и Verilog. Просмотрел несколько роликов для новичков, прочитал пару методичек университетских. Для закрепления материала попытался написать простенький контроллер SDRAM. Просимулировал в Qartus2, логика работы в принципе устраивает. Но очень смущает большое количество warning-ов, особенно "Latch has unsafe behavior". Помогите избавиться от защёлок! Сильно не пинайте, слово "верилог" первый раз услышал две недели назад))) `define SDRAM_IDLE 3'd0 `define SDRAM_INIT 3'd1 `define SDRAM_START_W 3'd2 `define SDRAM_W_BYTE 3'd3 `define SDRAM_STOP_WR 3'd4 `define SDRAM_START_R 3'd5 `define SDRAM_R_BYTE 3'd6 module SDRAM( input i_clk, //FPGA clock input i_STROB, //строб команды input [2:0]i_cmd, //индекс команды драйвера SDRAM output reg o_IRQ, //флаг события input [11:0]o_PAGE_ADR, //Адрес строки (в обоих банках), 11ый бит - выбор банка (BA) input [15:0]i_W_BUF, //Буфер для записи output reg [15:0]i_R_BUF, //Буфер для чтения //SDRAM pins output wire o_CLK, //SDRAM CLK output reg o_WE, output reg o_CAS, output reg o_RAS, output reg o_CS, output reg o_BA, output reg o_CKE, output reg [10:0]o_ADR, //SDRAM ADRES inout reg [15:0]io_DATA //SDRAM DATA ); reg [8:0]counter; reg [2:0]cmd; reg e_CLK; assign o_CLK = ~i_clk & e_CLK; //& pe_CLK; //Логика таймера always @(posedge i_clk or posedge i_STROB) begin if(i_STROB) begin counter <= 9'd0; end else begin counter <= counter + 1'd1; end end //Логика разрешения тактирования SDRAM (e_CLK) always @(o_IRQ) begin if(o_IRQ) e_CLK <= 1'd0; else e_CLK <= 1'd1; end //Логика выхода o_IRQ и переключения режимов cmd always @(posedge i_clk or posedge i_STROB) begin if(i_STROB) begin cmd <= i_cmd; o_IRQ <= 1'd0; end else begin //Логика работы выхода o_IRQ case(cmd) default: o_IRQ <= 1'd0; `SDRAM_INIT: begin if(counter == 9'd8) o_IRQ <= 1'd1; end `SDRAM_START_W: begin if(counter == 9'd1) o_IRQ <= 1'd1; end `SDRAM_W_BYTE: begin if(counter == 9'd0) o_IRQ <= 1'd1; end `SDRAM_STOP_WR: begin if(counter == 9'd0) o_IRQ <= 1'd1; end `SDRAM_START_R: begin if(counter == 9'd3) o_IRQ <= 1'd1; end `SDRAM_R_BYTE: begin if(counter == 9'd0) o_IRQ <= 1'd1; end endcase end //else if(i_STROB) end //always @(posedge i_clk or posedge i_STROB) //Основной блок логики отработки режимов always @(negedge o_CLK or posedge i_STROB) begin case(cmd) default: //Бездействие begin NOP_CMD (o_WE,o_CAS,o_RAS,o_CS,o_BA,o_CKE,o_ADR[10]); io_DATA <= 16'dZ; end //default `SDRAM_INIT: //Инициализация begin io_DATA <= 16'dZ; case(counter) 9'd0: NOP_CMD (o_WE,o_CAS,o_RAS,o_CS,o_BA,o_CKE,o_ADR[10]); 9'd2: PRECHARGE_ALL_BANKS_CMD (o_WE,o_CAS,o_RAS,o_CS,o_BA,o_CKE,o_ADR[10]); 9'd3: AUTO_REFRESH_CMD (o_WE,o_CAS,o_RAS,o_CS,o_BA,o_CKE,o_ADR[10]); 9'd5: NOP_CMD (o_WE,o_CAS,o_RAS,o_CS,o_BA,o_CKE,o_ADR[10]); 9'd6: MOD_REG_SET_CMD (o_WE,o_CAS,o_RAS,o_CS,o_BA,o_CKE,o_ADR); 9'd7: NOP_CMD (o_WE,o_CAS,o_RAS,o_CS,o_BA,o_CKE,o_ADR[10]); default: NOP_CMD (o_WE,o_CAS,o_RAS,o_CS,o_BA,o_CKE,o_ADR[10]); endcase end //cmd = SDRAM_INIT `SDRAM_START_W: //Запись data[0] begin if(counter == 9'd0) begin io_DATA <= 16'dZ; o_ADR <= o_PAGE_ADR[10:0]; o_BA <= o_PAGE_ADR[11]; ROW_ACTIVE_CMD(o_WE,o_CAS,o_RAS,o_CS,o_CKE); end if(counter == 9'd1) begin o_ADR <= 11'd0; o_BA <= o_PAGE_ADR[11]; io_DATA <= i_W_BUF; //записываем data[0] WRITE_CMD(o_WE,o_CAS,o_RAS,o_CS,o_CKE); end end //cmd = SDRAM_START_W `SDRAM_W_BYTE: //Запись data[1]...data[255] begin io_DATA <= i_W_BUF; //записываем остальные байты NOP_CMD (o_WE,o_CAS,o_RAS,o_CS,o_BA,o_CKE,o_ADR[10]); end //cmd = SDRAM_W_BYTE `SDRAM_STOP_WR: //Стоп запись/чтение begin io_DATA <= 16'dZ; o_ADR <= 11'd0; o_BA <= o_PAGE_ADR[11]; PRECHARGE_ROW_CMD (o_WE,o_CAS,o_RAS,o_CS,o_CKE); end //cmd = SDRAM_STOP_WR `SDRAM_START_R: //Чтение begin if(counter == 9'd0) begin io_DATA <= 16'dZ; o_ADR <= o_PAGE_ADR[10:0]; o_BA <= o_PAGE_ADR[11]; ROW_ACTIVE_CMD(o_WE,o_CAS,o_RAS,o_CS,o_CKE); end if(counter == 9'd1) begin o_ADR <= 11'd0; o_BA <= o_PAGE_ADR[11]; READ_CMD(o_WE,o_CAS,o_RAS,o_CS,o_CKE); end if(counter == 9'd2) NOP_CMD (o_WE,o_CAS,o_RAS,o_CS,o_BA,o_CKE,o_ADR[10]); if(counter == 9'd4) i_R_BUF <= io_DATA; //Читаем data[0] end //cmd = SDRAM_START_R `SDRAM_R_BYTE: //Чтение data[1]...data[255] begin if(!o_IRQ) i_R_BUF <= io_DATA; //Читаем остальное NOP_CMD (o_WE,o_CAS,o_RAS,o_CS,o_BA,o_CKE,o_ADR[10]); end //cmd = SDRAM_R_BYTE endcase //case(i_cmd) end //always @(negedge o_CLK or posedge i_STROB) //----------------------------------------- CMD ------------------------------------------- task PRECHARGE_ALL_BANKS_CMD; output we,cas,ras,cs,ba,cke,a10_ap; begin cke <= 1; cs <= 0; ras <= 0; cas <= 1; ba <= 1'bX; a10_ap <= 1; we <= 0; end endtask task AUTO_REFRESH_CMD; output we,cas,ras,cs,ba,cke,a10_ap; begin cke <= 1; cs <= 0; ras <= 0; cas <= 0; ba <= 1'bX; a10_ap <= 1'bX; we <= 1; end endtask task NOP_CMD; output we,cas,ras,cs,ba,cke,a10_ap; begin cke <= 1; cs <= 1; ras <= 1; cas <= 1; ba <= 0; a10_ap <= 0; we <= 1; end endtask task MOD_REG_SET_CMD; //Full page, Sequential, Latency 2 (11'h27) output we,cas,ras,cs,ba,cke; output reg [10:0]adr; begin cke <= 1; cs <= 0; ras <= 0; cas <= 0; ba <= 0; we <= 0; adr <= 11'h27; end endtask task ROW_ACTIVE_CMD; output we,cas,ras,cs,cke; begin cke <= 1; cs <= 0; ras <= 0; cas <= 1; we <= 1; end endtask task READ_CMD; output we,cas,ras,cs,cke; begin cke <= 1; cs <= 0; ras <= 1; cas <= 0; we <= 1; end endtask task WRITE_CMD; output we,cas,ras,cs,cke; begin cke <= 1; cs <= 0; ras <= 1; cas <= 0; we <= 0; end endtask task PRECHARGE_ROW_CMD; output we,cas,ras,cs,cke; begin cke <= 1; cs <= 0; ras <= 0; cas <= 1; we <= 0; end endtask task SELF_REF_ENTRY_CMD; output we,cas,ras,cs,ba,cke,a10_ap; begin cke <= 0; cs <= 0; ras <= 0; cas <= 0; ba <= 0; a10_ap <= 0; we <= 1; end endtask task SELF_REF_EXIT_CMD; output we,cas,ras,cs,ba,cke,a10_ap; begin cke <= 1; cs <= 1; ras <= 0; cas <= 0; ba <= 0; a10_ap <= 0; we <= 0; end endtask //----------------------------------------- END CMD ------------------------------------------- endmodule //module EPM240_Test Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Mad_kvmg 0 1 июня, 2020 Опубликовано 1 июня, 2020 · Жалоба 7 hours ago, pinchemierda said: always @(posedge i_clk or posedge i_STROB) Начните с того, что уберите из always posedge i_STROB, оставьте просто posedge i_clk Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
bmv89 0 1 июня, 2020 Опубликовано 1 июня, 2020 · Жалоба Да, уже догадался, что является причиной возникновения защёлок. Не могу придумать как убрать эту причину, не изменив всей логики работы. Мне именно нужно, чтобы содержимое этого always блока выполнялось и при фронте i_clk и при фронте i_STROB. Проверил ещё вариант у которого в списке чувствительности оба сигнала и при котором не образуются защёлки, но он в 2 раза больше ЛЕ занимает: always @(posedge i_clk or posedge i_STROB) begin if(i_STROB) begin //тут делаем всё что нужно end else begin //тут тупо делаем всё тоже самое end end Нужно чтобы логика выполнения содержимого always блока не зависело от уровня i_STROB, когда происходит событие posedge i_clk. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dvladim 0 1 июня, 2020 Опубликовано 1 июня, 2020 · Жалоба 38 минут назад, pinchemierda сказал: и при фронте i_clk и при фронте i_STROB не получится. В ПЛИС нет триггеров с двумя клоками. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
bmv89 0 1 июня, 2020 Опубликовано 1 июня, 2020 · Жалоба а как тогда работают структуры типа: always @(posedge clk or posedge reset) begin if(reset) begin // асинхронный сброс (к примеру) чего-нибудь end else begin // какое-то действие на каждом фронте clk end end Содержимое блока чувствительно одновременно к двум фронтам, или ошибаюсь? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Plain 168 1 июня, 2020 Опубликовано 1 июня, 2020 · Жалоба Синхросигнал должен быть один. Сигнал квитирования должен быть синхронным сам по себе и готовым к употреблению, т.е. однотактовым, либо нужное его изменение определять на месте. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dvladim 0 1 июня, 2020 Опубликовано 1 июня, 2020 · Жалоба 33 минуты назад, pinchemierda сказал: а как тогда работают структуры типа: Работают как триггер со сбросом )). Но никак не триггер с двумя клоками. Тут нужно понимать, что когда активен сброс действия по клоку не выполняются. И сбросом вы можете присвоить регистру только константу. PS. Сейчас конечно набегут люди и будут говорить, что не только константу, но другое только с серьезными извращениями. Типичное применение - как описано выше. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
bmv89 0 1 июня, 2020 Опубликовано 1 июня, 2020 (изменено) · Жалоба Такой логики пытаюсь добиться (но без защёлок пока не выходит): Придумал как сократить количество сигналов в списке чувствительности до одного. При этом (по идее) логика работы должна остаться без изменений. Добавил переменную wire trig и сделал так чтобы она косвенно зависела от i_STROB и i_clk wire trig; assign trig = ~o_CLK & ~o_IRQ; always @(posedge trig) begin //........ end в результате получил такую картинку (защёлок уже нет, как и нормальной работы модуля): Почему по фронту trig не выставляется соответствующая команда com (0x15)? com = 0x15 выставляется по ближайшему фронту i_clk. Изменено 1 июня, 2020 пользователем pinchemierda Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Plain 168 1 июня, 2020 Опубликовано 1 июня, 2020 · Жалоба Увеличьте тактовую частоту хотя бы на порядок. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
iosifk 3 1 июня, 2020 Опубликовано 1 июня, 2020 · Жалоба 7 минут назад, Plain сказал: Увеличьте тактовую частоту хотя бы на порядок. Добавлю. И сделайте синхронный проект(искать в сети по этим словам), а не выкладывайте картинки из фильмов ужаса... Иначе эти "почему по фронту trig" будут Вас преследовать очень и очень долго... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
bmv89 0 1 июня, 2020 Опубликовано 1 июня, 2020 · Жалоба Цитата Увеличьте тактовую частоту хотя бы на порядок. Ааа, ну так не интересно)) Если тактирование SDRAM делать с частотой хотя бы в 2 раза меньше тактовой CPLD это сильно упрощает реализацию. Развлекаюсь с простенькой платкой с EPM240 (нет PLL) и генератором на 50 МГц. Не хотелось бы опускаться ниже этой частоты. В общем ясно, я фигнёй занимаюсь. Просто если делать всё синхронно, то частота тактирования SDRAM снижается. Хотелось задействовать каждый такт генератора с максимальной пользой, так сказать... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Plain 168 1 июня, 2020 Опубликовано 1 июня, 2020 (изменено) · Жалоба То же самое другими словами — устраните в ТЗ все частоты больше тактовой. Конкретно речь про некий сигнал квитирования, асинхронный — следовательно, бесконечной частоты. Изменено 1 июня, 2020 пользователем Plain Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
iosifk 3 1 июня, 2020 Опубликовано 1 июня, 2020 · Жалоба 54 минуты назад, pinchemierda сказал: Развлекаюсь с простенькой платкой с EPM240 (нет PLL) и генератором на 50 МГц. Не хотелось бы опускаться ниже этой частоты. В общем ясно, я фигнёй занимаюсь. Просто если делать всё синхронно, то частота тактирования SDRAM снижается. Хотелось задействовать каждый такт генератора с максимальной пользой, так сказать... На самом деле все это "по-Суворовски, через Альпы". При всем моем уважении к полководцу... Как я понял ТС, у него есть задача: Научиться работать с ПЛИС. И, соответственно, должны быть пути ее решения. Так вот, в данном случае, абсолютно неверно выбран путь. EPM240 абсолютно не годится для тренировок. Несколько десятков перепрошивок и кранты... Невозможно использовать встроенный логический анализатор. Сложности с укладкой проекта в кристалл. И зачем SDRAM к этой CPLD тоже не понятно... И далее из неправильных установок следуют неправильные выводы: "Если тактирование SDRAM делать с частотой хотя бы в 2 раза меньше тактовой CPLD это сильно упрощает реализацию." А так, чисто по жизни, если нет умения делать RTL проекты, то и плата, как таковая не нужна... А уж купить недорогую FPGA, даже и не новой серии - сегодня вообще не проблема... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
bmv89 0 2 июня, 2020 Опубликовано 2 июня, 2020 · Жалоба Цитата Конкретно речь про некий сигнал квитирования, асинхронный — следовательно, бесконечной частоты. Источником этого сигнала конкретно в этом проекте хотел сделать микроконтроллер, частота то его уж точно не выше частоты тактирования ПЛИС. Задумывалось что-то типа переходника SDRAM<->SPI для подключения оперативки к мк без FMC (по SPI). И речь даже не идёт о том, что есть реальная задача, которую необходимо решить оптимальным путём. Цитата Несколько десятков перепрошивок и кранты... В сотню попыток бы я уж уложился. Не мало важно для меня, что цена чипа на уровне стоимости чебурека. Всякие циклоны за 2к+ пока что не рассматриваю. Рассматриваю ПЛИС пока что, только как расширитель аппаратных возможностей микроконтроллера. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Plain 168 2 июня, 2020 Опубликовано 2 июня, 2020 · Жалоба 1 час назад, pinchemierda сказал: что-то типа переходника SDRAM<->SPI Ну да, т.е. этот отсутствующий модуль SPI, находящийся в той же ПЛИС, по той же задумке тоже должен был быть асинхронным и создавать асинхронные сигналы другому модулю, находящемуся в той же ПЛИС. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться