Простая процедура VHDL testbench для отправки последовательных байтов? - PullRequest
3 голосов
/ 28 февраля 2020

Я пытаюсь убрать битбэширование в своем дизайне и отправляю тестовые сигналы извне DUT, используя процедуру. Формат сериализованного сообщения - это начальный бит «0», байт с первым MSB и стоп-бит «1». Линия бездействует на «1». Я думаю, что у меня возникла проблема с использованием типов данных, которые будут передаваться между процедурой и основным процессом.

Вот моя процедура (скорость передачи - постоянная времени для периода последовательных часов):

  procedure send_midi_byte (
    signal byte_in  : in  std_logic_vector;
    signal midi_out : out std_logic) is
  begin
    midi_out <= '0';
    wait for baudrate;
    for i in 7 to 0 loop
      midi_out <= byte_in(i);
      wait for baudrate;
    end loop;
    midi_out <= '1';
    wait for baudrate;
  end send_midi_byte;

И вот как я называю это, чтобы отправить несколько байтов (byte_slv - это 8-элементный std_logic_vector):

    byte_slv <= x"90";
    send_midi_byte(byte_slv, midi_in_int);

Я пробовал несколько разных методов, и это единственный, который не выдает ошибку, но, конечно, она не будет работать из-за неблокирующих назначений в процедуре, означающих, что мой последовательный сигнал будет просто «1» в течение времени, указанного в скорости передачи данных.

Как можно Я правильно пишу эту процедуру?

Ответы [ 3 ]

1 голос
/ 29 февраля 2020

Как и совет Джима, исправьте диапазон l oop и попробуйте снова, прежде чем пытаться что-либо еще. 7 to 0 - нулевой диапазон; 0 to 7 или 7 downto 0 - это не так.

Неблокирование (в отношении назначений) - бессмысленный термин в VHDL, но назначение сигналов в пределах * oop внутри процедуры абсолютно нормально. Это отложенное назначение, которое запланировано на начало wait for baudrate. Это, конечно, ждет в течение указанного времени, и следующая итерация l oop начинается после ее завершения.

0 голосов
/ 29 февраля 2020

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

Предпосылка вашего утверждения здесь неверна. Причина сбоя вызова процедуры заключается в том, что спецификация параметра l oop предоставляет нулевой диапазон (параметр l oop вычисляется первым, оператор al oop выполняется 0 или более раз).

Как мне правильно написать эту процедуру?

Пример Minimal, Complete и Verifiable с исправлением, включенным в процедуру send_midi_byte:

library ieee;
use ieee.std_logic_1164.all;

entity cmoc_cmoc is
end entity;

architecture mcve of cmoc_cmoc is
    constant baudrate:  time := 26.925 us;  -- 38.400 baud
    procedure send_midi_byte (
        signal byte_in:   in  std_logic_vector;
        signal midi_out:  out std_logic
    ) is
        alias in_byte: std_logic_vector (7 downto 0) is byte_in;  -- ADDED
    begin
        midi_out <= '0';
        wait for baudrate;
        for i in in_byte'range loop        -- WAS 7 to 0
            midi_out <= in_byte(i); -- WAS byte_in(i);
            wait for baudrate;
        end loop;
        midi_out <= '1';
        wait for baudrate;
    end procedure send_midi_byte;
    signal some_byte:   std_logic_vector (7 downto 0) := x"41";
    signal midi_out:    std_logic := '1';
    type baud is (IDLE,START, BD0, BD1, BD2, BD3, BD4, BD5, BD6, BD7, STOP);
    signal baud_cnt:    baud;
begin
PROCEDURE_CALL:
    process 
    begin
        wait for baudrate;  -- SHOW IDLE on midi_out;
        send_midi_byte(some_byte, midi_out);  -- added second parameter
        wait;
    end process;
BAUD_CTR:
    process
    begin
        if baud_cnt = IDLE then
            wait until midi_out = '0';
        end if;
        loop
            baud_cnt <= baud'RIGHTOF(baud_cnt);
            wait for 0 ns;
            report "baud(" & baud'image(baud_cnt) &
                   ") midi_out = "  & std_ulogic'image(midi_out);
            wait for baudrate;
            if baud_cnt = STOP then
                baud_cnt <= IDLE;
                exit;
            end if;
        end loop;
        wait;
    end process;
end architecture;

Обратите внимание на класс byte_in не указано в объявлении процедуры. Для параметра подпрограммы режима in класс по умолчанию - constant.

Первый порядок MSB был сохранен в соответствии с текстом вашего вопроса. (UART передают LSB первым).

Процесс BAUD_CTR является украшением для демонстрации передаваемого порядка передачи.

Для UART с входным байтом, заданным как MSB слева, и передачей Сначала LSB, либо диапазон псевдонимов можно изменить на обратный, либо параметр l oop может использовать `REVERSE_RANGE.

Операторы отчета:

ghdl -r cmoc_cmoc --wave=cmoc_cmoc.ghw
cmoc_cmoc.vhdl:45:13:@26925ns:(report note): baud(start) midi_out = '0'
cmoc_cmoc.vhdl:45:13:@53850ns:(report note): baud(bd0) midi_out = '0'
cmoc_cmoc.vhdl:45:13:@80775ns:(report note): baud(bd1) midi_out = '1'
cmoc_cmoc.vhdl:45:13:@107700ns:(report note): baud(bd2) midi_out = '0'
cmoc_cmoc.vhdl:45:13:@134625ns:(report note): baud(bd3) midi_out = '0'
cmoc_cmoc.vhdl:45:13:@161550ns:(report note): baud(bd4) midi_out = '0'
cmoc_cmoc.vhdl:45:13:@188475ns:(report note): baud(bd5) midi_out = '0'
cmoc_cmoc.vhdl:45:13:@215400ns:(report note): baud(bd6) midi_out = '0'
cmoc_cmoc.vhdl:45:13:@242325ns:(report note): baud(bd7) midi_out = '1'
cmoc_cmoc.vhdl:45:13:@269250ns:(report note): baud(stop) midi_out = '1'

И форма сигнала, показывающая baud_cnt:

MSB first order

0 голосов
/ 28 февраля 2020

Проблемы У вас есть две ошибки. Первое, на которое указал Брайан, ваш диапазон неверен. Простой способ express диапазона - использовать диапазон. Это показано в коде ниже.

Кроме того, вы хотите изменить класс вашего параметра byte_in на константу, также показанную в приведенном ниже коде.

Решение

  procedure send_midi_byte (
    constant byte_in  : in  std_logic_vector;
    signal   midi_out : out std_logic
  ) is
  begin
    midi_out <= '0';
    wait for baudrate;
    for i in byte_in'range loop
      midi_out <= byte_in(i);
      wait for baudrate;
    end loop;
    midi_out <= '1';
    wait for baudrate;
  end send_midi_byte;

Так почему же константа? Константа означает, что параметр stati c для времени жизни вызова подпрограммы. Параметры-константы допускают все, что создает значение (литерал, выражение или даже имя сигнала или переменной), например:

send_midi_byte(x"90", midi_in_int);
for i in 0 to 10 loop
  send_midi_byte(x"90" + i, midi_in_int);
end loop;

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

Рекомендации по параметрам
Для входных данных:
Используйте сигнал , когда ожидается обновление объекта - например, использование события или использование объекта в операторе ожидания. Обычно это означает, что объект исходит из архитектуры (такой как DUT).
Используйте константу , когда вам нужно передать буквальное значение.

Для выходных данных:
Использовать сигнал при передаче значения в архитектуру (например, DUT).
Использовать переменную при передаче значения обратно в локальный процесс .

Почему параметр должен быть константой
В вашем примере он будет работать с сигналом, однако модель использования всегда будет: 1) присваиваться сигналу, а затем 2) вызвать подпрограмму:

byte_slv <= x"90";
send_midi_byte(byte_slv, midi_in_int);

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

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

procedure send_inc_midi_bytes (
  constant first_byte_in : in std_logic_vector;
  constant number_bytes  : in integer ;
  signal midi_out  : std_logic
) is 
   -- signal byte_in : std_logic_vector(7 downto 0); -- want to do this
begin
  for i in 0 to number_bytes - 1 loop
    byte_in <= byte_in + i ; 
    send_midi_byte(byte_in, midi_out);
  end loop ;
end procedure send_inc_midi_bytes ; 

Я понимаю, что исправление диапазона решает вашу конкретную проблему, но однажды вы можете sh сделать больше - в этот момент вы захотите, чтобы кто-то предложил использовать вместо сигнала константу.

...