MASTER MOS 3.50 SIDEWAYS ROM RELOCATOR ====================================== Overview -------- The Second Processor has more usable memory than the main I/0 processor. If a ROM-based program is to make use of this extra memory, it must be loaded at a higher address in the Second Processor (say &B800) to that it uses in the main I/0 processor (typically &8000). This in turn means that the program itself must be different. With the existing MOS two approaches were used: * to have a different version of the same program for the two processors (for example, BASIC and HIBASIC) * to use the same program on either processor, thus not using the extra memory of the Second Processor. The new MOS approach is: * to support a new type of ROM-based program which can be run at a different address (or relocated) depending on which processor it is being run on. When such a ROM-based program is copied through the TUBE to the Second Processor: * it is automatically rewritten using information held in the ROM * it is then ready to run at the new address, and is loaded there. Technical details ----------------- If a program is assembled twice, using a different load address each time, the majority of bytes will be identical between the two versions. This includes bytes that specify: * the type of instruction to be performed * any relative addressing, since the target will still be the same number of bytes away * text strings * immediate data. The only bytes that are likely to be different are those that specify an absolute address within the program. These are likely to change by a fixed amount, as all the code should have moved in memory by the same offset. If the two programs were ROM images, to be loaded at &8000 and &B800 respectively, you would expect such bytes to differ by &38 - the number of pages offset between the two load addresses. A ROM image for the second processor can be derived from one for the main I/0 processor if we know: * which bytes differ from the corresponding ones in the other ROM image * what the fixed offset is between such bytes. A bit-map is used to keep track of which bytes need the offset added. Since the ROM itself only uses memory from pages &7F to &BF inclusive, all the bytes that do differ should lie in this range. Space is saved in the bit-map by only keeping a bit record for these bytes. The relocator is an extension to the TUBE code. When a ROM is copied through the TUBE the relocator checks if: * the Second Processor is a 6502 * the ROM is one of the new relocatable ones * the bit-map with the ROM has the expected format. If any of the above conditions are not met, the ROM is copied unaltered, and the relocator has no effect. If all the above conditions are met, the relocator selectively adds the offset to each byte as it is copied through the TUBE: * Bytes from &00 to &7E have no corresponding bit kept in the bit map. These bytes are not altered by the relocator as they are copied. * Bytes from &7F to &BF have a single corresponding bit kept in the bit-map. If the bit is set, the relocator adds the offset to the byte as it is copied; if the bit is clear, the byte is not altered * Bytes from &C0 to &FF have no corresponding bit kept in the bit map. These bytes are not altered by the relocator as they are copied. Limitations ----------- The relocator will only work correctly if the bytes in the two ROM images that differ do so by a fixed amount. This implies that the relocation must be by a whole number of pages. (If the relocation were by an offset of &1234, then some bytes would differ by &12, and s ome by &34). Avoiding relocation ------------------- The *FX 142 call has been extended so you can choose whether or not a ROM image relocates as it is copied: * if you want the ROM image to relocate, use *FX 142 * if you do not want the ROM image to relocate, type *FX 142 Writing a relocatable ROM ------------------------- A relocatable ROM is very similar to any other ROM written to be copied through the TUBE; the only major addition is the bit-map. The ROM's format is shown by the diagram - please refer to it as you read this section. You may also find the section of the Master Series Reference Manual entitled F.7 Paged ROMS useful. Note that the order of the title, version number and copyright strings shown in the diagram is correct; the Master Series Reference Manual incorrectly states that the optional version number string follows the copyright string. Note the following: * bytes &00 - &02 must not be zero, since the ROM will contain a language * the ROM must support a service call entry In the ROM type byte (offset &06): * the service entry bit (bit 7) must be set * the language bit (bit 6) must be set, since the ROM contains a language * the relocation bit (bit 5) must be set * bit 4 must be clear * the code type bits (bits 3-0) must specify 6502 code (0010) All ROMs that are copied through the TUBE have a relocation address, which follows the copyright string. This is the address at which the ROM is loaded in the second processor. The relocator can differ between an old-type ROM (for use only in the Second Processor) and one of the new relocatable ROMs (for use in either processor) because: * in an old-type ROM, the relocation address is followed by two null bytes * in a relocatable ROM, the relocation address is followed by a pointer to the bit-map descriptor table. The bit-map descriptor table must lie in the same ROM as the header. It tells the relocator where to find the bit-map. The bit-map itself can lie in another ROM. The descriptor table gives the address of the byte after the last byte of the bit-map. It also specifies which ROM the bit-map is in: * if the top-bit of the ROM number byte is set, the number is given relative to the ROM containing the descriptor table (so 10000000 would specify the same ROM as the descriptor table, 10000001 would specify the next highest ROM, and so on) * if the top-bit of the ROM number byte is clear, the ROM number is absolute, and so the ROM containing the bit-map must be in a specific socket. You should preferably use relative addressing; multi-chip sets should lie in adjacent sockets. The bit-map is the greatest difference between an old-type ROM and a relocatable ROM. Note the following: * the bit-map is filled from high memory to low memory * each byte of the bit-map is filled from bit 7 to bit 0 * the last byte in the bit-map to be filled (labelled +0 in the later diagram) has any unused low-order bits padded with zeroes * the two bytes &C0DE must be present as a redundancy check. <-- Low memory High memory --> +-------------------------------+---------------------------+ | 2nd byte of flags | 1st byte of flags | +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ | 9 | 10| 11| 12| 13| 14| 15| 16| 1 | 2 | 3 | 4 | 5 | 6 | 7 | +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ Order in which bit flags are filled (first two bytes shown) A program is given at the end of this appendix which will automatically generate a bit-map for you. Before running the program you will need to assemble your ROM image twice: once to run at &8000; and again to run at the relocation address, which should be a higher address at the start of a page (the low byte of the address must be &00). Store the two images in separate files. When you run the program, it will prompt you for the two filenames, generate the bit-map, and save it in the file bitmap. Three error messages are possible: Could not open The program could not open the given file. Check you typed its name correctly, and are in the correct directory. Fatal error - bitmap table underflow The space allowed by the program for the bitmap (64k bits) was inadequate. Check you have correctly typed the program. If necessary, increase the space allocated to bmbuff% in line 80. Fatal error - difference not constant The program found a pair of bytes whose difference was not the same as that of previous ones. The address of the offending pair is also given, relative to the start of the ROM image. Look at your source code and correct any reason for this. Relocatable ROM header ---------------------- &00 - &02 JMP ROM language entry address &03 - &05 JMP ROM service call entry &06 ROM type flags - must be 11100010 &07 offset to start of copyright string &08 version number in binary | ASCII NUL &09... title string [ ASCII NUL, version string ] ASCII NUL ASCII '(' ASCII 'C' ASCII ')' rest of copyright string ASCII NUL relocation address: low byte relocation address: hi byte pointer to bit-map descriptor table: low byte pointer to bit-map descriptor table: hi byte Bit-map descriptor table (must be in the relocatable ROM) --------------------------------------------------------- pointer to byte after bit-map: low byte pointer to byte after bit-map: hi byte relative/absolute ROM number bit-map is held in ASCII NUL (reserved for future use) Bit-map (can be in another ROM if necessary) -------------------------------------------- +0 nth byte of flags (for bytes at end of ROM image) +1 (n-1)th byte of flags ... ... +(n-2) 2nd byte of flags +(n-1) 1st byte of flags (for bytes at start of ROM image) +n length of bit-map n: low byte +(n+1) length of bit-map n: hi byte +(n+2) &C0 +(n+3) &DE +(n+4) This byte is pointed to by the descriptor table. It is not part of the bit-map. Program -------- 10 REM> GenBitMap 20 REM generates bitmap for the given image 30 REM the program requires two ROM images: 40 REM the original (assembled at &8000) 50 REM the alternative (assembled >= &8100) used to check for differences 60 REM the bitmap (if valid) is always placed in the binary image "bitmap" 70 : 80 DIM bmbuff% &2000:REM 8K should be large enough for the bitmap 90 bend%=bmbuff%+&2000 100 bptr%=bend%:REM start at the end 110 : 120 code%=&DEC0:REM bitmap identifier 130 dist%=&0000 140 numbits%=&0000 150 address%=&8000-1 160 : 170 INPUT "File containing ROM image assembled at &8000 => "realrom$ 180 INPUT "File containing ROM image assembled for relocation => "altrom$ 190 : 200 rr%=OPENIN(realrom$) 210 IF rr%=0 THEN PRINT "Could not open ";realrom$:END 220 : 230 ar%=OPENIN(altrom$) 240 IF ar%=0 THEN PRINT "Could not open ";altrom$:CLOSE#rr%:END 250 : 260 REM -- the bitmap is stored in reverse order, with the bitmap header 270 REM -- information stored at the end 280 REM -- the header contains a special identifies (CODE) and the length 290 REM -- of the bitmap in bytes 300 bptr%=bptr%-2:REM step over ID 310 bptr%?&00=code% MOD &0100 320 bptr%?&01=code% DIV &0100 330 bptr%=bptr%-2:REM step over bit count 340 bptr%?&00=&00 350 bptr%?&01=&00 360 bcadr%=bptr%:REM but remember where we need to place it 370 : 380 REPEAT 390 : 400 bptr%=bptr%-1 410 val%=0 420 bc%=8 430 : 440 REPEAT 450 : 460 v1%=BGET#rr% 470 v2%=BGET#ar% 480 address%=address%+1 490 : 500 IF ((v1% >= &7F) AND (v1% <= &BF)) THEN PROCcheck 510 : 520 UNTIL (bc%=0) OR (EOF#rr% OR EOF#ar%) 530 : 540 REM check and see if the last byte in the bitmap table needs to be 550 REM padded (this is required due to the lo-address byte being stored 560 REM in the highest bit) 570 IF (bc%=0) THEN PROCinsert ELSE IF (bc%>0 AND bc%<8) THEN FOR loop%=bc% TO 1 STEP -1:val%=(val%*2)+0:NEXT:PROCinsert 580 IF bc%=8 THEN bptr%=bptr%+1 590 : 600 UNTIL (EOF#rr% OR EOF#ar%) OR (bptr%" 720 IF bptr%>=bmbuff% THEN OSCLI(save$) 730 : 740 END 750 : 760 DEFPROCinsert 770 REM place a byte into the bitmap, and decrement pointers 780 bptr%?&00=val%:numbits%=numbits%+1 790 ENDPROC 800 : 810 DEFPROCcheck 820 REM - check if a byte needs relocating 840 LOCAL d% 850 IF v1%=v2% THEN PROCaddbit(0):ENDPROC 860 REM they are different 870 REM check they are always the same distance apart 880 d%=v2%-v1% 890 IF dist%<>0 AND d%<>dist% THEN PRINT"Fatal error - difference not constant" ELSE IF dist%=0 THEN dist%=d% 900 : 910 PRINT "Diff at &";~address% 920 : 930 PROCaddbit(1) 940 ENDPROC 950 : 960 DEFPROCaddbit(v%) 970 REM - add the bit given into the structure 980 REM this is done by remembering the bit in the current byte 990 REM bc% : global that holds the bit count within the current byte 1000 REM val% : global that holds the current byte 1010 bc%=bc%-1 1020 val%=(val%*2)+v% 1030 ENDPROC