Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
21 years ago

How to use the avalon bus correctly?

I am using Quartus 4.1 with SOPC-builder and the Cyclone Development Board von Altera. My nios-system contains the nios2 processor, some memory and some other peripherals.

I created my own user logic which I want to connect to the avalon bus and access from software. I read the complete avalon bus specification but I was not able to find any real example there. Can somebody give me a simple example how to connect some user logic to the avalon bus correctly? And how to access it in software then?

As a simple example we can take the following vhdl-code:

library IEEE;
use IEEE.std_logic_1164.all;
ENTITY example IS PORT (
    SIGNAL clk: IN STD_LOGIC;
    SIGNAL input1: IN STD_LOGIC;
        SIGNAL input2: IN STD_LOGIC;
    SIGNAL output: OUT STD_LOGIC
);
END example;
ARCHITECTURE behavior OF example IS
BEGIN
  PROCESS(clk)
  BEGIN
    IF clk'EVENT AND clk='1' THEN
      output <= input1 AND input2;
    END IF;
  END PROCESS;
END behavior;

How do I have change this vhdl-code in order to connect this user logic to the the avalon bus? Because I want to write to and read from the hardware module at least the signals chipselect, write (or write_n), writedata, read (or read_n), readdata and address must be there. Am I wright?

6 Replies

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Thank you for your answer, but the Lancelot VGA reference design is rather complicated for me.

    Where can I find a simple example of avalon bus usage like for the vhdl-code from above?
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Hi Owerty

    Look at this code:

    library IEEE;
    use IEEE.std_logic_1164.all;
    ENTITY example IS PORT (
        clk      : IN STD_LOGIC;
        nreset      : IN STD_LOGIC;
        -- Nios interface
        Nios_Cs  : IN STD_LOGIC;
        Nios_Rd  : IN STD_LOGIC;
        Nios_Wr  : IN STD_LOGIC;
        Nios_Addr    : IN STD_LOGIC_VECTOR(2 DOWNTO 0);    -- just an example
        Nios_Din    : IN STD_LOGIC_VECTOR(31 DOWNTO 0);
        Nios_Dout   : OUT STD_LOGIC_VECTOR(31 DOWNTO 0);
        -- The output from your entity
        output: OUT STD_LOGIC
    );
    END example;
    ARCHITECTURE behavior OF example IS
    -- Define some constnts to help woth addressing when the design gets bigger
    CONSTANT INPUT_1_ADDR    :    STD_LOGIC_VECTOR(2 DOWNTO 0) := "000";
    CONSTANT INPUT_2_ADDR    :    STD_LOGIC_VECTOR(2 DOWNTO 0) := "001";
    -- I also find this constant helpful
    CONSTANT ZEROS      :    STD_LOGIC_VECTOR(31 DOWNTO 0) := (OTHERS => &#39;0&#39;);
    -- Some registers to hold internal values
    SIGNAL  Input1      :    STD_LOGIC;
    SIGNAL  Input2      :    STD_LOGIC;
    BEGIN
    PROCESS(clk,nreset)
    BEGIN
        IF (nreset = &#39;0&#39;) THEN
      Input1 <= &#39;0&#39;;
      Input2 <= &#39;0&#39;;
        ELSIF (rising_edge(clk)) THEN
      IF (Nios_Cs = &#39;1&#39; AND Nios_Wr = &#39;1&#39;) THEN
          CASE Nios_Addr IS
        WHEN "000" =>
            Input1 <= Nios_Din(0);
            Input2 <= Input2;
        WHEN "001" =>
            Input1 <= Input1;
            Input2 <= Nios_Din(1);
        WHEN OTHERS =>
            Input1 <= Input1;
            Input2 <= Input2;
          END CASE;
      ELSE
          Input1 <= Input1;
          Input2 <= Input2;
      END IF;
        END IF;
    END PROCESS;
    Nios_Dout <= ZEROS(31 DOWNTO 1) & Input1 WHEN Nios_Cs = &#39;1&#39; AND Nios_Rd = &#39;1&#39; AND Nios_Addr = INPUT_1_ADDR ELSE
        ZEROS(31 DOWNTO 1) & Input2 WHEN Nios_Cs = &#39;1&#39; AND Nios_Rd = &#39;1&#39; AND Nios_Addr = INPUT_2_ADDR ELSE
        (OTHERS => &#39;0&#39;);
        
    output <= Input1 AND Input2    
    END behavior;

    This code generates a peripheral with two registers. You need to add it to your SOPC builder system and assign it with an address. You&#39;ll be able to access it from sw the same way you access any other address (with IOWR and IORD commands).

    Hope this helps.

    Nir
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Hi nir, thank you for your example. I added it to my system but I still have some questions about it.

    I mapped the "output" signal to type export because it&#39;s a not-avalon signal, right?

    Why are the expressions like input1 <= input1 needed? For me they don&#39;t make any sense.

    For accessing the peripheral I wrote the following code (EXAMPLE_INTERFACE_BASE is the address of our example peripheral):

    int t; 
    IOWR(EXAMPLE_INTERFACE_BASE, 0 , 255);
    t = IORD(EXAMPLE_INTERFACE_BASE, 0);
    printf ("t = %d\n", t);

    I would expect t to be 1 but the result is always 0. Why? What am I doing wrong?

    And the last question: in this example we in principle can access eigth 32-bit input ports and eigth 32-bit output ports (because address is a 3-bit value), right? What if I want to have lets say two 3-bit input ports, one 1-bit input port, one 32-bit input port and one 1-bit output port? How do I have do declare them in the vhdl-code and access them from them SW?
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Hello Qwerty

    Here are the answers to your questions:

    <div class='quotetop'>QUOTE </div>

    --- Quote Start ---

    I mapped the "output" signal to type export because it&#39;s a not-avalon signal, right?[/b]

    --- Quote End ---

    This is right.

    <div class='quotetop'>QUOTE </div>

    --- Quote Start ---

    Why are the expressions like input1 <= input1 needed? For me they don&#39;t make any sense.[/b]

    --- Quote End ---

    Let&#39;s say we removed the two lines syaing Input1 <= Input1. The compiler seeing that will not know what to do when the address seen is not "000". What it will do is generate a latch to keep the data in Input1 the same as it was. This is done without you knowing about it and is not desirable (latches in FPGAs are bad things). So, these lines actually make sure that the compiler knows what to do with each of the registers in each of the cases it may encounter. This prevents these transparent latches from being instantiated.

    Regarding the problem you are seeing in software: It&#39;s possible that you defined the polarity of the Nios control signals (or one of them) wrong when you added the peripheral to the SOPC builder ?

    <div class='quotetop'>QUOTE </div>

    --- Quote Start ---

    And the last question: in this example we in principle can access eigth 32-bit input ports and eigth 32-bit output ports (because address is a 3-bit value), right? What if I want to have lets say two 3-bit input ports, one 1-bit input port, one 32-bit input port and one 1-bit output port? How do I have do declare them in the vhdl-code and access them from them SW?[/b]

    --- Quote End ---

    I defined the peripheral to use a 3 bit address bus, meaning the address space is 8 addresses. Each address can have its own data width (from 1 to 32 bits). If ou add one more bit to the address space you can have 16 different addresses. These addresses are registers addresses. Each register can be either Read only, write only or read-write. I hope this ansewrs your question.

    Nir
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    <div class='quotetop'>QUOTE </div>

    --- Quote Start ---

    Let&#39;s say we removed the two lines syaing Input1 <= Input1. The compiler seeing that will not know what to do when the address seen is not "000". What it will do is generate a latch to keep the data in Input1 the same as it was. This is done without you knowing about it and is not desirable (latches in FPGAs are bad things). So, these lines actually make sure that the compiler knows what to do with each of the registers in each of the cases it may encounter. This prevents these transparent latches from being instantiated.[/b]

    --- Quote End ---

    Ok now I see.

    <div class='quotetop'>QUOTE </div>

    --- Quote Start ---

    Regarding the problem you are seeing in software: It&#39;s possible that you defined the polarity of the Nios control signals (or one of them) wrong when you added the peripheral to the SOPC builder ?[/b]

    --- Quote End ---

    This is possible, I will check the settings tommorow.

    Another question: is it possible that my peripheral needs some time to provide the result, so I have to wait a liitle bit before reading from it? How can I determine that my peripheral is ready for reading from it?