1
0
mirror of https://github.com/cc65/cc65.git synced 2024-12-23 04:30:10 +00:00

Adapted, to the c64 target, the INIT-segment overlay scheme from the apple2 targets.

When a program starts running, INIT is moved from one place to another place.  Then, INIT's code is executed; and, the first place is re-used for variables.  After the INIT code has finished, the second place can be re-used by the heap and the C stack.  That means that initiation code and data won't waste any RAM space after they stop being needed.
This commit is contained in:
Greg King 2015-10-05 05:47:43 -04:00
parent 24c2da980b
commit 074e10d288
5 changed files with 200 additions and 104 deletions

View File

@ -24,6 +24,7 @@ SCREEN_PTR := $D1 ; Pointer to current char in text screen
CURS_X := $D3 ; Cursor column CURS_X := $D3 ; Cursor column
CURS_Y := $D6 ; Cursor row CURS_Y := $D6 ; Cursor row
CRAM_PTR := $F3 ; Pointer to current char in color RAM CRAM_PTR := $F3 ; Pointer to current char in color RAM
FREKZP := $FB ; Five unused bytes
BASIC_BUF := $200 ; Location of command-line BASIC_BUF := $200 ; Location of command-line
BASIC_BUF_LEN = 89 ; Maximum length of command-line BASIC_BUF_LEN = 89 ; Maximum length of command-line
@ -212,4 +213,3 @@ CASSMOT = $20 ; Cassette motor on
TP_FAST = $80 ; Switch Rossmoeller TurboProcess to fast mode TP_FAST = $80 ; Switch Rossmoeller TurboProcess to fast mode
RAMONLY = $F8 ; (~(LORAM | HIRAM | IOEN)) & $FF RAMONLY = $F8 ; (~(LORAM | HIRAM | IOEN)) & $FF

View File

@ -1,64 +1,70 @@
FEATURES {
STARTADDRESS: default = $0801;
}
SYMBOLS { SYMBOLS {
__LOADADDR__: type = import; __LOADADDR__: type = import;
__EXEHDR__: type = import; __EXEHDR__: type = import;
__OVERLAYADDR__: type = import; __OVERLAYADDR__: type = import;
__STACKSIZE__: type = weak, value = $0800; # 2k stack __STACKSIZE__: type = weak, value = $0800; # 2k stack
__OVERLAYSIZE__: type = weak, value = $1000; # 4k overlay __OVERLAYSIZE__: type = weak, value = $1000; # 4k overlay
__HIMEM__: type = weak, value = $D000;
__HIMEM2__: type = export, value = __HIMEM__ - 2;
} }
MEMORY { MEMORY {
ZP: file = "", define = yes, start = $0002, size = $001A; ZP: file = "", define = yes, start = $0002, size = $001A;
LOADADDR: file = %O, start = $07FF, size = $0002; LOADADDR: file = %O, start = %S - 2, size = $0002;
HEADER: file = %O, start = $0801, size = $000C; HEADER: file = %O, define = yes, start = %S, size = $000D;
RAM: file = %O, define = yes, start = $080D, size = $C7F3 - __OVERLAYSIZE__ - __STACKSIZE__; RAM: file = %O, start = __HEADER_LAST__, size = __HIMEM__ - __OVERLAYSIZE__ - __STACKSIZE__ - __HEADER_LAST__;
OVL1ADDR: file = "%O.1", start = $CFFE - __OVERLAYSIZE__, size = $0002; MOVE: file = %O, start = __ZPSAVE_LOAD__, size = __HIMEM__ - __INIT_RUN__;
OVL1: file = "%O.1", start = $D000 - __OVERLAYSIZE__, size = __OVERLAYSIZE__; OVL1ADDR: file = "%O.1", start = __HIMEM2__ - __OVERLAYSIZE__, size = $0002;
OVL2ADDR: file = "%O.2", start = $CFFE - __OVERLAYSIZE__, size = $0002; OVL1: file = "%O.1", start = __HIMEM__ - __OVERLAYSIZE__, size = __OVERLAYSIZE__;
OVL2: file = "%O.2", start = $D000 - __OVERLAYSIZE__, size = __OVERLAYSIZE__; OVL2ADDR: file = "%O.2", start = __HIMEM2__ - __OVERLAYSIZE__, size = $0002;
OVL3ADDR: file = "%O.3", start = $CFFE - __OVERLAYSIZE__, size = $0002; OVL2: file = "%O.2", start = __HIMEM__ - __OVERLAYSIZE__, size = __OVERLAYSIZE__;
OVL3: file = "%O.3", start = $D000 - __OVERLAYSIZE__, size = __OVERLAYSIZE__; OVL3ADDR: file = "%O.3", start = __HIMEM2__ - __OVERLAYSIZE__, size = $0002;
OVL4ADDR: file = "%O.4", start = $CFFE - __OVERLAYSIZE__, size = $0002; OVL3: file = "%O.3", start = __HIMEM__ - __OVERLAYSIZE__, size = __OVERLAYSIZE__;
OVL4: file = "%O.4", start = $D000 - __OVERLAYSIZE__, size = __OVERLAYSIZE__; OVL4ADDR: file = "%O.4", start = __HIMEM2__ - __OVERLAYSIZE__, size = $0002;
OVL5ADDR: file = "%O.5", start = $CFFE - __OVERLAYSIZE__, size = $0002; OVL4: file = "%O.4", start = __HIMEM__ - __OVERLAYSIZE__, size = __OVERLAYSIZE__;
OVL5: file = "%O.5", start = $D000 - __OVERLAYSIZE__, size = __OVERLAYSIZE__; OVL5ADDR: file = "%O.5", start = __HIMEM2__ - __OVERLAYSIZE__, size = $0002;
OVL6ADDR: file = "%O.6", start = $CFFE - __OVERLAYSIZE__, size = $0002; OVL5: file = "%O.5", start = __HIMEM__ - __OVERLAYSIZE__, size = __OVERLAYSIZE__;
OVL6: file = "%O.6", start = $D000 - __OVERLAYSIZE__, size = __OVERLAYSIZE__; OVL6ADDR: file = "%O.6", start = __HIMEM2__ - __OVERLAYSIZE__, size = $0002;
OVL7ADDR: file = "%O.7", start = $CFFE - __OVERLAYSIZE__, size = $0002; OVL6: file = "%O.6", start = __HIMEM__ - __OVERLAYSIZE__, size = __OVERLAYSIZE__;
OVL7: file = "%O.7", start = $D000 - __OVERLAYSIZE__, size = __OVERLAYSIZE__; OVL7ADDR: file = "%O.7", start = __HIMEM2__ - __OVERLAYSIZE__, size = $0002;
OVL8ADDR: file = "%O.8", start = $CFFE - __OVERLAYSIZE__, size = $0002; OVL7: file = "%O.7", start = __HIMEM__ - __OVERLAYSIZE__, size = __OVERLAYSIZE__;
OVL8: file = "%O.8", start = $D000 - __OVERLAYSIZE__, size = __OVERLAYSIZE__; OVL8ADDR: file = "%O.8", start = __HIMEM2__ - __OVERLAYSIZE__, size = $0002;
OVL9ADDR: file = "%O.9", start = $CFFE - __OVERLAYSIZE__, size = $0002; OVL8: file = "%O.8", start = __HIMEM__ - __OVERLAYSIZE__, size = __OVERLAYSIZE__;
OVL9: file = "%O.9", start = $D000 - __OVERLAYSIZE__, size = __OVERLAYSIZE__; OVL9ADDR: file = "%O.9", start = __HIMEM2__ - __OVERLAYSIZE__, size = $0002;
OVL9: file = "%O.9", start = __HIMEM__ - __OVERLAYSIZE__, size = __OVERLAYSIZE__;
} }
SEGMENTS { SEGMENTS {
LOADADDR: load = LOADADDR, type = ro; ZEROPAGE: load = ZP, type = zp;
EXEHDR: load = HEADER, type = ro; LOADADDR: load = LOADADDR, type = ro;
STARTUP: load = RAM, type = ro; EXEHDR: load = HEADER, type = ro;
LOWCODE: load = RAM, type = ro, optional = yes; STARTUP: load = RAM, type = ro;
INIT: load = RAM, type = ro, define = yes, optional = yes; LOWCODE: load = RAM, type = ro, optional = yes;
CODE: load = RAM, type = ro; CODE: load = RAM, type = ro;
RODATA: load = RAM, type = ro; RODATA: load = RAM, type = ro;
DATA: load = RAM, type = rw; DATA: load = RAM, type = rw;
ZPSAVE: load = RAM, type = bss; ZPSAVE: load = RAM, type = bss, define = yes;
BSS: load = RAM, type = bss, define = yes; BSS: load = RAM, type = bss, define = yes;
ZEROPAGE: load = ZP, type = zp; INIT: load = MOVE, run = RAM, type = ro, define = yes, optional = yes;
OVL1ADDR: load = OVL1ADDR, type = ro; OVL1ADDR: load = OVL1ADDR, type = ro;
OVERLAY1: load = OVL1, type = ro, define = yes, optional = yes; OVERLAY1: load = OVL1, type = ro, define = yes, optional = yes;
OVL2ADDR: load = OVL2ADDR, type = ro; OVL2ADDR: load = OVL2ADDR, type = ro;
OVERLAY2: load = OVL2, type = ro, define = yes, optional = yes; OVERLAY2: load = OVL2, type = ro, define = yes, optional = yes;
OVL3ADDR: load = OVL3ADDR, type = ro; OVL3ADDR: load = OVL3ADDR, type = ro;
OVERLAY3: load = OVL3, type = ro, define = yes, optional = yes; OVERLAY3: load = OVL3, type = ro, define = yes, optional = yes;
OVL4ADDR: load = OVL4ADDR, type = ro; OVL4ADDR: load = OVL4ADDR, type = ro;
OVERLAY4: load = OVL4, type = ro, define = yes, optional = yes; OVERLAY4: load = OVL4, type = ro, define = yes, optional = yes;
OVL5ADDR: load = OVL5ADDR, type = ro; OVL5ADDR: load = OVL5ADDR, type = ro;
OVERLAY5: load = OVL5, type = ro, define = yes, optional = yes; OVERLAY5: load = OVL5, type = ro, define = yes, optional = yes;
OVL6ADDR: load = OVL6ADDR, type = ro; OVL6ADDR: load = OVL6ADDR, type = ro;
OVERLAY6: load = OVL6, type = ro, define = yes, optional = yes; OVERLAY6: load = OVL6, type = ro, define = yes, optional = yes;
OVL7ADDR: load = OVL7ADDR, type = ro; OVL7ADDR: load = OVL7ADDR, type = ro;
OVERLAY7: load = OVL7, type = ro, define = yes, optional = yes; OVERLAY7: load = OVL7, type = ro, define = yes, optional = yes;
OVL8ADDR: load = OVL8ADDR, type = ro; OVL8ADDR: load = OVL8ADDR, type = ro;
OVERLAY8: load = OVL8, type = ro, define = yes, optional = yes; OVERLAY8: load = OVL8, type = ro, define = yes, optional = yes;
OVL9ADDR: load = OVL9ADDR, type = ro; OVL9ADDR: load = OVL9ADDR, type = ro;
OVERLAY9: load = OVL9, type = ro, define = yes, optional = yes; OVERLAY9: load = OVL9, type = ro, define = yes, optional = yes;
} }
FEATURES { FEATURES {
CONDES: type = constructor, CONDES: type = constructor,

View File

@ -1,26 +1,31 @@
FEATURES {
STARTADDRESS: default = $0801;
}
SYMBOLS { SYMBOLS {
__LOADADDR__: type = import; __LOADADDR__: type = import;
__EXEHDR__: type = import; __EXEHDR__: type = import;
__STACKSIZE__: type = weak, value = $0800; # 2k stack __STACKSIZE__: type = weak, value = $0800; # 2k stack
__HIMEM__: type = weak, value = $D000;
} }
MEMORY { MEMORY {
ZP: file = "", define = yes, start = $0002, size = $001A; ZP: file = "", define = yes, start = $0002, size = $001A;
LOADADDR: file = %O, start = $07FF, size = $0002; LOADADDR: file = %O, start = %S - 2, size = $0002;
HEADER: file = %O, start = $0801, size = $000C; HEADER: file = %O, define = yes, start = %S, size = $000D;
RAM: file = %O, define = yes, start = $080D, size = $C7F3 - __STACKSIZE__; RAM: file = %O, start = __HEADER_LAST__, size = __HIMEM__ - __STACKSIZE__ - __HEADER_LAST__;
MOVE: file = %O, start = __ZPSAVE_LOAD__, size = __HIMEM__ - __INIT_RUN__;
} }
SEGMENTS { SEGMENTS {
LOADADDR: load = LOADADDR, type = ro; ZEROPAGE: load = ZP, type = zp;
EXEHDR: load = HEADER, type = ro; LOADADDR: load = LOADADDR, type = ro;
STARTUP: load = RAM, type = ro; EXEHDR: load = HEADER, type = ro;
LOWCODE: load = RAM, type = ro, optional = yes; STARTUP: load = RAM, type = ro;
INIT: load = RAM, type = ro, define = yes, optional = yes; LOWCODE: load = RAM, type = ro, optional = yes;
CODE: load = RAM, type = ro; CODE: load = RAM, type = ro;
RODATA: load = RAM, type = ro; RODATA: load = RAM, type = ro;
DATA: load = RAM, type = rw; DATA: load = RAM, type = rw;
ZPSAVE: load = RAM, type = bss; ZPSAVE: load = RAM, type = bss, define = yes;
BSS: load = RAM, type = bss, define = yes; BSS: load = RAM, type = bss, define = yes;
ZEROPAGE: load = ZP, type = zp; INIT: load = MOVE, run = RAM, type = ro, define = yes, optional = yes;
} }
FEATURES { FEATURES {
CONDES: type = constructor, CONDES: type = constructor,

View File

@ -3,13 +3,13 @@
; ;
.export _exit .export _exit
.exportzp init_load_, init_run_
.export __STARTUP__ : absolute = 1 ; Mark as startup .export __STARTUP__ : absolute = 1 ; Mark as startup
.import initlib, donelib .import initlib, donelib
.import zerobss .import move_init, zerobss, callmain
.import callmain
.import RESTOR, BSOUT, CLRCH .import RESTOR, BSOUT, CLRCH
.import __RAM_START__, __RAM_SIZE__ ; Linker generated .import __HIMEM__ ; from configure file
.import __STACKSIZE__ ; Linker generated
.importzp ST .importzp ST
.include "zeropage.inc" .include "zeropage.inc"
@ -19,18 +19,17 @@
; ------------------------------------------------------------------------ ; ------------------------------------------------------------------------
; Startup code ; Startup code
; Two zero-page pointers are needed before any zero-page stuff is saved.
; Choose locations that are not used by anything.
init_load_ := FREKZP
init_run_ := FREKZP+2
.segment "STARTUP" .segment "STARTUP"
Start: Start:
; Save the zero-page locations that we need.
ldx #zpspace-1
L1: lda sp,x
sta zpsave,x
dex
bpl L1
; Switch to the second charset. ; Switch to the second charset.
lda #14 lda #14
@ -39,35 +38,30 @@ L1: lda sp,x
; Switch off the BASIC ROM. ; Switch off the BASIC ROM.
lda $01 lda $01
pha ; Remember the value sta mmusave ; Save the memory configuration
and #$F8 and #$F8
ora #$06 ; Enable Kernal+I/O, disable BASIC ora #$06 ; Enable Kernal+I/O, disable BASIC
sta $01 sta $01
; Clear the BSS data.
jsr zerobss
; Save some system settings; and, set up the stack.
pla
sta mmusave ; Save the memory configuration
tsx tsx
stx spsave ; Save the system stack ptr stx spsave ; Save the system stack ptr
lda #<(__RAM_START__ + __RAM_SIZE__ + __STACKSIZE__) ; Allow some re-entrancy by skipping the next task if it already was done.
sta sp ; This often can let us rerun the program without reloading it.
lda #>(__RAM_START__ + __RAM_SIZE__ + __STACKSIZE__)
sta sp+1 ; Set argument stack ptr
; Call the module constructors. ldx moveinit
beq L0
jsr initlib ; Move the INIT segment from where it was loaded (over ZPSAVE and BSS)
; into where it must be run (in the heap).
; Push the command-line arguments; and, call main(). jsr move_init
dec moveinit ; set to false
jsr callmain ; Save space by putting the rest of the start-up code in the INIT segment,
; which can be re-used by the heap.
L0: jsr initstart
; Back from main() [this is also the exit() entry]. Run the module destructors. ; Back from main() [this is also the exit() entry]. Run the module destructors.
@ -98,14 +92,51 @@ L2: lda zpsave,x
rts rts
; ------------------------------------------------------------------------
.segment "INIT"
initstart:
; Save the zero-page locations that we need.
ldx #zpspace-1
L1: lda sp,x
sta zpsave,x
dex
bpl L1
; Clear the BSS data.
jsr zerobss
; Set up the stack.
lda #<__HIMEM__
ldx #>__HIMEM__
sta sp
stx sp+1 ; Set argument stack ptr
; Call the module constructors.
jsr initlib
; Push the command-line arguments; and, call main().
jmp callmain
; ------------------------------------------------------------------------ ; ------------------------------------------------------------------------
; Data ; Data
.data
mmusave:.res 1
spsave: .res 1
moveinit:
.byte 1
.segment "ZPSAVE" .segment "ZPSAVE"
zpsave: .res zpspace zpsave: .res zpspace
.bss
spsave: .res 1
mmusave:.res 1

54
libsrc/common/moveinit.s Normal file
View File

@ -0,0 +1,54 @@
;
; 2015-10-04, Greg King
;
.export move_init
.import __INIT_LOAD__, __INIT_RUN__, __INIT_SIZE__ ; Linker-generated
.importzp init_load_, init_run_
.macpack cpu
.macpack generic
; Move the INIT segment from where it was loaded (over the bss segments)
; into where it must be run (in the heap). The two areas might overlap; and,
; the segment is moved upwards. Therefore, this code starts at the highest
; address, and decrements to the lowest address. The low bytes of the starting
; pointers are not sums. The high bytes are sums; but, they do not include the
; carry. Both the low-byte sums and the carries will be done when the pointers
; are indexed by the .Y register.
move_init:
lda #<__INIT_LOAD__
ldx #>__INIT_LOAD__ + >__INIT_SIZE__
sta init_load_
stx init_load_+1
lda #<__INIT_RUN__
ldx #>__INIT_RUN__ + >__INIT_SIZE__
sta init_run_
stx init_run_+1
; First, move the last, partial page.
; Then, move all of the full pages.
ldx #>__INIT_SIZE__ + 1 ; number of pages, including partial
ldy #<__INIT_SIZE__ ; size of partial page
.if .cpu & CPU_ISET_65SC02
bra L3
.else
jmp L3
.endif
L1: dec init_load_+1
dec init_run_+1
L2: dey
lda (init_load_),y
sta (init_run_),y
tya
L3: bnz L2 ; page not finished
dex
bnz L1 ; move next page
rts