2013-08-29 5 views
2

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

Поведение файла:

LIBRARY ieee; 
USE ieee.std_logic_1164.ALL; 

entity DCT_beh is 
    port (
      Clk :   in std_logic; 
      Start :   in std_logic; 
      Din :   in INTEGER; 
      Done :   out std_logic; 
      Dout :   out INTEGER 
     ); 
end DCT_beh; 

architecture behavioral of DCT_beh is 
begin 
    process 
      type RF is array (0 to 7, 0 to 7) of INTEGER; 

      variable i, j, k  : INTEGER; 
      variable InBlock  : RF; 
      variable COSBlock  : RF; 
      variable TempBlock  : RF; 
      variable OutBlock  : RF; 
      variable A, B, P, Sum : INTEGER; 

    begin 

      COSBlock := ( 
    (125, 122, 115, 103, 88,  69,  47,  24 ), 
    (125, 103, 47,  -24, -88, -122, -115, -69 ), 
    (125, 69,  -47, -122, -88, 24,  115, 103 ), 
    (125, 24,  -115, -69, 88,  103, -47, -122 ), 
    (125, -24, -115, 69,  88,  -103, -47, 122 ), 
    (125, -69, -47, 122, -88, -24, 115, -103 ), 
    (125, -103, 47,  24,  -88, 122, -115, 69 ), 
    (125, -122, 115, -103, 88,  -69, 47,  -24 ) 
        ); 

--Starting 
    wait until Start = '1'; 
     Done <= '0'; 

--Read Input Data 
    for i in 0 to 7 loop 
     for j in 0 to 7 loop  
      wait until Clk = '1' and clk'event; 
      InBlock(i,j) := Din; 
     end loop; 
    end loop; 

--TempBlock = COSBLOCK * InBlock 

    for i in 0 to 7 loop 
     for j in 0 to 7 loop 
      Sum := 0; 
      for k in 0 to 7 loop 
       A := COSBlock(i, k); 
       B := InBlock(k, j); 
       P := A * B; 
       Sum := Sum + P; 
       if(k = 7) then 
       TempBlock(i, j) := Sum; 
       end if; 
      end loop; 
     end loop; 
    end loop; 


--Finishing 

    wait until Clk = '1' and Clk'event; 
    Done <= '1'; 

--Output Data 

    for i in 0 to 7 loop 
     for j in 0 to 7 loop 
      wait until Clk = '1' and Clk'event; 
      Done <= '0'; 
      Dout <= tempblock(i,j); 
     end loop; 
    end loop; 
end process;  
end behavioral; 

Testbench Файл:

LIBRARY ieee; 
USE ieee.std_logic_1164.ALL; 

-- Uncomment the following library declaration if using 
-- arithmetic functions with Signed or Unsigned values 
--USE ieee.numeric_std.ALL; 

ENTITY lab4b_tb IS 
END lab4b_tb; 

ARCHITECTURE behavior OF lab4b_tb IS 

-- Component Declaration for the Unit Under Test (UUT) 

COMPONENT DCT_beh 
PORT(
    Clk : IN std_logic; 
    Start : IN std_logic; 
    Din : IN INTEGER; 
    Done : OUT std_logic; 
    Dout : OUT INTEGER 
    ); 
END COMPONENT; 


    --Inputs 
    signal Clk : std_logic := '0'; 
    signal Start : std_logic := '0'; 
    signal Din : INTEGER; 

--Outputs 
    signal Done : std_logic; 
    signal Dout : INTEGER; 

    -- Clock period definitions 
    constant Clk_period : time := 10 ns; 

BEGIN 

-- Instantiate the Unit Under Test (UUT) 
    uut: DCT_beh PORT MAP (
     Clk => Clk, 
     Start => Start, 
     Din => Din, 
     Done => Done, 
     Dout => Dout 
    ); 

    -- Clock process definitions 
    Clk_process :process 
    begin 
    Clk <= '0'; 
    wait for Clk_period/2; 
    Clk <= '1'; 
    wait for Clk_period/2; 
    end process; 


    -- Stimulus process 
    stim_proc: process 

variable i, j : INTEGER; 
variable cnt : INTEGER; 

    begin  
    -- hold reset state for 100 ns. 

    wait for 100 ns; 

     start <= '1'; 
     wait for clk_period; 
     start <= '0'; 

    for cnt in 0 to 63 loop 
     wait until clk = '1' and clk'event; 
      din <= cnt; 
     end loop; 

     --wait for 100 ns; 

     --start <= '1'; 
     --wait for clk_period; 
     --start <= '0'; 

     --for i in 0 to 63 loop 
      -- wait for clk_period; 
      --if (i < 24) then 
       --din <= 255; 
      --elsif (i > 40) then 
       --din <= 255; 
      --else 
       --din <= 0; 
      --end if; 
     --end loop; 


    wait; 
    end process; 

END; 

Из того, что я делаю при запуске = 1 матрица считывается в inputblock. В этом случае матрица просто заполняется уникальными инкрементальными значениями от 0 до 63. Затем, когда сделано = 1, я выхожу из блока, который является умноженной матрицей. Проблема в том, что в моем моделировании я получаю некоторые значения, которые должны быть в финальной матрице, но не в правильном порядке. Например, строка ниже содержит первую строку в умноженной матрице, tempblock:

14464.000 15157.000 15850.000 16543.000 17236.000 17929.000 18622.000 19315.000 

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

У меня есть некоторые сомнения, что, возможно, din (0), din (1), din (2) ... din (n) не соответствует входному блоку (0,0), входному блоку (0,1), inputblock (0,2) и т. д. Но я тщательно изучил свой поведенческий файл и не вижу никаких проблем с ним. Что-то не так с тем, как я разработал свой тестовый стенд?

Testbench: bottom signals are unsigned values

EDIT: Мне нужна помощь в выводе для этого

 din<=0; 


    for i in 0 to 63 loop 
     wait until clk = '1' and clk'event; 
     if i = 0 then 
      Start <= '1','0' after clk_period; 
      end if; 
      if (i < 24) then 
       din <= 255; 
      elsif (i > 40) then 
       din <= 255; 
      else 
       din <= 0; 
      end if; 

    end loop; 

Я думал, что будет похож на код в ответ, но я столкнулся с точно такой же проблемой. Как это будет исправлено? Вот изображение того, что в настоящее время выводится. Правильные значения есть, но только сдвинуты на один такт. enter image description here

ОКОНЧАТЕЛЬНЫЙ РЕДАКТОР: Решил сам. Проблема заключалась в границах цикла.

+1

Невозможно большой или отрицательный? – user1155120

+0

кажется очень большим по сравнению с другими значениями в полученной матрице. появляется первое значение [0] [0], но только после первых двух тактовых периодов.что заставляет меня поверить, что время как-то отключено двумя часовыми периодами, из-за чего весь внешний блок отображается некорректно. – user1766888

+0

Обратите внимание, что вложенное изображение показывает волну add -radix unsigned/dout/din. В ghdl симуляция разбивается на передний фронт часов в 735 нс, когда ваша модель отходит от нормального режима полета. Я получаю исключение с плавающей запятой, которое может быть связано с диапазоном. Экспериментальный симулятор vhdl у меня показывает -2147469752 на 765 нс, 14464, 15157, 15850, 16543 и 17236 на последовательных часах до 820 нс. – user1155120

ответ

1

Вот что выглядит рабочая версия модели, и это тестовая

Добавлено (и обновлена)

Если вы должны были сделать матрицу множественного принимать в режиме реального времени (часы), вам 'd см. DONE, отложенное числом часов, которое потребовалось для умножения матрицы. Я произвольно выбрал два часа, чтобы показать преимущество добавленных файлов регистров.

Я прокомментирую интересные части кода.

LIBRARY ieee; 
USE ieee.std_logic_1164.ALL; 

ENTITY lab4b_tb IS 
END lab4b_tb; 

ARCHITECTURE behavior OF lab4b_tb IS 

    signal Clk:  std_logic := '0'; -- no reset 
    signal Start: std_logic := '0'; -- no reset 
    signal Din:  INTEGER  := 0;  -- no reset 

    signal Done : std_logic; 
    signal Dout : INTEGER; 

    constant Clk_period : time := 10 ns; 

BEGIN 

    uut: entity work.DCT_beh -- DCT_beh 
     PORT MAP (
      Clk => Clk, 
      Start => Start, 
      Din => Din, 
      Done => Done, 
      Dout => Dout 
    ); 

CLOCK: 
    process 
    begin 
     Clk <= '0'; 
     wait for Clk_period/2; 
     Clk <= '1'; 
     wait for Clk_period/2; 
    end process; 

STIMULUS: 
    process 
     variable i, j : INTEGER; 
     variable cnt : INTEGER; 
    begin  

     wait until clk = '1' and clk'event; -- sync Start to clk 

FIRST_BLOCK_IN: 
     Start <= '1','0' after 11 ns; --issued same time as datum 0 
     for i in 0 to 63 loop 
       if (i < 24) then 
        din <= 255; 
       elsif (i > 40) then 
        din <= 255; 
       else 
        din <= 0; 
       end if; 
       wait until clk = '1' and clk'event; 
     end loop; 
SECOND_BLOCK_N: 
     Start <= '1','0' after 11 ns; -- with first datum 
     for cnt in 0 to 63 loop 
      din <= cnt; 
      wait until clk = '1' and clk'event; 
     end loop; 
     din <= 0; -- to show the last input datum clearly 

     wait; 
    end process; 

END ARCHITECTURE; 

Два входных блока - это новое значение блока и исходное значение блока, которое предоставило индекс для первого выходного блока. Второй блок также показывает те же ответы, что и исходные, подтверждающие правильное установление связи DONE.

Примечание. Старт совпадает с первой базой данных каждого блока.

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

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

LIBRARY ieee; 
USE ieee.std_logic_1164.ALL; 

entity DCT_beh is 
    port (
     Clk :   in std_logic; 
     Start :   in std_logic; 
     Din :   in INTEGER; 
     Done :   out std_logic; 
     Dout :   out INTEGER 
    ); 

end DCT_beh; 

architecture behavioral of DCT_beh is 
    type RF is array (0 to 7, 0 to 7) of INTEGER; 
    signal OutBlock:   RF; 
    signal InBlock:    RF; 
    signal internal_Done:  std_logic := '0'; -- no reset 
    signal Input_Ready:   std_logic := '0'; -- no reset 
    signal done_detected:  std_logic := '0'; -- no reset 
    signal input_rdy_detected: std_logic := '0'; -- no reset 
    signal last_out:   std_logic := '0'; -- no reset 

begin 
INPUT_DATA: 
    process 
    begin 
     wait until Start = '1'; 
     --Read Input Data 
     for i in 0 to 7 loop 
      for j in 0 to 7 loop  
       wait until Clk = '1' and clk'event; 
       InBlock(i,j) <= Din; 
       if i=7 and j=7 then 
        Input_Ready <= '1', '0' after 11 ns; 
       end if; 
      end loop; 
     end loop; 
    end process; 

WAIT_FOR_InBlock: 
    process 
    begin 
     wait until clk = '1' and clk'event; 
     input_rdy_detected <= Input_Ready; 
     --InBlock valid after the following rising edge of clk 
    end process; 

TRANSFORM: 
    process 
      variable InpBlock  : RF; 
      constant COSBlock  : RF := 
      ( 
       (125, 122, 115, 103, 88,  69,  47,  24 ), 
       (125, 103, 47, -24, -88, -122, -115,  -69 ), 
       (125, 69, -47, -122, -88,  24, 115,  103 ), 
       (125, 24, -115, -69, 88, 103, -47, -122 ), 
       (125, -24, -115,  69, 88, -103, -47,  122 ), 
       (125, -69, -47, 122, -88, -24, 115, -103 ), 
       (125, -103, 47,  24, -88, 122, -115,  69 ), 
       (125, -122, 115, -103, 88, -69,  47,  -24 ) 
      ); 
      variable TempBlock  : RF; 
      variable A, B, P, Sum : INTEGER; 
    begin 

     if input_rdy_detected = '0' then 
      wait until input_rdy_detected = '1'; 
     end if; 

     InpBlock := InBlock; -- Broadside dump or swap 

--TempBlock = COSBLOCK * InBlock 

-- arbitrarily make matrix multiple 2 clocks long  
     wait until clk = '1' and clk'event; -- 1st xfm clock 

     for i in 0 to 7 loop 
      for j in 0 to 7 loop 
       Sum := 0; 
       for k in 0 to 7 loop 
        A := COSBlock(i, k); 
        B := InpBlock(k, j); 
        P := A * B; 
        Sum := Sum + P; 
        if(k = 7) then 
         TempBlock(i, j) := Sum; 
        end if; 
       end loop; 
      end loop; 
     end loop; 

    -- Done issued in clk cycle of last TempBlock(i, j) := Sum; 

     internal_Done <= '1', '0' after 11 ns; 
     wait until clk = '1' and clk'event; -- 2nd xfrm clk 
     -- OutBlock available after last TempBlock value stored 

     OutBlock <= TempBlock; -- Broadside dump or swap 
    end process; 

Done_BUFFER: 
    Done <= internal_Done; 


WAIT_FOR_OutBlock: 
    process 
    begin 
     wait until clk = '1' and clk'event; 
     done_detected <= internal_Done; 
     -- Done can come either before the first output_data transfer 
     -- or during the last output data transfer 
     -- this gives us the clock delay to finish the last xfm transfer to 
     -- TempBlock(i, j) 
     -- Technically part of the output process but was too cumbersome to write 
    end process; 

OUTPUT_DATA: 
    process 
    begin 
     -- OutBlock is valid after clock edge when Done is true 
     for i in 0 to 7 loop 
      for j in 0 to 7 loop 

       if i = 0 and j = 0 then 

        if done_detected = '0' then 
         wait until done_detected = '1'; 
        end if; 
       end if; 

       Dout <= OutBlock(i,j);       
       wait until clk = '1' and clk'event; 
      end loop; 
     end loop; 
    end process; 

end behavioral; 

Определение типа для радиочастоты было перенесено в декларативную часть архитектуры, чтобы обеспечить связь между процессами через сигналы. Входной цикл, матричный умножитель и выходной цикл находятся в собственных процессах. Я также добавил процессы для установления связи между процессами (Input_Ready и input_Done (Done), добавленные сигналы input_rdy_detect и done_detect.

Если процесс может занять 64 такта, то будет показан сигнал, показывающий последний процесс привязки (Input_Ready и потенциально Done) во время последней транзакции данных процесса нисходящего процесса. Было бы очень грязно кодировать код в противном случае, и вам все равно понадобятся флип-флопы.

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

Некоторые из задержек установления связи, по-видимому, были связаны с стилем кодирования и вылечены с помощью входных_данных и проделанных дефлекторов.

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

Two Clock Matrix Multiply

Вы можете увидеть первый выход ИГД следующей сразу следующим Совершенно это 78540, а не 110415 показан в вашем захвате экрана сигнала. Один из нас показывает неправильное значение. Эта версия DCT_beh строго обеспечивает передачу значений RF только после загрузки последней даты.

Я получил значение 110415 перед очисткой связи между процессом ввода и многократным процессом. Было бы очень много работы, чтобы проследить его через TempBlock наш OutBlock.

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

2nd Block Done and start of 2nd block output

Сигналы input_rdy_detect и done_detect случиться, чтобы показать первую транзакцию в их соответствующих процессах вниз по течению. Я добавил назначение сигнала заднего конца в 0, избегая путаницы в конце второго входного блока.

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

enter image description here

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

Это было сделано с использованием ghdl Tristan Gingold и gtkwave Tony Bybell на Mac под управлением OS X 10.8.4.

+0

Спасибо за этот ответ. Вы знаете, как я могу изменить приведенный выше код редактирования? У меня такая же проблема, но с другим набором инструкций. – user1766888

+0

Я отредактировал свою копию вашей модели, управляющей тремя состояниями в конвейере (и в отдельных процессах). Если вы сделаете это так близко, как я могу вам сказать, вам понадобится хотя бы один такт (эмуляция цикла Done выдается синонимом с последней записью в файл регистра). Поэтому я добавил второй, чтобы показать границы работы. – user1155120

Смежные вопросы