Introduction

The relocation format described here is designed to ease the porting of applications from a one 6502-based system (or from a generic 6502 baseline) to another 6502-based system.

The 65816 has instructions like BRL, PER, and PHK, so it possible to write code that is position-independent (i.e. it will run at any location) or relocates itself (assuming it is loaded into RAM) at initialization. These instructions are not present on either the NMOS 6502 or the 65C02, which is where this relocation format comes in. It can also relocate variable addresses (whether on the zero page or not), zero page usage, and allows the locations of system dependent routines (e.g. character input, line input, character output, etc.) to be specified.

All that needs to be provided is a table that maps the original addresses to the locations of system-dependent routines and available zero page and RAM locations. While it could be used by an OS to load applications, its main goal is to handle the bulk of the work involved in porting, and avoid converting assembler syntax or installing the assembler originally used by the author. As such, it handles only common cases; rare and/or special cases must be ported manually. In addition, it does not attempt to track or enforce any special requirements (e.g. page boundary alignment). This format is intentionally more primitive than the well thought out .o65 file format (by Andre Fachat).

For example, suppose you have a 6502 application you want to try on your system. One of its tables must be aligned on a page boundary. So you load it at such an address. Then you define the map table so that the code gets properly relocated, so that it uses the I/O routine addresses of your system, stores its variables in the available RAM of your system, and uses the available zero page locations of your system.

The relocation format

The format consists of a 6-byte header, followed by the program as originally assembled, followed by the relocation data. Note that the original program does not need to be modified at all, even it were written without this relocation format in mind; only the header and the relocation data need to be added.

The six byte header is (in hex):

10 04 30 02 LL HH

LL and HH are the low and high bytes of the length of the program data (i.e. the number of bytes between the header and the relocation data). The first four bytes, in addition to providing a "file identification" signature, also form BPL and BMI instructions that (in a relocatable fashion) skip past the length bytes, regardless of the value of the N flag upon entry. Thus it is not even necessary to strip off the header for applications that do not require relocation. Since the program is in its originally assembled form, it was presumably assembled to run on some system. If the memory map it uses is compatible with your system, there are no zero page conflicts, and any system-dependent routines are at the same addresses, you could just load it, header, relocation data, and all, and run it.

The relocation data consists of any number of relocation entries; each entry is one, five, or six bytes. The format of a relocation entry is:

DB relocation_type
DW number_of_bytes_to_advance ; not present if type = 0
DW address_referenced         ; not present if type = 0
DB low_byte_of_expression     ; not present if type = 0, 1, or 3

The relocation types are:

An 8-bit reference can be either a zero page location, or the low byte of a 16-bit address. It can also handle references in the form of address+constant or address-constant. For example:

ZP     = $12
TABLE  = $3480
OUTPUT = $ABCD
   ORG $1000
START
r1 LDA #TABLE   ; 8-bit reference (low byte of a 16-bit reference)
r2 STA ZP       ; 8-bit reference
r3 LDA #>TABLE  ; high byte of a 16-bit reference
r4 STA ZP+1     ; 8-bit reference
r5 LDA (ZP),Y   ; 8-bit reference
r6 LDA #>SUB-1  ; high byte of a 16-bit reference
   PHA
r7 LDA #SUB-1   ; 8-bit reference (low byte of a 16-bit reference)
   PHA
   RTS
SUB
r8 JSR OUTPUT   ; 16-bit reference
   RTS
r9 DW  OUTPUT-1 ; 16-bit reference
END

Consequently, the header is:

   DB  $10,$04,$30,$02
   DW  END-START

And the relocation data is:

   DB  1
   DW  r1+1 - START
   DW  TABLE

   DB  1
   DW  r2+1 - r1-1
   DW  ZP

   DB  2
   DW  r3+1 - r2-1
   DW  TABLE
   DB  TABLE

   DB  1
   DW  r4+1 - r3-1
   DW  ZP

   DB  1
   DW  r5+1 - r4-1
   DW  ZP

   DB  2
   DW  r6+1 - r5-1
   DW  SUB
   DB  SUB-1

   DB  1
   DW  r7+1 - r6-1
   DW  SUB

   DB  3 
   DW  r8+1 - r7-1
   DW  OUTPUT

   DB  3
   DW  r9 - r8-1
   DW  OUTPUT

Note that the relocation data contains the reference address, but not the +/- constant (except for the sixth byte of a type 2 entry). This allows things like:

MODE   DB  0 ; default value
OUTPUT RTS
       DW  MODE,OUTPUT-1

to be handled properly (where the two addresses in the DW have the same value, but they might not be after relocation, if one get relocated to RAM and the other to ROM).

How to use it

The map table is extremely simple. It consists of any number of entries. The format of an entry is:

DW original_address,new_address
There are two important requirements. First, the entries must be in order of decreasing original address. Second, the original address of the last entry must be $0000. For example:
   DW $F000,$FF00 ; $F000 and above -> $FF00 and above
   DW $89AB,$1200 ; $89AB and above (up to $F000) -> $1200 and above
   DW $8000,$1000 ; $8000 and above (up to $89AB) -> $1000 and above
   DW $0000,$0000 ; everything below $8000 stays at the same address

Before it can be used, (unless you wish to use it at its assembled address), the relocator itself must be relocated, so it has been prefaced with a short routine to do just that. This pre-relocator is very primitive, and rather than use a map table, it is relocated to run at the address it is loaded at, which means the pre-relocator requires the relocator to be in RAM. However, the relocator can relocate (a copy of) itself, so you can reload it and relocate that if you wish to e.g. generate a ROM version. As always, use the X register to specify which zero page locations to use. Initialize the first two locations with the address of the pre-relocator (important note: not the address of the header of the pre-relocator, i.e. the address of the CLD instruction, not the BPL instruction). The other four zero page locations do not need to be initialized.

To use actual relocator, again use the X register to specify which zero page locations to use. Initialize the first two locations with the address of the map table. Initialize the next two locations with the address of the header of the program to be relocated. The remaining 6 zero page locations do not need to be initialized.

Features

Source and object code

                 [ 10 @ 'BPL'                                  ]
                 [ 30 @ 'BMI'                                  ]
                 [ 60 @ 'RTS'                                  ]
                 [ 90 @ 'BCC'                                  ]
                 [ A0 @ 'LDY #'                                ]
                 [ D0 @ 'BNE'                                  ]
                 [ 61 @ 'ADC ,X)'                              ]
                 [ 81 @ 'STA ,X)'                              ]
                 [ A1 @ 'LDA ,X)'                              ]
                 [ 75 @ 'ADC ,X'                               ]
                 [ 95 @ 'STA ,X'                               ]
                 [ B5 @ 'LDA ,X'                               ]
                 [ F6 @ 'INC ,X'                               ]
                 [ 18 @ 'CLC'                                  ]
                 [ 38 @ 'SEC'                                  ]
                 [ 88 @ 'DEY'                                  ]
                 [ D8 @ 'CLD'                                  ]
                 [ 69 @ 'ADC #'                                ]
                 [                                             ]
                 [ 00 @ 'PGMP'                                 ]
                 [ 01 @ 'PGMP+1'                               ]
                 [ 02 @ 'RELP'                                 ]
                 [ 03 @ 'RELP+1'                               ]
                 [ 04 @ 'PSTL'                                 ]
                 [ 05 @ 'PSTH'                                 ]
                 [                                             ]
                 [ 20 @ 'JSR'                                  ]
                 [ B0 @ 'BCS'                                  ]
                 [ F0 @ 'BEQ'                                  ]
                 [ C1 @ 'CMP ,X)'                              ]
                 [ E1 @ 'SBC ,X)'                              ]
                 [ 48 @ 'PHA'                                  ]
                 [ 68 @ 'PLA'                                  ]
                 [ 98 @ 'TYA'                                  ]
                 [ A8 @ 'TAY'                                  ]
                 [ 49 @ 'EOR #'                                ]
                 [ A9 @ 'LDA #'                                ]
                 [ C9 @ 'CMP #'                                ]
                 [ 4C @ 'JMP'                                  ]
                 [                                             ]
                 [ 00 @ 'ML'                                   ]
                 [ 01 @ 'MH'                                   ]
                 [ 02 @ 'PP'                                   ]
                 [ 03 @ 'PP+1'                                 ]
                 [ 04 @ 'RP'                                   ]
                 [ 05 @ 'RP+1'                                 ]
                 [ 06 @ 'AL'                                   ]
                 [ 07 @ 'AH'                                   ]
                 [ 08 @ 'MP'                                   ]
                 [ 09 @ 'MP+1'                                 ]
                 [                                             ]
                 [ 7FA7 @                                      ]
                 [                                             ]
(10,04,         )[      'BPL',00*,                             ]
(30,02,         )[      'BMI',02*,                             ]
(A0,01,         )[      (DW) 01A0,, (PRELDATA-PRELOC)          ]
                 [ 00=>02=>                                    ]
                 [ (PRELOC)                                    ]
(D8,            )[      'CLD',                                 ]
(18,            )[      'CLC',                                 ]
(B5,00,         )[      'LDA ,X','PGMP',                       ]
(69,53,         )[      'ADC #',53, (PROGRAM-PRELOC)           ]
(95,00,         )[      'STA ,X','PGMP',                       ]
(90,03,         )[      'BCC',00*,                             ]
(F6,01,         )[      'INC ,X','PGMP+1',                     ]
(18,            )[      'CLC',                                 ]
(B5,00,         )[ 00=> 'LDA ,X','PGMP',                       ]
(95,04,         )[      'STA ,X','PSTL',                       ]
(69,F8,         )[      'ADC #',F8, (RELDATA+1-PROGRAM)        ]
(95,02,         )[      'STA ,X','RELP',                       ]
(B5,01,         )[      'LDA ,X','PGMP+1',                     ]
(95,05,         )[      'STA ,X','PSTH',                       ]
(69,00,         )[      'ADC #',00,                            ]
(95,03,         )[      'STA ,X','RELP+1',                     ]
(18,            )[      'CLC',                                 ]
(A0,11,         )[      'LDY #',11,                            ]
(A1,02,         )[ 02*  'LDA ,X)','RELP',                      ]
(75,00,         )[      'ADC ,X','PGMP',                       ]
(95,00,         )[      'STA ,X','PGMP',                       ]
(90,03,         )[      'BCC',04*,                             ]
(F6,01,         )[      'INC ,X','PGMP+1',                     ]
(18,            )[      'CLC',                                 ]
(B5,04,         )[ 04=> 'LDA ,X','PSTL',                       ]
(61,00,         )[      'ADC ,X)','PGMP',                      ]
(81,00,         )[      'STA ,X)','PGMP',                      ]
(F6,00,         )[      'INC ,X','PGMP',                       ]
(D0,02,         )[      'BNE',06*,                             ]
(F6,01,         )[      'INC ,X','PGMP+1',                     ]
(B5,05,         )[ 06=> 'LDA ,X','PSTH',                       ]
(69,00,         )[      'ADC #',00,                            ]
(81,00,         )[      'STA ,X)','PGMP',                      ]
(18,            )[      'CLC',                                 ]
(A9,05,         )[      'LDA #',05,                            ]
(75,02,         )[      'ADC ,X','RELP',                       ]
(95,02,         )[      'STA ,X','RELP',                       ]
(90,02,         )[      'BCC',08*,                             ]
(F6,03,         )[      'INC ,X','RELP+1',                     ]
(38,            )[ 08=> 'SEC',                                 ]
(88,            )[      'DEY',                                 ]
(D0,D4,         )[      'BNE',02=<                             ]
(60,            )[      'RTS',                                 ]
                 [                                             ]
(10,04,         )[      'BPL',00*,                             ]
(30,02,         )[      'BMI',02*,                             ]
(F7,00,         )[      (DW) 00F7,, (RELDATA-PROGRAM)          ]
                 [ 00=>02=>                                    ]
                 [ (PROGRAM)                                   ]
(D8,            )[      'CLD',                                 ]
(20,E6,80,      )[      'JSR','HEADER1 ',,                     ]
(20,ED,80,      )[      'JSR','HEADER2 ',,                     ]
(20,73,80,      )[      'JSR','ADJMAP ',,                      ]
(18,            )[      'CLC',                                 ]
(90,0E,         )[      'BCC',04*,                             ]
(20,22,80,      )[ 00*  'JSR',06*,,                            ]
(F6,08,         )[      'INC ,X','MP',                         ]
(D0,02,         )[      'BNE',02*,                             ]
(F6,09,         )[      'INC ,X','MP+1',                       ]
(A1,08,         )[ 02=> 'LDA ,X)','MP',                        ]
(20,AF,80,      )[      'JSR','ADDP 1',,                       ]
(20,C7,80,      )[ 04=> 'JSR','GETR 1',,                       ]
(A8,            )[      'TAY',                                 ]
(D0,EC,         )[      'BNE',00=<                             ]
(60,            )[      'RTS',                                 ]
                 [ 'relocate'                                  ]
(48,            )[ 06=;;'PHA',                                 ]
(20,C7,80,      )[      'JSR','GETR 2',,                       ]
(A8,            )[      'TAY',                                 ]
(20,C7,80,      )[      'JSR','GETR 3',,                       ]
(20,BA,80,      )[      'JSR','SEEKP ',,                       ]
(20,C7,80,      )[      'JSR','GETR 4',,                       ]
(95,06,         )[      'STA ,X','AL',                         ]
(20,C7,80,      )[      'JSR','GETR 5',,                       ]
(95,07,         )[      'STA ,X','AH',                         ]
                 [ (FIND)                                      ]
(B5,01,         )[      'LDA ,X','MH',                         ]
(95,09,         )[      'STA ,X','MP+1',                       ]
(B5,00,         )[      'LDA ,X','ML',                         ]
(95,08,         )[ 00*  'STA ,X','MP',                         ]
(B5,06,         )[      'LDA ,X','AL',                         ]
(C1,08,         )[      'CMP ,X)','MP',                        ]
(F6,08,         )[      'INC ,X','MP',                         ]
(D0,02,         )[      'BNE',02*,                             ]
(F6,09,         )[      'INC ,X','MP+1',                       ]
(B5,07,         )[ 02=> 'LDA ,X','AH',                         ]
(E1,08,         )[      'SBC ,X)','MP',                        ]
(B0,0A,         )[      'BCS',04*,                             ]
(A9,03,         )[      'LDA #',03,                            ]
(75,08,         )[      'ADC ,X','MP',                         ]
(90,E8,         )[      'BCC',00=<                             ]
(F6,09,         )[      'INC ,X','MP+1',                       ]
(B0,E4,         )[      'BCS',00=<                             ]
                 [ 04=>                                        ]
                 [ (ADJREF)                                    ]
(68,            )[      'PLA',                                 ]
(C9,82,         )[      'CMP #',82,                            ]
(10,0F,         )[      'BPL','REL8',                          ]
(F6,08,         )[      'INC ,X','MP',                         ]
(D0,02,         )[      'BNE',00*,                             ]
(F6,09,         )[      'INC ,X','MP+1',                       ]
(49,02,         )[ 00=> 'EOR #',02,                            ]
(D0,06,         )[      'BNE','REL16',                         ]
                 [ (RELH)                                      ]
(20,C7,80,      )[      'JSR','GETR 6',,                       ]
(61,08,         )[      'ADC ,X)','MP',                        ]
                 [ 'REL8'>                                     ]
(60,            )[      'RTS',                                 ]
                 [ 'REL16'>                                    ]
(A1,08,         )[      'LDA ,X)','MP',                        ]
(4C,AF,80,      )[      'JMP','ADDP 2',,                       ]
                 [ 'ADJMAP ';;                                 ]
                 [ 'ADJMAP'                                    ]
(B5,00,         )[      'LDA ,X','ML',                         ]
(95,08,         )[      'STA ,X','MP',                         ]
(B5,01,         )[      'LDA ,X','MH',                         ]
(95,09,         )[      'STA ,X','MP+1',                       ]
(A1,08,         )[ 00*  'LDA ,X)','MP',                        ]
(F6,08,         )[      'INC ,X','MP',                         ]
(D0,02,         )[      'BNE',02*,                             ]
(F6,09,         )[      'INC ,X','MP+1',                       ]
(A8,            )[ 02=> 'TAY',                                 ]
(A1,08,         )[      'LDA ,X)','MP',                        ]
(F6,08,         )[      'INC ,X','MP',                         ]
(D0,02,         )[      'BNE',04*,                             ]
(F6,09,         )[      'INC ,X','MP+1',                       ]
(48,            )[ 04=> 'PHA',                                 ]
(38,            )[      'SEC',                                 ]
(98,            )[      'TYA',                                 ]
(49,FF,         )[      'EOR #',FF,                            ]
(61,08,         )[      'ADC ,X)','MP',                        ]
(81,08,         )[      'STA ,X)','MP',                        ]
(F6,08,         )[      'INC ,X','MP',                         ]
(D0,02,         )[      'BNE',06*,                             ]
(F6,09,         )[      'INC ,X','MP+1',                       ]
(68,            )[ 06=> 'PLA',                                 ]
(F0,01,         )[      'BEQ',08*,                             ]
(A8,            )[      'TAY',                                 ]
(49,FF,         )[ 08=> 'EOR #',FF,                            ]
(61,08,         )[      'ADC ,X)','MP',                        ]
(81,08,         )[      'STA ,X)','MP',                        ]
(F6,08,         )[      'INC ,X','MP',                         ]
(D0,02,         )[      'BNE',0A*,                             ]
(F6,09,         )[      'INC ,X','MP+1',                       ]
(98,            )[ 0A=> 'TYA',                                 ]
(D0,CD,         )[      'BNE',00=<                             ]
(60,            )[      'RTS',                                 ]
                 [ 'ADDP 1';;                                  ]
                 [ 'ADDP 2';;                                  ]
                 [ 'ADDP'                                      ]
(61,02,         )[      'ADC ,X)','PP',                        ]
(81,02,         )[      'STA ,X)','PP',                        ]
(F6,02,         )[      'INC ,X','PP',                         ]
(D0,02,         )[      'BNE',00*,                             ]
(F6,03,         )[      'INC ,X','PP+1',                       ]
(60,            )[ 00=> 'RTS',                                 ]
                 [ 'SEEKP ';;                                  ]
                 [ 'SEEKP'                                     ]
(18,            )[      'CLC',                                 ]
(48,            )[      'PHA',                                 ]
(98,            )[      'TYA',                                 ]
(75,02,         )[      'ADC ,X','PP',                         ]
(95,02,         )[      'STA ,X','PP',                         ]
(68,            )[      'PLA',                                 ]
(75,03,         )[      'ADC ,X','PP+1',                       ]
(95,03,         )[      'STA ,X','PP+1',                       ]
(60,            )[      'RTS',                                 ]
                 [ 'GETR 1';;                                  ]
                 [ 'GETR 2';;                                  ]
                 [ 'GETR 3';;                                  ]
                 [ 'GETR 4';;                                  ]
                 [ 'GETR 5';;                                  ]
                 [ 'GETR 6';;                                  ]
                 [ 'GETR'                                      ]
(A1,04,         )[      'LDA ,X)','RP',                        ]
(F6,04,         )[      'INC ,X','RP',                         ]
(D0,02,         )[      'BNE',00*,                             ]
(F6,05,         )[      'INC ,X','RP+1',                       ]
(60,            )[ 00=> 'RTS',                                 ]
                 [ 'GETP'                                      ]
(A1,02,         )[      'LDA ,X)','PP',                        ]
(F6,02,         )[      'INC ,X','PP',                         ]
(D0,02,         )[      'BNE',00*,                             ]
(F6,03,         )[      'INC ,X','PP+1',                       ]
(60,            )[ 00=> 'RTS',                                 ]
                 [ 'SEEKR'                                     ]
(18,            )[      'CLC',                                 ]
(48,            )[      'PHA',                                 ]
(98,            )[      'TYA',                                 ]
(75,02,         )[      'ADC ,X','PP',                         ]
(95,04,         )[      'STA ,X','RP',                         ]
(68,            )[      'PLA',                                 ]
(75,03,         )[      'ADC ,X','PP+1',                       ]
(95,05,         )[      'STA ,X','RP+1',                       ]
(60,            )[      'RTS',                                 ]
                 [ 'HEADER1 ';;                                ]
                 [ 'HEADER1'                                   ]
(A0,04,         )[      'LDY #',04,                            ]
(A9,00,         )[      'LDA #',00,                            ]
(4C,BA,80,      )[      'JMP','SEEKP',,                        ]
                 [ 'HEADER2 ';;                                ]
                 [ 'HEADER2'                                   ]
(20,D0,80,      )[      'JSR','GETP',,                         ]
(A8,            )[      'TAY',                                 ]
(20,D0,80,      )[      'JSR','GETP',,                         ]
(4C,D9,80,      )[      'JMP','SEEKR',,                        ]
                 [ (RELDATA)                                   ]
(03,02,00,E6,80,)[      (DB) 03, (DW) 0002,, (DW) 'HEADER1',,  ]
(03,01,00,ED,80,)[      (DB) 03, (DW) 0001,, (DW) 'HEADER2',,  ]
(03,01,00,73,80,)[      (DB) 03, (DW) 0001,, (DW) 'ADJMAP',,   ]
(03,04,00,22,80,)[      (DB) 03, (DW) 0004,, (DW) 'relocate',, ]
(03,09,00,AF,80,)[      (DB) 03, (DW) 0009,, (DW) 'ADDP',,     ]
(03,01,00,C7,80,)[      (DB) 03, (DW) 0001,, (DW) 'GETR',,     ]
(03,06,00,C7,80,)[      (DB) 03, (DW) 0006,, (DW) 'GETR',,     ]
(03,02,00,C7,80,)[      (DB) 03, (DW) 0002,, (DW) 'GETR',,     ]
(03,01,00,BA,80,)[      (DB) 03, (DW) 0001,, (DW) 'SEEKP',,    ]
(03,01,00,C7,80,)[      (DB) 03, (DW) 0001,, (DW) 'GETR',,     ]
(03,03,00,C7,80,)[      (DB) 03, (DW) 0003,, (DW) 'GETR',,     ]
(03,34,00,C7,80,)[      (DB) 03, (DW) 0034,, (DW) 'GETR',,     ]
(03,06,00,AF,80,)[      (DB) 03, (DW) 0006,, (DW) 'ADDP',,     ]
(03,78,00,BA,80,)[      (DB) 03, (DW) 0078,, (DW) 'SEEKP',,    ]
(03,01,00,D0,80,)[      (DB) 03, (DW) 0001,, (DW) 'GETP',,     ]
(03,02,00,D0,80,)[      (DB) 03, (DW) 0002,, (DW) 'GETP',,     ]
(03,01,00,D9,80,)[      (DB) 03, (DW) 0001,, (DW) 'SEEKR',,    ]
(00,            )[      (DB) 00,                               ]
                 [ (PRELDATA)                                  ]
(00,            )[      (DB) 00,                               ]
(Q              )[ _                                           ]