First some backstory on this problem. In my current project I'm trying to create a Mandelbrot calculator which is optimized by using a FPGA. At this point I have attempted to establish a bridge between the nios processor and the FPGA (sadly with no luck what so ever).
I'm trying to understand the communication between the nios and the FPGA (which runs VHDL) using the Avalon bus. I've been using VHDL for over 15 weeks now and started the past 5 weeks on the nios 2 processor. Now the thing I want to accomplish is the following: So I want to create a setup on which I can test sending two times a 64 bit value, remember this value in VHDL and them try reading it so it gets back on the Nios 2 processor (in C code).
Of course I did not put this question up here before trying to figure this out myself. This is the work I have done until now.
On the nios I have created a simple setup in the main which writes two 64 bit values to the FPGA, then retrieves them and show the output on the red and green leds, btw: I run this on a Altera DE2 board. The C code looks like this
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;
}
I'm aware of the fact that this code may be incorrect due the fact that IQRD can only retrieve a 32 bit value. But I am unable to find a solution to reading a 64 bit address all at once. I got most of the techniques on how to do this from this question. So I do not know if this is correct.
Secondly there is the FPGA side written in VHDL. This component is a 64 bit component which is connected in QSYS with the avalon bus of the nios. The component that should handle the incoming and outgoing requests is the avalon_mandelbrot component (given below).
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;
It seems logic to me that this setup should work, but when I try to test the whole thing it does not seem to function as it should. Clearly I'm doing something wrong here, maybe that someone with a bit more experience can take a look at it. Hopefully someone will be able to help me with this soon.
I have not worked much with communication with a NIOS specifically, but I have worked with Altera's Avalon bus interface.
If you have not already done so, I would read their reference material. www.altera.com/literature/manual/mnl_avalon_spec.pdf
Particularly section 3.5.1 that gives an example of a typical transfer.
In your example, you did not specify that you are using fixed wait state times for this particular Avalon interface. I'm not sure if that's configurable on the NIOS, but typically fixed wait states is not the default operation of an Avalon bus. Meaning that you need to use the avs_s0_waitrequest
signal to signal to the master (NIOS) when a read/write is complete. This port is unconnected in your design.
In your case, it may be as simple as connecting avs_s0_waitrequest
to avs_s0_write
during a write operation, and avs_s0_read
during a read as your read latency is 1.