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

Одновременный доступ к элементам массива в Verilog'е.

Здравствуйте.

 

Есть такой тестовый скрипт:

`timescale 1ns/1ps

module test;

    ////////////////////////////////////////////////////////////////////////////
    // Часы

    parameter CLOCK = 10;

    reg  C;

    initial
    begin
        C = 1'b0;
        #CLOCK;

        forever #( CLOCK / 2 ) C = ~ C;
    end

    ////////////////////////////////////////////////////////////////////////////
    // Тестовый массив

    reg  [7 : 0] Array[3 : 0];

    ////////////////////////////////////////////////////////////////////////////
    // Тестовый task

    task automatic Post;
        input  integer idx;
        input  integer cnt;

        integer i;
        begin
            for(i = 0; i < cnt; i = i + 1)
            begin
               repeat(2) @( posedge C );
               Array[ idx ] = #1 { i[3 : 0], idx[3 : 0] };
            end

            repeat(2) @( posedge C );
        end
    endtask

    ////////////////////////////////////////////////////////////////////////////
    // Основной поток

    initial
    begin
        #(3 * CLOCK);

        fork
            Post(0, 5);
            Post(1, 5);
            Post(2, 5);
            Post(3, 5);
        join

        #(4 * CLOCK) $stop;
    end

endmodule

 

Почему при исполнении под modelsim'ом присваивание элементу массива значения в отдельном task'е перекрывает присваивания другим элементам во всех остальных task'ах (см. рис.) ? Допускается ли в verilog'е такое обращение с массивами в принципе ? Или я чего-то не знаю ...

post-25599-1220114591_thumb.jpg

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


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

Ух. Поехали.

 

Нет такого понятия: "массив". Есть понятие память. Доступ только по словам. Доступа к битам слова нет.

 

В task чаще передают "провод". Т.е. "input [7 : 0] iii;"

 

task у вас выполняется не мгновенно. Это нормально работает только для поведенческого описания. Не для синтеза.

 

(вот тут меня наверное поправят.)

Выполнение одного таска несколько раз одновременно ведет к непредсказуемым результатам. Из-за того, что переменные не копируются.

 

У вас fork ... join и таски все выполняются одновременно. Так что ...

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


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

Не, понятие массива в языке есть. Просто при синтезе масив инстанциируется в память. Речь идёт только о функциональном тестбенче, синтезируемость не преследуется. Приведённый выше пример есть иллюстрация проблемы в тестбенче для функциональной верификации параметризованного модуля. Чтобы не плодить для передачи модулю n аргументов (n = 4 :) ) в n потоков initial, был применён такой подход, но что-то он не сработал. Я, конечно, выкрутился, но получилось некузяво.

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


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

Приведённый выше пример есть иллюстрация проблемы в тестбенче для функциональной верификации параметризованного модуля. Чтобы не плодить для передачи модулю n аргументов (n = 4 :) ) в n потоков initial, был применён такой подход, но что-то он не сработал. Я, конечно, выкрутился, но получилось некузяво.

 

Проблем никаких нет. Все работает правильно, Что вы написали, то вы и получили. Вы же сами описываете ОДИН массив, к которому ОДНОВРЕМЕННО лезут, по ПЕРЕКРЫВАЮЩИМСЯ адресам 4 треда (в тасках).

 

или вы вставили порождение программных тредов fork/join для "красного словца", совершенно не осознавая к чему это приведет ?? %))

 

Удачи!!!

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


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

des00

fork/join обеспечивают параллельное выполнение statements, заключённых между ними, и применены осознанно. Посмотрите внимательно сорс: запись в массив происходит по разным индексам (но при этом запись в один элемент приводит к записи во все одного и того же значения).

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


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

Кстати только сейчас заметил, что в

Array[ idx ] = #1 { i[3 : 0], idx[3 : 0] };

idx слева правильный, а справа всегда = 3. Может из-за этого: "#1"?

 

А вообще правильно говорят, что нечего вызывать таск из разных мест одновременно.

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


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

А вот попробуйте перенести задержку вот так:

            begin
              repeat(2) @( posedge C );
              #idx Array[ idx ] = { i[3 : 0], idx[3 : 0] };
            end

Похоже, что доступ к массиву (даже по разным адресам) блокирующим присвоением из разных тасков в одно и то же время заканчивается вашим случаем.

В моделсиме можно пошагово пройти, с просмотром каждой переменной в каждом треде.

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


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

Да, в таком виде всё отработало как надо. Похоже, всё дело в типе задержки. Спасибо за подсказку.

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


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

des00

fork/join обеспечивают параллельное выполнение statements, заключённых между ними, и применены осознанно. Посмотрите внимательно сорс: запись в массив происходит по разным индексам (но при этом запись в один элемент приводит к записи во все одного и того же значения).

 

да вы правы, не туда посмотрел. если дело в задержке, то это бага. напишите в ментор, с примером.

 

хотя я добавил вот такой код к вашему примеру

 

 
    always_ff @(posedge C) begin
      string str;
      $timeformat(-9, 1, " ns", 10);
      str = $psprintf("%0t :", $time);
      foreach (Array[i])
        str  = {str, $psprintf("%0d ", Array[i])};
      $display (str);
    end

 

вот результат

 

# 15.0 ns :x x x x

# 25.0 ns :x x x x

# 35.0 ns :x x x x

# 45.0 ns :x x x x

# 55.0 ns :3 2 1 0

# 65.0 ns :3 2 1 0

# 75.0 ns :19 18 17 16

# 85.0 ns :19 18 17 16

# 95.0 ns :35 34 33 32

# 105.0 ns :35 34 33 32

# 115.0 ns :51 50 49 48

# 125.0 ns :51 50 49 48

# 135.0 ns :67 66 65 64

# 145.0 ns :67 66 65 64

# 155.0 ns :67 66 65 64

# 165.0 ns :67 66 65 64

# 175.0 ns :67 66 65 64

 

отмеченной вами баги не видно. проверялось на 6.3g

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


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

В ментор писать не буду, поскольку работаю с 6.2g. Кроме того, у меня вообще права писать туда нет ;) :)

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


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

хотя я добавил вот такой код к вашему примеру

вот результат

Не информативно.

Было бы интереснее следующее:

always @(array[0])
  $display($time, array[0]);

 

2All

Если таск написан с использованием временных задержек как то: #, @(), wait то вызов таска когда он же выполняется может приводить к произвольным результатам. Рекомендуется в таске вставлять проверку двойного вызова.

task
  reg in_use;
begin
  if (in_use === 1'b1) $stop;
  in_use = 1'b1;
..........
  in_use = 1'b0;
end
endtask

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


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

Не информативно.

 

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

 

И раз пошла такая пьянка, то ИМХО лучше сделать так :)

 

initial $monitor($time, Array[0], Array[1], Array[2], Array[3]);

 

2All

Если таск написан с использованием временных задержек как то: #, @(), wait то вызов таска когда он же выполняется может приводить к произвольным результатам. Рекомендуется в таске вставлять проверку двойного вызова.

task
  reg in_use;
begin
  if (in_use === 1'b1) $stop;
  in_use = 1'b1;
..........
  in_use = 1'b0;
end
endtask

 

ну это действительно только для тредов которые обращаются к разделяемым ресурсам (что в данном случае не верно) и лучше уж тогда воспользоваться семафором.

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


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

dvladim

Если таск написан с использованием временных задержек как то: #, @(), wait то вызов таска когда он же выполняется может приводить к произвольным результатам.

 

Атрибут automatic делает task реентрантным.

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


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

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

 

И раз пошла такая пьянка, то ИМХО лучше сделать так :)

initial $monitor($time, Array[0], Array[1], Array[2], Array[3]);

Если значение, скажем, Array[0] изменится несколько раз в одной временной точке, то $monitor покажет только последнее значение, always @() $display покажет все.

 

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

 

Атрибут automatic делает task реентрантным.

Это начиная с 2001. Раньше не было.

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


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

Если значение, скажем, Array[0] изменится несколько раз в одной временной точке, то $monitor покажет только последнее значение, always @() $display покажет все.

 

да вы правы, век живи век учись %)

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


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

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

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

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

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

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

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

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

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

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