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, _bzero
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
72 RelocVal = Header + 1 ; Relocation value
75 Read: jmp $FFFF ; Jump to read routine
79 .byte $01, $00 ; non C64 marker
80 .byte $6F, $36, $35 ; Magic ("o65")
82 .word O65_CPU_6502|O65_RELOC_BYTE|O65_SIZE_16BIT|O65_FTYPE_EXE|O65_ADDR_SIMPLE|O65_ALIGN_1
84 ExpectedHdrSize = * - ExpectedHdr
87 ;------------------------------------------------------------------------------
88 ; PushCtrl: Push the address of the control structure onto the C stack.
96 ;------------------------------------------------------------------------------
97 ; RestoreRegBank: Restore the register bank contents from the save area. Will
98 ; destroy A and X (the latter will be zero on return).
103 @L1: lda RegBankSave-1,x
109 ;------------------------------------------------------------------------------
110 ; GetReloc: Return a relocation value based on the segment in A.
111 ; The routine uses some knowledge about the values to make the code shorter.
121 ; Text, data and bss segment
124 ldx Module+1 ; Return start address of buffer
127 ; Zero page relocation
129 @L1: lda #<__ZP_START__
133 ;------------------------------------------------------------------------------
134 ; FormatError: Bail out with an o65 format error
139 ; bne CleanupAndExit ; Branch always
141 ;------------------------------------------------------------------------------
142 ; CleanupAndExit: Free any allocated resources, restore the stack and return
148 ; Restore the stack so we may return to the caller from here
153 ; Save the error return code
157 ; Check if we have to free the allocated block
161 beq @L1 ; Jump if no memory allocated
165 jsr _free ; Free the allocated block
167 ; Restore the register bank
169 @L1: jsr RestoreRegBank
171 ; Restore the error code and return to the caller
173 ldx #$00 ; Load the high byte
177 ;------------------------------------------------------------------------------
178 ; ReadByte: Read one byte with error checking into InputByte and A.
179 ; ReadAndCheckError: Call read with the current C stack and check for errors.
192 ; This is a second entry point used by the other calls to Read
197 ; Check the return code and bail out in case of problems
206 @L1: lda InputByte ; If called ReadByte, load the byte read
209 ;------------------------------------------------------------------------------
210 ; RelocSeg: Relocate the segment pointed to by a/x
214 jsr decax1 ; Start value is segment-1
218 Loop: jsr ReadByte ; Read byte from relocation table
219 beq Done ; Bail out if end of table reached
221 cmp #255 ; Special offset?
224 ; Increment offset by 254 and continue
233 ; Increment offset by A
240 ; Read the relocation byte, extract the segment id, fetch the corresponding
241 ; relocation value and place it into ptr1
249 ; Get the relocation byte again, this time extract the relocation type.
254 ; Check for and handle the different relocation types.
263 ; Relocate the low byte
271 ; Relocate a high byte
274 jsr ReadByte ; Read low byte from relocation table
277 adc RelocVal ; We just need the carry
283 jmp Loop ; Done, next entry
294 bne AddHigh ; Branch always (add high byte)
296 ;------------------------------------------------------------------------------
297 ; mod_load: Load and relocate an o65 module
302 ; Save the register bank and clear the Module pointer
314 ; Save the passed parameter
319 ; Save the stack pointer so we can bail out even from subroutines
324 ; Get the read function pointer from the control structure and place it into
334 ; Read the o65 header: C->read (C, &H, sizeof (H))
341 jsr pusha0 ; Always less than 256
342 jsr ReadAndCheckError ; Bails out in case of errors
344 ; We read the o65 header successfully. Validate it.
346 ldy #ExpectedHdrSize-1
354 ; Header is ok as far as we can say now. Read all options, check for the
355 ; OS option and ignore all others. The OS option contains a version number
356 ; and the module id as additional data.
359 sty TPtr+1 ; Flag for OS option read
360 Opt: jsr ReadByte ; Read the length byte
361 beq OptDone ; Jump if done
362 sta TPtr ; Use TPtr as a counter
364 ; An option has a length of at least 2 bytes
367 bcc HeaderError ; Must be 2 bytes total at least
369 ; Check for the OS option
372 jsr ReadByte ; Get the option type
373 cmp #O65_OPT_OS ; OS option?
374 bne SkipOpt ; No: Skip
376 lda TPtr ; Get remaining length+1
377 cmp #5 ; CC65 has 6 bytes total
380 jsr ReadByte ; Get the operating system
381 cmp #O65_OS_CC65_MODULE
382 bne OSError ; Wrong operating system
384 jsr ReadByte ; Get the version number, expect zero
385 bne OSError ; Wrong version
387 jsr ReadByte ; Get low byte of id
388 ldy #MODCTRL_MODULE_ID
391 ldy #MODCTRL_MODULE_ID+1
394 inc TPtr+1 ; Remember that we got the OS
402 beq Opt ; Next option
403 jsr ReadByte ; Skip one byte
406 ; Operating system error
412 ; Options done, check that we got the OS option
418 ; Entry point for header errors
424 ; Skipped all options. Calculate the size of text+data and of text+data+bss
425 ; (the latter is the size of the memory block we need). We will store the
426 ; total module size also into the control structure for evaluation by the
430 lda Header + O65_HDR_TLEN
431 add Header + O65_HDR_DLEN
433 lda Header + O65_HDR_TLEN + 1
434 adc Header + O65_HDR_DLEN + 1
437 add Header + O65_HDR_BLEN
438 pha ; Save low byte of total size
439 ldy #MODCTRL_MODULE_SIZE
442 adc Header + O65_HDR_BLEN + 1
446 pla ; Restore low byte of total size
448 ; Total memory size is now in a/x. Allocate memory and remember the result,
449 ; both, locally and in the control structure so it the caller can access
450 ; the memory block. After that, check if we got the requested memory.
464 ; Could not allocate memory
469 ; Control structure is complete now. Clear the bss segment.
470 ; bzero (bss_addr, bss_size)
476 adc TPtr+1 ; Module + tlen + dlen
480 lda Header + O65_HDR_BLEN
481 ldx Header + O65_HDR_BLEN+1
482 jsr _bzero ; bzero (bss, bss_size);
484 ; Load code and data segment into memory. The sum of the sizes of
485 ; code+data segment is still in TPtr.
486 ; C->read (C, C->module, H.tlen + H.dlen)
495 jsr ReadAndCheckError ; Bails out in case of errors
497 ; We've got the code and data segments in memory. Next section contains
498 ; undefined references which we don't support. So check if the count of
499 ; undefined references is actually zero.
505 Undef: jmp FormatError
507 ; Number of undefined references was zero. Next come the relocation tables
508 ; for code and data segment. Relocate the code segment
511 ldx Module + 1 ; Code segment address
514 ; Relocate the data segment
517 add Header + O65_HDR_TLEN
520 adc Header + O65_HDR_TLEN + 1
522 pla ; Data segment address in a/x
525 ; We're done. Restore the register bank and return a success code
527 jsr RestoreRegBank ; X will be zero on return