In the few months since I started playing around with the zpu_small core, expanding it into what ultimately became ZPUFlex, my variant of the CPU has gone from being an interesting experiment to something that might actually see some usefulness in other projects.
ZPUFlex was intended from the outset to be configurable and flexible, but this comes at the cost of complexity, and there are a number of competing factors to consider when configuring the CPU. The following is an attempt to document some of the choices that must be made when using ZPUFlex.
Do you need interrupts?
If you do, then you must use the full “crt0.s” startup code, since there’s currently no interrupt handler at location 32 in the “mincrt0.s” version of the startup code.
Do you need access to external memory (SDRAM)?
By default the boot ROM is mapped at location 0. If you need to access low memory that would normally be overlapped by the ROM, then you can remap the boot ROM’s location. This is done by using one of the “remapped” linker scripts, and specifying the REMAP_STACK=true generic when instantiating the CPU, The link script *MUST* match the setting of the REMAP_STACK option!
Do you need to minimise code size or the CPU’s usage of logic elements?
If your goal is to have a CPU that uses as few logic elements as possible, then ZPUFlex can be cut to the bone by setting the IMPL_* generics to false. If you do this, however, then you *must* use the full crt0.s startup code, since mincrt0.s doesn’t contain emulations for missing opcodes.
If, on the other hand, you need to keep code size to a minimum, then enable the optional instructions. If you do this, and also specify certain compiler flags when building your firmware, then the ZPU will be able to run the code without using the emulation table at the start of crt0.s. This means you can use mincrt0.s.
Is your program self-contained in a boot ROM, or will you use a boot ROM to load the actual application from external storage?
If you’re writing a self-contained ROM, then use either the standalone_simple, standalone_remapped or boot_mixed_remapped linker scripts.
If you’re writing a program that will be loaded to location 0 by a Boot ROM, then use the boot_mixed_remapped linkscript for the Boot ROM and the standalone_simple linkscript for the program that will be loaded by the Boot ROM. You must also specify REMAP_STACK=TRUE and EXECUTE_RAM=true in the processor instantiation.
Do you want uninitialised variables to be placed in Stack RAM or in external RAM (such as SDRAM)?
If your program is self-contained, its working set fits comfortably within Boot ROM / Stack RAM, and you don’t need to support hardware [load|store][b|h] accesses to your data, then the program’s ultimate speed will be better when running from Stack RAM, so use either the standalone_simple or standalone_remapped linker scripts.
If, on the other hand, you want uninitialized (BSS) data to end up in SDRAM, use the boot_mixed_remapped linker script. Note: by default this script places BSS data at 0x7ff000, on the assumption that at least 8 meg of SDRAM will be available. If you want the BSS data to be placed elsewhere, you’ll need to edit this script.