Newer
Older
uBix-Retro / dump / oa-2.0.9 / oldlib / loader.a65

/****************************************************************************
   
    OS/A65 Version 2.0.0
    Multitasking Operating System for 6502 Computers

    Copyright (C) 1989-1998 Andre Fachat 

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

****************************************************************************/

/**************************************************************************
 * 
 * Loader for 6502 relocatable binary format
 *
 * The loader supports 16 bit o65 version 1 files without undefined 
 * references. Also it doesn't like pagewise relocation and 65816 
 * code, because there are different/additional relocation entries.
 *
 * The support routines, that have to be changed are at the end of the
 * file. The stuff in this file is in absolute format (well, you have to
 * bootstrap from something :-)
 * The support routines for the file handling are for the operating system
 * OS/A65, as of version 1.3.10b. The first part of the file (wrapped in
 * "#ifdef C64") shows how to use it with a C64, for example.
 * 
 * The subroutine 'loader' is called with a file descriptor, that has a 
 * meaning for the support routines, in the X register.
 * The file must already be open. Also binit must have been called before.
 * The loader doesn't close the file.
 *
 * Support routines are:
 *
 *   zalloc	a   = length of needed zeropage block. returns a=address
 *   zfree	a   = address of block to free
 *
 *   fgetc	x   = file descriptor, returns read byte (c=0) or error (c=1)
 *		      The error is passed through; fgetc blocks if no data
 *		      available
 *   fgetb	x   = filedescriptor, a/y = address of block descriptor,
 *                    i.e. a word start address and a word length of block.
 *                    returns (c=0) or error in accu (c=1).
 *
 **************************************************************************/


/**************************************************************************
 * This part is a binding for a C64
 * to show how it works
 */

#include "file_o65.def"

#define	E_NOMEM		<-40
#define	E_FVERSION	<-41

loader 	.(
	.zero
p1	.word
p2	.word

	.data
tmp	.byt 0
file	.byt 0

header	.dsb HDR_LEN

textb	.byt 0		; memory block ID
texta	.word 0		; address of block
;textl	.word 0		; address of block
textd	.word 0		; difference to assemble address

;datab	.byt 0
dataa	.word 0
;datal	.word 0
datad	.word 0

;bssb	.byt 0
bssa	.word 0
bssd	.word 0

zeroa	.byt 0
zerod	.word 0

	.text

	stx file
	jsr Fgetc
	bcs end
	sta tmp
	jsr Fgetc
	bcs end
	tay
	lda tmp
	cpy #0
	bne rt
	cmp #1
	beq load
rt 	lda #E_FVERSION		; ok, but not this version
end	sec
	rts

load	.(
	lda #<header
	sta p1
	lda #>header
	sta p1+1
	ldx #p1
	lda #<HDR_LEN
	ldy #>HDR_LEN
	jsr fgetb
	bcs end
				; header loaded, check magic and version
	lda header+HDR_MAGIC
	cmp #$6f
	bne end
	lda header+HDR_MAGIC+1
	cmp #"6"
	bne end
	lda header+HDR_MAGIC+2
	cmp #"5"
	bne end
	lda header+HDR_VERSION
	cmp #0
	bne end
	lda header+HDR_MODE+1
	and #%11110000
	bne end
				; now allocate buffers
				/* TODO: check alignment! */
	lda header+HDR_TLEN
	ldy header+HDR_TLEN+1
	clc
	adc header+HDR_DLEN
	pha
	tya
	adc header+HDR_DLEN+1
	tay
	pla
	clc
	adc header+HDR_BLEN
	pha
	tya
	adc header+HDR_BLEN+1
	tay
	pla
	jsr Balloc
	bcc ok
	jmp no_text
ok
	stx textb
	sta texta
	sty texta+1
	clc
	adc header+HDR_TLEN
	sta dataa
	pha
	tya
	adc header+HDR_TLEN+1
	sta dataa+1
	tay
	pla
	adc header+HDR_DLEN
	sta bssa
	pha
	tya
	adc header+HDR_DLEN+1
	sta bssa+1
	tay
	pla

	sec
	sbc header+HDR_BBASE
	sta bssd
	tya
	sbc header+HDR_BBASE+1
	sta bssd+1

	sec
	lda dataa
	sbc header+HDR_DBASE
	sta datad
	lda dataa+1
	sbc header+HDR_DBASE+1
	sta datad+1

	sec
	lda texta
	sbc header+HDR_TBASE
	sta textd
	lda texta+1
	sbc header+HDR_TBASE+1
	sta textd+1

	lda header+HDR_ZLEN
	jsr Zalloc
	bcs no_zero

	sta zeroa
	sec
	sbc header+HDR_ZBASE
	sta zerod
	lda #0
	sta zerod+1

	jmp do_load

no_file
no_zero 
	ldx textb
	jsr Bfree

close
no_text	ldx file
	lda #E_NUL
	jsr STRCMD
	sec
	rts

do_load				; load options (i.e. ignore them now)
	ldx file
	jsr Fgetc
	bcs no_file
	cmp #0
	beq load_text
	tay
	dey
optl	jsr Fgetc
	bcs no_file
	dey
	bne optl
	beq do_load

load_text			; load text segment
	lda texta
	sta p1
	lda texta+1
	sta p1+1
	ldx #p1
	lda header+HDR_TLEN
	ldy header+HDR_TLEN+1
	jsr fgetb
	bcs no_file
				; load data segment
	lda dataa
	sta p1
	lda dataa+1
	sta p1+1
	ldx #p1
	lda header+HDR_DLEN
	ldy header+HDR_DLEN+1
	jsr fgetb
	bcs no_file
				; check number of undefined references
	ldx file
	jsr Fgetc
&no_file2 bcs no_file
	cmp #0
	bne no_file		; we have some -> not handled
	ldx file
	jsr Fgetc
	bcs no_file
	cmp #0
	bne no_file
				; ok, text segments loaded, now relocate
	lda texta
	sec
	sbc #1
	sta p1
	lda texta+1
	sbc #0
	sta p1+1
	jsr trel

	lda dataa
	sec
	sbc #1
	sta p1
	lda dataa+1
	sbc #0
	sta p1+1
	jsr trel

	jsr close 

	lda texta		; return start of text segment
	ldy texta+1
	clc
	rts
	.)

trel	.(
	ldx file
	jsr Fgetc
no_file1 bcs no_file2
	cmp #0
	beq reloc_rts
	cmp #255
	bne t1
	lda #254
	clc
	adc p1
	sta p1
	bcc trel
	inc p1+1
	jmp trel
t1	clc
	adc p1
	sta p1
	bcc t1a
	inc p1+1
t1a			; p1 is the relocation address
	ldx file
	jsr Fgetc
	bcs no_file1
	tay
	and #A_MASK
	sta tmp
	tya
	and #A_FMASK
	jsr getreldiff
	ldy tmp
	cpy #A_ADR
	bne t2

	ldy #0
	clc
	adc (p1),y
	sta (p1),y
	iny
	txa
	adc (p1),y
	sta (p1),y
	jmp trel
t2	
	cpy #A_LOW
	bne t3
	ldy #0
	clc
	adc (p1),y
	sta (p1),y
	jmp trel
t3
	cpy #A_HIGH
	bne trel
	sta p2
	stx p2+1
	ldx file
	jsr Fgetc
	clc
	adc p2		; just get the carry bit
	ldy #0
	lda p2+1	; relocate high byte
	adc (p1),y
	sta (p1),y
	jmp trel

reloc_rts
	clc
	rts
	.)
	
getreldiff .(		; comparing with SEG_UNDEF would give a way
			; to get label value here for undefined refs
	cmp #SEG_TEXT
	bne notext
	lda textd
	ldx textd+1
	rts
notext	cmp #SEG_DATA
	bne nodata
	lda datad
	ldx datad+1
	rts
nodata	cmp #SEG_BSS
	bne nobss
	lda bssd
	ldx bssd+1
	rts
nobss	cmp #SEG_ZERO
	bne nozero
	lda zerod
	ldx zerod+1
nozero	rts
	.)

fgetb   .(
	.zero
p       .word 0
	.data
l       .word 0
	.text

	sta l
	sty l+1
	lda 0,x
	sta p
	lda 1,x
	sta p+1

loop    ldx file
        jsr Fgetc               ; this is a simple implementation
        bcs end1
        ldy #0
        sta (p),y
        inc p
        bne l0
        inc p+1
l0
        lda l
        bne l1
        dec l+1
l1      dec l

        lda l
        ora l+1
        bne loop
        clc
end1
        rts
        .)

	.)