3

背景:我正在尝试创建一个用于将三个矩阵相乘的行为文件。我试图通过首先查看是否可以读取输入矩阵然后输出中间矩阵来调试它。

行为文件:

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;

测试台文件:

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;

从我在 start = 1 时所做的事情开始,矩阵被读入输入块。在这种情况下,矩阵只填充了从 0 到 63 的唯一增量值。然后当完成 = 1 时,我输出 outblock,它是相乘后的矩阵。问题是在我的模拟中,我收到了一些应该在最终矩阵中但顺序不正确的值。例如,下面的行包含相乘矩阵 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) 不对应于 inputblock(0,0), inputblock(0,1), inputblock(0, 2)等等。但是我彻底检查了我的行为文件,没有发现任何问题。我设计测试台的方式有问题吗?

测试台:底部信号是无符号值

编辑:我需要帮助输出这个

        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;

我认为它与答案中的代码相似,但我遇到了同样的问题。这将如何解决?这是当前输出的图片。正确的值在那里,但只是移动了一个时钟周期。 在此处输入图像描述

最终编辑:自己解决了。问题在于循环边界。

4

1 回答 1

2

这是您模型的工作版本,它是测试平台

添加(和更新)

如果您要使矩阵乘法实时(时钟),您会看到 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;

RF 的类型定义已移至架构声明部分,以允许通过信号进行进程间通信。输入循环、矩阵乘法和输出循环都在自己的过程中。我还为进程间握手添加了进程(Input_Ready 和 input_Done (Done),添加了信号 input_rdy_detect 和 done_detect。

如果一个进程可以占用 64 个时钟,则在下游进程的最后一个数据事务期间施加显示最后一个数据进程(Input_Ready 和可能完成)的信号。否则编码会非常混乱,你仍然需要人字拖。

在输入过程和乘法过程之间增加了一个射频,以便在矩阵乘法需要实时时允许并发操作(在本示例中需要 2 个时钟,我不想将波形拉得太远)。

一些握手延迟似乎与编码风格相关,并通过 input_rdy_detect 和 done_detect 触发器解决。

第一个波形图显示了转换过程现在采用的两个时钟之后的第一个输出数据,显示在 A 和 B 标记之间。

两个时钟矩阵乘法

您可以看到紧跟在 Done 之后的第一个输出数据是 78540,而不是波形屏幕截图中显示的 110415。我们中的一个人显示了错误的价值。此版本的 DCT_beh 仅在加载最后一个数据后才严格执行 RF 值的传输。

在清理输入进程和乘法进程之间的握手之前,我确实得到了 110415 值。通过我们的 OutBlock 的 TempBlock 跟踪它会做很多工作。

现在是好消息。第二个输入块取自您的原始刺激,输入值是输出传输的重要指标。这些输出数据值看起来都是正确的。

第二块完成并开始第二块输出

信号 input_rdy_detect 和 done_detect 恰好显示了它们各自下游进程中的第一个事务。我在第二个输入块的末尾添加了一个尾随 din 信号分配到 0 以避免混淆。

这是一个近似于你的屏幕截图,我不能选择缩放,而是使用逐次逼近。

在此处输入图像描述

您只需将模拟运行到 1955 ns 即可捕获第二个块的最后一个数据。

这是在运行 OS X 10.8.4 的 Mac 上使用 Tristan Gingold 的 ghdl 和 Tony Bybell 的 gtkwave 完成的。

于 2013-08-30T12:07:45.687 回答