This format is meant as an extension of the Editor/Assembler option
5 format, i.e. the files contain a "memory image" together with some information
on where and how to load it. It's completely backward compatible with the
EA5 format and the Gramkracker format, but adds extra options at the end
of the file. These options are in the form of a tagged list, which will
allow for adding new options in the future.
In case you wonder, FB6 was coined by just incrementing by one each character in EA5. But it could also mean "Fully Bloated".
The overall file stucture is the following:
CONT BYTE >xx continuation flag FLAG BYTE >xx target id ADDR DATA >xxxx loading address SIZE DATA >xxxx number of bytes to load CODE BSS SIZE code to be loaded EVEN TAGS BSS >xxxx tagged list of optionsAs you can see, the 6-byte header is the same as with EA5 and GK format.
CONT can be >00 or >FF. If it is >FF loading should proceed with another file. With EA5, the new file name is obtained by incrementing the last character in the file name. With GK format, the second file name is produced by appending a '1' to the first file name. This additional character is subsequently incremented if more files are to come.
FLAG indicates both the format and the target. If it is >00 or >FF, it denotes EA5 format and the target is always CPU memory. If it is between >01 and >08, the target is GROM 0 through 7, respectively (GROMs are >2000 bytes apart). If FLAG is between >09 and >18, the target is "cartridge" ROM banks 0 through 15, respectively (and the address should thus be in the range >6000-7FFF). Other values are reserved.
ADDR is the address where the code is to be loaded.
SIZE is the number of bytes to load.
CODE is the data to be loaded. It is a pure memory image, i.e. it must be loaded at the indicated address to work properly, and cannot be linked with other pieces of code at loading time. Some of the new options in the FB6 format allow to overcome these limitations.
TAGS is the list of FB6 options, which I shall describe below.
It starts on a word boundary, so if SIZE is an uneven number, a >00 byte
will be appended to the code.
TAG BYTE >xx option identifier SIZE BYTE >xx size of option in words (0=size in next word) OPTS BSS (2*SIZE)-2 data used to implement the option (if any)TAG is a one-byte identifier that describes the option. A loader that does not recognize an option can either skip it, issue a warning, or abort with an error.
SIZE is the size of the option in words. It does include the tag and size bytes, so it is always at least 1. A value of zero means that the option is bigger than 255 words, and that the size is provided in the next word.
OPTS depends on the options. Some will have nothing here, most will have data needed to implement the option.
Below is a description of the currently available options.
TAG BYTE >FB SIZE BYTE >01This is one of the rare exceptions to the rule that options can occur in any order. This must be the first option in the list, as it allows the loader to determine whether the file format is indeed FB6.
TAG BYTE >00 SIZE BYTE >01And here is the other exception to the above rule: this tag marks the end of the option list. The loader will not consider data located after this tag.
TAG BYTE >F1 SIZE BYTE >02 FLAGS DATA >xxxxThis option serves as a "table of contents" for the loader. It lists various properties of the code to be loaded, and indicates which option is to be found among the list. It is optional, but if present it should be placed towards the top of the list, to give the loader an advanced warning of what is to come. There could be more than one word of flags, although only one is defined at the moment.
Flag values are:
>0001: must load in RAM or GRAM (no EEPROM)
>0002: must be loaded in GRAM/GROM
TAG BYTE > SIZE BYTE >02 PAGE DATA >xxxx page number (device-specific)This option is used in case the target device has a paged memory (e.g. the IDE card SRAM, cartridge ROMs, SAMS memory card, etc) . It specifies which page the code is to be loaded into. The page number is device-specific.
If the code is to be loaded in GRAM/GROM, PAGE contains the GROM base
to be used, i.e. >9800, >9804, ... ,>983C.
TAG BYTE > SIZE BYTE >02 PAGE DATA >xxxx page number (linker-specific)This option is similar to the above, except that the page number is arbitrary. The loader is free to use any page it wishes in the target device, but it must keep track of this page number. The purpose of this option is to allow linking between files loaded in different pages. Another file may use the REF option to find out in which page the present file was loaded.
For GRAM/GROM files, the page number will be replaced with a GROM base
to be chosen by the loader.
TAG BYTE > SIZE BYTE >xx size of the whole list (in words) + 1 ADDR DATA >xxxx intended address OFFSET DATA >xxxx,>xxxx locations to be patchedThis option allows you to write code that can be loaded at any location. As explained below for plugin routines, assembly code only runs at the location is was meant for, unless special precautions are taken at the time of writing. An alternative solution is for the linker to provide a list of addresses that need to be fixed if the code is to be run at a different address than the intended one. If the loading address does not match the intended address indicated in this option, the loader will add the difference to every location in the offset list (the location is obtained by adding the actual loading address to the offset).
For instance, suppose you wrote the following program
AORG >A000 A000 MOV R11,@THERE >C020,>A014 A004 BL @SUB >0A20,>A00E A008 MOV @THERE,R11 >C80B,>A014 A00C B *R11 >045B SUB LI R0,THERE >0200,>A014 A012 B *R11 >045B THERE DATA 0 >0000This program will only run properly when loaded at >A000, because it expects SUB to be located at >A00E. But assume you provide the following relocation list:
TAG BYTE > SIZE BYTE >06 size of the option (i.e. list size + 2) ADDR DATA >A000 intended address OFFSET DATA >0002,>0006,>000A,>0010Now the code can be loaded at, say, >B000 and the loader will patch it as follows:
B000 MOV R11,@THERE >C020,>B014 <-- patched B004 BL @SUB >0A20,>B00E <-- patched B008 MOV @THERE,R11 >C80B,>B014 <-- patched B00C B *R11 >045B SUB LI R0,THERE >0200,>B014 <-- patched B012 B *R11 >045B THERE DATA 0 >0000The drawback of this method is that the relocation list can become fairly bulky. So you may want to make a compromise and use it together with the indexing technique described for plugins. Patch only the instructions that cannot be indexed, such as immediate instructions, or BLWP vectors.
TAG BYTE > SIZE BYTE >xx size of the whole list (in words) + 1 VALUE DATA >xxxx symbol value NAME TEXT 'NAME ' symbol name, always 6 charsThis option is used to provide one or more symbols to the loader. It will allow for linking with other files containing the REF option. The example above shows only one symbol, but there could be more. SIZE is used to decide when the end of the list has been reached. The loader will build a symbol table containing the names and values provided, and use it at the end of the loading process to patch all REFs.
Reserved names:
$SEG is used to specify a segment number for the code contained in the
current file. If no such label is provided, the loader just assigns segment
numbers sequentially: >0001 for the first file, >0002 for the second, etc.
TAG BYTE > SIZE BYTE >xx size of the whole list (in words) + 1 OFFSET DATA >xxxx symbol offset NAME TEXT 'NAME ' symbol name, always 6 charsThis option is identical to the above one, except that symbols values are offsets rather than absolute values. The loader will add the loading address of the code to the value placed in the symbol table. This allows DEFined symbols corresponding to locations within a relocatable program.
TAG BYTE > SIZE BYTE >xx size of the whole list (in words) + 1 OFFSET DATA >xxxx first appearance of the symbol NAME TEXT 'NAME ' symbol name, always 6 charsThis option is used in conjuction with the DEF one, to link together files that may be loaded at different places. It works pretty much like for an EA3 loader: the OFFSET word indicates where in the code is the first occurence of this symbol. That word will contain the offset of the second occurence, etc. The final word will contain >0000 (which means that the very first word in the code cannot be a REFed symbol). The loader will add the provided symbols to its symbol table and patch the code after loading. It will "walk the chain", substituting the value provided by the corresponding DEF. If no DEF with the same name is loaded, an error will be issued.
Reserved names:
$Sxxxx is used to get the loading address of a given segment. The segment
number is encoded in the label name, e.g. $S0012 for segment 18 (which
is >12 in hexadecimal notation).
$Pxxxx is used to get the absolute page number assigned by the
loader to a given relative page. The relative page number is encoded in
the label name, e.g. $P0001 for page 1.
TAG BYTE > SIZE BYTE >xx size of the whole list (in words) + 1 NAME TEXT "NAME " symbol name, always 6 chars OFFSET DATA >xxxx,>xxxx occurences of this symbol DATA >FFFF end of list for this symbolThis option is used pretty much like the above one, except that no chain exists in the code. Instead, a list of locations to be patched is provided (in the form of offsets, i.e. the loaded will add the loading address to each of these). Each list ends with a >FFFF offset. There may be more than one symbol, the loader use SIZE to decide if there are more.
The same names as for the REF chain option are reserved.
TAG BYTE > SIZE BYTE >xx size of the string (in words) + 1 ID TEXT 'NAME' device identifier EVEN append a zero if ID contains an uneven number of charsThis option is used to specify a particular target device. The loader should check whether the device is present in the system, and abort with an error if it isn't. Another option exists that provides a device-recognition routine, so that one can write code for devices that the loader does not know.
AORG >A000 WRONG MOV R11,@THERE this will NOT work BL @SUB MOV @THERE,R11 B *R11 SUB LI R0,THERE B *R11 THERE DATA 0The above code will only execute properly at >A000, because it references SUB and THERE as absolute addresses. Since it is ulikely to be loaded there, it will fail miserably: when branching at SUB is will actually branch at >A00E, no matter where SUB was actually loaded. The proper way to code this is:
AORG >A000 RIGHT MOV R11,@THERE(R9) this will work BL @SUB(R9) MOV @THERE(R9),R11 B *R11 SUB LI R0,THERE this is the wrong address A R9,R0 correct address in R0 B *R11 THERE DATA 0By indexing every address with R9, one allows the routine to work anywhere in memory. Note that we had to add an extra instruction after the LI because immediate instructions cannot be indexed.
TAG BYTE > SIZE BYTE >xx size of the routine (in words) + 1 CODE ... assembly routineThis plugin provides a routine that checks for the presence of its target device. It is entered with the following registers:
R0: loading flags (first word in file header)
R1: loading address (second word)
R2: loading size (third word)
R9: offset
R11: return address
R12: >FFFF
Your routine should scan the system looking for the presence of the
intended device. If it is found, place its CRU in R12 (if any) and return
with B *R11. If it is not found, return with INCT R11, B *R11.What the
loader will do in this case depends on the value in R12: if it is >FFFF
the loader will abort with a "Device not found" error, if it is >0000 a
warning will be issued but loading will proceed anyway, if it is >0001
loading skips to the next file (if any).
TAG BYTE > SIZE BYTE >xx size of the routine (in words) + 1 CODE ... assembly routine#This plugin routine will be called by the loader when it encounters a "relative page" tag. The routine should provide in R0 the absolute number of a page suitable to load the code described by R1 and R2. The registers will contain:
R0: relative page number
R1: loading address
R2: loading size
R9: offset
R11: return address
R12: device CRU
If a suitable page can be found, return its number in R0. If not, return
with INCT R11, B *R11 and an error code in R0 (see above).
TAG BYTE > SIZE BYTE >xx size of the routine (in words) + 1 CODE ... assembly routine#This plugin routine will be called before the loader begins writing to a device, and after it is done (with a different value in R3). It can be used for several purposes, such as to unprotect a write-protected device. It may also be called by the loaders to change the current page in the memory area designated by R1. The registers will contain the following values:
R0: loading page (>FFFF if none)
R1: loading address
R2: loading size
R3: >0000 to begin, >FFFF to end, >0001 to change pages
R9: offset
R11: return address
R12: device CRU
TAG BYTE > SIZE BYTE >xx size of the routine (in words) + 1 CODE ... assembly routine#This plugin is used with devices that require a special operation to write a word, as is the case with an EEPROM for instance. Your routine is in charge of writing the word (or byte, as the case may be). Return with B *R11 if all went well, and with INCT R11, B *R11 if a problem occured. In the latter case, an error code can be placed into R0, add >8000 to the code to cause the loader to issue a warning rather than aborting. Upon calling, the registers will contain the following values:
R0: loading page (>FFFF if none)
R1: loading address
R2: >0000 write a word, >0001 write a byte
R3: word (or byte) to write. If it's a byte, it will be in the most
significant byte if R3.
R9: offset
R11: return address
R12: device CRU
Last updated: 31/10/2007