如何使用 avalon 总线将两个 64 位从 nios 传输到 VHDL?

How to transfer two 64 bit from the nios to VHDL using the avalon bus?

首先介绍一下这个问题的背景故事。在我当前的项目中,我正在尝试创建一个使用 FPGA 优化的 Mandelbrot 计算器。在这一点上,我试图在 nios 处理器和 FPGA 之间建立一座桥梁(遗憾的是一直没有运气)。

我正在尝试了解使用 Avalon 总线的 nios 和 FPGA(运行s VHDL)之间的通信。我已经使用 VHDL 超过 15 周了,过去 5 周开始使用 nios 2 处理器。现在我想要完成的事情如下: 所以我想创建一个设置,在该设置上我可以测试发送两次 64 位值,在 VHDL 中记住这个值,然后他们尝试读取它,以便它返回到 Nios 2 处理器(C 代码)。

当然,在我自己尝试解决这个问题之前,我并没有把这个问题放在这里。这是我到目前为止所做的工作。

在 nios 上,我在 main 中创建了一个简单的设置,它将两个 64 位值写入 FPGA,然后检索它们并在红色和绿色 LED 上显示输出,顺便说一句:我 运行 这个在 Altera DE2 板上。 C代码看起来像这样

int main (void)
{
    //Reset the green and red leds to off
    IOWR(REDLEDS_BASE, 0, 0x0);
    IOWR(GREENLEDS_BASE, 0, 0x0);

    //Write the 64 bit x coordinate
    IOWR(MANDELBROT_CORE_BASE, 0x0, 0xAAAAAAAA);
    IOWR(MANDELBROT_CORE_BASE, 0x4, 0xAAAAAAAA);

    //Write the 64 bit y coordinate
    IOWR(MANDELBROT_CORE_BASE, 0x8, 0xEEEEEEEE);
    IOWR(MANDELBROT_CORE_BASE, 0x12, 0xEEEEEEEE);

    //Read the 64 bit x coordinate
    double x = IORD(MANDELBROT_CORE_BASE, 0);

    //Read the 64 bit y coordinate
    double y = IORD(MANDELBROT_CORE_BASE, 8);

    //Write the values to the leds
    IOWR(REDLEDS_BASE, 0, x);
    IOWR(GREENLEDS_BASE, 0, y);

    while(bRunning == true)
    {
    }

    return 1;
}

我知道此代码可能不正确,因为 IQRD 只能检索 32 位值。但我无法找到一次性读取 64 位地址的解决方案。我从 this question 那里获得了有关如何执行此操作的大部分技术。所以不知道对不对

其次是用VHDL编写的FPGA端。该组件是一个 64 位组件,它在 QSYS 中与 nios 的 avalon 总线连接。应该处理传入和传出请求的组件是 avalon_mandelbrot 组件(如下所示)。

entity avalon_mandelbrot is
    port (
        avs_s0_read        : in  std_logic                     := '0'; -- s0.read
        avs_s0_readdata    : out std_logic_vector(63 downto 0);        -- readdata
        avs_s0_write       : in  std_logic                     := '0'; -- write
        avs_s0_writedata   : in  std_logic_vector(63 downto 0) := (others => '0'); -- writedata
        avs_s0_waitrequest : out std_logic;                                        -- waitrequest
        avs_s0_address     : in  std_logic_vector(7 downto 0)  := (others => '0'); -- address
        avs_s0_byteenable  : in  std_logic_vector(7 downto 0) ;                    -- byte enable
        clk                : in  std_logic                     := '0';             -- clock
        reset              : in  std_logic                     := '0';             -- reset
    );
end entity avalon_mandelbrot;

architecture rtl of avalon_mandelbrot is
   begin
       process(clk)
           variable data_in : std_logic_vector(63 downto 0):= (others => '0');
           variable data_temp_x : std_logic_vector(63 downto 0):= (others => '0');
           variable data_temp_y : std_logic_vector(63 downto 0):= (others => '0');
       begin

           if rising_edge(clk) then

               if avs_s0_write = '1' then
                   if avs_s0_byteenable(0) = '1' then
                       data_in(7 downto 0) := avs_s0_writedata(7 downto 0);
                   end if;

                   if avs_s0_byteenable(1) = '1' then
                       data_in(15 downto 8) := avs_s0_writedata(15 downto 8);
                   end if;

                   if avs_s0_byteenable(2) = '1' then
                       data_in(23 downto 16) := avs_s0_writedata(23 downto 16);
                   end if;

                   if avs_s0_byteenable(3) = '1' then
                       data_in(31 downto 24) := avs_s0_writedata(31 downto 24);
                   end if;

                   if avs_s0_byteenable(4) = '1' then
                       data_in(39 downto 32) := avs_s0_writedata(39 downto 32);
                   end if;

                   if avs_s0_byteenable(5) = '1' then
                       data_in(47 downto 40) := avs_s0_writedata(47 downto 40);
                   end if;

                   if avs_s0_byteenable(6) = '1' then
                       data_in(55 downto 48) := avs_s0_writedata(55 downto 48);
                   end if;

                   if avs_s0_byteenable(7) = '1' then
                       data_in(63 downto 56) := avs_s0_writedata(63 downto 56);
                   end if;
               end if;

        
               --Master wants to write to slave
               if avs_s0_write = '1' then
                   case avs_s0_address is
                       when "00000000" => -- ADDR 0
                           data_temp_x(31 downto 0) := data_in(31 downto 0);
                       when "00000100" => -- ADDR 4
                           data_temp_x(63 downto 32) := data_in(63 downto 32);
                       when "00001000" => -- ADDR 8
                           data_temp_y(31 downto 0) := data_in(31 downto 0);
                       when "00001100" => -- ADDR 12
                           data_temp_y(63 downto 32) := data_in(63 downto 32);
                   end case;
               end if;
        
               --Master wants to read from slave
               if avs_s0_read = '1' then
                   case avs_s0_address is
                       when "00000000" =>
                           avs_s0_readdata <= data_temp_x;
                       when "00001000" =>
                           avs_s0_readdata <= data_temp_y;
                       when others =>
                           avs_s0_readdata <= (others => '0');
                   end case;
               end if;
           end if;
       end process;
end architecture rtl;

在我看来,此设置应该有效是合乎逻辑的,但是当我尝试测试整个过程时,它似乎无法正常工作。显然我在这里做错了什么,也许有更多经验的人可以看一下。希望很快有人能够帮助我。

我没有专门与 NIOS 通信,但我使用过 Altera 的 Avalon 总线接口。

如果您还没有这样做,我会阅读他们的参考资料 material。 www.altera.com/literature/manual/mnl_avalon_spec.pdf

特别是第 3.5.1 节给出了典型传输的示例。

在你的例子中,你没有指定你正在为这个特定的 Avalon 接口使用固定的等待状态时间。我不确定这是否可以在 NIOS 上配置,但通常固定等待状态不是 Avalon 总线的默认操作。这意味着当 read/write 完成时,您需要使用 avs_s0_waitrequest 信号向主机(NIOS)发出信号。该端口在您的设计中未连接。

在您的情况下,它可能就像在写入操作期间将 avs_s0_waitrequest 连接到 avs_s0_write 一样简单,并且在读取期间连接 avs_s0_read 因为您的读取延迟为 1。

在您的 Nios 代码中,您正在写入 0x12,它与地址 12(十六进制的 0xC)不同。

IOWR(MANDELBROT_CORE_BASE, 0x12, 0xEEEEEEEE);

你需要

IOWR(MANDELBROT_CORE_BASE, 0xC, 0xEEEEEEEE);