Перейти к содержанию
    

Начинаю изучать FPGA (verilog)

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

7 часов назад, one_eight_seven сказал:

1. В интерфейсе эта переменная может быть за пределами таска. (В модуле тоже)

2. Зачем вам неблокирующее присваивание?

1. Хочется внутри и чтобы сохранялась между вызовами таска, который расположен в модуле

2. Не нужно :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

33 minutes ago, HardRock said:

1. Хочется внутри и чтобы сохранялась между вызовами таска, который расположен в модуле

2. Не нужно :)

1a. Так пожалуйста, объявляете переменную в модуле, и обращаетесь к ней в таске, который также объявлен в модуле.

1b. Вы можете объявить таск в модуле, а внутри таска - статическую переменную. Но, она будет статической в пределах области видимости модуля, но автоматической в том смысле, что внутри каждого экземпляра этого модуля она будет своя.

2. Так зачем вы его используете?

Ну и самое главное - вам далеко ехать до компиляторов-симуляторов? Почему вы не можете взять и попробовать что-то в этом роде?
 

Spoiler

task non_module_update();
    static int value = 0;
    value ++;
    $display("outside of module task : %d", value);
endtask

module A #(parameter string NAME = "A");

    task update ();
        static int value = 0;
        value ++;
        $display("%s : %d", NAME, value);
    endtask : update

    task nmu();
        non_module_update();
    endtask : nmu

endmodule : A

module test;

    A #( .NAME("A1") ) a1 ();
    A #( .NAME("A2") ) a2 ();

    initial begin
        a1.update();
        a1.update();
        a2.update();
        a1.nmu();
        a1.update();
        a2.update();
        a2.nmu();
        a1.nmu();
    end
endmodule : test

 

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

P.S. Результат выполнения кода выше:
 

Spoiler

A1 :           1
A1 :           2
A2 :           1
outside of module task :           1
A1 :           3
A2 :           2
outside of module task :           2
outside of module task :           3

 

 

Изменено пользователем one_eight_seven

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

К сожалению ваш код не синтезируется. Падает на первом обращении a1.update() ошибкой

Цитата

Error (10207): Verilog HDL error at pwm.sv(172): can't resolve reference to object "update"

 

В свою очередь такая таска, определенная вне модуля (да и в модуле тоже)

task CMD_TEST(ref reset, ref reg[7:0] __MEMORY__[4], input wire [7:0] rx_byte) ;
  static int channel_id = 0;  
  
  if (reset) begin
    channel_id  <= rx_byte;
    reset       <= 0;
  end else begin
    __MEMORY__[channel_id] <= rx_byte;
  end
  
endtask

не синтезируется с ошибкой

Цитата

Error (10959): SystemVerilog error at pwm.sv(12): illegal assignment - automatic variables can't have non-blocking assignments

указывает на строку "channel_id  <= rx_byte;"

Если заменить на блокирующее присваивание, то синтезируется, но channel_id не сохраняется между вызовами. 

Вызываю так:

always @(posedge clk) begin
 
  ...
  
        // --- Execute command
        SPI_STATE_CMD: begin
          case (spi_session_cmd)
            // - Set PWM channel value
            //SPI_CMD_SET_PWM: CMD_SetPWMChannel(spi_session_cmd_reset, spi_rx_buffer);
              

            SPI_CMD_GET_PWM: CMD_TEST(spi_session_cmd_reset, __MEMORY__, spi_rx_buffer);
           
          endcase
        end
  ...
end

Если channel_id вытащить из таски в модуль, откуда она вызывается  - то всё прекрасно работает.

 

3 часа назад, des00 сказал:

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

Интернет есть, изучил книги, в том числе цикл статей от iosifk. Делаю как "должно быть", но оно не работает. Для меня это выглядит как глюк.

Либо есть какие-то неявные ограничения, либо какой-то момент упустил.

 

Использую Quartus Prime 19.11 Lite, синтезирую под Cyclone IV EP4CE6E22C8, язык SystemVerilog HDL.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

6 minutes ago, HardRock said:

К сожалению ваш код не синтезируется.

Это потому что он несинтезируемый. Это концепт, показывающий, как работает static для переменных, объявленных в тасках, и почему они всё-таки automatic.

Как вы этот код затянули к себе  - это и вовсе тайна, покрытая медным тазом, но синтезируете вы не мой код: У меня просто нет 172 строки.

Если нужно синтезируемое, то никаких печатей, никаких string'ов, никаких int'ов - выводите значение из task'ов в output аргументы. Сделайте счётчик типа logic[WIDTH-1:0], его значение смотрите на вейвформах.

Ну и ещё... Так и непонятно, чем вас не устраивает нормальный и работающий вариант, который у вас уже получился? Это нормально - использовать в task'ах то, что объявлено за их пределами.

Изменено пользователем one_eight_seven

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

3 минуты назад, HardRock сказал:

Интернет есть, изучил книги, в том числе цикл статей от iosifk. Делаю как "должно быть", но оно не работает. Для меня это выглядит как глюк.

Либо есть какие-то неявные ограничения, либо какой-то момент упустил.

Использую Quartus Prime 19.11 Lite, синтезирую под Cyclone IV EP4CE6E22C8, язык SystemVerilog HDL.

Когда Вам говорят как правильно делать Вы все советы игнорируете. Так-что Вы не просто пропустили какие-то важные моменты. Вы их просто проигнорировали. Единственное что Вы делаете - бездумно копируете чужой код в свой проект в надежде что заработает. При этом Вы совсем не знаете языка на котором пишите. Вы потратили кучу времени, но как говорил Иван Андреевич Крылов : "А воз и ныне там". 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

 

16 минут назад, one_eight_seven сказал:

Как вы этот код затянули к себе  - это и вовсе тайна, покрытая медным тазом,

Ну как, копипастой, но не 1 в 1, всетаки не настолько тупой :D

Вот если завернуть в интерфейс

interface TestCommand;
  reg [7:0] channel_id = 0; 
  
  task run(ref reset, ref reg [7:0] __MEMORY__[4], input wire [7:0] rx_byte);
    if (reset) begin
      channel_id  <= rx_byte;
      reset       <= 0;
    end else begin
      __MEMORY__[channel_id] <= rx_byte;
    end
  endtask

endinterface

и потом вызывать, то всё работает. Но выглядит как костыль немного. Хотя работает и такой вариант меня устроит. Но тема почему не работают стает статик - остаётся открытой.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

10 minutes ago, HardRock said:

Но выглядит как костыль немного.

Но это потому что вы сделали это как костыль. Интерфейс должен включать в себя всё, что нужно. А так, как вы делаете - ни таски ни интерфейсы не нужны. Вы всё-равно не делаете то, что декларировали, и не достигаете тех целей. которые декларировали.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

11 минут назад, Flip-fl0p сказал:

Когда Вам говорят как правильно делать Вы все советы игнорируете. Так-что Вы не просто пропустили какие-то важные моменты. Вы их просто проигнорировали. Единственное что Вы делаете - бездумно копируете чужой код в свой проект в надежде что заработает. При этом Вы совсем не знаете языка на котором пишите. Вы потратили кучу времени, но как говорил Иван Андреевич Крылов : "А воз и ныне там". 

Впервые близко этот язык увидел в прошлую среду. Так что да, не знаю языка на котором пишу, это правда. Только изучаю.

И кстати ни одной копипасты, даже когда разбираю примеры из интернета, то переписываю почти всегда с модификациями, но сохранением подхода. Воз тоже разгоняется ударными темпами и без копипасты. Начал с мигания светодиодом, теперь N светодиодов меняют яркость с управлением по SPI с протоколом обмена.

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

Вобщем меня интересует информация по различным нюансам, как например со static внутри таска - почему не работает и бест-практис так сказать в разработке, остальное способен расковырять сам.

4 минуты назад, one_eight_seven сказал:

Но это потому что вы сделали это как костыль. Интерфейс должен включать в себя всё, что нужно. А так, как вы делаете - ни таски ни интерфейсы не нужны. Вы всё-равно не делаете то, что декларировали, и не достигаете тех целей. которые декларировали.

Какие могут быть альтернативы интерфейсу? Классы на сколько понял не синтезируются, дернуть таску из другого модуля нельзя потому что область видимости внутри модуля. Статик переменные в таске не работают хз почему. Выносить все кишки таска в основной модуль не хочу по соображениям архитектуры и чистоты кода.

Когда потребуется добавить новую команду SPI, то хочется просто вставить файл в проект и в основном модуле добавить опцию в case.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

8 minutes ago, HardRock said:

Какие могут быть альтернативы интерфейсу?

Дело не в интерфейсе, а в том, как вы его используете. У вас просто интерфейс, который не выполняет функцию интерфейса. Он у вас только для инстанциирования одной внутренней переменной.
Ну вы теперь ещё для каждого сигнала, который использует или обновляет таск добавьте по интерфейсу, сделаете "луковицу", которая только всё усложняет.

Таск - понятно, он, в случае синтеза выступает лишь немногим отличаясь от текстового макро, но интерфейс - это, как и модуль, сущность, созданная для абстракции, а не для обозначения области видимости для переменной.

8 minutes ago, HardRock said:

Выносить все кишки таска в основной модуль не хочу по соображениям архитектуры и чистоты кода.

Точно? Ведь вы именно это сделали, только спрятали одну переменную в интерфейс, чтобы сложнее было разобраться в паутине тесных связей, которые вы нагородили. В этом случае лучше оставить это в модуле, чтобы оно было хотя бы очевидно.
 

Quote


Статик переменные в таске не работают хз почему.

 

Работают, и я выше показал, что работают. Но у вас задача другая. Вы хотите их синтезировать. Например, Inline инициализация статических переменных внутри тасков - несинтзируема (в моём примере оно имено такое). Кроме того, SystemVerilog, Verilog и т.д. - в первую очередь языки для симуляции, а не для синтеза, поэтому, то, что вы хотите синтезировать нужно делать максимально прозрачно, чтобы вы сами могли вообще без вопросов сказать, при каких уровнях на каких линиях (проводах) произойдёт то или иное.
Ну и расскажите, как это будет в случае статической переменной, если одновременно будут вызваны несколько тасков, которые изменяют значение этой переменной.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

35 минут назад, HardRock сказал:

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

Вот только даже в простых проектах нужен симулятор. Путь разработки примерно такой:

Структурная схема --> HDL описание --> modelsim --> временной анализ --> дебаг в реальной железке. 

Тем более Вы только начали изучать ПЛИС. Вам 100% обязательна работа с симулятором.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

one_eight_seven, теперь понятно, в синтезе это является ограничением :good:

Выходит ключевое слово interface - это нормально для абстракции, а не только для описания собственно интерфейсов между модулями.

31 минуту назад, one_eight_seven сказал:

Ну и расскажите, как это будет в случае статической переменной, если одновременно будут вызваны несколько тасков, которые изменяют значение этой переменной.

Нормальным поведением было бы как в "обычных" языках программирования. Если какая-то переменная объявлена в таске как статик, то она имеет область видимости внутри таска, но физически располагается компилятором в глобальном пространстве чтобы обеспечить сохранение значения между отдельными вызовами таска. В "обычных" языках в случае обращения к такой переменной из разных потоков её состояние будет не определено ввиду гонки. Для HDL логично было бы отслеживать такое обращение и выдавать ошибку, как это сделано с присвоением одной переменной в разных блоках always. Однако тут статик неявно становится не статиком.

Ну тоесть ожидалось что код:

task MyTask(ref value);
  static reg [8:0] count;

  count <= value;
end

Будет расценен компилятором в синтезе как

reg [8:0] count;

task MyTask(ref value);
  count <= value;
end

Но это оказывается не так, и это есть тот нюанс, который либо знаешь либо нет. Потому что компилятор игнорирует слово static и переменная становится reentrant, как без слова static. Более того, если указано слово static, то компилятор начинает считать переменную automatic и запрещает неблокирующее присвоение. Выглядит как бага в компиляторе, честно :D

31 минуту назад, one_eight_seven сказал:

Точно? Ведь вы именно это сделали, только спрятали одну переменную в интерфейс, чтобы сложнее было разобраться в паутине тесных связей, которые вы нагородили. В этом случае лучше оставить это в модуле, чтобы оно было хотя бы очевидно.

Есть код для примеров и есть код рабочий. Кроме этой переменной в другой команде будет куча переменных, автомат с кучей состояний и тп. Тоесть реализация команды в 99% случаев не является такой тривиальной. И если всё это тащить во внешний модуль, то когда команд будет с десяток, разобраться в модуле будет нереально. А так каждая команда в отдельном файле. Вход у всех одинаков, а в главном файле только case.

Пример двух команд из рабочего кода 

        // --- Execute command
        SPI_STATE_CMD: begin
          case (spi_session_cmd)
            // - Get PWM channel value
            SPI_CMD_SET_PWM: SPI_CMD_getChannelPWM.onReceive(spi_session_cmd_reset, __MEMORY__, spi_rx_buffer);
            
            // - Set PWM channel value
            SPI_CMD_GET_PWM: SPI_CMD_setChannelPWM.onReceive(spi_session_cmd_reset, __MEMORY__, spi_rx_buffer);
           
          endcase
        end

 

Изменено пользователем HardRock

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

6 minutes ago, HardRock said:

Но это оказывается не так, и это есть тот нюанс, который либо знаешь либо нет

Это вообще зависит от синтезатора. В вашем случае нет инициализации статической переменной. Не исключаю, что какой-нибудь Synopsys behavioral compiler сможет это синтезировать.

P.S. вы сейчас пользуетесь не языком программирования, а я зыком описания аппаратного обеспечения. Всё-таки есть разница.

Изменено пользователем one_eight_seven

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

52 минуты назад, HardRock сказал:

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

В реальном железе не всегда можно отследить все ошибки, симуляция необходима.

5 часов назад, des00 сказал:

 самоизоляция, 

Какая там самоизоляция... Полторы недели дали отдохнуть дома и вызвали приказом.:acute:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Да капец с этой короношизой одуреть можно столько дома сидеть :swoon:  На удалёнке можно всегда работать, но банально свободно перемещаться нельзя и всё закрыто - это уже перебор

Забавно что страны где нет жестких мер - совсем пропали из новостного эфира, например Беларусь. Молодцы, респект им и уважуха, как говорится. Наверно весь этот кипиш не стоит "тех бедолаг, умерших от тяжелых сопутствующих заболеваний, а тут ещё короновирус добавился", как сказал Лукашенко, поддерживаю.

Ну да дадно,  тема про FPGA.

 

Вобщем воз почти вышел на орбиту. Описал регистры железки пакед структурами, команды будут жить в interface. Всё клёво, всё работает. Осталось реализовать собственно набор команд и другой полезный функционал, например нужно будет ещё ловить UART на вход, парсить его протокол и складывать в регистры железки чтобы потом можно было забрать по SPI или использовать внутри для логики. Но тут уже всё понятно как делать. Ну и в финале развести плату и собрать железку с FPGA и STM32 на борту. 

Изменено пользователем HardRock

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...