mirror of
https://github.com/cc65/cc65.git
synced 2024-12-25 17:29:50 +00:00
New files for loading modules at runtime
git-svn-id: svn://svn.cc65.org/cc65/trunk@1252 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
parent
0876496d44
commit
0e4eef1f0f
@ -88,6 +88,8 @@ S_OBJS = _fdesc.o \
|
||||
memcmp.o \
|
||||
memcpy.o \
|
||||
memset.o \
|
||||
modfree.o \
|
||||
modload.o \
|
||||
printf.o \
|
||||
rand.o \
|
||||
setjmp.o \
|
||||
|
57
libsrc/common/modfree.s
Normal file
57
libsrc/common/modfree.s
Normal file
@ -0,0 +1,57 @@
|
||||
;*****************************************************************************/
|
||||
;* */
|
||||
;* modfree.s */
|
||||
;* */
|
||||
;* Free loaded o65 modules */
|
||||
;* */
|
||||
;* */
|
||||
;* */
|
||||
;* (C) 2002 Ullrich von Bassewitz */
|
||||
;* Wacholderweg 14 */
|
||||
;* D-70597 Stuttgart */
|
||||
;* EMail: uz@musoftware.de */
|
||||
;* */
|
||||
;* */
|
||||
;* This software is provided 'as-is', without any expressed or implied */
|
||||
;* warranty. In no event will the authors be held liable for any damages */
|
||||
;* arising from the use of this software. */
|
||||
;* */
|
||||
;* Permission is granted to anyone to use this software for any purpose, */
|
||||
;* including commercial applications, and to alter it and redistribute it */
|
||||
;* freely, subject to the following restrictions: */
|
||||
;* */
|
||||
;* 1. The origin of this software must not be misrepresented; you must not */
|
||||
;* claim that you wrote the original software. If you use this software */
|
||||
;* in a product, an acknowledgment in the product documentation would be */
|
||||
;* appreciated but is not required. */
|
||||
;* 2. Altered source versions must be plainly marked as such, and must not */
|
||||
;* be misrepresented as being the original software. */
|
||||
;* 3. This notice may not be removed or altered from any source */
|
||||
;* distribution. */
|
||||
;* */
|
||||
;*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
.include "modload.inc"
|
||||
|
||||
.import _free
|
||||
.importzp ptr1
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; mod_free: Free a loaded module
|
||||
|
||||
.code
|
||||
_mod_free:
|
||||
sta ptr1
|
||||
stx ptr1+1 ; Save parameter
|
||||
|
||||
ldy #MODCTRL_MODULE + 1
|
||||
lda (ptr1),y
|
||||
tax
|
||||
dey
|
||||
lda (ptr1),y ; Load module pointer
|
||||
|
||||
jmp _free ; Free the module memory
|
||||
|
||||
|
541
libsrc/common/modload.s
Normal file
541
libsrc/common/modload.s
Normal file
@ -0,0 +1,541 @@
|
||||
;*****************************************************************************/
|
||||
;* */
|
||||
;* modload.s */
|
||||
;* */
|
||||
;* o65 module loader for the cc65 library */
|
||||
;* */
|
||||
;* */
|
||||
;* */
|
||||
;* (C) 2002 Ullrich von Bassewitz */
|
||||
;* Wacholderweg 14 */
|
||||
;* D-70597 Stuttgart */
|
||||
;* EMail: uz@musoftware.de */
|
||||
;* */
|
||||
;* */
|
||||
;* This software is provided 'as-is', without any expressed or implied */
|
||||
;* warranty. In no event will the authors be held liable for any damages */
|
||||
;* arising from the use of this software. */
|
||||
;* */
|
||||
;* Permission is granted to anyone to use this software for any purpose, */
|
||||
;* including commercial applications, and to alter it and redistribute it */
|
||||
;* freely, subject to the following restrictions: */
|
||||
;* */
|
||||
;* 1. The origin of this software must not be misrepresented; you must not */
|
||||
;* claim that you wrote the original software. If you use this software */
|
||||
;* in a product, an acknowledgment in the product documentation would be */
|
||||
;* appreciated but is not required. */
|
||||
;* 2. Altered source versions must be plainly marked as such, and must not */
|
||||
;* be misrepresented as being the original software. */
|
||||
;* 3. This notice may not be removed or altered from any source */
|
||||
;* distribution. */
|
||||
;* */
|
||||
;*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
.include "o65.inc"
|
||||
.include "modload.inc"
|
||||
|
||||
.import pushax, pusha0, push0, push1, decax1
|
||||
.import _malloc, _free, _memset
|
||||
.importzp sp, ptr1, tmp1, regbank
|
||||
|
||||
.macpack generic
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; Variables stored in the register bank in the zero page. Placing the variables
|
||||
; here will protect them when calling other C functions.
|
||||
|
||||
Module = regbank+0 ; Pointer to module memory
|
||||
Ctrl = regbank+2 ; Pointer to mod_ctrl structure
|
||||
TPtr = regbank+4 ; Pointer to module data for relocation
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; Static module data
|
||||
|
||||
.bss
|
||||
|
||||
; Save areas and error recovery data
|
||||
Stack: .byte 0 ; Old stackpointer
|
||||
RegBankSave: .res 6 ; Save area for register bank
|
||||
|
||||
; The header of the o65 file. Since we don't need the 8 bytes any longer,
|
||||
; once we've checked them, we will overlay them with other data to save a
|
||||
; few bytes.
|
||||
Header: .res O65_HDR_SIZE ; The o65 header
|
||||
|
||||
; Input
|
||||
InputByte = Header ; Byte read from input
|
||||
|
||||
; Stuff needed for relocation
|
||||
TextReloc = Header + 1 ; Relocation value for code seg
|
||||
DataReloc = Header + 3 ; Relocation value for data seg
|
||||
BssReloc = Header + 5 ; Relocation value for bss seg
|
||||
|
||||
.data
|
||||
Read: jmp $FFFF ; Jump to read routine
|
||||
|
||||
.rodata
|
||||
ExpectedHdr: .byte $01, $00 ; non C64 marker
|
||||
.byte $6F, $36, $35 ; Magic ("o65")
|
||||
.byte $00 ; Version
|
||||
.word $0000 ; Mode word
|
||||
ExpectedHdrSize = * - ExpectedHdr
|
||||
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; PushCtrl: Push the address of the control structure onto the C stack.
|
||||
|
||||
.code
|
||||
PushCtrl:
|
||||
lda Ctrl
|
||||
ldx Ctrl+1
|
||||
jmp pushax
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; LoadCtrl: Load a word from the control structure into a/x. The offset of the
|
||||
; high byte is passed in Y.
|
||||
|
||||
.code
|
||||
LoadCtrl:
|
||||
lda (Ctrl),y
|
||||
tax
|
||||
dey
|
||||
lda (Ctrl),y
|
||||
rts
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; RestoreRegBank: Restore the register bank contents from the save area. Will
|
||||
; destroy A and X
|
||||
|
||||
.code
|
||||
RestoreRegBank:
|
||||
ldx #6-1
|
||||
@L1: lda RegBankSave,x
|
||||
sta regbank,x
|
||||
dex
|
||||
bpl @L1
|
||||
rts
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; GetReloc: Return a relocation value based on the segment in A
|
||||
|
||||
.code
|
||||
GetReloc:
|
||||
cmp #O65_SEGID_TEXT
|
||||
bne @L1
|
||||
lda TextReloc
|
||||
ldx TextReloc+1
|
||||
rts
|
||||
|
||||
@L1: cmp #O65_SEGID_DATA
|
||||
bne @L2
|
||||
lda DataReloc
|
||||
ldx DataReloc+1
|
||||
rts
|
||||
|
||||
@L2: cmp #O65_SEGID_BSS
|
||||
bne @L3
|
||||
lda BssReloc
|
||||
ldx BssReloc+1
|
||||
rts
|
||||
|
||||
@L3: lda #MLOAD_ERR_FMT
|
||||
; bne CleanupAndExit ; Branch always
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; CleanupAndExit: Free any allocated resources, restore the stack and return
|
||||
; to the caller.
|
||||
|
||||
.code
|
||||
CleanupAndExit:
|
||||
|
||||
; Restore the stack so we may return to the caller from here
|
||||
|
||||
ldx Stack
|
||||
txs
|
||||
|
||||
; Save the error return code
|
||||
|
||||
pha
|
||||
|
||||
; Check if we have to free the allocated block
|
||||
|
||||
lda Module
|
||||
ora Module+1
|
||||
beq @L1 ; Jump if no memory allocated
|
||||
|
||||
lda Module
|
||||
ldx Module+1
|
||||
jsr _free ; Free the allocated block
|
||||
|
||||
; Restore the register bank
|
||||
|
||||
@L1: jsr RestoreRegBank
|
||||
|
||||
; Restore the error code and return to the caller
|
||||
|
||||
ldx #$00 ; Load the high byte
|
||||
pla
|
||||
rts
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; ReadByte: Read one byte with error checking into InputByte and A.
|
||||
|
||||
.code
|
||||
ReadByte:
|
||||
|
||||
; C->read (C, &B, 1)
|
||||
|
||||
jsr PushCtrl
|
||||
lda #<InputByte
|
||||
ldx #>InputByte
|
||||
jsr pushax
|
||||
jsr push1
|
||||
jsr Read
|
||||
|
||||
; Check the return code and bail out in case of problems
|
||||
|
||||
tax
|
||||
beq @L1 ; Jump if ok
|
||||
lda #MLOAD_ERR_READ
|
||||
bne CleanupAndExit
|
||||
|
||||
; Done
|
||||
|
||||
@L1: lda InputByte
|
||||
Done: rts
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; RelocSeg: Relocate the segment pointed to by a/x
|
||||
|
||||
.code
|
||||
RelocSeg:
|
||||
jsr decax1 ; Start value is segment-1
|
||||
sta TPtr
|
||||
stx TPtr+1
|
||||
|
||||
Loop: jsr ReadByte ; Read byte from relocation table
|
||||
beq Done ; Bail out if end of table reached
|
||||
|
||||
cmp #255 ; Special offset?
|
||||
bne @L1
|
||||
|
||||
; Increment offset by 254 and continue
|
||||
|
||||
lda TPtr
|
||||
add #254
|
||||
sta TPtr
|
||||
bcc Loop
|
||||
inc TPtr+1
|
||||
jmp Loop
|
||||
|
||||
; Increment offset by A
|
||||
|
||||
@L1: add TPtr
|
||||
sta TPtr
|
||||
bcc @L2
|
||||
inc TPtr+1
|
||||
|
||||
; Read the relocation byte, extract the segment id, fetch the corresponding
|
||||
; relocation value and place it into ptr1
|
||||
|
||||
@L2: jsr ReadByte
|
||||
and #O65_SEGID_MASK
|
||||
jsr GetReloc
|
||||
sta ptr1
|
||||
stx ptr1+1
|
||||
|
||||
; Get the relocation byte again, this time extract the relocation type.
|
||||
|
||||
lda InputByte
|
||||
and #O65_RTYPE_MASK
|
||||
|
||||
; Check for and handle the different relocation types.
|
||||
|
||||
cmp #O65_RTYPE_WORD
|
||||
bne @L3
|
||||
ldy #0
|
||||
clc
|
||||
lda (TPtr),y
|
||||
adc ptr1
|
||||
sta (TPtr),y
|
||||
iny
|
||||
bne @L4 ; Branch always (add high byte)
|
||||
|
||||
@L3: cmp #O65_RTYPE_HIGH
|
||||
bne @L5
|
||||
jsr ReadByte ; Read low byte from relocation table
|
||||
ldy #0
|
||||
clc
|
||||
adc ptr1 ; We just need the carry
|
||||
@L4: lda (TPtr),y
|
||||
adc ptr1+1
|
||||
sta (TPtr),y
|
||||
jmp Loop ; Done, next entry
|
||||
|
||||
@L5: cmp #O65_RTYPE_LOW
|
||||
beq @L6
|
||||
|
||||
; Problem: Invalid relocation code
|
||||
|
||||
lda #MLOAD_ERR_FMT
|
||||
jmp CleanupAndExit
|
||||
|
||||
@L6: ldy #0
|
||||
clc
|
||||
lda (TPtr),y
|
||||
adc ptr1
|
||||
sta (TPtr),y
|
||||
|
||||
; Finished with this relocation
|
||||
|
||||
jmp Loop
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; mod_load: Load and relocate an o65 module
|
||||
|
||||
.code
|
||||
_mod_load:
|
||||
|
||||
; Save the register bank and clear the Module pointer
|
||||
|
||||
pha
|
||||
ldy #6
|
||||
@L1: lda regbank-1,y
|
||||
sta RegBankSave-1,y
|
||||
dey
|
||||
bne @L1
|
||||
sty Module
|
||||
sty Module+1
|
||||
pla
|
||||
|
||||
; Save the passed parameter
|
||||
|
||||
sta Ctrl
|
||||
stx Ctrl+1
|
||||
|
||||
; Save the stack pointer so we can bail out even from subroutines
|
||||
|
||||
tsx
|
||||
stx Stack
|
||||
|
||||
; Get the read function pointer from the control structure and place it into
|
||||
; our call vector
|
||||
|
||||
ldy #MODCTRL_READ+1
|
||||
jsr LoadCtrl
|
||||
sta Read+1
|
||||
stx Read+2
|
||||
|
||||
; Read the o65 header: C->read (C, &H, sizeof (H))
|
||||
|
||||
jsr PushCtrl
|
||||
lda #<Header
|
||||
ldx #>Header
|
||||
jsr pushax
|
||||
lda #O65_HDR_SIZE
|
||||
jsr pusha0 ; Always less than 256
|
||||
jsr Read
|
||||
|
||||
; Check the return code
|
||||
|
||||
tax
|
||||
beq @L2
|
||||
lda #MLOAD_ERR_READ
|
||||
jmp CleanupAndExit
|
||||
|
||||
; We read the o65 header successfully. Validate it.
|
||||
|
||||
@L2: ldy #ExpectedHdrSize-1
|
||||
@L3: lda Header,y
|
||||
cmp ExpectedHdr,y
|
||||
beq @L4
|
||||
lda #MLOAD_ERR_HDR
|
||||
jmp CleanupAndExit
|
||||
@L4: dey
|
||||
bpl @L3
|
||||
|
||||
; Header is ok as far as we can say now. Read and skip all options. We may
|
||||
; add a check here for the OS option later.
|
||||
|
||||
Opt: jsr ReadByte
|
||||
beq OptDone ; Jump if done
|
||||
sta TPtr ; Use TPtr as a counter
|
||||
OneOpt: dec TPtr
|
||||
beq Opt ; Next option
|
||||
jsr ReadByte ; Skip one byte
|
||||
jmp OneOpt
|
||||
OptDone:
|
||||
|
||||
; Skipped all options. Calculate the sizes of several areas needed later
|
||||
|
||||
lda Header + O65_HDR_TLEN
|
||||
add Header + O65_HDR_DLEN
|
||||
sta TPtr
|
||||
lda Header + O65_HDR_TLEN + 1
|
||||
adc Header + O65_HDR_DLEN + 1
|
||||
sta TPtr+1
|
||||
lda TPtr
|
||||
add Header + O65_HDR_BLEN
|
||||
sta tmp1
|
||||
lda TPtr+1
|
||||
adc Header + O65_HDR_BLEN + 1
|
||||
|
||||
; Load the total module size into a/x and store it into the control structure
|
||||
|
||||
ldy #MODCTRL_MODULE_SIZE + 1
|
||||
sta (Ctrl),y
|
||||
tax
|
||||
dey
|
||||
lda tmp1
|
||||
sta (Ctrl),y
|
||||
|
||||
; Allocate memory, check if we got it
|
||||
|
||||
jsr _malloc
|
||||
sta Module
|
||||
stx Module+1
|
||||
ora Module+1
|
||||
bne GotMem
|
||||
|
||||
; Could not allocate memory
|
||||
|
||||
lda #MLOAD_ERR_MEM
|
||||
jmp CleanupAndExit
|
||||
|
||||
; We got the memory block. Setup the pointers and sizes in the control
|
||||
; structure. We will use internal knowlege about the layout of the structure
|
||||
; here to save some code.
|
||||
|
||||
GotMem: lda Module
|
||||
ldy #MODCTRL_MODULE
|
||||
sta (Ctrl),y
|
||||
ldy #MODCTRL_CODE
|
||||
sta (Ctrl),y
|
||||
txa
|
||||
iny
|
||||
sta (Ctrl),y ; MODCTRL_CODE+1
|
||||
ldy #MODCTRL_MODULE+1
|
||||
sta (Ctrl),y
|
||||
|
||||
; The following loop will also copy some information that is not needed just
|
||||
; to save some code.
|
||||
|
||||
ldx #O65_HDR_TLEN
|
||||
ldy #MODCTRL_CODE_SIZE
|
||||
CLoop: lda Header,x
|
||||
sta (Ctrl),y
|
||||
inx
|
||||
iny
|
||||
cpy #MODCTRL_SIZE
|
||||
bne CLoop
|
||||
|
||||
; Missing in the control structure now: start of the data and bss segments
|
||||
|
||||
ldy #MODCTRL_DATA
|
||||
lda Module
|
||||
add Header + O65_HDR_TLEN
|
||||
sta (Ctrl),y
|
||||
iny
|
||||
lda Module + 1
|
||||
adc Header + O65_HDR_TLEN + 1
|
||||
sta (Ctrl),y
|
||||
|
||||
ldy #MODCTRL_BSS
|
||||
lda Module
|
||||
add TPtr
|
||||
sta (Ctrl),y
|
||||
iny
|
||||
lda Module+1
|
||||
add TPtr+1
|
||||
sta (Ctrl),y
|
||||
|
||||
; Control structure is complete now. Load code and data segment into memory.
|
||||
; The sum of the sizes of code and data segment is still in TPtr.
|
||||
; C->read (C, C->module, H.tlen + H.dlen)
|
||||
|
||||
jsr PushCtrl
|
||||
lda Module
|
||||
ldx Module+1
|
||||
jsr pushax
|
||||
lda TPtr
|
||||
ldx TPtr+1
|
||||
jsr pushax
|
||||
jsr Read
|
||||
|
||||
; Check for errors
|
||||
|
||||
tax
|
||||
beq LoadOk
|
||||
lda #MLOAD_ERR_READ
|
||||
jmp CleanupAndExit
|
||||
|
||||
; We've got the code and data segments in memory. Next section contains
|
||||
; undefined references which we don't support. So check if the count of
|
||||
; undefined references is actually zero.
|
||||
|
||||
LoadOk: jsr ReadByte
|
||||
bne Undef
|
||||
jsr ReadByte
|
||||
beq Reloc
|
||||
Undef: lda #MLOAD_ERR_FMT
|
||||
jmp CleanupAndExit
|
||||
|
||||
; Number of undefined references was zero. Next sections are the relocation
|
||||
; tables for code and data segment. Before doing the actual relocation, we
|
||||
; have to setup the relocation values for the three segments.
|
||||
|
||||
Reloc: lda Module
|
||||
sub Header + O65_HDR_TBASE
|
||||
sta TextReloc
|
||||
lda Module + 1
|
||||
sbc Header + O65_HDR_TBASE + 1
|
||||
sta TextReloc + 1
|
||||
|
||||
ldy #MODCTRL_DATA
|
||||
lda (Ctrl),y
|
||||
sub Header + O65_HDR_DBASE
|
||||
sta DataReloc
|
||||
iny
|
||||
lda (Ctrl),y
|
||||
sbc Header + O65_HDR_DBASE + 1
|
||||
sta DataReloc + 1
|
||||
|
||||
ldy #MODCTRL_BSS
|
||||
lda (Ctrl),y
|
||||
sub Header + O65_HDR_BBASE
|
||||
sta BssReloc
|
||||
iny
|
||||
lda (Ctrl),y
|
||||
sbc Header + O65_HDR_BBASE + 1
|
||||
sta BssReloc + 1
|
||||
|
||||
; Relocate the code segment
|
||||
|
||||
lda Module
|
||||
ldx Module + 1 ; Code segment address
|
||||
jsr RelocSeg
|
||||
|
||||
; Relocate the data segment
|
||||
|
||||
ldy #MODCTRL_DATA + 1
|
||||
jsr LoadCtrl ; Get data segment address
|
||||
jsr RelocSeg
|
||||
|
||||
; Clear the bss segment
|
||||
|
||||
ldy #MODCTRL_BSS + 1
|
||||
jsr LoadCtrl ; Load bss segment address
|
||||
jsr pushax
|
||||
jsr push0
|
||||
ldy #MODCTRL_BSS_SIZE + 1
|
||||
jsr LoadCtrl ; Load bss segment size
|
||||
jsr _memset ; memset (bss, 0, bss_size);
|
||||
|
||||
; We're done. Restore the register bank and return a success code
|
||||
|
||||
jsr RestoreRegBank
|
||||
lda #MLOAD_OK
|
||||
rts
|
||||
|
Loading…
Reference in New Issue
Block a user