The .Eeprom Image Format ======================== Understanding the .Eeprom Image Format can be quite confusing at first for those used to traditional, single, native executing processors. A code image for a traditional processor runs from address zero upwards and this address corresponds to the address in the image file ( .HEX or similar ) from which the Rom or Flash of the processor will be burned. There is a one-to-one mapping of image address to code address - Image Code .-------. .-------. 0000 | | <-------- 000 | | | | | | 01FF | | <-------- 1FF | | `-------' `-------' For the Propeller, there has to be a bootloader to start the assembler code and an initial application description placed at the start of the image, and thus the direct one-to-one mapping is lost - Image .-------. 0000 | Desc | |-------| 0010 | Boot | Code |-------| .-------. 0028 | | <-------- 000 | | | | | | 0227 | | <-------- 1FF | | `-------' `-------' To distinguish between Image Address and Code Address we use PC to describe the former ( Image ) and ORG to describe the later ( Cog ) addresses. Additionally, the image can contain separate code for each of the eight Cogs of the Propeller Chip. The code for each could be placed consecutively in the image - Image .-------. 0000 | Desc | |-------| 0010 | Boot | Code |-------| .-------. 0028 | | <-------- 000 | | | | | | For Cog 0 | | <-------- 1FF | | 0227 |_______| `-------' | | .-------. 0228 | | <-------- 000 | | | | | | For Cog 1 0427 | | <-------- 1FF | | `-------' `-------' The Propeller Chip loads the Code for a Cog based upon the PC address of where in the image the Cog code can be found. When loaded, 512 longs are copied from the image ( starting at PC ) to Cog memory ( starting at ORG $000 ), so it can be seen that there is a relationship between PC and ORG with respect to loading a Cog. Although a Cog is loaded with 512 longs, if the Cog does not use 512 longs, these do not have to be included in the code image. While 512 longs will still be loaded, and while that area after the Cog code may be garbage, it does not matter because that garbage is never used by the Cog - Image .-------. 0000 | Desc | |-------| 0010 | Boot | Code |-------| .-------. 0028 | | <-------- 000 | | For Cog 0 0127 |_______| <-------- 0FF | | | | `-------' |_______| | | .-------. 0227 | | <-------- 000 | | For Cog 1 0327 |_______| <-------- 0FF | | | | `-------' `-------' The two unused sections of image after the Cog code placed in Image can be removed. When the Cog is loaded, 512 longs will still be copied, and some of those loaded into Cog 1 will be the initial part of Cog 2 code, but as before, Cog 1 does not use that data so it does not matter - Image .-------. 0000 | Desc | |-------| 0010 | Boot | Code |-------| .-------. 0028 | | <-------- 000 | | For Cog 1 0127 | | <-------- 0FF | | |_______| `-------' | | .-------. 0128 | | <-------- 000 | | For Cog 1 0227 | | <-------- 0FF | | `-------' `-------' Where a Cog uses RES, this is data which does not require pre-initialising before the Cog starts, so it is allowed to containing garbage when loaded from the image. This is convenient, because it means that any RES used in a Cog do not have to be held in the Image - Image .-------. 0000 | Desc | |-------| 0010 | Boot | Code |-------| .-------. 0028 | | <-------- 000 | | For Cog 0 0127 |_______| <-------- 0FF |_______| 0128 | | <-----. 100 | RES | 0227 | | <---. | `-------' `-------' | | .-------. | `-- 000 | | For Cog 1 `---- 0FF |_______| 100 | RES | `-------' This is why it is preferable to use "RES 1" rather than "LONG 0" when defining temporary variables or those which do not require pre-initialisation because they will maximise the amount of image space available for other code for other Cogs, overlays, Spin Code and so forth. This is something which will not necessarily be obvious to the programmer used to a single processor and an image which is a one-to-one mapping of the code where "RES 1" often has the same end result as using "LONG 0" would. Large Memory Model and Overlays =============================== The Large Memory Model is the concept that a Cog can load any part of an Image into its Cog memory during execution and thus create the potential for nearly all of the Image to be used for Cog code, and effectively allow Cog programs to be greater than 512 longs in size. A Cog could reserve 256 longs into which to load a 256 long-sized part of the image from any arbitrary address - Image .-------. 0000 | Desc | |-------| 0010 | Boot | Code |-------| .-------. 0028 | | <-------- 000 | | | | <-------- 07F | ____| ________ | | 080 | | | | | | 1BF | |____| ___ | | | <-------- 1C0 | | | | 0227 |_______| <-------- 1FF | | | | 0228 | | `-------' | | | | | | |-------| ___________________________| | xxxx | | | |_______| ________________________________| | | | | `-------' In this example, the Cog reserves the 256 long space from $080 to $1BF and can copy 256 longs from the image starting at 'xxxx' when it needs to run the code held in the image, jump to $080 and begin executing that loaded code. The code which runs within a Cog which controls the loading of overlays - it must be done under Cog control as the Propeller does not natively support the use of code overlays - is commonly called a kernel because it provides a service for the cog and frequently called a micro-kernel because it is small in size. In order to specify what the code is to be overlaid, this code needs to be created as an 'overlay' piece of code separate to the code which exist for the Cog and with its ORG set to match how it would be when overlaid into the Cog - Image .-------. 0000 | Desc | |-------| 0010 | Boot | Kernel |-------| .-------. 0028 | | <-------- 000 | | | | <-------- 07F | ____| ________ | | 080 | | | | | | 1BF | |____| ___ | | | <-------- 1C0 | | | | 0227 |_______| <-------- 1FF | | | | 0228 | | `-------' | | | | Overlay | | |-------| .-------. ___| | xxxx | | <-------- 080 | | | |_______| <-------- 0BF | | ________| | | `-------' | | `-------' There can of course be multiple overlays, or the concept of the Large Memory Model would be quite limiting - Image .-------. 0000 | Desc | |-------| 0010 | Boot | Kernel |-------| .-------. 0028 | | <-------- 000 | | | | <-------- 07F | ____| ________ | | 080 | | | | | | 1BF | |____| ___ | | | <-------- 1C0 | | | | 0227 |_______| <-------- 1FF | | | | 0228 | | `-------' | | | | Overlay 1 | | |-------| .-------. ___| | xxxx | | <-------- 080 | | | |_______| <-------- 0BF | | ___ | | | `-------' | | | | Overlay 2 | | |-------| .-------. ___| | yyyy | | <-------- 080 | | | |_______| <-------- 0BF | | ________| | | `-------' | | `-------' Large Memory Model Programming ============================== To create the kernel and the overlays, getting the addresses right, knowing where in the Image and which ORG's are which and should be what is a complex business, but the AiChip Assembler provides aid with the "OVERLAY" and the "ORG OVERLAY" directives. To create the image as shown above - Kernel ORG $000 ? ... ; Code for the Kernel here Switch ? ... ; Code to switch to a new overlay ? ... ; More Kernel code Here OVERLAY 256 ; Allocate a 256 long overlaid area ? ... ; Rest of the kernel code and vars Ovlay1 ORG OVERLAY Here ? ... ; Code for Overlay 1 here Ovlay2 ORG OVERLAY Here ? ... ; Code for Overlay 2 here The code within the "ORG OVERLAY" sections will be placed at an appropriate ORG to where it will be overlaid into the Kernel ( at the 'Here' label ) and the code size of the overlay is enforced for code within it. Each overlay can use labels and variables defined within the Kernel simply by specifying them. If an overlay wants to provoke a switch to another overlay it would simply use "JMP #Switch" with some information indicating which overlay was to be loaded. Overlays can have their own local variables and RES, although these will only exist within the scope of the overlay's execution, and do not retain any changes made between invocations of the overlay. The Kernel can determine the address of the two overlays in the image by using the '@' operator; "MOV d,#[@Ovlay1]" will put the image address of 'Ovlay1' into the 'd' register. The kernel can then use this information to load 256 longs from that image location onwards into the Cog memory starting from the 'Here' label. If the Kernel 'Switch' code simply copied the longs as described above, then Overlay 1 could cause a switch to Overlay 2 by using - MOV d,#[@Ovlay2] JMP #Switch To simplify matters, the above construct can be more easily specified by using "FARJMP #Ovlay2", and leaving the assembler to sort out the intricacies. Likewise a "FARCALL #label" allows a call to an overlay. A "RETFAR" must be used instead of RET to return from a FARCALL overlay. The mechanism for allowing the assembler to sort out the details for "FARJMP" and "FARCALL" and how the programmer needs to define mechanisms to allow the assembler to do that is described in the following "programming the kernel" section. Where it is more convenient to put overlays in particular size blocks, or so they are aligned on particular sized boundaries and particular addresses, the "AT" directive can be used. This is the equivalent to "ORG" within a Cog but adjusts the Pc of the image. By utilising "AT", it is possible to put the overlays in specific image locations so which overlay to be loaded can be determined by a simple numeric index, in this case, address = n*$1000 - Kernel ORG $000 ? ... ; Code for the Kernel here Switch ? ... ; Code to switch to a new overlay ? ... ; More Kernel code Here OVERLAY 256 ; Allocate a 256 long overlaid area ? ... ; Rest of the kernel code and vars AT $1000 ; Put overlay 1 in image at $1000 Ovlay1 ORG OVERLAY Here ? ... ; Code for Overlay 1 here AT $2000 ; Put overlay 2 in image at $2000 Ovlay2 ORG OVERLAY Here ? ... ; Code for Overlay 2 here Programming the Kernel ====================== This section hasn't been finalised - in fact, the mechanisms to be used have not been fully researched or tested ! The following are provisional musings and subject to change ... The entry points into the Kernel to handle FARJMP, FARCALL and RETFAR are defined by using the KERNEL directive. This gives the assembler addresses to vector to within the kernel when the FARJMP, FARCALL and RETFAR opcodes are used - Kernel ORG $000 ; Start the kernel definition ? ... ; Code for the Kernel here FARJMP KERNEL ? ... ; Code to handle the FARJMP opcode FARCALL KERNEL ? ... ; Code to handle the FARCALL opcode RETFAR KERNEL ? ... ; Code to handle the RETFAR opcode ? ... ; More Kernel code Here OVERLAY 256 ; Allocate a 256 long overlaid area ? ... ; Rest of the kernel code and vars The KERNEL directive will also ( not shown above ) include a mechanism which defines what code sequences to generate when the FARJMP, FARCALL and RETFAR opcodes are used in an overlay. This allows the kernel designer complete freedom to implement whatever schemes necessary leaving the overlay code as simple to write as possible. Does ENTRY make more sense than KERNEL ? At present OVERLAY creates a zero-filled block. There's merit in using that for code when overlays have not been called and for initialisation of the kernel itself. Adding an "ORG INITIAL OVERLAY Here" to put code in that area and save on image size would make sense. Clumsy but perhaps the easiest way to implement it. A mechanism to have kernels in separate includable files is also sensible, maybe using "KERNEL filename.ext". general inclusion of files was not intended as this was to be provided for by the wrapping IDE, although it could be made to work, with either the IDE pre-filling the flat file with included stuff and removing any "INCLUDE" directives or the assembler doing that itself if it finds one.