des00 25 23 июня, 2020 Опубликовано 23 июня, 2020 · Жалоба 4 hours ago, dxp said: 2-3 часа достаточно для того, чтобы пройти по шагам инструкции, но совершенно недостаточно для того, чтобы что-то значимое осело в голове и появилось нормальное понимание и представление. Вы забываете что тот, кому это адресовалось, уже сидит плотно в квартусе, в его симуляторе, отлаживается по светодиодам) Ну а так, как говорю всем студентам что были у меня, ПЛИСовод выращивается около 4-5 лет. Есть уникумы проходящие этот срок за 2-3 года, но меньше никак. А вот я, все никак не вырасту, хотя уже 20 лет прошло( Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
bmv89 0 23 июня, 2020 Опубликовано 23 июня, 2020 · Жалоба В общем пытаясь освоить ModelSim, написал какой-то тестбенч, который как минимум позволяет проверить работу MISO выхода. Посоветуйте пожалуйста, где можно почитать (на русском) про составление тестбенчей на verilog. В итоге получил такие же диаграммы, как и во внутреннем симуляторе (функциональном) квартуса. Есть ли принципиальная разница, где делать функциональную симуляцию? Или для решения конкретно моей простенькой задачи без симуляции с учётом временных задержек лог. элементов не обойтись? `timescale 1ns / 1ns module spi_slave_tb; reg i_core_clk; //FPGA clock reg i_cs; reg i_clk; reg [7:0]i_tx_buf; reg i_mosi; wire o_miso; wire o_irq; wire [7:0]o_rx_buf; spi_slave spi( i_core_clk, i_cs, i_clk, i_mosi, o_miso, o_irq, o_rx_buf, i_tx_buf ); always #10 i_core_clk = ~i_core_clk; always #33 i_clk = ~i_clk; initial begin i_core_clk = 0; i_cs = 1; i_clk = 0; i_tx_buf = 8'h00; #130 i_tx_buf = 8'hAB; #27 i_cs = 0; #20 i_tx_buf = 8'h00; end initial begin #3000 $finish; end initial begin $dumpfile("out.vcd"); end initial $monitor($stime,, i_core_clk,, i_cs,,, i_clk,, i_mosi,, o_miso,, o_irq,, o_rx_buf,, i_tx_buf); endmodule Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
des00 25 23 июня, 2020 Опубликовано 23 июня, 2020 · Жалоба 44 minutes ago, pinchemierda said: В итоге получил такие же диаграммы, как и во внутреннем симуляторе (функциональном) квартуса. Есть ли принципиальная разница, где делать функциональную симуляцию? Или для решения конкретно моей простенькой задачи без симуляции с учётом временных задержек лог. элементов не обойтись? отлично, большой шаг сделан. Разница в том, что в коде вы можете сделать более сложные воздействия, проще изменить сценарии и т.д. Для всего этого, нужен соответствующий инструмент. То что вы получили одинаковый результат, ожидаемо, т.к. судя по задержками в вашем коде, вы подогнали мух под котлет. Выложите ваши оба файла, чтобы можно было их покрутить в симуляторе. Там можно будет двигаться дальше, разбирая, например, вот эти ваши места: //Детектирование фронта CLK always @(posedge i_core_clk) begin sync_clk <= i_clk; if(!counter && sync_clk) begin o_irq <= 1'd1; o_rx_buf <= sr_rx; end else o_irq <= 1'd0; end always @(posedge sync_clk or posedge i_cs) begin if(i_cs) counter <= 3'd0; else begin counter <= counter + 1'd1; sr_rx <= {sr_rx[6:0], i_mosi}; end end И еще, важный момент вашей разработки, которая вам будет нужна.: разработка ТЗ на ваш модуль. Да, этот модуль занимает 20-30 строчек, но ТЗ на него вам лучше оформить. ТЗ это не предложение: "хочу SPI, 4 провода и все чтоб работало". А указание по пунктам, например: "После принятия посылки из 8 бит, модуль должен сформировать сигнал прерывания длительностью 1 такт и выдать принятые данные на внешний порт" и т.д. Еще, будет очень вам полезно, сделать вейвформы вашего модуля, с указанием воздействий. Например вот типа таких https://wavedrom.com/editor.html Когда будет готово ТЗ, если к тому моменту, ваши ошибки будут не очевидны и код вы не исправите, будем решать по ситуации) ЗЫ. вот небольшой пример тестирования со сценарием и проверкой. http://www.asic-world.com/verilog/art_testbench_writing.html Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
bmv89 0 23 июня, 2020 Опубликовано 23 июня, 2020 · Жалоба Хорошо, спасибо большое, буду действовать по инструкции)) Цитата разбирая, например, вот эти ваши места: Вы намекаете на то что сигналы i_core_clk и sync_clk синхронны только с точки зрения функциональной логики? В реальности из-за таймингов лог. элементов они рассинхронизированы? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
des00 25 23 июня, 2020 Опубликовано 23 июня, 2020 · Жалоба 18 minutes ago, pinchemierda said: Хорошо, спасибо большое, буду действовать по инструкции)) Вы намекаете на то что сигналы i_core_clk и sync_clk синхронны только с точки зрения функциональной логики? В реальности из-за таймингов лог. элементов они рассинхронизированы? бинго, у вас дизайн не синхронный никак. вроде выше обсуждалось как фронты выделять в синхронной парадигме. Это не считая странной логики прерываний) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
bmv89 0 23 июня, 2020 Опубликовано 23 июня, 2020 · Жалоба ТЗ: 1. После принятия посылки из 8 бит по линии i_mosi, модуль должен сформировать сигнал o_irq длительностью 1 такт и выдать принятые данные на внешний порт o_rx_buf. 2. Спустя минимальное количество времени после спада i_cs или фронта o_irq должны защёлкиваться 8 бит на параллельном входе i_tx_buf. Затем этот байт должен быть передан последовательно (в соответствии с протоколом SPI CPHA=0, CPOL=0) по линии o_miso. Ну сейчас то уж синхронней некуда)): module spi_slave( input i_core_clk, //FPGA clock input i_cs, input i_clk, input i_mosi, output reg o_miso, output reg o_irq, output reg [7:0]o_rx_buf, input [7:0]i_tx_buf ); reg [2:0]counter; //счётчик битов //-------------------------- MOSI --------------------------------- reg [7:0]sr_rx; //сдвиговый приёмный регистр reg clk_flag, rx_flag; always @(posedge i_core_clk or posedge i_cs) begin if(i_cs) counter <= 3'd0; else begin if(i_clk && !clk_flag) begin clk_flag <= 1'd1; if(counter == 3'd7) rx_flag <= 1'd1; counter <= counter + 1'd1; sr_rx <= {sr_rx[6:0], i_mosi}; end if(o_irq) o_irq <= 1'd0; if(rx_flag) begin rx_flag <= 1'd0; o_irq <= 1'd1; o_rx_buf <= sr_rx; end if(!i_clk) clk_flag <= 1'd0; end end //-------------------------- MISO --------------------------------- reg [7:0]sr_tx; //сдвиговый регистр отправки reg [2:0]tmp; reg cs_flag; always @(*) begin if(i_cs) o_miso = 1'dZ; else o_miso = sr_tx[7]; end always @(negedge i_core_clk) begin tmp <= counter; if(counter != tmp) sr_tx <= sr_tx << 1'd1; if(!i_cs && !cs_flag || o_irq) begin cs_flag <= 1'd1; sr_tx <= i_tx_buf; end if(i_cs) cs_flag <= 1'd0; end endmodule на выходе порта опять светомузыка, голову сломал уже... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Джеймс 3 24 июня, 2020 Опубликовано 24 июня, 2020 · Жалоба 6 hours ago, pinchemierda said: Ну сейчас то уж синхронней некуда)): на выходе порта опять светомузыка, голову сломал уже... Т.е. вы хотите сказать, что в ModelSim это работает? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
andrew_b 14 24 июня, 2020 Опубликовано 24 июня, 2020 · Жалоба 11 часов назад, pinchemierda сказал: Ну сейчас то уж синхронней некуда)): Зря вы так думаете. always @(posedge i_core_clk or posedge i_cs) begin if(i_cs) counter <= 3'd0; else i_cs ни разу не синхронен i_core_clk. Тут надо или переносить i_cs и i_clk на i_core_clk, если частота позволяет, или принимать на i_clk, а по окончании приёма перенести принятое на i_clk. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
bmv89 0 24 июня, 2020 Опубликовано 24 июня, 2020 · Жалоба Цитата Т.е. вы хотите сказать, что в ModelSim это работает? Функциональную симуляцию делал только. Да, работает в симуляции. Цитата i_cs ни разу не синхронен i_core_clk Да цель и не в том, чтобы было супер синхронно. Цель в том, чтобы было правильно и в железе заработало. Вроде нет ошибки в том что я присваиваю константу в этом месте (асинхронный сброс counter). Вполне допустимый приём и часто используется. Или опять ошибаюсь? До этого пытался запустить вариант, найденный в интернете. Но проблема ровно такая же. В симуляторе всё хорошо, а в железе хрень. Там как раз было реализовано так, что принималось на SPI CLK, а по окончании приёма переносилось принятое на FPGA CLK. Но я подумал, что именно из-за этого то и не работает. Как мне тут уже замечание делали, в списке чувствительности асинхронный сигнал (SPI CLK). И, якобы, из этого следует, что он бесконечной частоты и это всё очень плохо и т.д.... Вот этот пример реализации. В общем в железе он тоже не работает: module SPI_Slave ( // Control/Data Signals, input i_Clk, // FPGA Clock output reg o_RX_DV, // Data Valid pulse (1 clock cycle) output reg [7:0] o_RX_Byte, // Byte received on MOSI input [7:0] i_TX_Byte, // Byte to serialize to MISO. // SPI Interface input i_SPI_Clk, output o_SPI_MISO, input i_SPI_MOSI, input i_SPI_CS_n ); wire w_SPI_MISO_Mux; reg [2:0] r_RX_Bit_Count; reg [2:0] r_TX_Bit_Count; reg [7:0] r_Temp_RX_Byte; reg [7:0] r_RX_Byte; reg r_RX_Done, r2_RX_Done, r3_RX_Done; reg r_SPI_MISO_Bit, r_Preload_MISO; // Purpose: Recover SPI Byte in SPI Clock Domain // Samples line on correct edge of SPI Clock always @(posedge i_SPI_Clk or posedge i_SPI_CS_n) begin if (i_SPI_CS_n) begin r_RX_Bit_Count <= 3'd0; r_RX_Done <= 1'b0; end else begin r_RX_Bit_Count <= r_RX_Bit_Count + 3'd1; // Receive in LSB, shift up to MSB r_Temp_RX_Byte <= {r_Temp_RX_Byte[6:0], i_SPI_MOSI}; if (r_RX_Bit_Count == 3'b111) begin r_RX_Done <= 1'b1; r_RX_Byte <= {r_Temp_RX_Byte[6:0], i_SPI_MOSI}; end else if (r_RX_Bit_Count == 3'b010) begin r_RX_Done <= 1'b0; end end // else: !if(i_SPI_CS_n) end // always @ (posedge i_SPI_Clk or posedge i_SPI_CS_n) // Purpose: Cross from SPI Clock Domain to main FPGA clock domain // Assert o_RX_DV for 1 clock cycle when o_RX_Byte has valid data. always @(posedge i_Clk) begin // Here is where clock domains are crossed. // This will require timing constraint created, can set up long path. r2_RX_Done <= r_RX_Done; r3_RX_Done <= r2_RX_Done; if (r3_RX_Done == 1'b0 && r2_RX_Done == 1'b1) // rising edge begin o_RX_DV <= 1'b1; // Pulse Data Valid 1 clock cycle o_RX_Byte <= r_RX_Byte; end else begin o_RX_DV <= 1'b0; end end // always @ (posedge i_Bus_Clk) // Control preload signal. Should be 1 when CS is high, but as soon as // first clock edge is seen it goes low. always @(posedge i_SPI_Clk or posedge i_SPI_CS_n) begin if (i_SPI_CS_n) begin r_Preload_MISO <= 1'b1; end else begin r_Preload_MISO <= 1'b0; end end // Purpose: Transmits 1 SPI Byte whenever SPI clock is toggling // Will transmit read data back to SW over MISO line. // Want to put data on the line immediately when CS goes low. always @(posedge i_SPI_Clk or posedge i_SPI_CS_n) begin if (i_SPI_CS_n) begin r_TX_Bit_Count <= 3'b111; // Send MSb first r_SPI_MISO_Bit <= i_TX_Byte[3'b111]; // Reset to MSb end else begin r_TX_Bit_Count <= r_TX_Bit_Count - 1'd1; // Here is where data crosses clock domains from i_Clk to i_SPI_Clk // Can set up a timing constraint with wide margin for data path. r_SPI_MISO_Bit <= i_TX_Byte[r_TX_Bit_Count]; end // else: !if(i_SPI_CS_n) end // always @ (negedge i_SPI_Clk or posedge i_SPI_CS_n_SW) // Preload MISO with top bit of send data when preload selector is high. // Otherwise just send the normal MISO data assign w_SPI_MISO_Mux = r_Preload_MISO ? i_TX_Byte[3'b111] : r_SPI_MISO_Bit; // Tri-statae MISO when CS is high. Allows for multiple slaves to talk. assign o_SPI_MISO = i_SPI_CS_n ? 1'bZ : w_SPI_MISO_Mux; endmodule // SPI_Slave И тут наблюдается такое же поведение в железе, как и в моём варианте: Если не делать никаких действий с параллельным входом модуля (i_tx_buf у меня), т.е. не выводить его наружу и ничего в него не писать, то байты по линии i_mosi принимаются правильно. Так же приём работает правильно, если закомментировать в коде всё что связано с отправкой по o_miso. В железе тестирую следующим образом: По mosi шлю микроконтроллером байт каждые 50 мс в бесконечном цикле от 0 до 255. И наблюдаю за светодиодами, подключёнными к порту o_rx_buf. В результате биты этого порта будто бы местами меняются в хаотичном порядке (с частотой 100 - 1000 мс). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Plain 168 24 июня, 2020 Опубликовано 24 июня, 2020 · Жалоба 13 часов назад, pinchemierda сказал: ТЗ: 1. После принятия посылки из 8 бит по линии i_mosi, модуль должен сформировать сигнал o_irq длительностью 1 такт и выдать принятые данные на внешний порт o_rx_buf Пару месяцев назад уже была тема с практически таким же ТЗ и практически так же называлась. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
bmv89 0 24 июня, 2020 Опубликовано 24 июня, 2020 · Жалоба Цитата Пару месяцев назад уже была тема с практически таким же ТЗ и практически так же называлась Этот пример вообще не понял, с дебаунсами какими-то, под 100 ЛЕ ещё занимает. Особо не вникал, просто скопировал. В симуляции он вообще ни на какие входные сигналы у меня не реагировал сначала. В приёмном буфере всегда 8'd0. Оказывается, чтобы заработало надо на CS единицу подать (лол!). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
bmv89 0 24 июня, 2020 Опубликовано 24 июня, 2020 · Жалоба Зато в железе он принимает байты правильно, но отправляет всё равно не то. Да и моему тз он мягко говоря не очень соответствует. Не хочу чужой под себя переделывать. Хочу свой до ума довести и уложиться в 35-50 ЛЕ, всё таки. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Джеймс 3 24 июня, 2020 Опубликовано 24 июня, 2020 · Жалоба 1 hour ago, pinchemierda said: Зато в железе он принимает байты правильно, но отправляет всё равно не то. Да и моему тз он мягко говоря не очень соответствует. Не хочу чужой под себя переделывать. Хочу свой до ума довести и уложиться в 35-50 ЛЕ, всё таки. Хотите до ума довести - доводите. Вопрос #1 - у вас reset генератор на плате есть? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
bmv89 0 24 июня, 2020 Опубликовано 24 июня, 2020 · Жалоба Прошу прощения за тупой вопрос, что за reset генератор? На плате кварцевый генератор 50МГц, его вход разрешения enable жёстко заведён на 3.3в, к плис не подключен. Или Вы не про это? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Джеймс 3 24 июня, 2020 Опубликовано 24 июня, 2020 · Жалоба 1 hour ago, pinchemierda said: Прошу прощения за тупой вопрос, что за reset генератор? На плате кварцевый генератор 50МГц, его вход разрешения enable жёстко заведён на 3.3в, к плис не подключен. Или Вы не про это? Плата типа такой? Cхему можете прикрепить? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться