http://www.6502.org/users/andre/o65/fileformat.html
or http://wilsonminesco.com/stacks/where-am-I.html
Unfortunately, the 6502 does not provide mnemonics to allow relative long jumps or relative subroutines nor relative access to data elements to make it position independent.
If you have diffrent memory configurations and you want to place your program anywhere in memory you have to have relocatable assembly code.
I came up with an solution, how 6502 code needs to be written to be relocatable. So it could be loaded at any starting addresses without re-assembling.
There is a support code as part of the initialization at program start (see attached example). This routines allow the user to call or jump to relative location within the program. In addition, a support routine is included, that returns an address within the program code to manage data elements, like text string output.
The attached program example makes use of all three support routines and can be loaded to anywhere in RAM.
It is written for the Ohio C1P computer
Only the relocation support routines have to be placed to a know availabe RAM address, here to $026B to $02FF
Code: Select all
;
; RELOCATION 6502 SUPPORT CODE (to support position independent asm programs)
; This subroutines have to be loaded to fixed available RAM space
; Concept: supporting JMP , JSR and ADR function at fixed free RAM area (Free_Mem)
; Call JMP , target Address ((word)Target offset - * +1) -> Rel_JMP takes 85 cycles
; Call JSR , target Address ((word)Target offset - * +1) -> Rel_JSR takes 110 cycle (without RTS)
; Call ADR ; target Address ((word)Target offset - * +1) -> Rel_ADR takes 108 cycles and returns Address on stack (first high)
; All three routines will not change ACCU, registers or status flags of the CPU !
;
; Relocation support code needs 149 bytes of available RAM and is written for Ohio Superboard 600 / C1P
; Zeropage address $FE and $FF are used for Adr_vector and must be available
; Uses self-modifying code for register backup/restore
Free_Mem = $026B
Rel_JMP = Free_Mem ; 149 Bytes free memory for Relocate code required
Rel_JSR = Free_Mem + $2E
Rel_ADR = Free_Mem + $60
temp_Al = $FE ; Free Zeropage (normally used for OSI Monitor Address)
temp_Ah = $FF
.ORG Free_Mem
SUB_JMP; ; ************ Jump Version <Rel_JMP>
sta temp_A+1 ; Save A
sty temp_Y+1 ; Save Y
php
pla
sta temp_S+1 ; Save Status
pla ; Get Caller address
sta temp_Al
pla
sta temp_Ah
ldy #1
clc
lda (temp_Al),y ; Points to lowbyte of jump delta
adc temp_Al
sta jump_A+1
iny
lda (temp_Al),y ; Points to lowbyte of jump delta
adc temp_Ah
sta jump_A+2
temp_Y: ldy #0 ; Dummy values/address for restore
temp_S: lda #0
pha
temp_A: lda #0
plp
jump_A: jmp 0
SUB_JSR; ; ************ JSR Version <Rel_JSR>
sta temp_A+1
sty temp_Y+1
php
pla
sta temp_S+1
pla ; Get Caller address
sta temp_Al
pla
sta temp_Ah
ldy #1
clc
lda (temp_Al),y ; Points to lowbyte of jsr delta
adc temp_Al
sta jump_A+1
iny
lda (temp_Al),y ; Points to lowbyte of jsr delta
adc temp_Ah
sta jump_A+2
clc ; Correct return address
lda temp_Al
adc #2
tay
lda temp_Ah
adc #0
pha
tya
pha
bcc temp_Y ; most of the time
SUB_ADR: ; ************ Get Address onto stack <Rel_ADR>
sta tema_A+1
sty tema_Y+1
php
pla
sta tema_S+1
pla ; Get Caller address
sta temp_Al
pla
sta temp_Ah
ldy #1
clc
lda (temp_Al),y ; Points to lowbyte of address delta
adc temp_Al
pha ; on stack
iny
lda (temp_Al),y ; Points to lowbyte of address delta
adc temp_Ah
pha ; on stack
clc ; Correct return address
lda temp_Al
adc #2
tay
lda temp_Ah
adc #0
pha
tya
pha
tema_Y: ldy #0 ; Dummy values for restore
tema_S: lda #0
pha
tema_A: lda #0
plp
rts
After compilation of RELOC_Example.asm, you can place the binary anywhere in RAM to run.