Forum Discussion

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

interrupt generation

I have an SOPC system with some custom avalon slaves. I would like to generate interrupts to nios with these blocks. I have searched here and on the altera site for documentation on how to implement the interrupt hardware in your avalon components but am coming up empty handed. Can anyone point me in the right direction?:confused::confused::confused:

8 Replies

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

    just found the interrupt section in the avalon spec. Not much there, I guess you just assert a line and hold it until your custom slave logic gets told to clear the irq by the cpu. seems pretty simple.

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

    there is one catch...

    you have to clear the irq-flag manually.

    But if you try to write via pointer on a peripheral module at the END of an interrupt subroutine (=last instruction) and have DATA CACHE enabled (standard, if using NIOS2/f), the data cache will be flushed and the write aborted.

    
    // regular isr
    static void test_isr(void* context, alt_u32 id) 
     {
        ...
     
      // RESET INTERRUPT at the end of an interrupt
      (*(long*)PERIPHERAL_BASE) = 0;
      }
    

    So better use

    IOWR(PERIPHERAL_BASE, 0, 0);

    instead, to bypass the data cache.

    or use the

    alt_dcache_flush_all();

    statement (# include <sys/alt_cache.h> ).

    it took me some time to figure out, why the interrupt flag wasn't cleared if the pointer insturction was the last one, but was cleared if there was an another one after it :D
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    I OR all of the pointers to my Avalon HW blocks with the data cache bypass bit so I don't get this kind of behavior. Hopefully it will avoid me this problem.

    # define DATA_CACHE_BYPASS_BIT 0x80000000

    volatile alt_u32* avalon_component_p = (volatile alt_u32*)(AVALON_COMP_BASE|DATA_CACHE_BYPASS_BIT);

    This is how I define all of my hw pointers in my C code.

    if you have no idea what I'm talking about google up data cache bypass niosII and read their document. I'm still not clear why volatile isn't sufficient but nios provides you with the ability to make the 31st bit '1' in order to force data cache bypassing.

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

    The ldio/stio family of instructions explicitly bypass the data cache.

    Bit-31 provides an alternate method to bypass the data cache. Using the

    bit-31 cache bypass, the normal ld/st family of instructions may be used

    to bypass the data cache if the most-significant bit of the address (bit 31)

    is set to one. The value of bit 31 is only used internally to the CPU; bit 31

    is forced to zero in the actual address accessed. This limits the maximum

    byte address space to 31 bits.

    Using bit 31 to bypass the data cache is a convenient mechanism for

    software because the cacheability of the associated address is contained

    within the address. This usage allows the address to be passed to code

    that uses the normal ld/st family of instructions, while still

    guaranteeing that all accesses to that address consistently bypass the data

    cache.

    Bit-31 cache bypass is only explicitly provided in the Nios II/f core, and

    should not be used for other Nios II cores. The other Nios II cores that do

    not support bit-31 cache bypass limit their maximum byte address space

    to 31 bits to ease migration of code from one implementation to another.

    They effectively ignore the value of bit 31, which allows code written for

    a Nios II/f core using bit 31 cache bypass to run correctly on other current

    Nios II implementations. In general, this feature is dependent on the

    Nios II core implementation.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    :confused:

    Device drivers typically access control registers associated with their

    device. These registers are mapped into the Nios II address space. When

    accessing device registers, the data cache must be bypassed to ensure that accesses are not lost or deferred due to the data cache.

    For device drivers, the data cache should be bypassed by using the

    ldio/stio family of instructions. On Nios II cores without a data cache,

    these instructions behave just like their corresponding ld/st

    instructions, and therefore are benign.

    for c programmers, note that declaring a pointer as volatile does not

    cause accesses using that volatile pointer to bypass the data cache. the

    volatile keyword only prevents the compiler from optimizing out

    accesses using the pointer.

    This volatile behavior is different from the methodology for

    the first-generation Nios processor.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Declaring it volatile and making sure that bit 31 is set will ensure that the cache is bypassed. Also, Altera provides HAL functions to remap the address to an uncached address if you don't like doing the bit 31 thing.

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

    Using the HAL functions is in fact better if you want to write code that can be recompiled for a NIOS CPU with MMU. The bit-31 trick won't work in that case IIRC.

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

    --- Quote Start ---

    Declaring it volatile and making sure that bit 31 is set will ensure that the cache is bypassed. Also, Altera provides HAL functions to remap the address to an uncached address if you don't like doing the bit 31 thing.

    Jake

    --- Quote End ---

    The 'volatile' only ensures that the compiler generate the instruction to write to memory. If the write is cached and the cache isn't write-through (I can't see a definition in the Nios ref book) then the write to memory won't happen until much later.

    Additionally you need to leave enough time between the memory write and exiting the ISR for the IRQ to actually have dropped. If you are executing code from tightly coupled memory, the io write requires an Avalon-MM transfer, and you do the write just before returning from the ISR it is possible the ISR will be re-entered.