Hi Ken,
Just wanted to follow-up from what I wrote last week. We're working on some more official documentation concerning the stuff below, but I figured it might be useful in the interim to get some of this info up on the forum!
Currently you cannot direct both CPUs to boot from the same EPCS controller. Rather than a memory-mapped device it operates in a 'poke a register, read a result' basis.. as such, having two CPUs fight over the EPCS controller is a bad idea. I had a discussion with our engr who is responsible for that (and is now thinking about multi-CPU boot-up for the future) who advised me of this. The same EPCS controller *can* be used to house code for two processors, however, but it requires a bit of a kludgy process to get into place. If you have separate non-volatile storage on your board it will be an easier process (never the less, I outlined the steps below).
As far as the IDE goes - the chief limitation as I alluded the other day is that currently you can only select program/data memories on a
device by device basis (so multiple processors is easy if they all use different memory peripherals), but for splitting up a single SDRAM you'll need to either make linker script modifications to partition your memory, or do some creative things with vector table assignments (details below).
Debugging multiple CPUs *is* supported in the IDE and that is what I had alluded to earlier as we'd tested 8 CPUs at once. I can send you an email if you like with a brief write-up on how to do this. The two important tricks are to enable multiple simultaneous run/debug sessions in the "Nios II Run and Build Settings" are of the IDE preferences, and to choose separate TCP ports for each CPU that you're debugging in the debug setup window prior to starting the debug session (the GDB debugger running behind the scenes uses TCP ports to communicate to the debug IDE).
some other notes: on making your code fit into a small on-chip memory: by default a lot of stuff will get linked into even a simple application. Such is life in a "hosted" environment with device drivers and C libraries. However, you can make it smaller. I suggest checking out hello_world.c in the software examples and reading the comments.. it will tell you how to make things much smaller. There was a thread on this very topic the other day on this forum, I believe. Also consider doing a "free-standing" application (look at the Hello Freestanding example program). These tools will allow you to compile tiny programs that run from onchip memory.
on exception locations in sopc builder: These need to be segregated. As you allude too this isn't too clear. Really it depends on how big the exception handling code is. The default code we link in is a little over 0x300 hex long (0x308 to be specific - just check an .objdump file and look for the code starting at the specified interrupt vector). In addition to the basic interrupt setup and ISR 'funnel' code, this software includes things like SW implementations of multiply & divide for Nios II systems that don't have HW multiply or divide enabled (i.e., the Nios II /e core). However, the software developer may very well wish to chuck our ISR code in favor of something more simple that takes fewer bytes. The only SOPC Builder requirement is that the exception address be aligned to a 0x20 boundary in the memory map.
that said, here is a cool multi-processor trick that deals with the exception addresses: If you want to share a common memory between two CPUs, consider putting the exception location for CPU# 1 at the beginning of shared memory, and then the exception location for CPU# 2 at the location of the "end" of memory that is available to CPU# 1. The reason is that the linker script we automatically generate in the IDE for a software project will link your app just after the exception address (and exception code) for a given processor. It will mark the "top" of the available memory space at the exception location for the next CPU. So.. if I have an SDRAM from 0x1000000 to 0x1ffffff, and put the exception addr for CPU# 2 at 0x1800000, half the memory will be linked against for CPU#1, and half for CPU#2. Both CPUs can live blissfully unaware that there is another processor in the system, other than the decreased memory bandwidth of course! For additional customization of how memory is partitioned, you'll have to edit the linker scripts to tell the linker where it can and cant put code/data/stack.
some conceptual steps for booting code for two cpus out of the same epcs chip: This is just a concept, we haven't tried it yet and it would require a bit of development to get right:
1. Designate a 'master' and 'slave' CPU.
2. Have the master boot out of EPCS, the slave boot out of some other on-chip memory which directs the slave to spin in a loop forever until a register is set (by the master CPU, at the appropriate time). This could be done via assembly language if you want to keep the slave's boot memory ultra small. Of course, after the boot process this memory's job is done, so you could use it for your processor-message box or something else that's useful.
3. Ensure that the code/data spaces of the application code for each CPU don't trample each other (as outlined above, either with exception address placement, or custom linker scripts).
4. Build the application software for the slave CPU, and get an .elf file for it
5. (Here is where we diverge from "have done" into "could be done"): Use a tool such as nios2-elf-objcopy to create a hex representation of the .elf that was compiled for the slave CPU. Then, suck this data into some initialized memory *for the master CPU* via a perl script or something similar (really what would be done is to have the perl script create a .c file with a big C array of data which contains the hex dump of the other .elf file).
6. Build the master CPU's code. Its .elf file will now load both master and slave CPUs' code & data into memory!
7. Program this .elf file into the EPCS chip and have the EPCS boot-loader copy it into memory.
8. When the master CPU wakes up, have it poke a register somewhere that the slave is aware of -- when this happens, your slave's boot program should direct it to jump to its application code at whatever address you linked the software to.
The big disadvantage in the above process (besides getting it going in the first place) is that any change in the slave CPU's code will require the process to be repeated in order to get the EPCS chip reprogrammed.
Whew, that is a bit of info to slog through, just reading back to myself what I typed! Like I say the above will require a bit of work to get done. Again, this is all applicable only for the immediate future. Multi-CPU support in a nice clean manner is yet to come, although it is way to early to say whether we'll have a clean mechanism for booting multiple CPUs out of the same EPCS chip.