1 ;*****************************************************************************/
5 ;* o65 module loader for the cc65 library */
9 ;* (C) 2002 Ullrich von Bassewitz */
11 ;* D-70597 Stuttgart */
12 ;* EMail: uz@musoftware.de */
15 ;* This software is provided 'as-is', without any expressed or implied */
16 ;* warranty. In no event will the authors be held liable for any damages */
17 ;* arising from the use of this software. */
19 ;* Permission is granted to anyone to use this software for any purpose, */
20 ;* including commercial applications, and to alter it and redistribute it */
21 ;* freely, subject to the following restrictions: */
23 ;* 1. The origin of this software must not be misrepresented; you must not */
24 ;* claim that you wrote the original software. If you use this software */
25 ;* in a product, an acknowledgment in the product documentation would be */
26 ;* appreciated but is not required. */
27 ;* 2. Altered source versions must be plainly marked as such, and must not */
28 ;* be misrepresented as being the original software. */
29 ;* 3. This notice may not be removed or altered from any source */
32 ;*****************************************************************************/
37 .include "modload.inc"
39 .import pushax, pusha0, push0, push1, decax1
40 .import _malloc, _free, _memset
41 .import __ZP_START__ ; Linker generated
42 .importzp sp, ptr1, tmp1, regbank
46 ;------------------------------------------------------------------------------
47 ; Variables stored in the register bank in the zero page. Placing the variables
48 ; here will protect them when calling other C functions.
50 Module = regbank+0 ; Pointer to module memory
51 Ctrl = regbank+2 ; Pointer to mod_ctrl structure
52 TPtr = regbank+4 ; Pointer to module data for relocation
54 ;------------------------------------------------------------------------------
59 ; Save areas and error recovery data
60 Stack: .byte 0 ; Old stackpointer
61 RegBankSave: .res 6 ; Save area for register bank
63 ; The header of the o65 file. Since we don't need the first 8 bytes any
64 ; longer, once we've checked them, we will overlay them with other data to
66 Header: .res O65_HDR_SIZE ; The o65 header
69 InputByte = Header ; Byte read from input
71 ; Stuff needed for relocation. Since the ld65 linker uses a relocation base
72 ; address of zero for all segments, the relocation values needed are actually
73 ; the start addresses of the segments. Among other things this means that the
74 ; relocation value for the text segment is the same as the start address as
75 ; the whole module block.
76 TextReloc = Module ; Relocation value for code seg
77 DataReloc = Header + 1 ; Relocation value for data seg
78 BssReloc = Header + 3 ; Relocation value for bss seg
81 Read: jmp $FFFF ; Jump to read routine
84 ExpectedHdr: .byte $01, $00 ; non C64 marker
85 .byte $6F, $36, $35 ; Magic ("o65")
87 .word $0000 ; Mode word
88 ExpectedHdrSize = * - ExpectedHdr
91 ;------------------------------------------------------------------------------
92 ; PushCtrl: Push the address of the control structure onto the C stack.
100 ;------------------------------------------------------------------------------
101 ; LoadCtrl: Load a word from the control structure into a/x. The offset of the
102 ; high byte is passed in Y.
112 ;------------------------------------------------------------------------------
113 ; RestoreRegBank: Restore the register bank contents from the save area. Will
114 ; destroy A and X (the latter will be zero on return).
119 @L1: lda RegBankSave-1,x
125 ;------------------------------------------------------------------------------
126 ; GetReloc: Return a relocation value based on the segment in A
136 @L1: cmp #O65_SEGID_DATA
142 @L2: cmp #O65_SEGID_BSS
148 @L3: cmp #O65_SEGID_ZP
154 ;------------------------------------------------------------------------------
155 ; FormatError: Bail out with an o65 format error
159 ; bne CleanupAndExit ; Branch always
161 ;------------------------------------------------------------------------------
162 ; CleanupAndExit: Free any allocated resources, restore the stack and return
168 ; Restore the stack so we may return to the caller from here
173 ; Save the error return code
177 ; Check if we have to free the allocated block
181 beq @L1 ; Jump if no memory allocated
185 jsr _free ; Free the allocated block
187 ; Restore the register bank
189 @L1: jsr RestoreRegBank
191 ; Restore the error code and return to the caller
193 ldx #$00 ; Load the high byte
197 ;------------------------------------------------------------------------------
198 ; ReadByte: Read one byte with error checking into InputByte and A.
199 ; ReadAndCheckError: Call read with the current C stack and check for errors.
212 ; This is a second entry point used by the other calls to Read
217 ; Check the return code and bail out in case of problems
226 @L1: lda InputByte ; If called ReadByte, load the byte read
229 ;------------------------------------------------------------------------------
230 ; RelocSeg: Relocate the segment pointed to by a/x
234 jsr decax1 ; Start value is segment-1
238 Loop: jsr ReadByte ; Read byte from relocation table
239 beq Done ; Bail out if end of table reached
241 cmp #255 ; Special offset?
244 ; Increment offset by 254 and continue
253 ; Increment offset by A
260 ; Read the relocation byte, extract the segment id, fetch the corresponding
261 ; relocation value and place it into ptr1
269 ; Get the relocation byte again, this time extract the relocation type.
274 ; Check for and handle the different relocation types.
283 ; Relocate the low byte
293 ; Relocate a high byte
296 jsr ReadByte ; Read low byte from relocation table
299 adc ptr1 ; We just need the carry
303 jmp Loop ; Done, next entry
314 bne AddHigh ; Branch always (add high byte)
316 ;------------------------------------------------------------------------------
317 ; mod_load: Load and relocate an o65 module
322 ; Save the register bank and clear the Module pointer
334 ; Save the passed parameter
339 ; Save the stack pointer so we can bail out even from subroutines
344 ; Get the read function pointer from the control structure and place it into
352 ; Read the o65 header: C->read (C, &H, sizeof (H))
359 jsr pusha0 ; Always less than 256
360 jsr ReadAndCheckError ; Bails out in case of errors
362 ; We read the o65 header successfully. Validate it.
364 ldy #ExpectedHdrSize-1
373 ; Header is ok as far as we can say now. Read and skip all options. We may
374 ; add a check here for the OS option later.
377 beq OptDone ; Jump if done
378 sta TPtr ; Use TPtr as a counter
380 beq Opt ; Next option
381 jsr ReadByte ; Skip one byte
385 ; Skipped all options. Calculate the size of text+data and of text+data+bss
386 ; (the latter is the size of the memory block we need). We will store the
387 ; total module size also into the control structure for evaluation by the
390 lda Header + O65_HDR_TLEN
391 add Header + O65_HDR_DLEN
393 lda Header + O65_HDR_TLEN + 1
394 adc Header + O65_HDR_DLEN + 1
397 add Header + O65_HDR_BLEN
398 pha ; Save low byte of total size
399 ldy #MODCTRL_MODULE_SIZE
402 adc Header + O65_HDR_BLEN + 1
406 pla ; Restore low byte of total size
408 ; Total memory size is now in a/x. Allocate memory, check if we got it.
416 ; Could not allocate memory
421 ; We got the memory block. Setup the pointers and sizes in the control
422 ; structure. We will use internal knowlege about the layout of the structure
423 ; here to save some code.
425 GotMem: lda Module ; Ctrl->module = Module;
428 ldy #MODCTRL_CODE ; Ctrl->code = Module;
432 sta (Ctrl),y ; MODCTRL_CODE+1
433 ldy #MODCTRL_MODULE+1
436 ; The following loop will also copy some information that is not needed just
440 ldy #MODCTRL_CODE_SIZE
448 ; Missing in the control structure now: start of the data and bss segments.
449 ; Since the linker relocates all segments to zero, these addresses are also
450 ; the relocation values for the segments.
454 add Header + O65_HDR_TLEN
459 adc Header + O65_HDR_TLEN + 1
474 ; Control structure is complete now. Load code and data segment into memory.
475 ; The sum of the sizes of code+data segment is still in TPtr.
476 ; C->read (C, C->module, H.tlen + H.dlen)
485 jsr ReadAndCheckError ; Bails out in case of errors
487 ; We've got the code and data segments in memory. Next section contains
488 ; undefined references which we don't support. So check if the count of
489 ; undefined references is actually zero.
495 Undef: jmp FormatError
497 ; Number of undefined references was zero. Next sections are the relocation
498 ; tables for code and data segment. Relocate the code segment
501 ldx Module + 1 ; Code segment address
504 ; Relocate the data segment
506 ldy #MODCTRL_DATA + 1
507 jsr LoadCtrl ; Get data segment address
510 ; Clear the bss segment
513 jsr LoadCtrl ; Load bss segment address
516 lda Header + O65_HDR_BLEN
517 ldx Header + O65_HDR_BLEN+1
518 jsr _memset ; memset (bss, 0, bss_size);
520 ; We're done. Restore the register bank and return a success code
522 jsr RestoreRegBank ; X will be zero on return