Nios® V/II Embedded Design Suite (EDS)
Support for Embedded Development Tools, Processors (SoCs and Nios® V/II processor), Embedded Development Suites (EDSs), Boot and Configuration, Operating Systems, C and C++
12746 Discussions

How one program can download and run another.

Altera_Forum
Honored Contributor II
1,392 Views

I want to be able to run a program in high ram memory which reads the data for another program over a usb link and stores this data in low memory. Once all the data has been received and validated the high memory program will jump to the start address of the low memory program. 

 

We have 16MB of SDRAM and the plan was to have the usb loader program run at 0xF00000 and the other program run at as low address as possible. 

 

I seem to have several problems with trying to do this: 

 

Both the high memory and low memory program have exception code at 0x20. 

Creating a bin file for the high memory program results in a file of over 15MB as it spans the full distance from 0x20 to 0xFxxxxx. 

I don't think I can move the exception address for the bootloader without affecting the subsequent program. 

 

Is there a way to do what I want, do I need to re-order how things are positioned in memory?
0 Kudos
4 Replies
Altera_Forum
Honored Contributor II
627 Views

Hi dunxm, 

 

> Both the high memory and low memory program have exception code at 0x20. 

 

There are several ways to handle this. The most common ways are: 

 

1. Disable interrupts during the download. In many situations this is not feasible -- due to the 

way your drivers operate. 

 

2. Let your downloaded application relocate itself. That is, download the new app to some 

convenient memory location, disable interrupts, then jump to the new app's entry point. The 

new app is then responsible for moving its exception trampoline to the exeception address 

(and relocating any other sections to their appropriate addresses), jumping to the relocated 

code, then enabling interrupts when appropriate. 

 

This is the technique that u-boot uses. 

 

> Creating a bin file for the high memory program results in a file of over 15MB as it spans the 

> full distance from 0x20 to 0xFxxxxx. 

 

You can avoid this problem by changing the lma of the exception handler -- then moving it 

to the proper location at run time (just like# 2 above). Otherwise, objcopy will fill the unused 

memory regions (as you have observed). 

 

You can find an example of how to do this in the u-boot sources. Take a look at the linker script 

for one of the Nios II boards (e.g. board/altera/ep1c20/u-boot.lds, and the cpu starup code 

in the cpu/nios2/start.S file. 

 

Regards, 

--Scott
0 Kudos
Altera_Forum
Honored Contributor II
627 Views

Hi Dunxm, 

 

Everything Scott says is exactly right but I would add a little bit. 

 

After disabling interrupts (globally) and before overlaying the old exception area with the new exception area you should disable all interrupts at the device level too, also then remove any pending interrupts from the devices. This stops you getting interrupts when the new program enables interrupts (globally) but before your code has installed the device isr for them. 

 

Banx.
0 Kudos
Altera_Forum
Honored Contributor II
627 Views

I'm afraid I'm still not fully understanding what I need to do. 

 

So far, I've done the following: 

 

Firstly the bootloader now resides at the bottom of memory rather than the top of memory. This allowed me to create a large static array to hold the downloaded program. I've based the program I want to run from another program on hello_world_alt_main. I've added code to the start of alt_main to copy the .exceptions section to 0x20. When I build this and download as a .srec it works and displays some output. We are not using reduced device drivers so the printf should be using an interrupt on the UART. 

 

My additions to the start of alt_main are as follows: 

 

/* Copy exception code from 0x000FFE00 to 0x20. */ 

unsigned char *src = (unsigned char *) 0x000FFE00; 

unsigned char *dest = (unsigned char *) 0x00000020; 

unsigned char *end = (unsigned char *) 0x000001C8; 

 

while (dest != end) 

*dest = *src; 

*dest++; 

*src++; 

 

 

alt_dcache_flush_all(); 

alt_icache_flush_all(); 

 

I made the program have a start address of 0x00100000 and relocated the .exceptions section to 0x000FFE00 using the following command: 

 

nios2-elf-objcopy --change-section-lma .exceptions=0x000FFE00 my_hello_alt_main.elf my_ham_exc.elf 

 

However when I try and run this from my bootloader program everything appears to hang. I have tried removing some of the other parts of alt_main e.g. alt_irq_init and turning off interrupts before and after copying the exception code but nothing seems to do anything. I'm not certain how to remove pending interrupts from the UART. 

 

The bootloader receives the program data to run over a USB link, turns off everything to do with USB interrupts and stops the hardware from generating any more USB interrupts before running the downloaded code using the following: 

 

// Start downloadable 

asm("MOVIA %0, %1" : "=r" (Jump) : "i" DOWNLOADABLE_START_ADDRESS)); 

asm("JMP %0" : : "r" (Jump));  

 

Where DOWNLOADABLE_START_ADDRESS is defined as:# define DOWNLOADABLE_START_ADDRESS (unsigned char *) 0x100000 

 

Any ideas where I am going wrong?
0 Kudos
Altera_Forum
Honored Contributor II
627 Views

My last post was slightly wrong - it seems that once I added a change to an LED on the board I noticed that things did sometimes work - I just wasn't getting any printf output. Once I realised that it did sometimes run OK I was able to come up with something which seems to work all the time: 

 

The bootloader now disables all interrupts (and does not bother to keep the returned context) before the jump to the downloaded program: 

 

// Disable ALL Interrupts 

alt_irq_disable_all(); 

 

// Start downloadable 

asm("MOVIA %0, %1" : "=r" (Jump) : "i" DOWNLOADABLE_START_ADDRESS)); 

asm("JMP %0" : : "r" (Jump));  

 

 

The alt_main function now starts like this: 

 

/* Copy exception code from 0x000FFE00 to 0x20. */ 

unsigned char *src = (unsigned char *) 0x000FFE00; 

unsigned char *dest = (unsigned char *) 0x00000020; 

unsigned char *end = (unsigned char *) 0x000001C8; 

 

int context = alt_irq_disable_all(); 

 

while (dest != end) 

*dest = *src; 

dest++; 

src++; 

 

 

alt_dcache_flush_all(); 

alt_icache_flush_all(); 

 

alt_irq_enable_all(context); 

 

 

Note that I've removed the redundant dereference('*') from *dest++ and *src++. 

 

I still need to wait for or clear pending interrupts in the bootloader program, at the moment I allow any printf output to finish by putting in a call to usleep. Without this it seems to still work but not all the printf output is seen.
0 Kudos
Reply